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/node.hpp
Line
Count
Source
1
/*************************************************************************
2
 *
3
 * Copyright (c) 2008-2014 Kohei Yoshida
4
 *
5
 * Permission is hereby granted, free of charge, to any person
6
 * obtaining a copy of this software and associated documentation
7
 * files (the "Software"), to deal in the Software without
8
 * restriction, including without limitation the rights to use,
9
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the
11
 * Software is furnished to do so, subject to the following
12
 * conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be
15
 * included in all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24
 * OTHER DEALINGS IN THE SOFTWARE.
25
 *
26
 ************************************************************************/
27
28
#ifndef __MDDS_NODE_HXX__
29
#define __MDDS_NODE_HXX__
30
31
#include "mdds/global.hpp"
32
33
#include <iostream>
34
#include <vector>
35
#include <cassert>
36
#include <sstream>
37
38
#include <boost/intrusive_ptr.hpp>
39
40
namespace mdds { namespace st { namespace detail {
41
42
#ifdef MDDS_DEBUG_NODE_BASE
43
44
inline std::size_t node_instance_count = 0;
45
46
#endif
47
48
struct node_base
49
{
50
    node_base* parent; /// parent nonleaf_node
51
    bool is_leaf;
52
53
2.33k
    node_base(bool _is_leaf) : parent(nullptr), is_leaf(_is_leaf)
54
2.33k
    {}
55
538
    node_base(const node_base& r) : parent(nullptr), is_leaf(r.is_leaf)
56
538
    {}
57
};
58
59
/**
60
 * Represents a non-leaf node in a segment-tree like structure.
61
 */
62
template<typename KeyT, typename ValueT>
63
struct nonleaf_node : public node_base
64
{
65
    using key_type = KeyT;
66
    using nonleaf_value_type = ValueT;
67
68
    nonleaf_value_type value_nonleaf;
69
70
    key_type low = {}; /// low range value (inclusive)
71
    key_type high = {}; /// high range value (non-inclusive)
72
73
    node_base* left = nullptr; /// left child nonleaf_node
74
    node_base* right = nullptr; /// right child nonleaf_node
75
76
public:
77
381
    nonleaf_node() : node_base(false), value_nonleaf()
78
381
    {}
79
80
    /**
81
     * When copying nonleaf_node, only the stored values should be copied.
82
     * Connections to the parent, left and right nodes must not be copied.
83
     */
84
0
    nonleaf_node(const nonleaf_node& r) : node_base(r), value_nonleaf(r.value_nonleaf), low(r.low), high(r.high)
85
0
    {}
86
87
    /**
88
     * Like the copy constructor, only the stored values should be copied.
89
     */
90
    nonleaf_node& operator=(const nonleaf_node& r)
91
    {
92
        if (this == &r)
93
            // assignment to self.
94
            return *this;
95
96
        value_nonleaf = r.value_nonleaf;
97
        return *this;
98
    }
99
100
    bool operator==(const nonleaf_node& r) const
101
    {
102
        return low == r.low && high == r.high && value_nonleaf == r.value_nonleaf;
103
    }
104
105
    bool operator!=(const nonleaf_node& r) const
106
    {
107
        return !operator==(r);
108
    }
109
110
    std::string to_string() const
111
    {
112
        std::ostringstream os;
113
        os << "[" << low << "-" << high << ")";
114
        return os.str();
115
    }
116
};
117
118
/**
119
 * Represents a leaf node in a segment-tree like structure.
120
 */
121
template<typename KeyT, typename ValueT>
122
struct node : node_base
123
{
124
    using key_type = KeyT;
125
    using leaf_value_type = ValueT;
126
    using node_ptr = boost::intrusive_ptr<node>;
127
128
    static size_t get_instance_count()
129
    {
130
#ifdef MDDS_DEBUG_NODE_BASE
131
        return node_instance_count;
132
#else
133
        return 0;
134
#endif
135
    }
136
137
    leaf_value_type value_leaf;
138
139
    key_type key = {};
140
141
    node_ptr prev; /// previous sibling leaf node.
142
    node_ptr next; /// next sibling leaf node.
143
144
    std::size_t refcount = 0;
145
146
public:
147
1.95k
    node() : node_base(true)
148
1.95k
    {
149
#ifdef MDDS_DEBUG_NODE_BASE
150
        ++node_instance_count;
151
#endif
152
1.95k
    }
mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, float>::leaf_value_type>::node()
Line
Count
Source
147
988
    node() : node_base(true)
148
988
    {
149
#ifdef MDDS_DEBUG_NODE_BASE
150
        ++node_instance_count;
151
#endif
152
988
    }
mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, bool>::leaf_value_type>::node()
Line
Count
Source
147
424
    node() : node_base(true)
148
424
    {
149
#ifdef MDDS_DEBUG_NODE_BASE
150
        ++node_instance_count;
151
#endif
152
424
    }
mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> >::leaf_value_type>::node()
Line
Count
Source
147
540
    node() : node_base(true)
148
540
    {
149
#ifdef MDDS_DEBUG_NODE_BASE
150
        ++node_instance_count;
151
#endif
152
540
    }
153
154
    /**
155
     * When copying node, only the stored values should be copied.
156
     * Connections to the parent, left and right nodes must not be copied.
157
     */
158
538
    node(const node& r) : node_base(r), key(r.key)
159
538
    {
160
#ifdef MDDS_DEBUG_NODE_BASE
161
        ++node_instance_count;
162
#endif
163
538
        value_leaf = r.value_leaf;
164
538
    }
165
166
    /**
167
     * Like the copy constructor, only the stored values should be copied.
168
     */
169
    node& operator=(const node& r)
170
    {
171
        if (this == &r)
172
            // assignment to self.
173
            return *this;
174
175
        value_leaf = r.value_leaf;
176
        return *this;
177
    }
178
179
    ~node()
180
2.49k
    {
181
#ifdef MDDS_DEBUG_NODE_BASE
182
        --node_instance_count;
183
#endif
184
2.49k
    }
mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, bool>::leaf_value_type>::~node()
Line
Count
Source
180
424
    {
181
#ifdef MDDS_DEBUG_NODE_BASE
182
        --node_instance_count;
183
#endif
184
424
    }
mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> >::leaf_value_type>::~node()
Line
Count
Source
180
1.07k
    {
181
#ifdef MDDS_DEBUG_NODE_BASE
182
        --node_instance_count;
183
#endif
184
1.07k
    }
mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, float>::leaf_value_type>::~node()
Line
Count
Source
180
988
    {
181
#ifdef MDDS_DEBUG_NODE_BASE
182
        --node_instance_count;
183
#endif
184
988
    }
185
186
    bool operator==(const node& r) const
187
    {
188
        return key == r.key && value_leaf == r.value_leaf;
189
    }
190
191
    bool operator!=(const node& r) const
192
    {
193
        return !operator==(r);
194
    }
195
196
    std::string to_string() const
197
    {
198
        std::ostringstream os;
199
        os << "[" << key << "]";
200
        return os.str();
201
    }
202
};
203
204
template<typename KeyT, typename ValueT>
205
inline void intrusive_ptr_add_ref(node<KeyT, ValueT>* p)
206
15.3k
{
207
15.3k
    ++p->refcount;
208
15.3k
}
void mdds::st::detail::intrusive_ptr_add_ref<unsigned int, mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> >::leaf_value_type>(mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> >::leaf_value_type>*)
Line
Count
Source
206
5.21k
{
207
5.21k
    ++p->refcount;
208
5.21k
}
void mdds::st::detail::intrusive_ptr_add_ref<unsigned int, mdds::flat_segment_tree<unsigned int, float>::leaf_value_type>(mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, float>::leaf_value_type>*)
Line
Count
Source
206
6.79k
{
207
6.79k
    ++p->refcount;
208
6.79k
}
void mdds::st::detail::intrusive_ptr_add_ref<unsigned int, mdds::flat_segment_tree<unsigned int, bool>::leaf_value_type>(mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, bool>::leaf_value_type>*)
Line
Count
Source
206
3.29k
{
207
3.29k
    ++p->refcount;
208
3.29k
}
209
210
template<typename KeyT, typename ValueT>
211
inline void intrusive_ptr_release(node<KeyT, ValueT>* p)
212
15.3k
{
213
15.3k
    --p->refcount;
214
15.3k
    if (!p->refcount)
215
2.49k
        delete p;
216
15.3k
}
void mdds::st::detail::intrusive_ptr_release<unsigned int, mdds::flat_segment_tree<unsigned int, bool>::leaf_value_type>(mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, bool>::leaf_value_type>*)
Line
Count
Source
212
3.29k
{
213
3.29k
    --p->refcount;
214
3.29k
    if (!p->refcount)
215
424
        delete p;
216
3.29k
}
void mdds::st::detail::intrusive_ptr_release<unsigned int, mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> >::leaf_value_type>(mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> >::leaf_value_type>*)
Line
Count
Source
212
5.21k
{
213
5.21k
    --p->refcount;
214
5.21k
    if (!p->refcount)
215
1.07k
        delete p;
216
5.21k
}
void mdds::st::detail::intrusive_ptr_release<unsigned int, mdds::flat_segment_tree<unsigned int, float>::leaf_value_type>(mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, float>::leaf_value_type>*)
Line
Count
Source
212
6.79k
{
213
6.79k
    --p->refcount;
214
6.79k
    if (!p->refcount)
215
988
        delete p;
216
6.79k
}
217
218
template<typename NodePtrT>
219
void link_nodes(NodePtrT& left, NodePtrT& right)
220
1.66k
{
221
1.66k
    left->next = right;
222
1.66k
    right->prev = left;
223
1.66k
}
void mdds::st::detail::link_nodes<boost::intrusive_ptr<mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, float>::leaf_value_type> > >(boost::intrusive_ptr<mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, float>::leaf_value_type> >&, boost::intrusive_ptr<mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, float>::leaf_value_type> >&)
Line
Count
Source
220
1.12k
{
221
1.12k
    left->next = right;
222
1.12k
    right->prev = left;
223
1.12k
}
Unexecuted instantiation: void mdds::st::detail::link_nodes<boost::intrusive_ptr<mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, bool>::leaf_value_type> > >(boost::intrusive_ptr<mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, bool>::leaf_value_type> >&, boost::intrusive_ptr<mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, bool>::leaf_value_type> >&)
void mdds::st::detail::link_nodes<boost::intrusive_ptr<mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> >::leaf_value_type> > >(boost::intrusive_ptr<mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> >::leaf_value_type> >&, boost::intrusive_ptr<mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> >::leaf_value_type> >&)
Line
Count
Source
220
532
{
221
532
    left->next = right;
222
532
    right->prev = left;
223
532
}
224
225
template<typename T>
226
class tree_builder
227
{
228
public:
229
    typedef typename T::node leaf_node;
230
    typedef typename leaf_node::node_ptr leaf_node_ptr;
231
    typedef typename T::nonleaf_node nonleaf_node;
232
    typedef std::vector<nonleaf_node> nonleaf_node_pool_type;
233
234
129
    tree_builder(nonleaf_node_pool_type& pool) : m_pool(pool), m_pool_pos(pool.begin()), m_pool_pos_end(pool.end())
235
129
    {}
236
237
    nonleaf_node* build(const leaf_node_ptr& left_leaf_node)
238
129
    {
239
129
        if (!left_leaf_node)
240
            // The left leaf node is empty.  Nothing to build.
241
0
            return nullptr;
242
243
129
        leaf_node_ptr node1 = left_leaf_node;
244
245
129
        std::vector<nonleaf_node*> node_list;
246
255
        while (true)
247
255
        {
248
255
            leaf_node_ptr node2 = node1->next;
249
255
            nonleaf_node* parent_node = make_parent_node(node1.get(), node2.get());
250
255
            node_list.push_back(parent_node);
251
252
255
            if (!node2 || !node2->next)
253
                // no more nodes.  Break out of the loop.
254
129
                break;
255
256
126
            node1 = node2->next;
257
126
        }
258
259
129
        return build_tree_non_leaf(node_list);
260
129
    }
261
262
private:
263
    nonleaf_node* make_parent_node(node_base* node1, node_base* node2)
264
381
    {
265
381
        assert(m_pool_pos != m_pool_pos_end);
266
267
381
        nonleaf_node* parent_node = &(*m_pool_pos);
268
381
        ++m_pool_pos;
269
381
        node1->parent = parent_node;
270
381
        parent_node->left = node1;
271
381
        if (node2)
272
381
        {
273
381
            node2->parent = parent_node;
274
381
            parent_node->right = node2;
275
381
        }
276
277
381
        fill_nonleaf_parent_node(parent_node, node1, node2);
278
381
        return parent_node;
279
381
    }
280
281
    void fill_nonleaf_parent_node(nonleaf_node* parent_node, const node_base* left_node, const node_base* right_node)
282
381
    {
283
        // Parent node should carry the range of all of its child nodes.
284
381
        if (left_node)
285
381
        {
286
381
            parent_node->low = left_node->is_leaf ? static_cast<const leaf_node*>(left_node)->key
287
381
                                                  : static_cast<const nonleaf_node*>(left_node)->low;
288
381
        }
289
0
        else
290
0
        {
291
            // Having a left node is prerequisite.
292
0
            throw general_error("fill_nonleaf_parent_node: Having a left node is prerequisite.");
293
0
        }
294
295
381
        if (right_node)
296
381
        {
297
381
            if (right_node->is_leaf)
298
255
            {
299
                // When the child nodes are leaf nodes, the upper bound
300
                // must be the value of the node that comes after the
301
                // right leaf node (if such node exists).
302
303
255
                const auto* p = static_cast<const leaf_node*>(right_node);
304
255
                if (p->next)
305
126
                    parent_node->high = p->next->key;
306
129
                else
307
129
                    parent_node->high = p->key;
308
255
            }
309
126
            else
310
126
            {
311
126
                parent_node->high = static_cast<const nonleaf_node*>(right_node)->high;
312
126
            }
313
381
        }
314
0
        else
315
0
        {
316
0
            parent_node->high = left_node->is_leaf ? static_cast<const leaf_node*>(left_node)->key
317
0
                                                   : static_cast<const nonleaf_node*>(left_node)->high;
318
0
        }
319
381
    }
320
321
    nonleaf_node* build_tree_non_leaf(const std::vector<nonleaf_node*>& node_list)
322
255
    {
323
255
        size_t node_count = node_list.size();
324
255
        if (node_count == 1)
325
129
        {
326
129
            return node_list.front();
327
129
        }
328
126
        else if (node_count == 0)
329
0
            return nullptr;
330
331
126
        std::vector<nonleaf_node*> new_node_list;
332
126
        nonleaf_node* node1 = nullptr;
333
126
        typename std::vector<nonleaf_node*>::const_iterator it = node_list.begin();
334
126
        typename std::vector<nonleaf_node*>::const_iterator it_end = node_list.end();
335
378
        for (bool even_itr = false; it != it_end; ++it, even_itr = !even_itr)
336
252
        {
337
252
            if (even_itr)
338
126
            {
339
126
                nonleaf_node* node2 = *it;
340
126
                nonleaf_node* parent_node = make_parent_node(node1, node2);
341
126
                new_node_list.push_back(parent_node);
342
126
                node1 = nullptr;
343
126
                node2 = nullptr;
344
126
            }
345
126
            else
346
126
                node1 = *it;
347
252
        }
348
349
126
        if (node1)
350
0
        {
351
            // Un-paired node still needs a parent...
352
0
            nonleaf_node* parent_node = make_parent_node(node1, nullptr);
353
0
            new_node_list.push_back(parent_node);
354
0
        }
355
356
        // Move up one level, and do the same procedure until the root node is reached.
357
126
        return build_tree_non_leaf(new_node_list);
358
255
    }
359
360
    nonleaf_node_pool_type& m_pool;
361
    typename nonleaf_node_pool_type::iterator m_pool_pos;
362
    typename nonleaf_node_pool_type::iterator m_pool_pos_end;
363
};
364
365
template<typename KeyT, typename ValueT>
366
void disconnect_all_nodes(node<KeyT, ValueT>* p)
367
2.00k
{
368
2.00k
    if (!p)
369
0
        return;
370
371
2.00k
    p->prev.reset();
372
2.00k
    p->next.reset();
373
2.00k
    p->parent = nullptr;
374
2.00k
}
void mdds::st::detail::disconnect_all_nodes<unsigned int, mdds::flat_segment_tree<unsigned int, bool>::leaf_value_type>(mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, bool>::leaf_value_type>*)
Line
Count
Source
367
424
{
368
424
    if (!p)
369
0
        return;
370
371
424
    p->prev.reset();
372
424
    p->next.reset();
373
424
    p->parent = nullptr;
374
424
}
void mdds::st::detail::disconnect_all_nodes<unsigned int, mdds::flat_segment_tree<unsigned int, float>::leaf_value_type>(mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, float>::leaf_value_type>*)
Line
Count
Source
367
498
{
368
498
    if (!p)
369
0
        return;
370
371
498
    p->prev.reset();
372
498
    p->next.reset();
373
498
    p->parent = nullptr;
374
498
}
void mdds::st::detail::disconnect_all_nodes<unsigned int, mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> >::leaf_value_type>(mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> >::leaf_value_type>*)
Line
Count
Source
367
1.07k
{
368
1.07k
    if (!p)
369
0
        return;
370
371
1.07k
    p->prev.reset();
372
1.07k
    p->next.reset();
373
1.07k
    p->parent = nullptr;
374
1.07k
}
375
376
template<typename KeyT, typename ValueT>
377
void disconnect_leaf_nodes(node<KeyT, ValueT>* left_node, node<KeyT, ValueT>* right_node)
378
971
{
379
971
    if (!left_node || !right_node)
380
274
        return;
381
382
    // Go through all leaf nodes, and disconnect their links.
383
697
    auto* cur_node = left_node;
384
697
    do
385
1.30k
    {
386
1.30k
        auto* next_node = cur_node->next.get();
387
1.30k
        disconnect_all_nodes(cur_node);
388
1.30k
        cur_node = next_node;
389
1.30k
    } while (cur_node != right_node);
390
391
697
    disconnect_all_nodes(right_node);
392
697
}
void mdds::st::detail::disconnect_leaf_nodes<unsigned int, mdds::flat_segment_tree<unsigned int, bool>::leaf_value_type>(mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, bool>::leaf_value_type>*, mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, bool>::leaf_value_type>*)
Line
Count
Source
378
212
{
379
212
    if (!left_node || !right_node)
380
0
        return;
381
382
    // Go through all leaf nodes, and disconnect their links.
383
212
    auto* cur_node = left_node;
384
212
    do
385
212
    {
386
212
        auto* next_node = cur_node->next.get();
387
212
        disconnect_all_nodes(cur_node);
388
212
        cur_node = next_node;
389
212
    } while (cur_node != right_node);
390
391
212
    disconnect_all_nodes(right_node);
392
212
}
void mdds::st::detail::disconnect_leaf_nodes<unsigned int, mdds::flat_segment_tree<unsigned int, float>::leaf_value_type>(mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, float>::leaf_value_type>*, mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, float>::leaf_value_type>*)
Line
Count
Source
378
212
{
379
212
    if (!left_node || !right_node)
380
0
        return;
381
382
    // Go through all leaf nodes, and disconnect their links.
383
212
    auto* cur_node = left_node;
384
212
    do
385
286
    {
386
286
        auto* next_node = cur_node->next.get();
387
286
        disconnect_all_nodes(cur_node);
388
286
        cur_node = next_node;
389
286
    } while (cur_node != right_node);
390
391
212
    disconnect_all_nodes(right_node);
392
212
}
void mdds::st::detail::disconnect_leaf_nodes<unsigned int, mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> >::leaf_value_type>(mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> >::leaf_value_type>*, mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> >::leaf_value_type>*)
Line
Count
Source
378
547
{
379
547
    if (!left_node || !right_node)
380
274
        return;
381
382
    // Go through all leaf nodes, and disconnect their links.
383
273
    auto* cur_node = left_node;
384
273
    do
385
805
    {
386
805
        auto* next_node = cur_node->next.get();
387
805
        disconnect_all_nodes(cur_node);
388
805
        cur_node = next_node;
389
805
    } while (cur_node != right_node);
390
391
273
    disconnect_all_nodes(right_node);
392
273
}
393
394
template<typename KeyT, typename ValueT>
395
size_t count_leaf_nodes(const node<KeyT, ValueT>* left_end, const node<KeyT, ValueT>* right_end)
396
129
{
397
129
    size_t leaf_count = 1;
398
129
    const auto* p = left_end;
399
129
    const auto* p_end = right_end;
400
510
    for (; p != p_end; p = p->next.get(), ++leaf_count)
401
381
        ;
402
403
129
    return leaf_count;
404
129
}
405
406
inline size_t count_needed_nonleaf_nodes(size_t leaf_count)
407
129
{
408
129
    size_t nonleaf_count = 0;
409
384
    while (true)
410
384
    {
411
384
        if (leaf_count == 1)
412
129
            break;
413
414
255
        if ((leaf_count % 2) == 1)
415
            // Add one to make it an even number.
416
0
            ++leaf_count;
417
418
255
        leaf_count /= 2;
419
255
        nonleaf_count += leaf_count;
420
255
    }
421
422
129
    return nonleaf_count;
423
129
}
424
425
template<typename TraitsT>
426
class tree_dumper
427
{
428
    using node_list_type = std::vector<const node_base*>;
429
    using tree_type = typename TraitsT::tree_type;
430
431
public:
432
    static size_t dump(std::ostream& os, const tree_type& tree, const node_base* root_node)
433
    {
434
        if (!root_node)
435
            return 0;
436
437
        node_list_type node_list;
438
        node_list.push_back(root_node);
439
        return dump_layer(os, tree, node_list, 0);
440
    }
441
442
private:
443
    static size_t dump_layer(
444
        std::ostream& os, const tree_type& tree, const node_list_type& node_list, unsigned int level)
445
    {
446
        using leaf_type = typename TraitsT::leaf_type;
447
        using nonleaf_type = typename TraitsT::nonleaf_type;
448
        using to_string = typename TraitsT::to_string;
449
450
        if (node_list.empty())
451
            return 0;
452
453
        size_t node_count = node_list.size();
454
455
        bool is_leaf = node_list.front()->is_leaf;
456
        os << "level " << level << ':' << std::endl;
457
        os << "  type: " << (is_leaf ? "leaf" : "non-leaf") << std::endl;
458
        os << "  nodes:" << std::endl;
459
460
        node_list_type new_list;
461
462
        for (const node_base* p : node_list)
463
        {
464
            os << "    - '";
465
466
            if (!p)
467
            {
468
                os << "*'" << std::endl;
469
                continue;
470
            }
471
472
            if (p->is_leaf)
473
            {
474
                const auto* pl = static_cast<const leaf_type*>(p);
475
                os << to_string{tree}(*pl) << "'" << std::endl;
476
                continue;
477
            }
478
479
            const auto* pnl = static_cast<const nonleaf_type*>(p);
480
            os << to_string{tree}(*pnl) << "'" << std::endl;
481
482
            if (pnl->left)
483
            {
484
                new_list.push_back(pnl->left);
485
                if (pnl->right)
486
                    new_list.push_back(pnl->right);
487
            }
488
        }
489
490
        if (!new_list.empty())
491
            node_count += dump_layer(os, tree, new_list, level + 1);
492
493
        return node_count;
494
    }
495
};
496
497
}}} // namespace mdds::st::detail
498
499
#endif