Coverage Report

Created: 2026-06-13 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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: */