[latexila] Structure: optimize add_item_at_end ()
- From: SÃbastien Wilmet <swilmet src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [latexila] Structure: optimize add_item_at_end ()
- Date: Sat, 23 Jul 2011 01:19:18 +0000 (UTC)
commit 57b28180a48123ac5d9cf53c65ed14f8406823de
Author: SÃbastien Wilmet <swilmet src gnome org>
Date: Fri Jul 22 23:33:30 2011 +0200
Structure: optimize add_item_at_end ()
Avoid using O(N) GNode functions.
The improvement is not visible with normal documents, but with big
documents with parent who have a lot of direct children, then it's
better.
src/structure_model.vala | 167 +++++++++++-----------------------------------
1 files changed, 40 insertions(+), 127 deletions(-)
---
diff --git a/src/structure_model.vala b/src/structure_model.vala
index bcb469f..6ff5a81 100644
--- a/src/structure_model.vala
+++ b/src/structure_model.vala
@@ -57,6 +57,7 @@ public class StructureModel : TreeModel, GLib.Object
private Node<StructData?> _tree;
private int _stamp;
private uint _nb_nodes = 0;
+ private unowned Node<StructData?> _end_node = null;
private Gee.ArrayList<unowned Node<StructData?>> _list_labels;
private Gee.ArrayList<unowned Node<StructData?>> _list_includes;
@@ -351,89 +352,43 @@ public class StructureModel : TreeModel, GLib.Object
public TreeIter? add_item_at_end (StructData item)
{
- /* search the parent, based on the type */
- unowned Node<StructData?> parent = _tree;
- StructType item_depth = item.type;
+ // A first implementation used node.last_child (), but this function is O(N)
+ // with N the number of children. This was too slow with some big documents.
+ // Now we keep track of the last node in the tree, so we simply have to traverse
+ // the parents (wich is O(1)).
+
+ // Another improvement is to find the previous sibling instead of the parent,
+ // because when we _append_ a new child, all the children are traversed, which is
+ // O(N). When we insert a node just after another, it's O(1).
+
+ if (_end_node == null)
+ search_end_node ();
+ /* Search the previous sibling, or the parent */
+ StructType item_depth = item.type;
+ unowned Node<StructData?> parent = _end_node;
+ unowned Node<StructData?>? prev_sibling = null;
while (true)
{
- unowned Node<StructData?> last_child = parent.last_child ();
- if (last_child == null)
+ if (parent == _tree)
break;
- StructType cur_depth = last_child.data.type;
- if (item_depth <= cur_depth || ! Structure.is_section (cur_depth))
+ StructType cur_depth = parent.data.type;
+ if (Structure.is_section (cur_depth) && cur_depth < item_depth)
break;
- parent = last_child;
+ prev_sibling = parent;
+ parent = parent.parent;
}
- return append_item (parent, item);
- }
+ /* Insert the node at the right place */
+ TreeIter? end_iter = insert_item_after (parent, prev_sibling, item);
- // In the middle means that we have to find where to insert the data in the tree.
- // If items have to be shifted (for example: insert a chapter in the middle of
- // sections), it will be done by insert_item_at_position().
- /*
- public void add_item_in_middle (StructData item)
- {
- // if the tree is empty
- if (_tree.is_leaf ())
- {
- append_item (_tree, item);
- return;
- }
+ if (end_iter != null)
+ _end_node = get_node_from_iter (end_iter);
- int pos = get_position_from_mark (item.start_mark);
- unowned Node<StructData?> cur_parent = _tree;
- while (true)
- {
- unowned Node<StructData?> cur_child = cur_parent.first_child ();
- int child_index = 0;
- while (true)
- {
- int cur_pos = get_position_from_mark (cur_child.data.start_mark);
-
- if (cur_pos > pos)
- {
- if (child_index == 0)
- {
- insert_item_at_position (item, cur_parent, child_index);
- return;
- }
-
- unowned Node<StructData?> prev_child = cur_child.prev_sibling ();
- if (prev_child.is_leaf ())
- {
- insert_item_at_position (item, cur_parent, child_index);
- return;
- }
-
- cur_parent = prev_child;
- break;
- }
-
- unowned Node<StructData?> next_child = cur_child.next_sibling ();
-
- // current child is the last child
- if (next_child == null)
- {
- if (cur_child.is_leaf ())
- {
- insert_item_at_position (item, cur_parent, child_index + 1);
- return;
- }
-
- cur_parent = cur_child;
- break;
- }
-
- cur_child = next_child;
- child_index++;
- }
- }
+ return end_iter;
}
- */
// With the iter returned, we can simply go one line backward and we have the end of
// the section. If null is returned, the end of the section is the end of the doc.
@@ -466,7 +421,7 @@ public class StructureModel : TreeModel, GLib.Object
unowned Node<StructData?> node = get_node_from_iter (iter);
delete_node (node);
-
+ _end_node = null;
regenerate_simple_lists ();
}
@@ -684,65 +639,16 @@ public class StructureModel : TreeModel, GLib.Object
}
}
- /*
- private void insert_item_at_position (StructData item, Node<StructData?> parent,
- int pos)
- {
- // If a simple item (not a section) is inserted between sections. For example:
- // chapter
- // section 1
- // => insert simple item here
- // section 2
- //
- // The item's parent will be 'section 1' instead of 'chapter'.
- if (pos > 0)
- {
- unowned Node<StructData?> prev = parent.nth_child (pos - 1);
- bool prev_is_section = Structure.is_section (prev.data.type);
- bool item_is_section = Structure.is_section (item.type);
-
- if (prev_is_section && ! item_is_section)
- {
- append_item (prev, item);
- return;
- }
- }
-
- // If the parent is not a section, insert the item after the parent.
- // AFAIK, the unique case which can happen is:
- // section
- // figure or table (the parent)
- // image, label, etc.
- // => insert a figure or a table here
- // => it must be inserted here instead
- if (parent != _tree && ! Structure.is_section (parent.data.type))
- {
- unowned Node<StructData?> grand_parent = parent.parent;
- int parent_pos = grand_parent.child_position (parent);
- insert_item (grand_parent, parent_pos + 1, item);
- return;
- }
-
- insert_item (parent, pos, item);
- }
- */
-
- private TreeIter? append_item (Node<StructData?> parent, StructData item)
- {
- return insert_item (parent, -1, item);
- }
-
- // insert the item, and emits the appropriate signals
- private TreeIter? insert_item (Node<StructData?> parent, int pos, StructData item)
+ private TreeIter? insert_item_after (Node<StructData?> parent,
+ Node<StructData?>? sibling, StructData item)
{
return_val_if_fail (item.text != null, null);
- unowned Node<StructData?> new_node = parent.insert_data (pos, item);
- insert_node (new_node);
+ unowned Node<StructData?> new_node = parent.insert_after (sibling,
+ new Node<StructData?> (item));
- // Store the node to a list, if it's not a section
- bool append = pos == -1;
- insert_node_in_list (new_node, append);
+ insert_node (new_node);
+ insert_node_in_list (new_node, true);
return create_iter_at_node (new_node);
}
@@ -780,6 +686,13 @@ public class StructureModel : TreeModel, GLib.Object
}
}
+ private void search_end_node ()
+ {
+ _end_node = _tree;
+ while (! _end_node.is_leaf ())
+ _end_node = _end_node.last_child ();
+ }
+
private static int get_position_from_mark (TextMark mark)
{
TextIter iter;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]