Coverage Report

Created: 2026-07-20 07:04

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
3.43k
    node_base(bool _is_leaf) : parent(nullptr), is_leaf(_is_leaf)
54
3.43k
    {}
55
868
    node_base(const node_base& r) : parent(nullptr), is_leaf(r.is_leaf)
56
868
    {}
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
583
    nonleaf_node() : node_base(false), value_nonleaf()
78
583
    {}
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
2.85k
    node() : node_base(true)
148
2.85k
    {
149
#ifdef MDDS_DEBUG_NODE_BASE
150
        ++node_instance_count;
151
#endif
152
2.85k
    }
mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, float>::leaf_value_type>::node()
Line
Count
Source
147
1.38k
    node() : node_base(true)
148
1.38k
    {
149
#ifdef MDDS_DEBUG_NODE_BASE
150
        ++node_instance_count;
151
#endif
152
1.38k
    }
mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, bool>::leaf_value_type>::node()
Line
Count
Source
147
588
    node() : node_base(true)
148
588
    {
149
#ifdef MDDS_DEBUG_NODE_BASE
150
        ++node_instance_count;
151
#endif
152
588
    }
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
886
    node() : node_base(true)
148
886
    {
149
#ifdef MDDS_DEBUG_NODE_BASE
150
        ++node_instance_count;
151
#endif
152
886
    }
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
868
    node(const node& r) : node_base(r), key(r.key)
159
868
    {
160
#ifdef MDDS_DEBUG_NODE_BASE
161
        ++node_instance_count;
162
#endif
163
868
        value_leaf = r.value_leaf;
164
868
    }
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
3.72k
    {
181
#ifdef MDDS_DEBUG_NODE_BASE
182
        --node_instance_count;
183
#endif
184
3.72k
    }
mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, bool>::leaf_value_type>::~node()
Line
Count
Source
180
588
    {
181
#ifdef MDDS_DEBUG_NODE_BASE
182
        --node_instance_count;
183
#endif
184
588
    }
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.75k
    {
181
#ifdef MDDS_DEBUG_NODE_BASE
182
        --node_instance_count;
183
#endif
184
1.75k
    }
mdds::st::detail::node<unsigned int, mdds::flat_segment_tree<unsigned int, float>::leaf_value_type>::~node()
Line
Count
Source
180
1.38k
    {
181
#ifdef MDDS_DEBUG_NODE_BASE
182
        --node_instance_count;
183
#endif
184
1.38k
    }
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
22.7k
{
207
22.7k
    ++p->refcount;
208
22.7k
}
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
8.45k
{
207
8.45k
    ++p->refcount;
208
8.45k
}
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
9.63k
{
207
9.63k
    ++p->refcount;
208
9.63k
}
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
4.67k
{
207
4.67k
    ++p->refcount;
208
4.67k
}
209
210
template<typename KeyT, typename ValueT>
211
inline void intrusive_ptr_release(node<KeyT, ValueT>* p)
212
22.7k
{
213
22.7k
    --p->refcount;
214
22.7k
    if (!p->refcount)
215
3.72k
        delete p;
216
22.7k
}
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
4.67k
{
213
4.67k
    --p->refcount;
214
4.67k
    if (!p->refcount)
215
588
        delete p;
216
4.67k
}
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
8.45k
{
213
8.45k
    --p->refcount;
214
8.45k
    if (!p->refcount)
215
1.75k
        delete p;
216
8.45k
}
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
9.63k
{
213
9.63k
    --p->refcount;
214
9.63k
    if (!p->refcount)
215
1.38k
        delete p;
216
9.63k
}
217
218
template<typename NodePtrT>
219
void link_nodes(NodePtrT& left, NodePtrT& right)
220
2.45k
{
221
2.45k
    left->next = right;
222
2.45k
    right->prev = left;
223
2.45k
}
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.58k
{
221
1.58k
    left->next = right;
222
1.58k
    right->prev = left;
223
1.58k
}
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
872
{
221
872
    left->next = right;
222
872
    right->prev = left;
223
872
}
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
197
    tree_builder(nonleaf_node_pool_type& pool) : m_pool(pool), m_pool_pos(pool.begin()), m_pool_pos_end(pool.end())
235
197
    {}
236
237
    nonleaf_node* build(const leaf_node_ptr& left_leaf_node)
238
197
    {
239
197
        if (!left_leaf_node)
240
            // The left leaf node is empty.  Nothing to build.
241
0
            return nullptr;
242
243
197
        leaf_node_ptr node1 = left_leaf_node;
244
245
197
        std::vector<nonleaf_node*> node_list;
246
390
        while (true)
247
390
        {
248
390
            leaf_node_ptr node2 = node1->next;
249
390
            nonleaf_node* parent_node = make_parent_node(node1.get(), node2.get());
250
390
            node_list.push_back(parent_node);
251
252
390
            if (!node2 || !node2->next)
253
                // no more nodes.  Break out of the loop.
254
197
                break;
255
256
193
            node1 = node2->next;
257
193
        }
258
259
197
        return build_tree_non_leaf(node_list);
260
197
    }
261
262
private:
263
    nonleaf_node* make_parent_node(node_base* node1, node_base* node2)
264
583
    {
265
583
        assert(m_pool_pos != m_pool_pos_end);
266
267
583
        nonleaf_node* parent_node = &(*m_pool_pos);
268
583
        ++m_pool_pos;
269
583
        node1->parent = parent_node;
270
583
        parent_node->left = node1;
271
583
        if (node2)
272
583
        {
273
583
            node2->parent = parent_node;
274
583
            parent_node->right = node2;
275
583
        }
276
277
583
        fill_nonleaf_parent_node(parent_node, node1, node2);
278
583
        return parent_node;
279
583
    }
280
281
    void fill_nonleaf_parent_node(nonleaf_node* parent_node, const node_base* left_node, const node_base* right_node)
282
583
    {
283
        // Parent node should carry the range of all of its child nodes.
284
583
        if (left_node)
285
583
        {
286
583
            parent_node->low = left_node->is_leaf ? static_cast<const leaf_node*>(left_node)->key
287
583
                                                  : static_cast<const nonleaf_node*>(left_node)->low;
288
583
        }
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
583
        if (right_node)
296
583
        {
297
583
            if (right_node->is_leaf)
298
390
            {
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
390
                const auto* p = static_cast<const leaf_node*>(right_node);
304
390
                if (p->next)
305
193
                    parent_node->high = p->next->key;
306
197
                else
307
197
                    parent_node->high = p->key;
308
390
            }
309
193
            else
310
193
            {
311
193
                parent_node->high = static_cast<const nonleaf_node*>(right_node)->high;
312
193
            }
313
583
        }
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
583
    }
320
321
    nonleaf_node* build_tree_non_leaf(const std::vector<nonleaf_node*>& node_list)
