Coverage Report

Created: 2026-03-12 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mdds-1.3.1/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 <iostream>
32
#include <vector>
33
#include <cassert>
34
35
#include <boost/intrusive_ptr.hpp>
36
37
namespace mdds { namespace __st {
38
39
#ifdef MDDS_DEBUG_NODE_BASE
40
size_t node_instance_count = 0;
41
#endif
42
43
struct node_base
44
{
45
    node_base* parent; /// parent nonleaf_node
46
    bool is_leaf;
47
48
2.06k
    node_base(bool _is_leaf) : parent(nullptr), is_leaf(_is_leaf) {}
49
870
    node_base(const node_base& r) : parent(nullptr), is_leaf(r.is_leaf) {}
50
};
51
52
template<typename T>
53
struct nonleaf_node : public node_base
54
{
55
    typedef typename T::nonleaf_value_type nonleaf_value_type;
56
    typedef typename T::fill_nonleaf_value_handler fill_nonleaf_value_handler;
57
    typedef typename T::init_handler init_handler;
58
    typedef typename T::dispose_handler dispose_handler;
59
#ifdef MDDS_UNIT_TEST
60
    typedef typename T::to_string_handler to_string_handler;
61
#endif
62
    nonleaf_value_type value_nonleaf;
63
64
    node_base* left;   /// left child nonleaf_node
65
    node_base* right;  /// right child nonleaf_node
66
67
private:
68
    fill_nonleaf_value_handler  _hdl_fill_nonleaf;
69
    init_handler                _hdl_init;
70
    dispose_handler             _hdl_dispose;
71
#ifdef MDDS_UNIT_TEST
72
    to_string_handler           _hdl_to_string;
73
#endif
74
75
public:
76
    nonleaf_node() :
77
310
        node_base(false),
78
310
        left(nullptr),
79
310
        right(nullptr)
80
310
    {
81
310
        _hdl_init(*this);
82
310
    }
83
84
    /**
85
     * When copying nonleaf_node, only the stored values should be copied.
86
     * Connections to the parent, left and right nodes must not be copied.
87
     */
88
    nonleaf_node(const nonleaf_node& r) :
89
0
        node_base(r),
90
0
        left(nullptr),
91
0
        right(nullptr)
92
0
    {
93
0
        value_nonleaf = r.value_nonleaf;
94
0
    }
95
96
    /**
97
     * Like the copy constructor, only the stored values should be copied.
98
     */
99
    nonleaf_node& operator=(const nonleaf_node& r)
100
    {
101
        if (this == &r)
102
            // assignment to self.
103
            return *this;
104
105
        value_nonleaf = r.value_nonleaf;
106
        return *this;
107
    }
108
109
    ~nonleaf_node()
110
310
    {
111
310
        dispose();
112
310
    }
Unexecuted instantiation: mdds::__st::nonleaf_node<mdds::flat_segment_tree<unsigned int, bool> >::~nonleaf_node()
mdds::__st::nonleaf_node<mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> > >::~nonleaf_node()
Line
Count
Source
110
310
    {
111
310
        dispose();
112
310
    }
Unexecuted instantiation: mdds::__st::nonleaf_node<mdds::flat_segment_tree<unsigned int, float> >::~nonleaf_node()
113
114
    void dispose()
115
310
    {
116
310
        _hdl_dispose(*this);
117
310
    }
Unexecuted instantiation: mdds::__st::nonleaf_node<mdds::flat_segment_tree<unsigned int, bool> >::dispose()
mdds::__st::nonleaf_node<mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> > >::dispose()
Line
Count
Source
115
310
    {
116
310
        _hdl_dispose(*this);
117
310
    }
Unexecuted instantiation: mdds::__st::nonleaf_node<mdds::flat_segment_tree<unsigned int, float> >::dispose()
118
119
    bool equals(const nonleaf_node& r) const
120
    {
121
        return value_nonleaf == r.value_nonleaf;
122
    }
123
124
    void fill_nonleaf_value(const node_base* left_node, const node_base* right_node)
125
310
    {
126
310
        _hdl_fill_nonleaf(*this, left_node, right_node);
127
310
    }
128
129
#ifdef MDDS_UNIT_TEST
130
    void dump_value() const
131
    {
132
        ::std::cout << _hdl_to_string(*this);
133
    }
134
135
    ::std::string to_string() const
136
    {
137
        return _hdl_to_string(*this);
138
    }
139
#endif
140
};
141
142
template<typename T>
143
struct node : public node_base
144
{
145
    typedef ::boost::intrusive_ptr<node>  node_ptr;
146
147
    typedef typename T::leaf_value_type leaf_value_type;
148
    typedef typename T::init_handler init_handler;
149
    typedef typename T::dispose_handler dispose_handler;
150
#ifdef MDDS_UNIT_TEST
151
    typedef typename T::to_string_handler to_string_handler;
152
#endif
153
154
    static size_t get_instance_count()
155
    {
156
#ifdef MDDS_DEBUG_NODE_BASE
157
        return node_instance_count;
158
#else
159
        return 0;
160
#endif
161
    }
162
163
    leaf_value_type     value_leaf;
164
165
    node_ptr    prev;   /// previous sibling leaf node.
166
    node_ptr    next;  /// next sibling leaf node.
167
168
    size_t      refcount;
169
private:
170
    init_handler                _hdl_init;
171
    dispose_handler             _hdl_dispose;
172
#ifdef MDDS_UNIT_TEST
173
    to_string_handler           _hdl_to_string;
174
#endif
175
176
public:
177
1.75k
    node() : node_base(true), refcount(0)
178
1.75k
    {
179
#ifdef MDDS_DEBUG_NODE_BASE
180
        ++node_instance_count;
181
#endif
182
1.75k
        _hdl_init(*this);
183
1.75k
    }
mdds::__st::node<mdds::flat_segment_tree<unsigned int, float> >::node()
Line
Count
Source
177
930
    node() : node_base(true), refcount(0)
178
930
    {
179
#ifdef MDDS_DEBUG_NODE_BASE
180
        ++node_instance_count;
181
#endif
182
930
        _hdl_init(*this);
183
930
    }
mdds::__st::node<mdds::flat_segment_tree<unsigned int, bool> >::node()
Line
Count
Source
177
392
    node() : node_base(true), refcount(0)
178
392
    {
179
#ifdef MDDS_DEBUG_NODE_BASE
180
        ++node_instance_count;
181
#endif
182
392
        _hdl_init(*this);
183
392
    }
mdds::__st::node<mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> > >::node()
Line
Count
Source
177
434
    node() : node_base(true), refcount(0)
178
434
    {
179
#ifdef MDDS_DEBUG_NODE_BASE
180
        ++node_instance_count;
181
#endif
182
434
        _hdl_init(*this);
183
434
    }
184
185
    /**
186
     * When copying node, only the stored values should be copied.
187
     * Connections to the parent, left and right nodes must not be copied.
188
     */
189
870
    node(const node& r) : node_base(r), refcount(0)
190
870
    {
191
#ifdef MDDS_DEBUG_NODE_BASE
192
        ++node_instance_count;
193
#endif
194
870
        value_leaf = r.value_leaf;
195
870
    }
196
197
    /**
198
     * Like the copy constructor, only the stored values should be copied.
199
     */
200
    node& operator=(const node& r)
201
    {
202
        if (this == &r)
203
            // assignment to self.
204
            return *this;
205
206
        value_leaf = r.value_leaf;
207
        return *this;
208
    }
209
210
    ~node()
211
2.62k
    {
212
#ifdef MDDS_DEBUG_NODE_BASE
213
        --node_instance_count;
214
#endif
215
2.62k
        dispose();
216
2.62k
    }
mdds::__st::node<mdds::flat_segment_tree<unsigned int, bool> >::~node()
Line
Count
Source
211
392
    {
212
#ifdef MDDS_DEBUG_NODE_BASE
213
        --node_instance_count;
214
#endif
215
392
        dispose();
216
392
    }
mdds::__st::node<mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> > >::~node()
Line
Count
Source
211
1.30k
    {
212
#ifdef MDDS_DEBUG_NODE_BASE
213
        --node_instance_count;
214
#endif
215
1.30k
        dispose();
216
1.30k
    }
mdds::__st::node<mdds::flat_segment_tree<unsigned int, float> >::~node()
Line
Count
Source
211
930
    {
212
#ifdef MDDS_DEBUG_NODE_BASE
213
        --node_instance_count;
214
#endif
215
930
        dispose();
216
930
    }
217
218
    void dispose()
219
2.62k
    {
220
2.62k
        _hdl_dispose(*this);
221
2.62k
    }
mdds::__st::node<mdds::flat_segment_tree<unsigned int, bool> >::dispose()
Line
Count
Source
219
392
    {
220
392
        _hdl_dispose(*this);
221
392
    }
mdds::__st::node<mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> > >::dispose()
Line
Count
Source
219
1.30k
    {
220
1.30k
        _hdl_dispose(*this);
221
1.30k
    }
mdds::__st::node<mdds::flat_segment_tree<unsigned int, float> >::dispose()
Line
Count
Source
219
930
    {
220
930
        _hdl_dispose(*this);
221
930
    }
222
223
    bool equals(const node& r) const
224
    {
225
        return value_leaf == r.value_leaf;
226
    }
227
228
#ifdef MDDS_UNIT_TEST
229
    void dump_value() const
230
    {
231
        ::std::cout << _hdl_to_string(*this);
232
    }
233
234
    ::std::string to_string() const
235
    {
236
        return _hdl_to_string(*this);
237
    }
238
#endif
239
};
240
241
template<typename T>
242
inline void intrusive_ptr_add_ref(node<T>* p)
243
15.4k
{
244
15.4k
    ++p->refcount;
245
15.4k
}
void mdds::__st::intrusive_ptr_add_ref<mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> > >(mdds::__st::node<mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> > >*)
Line
Count
Source
243
5.62k
{
244
5.62k
    ++p->refcount;
245
5.62k
}
void mdds::__st::intrusive_ptr_add_ref<mdds::flat_segment_tree<unsigned int, float> >(mdds::__st::node<mdds::flat_segment_tree<unsigned int, float> >*)
Line
Count
Source
243
6.58k
{
244
6.58k
    ++p->refcount;
245
6.58k
}
void mdds::__st::intrusive_ptr_add_ref<mdds::flat_segment_tree<unsigned int, bool> >(mdds::__st::node<mdds::flat_segment_tree<unsigned int, bool> >*)
Line
Count
Source
243
3.24k
{
244
3.24k
    ++p->refcount;
245
3.24k
}
246
247
template<typename T>
248
inline void intrusive_ptr_release(node<T>* p)
249
15.4k
{
250
15.4k
    --p->refcount;
251
15.4k
    if (!p->refcount)
252
2.62k
        delete p;
253
15.4k
}
void mdds::__st::intrusive_ptr_release<mdds::flat_segment_tree<unsigned int, bool> >(mdds::__st::node<mdds::flat_segment_tree<unsigned int, bool> >*)
Line
Count
Source
249
3.24k
{
250
3.24k
    --p->refcount;
251
3.24k
    if (!p->refcount)
252
392
        delete p;
253
3.24k
}
void mdds::__st::intrusive_ptr_release<mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> > >(mdds::__st::node<mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> > >*)
Line
Count
Source
249
5.62k
{
250
5.62k
    --p->refcount;
251
5.62k
    if (!p->refcount)
252
1.30k
        delete p;
253
5.62k
}
void mdds::__st::intrusive_ptr_release<mdds::flat_segment_tree<unsigned int, float> >(mdds::__st::node<mdds::flat_segment_tree<unsigned int, float> >*)
Line
Count
Source
249
6.58k
{
250
6.58k
    --p->refcount;
251
6.58k
    if (!p->refcount)
252
930
        delete p;
253
6.58k
}
254
255
template<typename T>
256
void link_nodes(typename node<T>::node_ptr& left, typename node<T>::node_ptr& right)
257
1.50k
{
258
1.50k
    left->next = right;
259
1.50k
    right->prev = left;
260
1.50k
}
void mdds::__st::link_nodes<mdds::flat_segment_tree<unsigned int, float> >(mdds::__st::node<mdds::flat_segment_tree<unsigned int, float> >::node_ptr&, mdds::__st::node<mdds::flat_segment_tree<unsigned int, float> >::node_ptr&)
Line
Count
Source
257
1.07k
{
258
1.07k
    left->next = right;
259
1.07k
    right->prev = left;
260
1.07k
}
Unexecuted instantiation: void mdds::__st::link_nodes<mdds::flat_segment_tree<unsigned int, bool> >(mdds::__st::node<mdds::flat_segment_tree<unsigned int, bool> >::node_ptr&, mdds::__st::node<mdds::flat_segment_tree<unsigned int, bool> >::node_ptr&)
void mdds::__st::link_nodes<mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> > >(mdds::__st::node<mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> > >::node_ptr&, mdds::__st::node<mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> > >::node_ptr&)
Line
Count
Source
257
432
{
258
432
    left->next = right;
259
432
    right->prev = left;
260
432
}
261
262
template<typename T>
263
class tree_builder
264
{
265
public:
266
    typedef mdds::__st::node<T> leaf_node;
267
    typedef typename mdds::__st::node<T>::node_ptr leaf_node_ptr;
268
    typedef mdds::__st::nonleaf_node<T> nonleaf_node;
269
    typedef std::vector<nonleaf_node> nonleaf_node_pool_type;
270
271
    tree_builder(nonleaf_node_pool_type& pool) :
272
104
        m_pool(pool), m_pool_pos(pool.begin()), m_pool_pos_end(pool.end()) {}
273
274
    nonleaf_node* build(const leaf_node_ptr& left_leaf_node)
275
104
    {
276
104
        if (!left_leaf_node)
277
            // The left leaf node is empty.  Nothing to build.
278
0
            return nullptr;
279
280
104
        leaf_node_ptr node1 = left_leaf_node;
281
282
104
        std::vector<nonleaf_node*> node_list;
283
207
        while (true)
284
207
        {
285
207
            leaf_node_ptr node2 = node1->next;
286
207
            nonleaf_node* parent_node = make_parent_node(node1.get(), node2.get());
287
207
            node_list.push_back(parent_node);
288
289
207
            if (!node2 || !node2->next)
290
                // no more nodes.  Break out of the loop.
291
104
                break;
292
293
103
            node1 = node2->next;
294
103
        }
295
296
104
        return build_tree_non_leaf(node_list);
297
104
    }
298
299
private:
300
301
    nonleaf_node* make_parent_node(node_base* node1, node_base* node2)
302
310
    {
303
310
        assert(m_pool_pos != m_pool_pos_end);
304
305
310
        nonleaf_node* parent_node = &(*m_pool_pos);
306
310
        ++m_pool_pos;
307
310
        node1->parent = parent_node;
308
310
        parent_node->left = node1;
309
310
        if (node2)
310
310
        {
311
310
            node2->parent = parent_node;
312
310
            parent_node->right = node2;
313
310
        }
314
315
310
        parent_node->fill_nonleaf_value(node1, node2);
316
310
        return parent_node;
317
310
    }
318
319
    nonleaf_node* build_tree_non_leaf(const std::vector<nonleaf_node*>& node_list)
320
207
    {
321
207
        size_t node_count = node_list.size();
322
207
        if (node_count == 1)
323
104
        {
324
104
            return node_list.front();
325
104
        }
326
103
        else if (node_count == 0)
327
0
            return nullptr;
328
329
103
        std::vector<nonleaf_node*> new_node_list;
330
103
        nonleaf_node* node1 = nullptr;
331
103
        typename std::vector<nonleaf_node*>::const_iterator it = node_list.begin();
332
103
        typename std::vector<nonleaf_node*>::const_iterator it_end = node_list.end();
333
309
        for (bool even_itr = false; it != it_end; ++it, even_itr = !even_itr)
334
206
        {
335
206
            if (even_itr)
336
103
            {
337
103
                nonleaf_node* node2 = *it;
338
103
                nonleaf_node* parent_node = make_parent_node(node1, node2);
339
103
                new_node_list.push_back(parent_node);
340
103
                node1 = nullptr;
341
103
                node2 = nullptr;
342
103
            }
343
103
            else
344
103
                node1 = *it;
345
206
        }
346
347
103
        if (node1)
348
0
        {
349
            // Un-paired node still needs a parent...
350
0
            nonleaf_node* parent_node = make_parent_node(node1, nullptr);
351
0
            new_node_list.push_back(parent_node);
352
0
        }
353
354
        // Move up one level, and do the same procedure until the root node is reached.
355
103
        return build_tree_non_leaf(new_node_list);
356
207
    }
357
358
    nonleaf_node_pool_type& m_pool;
359
    typename nonleaf_node_pool_type::iterator m_pool_pos;
360
    typename nonleaf_node_pool_type::iterator m_pool_pos_end;
361
};
362
363
364
template<typename T>
365
void disconnect_all_nodes(node<T>* p)
366
2.16k
{
367
2.16k
    if (!p)
368
0
        return;
369
370
2.16k
    p->prev.reset();
371
2.16k
    p->next.reset();
372
2.16k
    p->parent = nullptr;
373
2.16k
}
void mdds::__st::disconnect_all_nodes<mdds::flat_segment_tree<unsigned int, bool> >(mdds::__st::node<mdds::flat_segment_tree<unsigned int, bool> >*)
Line
Count
Source
366
392
{
367
392
    if (!p)
368
0
        return;
369
370
392
    p->prev.reset();
371
392
    p->next.reset();
372
392
    p->parent = nullptr;
373
392
}
void mdds::__st::disconnect_all_nodes<mdds::flat_segment_tree<unsigned int, float> >(mdds::__st::node<mdds::flat_segment_tree<unsigned int, float> >*)
Line
Count
Source
366
468
{
367
468
    if (!p)
368
0
        return;
369
370
468
    p->prev.reset();
371
468
    p->next.reset();
372
468
    p->parent = nullptr;
373
468
}
void mdds::__st::disconnect_all_nodes<mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> > >(mdds::__st::node<mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> > >*)
Line
Count
Source
366
1.30k
{
367
1.30k
    if (!p)
368
0
        return;
369
370
1.30k
    p->prev.reset();
371
1.30k
    p->next.reset();
372
1.30k
    p->parent = nullptr;
373
1.30k
}
374
375
template<typename T>
376
void disconnect_leaf_nodes(node<T>* left_node, node<T>* right_node)
377
828
{
378
828
    if (!left_node || !right_node)
379
0
        return;
380
381
    // Go through all leaf nodes, and disconnect their links.
382
828
    node<T>* cur_node = left_node;
383
828
    do
384
1.33k
    {
385
1.33k
        node<T>* next_node = cur_node->next.get();
386
1.33k
        disconnect_all_nodes(cur_node);
387
1.33k
        cur_node = next_node;
388
1.33k
    }
389
1.33k
    while (cur_node != right_node);
390
391
828
    disconnect_all_nodes(right_node);
392
828
}
void mdds::__st::disconnect_leaf_nodes<mdds::flat_segment_tree<unsigned int, bool> >(mdds::__st::node<mdds::flat_segment_tree<unsigned int, bool> >*, mdds::__st::node<mdds::flat_segment_tree<unsigned int, bool> >*)
Line
Count
Source
377
196
{
378
196
    if (!left_node || !right_node)
379
0
        return;
380
381
    // Go through all leaf nodes, and disconnect their links.
382
196
    node<T>* cur_node = left_node;
383
196
    do
384
196
    {
385
196
        node<T>* next_node = cur_node->next.get();
386
196
        disconnect_all_nodes(cur_node);
387
196
        cur_node = next_node;
388
196
    }
389
196
    while (cur_node != right_node);
390
391
196
    disconnect_all_nodes(right_node);
392
196
}
void mdds::__st::disconnect_leaf_nodes<mdds::flat_segment_tree<unsigned int, float> >(mdds::__st::node<mdds::flat_segment_tree<unsigned int, float> >*, mdds::__st::node<mdds::flat_segment_tree<unsigned int, float> >*)
Line
Count
Source
377
196
{
378
196
    if (!left_node || !right_node)
379
0
        return;
380
381
    // Go through all leaf nodes, and disconnect their links.
382
196
    node<T>* cur_node = left_node;
383
196
    do
384
272
    {
385
272
        node<T>* next_node = cur_node->next.get();
386
272
        disconnect_all_nodes(cur_node);
387
272
        cur_node = next_node;
388
272
    }
389
272
    while (cur_node != right_node);
390
391
196
    disconnect_all_nodes(right_node);
392
196
}
void mdds::__st::disconnect_leaf_nodes<mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> > >(mdds::__st::node<mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> > >*, mdds::__st::node<mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> > >*)
Line
Count
Source
377
436
{
378
436
    if (!left_node || !right_node)
379
0
        return;
380
381
    // Go through all leaf nodes, and disconnect their links.
382
436
    node<T>* cur_node = left_node;
383
436
    do
384
868
    {
385
868
        node<T>* next_node = cur_node->next.get();
386
868
        disconnect_all_nodes(cur_node);
387
868
        cur_node = next_node;
388
868
    }
389
868
    while (cur_node != right_node);
390
391
436
    disconnect_all_nodes(right_node);
392
436
}
393
394
template<typename T>
395
size_t count_leaf_nodes(const node<T>* left_end, const node<T>* right_end)
396
104
{
397
104
    size_t leaf_count = 1;
398
104
    const node<T>* p = left_end;
399
104
    const node<T>* p_end = right_end;
400
414
    for (; p != p_end; p = p->next.get(), ++leaf_count)
401
310
        ;
402
403
104
    return leaf_count;
404
104
}
405
406
inline size_t count_needed_nonleaf_nodes(size_t leaf_count)
407
104
{
408
104
    size_t nonleaf_count = 0;
409
311
    while (true)
410
311
    {
411
311
        if (leaf_count == 1)
412
104
            break;
413
414
207
        if ((leaf_count % 2) == 1)
415
            // Add one to make it an even number.
416
0
            ++leaf_count;
417
418
207
        leaf_count /= 2;
419
207
        nonleaf_count += leaf_count;
420
207
    }
421
422
104
    return nonleaf_count;
423
104
}
424
425
#ifdef MDDS_UNIT_TEST
426
427
template<typename _Leaf, typename _NonLeaf>
428
class tree_dumper
429
{
430
    typedef std::vector<const node_base*> node_list_type;
431
432
public:
433
    static size_t dump(const node_base* root_node)
434
    {
435
        if (!root_node)
436
            return 0;
437
438
        node_list_type node_list;
439
        node_list.push_back(root_node);
440
        return dump_layer(node_list, 0);
441
    }
442
443
private:
444
    static size_t dump_layer(const node_list_type& node_list, unsigned int level)
445
    {
446
        using ::std::cout;
447
        using ::std::endl;
448
449
        if (node_list.empty())
450
            return 0;
451
452
        size_t node_count = node_list.size();
453
454
        bool is_leaf = node_list.front()->is_leaf;
455
        cout << "level " << level << " (" << (is_leaf?"leaf":"non-leaf") << ")" << endl;
456
457
        node_list_type new_list;
458
        typename node_list_type::const_iterator it = node_list.begin(), it_end = node_list.end();
459
        for (; it != it_end; ++it)
460
        {
461
            const node_base* p = *it;
462
            if (!p)
463
            {
464
                cout << "(x) ";
465
                continue;
466
            }
467
468
            if (p->is_leaf)
469
                static_cast<const _Leaf*>(p)->dump_value();
470
            else
471
                static_cast<const _NonLeaf*>(p)->dump_value();
472
473
            if (p->is_leaf)
474
                continue;
475
476
            if (static_cast<const _NonLeaf*>(p)->left)
477
            {
478
                new_list.push_back(static_cast<const _NonLeaf*>(p)->left);
479
                if (static_cast<const _NonLeaf*>(p)->right)
480
                    new_list.push_back(static_cast<const _NonLeaf*>(p)->right);
481
            }
482
        }
483
        cout << endl;
484
485
        if (!new_list.empty())
486
            node_count += dump_layer(new_list, level+1);
487
488
        return node_count;
489
    }
490
};
491
492
#endif
493
494
}}
495
496
#endif