/src/mdds-3.1.0/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-2023 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 | | #pragma once |
30 | | |
31 | | #include <iostream> |
32 | | #include <sstream> |
33 | | #include <utility> |
34 | | #include <cassert> |
35 | | |
36 | | #include "./node.hpp" |
37 | | #include "./flat_segment_tree_itr.hpp" |
38 | | #include "./global.hpp" |
39 | | |
40 | | #ifdef MDDS_UNIT_TEST |
41 | | #include <cstdio> |
42 | | #include <vector> |
43 | | #endif |
44 | | |
45 | | namespace mdds { |
46 | | |
47 | | template<typename Key, typename Value> |
48 | | class flat_segment_tree |
49 | | { |
50 | | public: |
51 | | typedef Key key_type; |
52 | | typedef Value value_type; |
53 | | typedef size_t size_type; |
54 | | |
55 | | struct nonleaf_value_type |
56 | | { |
57 | | }; |
58 | | |
59 | | struct leaf_value_type |
60 | | { |
61 | | value_type value; |
62 | | |
63 | | bool operator==(const leaf_value_type& r) const |
64 | | { |
65 | | return value == r.value; |
66 | | } |
67 | | |
68 | | bool operator!=(const leaf_value_type& r) const |
69 | | { |
70 | | return !operator==(r); |
71 | | } |
72 | | |
73 | 1.41k | leaf_value_type() : value{} |
74 | 2.49k | {}mdds::flat_segment_tree<unsigned int, float>::leaf_value_type::leaf_value_type() Line | Count | Source | 73 | 988 | leaf_value_type() : value{} | 74 | 988 | {} |
mdds::flat_segment_tree<unsigned int, bool>::leaf_value_type::leaf_value_type() Line | Count | Source | 73 | 424 | leaf_value_type() : value{} | 74 | 424 | {} |
|
75 | | }; |
76 | | |
77 | | using node = st::detail::node<key_type, leaf_value_type>; |
78 | | using node_ptr = typename node::node_ptr; |
79 | | using nonleaf_node = st::detail::nonleaf_node<key_type, nonleaf_value_type>; |
80 | | |
81 | | private: |
82 | | friend struct ::mdds::fst::detail::forward_itr_handler<flat_segment_tree>; |
83 | | friend struct ::mdds::fst::detail::reverse_itr_handler<flat_segment_tree>; |
84 | | |
85 | | public: |
86 | | using const_segment_iterator = mdds::fst::detail::const_segment_iterator<flat_segment_tree>; |
87 | | |
88 | | class const_iterator : public ::mdds::fst::detail::const_iterator_base< |
89 | | flat_segment_tree, ::mdds::fst::detail::forward_itr_handler<flat_segment_tree>> |
90 | | { |
91 | | typedef ::mdds::fst::detail::const_iterator_base< |
92 | | flat_segment_tree, ::mdds::fst::detail::forward_itr_handler<flat_segment_tree>> |
93 | | base_type; |
94 | | friend class flat_segment_tree; |
95 | | |
96 | | using base_type::get_parent; |
97 | | using base_type::get_pos; |
98 | | using base_type::is_end_pos; |
99 | | |
100 | | public: |
101 | | const_iterator() : base_type(nullptr, false) |
102 | | {} |
103 | | |
104 | | /** |
105 | | * Create a segment iterator that references the same segment the source |
106 | | * iterator references the start key of. |
107 | | */ |
108 | | const_segment_iterator to_segment() const; |
109 | | |
110 | | private: |
111 | 1.27k | explicit const_iterator(const typename base_type::fst_type* _db, bool _end) : base_type(_db, _end) |
112 | 1.27k | {}mdds::flat_segment_tree<unsigned int, float>::const_iterator::const_iterator(mdds::flat_segment_tree<unsigned int, float> const*, bool) Line | Count | Source | 111 | 1.27k | explicit const_iterator(const typename base_type::fst_type* _db, bool _end) : base_type(_db, _end) | 112 | 1.27k | {} |
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) |
113 | | |
114 | 2.16k | explicit const_iterator(const typename base_type::fst_type* _db, const node* p) : base_type(_db, p) |
115 | 2.16k | {}mdds::flat_segment_tree<unsigned int, float>::const_iterator::const_iterator(mdds::flat_segment_tree<unsigned int, float> const*, mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, float>::leaf_value_type> const*) Line | Count | Source | 114 | 656 | explicit const_iterator(const typename base_type::fst_type* _db, const node* p) : base_type(_db, p) | 115 | 656 | {} |
mdds::flat_segment_tree<unsigned int, bool>::const_iterator::const_iterator(mdds::flat_segment_tree<unsigned int, bool> const*, mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, bool>::leaf_value_type> const*) Line | Count | Source | 114 | 651 | explicit const_iterator(const typename base_type::fst_type* _db, const node* p) : base_type(_db, p) | 115 | 651 | {} |
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::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> >::leaf_value_type> const*) Line | Count | Source | 114 | 861 | explicit const_iterator(const typename base_type::fst_type* _db, const node* p) : base_type(_db, p) | 115 | 861 | {} |
|
116 | | }; |
117 | | |
118 | | class const_reverse_iterator : public ::mdds::fst::detail::const_iterator_base< |
119 | | flat_segment_tree, ::mdds::fst::detail::reverse_itr_handler<flat_segment_tree>> |
120 | | { |
121 | | typedef ::mdds::fst::detail::const_iterator_base< |
122 | | flat_segment_tree, ::mdds::fst::detail::reverse_itr_handler<flat_segment_tree>> |
123 | | base_type; |
124 | | friend class flat_segment_tree; |
125 | | |
126 | | public: |
127 | | const_reverse_iterator() : base_type(nullptr, false) |
128 | | {} |
129 | | |
130 | | private: |
131 | | explicit const_reverse_iterator(const typename base_type::fst_type* _db, bool _end) : base_type(_db, _end) |
132 | | {} |
133 | | }; |
134 | | |
135 | | class const_segment_range_type |
136 | | { |
137 | | node_ptr m_left_leaf; |
138 | | node_ptr m_right_leaf; |
139 | | |
140 | | public: |
141 | | const_segment_range_type(node_ptr left_leaf, node_ptr right_leaf); |
142 | | |
143 | | const_segment_iterator begin() const; |
144 | | const_segment_iterator end() const; |
145 | | }; |
146 | | |
147 | | /** |
148 | | * Return an iterator that points to the first leaf node that correspondes |
149 | | * with the start position of the first segment. |
150 | | * |
151 | | * @return immutable iterator that points to the first leaf node that |
152 | | * corresponds with the start position of the first segment. |
153 | | */ |
154 | | const_iterator begin() const |
155 | 190 | { |
156 | 190 | return const_iterator(this, false); |
157 | 190 | } |
158 | | |
159 | | /** |
160 | | * Return an iterator that points to the position past the last leaf node |
161 | | * that corresponds with the end position of the last segment. |
162 | | * |
163 | | * @return immutable iterator that points to the position past last leaf |
164 | | * node that corresponds with the end position of the last |
165 | | * segment. |
166 | | */ |
167 | | const_iterator end() const |
168 | 1.08k | { |
169 | 1.08k | return const_iterator(this, true); |
170 | 1.08k | } |
171 | | |
172 | | /** |
173 | | * Return an iterator that points to the last leaf node that correspondes |
174 | | * with the end position of the last segment. This iterator moves in the |
175 | | * reverse direction of a normal iterator. |
176 | | * |
177 | | * @return immutable reverse iterator that points to the last leaf node |
178 | | * that corresponds with the end position of the last segment. |
179 | | */ |
180 | | const_reverse_iterator rbegin() const |
181 | | { |
182 | | return const_reverse_iterator(this, false); |
183 | | } |
184 | | |
185 | | /** |
186 | | * Return an iterator that points to the position past the first leaf node |
187 | | * that corresponds with the start position of the first segment. This |
188 | | * iterator moves in the reverse direction of a normal iterator. |
189 | | * |
190 | | * @return immutable reverse iterator that points to the position past |
191 | | * first leaf node that corresponds with the start position of the |
192 | | * first segment. |
193 | | */ |
194 | | const_reverse_iterator rend() const |
195 | | { |
196 | | return const_reverse_iterator(this, true); |
197 | | } |
198 | | |
199 | | /** |
200 | | * Return an immutable iterator that points to the first segment stored in |
201 | | * the tree. It iterates through the segments one segment at a time. |
202 | | * Each iterator value consists of <code>start</code>, <code>end</code>, |
203 | | * and <code>value</code> members that correspond with the start and end |
204 | | * positions of a segment and the value of that segment, respectively. |
205 | | * |
206 | | * @return immutable iterator that points to the first segment stored in |
207 | | * the tree. |
208 | | */ |
209 | | const_segment_iterator begin_segment() const; |
210 | | |
211 | | /** |
212 | | * Return an immutable iterator that points to the position past the last |
213 | | * segment stored in the tree. It iterates through the segments one |
214 | | * segment at a time. Each iterator value consists of <code>start</code>, |
215 | | * <code>end</code>, and <code>value</code> members that correspond with |
216 | | * the start and end positions of a segment and the value of that segment, |
217 | | * respectively. |
218 | | * |
219 | | * @return immutable iterator that points to the position past the last |
220 | | * segment stored in the tree. |
221 | | */ |
222 | | const_segment_iterator end_segment() const; |
223 | | |
224 | | /** |
225 | | * Return a range object that provides a begin iterator and an end sentinel. |
226 | | */ |
227 | | const_segment_range_type segment_range() const; |
228 | | |
229 | | flat_segment_tree() = delete; |
230 | | |
231 | | /** |
232 | | * Constructor that takes minimum and maximum keys and the value to be |
233 | | * used for the initial segment. |
234 | | * |
235 | | * @param min_val minimum allowed key value for the entire series of |
236 | | * segments. |
237 | | * @param max_val maximum allowed key value for the entires series of |
238 | | * segments. |
239 | | * @param init_val value to be used for the initial segment. This value |
240 | | * will also be used for empty segments. |
241 | | */ |
242 | | flat_segment_tree(key_type min_val, key_type max_val, value_type init_val); |
243 | | |
244 | | /** |
245 | | * Copy constructor only copies the leaf nodes. |
246 | | */ |
247 | | flat_segment_tree(const flat_segment_tree& r); |
248 | | |
249 | | /** |
250 | | * Move constructor. |
251 | | * |
252 | | * @warning The source instance will not be usable after the move |
253 | | * construction. |
254 | | */ |
255 | | flat_segment_tree(flat_segment_tree&& other); |
256 | | |
257 | | ~flat_segment_tree(); |
258 | | |
259 | | /** |
260 | | * Copy assignment operator. |
261 | | * |
262 | | * @param other Source instance to copy from. |
263 | | * |
264 | | * @note It only copies the leaf nodes. |
265 | | */ |
266 | | flat_segment_tree<Key, Value>& operator=(const flat_segment_tree& other); |
267 | | |
268 | | /** |
269 | | * Move assignment operator. |
270 | | * |
271 | | * @param other Source instance to move from. |
272 | | */ |
273 | | flat_segment_tree<Key, Value>& operator=(flat_segment_tree&& other); |
274 | | |
275 | | /** |
276 | | * Swap the content of the tree with another instance. |
277 | | * |
278 | | * @param other instance of flat_segment_tree to swap content with. |
279 | | */ |
280 | | void swap(flat_segment_tree& other); |
281 | | |
282 | | /** |
283 | | * Remove all stored segments except for the initial segment. The minimum |
284 | | * and maximum keys and the default value will be retained after the call |
285 | | * returns. This call will also remove the tree. |
286 | | */ |
287 | | void clear(); |
288 | | |
289 | | /** |
290 | | * Insert a new segment into the tree. It searches for the point of |
291 | | * insertion from the first leaf node. |
292 | | * |
293 | | * @param start_key start value of the segment being inserted. The value |
294 | | * is inclusive. |
295 | | * @param end_key end value of the segment being inserted. The value is |
296 | | * not inclusive. |
297 | | * @param val value associated with this segment. |
298 | | * |
299 | | * @return pair of const_iterator corresponding to the start position of |
300 | | * the inserted segment, and a boolean value indicating whether or |
301 | | * not the insertion has modified the tree. |
302 | | */ |
303 | | std::pair<const_iterator, bool> insert_front(key_type start_key, key_type end_key, value_type val) |
304 | | { |
305 | | return insert_segment_impl(std::move(start_key), std::move(end_key), std::move(val), true); |
306 | | } |
307 | | |
308 | | /** |
309 | | * Insert a new segment into the tree. Unlike the insert_front() |
310 | | * counterpart, this method searches for the point of insertion from the |
311 | | * last leaf node toward the first. |
312 | | * |
313 | | * @param start_key start value of the segment being inserted. The value |
314 | | * is inclusive. |
315 | | * @param end_key end value of the segment being inserted. The value is |
316 | | * not inclusive. |
317 | | * @param val value associated with this segment. |
318 | | * |
319 | | * @return pair of const_iterator corresponding to the start position of |
320 | | * the inserted segment, and a boolean value indicating whether or |
321 | | * not the insertion has modified the tree. |
322 | | */ |
323 | | std::pair<const_iterator, bool> insert_back(key_type start_key, key_type end_key, value_type val) |
324 | 1.44k | { |
325 | 1.44k | return insert_segment_impl(std::move(start_key), std::move(end_key), std::move(val), false); |
326 | 1.44k | } mdds::flat_segment_tree<unsigned int, float>::insert_back(unsigned int, unsigned int, float) Line | Count | Source | 324 | 656 | { | 325 | 656 | return insert_segment_impl(std::move(start_key), std::move(end_key), std::move(val), false); | 326 | 656 | } |
mdds::flat_segment_tree<unsigned int, bool>::insert_back(unsigned int, unsigned int, bool) Line | Count | Source | 324 | 651 | { | 325 | 651 | return insert_segment_impl(std::move(start_key), std::move(end_key), std::move(val), false); | 326 | 651 | } |
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 | 324 | 133 | { | 325 | 133 | return insert_segment_impl(std::move(start_key), std::move(end_key), std::move(val), false); | 326 | 133 | } |
|
327 | | |
328 | | /** |
329 | | * Insert a new segment into the tree at or after specified point of |
330 | | * insertion. |
331 | | * |
332 | | * @param pos specified insertion point |
333 | | * @param start_key start value of the segment being inserted. The value |
334 | | * is inclusive. |
335 | | * @param end_key end value of the segment being inserted. The value is |
336 | | * not inclusive. |
337 | | * @param val value associated with this segment. |
338 | | * |
339 | | * @return pair of const_iterator corresponding to the start position of |
340 | | * the inserted segment, and a boolean value indicating whether or |
341 | | * not the insertion has modified the tree. |
342 | | */ |
343 | | std::pair<const_iterator, bool> insert(const_iterator pos, key_type start_key, key_type end_key, value_type val); |
344 | | |
345 | | /** |
346 | | * Remove a segment specified by the start and end key values, and shift |
347 | | * the remaining segments (i.e. those segments that come after the removed |
348 | | * segment) to left. Note that the start and end positions of the segment |
349 | | * being removed <b>must</b> be within the base segment span. |
350 | | * |
351 | | * @param start_key start position of the segment being removed. |
352 | | * @param end_key end position of the segment being removed. |
353 | | */ |
354 | | void shift_left(key_type start_key, key_type end_key); |
355 | | |
356 | | /** |
357 | | * Shift all segments that occur at or after the specified start position |
358 | | * to right by the size specified. |
359 | | * |
360 | | * @param pos position where the right-shift occurs. |
361 | | * @param size amount of shift (must be greater than 0) |
362 | | * @param skip_start_node if true, and the specified position is at an |
363 | | * existing node position, that node will |
364 | | * <i>not</i> be shifted. This argument has no |
365 | | * effect if the position specified does not |
366 | | * coincide with any of the existing nodes. |
367 | | */ |
368 | | void shift_right(key_type pos, key_type size, bool skip_start_node); |
369 | | |
370 | | /** |
371 | | * Perform leaf-node search for a value associated with a key. |
372 | | * |
373 | | * @param key key value |
374 | | * @param value value associated with key specified gets stored upon |
375 | | * successful search. |
376 | | * @param start_key pointer to a variable where the start key value of the |
377 | | * segment that contains the key gets stored upon |
378 | | * successful search. |
379 | | * @param end_key pointer to a varaible where the end key value of the |
380 | | * segment that contains the key gets stored upon |
381 | | * successful search. |
382 | | * @return a pair of const_iterator corresponding to the start position of |
383 | | * the segment containing the key, and a boolean value indicating |
384 | | * whether or not the search has been successful. |
385 | | * |
386 | | */ |
387 | | std::pair<const_iterator, bool> search( |
388 | | key_type key, value_type& value, key_type* start_key = nullptr, key_type* end_key = nullptr) const; |
389 | | |
390 | | /** |
391 | | * Perform leaf-node search for a value associated with a key. |
392 | | * |
393 | | * @param pos position from which the search should start. When the |
394 | | * position is invalid, it falls back to the normal search. |
395 | | * @param key key value. |
396 | | * @param value value associated with key specified gets stored upon |
397 | | * successful search. |
398 | | * @param start_key pointer to a variable where the start key value of the |
399 | | * segment that contains the key gets stored upon |
400 | | * successful search. |
401 | | * @param end_key pointer to a varaible where the end key value of the |
402 | | * segment that contains the key gets stored upon |
403 | | * successful search. |
404 | | * @return a pair of const_iterator corresponding to the start position of |
405 | | * the segment containing the key, and a boolean value indicating |
406 | | * whether or not the search has been successful. |
407 | | */ |
408 | | std::pair<const_iterator, bool> search( |
409 | | const_iterator pos, key_type key, value_type& value, key_type* start_key = nullptr, |
410 | | key_type* end_key = nullptr) const; |
411 | | |
412 | | /** |
413 | | * Perform leaf-node search for a value associated with a key. |
414 | | * |
415 | | * @param key Key value to perform search for. |
416 | | * |
417 | | * @return Iterator position associated with the start position of the |
418 | | * segment containing the key, or end iterator position upon search |
419 | | * failure. |
420 | | */ |
421 | | const_iterator search(key_type key) const; |
422 | | |
423 | | /** |
424 | | * Perform leaf-node search for a value associated with a key. |
425 | | * |
426 | | * @param pos Position from which the search should start if valid. In case |
427 | | * of an invalid position, it falls back to a search starting |
428 | | * with the first position. |
429 | | * @param key Key value to perform search for. |
430 | | * |
431 | | * @return Iterator position associated with the start position of the |
432 | | * segment containing the key, or end iterator position if the |
433 | | * search has failed. |
434 | | */ |
435 | | const_iterator search(const_iterator pos, key_type key) const; |
436 | | |
437 | | /** |
438 | | * Perform tree search for a value associated with a key. This method |
439 | | * assumes that the tree is valid. Call is_tree_valid() to find out |
440 | | * whether the tree is valid, and build_tree() to build a new tree in case |
441 | | * it's not. |
442 | | * |
443 | | * @param key key value |
444 | | * @param value value associated with key specified gets stored upon |
445 | | * successful search. |
446 | | * @param start_key pointer to a variable where the start key value of the |
447 | | * segment that contains the key gets stored upon |
448 | | * successful search. |
449 | | * @param end_key pointer to a varaible where the end key value of the |
450 | | * segment that contains the key gets stored upon |
451 | | * successful search. |
452 | | * @return a pair of const_iterator corresponding to the start position of |
453 | | * the segment containing the key, and a boolean value indicating |
454 | | * whether or not the search has been successful. |
455 | | */ |
456 | | std::pair<const_iterator, bool> search_tree( |
457 | | key_type key, value_type& value, key_type* start_key = nullptr, key_type* end_key = nullptr) const; |
458 | | |
459 | | /** |
460 | | * Perform tree search for a value associated with a key. The tree must be |
461 | | * valid before performing the search, else the search will fail. |
462 | | * |
463 | | * @param key Key value to perform search for. |
464 | | * |
465 | | * @return Iterator position associated with the start position of the |
466 | | * segment containing the key, or end iterator position if the |
467 | | * search has failed. |
468 | | */ |
469 | | const_iterator search_tree(key_type key) const; |
470 | | |
471 | | /** |
472 | | * Build a tree of non-leaf nodes based on the values stored in the leaf |
473 | | * nodes. The tree must be valid before you can call the search_tree() |
474 | | * method. |
475 | | */ |
476 | | void build_tree(); |
477 | | |
478 | | /** |
479 | | * @return true if the tree is valid, otherwise false. The tree must be |
480 | | * valid before you can call the search_tree() method. |
481 | | */ |
482 | | bool valid_tree() const noexcept |
483 | 728 | { |
484 | 728 | return m_valid_tree; |
485 | 728 | } |
486 | | |
487 | | /** |
488 | | * Equality between two flat_segment_tree instances is evaluated by |
489 | | * comparing the keys and the values of the leaf nodes only. Neither the |
490 | | * non-leaf nodes nor the validity of the tree is evaluated. |
491 | | */ |
492 | | bool operator==(const flat_segment_tree& other) const; |
493 | | |
494 | | bool operator!=(const flat_segment_tree& other) const |
495 | | { |
496 | | return !operator==(other); |
497 | | } |
498 | | |
499 | | key_type min_key() const |
500 | | { |
501 | | return m_left_leaf->key; |
502 | | } |
503 | | |
504 | | key_type max_key() const |
505 | 933 | { |
506 | 933 | return m_right_leaf->key; |
507 | 933 | } |
508 | | |
509 | | value_type default_value() const |
510 | 285 | { |
511 | 285 | return m_init_val; |
512 | 285 | } |
513 | | |
514 | | /** |
515 | | * Return the number of leaf nodes. |
516 | | * |
517 | | * @return number of leaf nodes. |
518 | | */ |
519 | | size_type leaf_size() const; |
520 | | |
521 | | #ifdef MDDS_UNIT_TEST |
522 | | const nonleaf_node* get_root_node() const |
523 | | { |
524 | | return m_root_node; |
525 | | } |
526 | | |
527 | | struct tree_dumper_traits |
528 | | { |
529 | | using leaf_type = node; |
530 | | using nonleaf_type = nonleaf_node; |
531 | | using tree_type = flat_segment_tree; |
532 | | |
533 | | struct to_string |
534 | | { |
535 | | to_string(const tree_type&) |
536 | | {} |
537 | | |
538 | | std::string operator()(const leaf_type& leaf) const |
539 | | { |
540 | | return leaf.to_string(); |
541 | | } |
542 | | |
543 | | std::string operator()(const nonleaf_type& nonleaf) const |
544 | | { |
545 | | return nonleaf.to_string(); |
546 | | } |
547 | | }; |
548 | | }; |
549 | | |
550 | | void dump_tree() const |
551 | | { |
552 | | using ::std::cout; |
553 | | using ::std::endl; |
554 | | |
555 | | if (!m_valid_tree) |
556 | | assert(!"attempted to dump an invalid tree!"); |
557 | | |
558 | | size_t node_count = mdds::st::detail::tree_dumper<tree_dumper_traits>::dump(std::cout, *this, m_root_node); |
559 | | size_t node_instance_count = node::get_instance_count(); |
560 | | size_t leaf_count = leaf_size(); |
561 | | |
562 | | cout << "tree node count = " << node_count << "; node instance count = " << node_instance_count |
563 | | << "; leaf node count = " << leaf_count << endl; |
564 | | |
565 | | assert(leaf_count == node_instance_count); |
566 | | } |
567 | | |
568 | | void dump_leaf_nodes() const |
569 | | { |
570 | | using ::std::cout; |
571 | | using ::std::endl; |
572 | | |
573 | | cout << "------------------------------------------" << endl; |
574 | | |
575 | | node_ptr cur_node = m_left_leaf; |
576 | | long node_id = 0; |
577 | | while (cur_node) |
578 | | { |
579 | | cout << " node " << node_id++ << ": key = " << cur_node->key << "; value = " << cur_node->value_leaf.value |
580 | | << endl; |
581 | | cur_node = cur_node->next; |
582 | | } |
583 | | cout << endl << " node instance count = " << node::get_instance_count() << endl; |
584 | | } |
585 | | |
586 | | /** |
587 | | * Verify keys in the leaf nodes. |
588 | | * |
589 | | * @param key_values vector containing key values in the left-to-right |
590 | | * order, including the key value of the rightmost leaf |
591 | | * node. |
592 | | */ |
593 | | bool verify_keys(const ::std::vector<key_type>& key_values) const |
594 | | { |
595 | | { |
596 | | // Start from the left-most node, and traverse right. |
597 | | node* cur_node = m_left_leaf.get(); |
598 | | typename ::std::vector<key_type>::const_iterator itr = key_values.begin(), itr_end = key_values.end(); |
599 | | for (; itr != itr_end; ++itr) |
600 | | { |
601 | | if (!cur_node) |
602 | | // Position past the right-mode node. Invalid. |
603 | | return false; |
604 | | |
605 | | if (cur_node->key != *itr) |
606 | | // Key values differ. |
607 | | return false; |
608 | | |
609 | | cur_node = cur_node->next.get(); |
610 | | } |
611 | | |
612 | | if (cur_node) |
613 | | // At this point, we expect the current node to be at the position |
614 | | // past the right-most node, which is nullptr. |
615 | | return false; |
616 | | } |
617 | | |
618 | | { |
619 | | // Start from the right-most node, and traverse left. |
620 | | node* cur_node = m_right_leaf.get(); |
621 | | typename ::std::vector<key_type>::const_reverse_iterator itr = key_values.rbegin(), |
622 | | itr_end = key_values.rend(); |
623 | | for (; itr != itr_end; ++itr) |
624 | | { |
625 | | if (!cur_node) |
626 | | // Position past the left-mode node. Invalid. |
627 | | return false; |
628 | | |
629 | | if (cur_node->key != *itr) |
630 | | // Key values differ. |
631 | | return false; |
632 | | |
633 | | cur_node = cur_node->prev.get(); |
634 | | } |
635 | | |
636 | | if (cur_node) |
637 | | // Likewise, we expect the current position to be past the |
638 | | // left-most node, in which case the node value is nullptr. |
639 | | return false; |
640 | | } |
641 | | |
642 | | return true; |
643 | | } |
644 | | |
645 | | /** |
646 | | * Verify values in the leaf nodes. |
647 | | * |
648 | | * @param values vector containing values to verify against, in the |
649 | | * left-to-right order, <i>not</i> including the value of |
650 | | * the rightmost leaf node. |
651 | | */ |
652 | | bool verify_values(const ::std::vector<value_type>& values) const |
653 | | { |
654 | | node* cur_node = m_left_leaf.get(); |
655 | | node* end_node = m_right_leaf.get(); |
656 | | typename ::std::vector<value_type>::const_iterator itr = values.begin(), itr_end = values.end(); |
657 | | for (; itr != itr_end; ++itr) |
658 | | { |
659 | | if (cur_node == end_node || !cur_node) |
660 | | return false; |
661 | | |
662 | | if (cur_node->value_leaf.value != *itr) |
663 | | // Key values differ. |
664 | | return false; |
665 | | |
666 | | cur_node = cur_node->next.get(); |
667 | | } |
668 | | |
669 | | if (cur_node != end_node) |
670 | | // At this point, we expect the current node to be at the end of |
671 | | // range. |
672 | | return false; |
673 | | |
674 | | return true; |
675 | | } |
676 | | #endif |
677 | | |
678 | | private: |
679 | | const_iterator search_by_key_impl(const node* start_pos, key_type key) const; |
680 | | |
681 | | const node* search_tree_for_leaf_node(key_type key) const; |
682 | | |
683 | | void append_new_segment(key_type start_key) |
684 | | { |
685 | | if (m_right_leaf->prev->key == start_key) |
686 | | { |
687 | | m_right_leaf->prev->value_leaf.value = m_init_val; |
688 | | return; |
689 | | } |
690 | | |
691 | | #ifdef MDDS_UNIT_TEST |
692 | | // The start position must come after the position of the last node |
693 | | // before the right-most node. |
694 | | assert(m_right_leaf->prev->key < start_key); |
695 | | #endif |
696 | | |
697 | | if (m_right_leaf->prev->value_leaf.value == m_init_val) |
698 | | // The existing segment has the same value. No need to insert a |
699 | | // new segment. |
700 | | return; |
701 | | |
702 | | node_ptr new_node(new node); |
703 | | new_node->key = start_key; |
704 | | new_node->value_leaf.value = m_init_val; |
705 | | new_node->prev = m_right_leaf->prev; |
706 | | new_node->next = m_right_leaf; |
707 | | m_right_leaf->prev->next = new_node; |
708 | | m_right_leaf->prev = std::move(new_node); |
709 | | m_valid_tree = false; |
710 | | } |
711 | | |
712 | | ::std::pair<const_iterator, bool> insert_segment_impl( |
713 | | key_type start_key, key_type end_key, value_type val, bool forward); |
714 | | |
715 | | ::std::pair<const_iterator, bool> insert_to_pos( |
716 | | node_ptr start_pos, key_type start_key, key_type end_key, value_type val); |
717 | | |
718 | | ::std::pair<const_iterator, bool> search_impl( |
719 | | const node* pos, key_type key, value_type& value, key_type* start_key, key_type* end_key) const; |
720 | | |
721 | | const node* get_insertion_pos_leaf_reverse(const key_type& key, const node* start_pos) const; |
722 | | |
723 | | /** |
724 | | * Find a node with the largest value whose key equals or less than a |
725 | | * specified key, starting with a specific node. |
726 | | * |
727 | | * @pre The caller must ensure that the key equals or greater than the min |
728 | | * key. |
729 | | * |
730 | | * @note If the key exceeds the max key value, it will return |
731 | | * <code>nullptr</code>. |
732 | | */ |
733 | | const node* get_insertion_pos_leaf(const key_type& key, const node* start_pos) const; |
734 | | |
735 | | static void shift_leaf_key_left(node_ptr& begin_node, node_ptr& end_node, key_type shift_value) |
736 | | { |
737 | | node* cur_node_p = begin_node.get(); |
738 | | node* end_node_p = end_node.get(); |
739 | | while (cur_node_p != end_node_p) |
740 | | { |
741 | | cur_node_p->key -= shift_value; |
742 | | cur_node_p = cur_node_p->next.get(); |
743 | | } |
744 | | } |
745 | | |
746 | | static void shift_leaf_key_right(node_ptr& cur_node, node_ptr& end_node, key_type shift_value) |
747 | | { |
748 | | key_type end_node_key = end_node->key; |
749 | | while (cur_node.get() != end_node.get()) |
750 | | { |
751 | | cur_node->key += shift_value; |
752 | | if (cur_node->key < end_node_key) |
753 | | { |
754 | | // The node is still in-bound. Keep shifting. |
755 | | cur_node = cur_node->next; |
756 | | continue; |
757 | | } |
758 | | |
759 | | // This node has been pushed outside the end node position. |
760 | | // Remove all nodes that follows, and connect the previous node |
761 | | // with the end node. |
762 | | |
763 | | node_ptr last_node = cur_node->prev; |
764 | | while (cur_node.get() != end_node.get()) |
765 | | { |
766 | | node_ptr next_node = cur_node->next; |
767 | | disconnect_all_nodes(cur_node.get()); |
768 | | cur_node = std::move(next_node); |
769 | | } |
770 | | last_node->next = end_node; |
771 | | end_node->prev = std::move(last_node); |
772 | | return; |
773 | | } |
774 | | } |
775 | | |
776 | | void destroy(); |
777 | | |
778 | | /** |
779 | | * Check and optionally adjust the start and end key values if one of them |
780 | | * is out-of-bound. |
781 | | * |
782 | | * @return true if the start and end key values are valid, either with or |
783 | | * without adjustments, otherwise false. |
784 | | */ |
785 | | bool adjust_segment_range(key_type& start_key, key_type& end_key) const; |
786 | | |
787 | | private: |
788 | | std::vector<nonleaf_node> m_nonleaf_node_pool; |
789 | | |
790 | | const nonleaf_node* m_root_node; |
791 | | node_ptr m_left_leaf; |
792 | | node_ptr m_right_leaf; |
793 | | value_type m_init_val; |
794 | | bool m_valid_tree; |
795 | | }; |
796 | | |
797 | | template<typename Key, typename Value> |
798 | | void swap(flat_segment_tree<Key, Value>& left, flat_segment_tree<Key, Value>& right) |
799 | | { |
800 | | left.swap(right); |
801 | | } |
802 | | |
803 | | } // namespace mdds |
804 | | |
805 | | #include "flat_segment_tree_def.inl" |
806 | | |
807 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |