Fix insertion and deletion of children elements
authorAndrew Young <youngar17@gmail.com>
Thu, 16 Aug 2012 08:23:35 +0000 (04:23 -0400)
committerAndrew Young <youngar17@gmail.com>
Thu, 16 Aug 2012 08:23:35 +0000 (04:23 -0400)
* recursively note_insert the children of an inserted element.
* recursively note_delete
* make mergers clone contexts before modifying them.
* make mergers indicate strategy in merge context.

src/doc_ref.c
src/doc_ref.h
src/merge_ctxt.c
src/merge_ctxt.h
src/print.c
src/print.h
src/print_ctxt.c
src/print_ctxt.h
src/smerger.c

index 247def9..c21691c 100644 (file)
@@ -3,6 +3,7 @@
  */
 
 #include <stdlib.h>
+#include <string.h>
 #include "debug.h"
 #include "config.h"
 #include "gl_list.h"
@@ -12,6 +13,7 @@
 #include <stdbool.h>
 #include "minmax.h"
 
+#include "print.h"
 #include "doc_elt.h"
 #include "doc_ref.h"
 
@@ -42,9 +44,16 @@ doc_reflist_isupdated (gl_list_t reflist)
 void
 doc_reflist_print (gl_list_t reflist, void *context, doc_stream *out)
 {
-  /**
-   * @todo make the print ctxt pass around correctly
+  /*
+   * copy the mave context to allow nested movement conflicts
    */
+  print_ctxt * print_ctxt = context;
+
+  conflict_state parent_move_state = print_ctxt_get_movement_state (print_ctxt);
+  print_ctxt_set_movement_state (print_ctxt, no_conflict);
+
+  size_t parent_level = print_ctxt->current_level;
+
   debug_msg (DOC, 5, "Printing element list\n");
   gl_list_iterator_t i;
   i = gl_list_iterator (reflist);
@@ -55,13 +64,54 @@ doc_reflist_print (gl_list_t reflist, void *context, doc_stream *out)
     {
       debug_msg (DOC, 4, "Printing element\n");
       elt = doc_ref_get_elt (ref);
+      print_ctxt->current_level = parent_level;
       doc_elt_print (ref, context, out);
+      enter_movement_conflict (print_ctxt, no_conflict, "Moved\n", out);
     }
+
+  print_ctxt_set_movement_state (print_ctxt, parent_move_state);
+
   debug_msg (DOC, 5, "Finished printing element\n");
   gl_list_iterator_free (&i);
   return;
 }
 
+void
+doc_reflist_note_insert (gl_list_t reflist, merge_ctxt *ctxt)
+{
+  debug_msg (DOC, 5, "Inserting element list\n");
+  gl_list_iterator_t i;
+  i = gl_list_iterator (reflist);
+  doc_ref *ref;
+  doc_elt *elt;
+
+  while (gl_list_iterator_next (&i, (const void **) &ref, NULL))
+    {
+      elt = doc_ref_get_elt (ref);
+      doc_elt_note_insert (ref, ctxt);
+    }
+  gl_list_iterator_free (&i);
+  return;
+}
+
+void
+doc_reflist_note_delete(gl_list_t reflist, merge_ctxt *ctxt)
+{
+  debug_msg (DOC, 5, "Deleting element list\n");
+  gl_list_iterator_t i;
+  i = gl_list_iterator (reflist);
+  doc_ref *ref;
+  doc_elt *elt;
+
+  while (gl_list_iterator_next (&i, (const void **) &ref, NULL))
+    {
+      elt = doc_ref_get_elt (ref);
+      doc_elt_note_delete (ref, ctxt);
+    }
+  gl_list_iterator_free (&i);
+  return;
+}
+
 struct context;
 
 typedef enum mapped_state
@@ -121,8 +171,14 @@ is_related (struct context *ctxt, OFFSET xoff, OFFSET yoff)
 }
 
 void