322
390
    {
323
390
        size_t node_count = node_list.size();
324
390
        if (node_count == 1)
325
197
        {
326
197
            return node_list.front();
327
197
        }
328
193
        else if (node_count == 0)
329
0
            return nullptr;
330
331
193
        std::vector<nonleaf_node*> new_node_list;
332
193
        nonleaf_node* node1 = nullptr;
333
193
        typename std::vector<nonleaf_node*>::const_iterator it = node_list.begin();
334
193
        typename std::vector<nonleaf_node*>::const_iterator it_end = node_list.end();
335
579
        for (bool even_itr = false; it != it_end; ++it, even_itr = !even_itr)
336
386
        {
337
386
            if (even_itr)
338
193
            {
339
193
                nonleaf_node* node2 = *it;
340
193
                nonleaf_node* parent_node = make_parent_node(node1, node2);
341
193
                new_node_list.push_back(parent_node);
342
193
                node1 = nullptr;
343
193
                node2 = nullptr;
344
193
            }
345
193
            else
346
193
                node1 = *it;
347
386
        }
348
349
193
        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
193
        return build_tree_non_leaf(new_node_list);
358
390
    }
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
3.02k
{
368
3.02k
    if (!p)
369
0
        return;
370
371
3.02k
    p->prev.reset();
372
3.02k
    p->next.reset();
373
3.02k
    p->parent = nullptr;
374
3.02k
}
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
588
{
368
588
    if (!p)
369
0
        return;
370
371
588
    p->prev.reset();
372
588
    p->next.reset();
373
588
    p->parent = nullptr;
374
588
}
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
680
{
368
680
    if (!p)
369
0
        return;
370
371
680
    p->prev.reset();
372
680
    p->next.reset();
373
680
    p->parent = nullptr;
374
680
}
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.75k
{
368
1.75k
    if (!p)
369
0
        return;
370
371
1.75k
    p->prev.reset();
372
1.75k
    p->next.reset();
373
1.75k
    p->parent = nullptr;
374
1.75k
}
375
376
template<typename KeyT, typename ValueT>
377
void disconnect_leaf_nodes(node<KeyT, ValueT>* left_node, node<KeyT, ValueT>* right_node)
378
1.48k
{
379
1.48k
    if (!left_node || !right_node)
380
450
        return;
381
382
    // Go through all leaf nodes, and disconnect their links.
383
1.03k
    auto* cur_node = left_node;
384
1.03k
    do
385
1.99k
    {
386
1.99k
        auto* next_node = cur_node->next.get();
387
1.99k
        disconnect_all_nodes(cur_node);
388
1.99k
        cur_node = next_node;
389
1.99k
    } while (cur_node != right_node);
390
391
1.03k
    disconnect_all_nodes(right_node);
392
1.03k
}
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
294
{
379
294
    if (!left_node || !right_node)
380
0
        return;
381
382
    // Go through all leaf nodes, and disconnect their links.
383
294
    auto* cur_node = left_node;
384
294
    do
385
294
    {
386
294
        auto* next_node = cur_node->next.get();
387
294
        disconnect_all_nodes(cur_node);
388
294
        cur_node = next_node;
389
294
    } while (cur_node != right_node);
390
391
294
    disconnect_all_nodes(right_node);
392
294
}
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
294
{
379
294
    if (!left_node || !right_node)
380
0
        return;
381
382
    // Go through all leaf nodes, and disconnect their links.
383
294
    auto* cur_node = left_node;
384
294
    do
385
386
    {
386
386
        auto* next_node = cur_node->next.get();
387
386
        disconnect_all_nodes(cur_node);
388
386
        cur_node = next_node;
389
386
    } while (cur_node != right_node);
390
391
294
    disconnect_all_nodes(right_node);
392
294
}
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
894
{
379
894
    if (!left_node || !right_node)
380
450
        return;
381
382
    // Go through all leaf nodes, and disconnect their links.
383
444
    auto* cur_node = left_node;
384
444
    do
385
1.31k
    {
386
1.31k
        auto* next_node = cur_node->next.get();
387
1.31k
        disconnect_all_nodes(cur_node);
388
1.31k
        cur_node = next_node;
389
1.31k
    } while (cur_node != right_node);
390
391
444
    disconnect_all_nodes(right_node);
392
444
}
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
197
{
397
197
    size_t leaf_count = 1;
398
197
    const auto* p = left_end;
399
197
    const auto* p_end = right_end;
400
780
    for (; p != p_end; p = p->next.get(), ++leaf_count)
401
583
        ;
402
403
197
    return leaf_count;
404
197
}
405
406
inline size_t count_needed_nonleaf_nodes(size_t leaf_count)
407
197
{
408
197
    size_t nonleaf_count = 0;
409
587
    while (true)
410
587
    {
411
587
        if (leaf_count == 1)
412
197
            break;
413
414
390
        if ((leaf_count % 2) == 1)
415
            // Add one to make it an even number.
416
0
            ++leaf_count;
417
418
390
        leaf_count /= 2;
419
390
        nonleaf_count += leaf_count;
420
390
    }
421
422
197
    return nonleaf_count;
423
197
}
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