/src/mdds-1.3.1/include/mdds/flat_segment_tree.hpp
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /************************************************************************* |
3 | | * |
4 | | * Copyright (c) 2008-2017 Kohei Yoshida |
5 | | * |
6 | | * Permission is hereby granted, free of charge, to any person |
7 | | * obtaining a copy of this software and associated documentation |
8 | | * files (the "Software"), to deal in the Software without |
9 | | * restriction, including without limitation the rights to use, |
10 | | * copy, modify, merge, publish, distribute, sublicense, and/or sell |
11 | | * copies of the Software, and to permit persons to whom the |
12 | | * Software is furnished to do so, subject to the following |
13 | | * conditions: |
14 | | * |
15 | | * The above copyright notice and this permission notice shall be |
16 | | * included in all copies or substantial portions of the Software. |
17 | | * |
18 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
19 | | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
20 | | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
21 | | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
22 | | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
23 | | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
24 | | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
25 | | * OTHER DEALINGS IN THE SOFTWARE. |
26 | | * |
27 | | ************************************************************************/ |
28 | | |
29 | | #ifndef INCLUDED_MDDS_FLAT_SEGMENT_TREE_HPP |
30 | | #define INCLUDED_MDDS_FLAT_SEGMENT_TREE_HPP |
31 | | |
32 | | #include <iostream> |
33 | | #include <sstream> |
34 | | #include <utility> |
35 | | #include <cassert> |
36 | | |
37 | | #include "mdds/node.hpp" |
38 | | #include "mdds/flat_segment_tree_itr.hpp" |
39 | | #include "mdds/global.hpp" |
40 | | |
41 | | #ifdef MDDS_UNIT_TEST |
42 | | #include <cstdio> |
43 | | #include <vector> |
44 | | #endif |
45 | | |
46 | | namespace mdds { |
47 | | |
48 | | template<typename _Key, typename _Value> |
49 | | class flat_segment_tree |
50 | | { |
51 | | public: |
52 | | typedef _Key key_type; |
53 | | typedef _Value value_type; |
54 | | typedef size_t size_type; |
55 | | |
56 | | struct nonleaf_value_type |
57 | | { |
58 | | key_type low; /// low range value (inclusive) |
59 | | key_type high; /// high range value (non-inclusive) |
60 | | |
61 | | bool operator== (const nonleaf_value_type& r) const |
62 | | { |
63 | | return low == r.low && high == r.high; |
64 | | } |
65 | | |
66 | | nonleaf_value_type() |
67 | 310 | : low(0) |
68 | 310 | , high(0) |
69 | 310 | { |
70 | 310 | } |
71 | | }; |
72 | | |
73 | | struct leaf_value_type |
74 | | { |
75 | | key_type key; |
76 | | value_type value; |
77 | | |
78 | | bool operator== (const leaf_value_type& r) const |
79 | | { |
80 | | return key == r.key && value == r.value; |
81 | | } |
82 | | |
83 | | leaf_value_type() |
84 | 2.62k | : key(0) |
85 | 1.30k | , value() |
86 | 2.62k | { |
87 | 2.62k | } mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> >::leaf_value_type::leaf_value_type() Line | Count | Source | 84 | 1.30k | : key(0) | 85 | 1.30k | , value() | 86 | 1.30k | { | 87 | 1.30k | } |
mdds::flat_segment_tree<unsigned int, float>::leaf_value_type::leaf_value_type() Line | Count | Source | 84 | 930 | : key(0) | 85 | | , value() | 86 | 930 | { | 87 | 930 | } |
mdds::flat_segment_tree<unsigned int, bool>::leaf_value_type::leaf_value_type() Line | Count | Source | 84 | 392 | : key(0) | 85 | | , value() | 86 | 392 | { | 87 | 392 | } |
|
88 | | }; |
89 | | |
90 | | // Handlers required by the node template class. |
91 | | struct fill_nonleaf_value_handler; |
92 | | struct init_handler; |
93 | | struct dispose_handler; |
94 | | #ifdef MDDS_UNIT_TEST |
95 | | struct to_string_handler; |
96 | | #endif |
97 | | |
98 | | typedef __st::node<flat_segment_tree> node; |
99 | | typedef typename node::node_ptr node_ptr; |
100 | | |
101 | | typedef __st::nonleaf_node<flat_segment_tree> nonleaf_node; |
102 | | |
103 | | struct fill_nonleaf_value_handler |
104 | | { |
105 | | void operator() (__st::nonleaf_node<flat_segment_tree>& _self, const __st::node_base* left_node, const __st::node_base* right_node) |
106 | 310 | { |
107 | | // Parent node should carry the range of all of its child nodes. |
108 | 310 | if (left_node) |
109 | 310 | { |
110 | 310 | _self.value_nonleaf.low = |
111 | 310 | left_node->is_leaf ? |
112 | 207 | static_cast<const node*>(left_node)->value_leaf.key : |
113 | 310 | static_cast<const nonleaf_node*>(left_node)->value_nonleaf.low; |
114 | 310 | } |
115 | 0 | else |
116 | 0 | { |
117 | | // Having a left node is prerequisite. |
118 | 0 | throw general_error("flat_segment_tree::fill_nonleaf_value_handler: Having a left node is prerequisite."); |
119 | 0 | } |
120 | | |
121 | 310 | if (right_node) |
122 | 310 | { |
123 | 310 | if (right_node->is_leaf) |
124 | 207 | { |
125 | | // When the child nodes are leaf nodes, the upper bound |
126 | | // must be the value of the node that comes after the |
127 | | // right leaf node (if such node exists). |
128 | 207 | const node* p = static_cast<const node*>(right_node); |
129 | 207 | if (p->next) |
130 | 103 | _self.value_nonleaf.high = p->next->value_leaf.key; |
131 | 104 | else |
132 | 104 | _self.value_nonleaf.high = p->value_leaf.key; |
133 | 207 | } |
134 | 103 | else |
135 | 103 | { |
136 | 103 | _self.value_nonleaf.high = static_cast<const nonleaf_node*>(right_node)->value_nonleaf.high; |
137 | 103 | } |
138 | 310 | } |
139 | 0 | else |
140 | 0 | { |
141 | 0 | _self.value_nonleaf.high = |
142 | 0 | left_node->is_leaf ? |
143 | 0 | static_cast<const node*>(left_node)->value_leaf.key : |
144 | 0 | static_cast<const nonleaf_node*>(left_node)->value_nonleaf.high; |
145 | 0 | } |
146 | 310 | } |
147 | | }; |
148 | | |
149 | | #ifdef MDDS_UNIT_TEST |
150 | | struct to_string_handler |
151 | | { |
152 | | std::string operator() (const node& _self) const |
153 | | { |
154 | | std::ostringstream os; |
155 | | os << "(" << _self.value_leaf.key << ") "; |
156 | | return os.str(); |
157 | | } |
158 | | |
159 | | std::string operator() (const mdds::__st::nonleaf_node<flat_segment_tree>& _self) const |
160 | | { |
161 | | std::ostringstream os; |
162 | | os << "(" << _self.value_nonleaf.low << "-" << _self.value_nonleaf.high << ") "; |
163 | | return os.str(); |
164 | | } |
165 | | }; |
166 | | #endif |
167 | | |
168 | | struct init_handler |
169 | | { |
170 | 1.75k | void operator() (node& /*_self*/) {}mdds::flat_segment_tree<unsigned int, float>::init_handler::operator()(mdds::__st::node<mdds::flat_segment_tree<unsigned int, float> >&) Line | Count | Source | 170 | 930 | void operator() (node& /*_self*/) {} |
mdds::flat_segment_tree<unsigned int, bool>::init_handler::operator()(mdds::__st::node<mdds::flat_segment_tree<unsigned int, bool> >&) Line | Count | Source | 170 | 392 | void operator() (node& /*_self*/) {} |
mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> >::init_handler::operator()(mdds::__st::node<mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> > >&) Line | Count | Source | 170 | 434 | void operator() (node& /*_self*/) {} |
|
171 | 310 | void operator() (__st::nonleaf_node<flat_segment_tree>& /*_self*/) {} |
172 | | }; |
173 | | |
174 | | struct dispose_handler |
175 | | { |
176 | 2.62k | void operator() (node& /*_self*/) {}mdds::flat_segment_tree<unsigned int, bool>::dispose_handler::operator()(mdds::__st::node<mdds::flat_segment_tree<unsigned int, bool> >&) Line | Count | Source | 176 | 392 | void operator() (node& /*_self*/) {} |
mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> >::dispose_handler::operator()(mdds::__st::node<mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> > >&) Line | Count | Source | 176 | 1.30k | void operator() (node& /*_self*/) {} |
mdds::flat_segment_tree<unsigned int, float>::dispose_handler::operator()(mdds::__st::node<mdds::flat_segment_tree<unsigned int, float> >&) Line | Count | Source | 176 | 930 | void operator() (node& /*_self*/) {} |
|
177 | 310 | void operator() (__st::nonleaf_node<flat_segment_tree>& /*_self*/) {}Unexecuted instantiation: mdds::flat_segment_tree<unsigned int, bool>::dispose_handler::operator()(mdds::__st::nonleaf_node<mdds::flat_segment_tree<unsigned int, bool> >&) mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> >::dispose_handler::operator()(mdds::__st::nonleaf_node<mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> > >&) Line | Count | Source | 177 | 310 | void operator() (__st::nonleaf_node<flat_segment_tree>& /*_self*/) {} |
Unexecuted instantiation: mdds::flat_segment_tree<unsigned int, float>::dispose_handler::operator()(mdds::__st::nonleaf_node<mdds::flat_segment_tree<unsigned int, float> >&) |
178 | | }; |
179 | | |
180 | | private: |
181 | | |
182 | | friend struct ::mdds::__fst::itr_forward_handler<flat_segment_tree>; |
183 | | friend struct ::mdds::__fst::itr_reverse_handler<flat_segment_tree>; |
184 | | |
185 | | public: |
186 | | class const_iterator : public ::mdds::__fst::const_iterator_base< |
187 | | flat_segment_tree, ::mdds::__fst::itr_forward_handler<flat_segment_tree> > |
188 | | { |
189 | | typedef ::mdds::__fst::const_iterator_base< |
190 | | flat_segment_tree, ::mdds::__fst::itr_forward_handler<flat_segment_tree> > |
191 | | base_type; |
192 | | friend class flat_segment_tree; |
193 | | public: |
194 | | const_iterator() : |
195 | | base_type(nullptr, false) {} |
196 | | |
197 | | private: |
198 | | explicit const_iterator(const typename base_type::fst_type* _db, bool _end) : |
199 | 1.18k | base_type(_db, _end) {}mdds::flat_segment_tree<unsigned int, float>::const_iterator::const_iterator(mdds::flat_segment_tree<unsigned int, float> const*, bool) Line | Count | Source | 199 | 1.18k | base_type(_db, _end) {} |
Unexecuted instantiation: mdds::flat_segment_tree<unsigned int, bool>::const_iterator::const_iterator(mdds::flat_segment_tree<unsigned int, bool> const*, bool) Unexecuted instantiation: mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> >::const_iterator::const_iterator(mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> > const*, bool) |
200 | | |
201 | | explicit const_iterator(const typename base_type::fst_type* _db, const node* p) : |
202 | 1.80k | base_type(_db, p) {}mdds::flat_segment_tree<unsigned int, float>::const_iterator::const_iterator(mdds::flat_segment_tree<unsigned int, float> const*, mdds::__st::node<mdds::flat_segment_tree<unsigned int, float> > const*) Line | Count | Source | 202 | 621 | base_type(_db, p) {} |
mdds::flat_segment_tree<unsigned int, bool>::const_iterator::const_iterator(mdds::flat_segment_tree<unsigned int, bool> const*, mdds::__st::node<mdds::flat_segment_tree<unsigned int, bool> > const*) Line | Count | Source | 202 | 616 | base_type(_db, p) {} |
mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> >::const_iterator::const_iterator(mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> > const*, mdds::__st::node<mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> > > const*) Line | Count | Source | 202 | 566 | base_type(_db, p) {} |
|
203 | | }; |
204 | | |
205 | | class const_reverse_iterator : public ::mdds::__fst::const_iterator_base< |
206 | | flat_segment_tree, ::mdds::__fst::itr_reverse_handler<flat_segment_tree> > |
207 | | { |
208 | | typedef ::mdds::__fst::const_iterator_base< |
209 | | flat_segment_tree, ::mdds::__fst::itr_reverse_handler<flat_segment_tree> > |
210 | | base_type; |
211 | | friend class flat_segment_tree; |
212 | | public: |
213 | | const_reverse_iterator() : |
214 | | base_type(nullptr, false) {} |
215 | | private: |
216 | | explicit const_reverse_iterator(const typename base_type::fst_type* _db, bool _end) : |
217 | | base_type(_db, _end) {} |
218 | | }; |
219 | | |
220 | | using const_segment_iterator = mdds::__fst::const_segment_iterator<flat_segment_tree>; |
221 | | |
222 | | const_iterator begin() const |
223 | 174 | { |
224 | 174 | return const_iterator(this, false); |
225 | 174 | } |
226 | | |
227 | | const_iterator end() const |
228 | 1.01k | { |
229 | 1.01k | return const_iterator(this, true); |
230 | 1.01k | } |
231 | | |
232 | | const_reverse_iterator rbegin() const |
233 | | { |
234 | | return const_reverse_iterator(this, false); |
235 | | } |
236 | | |
237 | | const_reverse_iterator rend() const |
238 | | { |
239 | | return const_reverse_iterator(this, true); |
240 | | } |
241 | | |
242 | | const_segment_iterator begin_segment() const; |
243 | | |
244 | | const_segment_iterator end_segment() const; |
245 | | |
246 | | flat_segment_tree(key_type min_val, key_type max_val, value_type init_val); |
247 | | |
248 | | /** |
249 | | * Copy constructor only copies the leaf nodes. |
250 | | */ |
251 | | flat_segment_tree(const flat_segment_tree<key_type, value_type>& r); |
252 | | |
253 | | ~flat_segment_tree(); |
254 | | |
255 | | /** |
256 | | * Assignment only copies the leaf nodes. |
257 | | */ |
258 | | flat_segment_tree<key_type, value_type>& |
259 | | operator=(const flat_segment_tree<key_type, value_type>& other); |
260 | | |
261 | | void swap(flat_segment_tree<key_type, value_type>& other); |
262 | | |
263 | | void clear(); |
264 | | |
265 | | /** |
266 | | * Insert a new segment into the tree. It searches for the point of |
267 | | * insertion from the first leaf node. |
268 | | * |
269 | | * @param start_key start value of the segment being inserted. The value |
270 | | * is inclusive. |
271 | | * @param end_key end value of the segment being inserted. The value is |
272 | | * not inclusive. |
273 | | * @param val value associated with this segment. |
274 | | * |
275 | | * @return pair of const_iterator corresponding to the start position of |
276 | | * the inserted segment, and a boolean value indicating whether or |
277 | | * not the insertion has modified the tree. |
278 | | */ |
279 | | std::pair<const_iterator, bool> |
280 | | insert_front(key_type start_key, key_type end_key, value_type val) |
281 | | { |
282 | | return insert_segment_impl(start_key, end_key, val, true); |
283 | | } |
284 | | |
285 | | /** |
286 | | * Insert a new segment into the tree. Unlike the insert_front() |
287 | | * counterpart, this method searches for the point of insertion from the |
288 | | * last leaf node toward the first. |
289 | | * |
290 | | * @param start_key start value of the segment being inserted. The value |
291 | | * is inclusive. |
292 | | * @param end_key end value of the segment being inserted. The value is |
293 | | * not inclusive. |
294 | | * @param val value associated with this segment. |
295 | | * |
296 | | * @return pair of const_iterator corresponding to the start position of |
297 | | * the inserted segment, and a boolean value indicating whether or |
298 | | * not the insertion has modified the tree. |
299 | | */ |
300 | | std::pair<const_iterator, bool> |
301 | | insert_back(key_type start_key, key_type end_key, value_type val) |
302 | 1.34k | { |
303 | 1.34k | return insert_segment_impl(start_key, end_key, val, false); |
304 | 1.34k | } mdds::flat_segment_tree<unsigned int, float>::insert_back(unsigned int, unsigned int, float) Line | Count | Source | 302 | 621 | { | 303 | 621 | return insert_segment_impl(start_key, end_key, val, false); | 304 | 621 | } |
mdds::flat_segment_tree<unsigned int, bool>::insert_back(unsigned int, unsigned int, bool) Line | Count | Source | 302 | 616 | { | 303 | 616 | return insert_segment_impl(start_key, end_key, val, false); | 304 | 616 | } |
mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> >::insert_back(unsigned int, unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle>) Line | Count | Source | 302 | 108 | { | 303 | 108 | return insert_segment_impl(start_key, end_key, val, false); | 304 | 108 | } |
|
305 | | |
306 | | /** |
307 | | * Insert a new segment into the tree at or after specified point of |
308 | | * insertion. |
309 | | * |
310 | | * @param pos specified insertion point |
311 | | * @param start_key start value of the segment being inserted. The value |
312 | | * is inclusive. |
313 | | * @param end_key end value of the segment being inserted. The value is |
314 | | * not inclusive. |
315 | | * @param val value associated with this segment. |
316 | | * |
317 | | * @return pair of const_iterator corresponding to the start position of |
318 | | * the inserted segment, and a boolean value indicating whether or |
319 | | * not the insertion has modified the tree. |
320 | | */ |
321 | | std::pair<const_iterator, bool> |
322 | | insert(const const_iterator& pos, key_type start_key, key_type end_key, value_type val); |
323 | | |
324 | | /** |
325 | | * Remove a segment specified by the start and end key values, and shift |
326 | | * the remaining segments (i.e. those segments that come after the removed |
327 | | * segment) to left. Note that the start and end positions of the segment |
328 | | * being removed <b>must</b> be within the base segment span. |
329 | | * |
330 | | * @param start_key start position of the segment being removed. |
331 | | * @param end_key end position of the segment being removed. |
332 | | */ |
333 | | void shift_left(key_type start_key, key_type end_key); |
334 | | |
335 | | /** |
336 | | * Shift all segments that occur at or after the specified start position |
337 | | * to right by the size specified. |
338 | | * |
339 | | * @param pos position where the right-shift occurs. |
340 | | * @param size amount of shift (must be greater than 0) |
341 | | * @param skip_start_node if true, and the specified position is at an |
342 | | * existing node position, that node will |
343 | | * <i>not</i> be shifted. This argument has no |
344 | | * effect if the position specified does not |
345 | | * coincide with any of the existing nodes. |
346 | | */ |
347 | | void shift_right(key_type pos, key_type size, bool skip_start_node); |
348 | | |
349 | | /** |
350 | | * Perform leaf-node search for a value associated with a key. |
351 | | * |
352 | | * @param key key value |
353 | | * @param value value associated with key specified gets stored upon |
354 | | * successful search. |
355 | | * @param start_key pointer to a variable where the start key value of the |
356 | | * segment that contains the key gets stored upon |
357 | | * successful search. |
358 | | * @param end_key pointer to a varaible where the end key value of the |
359 | | * segment that contains the key gets stored upon |
360 | | * successful search. |
361 | | * @return a pair of const_iterator corresponding to the start position of |
362 | | * the segment containing the key, and a boolean value indicating |
363 | | * whether or not the search has been successful. |
364 | | * |
365 | | */ |
366 | | std::pair<const_iterator, bool> |
367 | | search(key_type key, value_type& value, key_type* start_key = nullptr, key_type* end_key = nullptr) const; |
368 | | |
369 | | /** |
370 | | * Perform leaf-node search for a value associated with a key. |
371 | | * |
372 | | * @param pos position from which the search should start. When the |
373 | | * position is invalid, it falls back to the normal search. |
374 | | * @param key key value |
375 | | * @param value value associated with key specified gets stored upon |
376 | | * successful search. |
377 | | * @param start_key pointer to a variable where the start key value of the |
378 | | * segment that contains the key gets stored upon |
379 | | * successful search. |
380 | | * @param end_key pointer to a varaible where the end key value of the |
381 | | * segment that contains the key gets stored upon |
382 | | * successful search. |
383 | | * @return a pair of const_iterator corresponding to the start position of |
384 | | * the segment containing the key, and a boolean value indicating |
385 | | * whether or not the search has been successful. |
386 | | */ |
387 | | std::pair<const_iterator, bool> |
388 | | search(const const_iterator& pos, key_type key, value_type& value, key_type* start_key = nullptr, key_type* end_key = nullptr) const; |
389 | | |
390 | | /** |
391 | | * Perform tree search for a value associated with a key. This method |
392 | | * assumes that the tree is valid. Call is_tree_valid() to find out |
393 | | * whether the tree is valid, and build_tree() to build a new tree in case |
394 | | * it's not. |
395 | | * |
396 | | * @param key key value |
397 | | * @param value value associated with key specified gets stored upon |
398 | | * successful search. |
399 | | * @param start_key pointer to a variable where the start key value of the |
400 | | * segment that contains the key gets stored upon |
401 | | * successful search. |
402 | | * @param end_key pointer to a varaible where the end key value of the |
403 | | * segment that contains the key gets stored upon |
404 | | * successful search. |
405 | | * @return a pair of const_iterator corresponding to the start position of |
406 | | * the segment containing the key, and a boolean value indicating |
407 | | * whether or not the search has been successful. |
408 | | */ |
409 | | std::pair<const_iterator, bool> |
410 | | search_tree(key_type key, value_type& value, key_type* start_key = nullptr, key_type* end_key = nullptr) const; |
411 | | |
412 | | /** |
413 | | * Build a tree of non-leaf nodes based on the values stored in the leaf |
414 | | * nodes. The tree must be valid before you can call the search_tree() |
415 | | * method. |
416 | | */ |
417 | | void build_tree(); |
418 | | |
419 | | /** |
420 | | * @return true if the tree is valid, otherwise false. The tree must be |
421 | | * valid before you can call the search_tree() method. |
422 | | */ |
423 | | bool is_tree_valid() const |
424 | 458 | { |
425 | 458 | return m_valid_tree; |
426 | 458 | } |
427 | | |
428 | | /** |
429 | | * Equality between two flat_segment_tree instances is evaluated by |
430 | | * comparing the keys and the values of the leaf nodes only. Neither the |
431 | | * non-leaf nodes nor the validity of the tree is evaluated. |
432 | | */ |
433 | | bool operator==(const flat_segment_tree<key_type, value_type>& r) const; |
434 | | |
435 | | bool operator !=(const flat_segment_tree<key_type, value_type>& r) const |
436 | | { |
437 | | return !operator==(r); |
438 | | } |
439 | | |
440 | | key_type min_key() const |
441 | | { |
442 | | return m_left_leaf->value_leaf.key; |
443 | | } |
444 | | |
445 | | key_type max_key() const |
446 | 885 | { |
447 | 885 | return m_right_leaf->value_leaf.key; |
448 | 885 | } |
449 | | |
450 | | value_type default_value() const |
451 | 261 | { |
452 | 261 | return m_init_val; |
453 | 261 | } |
454 | | |
455 | | /** |
456 | | * Return the number of leaf nodes. |
457 | | * |
458 | | * @return number of leaf nodes. |
459 | | */ |
460 | | size_type leaf_size() const; |
461 | | |
462 | | #ifdef MDDS_UNIT_TEST |
463 | | nonleaf_node* get_root_node() const |
464 | | { |
465 | | return m_root_node; |
466 | | } |
467 | | |
468 | | void dump_tree() const |
469 | | { |
470 | | using ::std::cout; |
471 | | using ::std::endl; |
472 | | |
473 | | if (!m_valid_tree) |
474 | | assert(!"attempted to dump an invalid tree!"); |
475 | | |
476 | | size_t node_count = mdds::__st::tree_dumper<node, nonleaf_node>::dump(m_root_node); |
477 | | size_t node_instance_count = node::get_instance_count(); |
478 | | size_t leaf_count = leaf_size(); |
479 | | |
480 | | cout << "tree node count = " << node_count << "; node instance count = " |
481 | | << node_instance_count << "; leaf node count = " << leaf_count << endl; |
482 | | |
483 | | assert(leaf_count == node_instance_count); |
484 | | } |
485 | | |
486 | | void dump_leaf_nodes() const |
487 | | { |
488 | | using ::std::cout; |
489 | | using ::std::endl; |
490 | | |
491 | | cout << "------------------------------------------" << endl; |
492 | | |
493 | | node_ptr cur_node = m_left_leaf; |
494 | | long node_id = 0; |
495 | | while (cur_node) |
496 | | { |
497 | | cout << " node " << node_id++ << ": key = " << cur_node->value_leaf.key |
498 | | << "; value = " << cur_node->value_leaf.value |
499 | | << endl; |
500 | | cur_node = cur_node->next; |
501 | | } |
502 | | cout << endl << " node instance count = " << node::get_instance_count() << endl; |
503 | | } |
504 | | |
505 | | /** |
506 | | * Verify keys in the leaf nodes. |
507 | | * |
508 | | * @param key_values vector containing key values in the left-to-right |
509 | | * order, including the key value of the rightmost leaf |
510 | | * node. |
511 | | */ |
512 | | bool verify_keys(const ::std::vector<key_type>& key_values) const |
513 | | { |
514 | | { |
515 | | // Start from the left-most node, and traverse right. |
516 | | node* cur_node = m_left_leaf.get(); |
517 | | typename ::std::vector<key_type>::const_iterator itr = key_values.begin(), itr_end = key_values.end(); |
518 | | for (; itr != itr_end; ++itr) |
519 | | { |
520 | | if (!cur_node) |
521 | | // Position past the right-mode node. Invalid. |
522 | | return false; |
523 | | |
524 | | if (cur_node->value_leaf.key != *itr) |
525 | | // Key values differ. |
526 | | return false; |
527 | | |
528 | | cur_node = cur_node->next.get(); |
529 | | } |
530 | | |
531 | | if (cur_node) |
532 | | // At this point, we expect the current node to be at the position |
533 | | // past the right-most node, which is nullptr. |
534 | | return false; |
535 | | } |
536 | | |
537 | | { |
538 | | // Start from the right-most node, and traverse left. |
539 | | node* cur_node = m_right_leaf.get(); |
540 | | typename ::std::vector<key_type>::const_reverse_iterator itr = key_values.rbegin(), itr_end = key_values.rend(); |
541 | | for (; itr != itr_end; ++itr) |
542 | | { |
543 | | if (!cur_node) |
544 | | // Position past the left-mode node. Invalid. |
545 | | return false; |
546 | | |
547 | | if (cur_node->value_leaf.key != *itr) |
548 | | // Key values differ. |
549 | | return false; |
550 | | |
551 | | cur_node = cur_node->prev.get(); |
552 | | } |
553 | | |
554 | | if (cur_node) |
555 | | // Likewise, we expect the current position to be past the |
556 | | // left-most node, in which case the node value is nullptr. |
557 | | return false; |
558 | | } |
559 | | |
560 | | return true; |
561 | | } |
562 | | |
563 | | /** |
564 | | * Verify values in the leaf nodes. |
565 | | * |
566 | | * @param values vector containing values to verify against, in the |
567 | | * left-to-right order, <i>not</i> including the value of |
568 | | * the rightmost leaf node. |
569 | | */ |
570 | | bool verify_values(const ::std::vector<value_type>& values) const |
571 | | { |
572 | | node* cur_node = m_left_leaf.get(); |
573 | | node* end_node = m_right_leaf.get(); |
574 | | typename ::std::vector<value_type>::const_iterator itr = values.begin(), itr_end = values.end(); |
575 | | for (; itr != itr_end; ++itr) |
576 | | { |
577 | | if (cur_node == end_node || !cur_node) |
578 | | return false; |
579 | | |
580 | | if (cur_node->value_leaf.value != *itr) |
581 | | // Key values differ. |
582 | | return false; |
583 | | |
584 | | cur_node = cur_node->next.get(); |
585 | | } |
586 | | |
587 | | if (cur_node != end_node) |
588 | | // At this point, we expect the current node to be at the end of |
589 | | // range. |
590 | | return false; |
591 | | |
592 | | return true; |
593 | | } |
594 | | #endif |
595 | | |
596 | | private: |
597 | | flat_segment_tree(); // default constructor is not allowed. |
598 | | |
599 | | void append_new_segment(key_type start_key) |
600 | | { |
601 | | if (m_right_leaf->prev->value_leaf.key == start_key) |
602 | | { |
603 | | m_right_leaf->prev->value_leaf.value = m_init_val; |
604 | | return; |
605 | | } |
606 | | |
607 | | #ifdef MDDS_UNIT_TEST |
608 | | // The start position must come after the position of the last node |
609 | | // before the right-most node. |
610 | | assert(m_right_leaf->prev->value_leaf.key < start_key); |
611 | | #endif |
612 | | |
613 | | if (m_right_leaf->prev->value_leaf.value == m_init_val) |
614 | | // The existing segment has the same value. No need to insert a |
615 | | // new segment. |
616 | | return; |
617 | | |
618 | | node_ptr new_node(new node); |
619 | | new_node->value_leaf.key = start_key; |
620 | | new_node->value_leaf.value = m_init_val; |
621 | | new_node->prev = m_right_leaf->prev; |
622 | | new_node->next = m_right_leaf; |
623 | | m_right_leaf->prev->next = new_node; |
624 | | m_right_leaf->prev = new_node; |
625 | | m_valid_tree = false; |
626 | | } |
627 | | |
628 | | ::std::pair<const_iterator, bool> |
629 | | insert_segment_impl(key_type start_key, key_type end_key, value_type val, bool forward); |
630 | | |
631 | | ::std::pair<const_iterator, bool> |
632 | | insert_to_pos(node_ptr& start_pos, key_type start_key, key_type end_key, value_type val); |
633 | | |
634 | | ::std::pair<const_iterator, bool> |
635 | | search_impl(const node* pos, key_type key, value_type& value, key_type* start_key, key_type* end_key) const; |
636 | | |
637 | | const node* get_insertion_pos_leaf_reverse(key_type key, const node* start_pos) const; |
638 | | |
639 | | const node* get_insertion_pos_leaf(key_type key, const node* start_pos) const; |
640 | | |
641 | | static void shift_leaf_key_left(node_ptr& begin_node, node_ptr& end_node, key_type shift_value) |
642 | | { |
643 | | node* cur_node_p = begin_node.get(); |
644 | | node* end_node_p = end_node.get(); |
645 | | while (cur_node_p != end_node_p) |
646 | | { |
647 | | cur_node_p->value_leaf.key -= shift_value; |
648 | | cur_node_p = cur_node_p->next.get(); |
649 | | } |
650 | | } |
651 | | |
652 | | static void shift_leaf_key_right(node_ptr& cur_node, node_ptr& end_node, key_type shift_value) |
653 | | { |
654 | | key_type end_node_key = end_node->value_leaf.key; |
655 | | while (cur_node.get() != end_node.get()) |
656 | | { |
657 | | cur_node->value_leaf.key += shift_value; |
658 | | if (cur_node->value_leaf.key < end_node_key) |
659 | | { |
660 | | // The node is still in-bound. Keep shifting. |
661 | | cur_node = cur_node->next; |
662 | | continue; |
663 | | } |
664 | | |
665 | | // This node has been pushed outside the end node position. |
666 | | // Remove all nodes that follows, and connect the previous node |
667 | | // with the end node. |
668 | | |
669 | | node_ptr last_node = cur_node->prev; |
670 | | while (cur_node.get() != end_node.get()) |
671 | | { |
672 | | node_ptr next_node = cur_node->next; |
673 | | disconnect_all_nodes(cur_node.get()); |
674 | | cur_node = next_node; |
675 | | } |
676 | | last_node->next = end_node; |
677 | | end_node->prev = last_node; |
678 | | return; |
679 | | } |
680 | | } |
681 | | |
682 | | void destroy(); |
683 | | |
684 | | /** |
685 | | * Check and optionally adjust the start and end key values if one of them |
686 | | * is out-of-bound. |
687 | | * |
688 | | * @return true if the start and end key values are valid, either with or |
689 | | * without adjustments, otherwise false. |
690 | | */ |
691 | | bool adjust_segment_range(key_type& start_key, key_type& end_key) const; |
692 | | |
693 | | private: |
694 | | std::vector<nonleaf_node> m_nonleaf_node_pool; |
695 | | |
696 | | nonleaf_node* m_root_node; |
697 | | node_ptr m_left_leaf; |
698 | | node_ptr m_right_leaf; |
699 | | value_type m_init_val; |
700 | | bool m_valid_tree; |
701 | | }; |
702 | | |
703 | | template<typename _Key, typename _Value> |
704 | | void |
705 | | swap(flat_segment_tree<_Key, _Value>& left, flat_segment_tree<_Key, _Value>& right) |
706 | | { |
707 | | left.swap(right); |
708 | | } |
709 | | |
710 | | } // namespace mdds |
711 | | |
712 | | #include "flat_segment_tree_def.inl" |
713 | | |
714 | | #endif |
715 | | |
716 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |