update ooo310-m15
[ooovba.git] / applied_patches / 0868-calc-perf-flat-segment-tree.diff
blobe7ee4c311b87216e27dbb26f6e26cdd6e4f89f87
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,761 @@
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.
323 + * @param start start value of the segment being removed.
324 + * @param end end value of the segment being removed.
325 + */
326 + void shift_segment_left(key_type start, key_type end)
328 + if (start >= end)
329 + return;
331 + key_type left_leaf_key = get_node(m_left_leaf)->value_leaf.key;
332 + key_type right_leaf_key = get_node(m_right_leaf)->value_leaf.key;
333 + if (start < left_leaf_key || end < left_leaf_key)
334 + // invalid key value
335 + return;
337 + if (start > right_leaf_key || end > right_leaf_key)
338 + // invalid key value.
339 + return;
341 + node_base_ptr node_pos;
342 + if (left_leaf_key == start)
343 + node_pos = m_left_leaf;
344 + else
345 + // Get the first node with a key value equal to or greater than the
346 + // start key value. But we want to skip the leftmost node.
347 + node_pos = get_insertion_pos_leaf(start, m_left_leaf->right);
349 + if (!node_pos)
350 + return;
352 + key_type segment_size = end - start;
354 + if (end < get_node(node_pos)->value_leaf.key)
356 + // The removed segment does not overlap with any nodes. Simply
357 + // shift the key values of those nodes that come after the removed
358 + // segment.
359 + shift_leaf_key_left(node_pos, m_right_leaf, segment_size);
360 + m_valid_tree = false;
361 + return;
364 + // Move the first node to the starting position, and from there search
365 + // for the first node whose key value is greater than the end value.
366 + get_node(node_pos)->value_leaf.key = start;
367 + node_base_ptr start_pos = node_pos;
368 + node_pos = node_pos->right;
369 + value_type last_seg_value = get_node(start_pos)->value_leaf.value;
370 + while (get_node(node_pos) != get_node(m_right_leaf) && get_node(node_pos)->value_leaf.key <= end)
372 + last_seg_value = get_node(node_pos)->value_leaf.value;
373 + node_base_ptr next = node_pos->right;
374 + disconnect_node(node_pos.get());
375 + node_pos = next;
378 + get_node(start_pos)->value_leaf.value = last_seg_value;
379 + start_pos->right = node_pos;
380 + node_pos->left = start_pos;
381 + if (start_pos->left && get_node(start_pos->left)->value_leaf.value == get_node(start_pos)->value_leaf.value)
383 + // Removing a segment resulted in two consecutive segments with
384 + // identical value. Combine them by removing the 2nd redundant
385 + // node.
386 + start_pos->left->right = start_pos->right;
387 + start_pos->right->left = start_pos->left;
388 + disconnect_node(start_pos.get());
391 + shift_leaf_key_left(node_pos, m_right_leaf, segment_size);
392 + m_valid_tree = false;
395 + /**
396 + * Shift all segments that occur at or after the specified start position
397 + * to right by the size specified.
399 + * @param pos position where the right-shift occurs.
400 + * @param size amount of shift (must be greater than 0)
401 + */
402 + void shift_segment_right(key_type pos, key_type size, bool skip_start_node)
404 + if (size <= 0)
405 + return;
407 + if (pos < get_node(m_left_leaf)->value_leaf.key || get_node(m_right_leaf)->value_leaf.key <= pos)
408 + // specified position is out-of-bound
409 + return;
411 + if (get_node(m_left_leaf)->value_leaf.key == pos)
413 + // Position is at the leftmost node. Shift all the other nodes,
414 + // and insert a new node at (pos + size) position.
415 + node_base_ptr cur_node = m_left_leaf->right;
416 + shift_leaf_key_right(cur_node, m_right_leaf, size);
418 + if (get_node(m_left_leaf)->value_leaf.value != m_init_val)
420 + // The leftmost leaf node has a non-initial value. We need to
421 + // insert a new node to carry that value after the shift.
422 + node_base_ptr new_node(new node(true));
423 + get_node(new_node)->value_leaf.key = pos + size;
424 + get_node(new_node)->value_leaf.value = get_node(m_left_leaf)->value_leaf.value;
425 + get_node(m_left_leaf)->value_leaf.value = m_init_val;
426 + new_node->left = m_left_leaf;
427 + new_node->right = m_left_leaf->right;
428 + m_left_leaf->right = new_node;
431 + m_valid_tree = false;
432 + return;
435 + // Get the first node with a key value equal to or greater than the
436 + // start key value. But we want to skip the leftmost node.
437 + node_base_ptr cur_node = get_insertion_pos_leaf(pos, m_left_leaf->right);
439 + // If the point of insertion is at an existing node position, don't
440 + // shift that node but start with the one after it if that's
441 + // requested.
442 + if (skip_start_node && cur_node && get_node(cur_node)->value_leaf.key == pos)
443 + cur_node = cur_node->right;
445 + if (!cur_node)
446 + return;
448 + shift_leaf_key_right(cur_node, m_right_leaf, size);
449 + m_valid_tree = false;
452 + bool search(key_type key, value_type& value, key_type* start = NULL, key_type* end = NULL) const
454 + if (key < get_node(m_left_leaf)->value_leaf.key || get_node(m_right_leaf)->value_leaf.key <= key)
455 + // key value is out-of-bound.
456 + return false;
458 + const node* pos = get_insertion_pos_leaf(key, get_node(m_left_leaf));
459 + if (pos->value_leaf.key == key)
461 + value = pos->value_leaf.value;
462 + if (start)
463 + *start = pos->value_leaf.key;
464 + if (end && pos->right)
465 + *end = get_node(pos->right)->value_leaf.key;
466 + return true;
468 + else if (pos->left && get_node(pos->left)->value_leaf.key < key)
470 + value = get_node(pos->left)->value_leaf.value;
471 + if (start)
472 + *start = get_node(pos->left)->value_leaf.key;
473 + if (end)
474 + *end = pos->value_leaf.key;
475 + return true;
478 + return false;
481 + bool search_tree(key_type key, value_type& value, key_type* start = NULL, key_type* end = NULL) const
483 + if (!m_root_node || !m_valid_tree)
484 + {
485 + // either tree has not been built, or is in an invalid state.
486 + return false;
489 + if (key < get_node(m_left_leaf)->value_leaf.key || get_node(m_right_leaf)->value_leaf.key <= key)
490 + {
491 + // key value is out-of-bound.
492 + return false;
495 + // Descend down the tree through the last non-leaf layer.
497 + node* cur_node = get_node(m_root_node);
498 + while (true)
500 + if (cur_node->left)
502 + if (cur_node->left->is_leaf)
503 + break;
505 + const nonleaf_value_type& v = get_node(cur_node->left)->value_nonleaf;
506 + if (v.low <= key && key < v.high)
507 + {
508 + cur_node = get_node(cur_node->left);
509 + continue;
512 + else
513 + {
514 + // left child node can't be missing !
515 + return false;
518 + if (cur_node->right)
520 + const nonleaf_value_type& v = get_node(cur_node->right)->value_nonleaf;
521 + if (v.low <= key && key < v.high)
522 + {
523 + cur_node = get_node(cur_node->right);
524 + continue;
527 + return false;
530 + assert(cur_node->left->is_leaf && cur_node->right->is_leaf);
532 + key_type key1 = get_node(cur_node->left)->value_leaf.key;
533 + key_type key2 = get_node(cur_node->right)->value_leaf.key;
535 + if (key1 <= key && key < key2)
537 + cur_node = get_node(cur_node->left);
539 + else if (key2 <= key && key < cur_node->value_nonleaf.high)
541 + cur_node = get_node(cur_node->right);
543 + else
544 + cur_node = NULL;
546 + if (!cur_node)
547 + {
548 + return false;
551 + value = cur_node->value_leaf.value;
552 + if (start)
553 + *start = cur_node->value_leaf.key;
555 + if (end)
557 + assert(cur_node->right);
558 + if (cur_node->right)
559 + *end = get_node(cur_node->right)->value_leaf.key;
560 + else
561 + // This should never happen, but just in case....
562 + *end = get_node(m_right_leaf)->value_leaf.key;
565 + return true;
568 + void build_tree()
570 + if (!m_left_leaf)
571 + return;
573 + clear_tree(m_root_node);
574 + m_root_node = ::mdds::build_tree(m_left_leaf);
575 + m_valid_tree = true;
578 + bool is_tree_valid() const
580 + return m_valid_tree;
583 +#ifdef UNIT_TEST
584 + void dump_tree() const
586 + using ::std::cout;
587 + using ::std::endl;
589 + if (!m_valid_tree)
590 + assert(!"attempted to dump an invalid tree!");
592 + size_t node_count = ::mdds::dump_tree(m_root_node);
593 + size_t node_instance_count = node_base::get_instance_count();
595 + cout << "tree node count = " << node_count << " node instance count = " << node_instance_count << endl;
596 + assert(node_count == node_instance_count);
599 + void dump_leaf_nodes() const
601 + using ::std::cout;
602 + using ::std::endl;
604 + cout << "------------------------------------------" << endl;
606 + node_base_ptr cur_node = m_left_leaf;
607 + long node_id = 0;
608 + while (cur_node)
610 + cout << " node " << node_id++ << ": key = " << get_node(cur_node)->value_leaf.key
611 + << "; value = " << get_node(cur_node)->value_leaf.value
612 + << endl;
613 + cur_node = cur_node->right;
615 + cout << endl << " node instance count = " << node_base::get_instance_count() << endl;
618 + /**
619 + * Verify keys in the leaf nodes.
621 + * @param key_values vector containing key values in the left-to-right
622 + * order, including the key value of the rightmost leaf
623 + * node.
624 + */
625 + bool verify_keys(const ::std::vector<key_type>& key_values) const
627 + node* cur_node = get_node(m_left_leaf);
628 + typename ::std::vector<key_type>::const_iterator itr = key_values.begin(), itr_end = key_values.end();
629 + for (; itr != itr_end; ++itr)
631 + if (!cur_node)
632 + // Position past the right-mode node. Invalid.
633 + return false;
635 + if (cur_node->value_leaf.key != *itr)
636 + // Key values differ.
637 + return false;
639 + cur_node = get_node(cur_node->right);
642 + if (cur_node)
643 + // At this point, we expect the current node to be at the position
644 + // past the right-most node, which is NULL.
645 + return false;
647 + return true;
650 + /**
651 + * Verify values in the leaf nodes.
653 + * @param values vector containing values to verify against, in the
654 + * left-to-right order, <i>not</i> including the value of
655 + * the rightmost leaf node.
656 + */
657 + bool verify_values(const ::std::vector<value_type>& values) const
659 + node* cur_node = get_node(m_left_leaf);
660 + node* end_node = get_node(m_right_leaf);
661 + typename ::std::vector<value_type>::const_iterator itr = values.begin(), itr_end = values.end();
662 + for (; itr != itr_end; ++itr)
664 + if (cur_node == end_node || !cur_node)
665 + return false;
667 + if (cur_node->value_leaf.value != *itr)
668 + // Key values differ.
669 + return false;
671 + cur_node = get_node(cur_node->right);
674 + if (cur_node != end_node)
675 + // At this point, we expect the current node to be at the end of
676 + // range.
677 + return false;
679 + return true;
681 +#endif
683 +private:
684 + flat_segment_tree();
686 + node_base_ptr get_insertion_pos_leaf(key_type key, const node_base_ptr& start_pos) const
688 + node_base_ptr cur_node = start_pos;
689 + while (cur_node)
691 + if (key <= get_node(cur_node)->value_leaf.key)
693 + // Found the insertion position.
694 + return cur_node;
696 + cur_node = cur_node->right;
698 + return node_base_ptr();
701 + const node* get_insertion_pos_leaf(key_type key, const node* start_pos) const
703 + const node* cur_node = start_pos;
704 + while (cur_node)
706 + if (key <= cur_node->value_leaf.key)
708 + // Found the insertion position.
709 + return cur_node;
711 + cur_node = get_node(cur_node->right);
713 + return NULL;
716 + static void shift_leaf_key_left(node_base_ptr& begin_node, node_base_ptr& end_node, key_type shift_value)
718 + node* cur_node_p = get_node(begin_node);
719 + node* end_node_p = get_node(end_node);
720 + while (cur_node_p != end_node_p)
722 + cur_node_p->value_leaf.key -= shift_value;
723 + cur_node_p = get_node(cur_node_p->right);
727 + static void shift_leaf_key_right(node_base_ptr& cur_node, node_base_ptr& end_node, key_type shift_value)
729 + key_type end_node_key = get_node(end_node)->value_leaf.key;
730 + while (get_node(cur_node) != get_node(end_node))
732 + get_node(cur_node)->value_leaf.key += shift_value;
733 + if (get_node(cur_node)->value_leaf.key < end_node_key)
735 + // The node is still in-bound. Keep shifting.
736 + cur_node = cur_node->right;
737 + continue;
740 + // This node has been pushed outside the end node position.
741 + // Remove all nodes that follows, and connect the previous node
742 + // with the end node.
744 + node_base_ptr last_node = cur_node->left;
745 + while (get_node(cur_node) != get_node(end_node))
747 + node_base_ptr next_node = cur_node->right;
748 + disconnect_node(cur_node);
749 + cur_node = next_node;
751 + last_node->right = end_node;
752 + end_node->left = last_node;
753 + return;
757 +private:
758 + node_base_ptr m_root_node;
759 + node_base_ptr m_left_leaf;
760 + node_base_ptr m_right_leaf;
761 + value_type m_init_val;
762 + bool m_valid_tree;
767 +#endif
768 diff --git sc/inc/mdds/node.hxx sc/inc/mdds/node.hxx
769 new file mode 100644
770 index 0000000..59749a0
771 --- /dev/null
772 +++ sc/inc/mdds/node.hxx
773 @@ -0,0 +1,307 @@
774 +/*************************************************************************
776 + * Copyright (c) 2008-2009 Kohei Yoshida
777 + *
778 + * Permission is hereby granted, free of charge, to any person
779 + * obtaining a copy of this software and associated documentation
780 + * files (the "Software"), to deal in the Software without
781 + * restriction, including without limitation the rights to use,
782 + * copy, modify, merge, publish, distribute, sublicense, and/or sell
783 + * copies of the Software, and to permit persons to whom the
784 + * Software is furnished to do so, subject to the following
785 + * conditions:
786 + *
787 + * The above copyright notice and this permission notice shall be
788 + * included in all copies or substantial portions of the Software.
789 + *
790 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
791 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
792 + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
793 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
794 + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
795 + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
796 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
797 + * OTHER DEALINGS IN THE SOFTWARE.
799 + ************************************************************************/
801 +#ifndef __MDDS_NODE_HXX__
802 +#define __MDDS_NODE_HXX__
804 +#include <iostream>
805 +#include <list>
806 +#include <cassert>
808 +//#define DEBUG_NODE_BASE 1
810 +#define USE_INTRUSIVE_PTR 0
812 +#if USE_INTRUSIVE_PTR
813 +#include <boost/intrusive_ptr.hpp>
814 +#else
815 +#include <boost/shared_ptr.hpp>
816 +#endif
818 +namespace mdds {
820 +struct intrusive_ref_base
822 +#if USE_INTRUSIVE_PTR
823 + size_t _refcount;
825 + intrusive_ref_base() :
826 + _refcount(0) {}
827 +#endif
828 + virtual ~intrusive_ref_base() {}
831 +#if USE_INTRUSIVE_PTR
832 +inline void intrusive_ptr_add_ref(intrusive_ref_base* p)
834 + ++p->_refcount;
837 +inline void intrusive_ptr_release(intrusive_ref_base* p)
839 + --p->_refcount;
840 + if (!p->_refcount)
841 + delete p;
843 +#endif
845 +#ifdef DEBUG_NODE_BASE
846 +size_t node_instance_count = 0;
847 +#endif
849 +struct node_base;
850 +#if USE_INTRUSIVE_PTR
851 +typedef ::boost::intrusive_ptr<node_base> node_base_ptr;
852 +#else
853 +typedef ::boost::shared_ptr<node_base> node_base_ptr;
854 +#endif
856 +struct node_base : public intrusive_ref_base
858 + static size_t get_instance_count()
860 +#ifdef DEBUG_NODE_BASE
861 + return node_instance_count;
862 +#else
863 + return 0;
864 +#endif
866 + node_base_ptr parent; /// parent node
867 + node_base_ptr left; /// left child node or previous sibling if it's a leaf node.
868 + node_base_ptr right; /// right child node or next sibling if it's aleaf node.
869 + bool is_leaf;
871 + node_base(bool _is_leaf) :
872 + intrusive_ref_base(),
873 + parent(static_cast<node_base*>(NULL)),
874 + left(static_cast<node_base*>(NULL)),
875 + right(static_cast<node_base*>(NULL)),
876 + is_leaf(_is_leaf)
878 +#ifdef DEBUG_NODE_BASE
879 + ++node_instance_count;
880 +#endif
883 + virtual ~node_base()
885 +#ifdef DEBUG_NODE_BASE
886 + --node_instance_count;
887 +#endif
890 + // These methods are specific to concrete class implementation.
892 + virtual void fill_nonleaf_value(const node_base_ptr& left_node, const node_base_ptr& right_node) = 0;
893 + virtual void dump_value() const = 0;
894 + virtual node_base* create_new(bool leaf) const = 0;
897 +template<typename _NodePtr>
898 +void disconnect_node(_NodePtr p)
900 + if (!p)
901 + return;
903 + p->left.reset();
904 + p->right.reset();
905 + p->parent.reset();
908 +template<typename _NodePtr>
909 +void link_nodes(_NodePtr& left, _NodePtr& right)
911 + left->right = right;
912 + right->left = left;
915 +/**
916 + * Disconnect all non-leaf nodes so that their ref-counted instances will
917 + * all get destroyed afterwards.
918 + */
919 +template<typename _NodePtr>
920 +void clear_tree(const _NodePtr& node)
922 + if (!node)
923 + // Nothing to do.
924 + return;
926 + if (node->is_leaf)
928 + node->parent.reset();
929 + return;
932 + clear_tree(node->left);
933 + clear_tree(node->right);
934 + disconnect_node(node.get());
937 +template<typename _NodePtr>
938 +_NodePtr make_parent_node(const _NodePtr& node1, const _NodePtr& node2)
940 + _NodePtr parent_node(node1->create_new(false));
941 + node1->parent = parent_node;
942 + parent_node->left = node1;
943 + if (node2)
945 + node2->parent = parent_node;
946 + parent_node->right = node2;
949 + parent_node->fill_nonleaf_value(node1, node2);
950 + return parent_node;
953 +template<typename _NodePtr>
954 +_NodePtr build_tree(const _NodePtr& left_leaf_node)
956 + if (!left_leaf_node)
957 + // The left leaf node is empty. Nothing to build.
958 + return _NodePtr();
960 + _NodePtr node1, node2;
961 + node1 = left_leaf_node;
963 + ::std::list<_NodePtr> node_list;
964 + while (true)
966 + node2 = node1->right;
967 + _NodePtr parent_node = make_parent_node(node1, node2);
968 + node_list.push_back(parent_node);
970 + if (!node2 || !node2->right)
971 + // no more nodes. Break out of the loop.
972 + break;
974 + node1 = node2->right;
977 + return build_tree_non_leaf(node_list);
980 +template<typename _NodePtr>
981 +_NodePtr build_tree_non_leaf(const ::std::list<_NodePtr>& node_list)
983 + size_t node_count = node_list.size();
984 + if (node_count == 1)
986 + return node_list.front();
988 + else if (node_count == 0)
989 + return _NodePtr();
991 + ::std::list<_NodePtr> new_node_list;
992 + _NodePtr node_pair[2];
993 + typename ::std::list<_NodePtr>::const_iterator itr = node_list.begin();
994 + typename ::std::list<_NodePtr>::const_iterator itrEnd = node_list.end();
995 + for (bool even_itr = false; itr != itrEnd; ++itr, even_itr = !even_itr)
997 + node_pair[even_itr] = *itr;
998 + if (even_itr)
1000 + _NodePtr parent_node = make_parent_node(node_pair[0], node_pair[1]);
1001 + node_pair[0].reset();
1002 + node_pair[1].reset();
1003 + new_node_list.push_back(parent_node);
1007 + if (node_pair[0])
1009 + // Un-paired node still needs a parent...
1010 + _NodePtr parent_node = make_parent_node(node_pair[0], _NodePtr());
1011 + node_pair[0].reset();
1012 + node_pair[1].reset();
1013 + new_node_list.push_back(parent_node);
1016 + // Move up one level, and do the same procedure until the root node is reached.
1017 + return build_tree_non_leaf(new_node_list);
1020 +#ifdef UNIT_TEST
1021 +template<typename _NodePtr>
1022 +size_t dump_tree_layer(const ::std::list<_NodePtr>& node_list, unsigned int level)
1024 + using ::std::cout;
1025 + using ::std::endl;
1027 + if (node_list.empty())
1028 + return 0;
1030 + size_t node_count = node_list.size();
1032 + bool isLeaf = node_list.front()->is_leaf;
1033 + cout << "level " << level << " (" << (isLeaf?"leaf":"non-leaf") << ")" << endl;
1035 + ::std::list<_NodePtr> newList;
1036 + typename ::std::list<_NodePtr>::const_iterator itr = node_list.begin(), itrEnd = node_list.end();
1037 + for (; itr != itrEnd; ++itr)
1039 + const _NodePtr& p = *itr;
1040 + if (!p)
1042 + cout << "(x) ";
1043 + continue;
1046 + p->dump_value();
1048 + if (p->is_leaf)
1049 + continue;
1051 + if (p->left)
1053 + newList.push_back(p->left);
1054 + if (p->right)
1055 + newList.push_back(p->right);
1058 + cout << endl;
1060 + if (!newList.empty())
1061 + node_count += dump_tree_layer(newList, level+1);
1063 + return node_count;
1066 +template<typename _NodePtr>
1067 +size_t dump_tree(const _NodePtr& root_node)
1069 + if (!root_node)
1070 + return 0;
1072 + ::std::list<_NodePtr> node_list;
1073 + node_list.push_back(root_node);
1074 + return dump_tree_layer(node_list, 0);
1076 +#endif
1080 +#endif
1081 diff --git sc/inc/segmenttree.hxx sc/inc/segmenttree.hxx
1082 new file mode 100644
1083 index 0000000..466f9ed
1084 --- /dev/null
1085 +++ sc/inc/segmenttree.hxx
1086 @@ -0,0 +1,89 @@
1087 +/*************************************************************************
1089 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1090 + *
1091 + * Copyright 2008 by Sun Microsystems, Inc.
1093 + * OpenOffice.org - a multi-platform office productivity suite
1095 + * $RCSfile: compressedarray.hxx,v $
1096 + * $Revision: 1.7.32.2 $
1098 + * This file is part of OpenOffice.org.
1100 + * OpenOffice.org is free software: you can redistribute it and/or modify
1101 + * it under the terms of the GNU Lesser General Public License version 3
1102 + * only, as published by the Free Software Foundation.
1104 + * OpenOffice.org is distributed in the hope that it will be useful,
1105 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1106 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1107 + * GNU Lesser General Public License version 3 for more details
1108 + * (a copy is included in the LICENSE file that accompanied this code).
1110 + * You should have received a copy of the GNU Lesser General Public License
1111 + * version 3 along with OpenOffice.org. If not, see
1112 + * <http://www.openoffice.org/license.html>
1113 + * for a copy of the LGPLv3 License.
1115 + ************************************************************************/
1117 +#ifndef SC_SEGMENTTREE_HXX
1118 +#define SC_SEGMENTTREE_HXX
1120 +#include "address.hxx"
1122 +#include <memory>
1124 +class ScFlatBoolSegmentsImpl;
1126 +class ScFlatBoolRowSegments
1128 +public:
1129 + struct RangeData
1131 + SCROW mnRow1;
1132 + SCROW mnRow2;
1133 + bool mbValue;
1134 + };
1135 + ScFlatBoolRowSegments();
1136 + ~ScFlatBoolRowSegments();
1138 + void setTrue(SCROW nRow1, SCROW nRow2);
1139 + void setFalse(SCROW nRow1, SCROW nRow2);
1140 + bool getValue(SCROW nRow);
1141 + bool getRangeData(SCROW nRow, RangeData& rData);
1142 + void removeSegment(SCROW nRow1, SCROW nRow2);
1143 + void insertSegment(SCROW nRow, SCROW nSize, bool bSkipStartBoundary);
1145 +private:
1146 + ::std::auto_ptr<ScFlatBoolSegmentsImpl> mpImpl;
1149 +// ============================================================================
1151 +class ScFlatBoolColSegments
1153 +public:
1154 + struct RangeData
1156 + SCCOL mnCol1;
1157 + SCCOL mnCol2;
1158 + bool mbValue;
1159 + };
1160 + ScFlatBoolColSegments();
1161 + ~ScFlatBoolColSegments();
1163 + void setTrue(SCCOL nCol1, SCCOL nCol2);
1164 + void setFalse(SCCOL nCol1, SCCOL nCol2);
1165 + bool getValue(SCCOL nCol);
1166 + bool getRangeData(SCCOL nCol, RangeData& rData);
1167 + void removeSegment(SCCOL nCol1, SCCOL nCol2);
1168 + void insertSegment(SCCOL nCol, SCCOL nSize, bool bSkipStartBoundary);
1170 +private:
1171 + ::std::auto_ptr<ScFlatBoolSegmentsImpl> mpImpl;
1175 +#endif
1176 diff --git sc/source/core/data/makefile.mk sc/source/core/data/makefile.mk
1177 index c631bb4..5fbec41 100644
1178 --- sc/source/core/data/makefile.mk
1179 +++ sc/source/core/data/makefile.mk
1180 @@ -102,6 +102,7 @@ SLOFILES = \
1181 $(SLO)$/phonetic.obj \
1182 $(SLO)$/poolhelp.obj \
1183 $(SLO)$/scimpexpmsg.obj \
1184 + $(SLO)$/segmenttree.obj \
1185 $(SLO)$/sortparam.obj \
1186 $(SLO)$/stlpool.obj \
1187 $(SLO)$/stlsheet.obj \
1188 @@ -147,7 +148,8 @@ EXCEPTIONSFILES= \
1189 $(SLO)$/dbdocutl.obj \
1190 $(SLO)$/dptabsrc.obj \
1191 $(SLO)$/drwlayer.obj \
1192 - $(SLO)$/globalx.obj
1193 + $(SLO)$/globalx.obj \
1194 + $(SLO)$/segmenttree.obj
1196 .IF "$(OS)$(COM)$(CPUNAME)"=="LINUXGCCSPARC"
1197 NOOPTFILES= \
1198 diff --git sc/source/core/data/segmenttree.cxx sc/source/core/data/segmenttree.cxx
1199 new file mode 100644
1200 index 0000000..be8e408
1201 --- /dev/null
1202 +++ sc/source/core/data/segmenttree.cxx
1203 @@ -0,0 +1,225 @@
1204 +/*************************************************************************
1206 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1207 + *
1208 + * Copyright 2008 by Sun Microsystems, Inc.
1210 + * OpenOffice.org - a multi-platform office productivity suite
1212 + * $RCSfile: compressedarray.hxx,v $
1213 + * $Revision: 1.7.32.2 $
1215 + * This file is part of OpenOffice.org.
1217 + * OpenOffice.org is free software: you can redistribute it and/or modify
1218 + * it under the terms of the GNU Lesser General Public License version 3
1219 + * only, as published by the Free Software Foundation.
1221 + * OpenOffice.org is distributed in the hope that it will be useful,
1222 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1223 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1224 + * GNU Lesser General Public License version 3 for more details
1225 + * (a copy is included in the LICENSE file that accompanied this code).
1227 + * You should have received a copy of the GNU Lesser General Public License
1228 + * version 3 along with OpenOffice.org. If not, see
1229 + * <http://www.openoffice.org/license.html>
1230 + * for a copy of the LGPLv3 License.
1232 + ************************************************************************/
1234 +// MARKER(update_precomp.py): autogen include statement, do not remove
1235 +#include "precompiled_sc.hxx"
1237 +#include "segmenttree.hxx"
1238 +#include "mdds/flatsegmenttree.hxx"
1240 +#define USE_TREE_SEARCH 1
1242 +class ScFlatBoolSegmentsImpl
1244 +public:
1245 + struct RangeData
1247 + SCCOLROW mnPos1;
1248 + SCCOLROW mnPos2;
1249 + bool mbValue;
1250 + };
1251 + ScFlatBoolSegmentsImpl(SCCOLROW nMax);
1252 + ~ScFlatBoolSegmentsImpl();
1254 + void setTrue(SCCOLROW nPos1, SCCOLROW nPos2);
1255 + void setFalse(SCCOLROW nPos1, SCCOLROW nPos2);
1256 + bool getValue(SCCOLROW nPos);
1257 + bool getRangeData(SCCOLROW nPos, RangeData& rData);
1258 + void removeSegment(SCCOLROW nPos1, SCCOLROW nPos2);
1259 + void insertSegment(SCCOLROW nPos, SCCOLROW nSize, bool bSkipStartBoundary);
1261 +private:
1262 + ScFlatBoolSegmentsImpl();
1263 + ScFlatBoolSegmentsImpl(const ScFlatBoolSegmentsImpl&);
1265 + ::mdds::flat_segment_tree<SCCOLROW, bool> maSegments;
1268 +ScFlatBoolSegmentsImpl::ScFlatBoolSegmentsImpl(SCCOLROW nMax) :
1269 + maSegments(0, nMax+1, false)
1273 +ScFlatBoolSegmentsImpl::~ScFlatBoolSegmentsImpl()
1277 +void ScFlatBoolSegmentsImpl::setTrue(SCCOLROW nPos1, SCCOLROW nPos2)
1279 + maSegments.insert_segment(nPos1, nPos2+1, true);
1282 +void ScFlatBoolSegmentsImpl::setFalse(SCCOLROW nPos1, SCCOLROW nPos2)
1284 + maSegments.insert_segment(nPos1, nPos2+1, false);
1287 +bool ScFlatBoolSegmentsImpl::getValue(SCCOLROW nPos)
1289 + bool bValue = false;
1290 +#if USE_TREE_SEARCH
1291 + if (!maSegments.is_tree_valid())
1292 + maSegments.build_tree();
1294 + maSegments.search_tree(nPos, bValue);
1295 +#else
1296 + maSegments.search(nPos, bValue);
1297 +#endif
1298 + return bValue;
1301 +bool ScFlatBoolSegmentsImpl::getRangeData(SCCOLROW nPos, RangeData& rData)
1303 +#if USE_TREE_SEARCH
1304 + if (!maSegments.is_tree_valid())
1305 + maSegments.build_tree();
1306 +#endif
1308 + bool bValue;
1309 + SCCOLROW nPos1, nPos2;
1310 +#if USE_TREE_SEARCH
1311 + if (!maSegments.search_tree(nPos, bValue, &nPos1, &nPos2))
1312 + return false;
1313 +#else
1314 + if (!maSegments.search(nPos, bValue, &nPos1, &nPos2))
1315 + return false;
1316 +#endif
1318 + rData.mnPos1 = nPos1;
1319 + rData.mnPos2 = nPos2-1; // end point is not inclusive.
1320 + rData.mbValue = bValue;
1321 + return true;
1324 +void ScFlatBoolSegmentsImpl::removeSegment(SCCOLROW nPos1, SCCOLROW nPos2)
1326 + maSegments.shift_segment_left(nPos1, nPos2);
1329 +void ScFlatBoolSegmentsImpl::insertSegment(SCCOLROW nPos, SCCOLROW nSize, bool bSkipStartBoundary)
1331 + maSegments.shift_segment_right(nPos, nSize, bSkipStartBoundary);
1334 +// ============================================================================
1336 +ScFlatBoolRowSegments::ScFlatBoolRowSegments() :
1337 + mpImpl(new ScFlatBoolSegmentsImpl(static_cast<SCCOLROW>(MAXROW)))
1341 +ScFlatBoolRowSegments::~ScFlatBoolRowSegments()
1345 +void ScFlatBoolRowSegments::setTrue(SCROW nRow1, SCROW nRow2)
1347 + mpImpl->setTrue(static_cast<SCCOLROW>(nRow1), static_cast<SCCOLROW>(nRow2));
1350 +void ScFlatBoolRowSegments::setFalse(SCROW nRow1, SCROW nRow2)
1352 + mpImpl->setFalse(static_cast<SCCOLROW>(nRow1), static_cast<SCCOLROW>(nRow2));
1355 +bool ScFlatBoolRowSegments::getValue(SCROW nRow)
1357 + return mpImpl->getValue(static_cast<SCCOLROW>(nRow));
1360 +bool ScFlatBoolRowSegments::getRangeData(SCROW nRow, RangeData& rData)
1362 + ScFlatBoolSegmentsImpl::RangeData aData;
1363 + if (!mpImpl->getRangeData(static_cast<SCCOLROW>(nRow), aData))
1364 + return false;
1366 + rData.mbValue = aData.mbValue;
1367 + rData.mnRow1 = static_cast<SCROW>(aData.mnPos1);
1368 + rData.mnRow2 = static_cast<SCROW>(aData.mnPos2);
1369 + return true;
1372 +void ScFlatBoolRowSegments::removeSegment(SCROW nRow1, SCROW nRow2)
1374 + mpImpl->removeSegment(static_cast<SCCOLROW>(nRow1), static_cast<SCCOLROW>(nRow2));
1377 +void ScFlatBoolRowSegments::insertSegment(SCROW nRow, SCROW nSize, bool bSkipStartBoundary)
1379 + mpImpl->insertSegment(static_cast<SCCOLROW>(nRow), static_cast<SCCOLROW>(nSize), bSkipStartBoundary);
1382 +// ============================================================================
1384 +ScFlatBoolColSegments::ScFlatBoolColSegments() :
1385 + mpImpl(new ScFlatBoolSegmentsImpl(static_cast<SCCOLROW>(MAXCOL)))
1389 +ScFlatBoolColSegments::~ScFlatBoolColSegments()
1393 +void ScFlatBoolColSegments::setTrue(SCCOL nCol1, SCCOL nCol2)
1395 + mpImpl->setTrue(static_cast<SCCOLROW>(nCol1), static_cast<SCCOLROW>(nCol2));
1398 +void ScFlatBoolColSegments::setFalse(SCCOL nCol1, SCCOL nCol2)
1400 + mpImpl->setFalse(static_cast<SCCOLROW>(nCol1), static_cast<SCCOLROW>(nCol2));
1403 +bool ScFlatBoolColSegments::getValue(SCCOL nCol)
1405 + return mpImpl->getValue(static_cast<SCCOLROW>(nCol));
1408 +bool ScFlatBoolColSegments::getRangeData(SCCOL nCol, RangeData& rData)
1410 + ScFlatBoolSegmentsImpl::RangeData aData;
1411 + if (!mpImpl->getRangeData(static_cast<SCCOLROW>(nCol), aData))
1412 + return false;
1414 + rData.mbValue = aData.mbValue;
1415 + rData.mnCol1 = static_cast<SCCOL>(aData.mnPos1);
1416 + rData.mnCol2 = static_cast<SCCOL>(aData.mnPos2);
1417 + return true;
1420 +void ScFlatBoolColSegments::removeSegment(SCCOL nCol1, SCCOL nCol2)
1422 + mpImpl->removeSegment(static_cast<SCCOLROW>(nCol1), static_cast<SCCOLROW>(nCol2));
1425 +void ScFlatBoolColSegments::insertSegment(SCCOL nCol, SCCOL nSize, bool bSkipStartBoundary)
1427 + mpImpl->insertSegment(static_cast<SCCOLROW>(nCol), static_cast<SCCOLROW>(nSize), bSkipStartBoundary);