-doc_reflist_merge (doc_ref *parent, gl_list_t ancestor, gl_list_t descendant, merge_ctxt *merge_ctxt)
+doc_reflist_merge (doc_ref *parent, gl_list_t ancestor, gl_list_t descendant, merge_ctxt *m_ctxt)
 {
+
+  /* Clone the merge context */
+  merge_ctxt new_m_ctxt = *m_ctxt;
+  // memcpy (&new_m_ctxt, m_ctxt, sizeof (merge_ctxt));
+  new_m_ctxt.strategy = LOCAL_LIST_MERGE;
+
   /* First, create a mapped_state for every element that will be mapped.
    * Compare the two strigs marking mapped and unmapped nodes.  Then,
    * merge the two lists, combining mapped elements ino a sigle element.
@@ -149,7 +205,7 @@ doc_reflist_merge (doc_ref *parent, gl_list_t ancestor, gl_list_t descendant, me
   ctxt.a_state    = a_state;
   ctxt.ancestor   = ancestor;
   ctxt.descendant = descendant;
-  ctxt.merge_ctxt = merge_ctxt;
+  ctxt.merge_ctxt = &new_m_ctxt;
 
   /* Allocate data for the algorithm to use*/
   size_t diags = a_size + d_size + 3;
@@ -244,7 +300,7 @@ doc_reflist_merge (doc_ref *parent, gl_list_t ancestor, gl_list_t descendant, me
           //doc_ref_check_for_circular_conflict (d_ref);
 
          //mark_insert_children ();
-         doc_elt_note_insert (d_ref, merge_ctxt);
+         doc_elt_note_insert (d_ref, &new_m_ctxt);
 
          a_index++;
          a_size++;
@@ -258,7 +314,7 @@ doc_reflist_merge (doc_ref *parent, gl_list_t ancestor, gl_list_t descendant, me
          doc_ref * a_ref = (doc_ref *) gl_list_get_at (ancestor, a_index);
 
          // mark_remove_children (m_child, src);
-         doc_elt_note_delete (a_ref, merge_ctxt);
+         doc_elt_note_delete (a_ref, &new_m_ctxt);
          a_index++;
        }
       else  if ((a_index != a_size) && (d_index != d_size))
@@ -275,12 +331,12 @@ doc_reflist_merge (doc_ref *parent, gl_list_t ancestor, gl_list_t descendant, me
          doc_ref_add_src (a_ref, doc_ref_get_src (d_ref));
 
          /* get the element to merge the content and children */
-         doc_elt_merge (a_ref, d_ref, merge_ctxt);
+         doc_elt_merge (a_ref, d_ref, &new_m_ctxt);
 
          /* make the doc_refs point to the same element */
-         //doc_ref_set_elt (d_ref, doc_ref_get_elt (a_ref) );
+         doc_ref_set_elt (d_ref, doc_ref_get_elt (a_ref) );
           //doc_ref_set_parent (d_ref, doc_ref_get_parent (a_ref));
-          //printf ("merging docrefs, par=%d, ref=%d\n", doc_ref_get_elt (a_ref), doc_ref_get_elt (d_ref));
+
          a_index++;
          d_index++;
        }
index 763c6cb..29666f1 100644 (file)
@@ -8,9 +8,7 @@
 #include <stdlib.h>
 #include "gl_list.h"
 #include "doc_stream.h"
-//#include "doc_elt.h"
 
-/* #include "doc_elt.h" */
 struct doc_elt;
 typedef struct doc_elt doc_elt;
 typedef struct merge_ctxt merge_ctxt;
@@ -54,7 +52,10 @@ static inline void doc_ref_add_src (doc_ref *ref, doc_src src);
 static inline bool doc_ref_isexactly (doc_ref *ref, doc_src src);
 static inline bool doc_ref_contains (doc_ref *ref, doc_src src);
 static inline doc_ref *doc_ref_get_parent (doc_ref *ref);
-static inline void doc_ref_set_paraent (doc_ref *ref, doc_ref* parent);
+static inline void doc_ref_set_parent (doc_ref *ref, doc_ref* parent);
+
+void doc_reflist_note_insert (gl_list_t reflist, merge_ctxt *ctxt);
+void doc_reflist_note_delete (gl_list_t reflist, merge_ctxt *ctxt);
 
 /* circular conflict */
 static inline bool doc_ref_is_circular_conflict (doc_ref *ref);
index 13f9671..338233b 100644 (file)
@@ -17,6 +17,7 @@ static gl_list_t merge_ctxt_create_default_priorities ();
 void
 merge_ctxt_init (merge_ctxt *ctxt)
 {
+  ctxt->strategy = NO_STRATEGY;
   ctxt->global_smerger = NULL;
   ctxt->priorities = NULL;
   return;
index 51b28f4..745f4ea 100644 (file)
@@ -8,6 +8,13 @@
 #ifndef MERGE_CTXT_H
 #define MERGE_CTXT_H
 
+typedef enum merge_strategy {
+  NO_STRATEGY,
+  GLOBAL_SEARCH_MERGE,
+  LOCAL_LIST_MERGE,
+  LOCAL_SEARCH_MERGE
+} merge_strategy;
+
 struct gl_list_impl;
 typedef struct gl_list_impl * gl_list_t;
 
@@ -18,6 +25,7 @@ typedef struct merge_ctxt
 {
   smerger *global_smerger;
   gl_list_t priorities;
+  merge_strategy strategy;
 } merge_ctxt;
 
 /**
index ec6a9ab..5c71e8f 100644 (file)
@@ -7,6 +7,14 @@ static const char *start_mark  = ">>>>>>> ";
 static const char *middle_mark = "======= ";
 static const char *end_mark    = "<<<<<<< ";
 
+/*
+ * Print the conflict markers
+ */
+static void
+print_conflict_markers (conflict_state *current_state, conflict_state state,
+                        char* msg, doc_stream *out);
+
+
 void
 enter_structural_conflict (print_ctxt *ctxt, conflict_state state,
                           char* msg, doc_stream *out)
@@ -16,7 +24,7 @@ enter_structural_conflict (print_ctxt *ctxt, conflict_state state,
 
   if ( ctxt->structure_conflict != state )
     {
-      enter_content_conflict (ctxt, no_conflict, NULL, out);
+      enter_movement_conflict (ctxt, no_conflict, NULL, out);
     }
   else
     return;
@@ -24,38 +32,28 @@ enter_structural_conflict (print_ctxt *ctxt, conflict_state state,
   if (state != no_conflict)
     ctxt->conflict_occurred = true;
 
-  while (ctxt->structure_conflict != state )
-    {
-      /*conflict wrap up */
-      switch (ctxt->structure_conflict)
-       {
-       case no_conflict:
-         doc_stream_puts (start_mark, out);
-         break;
-       case local_side:
-         doc_stream_puts (middle_mark, out);
-         break;
-       case remote_side:
-         doc_stream_puts (end_mark, out);
-         break;
-       }
-      ctxt->structure_conflict ++;
-
-      if (ctxt->structure_conflict == 3)
-       ctxt->structure_conflict = 0;
+  print_conflict_markers (&ctxt->structure_conflict, state, msg, out);
 
-      if (ctxt->structure_conflict != state)
-       doc_stream_putc ('\n', out);
-    }
+  return;
+}
 
-  if (msg != NULL)
+void
+enter_movement_conflict (print_ctxt *ctxt, conflict_state state,
+                         char* msg, doc_stream *out)
+{
+  /* wrap up the conflicts, print a message on the last conflict
+   * marker, if there is one */
+  if ( ctxt->movement_conflict != state )
     {
-      doc_stream_puts (msg, out);
+      enter_content_conflict (ctxt, no_conflict, NULL, out);
     }
   else
-    {
-      doc_stream_putc ('\n', out);
-    }
+    return;
+
+  if (state != no_conflict)
+    ctxt->conflict_occurred = true;
+
+  print_conflict_markers (&ctxt->movement_conflict, state, msg, out);
 
   return;
 }
@@ -70,10 +68,20 @@ enter_content_conflict (print_ctxt *ctxt, conflict_state state,
   if (state != no_conflict)
     ctxt->conflict_occurred = true;
 
-  while ( ctxt->content_conflict != state  )
+  print_conflict_markers (&ctxt->content_conflict, state, msg, out);
+
+  return;
+}
+
+static void
+print_conflict_markers (conflict_state *current_state, conflict_state state,
+                        char* msg, doc_stream *out)
+{
+
+  while (*current_state != state )
     {
       /*conflict wrap up */
-      switch (ctxt->content_conflict)
+      switch (*current_state)
        {
        case no_conflict:
          doc_stream_puts (start_mark, out);
@@ -85,14 +93,13 @@ enter_content_conflict (print_ctxt *ctxt, conflict_state state,
          doc_stream_puts (end_mark, out);
          break;
        }
-      ctxt->content_conflict ++;
+      (*current_state) ++;
 
-      if (ctxt->content_conflict == 3)
-       ctxt->content_conflict = 0;
+      if (*current_state == 3)
+       *current_state = 0;
 
-      if (ctxt->content_conflict != state)
+      if (*current_state != state)
        doc_stream_putc ('\n', out);
-
     }
 
   if (msg != NULL)
@@ -103,7 +110,5 @@ enter_content_conflict (print_ctxt *ctxt, conflict_state state,
     {
       doc_stream_putc ('\n', out);
     }
-
   return;
 }
-
index 899281c..cac8beb 100644 (file)
@@ -7,8 +7,7 @@
 #define PRINT_H
 #include "doc_stream.h"
 
-struct print_ctxt;
-typedef struct print_ctxt print_ctxt;
+#include "print_ctxt.h"
 
 /**
  * @todo Find a way to deal with advancing the print mode with the
@@ -16,40 +15,28 @@ typedef struct print_ctxt print_ctxt;
  */
 
 /**
- * @brief A context for the current printing mode.
- *
- * It acts as a request to print only certain information.  It does
- * not imply what side of a conflict we are printing.
- */
-typedef enum print_state
-  {
-    print_merged,
-    print_remote,
-    print_local,
-    print_ancestor
-  } print_state;
-
-/**
- * @brief The current state of conflict markers.
- */
-typedef enum conflict_state
-  {
-    no_conflict = 0,
-    local_side  = 1,
-    remote_side = 2
-  } conflict_state;
-
-/**
  * @brief enter a certain part of a structural conflict.
  *
  * This function enters a structural conflict.  If it is already in
- * the correct state, it will do nothing.  It will wrap up any content
+ * the correct state, it will do nothing.  It will wrap up any movement
  * conflicts before switching
  */
 void enter_structural_conflict (print_ctxt *ctxt, conflict_state state,
                                char* msg, doc_stream *out);
 
 /**
+ * @brief enter a certain part of a movement conflict.
+ *
+ * This function enters a structural conflict. If it is already in the
+ * correct state, it will do nothing. It will wrap up any content
+ * conflicts before switching. Movement Conflicts are assumed to be
+ * nestable between parents and children. It is up to the parent to
+ * ensure that the print ctxt is set up for this.
+ */
+void enter_movement_conflict (print_ctxt *ctxt, conflict_state state,
+                         char* msg, doc_stream *out);
+
+/**
  * @brief enter a certain part of a content conflict.
  *
  * This function enters a content conflict.  If it is already in the
@@ -58,4 +45,39 @@ void enter_structural_conflict (print_ctxt *ctxt, conflict_state state,
 void enter_content_conflict (print_ctxt *ctxt, conflict_state state,
                             char* msg, doc_stream *out);
 
+static inline conflict_state print_ctxt_get_content_state (print_ctxt *ctxt);
+
+static inline conflict_state print_ctxt_get_structure_state (print_ctxt *ctxt);
+
+static inline conflict_state print_ctxt_get_movement_state (print_ctxt *ctxt);
+static inline void print_ctxt_set_movement_state (print_ctxt *ctxt, conflict_state state);
+
+/*
+ * Implementation
+ */
+
+static inline conflict_state
+print_ctxt_get_content_state (print_ctxt *ctxt)
+{
+  return ctxt->structure_conflict;
+}
+
+static inline conflict_state
+print_ctxt_get_structure_state (print_ctxt *ctxt)
+{
+  return ctxt->content_conflict;
+}
+
+static inline conflict_state
+print_ctxt_get_movement_state (print_ctxt *ctxt)
+{
+  return ctxt->movement_conflict;
+}
+
+static inline void
+print_ctxt_set_movement_state (print_ctxt *ctxt, conflict_state state)
+{
+  ctxt->movement_conflict = state;
+}
+
 #endif /* PRINT_H */
index 7688dfb..1087ea1 100644 (file)
@@ -20,6 +20,7 @@ void
 print_ctxt_init (print_ctxt *ctxt)
 {
   ctxt->depth = 0;
+  ctxt->current_level = 0;
   ctxt->rmargin = 0;
   ctxt->tab_width = 0;
   ctxt->use_tabs = 0;
@@ -27,6 +28,7 @@ print_ctxt_init (print_ctxt *ctxt)
   ctxt->nested_conflicts = no_conflict;
   ctxt->structure_conflict = no_conflict;
   ctxt->content_conflict = no_conflict;
+  ctxt->movement_conflict = no_conflict;
   ctxt->conflict_occurred = false;
   return;
 }
index 5d9b821..8cd8514 100644 (file)
@@ -7,15 +7,40 @@
 
 #ifndef PRINT_CTXT_H
 #define PRINT_CTXT_H
-#include "print.h"
+//#include "print.h"
 #include "stdbool.h"
 
 /**
+ * @brief A context for the current printing mode.
+ *
+ * It acts as a request to print only certain information.  It does
+ * not imply what side of a conflict we are printing.
+ */
+typedef enum print_state
+  {
+    print_merged,
+    print_remote,
+    print_local,
+    print_ancestor
+  } print_state;
+
+/**
+ * @brief The current state of conflict markers.
+ */
+typedef enum conflict_state
+  {
+    no_conflict = 0,
+    local_side  = 1,
+    remote_side = 2
+  } conflict_state;
+
+/**
  * @brief A context for printing doc_elt's in a tree.
  */
 typedef struct print_ctxt
 {
   int            depth;              /*< The current depth in a document tree */
+  size_t         current_level;      /*< the current level of a document      */
   size_t         rmargin;            /*< The column of the doc's right margin */
   size_t         tab_width;          /*< The column width of a tab character  */
   bool           use_tabs;           /*< Should generated output use tabs?    */
@@ -23,7 +48,8 @@ typedef struct print_ctxt
   bool           nested_conflicts;   /*< if there are nested conflicts        */
   conflict_state structure_conflict; /*< the current state of conflicts       */
   conflict_state content_conflict;   /*< the current state of conflicts       */
-  bool           conflict_occurred;   /* IF a conflict occured                 */
+  conflict_state movement_conflict;  /*< the current state of conflict        */
+  bool           conflict_occurred;  /*< IF a conflict occured                */
 } print_ctxt;
 
 /**
index d79f459..e9a7859 100644 (file)
@@ -1,3 +1,5 @@
+#include <string.h>
+
 #include "config.h"
 #include "gl_rbtree_list.h"
 #include "gl_list.h"
@@ -133,14 +135,7 @@ static inline doc_ref *
 smerger_match_remove (gl_list_t list, doc_ref *ref, merge_ctxt *ctxt)
 {
   debug_msg (SMERGER, 5, "Begin\n");
-  /*
-  if (SMERGER_PRINTLEVEL > 3)
-    {
-      debug_msg (SMERGER, 3, "Matching heading ='");
-      doc_elt_print (ref, NULL, stdout);
-      debug_msg (SMERGER, 3, "'\n");
-    }
-  */
+
   doc_ref        *match    = NULL;
   gl_list_node_t listnode  = NULL;
   int            last_pos  = 0;
@@ -207,25 +202,21 @@ smerger_remove_exactly ( gl_list_t list, doc_ref *ref)
  * element.
  */
 static inline int
-smerger_merge (doc_ref *ancestor, doc_ref *descendant, merge_ctxt *ctxt)
+smerger_merge (doc_ref *ancestor, doc_ref *descendant, merge_ctxt *old_ctxt)
 {
   debug_msg (SMERGER, 5, "Begin\n");
   int status = 0;
   doc_elt *anc_elt = doc_ref_get_elt (ancestor);
 
-  /* check for a circular conflict */
-  //doc_ref_set_elt (descendant, anc_elt);
-  //doc_ref_set_parent (descendant, ancestor->parent);
-  //doc_ref_check_for_circular_conflict (descendant);
-  // doc_ref_set_parent (ancestor,descendant->parent);
+  /* Clone the context */
+  merge_ctxt new_ctxt = *old_ctxt;
+  //memcpy (&new_ctxt, ctxt, sizeof (merge_ctxt));
 
-  doc_elt_merge (ancestor, descendant, ctxt);
+  /* Modify the strategy to indicate */
+  new_ctxt.strategy = GLOBAL_SEARCH_MERGE;
 
-  //if (doc_elt_get_type (anc_elt) == ORG_HEADING)
-  //if (doc_ref_contains (descendant, LOC_SRC))
-  //{
-      //org_heading_set_doc_ref ((org_heading *)anc_elt, descendant);
-  //}
+  doc_elt_merge (ancestor, descendant, &new_ctxt);
+  doc_ref_set_elt (descendant, anc_elt);
 
   debug_msg (SMERGER, 5, "Return =%d\n", status);
   return status;