Update ooo320-m1
[ooovba.git] / applied_patches / 0185-calc-perf-flat-segment-tree.diff
blobcf4a1c920751ab7c636f5f19bd829f99ca471afd
1 diff --git sc/inc/mdds/flatsegmenttree.hxx sc/inc/mdds/flatsegmenttree.hxx
2 new file mode 100644
3 index 0000000..96a6256
4 --- /dev/null
5 +++ sc/inc/mdds/flatsegmenttree.hxx
6 @@ -0,0 +1,815 @@
7 +/*************************************************************************
8 + *
9 + * Copyright (c) 2008-2009 Kohei Yoshida
10 + *
11 + * Permission is hereby granted, free of charge, to any person
12 + * obtaining a copy of this software and associated documentation
13 + * files (the "Software"), to deal in the Software without
14 + * restriction, including without limitation the rights to use,
15 + * copy, modify, merge, publish, distribute, sublicense, and/or sell
16 + * copies of the Software, and to permit persons to whom the
17 + * Software is furnished to do so, subject to the following
18 + * conditions:
19 + *
20 + * The above copyright notice and this permission notice shall be
21 + * included in all copies or substantial portions of the Software.
22 + *
23 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
25 + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
27 + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
28 + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
30 + * OTHER DEALINGS IN THE SOFTWARE.
31 + *
32 + ************************************************************************/
34 +#ifndef __MDDS_FLATSEGMENTTREE_HXX__
35 +#define __MDDS_FLATSEGMENTTREE_HXX__
37 +#include <iostream>
38 +#include <cassert>
40 +#include "node.hxx"
42 +#ifdef UNIT_TEST
43 +#include <vector>
44 +#endif
46 +namespace mdds {
48 +template<typename _Key, typename _Value>
49 +class flat_segment_tree
51 +public:
52 + typedef _Key key_type;
53 + typedef _Value value_type;
55 + struct nonleaf_value_type
56 + {
57 + key_type low; /// low range value (inclusive)
58 + key_type high; /// high range value (non-inclusive)
59 + };
61 + struct leaf_value_type
62 + {
63 + key_type key;
64 + value_type value;
65 + };
67 + struct node : public node_base
68 + {
69 + union {
70 + nonleaf_value_type value_nonleaf;
71 + leaf_value_type value_leaf;
72 + };
74 + node(bool _is_leaf) :
75 + node_base(_is_leaf)
76 + {
77 + }
79 + virtual ~node()
80 + {
81 + }
83 + virtual void fill_nonleaf_value(const node_base_ptr& left_node, const node_base_ptr& right_node)
84 + {
85 + // Parent node should carry the range of all of its child nodes.
86 + if (left_node)
87 + value_nonleaf.low = left_node->is_leaf ? get_node(left_node)->value_leaf.key : get_node(left_node)->value_nonleaf.low;
88 + else
89 + // Having a left node is prerequisite.
90 + return;
92 + if (right_node)
93 + {
94 + if (right_node->is_leaf)
95 + {
96 + // When the child nodes are leaf nodes, the upper bound
97 + // must be the value of the node that comes after the
98 + // right leaf node (if such node exists).
100 + if (right_node->right)
101 + value_nonleaf.high = get_node(right_node->right)->value_leaf.key;
102 + else
103 + value_nonleaf.high = get_node(right_node)->value_leaf.key;
105 + else
107 + value_nonleaf.high = get_node(right_node)->value_nonleaf.high;
110 + else
111 + value_nonleaf.high = left_node->is_leaf ? get_node(left_node)->value_leaf.key : get_node(left_node)->value_nonleaf.high;
114 + virtual void dump_value() const
116 + using ::std::cout;
117 + if (is_leaf)
119 + cout << "(" << value_leaf.key << ")";
121 + else
123 + cout << "(" << value_nonleaf.low << "-" << value_nonleaf.high << ")";
125 + cout << " ";
128 + virtual node_base* create_new(bool leaf) const
130 + return new node(leaf);
132 + };
134 + /**
135 + * Get a pointer of concrete node type from the base pointer.
137 + * @param base_node base node pointer (ref-counted)
138 + *
139 + * @return raw pointer of concrete node type
140 + */
141 + static node* get_node(const node_base_ptr& base_node)
143 + return static_cast<node*>(base_node.get());
146 + flat_segment_tree(key_type min_val, key_type max_val, value_type init_val) :
147 + m_root_node(static_cast<node*>(NULL)),
148 + m_left_leaf(new node(true)),
149 + m_right_leaf(new node(true)),
150 + m_init_val(init_val),
151 + m_valid_tree(false)
153 + // we need to create two end nodes during initialization.
154 + get_node(m_left_leaf)->value_leaf.key = min_val;
155 + get_node(m_left_leaf)->value_leaf.value = init_val;
156 + m_left_leaf->right = m_right_leaf;
158 + get_node(m_right_leaf)->value_leaf.key = max_val;
159 + m_right_leaf->left = m_left_leaf;
162 + ~flat_segment_tree()
164 + // Go through all leaf nodes, and disconnect their links.
165 + node_base* cur_node = m_left_leaf.get();
166 + do
168 + node_base* next_node = cur_node->right.get();
169 + disconnect_node(cur_node);
170 + cur_node = next_node;
172 + while (cur_node != m_right_leaf.get());
174 + disconnect_node(m_right_leaf.get());
175 + clear_tree(m_root_node);
176 + disconnect_node(m_root_node.get());
179 + /**
180 + * Insert a new segment into the tree.
182 + * @param start start value of the segment being inserted. The value is
183 + * inclusive.
184 + * @param end end value of the segment being inserted. The value is not
185 + * inclusive.
186 + * @param val value associated with this segment.
187 + */
188 + void insert_segment(key_type start, key_type end, value_type val)
190 + if (end < get_node(m_left_leaf)->value_leaf.key || start > get_node(m_right_leaf)->value_leaf.key)
191 + // The new segment does not overlap the current interval.
192 + return;
194 + if (start < get_node(m_left_leaf)->value_leaf.key)
195 + // The start value should not be smaller than the current minimum.
196 + start = get_node(m_left_leaf)->value_leaf.key;
198 + if (end > get_node(m_right_leaf)->value_leaf.key)
199 + // The end value should not be larger than the current maximum.
200 + end = get_node(m_right_leaf)->value_leaf.key;
202 + if (start >= end)
203 + return;
205 + // Find the node with value that either equals or is greater than the
206 + // start value.
208 + node_base_ptr start_pos = get_insertion_pos_leaf(start, m_left_leaf);
209 + if (!start_pos)
210 + // Insertion position not found. Bail out.
211 + return;
213 + node_base_ptr end_pos = get_insertion_pos_leaf(end, start_pos);
214 + if (!end_pos)
215 + end_pos = m_right_leaf;
217 + node_base_ptr new_start_node;
218 + value_type old_value;
220 + // Set the start node.
222 + if (get_node(start_pos)->value_leaf.key == start)
224 + // Re-use the existing node, but save the old value for later.
226 + if (start_pos->left && get_node(start_pos->left)->value_leaf.value == val)
228 + // Extend the existing segment.
229 + old_value = get_node(start_pos)->value_leaf.value;
230 + new_start_node = start_pos->left;
232 + else
234 + // Update the value of the existing node.
235 + old_value = get_node(start_pos)->value_leaf.value;
236 + get_node(start_pos)->value_leaf.value = val;
237 + new_start_node = start_pos;
240 + else if (get_node(start_pos->left)->value_leaf.value == val)
242 + // Extend the existing segment.
243 + old_value = get_node(start_pos->left)->value_leaf.value;
244 + new_start_node = start_pos->left;
246 + else
248 + // Insert a new node before the insertion position node.
249 + node_base_ptr new_node(new node(true));
250 + get_node(new_node)->value_leaf.key = start;
251 + get_node(new_node)->value_leaf.value = val;
252 + new_start_node = new_node;
254 + node_base_ptr left_node = start_pos->left;
255 + old_value = get_node(left_node)->value_leaf.value;
257 + // Link to the left node.
258 + link_nodes(left_node, new_node);
260 + // Link to the right node.
261 + link_nodes(new_node, start_pos);
264 + node_base_ptr cur_node = new_start_node->right;
265 + while (cur_node != end_pos)
267 + // Disconnect the link between the current node and the previous node.
268 + cur_node->left->right.reset();
269 + cur_node->left.reset();
270 + old_value = get_node(cur_node)->value_leaf.value;
272 + cur_node = cur_node->right;
275 + // Set the end node.
277 + if (get_node(end_pos)->value_leaf.key == end)
279 + // The new segment ends exactly at the end node position.
281 + if (end_pos->right && get_node(end_pos)->value_leaf.value == val)
283 + // Remove this node, and connect the new start node with the
284 + // node that comes after this node.
285 + new_start_node->right = end_pos->right;
286 + if (end_pos->right)
287 + end_pos->right->left = new_start_node;
288 + disconnect_node(end_pos.get());
290 + else
292 + // Just link the new segment to this node.
293 + new_start_node->right = end_pos;
294 + end_pos->left = new_start_node;
297 + else if (old_value == val)
299 + link_nodes(new_start_node, end_pos);
301 + else
303 + // Insert a new node before the insertion position node.
304 + node_base_ptr new_node(new node(true));
305 + get_node(new_node)->value_leaf.key = end;
306 + get_node(new_node)->value_leaf.value = old_value;
308 + // Link to the left node.
309 + link_nodes(new_start_node, new_node);
311 + // Link to the right node.
312 + link_nodes(new_node, end_pos);
315 + m_valid_tree = false;
318 + /**
319 + * Remove a segment specified by the start and end key values, and shift
320 + * the remaining segments (i.e. those segments that come after the removed
321 + * segment) to left. Note that the start and end positions of the segment
322 + * being removed <b>must</b> be within the base segment span.
324 + * @param start start position of the segment being removed.
325 + * @param end end position of the segment being removed.
326 + */
327 + void shift_segment_left(key_type start, key_type end)
329 + if (start >= end)
330 + return;
332 + key_type left_leaf_key = get_node(m_left_leaf)->value_leaf.key;
333 + key_type right_leaf_key = get_node(m_right_leaf)->value_leaf.key;
334 + if (start < left_leaf_key || end < left_leaf_key)
335 + // invalid key value
336 + return;
338 + if (start > right_leaf_key || end > right_leaf_key)
339 + // invalid key value.
340 + return;
342 + node_base_ptr node_pos;
343 + if (left_leaf_key == start)
344 + node_pos = m_left_leaf;
345 + else
346 + // Get the first node with a key value equal to or greater than the
347 + // start key value. But we want to skip the leftmost node.
348 + node_pos = get_insertion_pos_leaf(start, m_left_leaf->right);
350 + if (!node_pos)
351 + return;
353 + key_type segment_size = end - start;
355 + if (node_pos == m_right_leaf)
357 + // The segment being removed begins after the last node before the
358 + // right-most node.
360 + if (right_leaf_key <= end)
362 + // The end position equals or is past the right-most node.
363 + append_new_segment(start);
365 + else
367 + // The end position stops before the right-most node. Simply
368 + // append the blank segment to the end.
369 + append_new_segment(right_leaf_key - segment_size);
371 + return;
374 + if (end < get_node(node_pos)->value_leaf.key)
376 + // The removed segment does not overlap with any nodes. Simply
377 + // shift the key values of those nodes that come after the removed
378 + // segment.
379 + shift_leaf_key_left(node_pos, m_right_leaf, segment_size);
380 + append_new_segment(right_leaf_key - segment_size);
381 + m_valid_tree = false;
382 + return;
385 + // Move the first node to the starting position, and from there search
386 + // for the first node whose key value is greater than the end value.
387 + get_node(node_pos)->value_leaf.key = start;
388 + node_base_ptr start_pos = node_pos;
389 + node_pos = node_pos->right;
390 + value_type last_seg_value = get_node(start_pos)->value_leaf.value;
391 + while (get_node(node_pos) != get_node(m_right_leaf) && get_node(node_pos)->value_leaf.key <= end)
393 + last_seg_value = get_node(node_pos)->value_leaf.value;
394 + node_base_ptr next = node_pos->right;
395 + disconnect_node(node_pos.get());
396 + node_pos = next;
399 + get_node(start_pos)->value_leaf.value = last_seg_value;
400 + start_pos->right = node_pos;
401 + node_pos->left = start_pos;
402 + if (start_pos->left && get_node(start_pos->left)->value_leaf.value == get_node(start_pos)->value_leaf.value)
404 + // Removing a segment resulted in two consecutive segments with
405 + // identical value. Combine them by removing the 2nd redundant
406 + // node.
407 + start_pos->left->right = start_pos->right;
408 + start_pos->right->left = start_pos->left;
409 + disconnect_node(start_pos.get());
412 + shift_leaf_key_left(node_pos, m_right_leaf, segment_size);
413 + m_valid_tree = false;
415 + // Insert at the end a new segment with the initial base value, for
416 + // the length of the removed segment.
417 + append_new_segment(right_leaf_key - segment_size);
420 + /**
421 + * Shift all segments that occur at or after the specified start position
422 + * to right by the size specified.
424 + * @param pos position where the right-shift occurs.
425 + * @param size amount of shift (must be greater than 0)
426 + */
427 + void shift_segment_right(key_type pos, key_type size, bool skip_start_node)
429 + if (size <= 0)
430 + return;
432 + if (pos < get_node(m_left_leaf)->value_leaf.key || get_node(m_right_leaf)->value_leaf.key <= pos)
433 + // specified position is out-of-bound
434 + return;
436 + if (get_node(m_left_leaf)->value_leaf.key == pos)
438 + // Position is at the leftmost node. Shift all the other nodes,
439 + // and insert a new node at (pos + size) position.
440 + node_base_ptr cur_node = m_left_leaf->right;
441 + shift_leaf_key_right(cur_node, m_right_leaf, size);
443 + if (get_node(m_left_leaf)->value_leaf.value != m_init_val)
445 + // The leftmost leaf node has a non-initial value. We need to
446 + // insert a new node to carry that value after the shift.
447 + node_base_ptr new_node(new node(true));
448 + get_node(new_node)->value_leaf.key = pos + size;
449 + get_node(new_node)->value_leaf.value = get_node(m_left_leaf)->value_leaf.value;
450 + get_node(m_left_leaf)->value_leaf.value = m_init_val;
451 + new_node->left = m_left_leaf;
452 + new_node->right = m_left_leaf->right;
453 + m_left_leaf->right = new_node;
456 + m_valid_tree = false;
457 + return;
460 + // Get the first node with a key value equal to or greater than the
461 + // start key value. But we want to skip the leftmost node.
462 + node_base_ptr cur_node = get_insertion_pos_leaf(pos, m_left_leaf->right);
464 + // If the point of insertion is at an existing node position, don't
465 + // shift that node but start with the one after it if that's
466 + // requested.
467 + if (skip_start_node && cur_node && get_node(cur_node)->value_leaf.key == pos)
468 + cur_node = cur_node->right;
470 + if (!cur_node)
471 + return;
473 + shift_leaf_key_right(cur_node, m_right_leaf, size);
474 + m_valid_tree = false;
477 + bool search(key_type key, value_type& value, key_type* start = NULL, key_type* end = NULL) const
479 + if (key < get_node(m_left_leaf)->value_leaf.key || get_node(m_right_leaf)->value_leaf.key <= key)
480 + // key value is out-of-bound.
481 + return false;
483 + const node* pos = get_insertion_pos_leaf(key, get_node(m_left_leaf));
484 + if (pos->value_leaf.key == key)
486 + value = pos->value_leaf.value;
487 + if (start)
488 + *start = pos->value_leaf.key;
489 + if (end && pos->right)
490 + *end = get_node(pos->right)->value_leaf.key;
491 + return true;
493 + else if (pos->left && get_node(pos->left)->value_leaf.key < key)
495 + value = get_node(pos->left)->value_leaf.value;
496 + if (start)
497 + *start = get_node(pos->left)->value_leaf.key;
498 + if (end)
499 + *end = pos->value_leaf.key;
500 + return true;
503 + return false;
506 + bool search_tree(key_type key, value_type& value, key_type* start = NULL, key_type* end = NULL) const
508 + if (!m_root_node || !m_valid_tree)
509 + {
510 + // either tree has not been built, or is in an invalid state.
511 + return false;
514 + if (key < get_node(m_left_leaf)->value_leaf.key || get_node(m_right_leaf)->value_leaf.key <= key)
515 + {
516 + // key value is out-of-bound.
517 + return false;
520 + // Descend down the tree through the last non-leaf layer.
522 + node* cur_node = get_node(m_root_node);
523 + while (true)
525 + if (cur_node->left)
527 + if (cur_node->left->is_leaf)
528 + break;
530 + const nonleaf_value_type& v = get_node(cur_node->left)->value_nonleaf;
531 + if (v.low <= key && key < v.high)
532 + {
533 + cur_node = get_node(cur_node->left);
534 + continue;
537 + else
538 + {
539 + // left child node can't be missing !
540 + return false;
543 + if (cur_node->right)
545 + const nonleaf_value_type& v = get_node(cur_node->right)->value_nonleaf;
546 + if (v.low <= key && key < v.high)
547 + {
548 + cur_node = get_node(cur_node->right);
549 + continue;
552 + return false;
555 + assert(cur_node->left->is_leaf && cur_node->right->is_leaf);
557 + key_type key1 = get_node(cur_node->left)->value_leaf.key;
558 + key_type key2 = get_node(cur_node->right)->value_leaf.key;
560 + if (key1 <= key && key < key2)
562 + cur_node = get_node(cur_node->left);
564 + else if (key2 <= key && key < cur_node->value_nonleaf.high)
566 + cur_node = get_node(cur_node->right);
568 + else
569 + cur_node = NULL;
571 + if (!cur_node)
572 + {
573 + return false;
576 + value = cur_node->value_leaf.value;
577 + if (start)
578 + *start = cur_node->value_leaf.key;
580 + if (end)
582 + assert(cur_node->right);
583 + if (cur_node->right)
584 + *end = get_node(cur_node->right)->value_leaf.key;
585 + else
586 + // This should never happen, but just in case....
587 + *end = get_node(m_right_leaf)->value_leaf.key;
590 + return true;
593 + void build_tree()
595 + if (!m_left_leaf)
596 + return;
598 + clear_tree(m_root_node);
599 + m_root_node = ::mdds::build_tree(m_left_leaf);
600 + m_valid_tree = true;
603 + bool is_tree_valid() const
605 + return m_valid_tree;
608 +#ifdef UNIT_TEST
609 + void dump_tree() const
611 + using ::std::cout;
612 + using ::std::endl;
614 + if (!m_valid_tree)
615 + assert(!"attempted to dump an invalid tree!");
617 + size_t node_count = ::mdds::dump_tree(m_root_node);
618 + size_t node_instance_count = node_base::get_instance_count();
620 + cout << "tree node count = " << node_count << " node instance count = " << node_instance_count << endl;
621 + assert(node_count == node_instance_count);
624 + void dump_leaf_nodes() const
626 + using ::std::cout;
627 + using ::std::endl;
629 + cout << "------------------------------------------" << endl;
631 + node_base_ptr cur_node = m_left_leaf;
632 + long node_id = 0;
633 + while (cur_node)
635 + cout << " node " << node_id++ << ": key = " << get_node(cur_node)->value_leaf.key
636 + << "; value = " << get_node(cur_node)->value_leaf.value
637 + << endl;
638 + cur_node = cur_node->right;
640 + cout << endl << " node instance count = " << node_base::get_instance_count() << endl;
643 + /**
644 + * Verify keys in the leaf nodes.
646 + * @param key_values vector containing key values in the left-to-right
647 + * order, including the key value of the rightmost leaf
648 + * node.
649 + */
650 + bool verify_keys(const ::std::vector<key_type>& key_values) const
652 + node* cur_node = get_node(m_left_leaf);
653 + typename ::std::vector<key_type>::const_iterator itr = key_values.begin(), itr_end = key_values.end();
654 + for (; itr != itr_end; ++itr)
656 + if (!cur_node)
657 + // Position past the right-mode node. Invalid.
658 + return false;
660 + if (cur_node->value_leaf.key != *itr)
661 + // Key values differ.
662 + return false;
664 + cur_node = get_node(cur_node->right);
667 + if (cur_node)
668 + // At this point, we expect the current node to be at the position
669 + // past the right-most node, which is NULL.
670 + return false;
672 + return true;
675 + /**
676 + * Verify values in the leaf nodes.
678 + * @param values vector containing values to verify against, in the
679 + * left-to-right order, <i>not</i> including the value of
680 + * the rightmost leaf node.
681 + */
682 + bool verify_values(const ::std::vector<value_type>& values) const
684 + node* cur_node = get_node(m_left_leaf);
685 + node* end_node = get_node(m_right_leaf);
686 + typename ::std::vector<value_type>::const_iterator itr = values.begin(), itr_end = values.end();
687 + for (; itr != itr_end; ++itr)
689 + if (cur_node == end_node || !cur_node)
690 + return false;
692 + if (cur_node->value_leaf.value != *itr)
693 + // Key values differ.
694 + return false;
696 + cur_node = get_node(cur_node->right);
699 + if (cur_node != end_node)
700 + // At this point, we expect the current node to be at the end of
701 + // range.
702 + return false;
704 + return true;
706 +#endif
708 +private:
709 + flat_segment_tree();
711 + void append_new_segment(key_type start)
713 + if (get_node(m_right_leaf->left)->value_leaf.key == start)
715 + get_node(m_right_leaf->left)->value_leaf.value = m_init_val;
716 + return;
719 +#ifdef UNIT_TEST
720 + // The start position must come after the position of the last node
721 + // before the right-most node.
722 + assert(get_node(m_right_leaf->left)->value_leaf.key < start);
723 +#endif
725 + if (get_node(m_right_leaf->left)->value_leaf.value == m_init_val)
726 + // The existing segment has the same value. No need to insert a
727 + // new segment.
728 + return;
730 + node_base_ptr new_node(new node(true));
731 + get_node(new_node)->value_leaf.key = start;
732 + get_node(new_node)->value_leaf.value = m_init_val;
733 + new_node->left = m_right_leaf->left;
734 + new_node->right = m_right_leaf;
735 + m_right_leaf->left->right = new_node;
736 + m_right_leaf->left = new_node;
737 + m_valid_tree = false;
740 + node_base_ptr get_insertion_pos_leaf(key_type key, const node_base_ptr& start_pos) const
742 + node_base_ptr cur_node = start_pos;
743 + while (cur_node)
745 + if (key <= get_node(cur_node)->value_leaf.key)
747 + // Found the insertion position.
748 + return cur_node;
750 + cur_node = cur_node->right;
752 + return node_base_ptr();
755 + const node* get_insertion_pos_leaf(key_type key, const node* start_pos) const
757 + const node* cur_node = start_pos;
758 + while (cur_node)
760 + if (key <= cur_node->value_leaf.key)
762 + // Found the insertion position.
763 + return cur_node;
765 + cur_node = get_node(cur_node->right);
767 + return NULL;
770 + static void shift_leaf_key_left(node_base_ptr& begin_node, node_base_ptr& end_node, key_type shift_value)
772 + node* cur_node_p = get_node(begin_node);
773 + node* end_node_p = get_node(end_node);
774 + while (cur_node_p != end_node_p)
776 + cur_node_p->value_leaf.key -= shift_value;
777 + cur_node_p = get_node(cur_node_p->right);
781 + static void shift_leaf_key_right(node_base_ptr& cur_node, node_base_ptr& end_node, key_type shift_value)
783 + key_type end_node_key = get_node(end_node)->value_leaf.key;
784 + while (get_node(cur_node) != get_node(end_node))
786 + get_node(cur_node)->value_leaf.key += shift_value;
787 + if (get_node(cur_node)->value_leaf.key < end_node_key)
789 + // The node is still in-bound. Keep shifting.
790 + cur_node = cur_node->right;
791 + continue;
794 + // This node has been pushed outside the end node position.
795 + // Remove all nodes that follows, and connect the previous node
796 + // with the end node.
798 + node_base_ptr last_node = cur_node->left;
799 + while (get_node(cur_node) != get_node(end_node))
801 + node_base_ptr next_node = cur_node->right;
802 + disconnect_node(cur_node);
803 + cur_node = next_node;
805 + last_node->right = end_node;
806 + end_node->left = last_node;
807 + return;
811 +private:
812 + node_base_ptr m_root_node;
813 + node_base_ptr m_left_leaf;
814 + node_base_ptr m_right_leaf;
815 + value_type m_init_val;
816 + bool m_valid_tree;
821 +#endif
822 diff --git sc/inc/mdds/node.hxx sc/inc/mdds/node.hxx
823 new file mode 100644
824 index 0000000..59749a0
825 --- /dev/null
826 +++ sc/inc/mdds/node.hxx
827 @@ -0,0 +1,307 @@
828 +/*************************************************************************
830 + * Copyright (c) 2008-2009 Kohei Yoshida
831 + *
832 + * Permission is hereby granted, free of charge, to any person
833 + * obtaining a copy of this software and associated documentation
834 + * files (the "Software"), to deal in the Software without
835 + * restriction, including without limitation the rights to use,
836 + * copy, modify, merge, publish, distribute, sublicense, and/or sell
837 + * copies of the Software, and to permit persons to whom the
838 + * Software is furnished to do so, subject to the following
839 + * conditions:
840 + *
841 + * The above copyright notice and this permission notice shall be
842 + * included in all copies or substantial portions of the Software.
843 + *
844 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
845 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
846 + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
847 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
848 + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
849 + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
850 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
851 + * OTHER DEALINGS IN THE SOFTWARE.
853 + ************************************************************************/
855 +#ifndef __MDDS_NODE_HXX__
856 +#define __MDDS_NODE_HXX__
858 +#include <iostream>
859 +#include <list>
860 +#include <cassert>
862 +//#define DEBUG_NODE_BASE 1
864 +#define USE_INTRUSIVE_PTR 0
866 +#if USE_INTRUSIVE_PTR
867 +#include <boost/intrusive_ptr.hpp>
868 +#else
869 +#include <boost/shared_ptr.hpp>
870 +#endif
872 +namespace mdds {
874 +struct intrusive_ref_base
876 +#if USE_INTRUSIVE_PTR
877 + size_t _refcount;
879 + intrusive_ref_base() :
880 + _refcount(0) {}
881 +#endif
882 + virtual ~intrusive_ref_base() {}
885 +#if USE_INTRUSIVE_PTR
886 +inline void intrusive_ptr_add_ref(intrusive_ref_base* p)
888 + ++p->_refcount;
891 +inline void intrusive_ptr_release(intrusive_ref_base* p)
893 + --p->_refcount;
894 + if (!p->_refcount)
895 + delete p;
897 +#endif
899 +#ifdef DEBUG_NODE_BASE
900 +size_t node_instance_count = 0;
901 +#endif
903 +struct node_base;
904 +#if USE_INTRUSIVE_PTR
905 +typedef ::boost::intrusive_ptr<node_base> node_base_ptr;
906 +#else
907 +typedef ::boost::shared_ptr<node_base> node_base_ptr;
908 +#endif
910 +struct node_base : public intrusive_ref_base
912 + static size_t get_instance_count()
914 +#ifdef DEBUG_NODE_BASE
915 + return node_instance_count;
916 +#else
917 + return 0;
918 +#endif
920 + node_base_ptr parent; /// parent node
921 + node_base_ptr left; /// left child node or previous sibling if it's a leaf node.
922 + node_base_ptr right; /// right child node or next sibling if it's aleaf node.
923 + bool is_leaf;
925 + node_base(bool _is_leaf) :
926 + intrusive_ref_base(),
927 + parent(static_cast<node_base*>(NULL)),
928 + left(static_cast<node_base*>(NULL)),
929 + right(static_cast<node_base*>(NULL)),
930 + is_leaf(_is_leaf)
932 +#ifdef DEBUG_NODE_BASE
933 + ++node_instance_count;
934 +#endif
937 + virtual ~node_base()
939 +#ifdef DEBUG_NODE_BASE
940 + --node_instance_count;
941 +#endif
944 + // These methods are specific to concrete class implementation.
946 + virtual void fill_nonleaf_value(const node_base_ptr& left_node, const node_base_ptr& right_node) = 0;
947 + virtual void dump_value() const = 0;
948 + virtual node_base* create_new(bool leaf) const = 0;
951 +template<typename _NodePtr>
952 +void disconnect_node(_NodePtr p)
954 + if (!p)
955 + return;
957 + p->left.reset();
958 + p->right.reset();
959 + p->parent.reset();
962 +template<typename _NodePtr>
963 +void link_nodes(_NodePtr& left, _NodePtr& right)
965 + left->right = right;
966 + right->left = left;
969 +/**
970 + * Disconnect all non-leaf nodes so that their ref-counted instances will
971 + * all get destroyed afterwards.
972 + */
973 +template<typename _NodePtr>
974 +void clear_tree(const _NodePtr& node)
976 + if (!node)
977 + // Nothing to do.
978 + return;
980 + if (node->is_leaf)
982 + node->parent.reset();
983 + return;
986 + clear_tree(node->left);
987 + clear_tree(node->right);
988 + disconnect_node(node.get());
991 +template<typename _NodePtr>
992 +_NodePtr make_parent_node(const _NodePtr& node1, const _NodePtr& node2)
994 + _NodePtr parent_node(node1->create_new(false));
995 + node1->parent = parent_node;
996 + parent_node->left = node1;
997 + if (node2)
999 + node2->parent = parent_node;
1000 + parent_node->right = node2;
1003 + parent_node->fill_nonleaf_value(node1, node2);
1004 + return parent_node;
1007 +template<typename _NodePtr>
1008 +_NodePtr build_tree(const _NodePtr& left_leaf_node)
1010 + if (!left_leaf_node)
1011 + // The left leaf node is empty. Nothing to build.
1012 + return _NodePtr();
1014 + _NodePtr node1, node2;
1015 + node1 = left_leaf_node;
1017 + ::std::list<_NodePtr> node_list;
1018 + while (true)
1020 + node2 = node1->right;
1021 + _NodePtr parent_node = make_parent_node(node1, node2);
1022 + node_list.push_back(parent_node);
1024 + if (!node2 || !node2->right)
1025 + // no more nodes. Break out of the loop.
1026 + break;
1028 + node1 = node2->right;
1031 + return build_tree_non_leaf(node_list);
1034 +template<typename _NodePtr>
1035 +_NodePtr build_tree_non_leaf(const ::std::list<_NodePtr>& node_list)
1037 + size_t node_count = node_list.size();
1038 + if (node_count == 1)
1040 + return node_list.front();
1042 + else if (node_count == 0)
1043 + return _NodePtr();
1045 + ::std::list<_NodePtr> new_node_list;
1046 + _NodePtr node_pair[2];
1047 + typename ::std::list<_NodePtr>::const_iterator itr = node_list.begin();
1048 + typename ::std::list<_NodePtr>::const_iterator itrEnd = node_list.end();
1049 + for (bool even_itr = false; itr != itrEnd; ++itr, even_itr = !even_itr)
1051 + node_pair[even_itr] = *itr;
1052 + if (even_itr)
1054 + _NodePtr parent_node = make_parent_node(node_pair[0], node_pair[1]);
1055 + node_pair[0].reset();
1056 + node_pair[1].reset();
1057 + new_node_list.push_back(parent_node);
1061 + if (node_pair[0])
1063 + // Un-paired node still needs a parent...
1064 + _NodePtr parent_node = make_parent_node(node_pair[0], _NodePtr());
1065 + node_pair[0].reset();
1066 + node_pair[1].reset();
1067 + new_node_list.push_back(parent_node);
1070 + // Move up one level, and do the same procedure until the root node is reached.
1071 + return build_tree_non_leaf(new_node_list);
1074 +#ifdef UNIT_TEST
1075 +template<typename _NodePtr>
1076 +size_t dump_tree_layer(const ::std::list<_NodePtr>& node_list, unsigned int level)
1078 + using ::std::cout;
1079 + using ::std::endl;
1081 + if (node_list.empty())
1082 + return 0;
1084 + size_t node_count = node_list.size();
1086 + bool isLeaf = node_list.front()->is_leaf;
1087 + cout << "level " << level << " (" << (isLeaf?"leaf":"non-leaf") << ")" << endl;
1089 + ::std::list<_NodePtr> newList;
1090 + typename ::std::list<_NodePtr>::const_iterator itr = node_list.begin(), itrEnd = node_list.end();
1091 + for (; itr != itrEnd; ++itr)
1093 + const _NodePtr& p = *itr;
1094 + if (!p)
1096 + cout << "(x) ";
1097 + continue;
1100 + p->dump_value();
1102 + if (p->is_leaf)
1103 + continue;
1105 + if (p->left)
1107 + newList.push_back(p->left);
1108 + if (p->right)
1109 + newList.push_back(p->right);
1112 + cout << endl;
1114 + if (!newList.empty())
1115 + node_count += dump_tree_layer(newList, level+1);
1117 + return node_count;
1120 +template<typename _NodePtr>
1121 +size_t dump_tree(const _NodePtr& root_node)
1123 + if (!root_node)
1124 + return 0;
1126 + ::std::list<_NodePtr> node_list;
1127 + node_list.push_back(root_node);
1128 + return dump_tree_layer(node_list, 0);
1130 +#endif
1134 +#endif
1135 diff --git sc/inc/segmenttree.hxx sc/inc/segmenttree.hxx
1136 new file mode 100644
1137 index 0000000..466f9ed
1138 --- /dev/null
1139 +++ sc/inc/segmenttree.hxx
1140 @@ -0,0 +1,89 @@
1141 +/*************************************************************************
1143 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1144 + *
1145 + * Copyright 2008 by Sun Microsystems, Inc.
1147 + * OpenOffice.org - a multi-platform office productivity suite
1149 + * $RCSfile: compressedarray.hxx,v $
1150 + * $Revision: 1.7.32.2 $
1152 + * This file is part of OpenOffice.org.
1154 + * OpenOffice.org is free software: you can redistribute it and/or modify
1155 + * it under the terms of the GNU Lesser General Public License version 3
1156 + * only, as published by the Free Software Foundation.
1158 + * OpenOffice.org is distributed in the hope that it will be useful,
1159 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1160 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1161 + * GNU Lesser General Public License version 3 for more details
1162 + * (a copy is included in the LICENSE file that accompanied this code).
1164 + * You should have received a copy of the GNU Lesser General Public License
1165 + * version 3 along with OpenOffice.org. If not, see
1166 + * <http://www.openoffice.org/license.html>
1167 + * for a copy of the LGPLv3 License.
1169 + ************************************************************************/
1171 +#ifndef SC_SEGMENTTREE_HXX
1172 +#define SC_SEGMENTTREE_HXX
1174 +#include "address.hxx"
1176 +#include <memory>
1178 +class ScFlatBoolSegmentsImpl;
1180 +class ScFlatBoolRowSegments
1182 +public:
1183 + struct RangeData
1185 + SCROW mnRow1;
1186 + SCROW mnRow2;
1187 + bool mbValue;
1188 + };
1189 + ScFlatBoolRowSegments();
1190 + ~ScFlatBoolRowSegments();
1192 + void setTrue(SCROW nRow1, SCROW nRow2);
1193 + void setFalse(SCROW nRow1, SCROW nRow2);
1194 + bool getValue(SCROW nRow);
1195 + bool getRangeData(SCROW nRow, RangeData& rData);
1196 + void removeSegment(SCROW nRow1, SCROW nRow2);
1197 + void insertSegment(SCROW nRow, SCROW nSize, bool bSkipStartBoundary);
1199 +private:
1200 + ::std::auto_ptr<ScFlatBoolSegmentsImpl> mpImpl;
1203 +// ============================================================================
1205 +class ScFlatBoolColSegments
1207 +public:
1208 + struct RangeData
1210 + SCCOL mnCol1;
1211 + SCCOL mnCol2;
1212 + bool mbValue;
1213 + };
1214 + ScFlatBoolColSegments();
1215 + ~ScFlatBoolColSegments();
1217 + void setTrue(SCCOL nCol1, SCCOL nCol2);
1218 + void setFalse(SCCOL nCol1, SCCOL nCol2);
1219 + bool getValue(SCCOL nCol);
1220 + bool getRangeData(SCCOL nCol, RangeData& rData);
1221 + void removeSegment(SCCOL nCol1, SCCOL nCol2);
1222 + void insertSegment(SCCOL nCol, SCCOL nSize, bool bSkipStartBoundary);
1224 +private:
1225 + ::std::auto_ptr<ScFlatBoolSegmentsImpl> mpImpl;
1229 +#endif
1230 diff --git sc/source/core/data/makefile.mk sc/source/core/data/makefile.mk
1231 index c631bb4..5fbec41 100644
1232 --- sc/source/core/data/makefile.mk
1233 +++ sc/source/core/data/makefile.mk
1234 @@ -102,6 +102,7 @@ SLOFILES = \
1235 $(SLO)$/phonetic.obj \
1236 $(SLO)$/poolhelp.obj \
1237 $(SLO)$/scimpexpmsg.obj \
1238 + $(SLO)$/segmenttree.obj \
1239 $(SLO)$/sortparam.obj \
1240 $(SLO)$/stlpool.obj \
1241 $(SLO)$/stlsheet.obj \
1242 @@ -147,7 +148,8 @@ EXCEPTIONSFILES= \
1243 $(SLO)$/dbdocutl.obj \
1244 $(SLO)$/dptabsrc.obj \
1245 $(SLO)$/drwlayer.obj \
1246 - $(SLO)$/globalx.obj
1247 + $(SLO)$/globalx.obj \
1248 + $(SLO)$/segmenttree.obj
1250 .IF "$(OS)$(COM)$(CPUNAME)"=="LINUXGCCSPARC"
1251 NOOPTFILES= \
1252 diff --git sc/source/core/data/segmenttree.cxx sc/source/core/data/segmenttree.cxx
1253 new file mode 100644
1254 index 0000000..be8e408
1255 --- /dev/null
1256 +++ sc/source/core/data/segmenttree.cxx
1257 @@ -0,0 +1,225 @@
1258 +/*************************************************************************
1260 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1261 + *
1262 + * Copyright 2008 by Sun Microsystems, Inc.
1264 + * OpenOffice.org - a multi-platform office productivity suite
1266 + * $RCSfile: compressedarray.hxx,v $
1267 + * $Revision: 1.7.32.2 $
1269 + * This file is part of OpenOffice.org.
1271 + * OpenOffice.org is free software: you can redistribute it and/or modify
1272 + * it under the terms of the GNU Lesser General Public License version 3
1273 + * only, as published by the Free Software Foundation.
1275 + * OpenOffice.org is distributed in the hope that it will be useful,
1276 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1277 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1278 + * GNU Lesser General Public License version 3 for more details
1279 + * (a copy is included in the LICENSE file that accompanied this code).
1281 + * You should have received a copy of the GNU Lesser General Public License
1282 + * version 3 along with OpenOffice.org. If not, see
1283 + * <http://www.openoffice.org/license.html>
1284 + * for a copy of the LGPLv3 License.
1286 + ************************************************************************/
1288 +// MARKER(update_precomp.py): autogen include statement, do not remove
1289 +#include "precompiled_sc.hxx"
1291 +#include "segmenttree.hxx"
1292 +#include "mdds/flatsegmenttree.hxx"
1294 +#define USE_TREE_SEARCH 1
1296 +class ScFlatBoolSegmentsImpl
1298 +public:
1299 + struct RangeData
1301 + SCCOLROW mnPos1;
1302 + SCCOLROW mnPos2;
1303 + bool mbValue;
1304 + };
1305 + ScFlatBoolSegmentsImpl(SCCOLROW nMax);
1306 + ~ScFlatBoolSegmentsImpl();
1308 + void setTrue(SCCOLROW nPos1, SCCOLROW nPos2);
1309 + void setFalse(SCCOLROW nPos1, SCCOLROW nPos2);
1310 + bool getValue(SCCOLROW nPos);
1311 + bool getRangeData(SCCOLROW nPos, RangeData& rData);
1312 + void removeSegment(SCCOLROW nPos1, SCCOLROW nPos2);
1313 + void insertSegment(SCCOLROW nPos, SCCOLROW nSize, bool bSkipStartBoundary);
1315 +private:
1316 + ScFlatBoolSegmentsImpl();
1317 + ScFlatBoolSegmentsImpl(const ScFlatBoolSegmentsImpl&);
1319 + ::mdds::flat_segment_tree<SCCOLROW, bool> maSegments;
1322 +ScFlatBoolSegmentsImpl::ScFlatBoolSegmentsImpl(SCCOLROW nMax) :
1323 + maSegments(0, nMax+1, false)
1327 +ScFlatBoolSegmentsImpl::~ScFlatBoolSegmentsImpl()
1331 +void ScFlatBoolSegmentsImpl::setTrue(SCCOLROW nPos1, SCCOLROW nPos2)
1333 + maSegments.insert_segment(nPos1, nPos2+1, true);
1336 +void ScFlatBoolSegmentsImpl::setFalse(SCCOLROW nPos1, SCCOLROW nPos2)
1338 + maSegments.insert_segment(nPos1, nPos2+1, false);
1341 +bool ScFlatBoolSegmentsImpl::getValue(SCCOLROW nPos)
1343 + bool bValue = false;
1344 +#if USE_TREE_SEARCH
1345 + if (!maSegments.is_tree_valid())
1346 + maSegments.build_tree();
1348 + maSegments.search_tree(nPos, bValue);
1349 +#else
1350 + maSegments.search(nPos, bValue);
1351 +#endif
1352 + return bValue;
1355 +bool ScFlatBoolSegmentsImpl::getRangeData(SCCOLROW nPos, RangeData& rData)
1357 +#if USE_TREE_SEARCH
1358 + if (!maSegments.is_tree_valid())
1359 + maSegments.build_tree();
1360 +#endif
1362 + bool bValue;
1363 + SCCOLROW nPos1, nPos2;
1364 +#if USE_TREE_SEARCH
1365 + if (!maSegments.search_tree(nPos, bValue, &nPos1, &nPos2))
1366 + return false;
1367 +#else
1368 + if (!maSegments.search(nPos, bValue, &nPos1, &nPos2))
1369 + return false;
1370 +#endif
1372 + rData.mnPos1 = nPos1;
1373 + rData.mnPos2 = nPos2-1; // end point is not inclusive.
1374 + rData.mbValue = bValue;
1375 + return true;
1378 +void ScFlatBoolSegmentsImpl::removeSegment(SCCOLROW nPos1, SCCOLROW nPos2)
1380 + maSegments.shift_segment_left(nPos1, nPos2);
1383 +void ScFlatBoolSegmentsImpl::insertSegment(SCCOLROW nPos, SCCOLROW nSize, bool bSkipStartBoundary)
1385 + maSegments.shift_segment_right(nPos, nSize, bSkipStartBoundary);
1388 +// ============================================================================
1390 +ScFlatBoolRowSegments::ScFlatBoolRowSegments() :
1391 + mpImpl(new ScFlatBoolSegmentsImpl(static_cast<SCCOLROW>(MAXROW)))
1395 +ScFlatBoolRowSegments::~ScFlatBoolRowSegments()
1399 +void ScFlatBoolRowSegments::setTrue(SCROW nRow1, SCROW nRow2)
1401 + mpImpl->setTrue(static_cast<SCCOLROW>(nRow1), static_cast<SCCOLROW>(nRow2));
1404 +void ScFlatBoolRowSegments::setFalse(SCROW nRow1, SCROW nRow2)
1406 + mpImpl->setFalse(static_cast<SCCOLROW>(nRow1), static_cast<SCCOLROW>(nRow2));
1409 +bool ScFlatBoolRowSegments::getValue(SCROW nRow)
1411 + return mpImpl->getValue(static_cast<SCCOLROW>(nRow));
1414 +bool ScFlatBoolRowSegments::getRangeData(SCROW nRow, RangeData& rData)
1416 + ScFlatBoolSegmentsImpl::RangeData aData;
1417 + if (!mpImpl->getRangeData(static_cast<SCCOLROW>(nRow), aData))
1418 + return false;
1420 + rData.mbValue = aData.mbValue;
1421 + rData.mnRow1 = static_cast<SCROW>(aData.mnPos1);
1422 + rData.mnRow2 = static_cast<SCROW>(aData.mnPos2);
1423 + return true;
1426 +void ScFlatBoolRowSegments::removeSegment(SCROW nRow1, SCROW nRow2)
1428 + mpImpl->removeSegment(static_cast<SCCOLROW>(nRow1), static_cast<SCCOLROW>(nRow2));
1431 +void ScFlatBoolRowSegments::insertSegment(SCROW nRow, SCROW nSize, bool bSkipStartBoundary)
1433 + mpImpl->insertSegment(static_cast<SCCOLROW>(nRow), static_cast<SCCOLROW>(nSize), bSkipStartBoundary);
1436 +// ============================================================================
1438 +ScFlatBoolColSegments::ScFlatBoolColSegments() :
1439 + mpImpl(new ScFlatBoolSegmentsImpl(static_cast<SCCOLROW>(MAXCOL)))
1443 +ScFlatBoolColSegments::~ScFlatBoolColSegments()
1447 +void ScFlatBoolColSegments::setTrue(SCCOL nCol1, SCCOL nCol2)
1449 + mpImpl->setTrue(static_cast<SCCOLROW>(nCol1), static_cast<SCCOLROW>(nCol2));
1452 +void ScFlatBoolColSegments::setFalse(SCCOL nCol1, SCCOL nCol2)
1454 + mpImpl->setFalse(static_cast<SCCOLROW>(nCol1), static_cast<SCCOLROW>(nCol2));
1457 +bool ScFlatBoolColSegments::getValue(SCCOL nCol)
1459 + return mpImpl->getValue(static_cast<SCCOLROW>(nCol));
1462 +bool ScFlatBoolColSegments::getRangeData(SCCOL nCol, RangeData& rData)
1464 + ScFlatBoolSegmentsImpl::RangeData aData;
1465 + if (!mpImpl->getRangeData(static_cast<SCCOLROW>(nCol), aData))
1466 + return false;
1468 + rData.mbValue = aData.mbValue;
1469 + rData.mnCol1 = static_cast<SCCOL>(aData.mnPos1);
1470 + rData.mnCol2 = static_cast<SCCOL>(aData.mnPos2);
1471 + return true;
1474 +void ScFlatBoolColSegments::removeSegment(SCCOL nCol1, SCCOL nCol2)
1476 + mpImpl->removeSegment(static_cast<SCCOLROW>(nCol1), static_cast<SCCOLROW>(nCol2));
1479 +void ScFlatBoolColSegments::insertSegment(SCCOL nCol, SCCOL nSize, bool bSkipStartBoundary)
1481 + mpImpl->insertSegment(static_cast<SCCOLROW>(nCol), static_cast<SCCOLROW>(nSize), bSkipStartBoundary);