Coverage Report

Created: 2026-04-29 07:28

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.14k
    node_base(bool _is_leaf) : parent(nullptr), is_leaf(_is_leaf) {}
49
970
    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
340
        node_base(false),
78
340
        left(nullptr),
79
340
        right(nullptr)
80
340
    {
81
340
        _hdl_init(*this);
82
340
    }
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
340
    {
111
340
        dispose();
112
340
    }
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
340
    {
111
340
        dispose();
112
340
    }
Unexecuted instantiation: mdds::__st::nonleaf_node<mdds::flat_segment_tree<unsigned int, float> >::~nonleaf_node()
113
114
    void dispose()
115
340
    {
116
340
        _hdl_dispose(*this);
117
340
    }
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
340
    {
116
340
        _hdl_dispose(*this);
117
340
    }
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
340
    {
126
340
        _hdl_fill_nonleaf(*this, left_node, right_node);
127
340
    }
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.80k
    node() : node_base(true), refcount(0)
178
1.80k
    {
179
#ifdef MDDS_DEBUG_NODE_BASE
180
        ++node_instance_count;
181
#endif
182
1.80k
        _hdl_init(*this);
183
1.80k
    }
mdds::__st::node<mdds::flat_segment_tree<unsigned int, float> >::node()
Line
Count
Source
177
927
    node() : node_base(true), refcount(0)
178
927
    {
179
#ifdef MDDS_DEBUG_NODE_BASE
180
        ++node_instance_count;
181
#endif
182
927
        _hdl_init(*this);
183
927
    }
mdds::__st::node<mdds::flat_segment_tree<unsigned int, bool> >::node()
Line
Count
Source
177
396
    node() : node_base(true), refcount(0)
178
396
    {
179
#ifdef MDDS_DEBUG_NODE_BASE
180
        ++node_instance_count;
181
#endif
182
396
        _hdl_init(*this);
183
396
    }
mdds::__st::node<mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> > >::node()
Line
Count
Source
177
484
    node() : node_base(true), refcount(0)
178
484
    {
179
#ifdef MDDS_DEBUG_NODE_BASE
180
        ++node_instance_count;
181
#endif
182
484
        _hdl_init(*this);
183
484
    }
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
970
    node(const node& r) : node_base(r), refcount(0)
190
970
    {
191
#ifdef MDDS_DEBUG_NODE_BASE
192
        ++node_instance_count;
193
#endif
194
970
        value_leaf = r.value_leaf;
195
970
    }
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.77k
    {
212
#ifdef MDDS_DEBUG_NODE_BASE
213
        --node_instance_count;
214
#endif
215
2.77k
        dispose();
216
2.77k
    }
mdds::__st::node<mdds::flat_segment_tree<unsigned int, bool> >::~node()
Line
Count
Source
211
396
    {
212
#ifdef MDDS_DEBUG_NODE_BASE
213
        --node_instance_count;
214
#endif
215
396
        dispose();
216
396
    }
mdds::__st::node<mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> > >::~node()
Line
Count
Source
211
1.45k
    {
212
#ifdef MDDS_DEBUG_NODE_BASE
213
        --node_instance_count;
214
#endif
215
1.45k
        dispose();
216
1.45k
    }
mdds::__st::node<mdds::flat_segment_tree<unsigned int, float> >::~node()
Line
Count
Source
211
927
    {
212
#ifdef MDDS_DEBUG_NODE_BASE
213
        --node_instance_count;
214
#endif
215
927
        dispose();
216
927
    }
217
218
    void dispose()
219
2.77k
    {
220
2.77k
        _hdl_dispose(*this);
221
2.77k
    }
mdds::__st::node<mdds::flat_segment_tree<unsigned int, bool> >::dispose()
Line
Count
Source
219
396
    {
220
396
        _hdl_dispose(*this);
221
396
    }
mdds::__st::node<mdds::flat_segment_tree<unsigned int, std::__1::shared_ptr<libetonyek::IWORKStyle> > >::dispose()
Line
Count
Source
219
1.45k
    {
220
1.45k
        _hdl_dispose(*this);
221
1.45k
    }
mdds::__st::node<mdds::flat_segment_tree<unsigned int, float> >::dispose()
Line
Count
Source
219
927
    {
220
927
        _hdl_dispose(*this);
221
927
    }
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
16.0k
{
244
16.0k
    ++p->refcount;
245
16.0k
}
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
6.25k
{
244
6.25k
    ++p->refcount;
245
6.25k
}
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.53k
{
244
6.53k
    ++p->refcount;
245
6.53k
}
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.23k
{
244
3.23k
    ++p->refcount;
245
3.23k
}
246
247
template<typename T>
248
inline void intrusive_ptr_release(node<T>* p)
249
16.0k
{
250
16.0k
    --p->refcount;
251
16.0k
    if (!p->refcount)
252
2.77k
        delete p;
253
16.0k
}
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.23k
{
250
3.23k
    --p->refcount;
251
3.23k
    if (!p->refcount)
252
396
        delete p;
253
3.23k
}
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
6.25k
{
250
6.25k
    --p->refcount;
251
6.25k
    if (!p->refcount)
252
1.45k
        delete p;
253
6.25k
}
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.53k
{
250
6.53k
    --p->refcount;
251
6.53k
    if (!p->refcount)
252
927
        delete p;
253
6.53k
}
254
255
template<typename T>
256
void link_nodes(typename node<T>::node_ptr& left, typename node<T>::node_ptr& right)
257
1.54k
{
258
1.54k
    left->next = right;
259
1.54k
    right->prev = left;
260
1.54k
}
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.06k
{
258
1.06k
    left->next = right;
259
1.06k
    right->prev = left;
260
1.06k
}
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
480
{
258
480
    left->next = right;
259
480
    right->prev = left;
260
480
}
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
114
        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
114
    {
276
114
        if (!left_leaf_node)
277
            // The left leaf node is empty.  Nothing to build.
278
0
            return nullptr;
279
280
114
        leaf_node_ptr node1 = left_leaf_node;
281
282
114
        std::vector<nonleaf_node*> node_list;
283
227
        while (true)
284
227
        {
285
227
            leaf_node_ptr node2 = node1->next;
286
227
            nonleaf_node* parent_node = make_parent_node(node1.get(), node2.get());
287
227
            node_list.push_back(parent_node);
288
289
227
            if (!node2 || !node2->next)
290
                // no more nodes.  Break out of the loop.
291
114
                break;
292
293
113
            node1 = node2->next;
294
113
        }
295
296
114
        return build_tree_non_leaf(node_list);
297
114
    }
298
299
private:
300
301
    nonleaf_node* make_parent_node(node_base* node1, node_base* node2)
302
340
    {
303
340
        assert(m_pool_pos != m_pool_pos_end);
304
305
340
        nonleaf_node* parent_node = &(*m_pool_pos);
306
340
        ++m_pool_pos;
307
340
        node1->parent = parent_node;
308
340
        parent_node->left = node1;
309
340
        if (node2)
310
340
        {
311
340
            node2->parent = parent_node;
312
340
            parent_node->right = node2;
313
340
        }
314
315
340
        parent_node->fill_nonleaf_value(node1, node2);
316
340
        return parent_node;
317
340
    }
318
319
    nonleaf_node* build_tree_non_leaf(const std::vector<nonleaf_node*>& node_list)
320
227
    {
321
227
        size_t node_count = node_list.size();
322
227
        if (node_count == 1)
323
114
        {
324
114
            return node_list.front();
325
114
        }
326
113
        else if (node_count == 0)
327
0
            return nullptr;
328
329
113
        std::vector<nonleaf_node*> new_node_list;
330
113
        nonleaf_node* node1 = nullptr;
331
113
        typename std::vector<nonleaf_node*>::const_iterator it = node_list.begin();
332
113
        typename std::vector<nonleaf_node*>::const_iterator it_end = node_list.end();
333
339
        for (bool even_itr = false; it != it_end; ++it, even_itr = !even_itr)
334
226
        {
335
226
            if (even_itr)
336
113
            {
337
113
                nonleaf_node* node2 = *it;
338
113
                nonleaf_node* parent_node = make_parent_node(node1, node2);
339
113
                new_node_list.push_back(parent_node);
340
113
                node1 = nullptr;
341
113
                node2 = nullptr;
342
113
            }
343
113
            else
344
113
                node1 = *it;
345
226
        }
346
347
113
        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
113
        return build_tree_non_leaf(new_node_list);
356
227
    }
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.31k
{
367
2.31k
    if (!p)
368
0
        return;
369
370
2.31k
    p->prev.reset();
371
2.31k
    p->next.reset();
372
2.31k
    p->parent = nullptr;
373
2.31k
}
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
396
{
367
396
    if (!p)
368
0
        return;
369
370
396
    p->prev.reset();
371
396
    p->next.reset();
372
396
    p->parent = nullptr;
373
396
}
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
469
{
367
469
    if (!p)
368
0
        return;
369
370
469
    p->prev.reset();
371
469
    p->next.reset();
372
469
    p->parent = nullptr;
373
469
}
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.45k
{
367
1.45k
    if (!p)
368
0
        return;
369
370
1.45k
    p->prev.reset();
371
1.45k
    p->next.reset();
372
1.45k
    p->parent = nullptr;
373
1.45k
}
374
375
template<typename T>
376
void disconnect_leaf_nodes(node<T>* left_node, node<T>* right_node)
377
883
{
378
883
    if (!left_node || !right_node)
379
0
        return;
380
381
    // Go through all leaf nodes, and disconnect their links.
382
883
    node<T>* cur_node = left_node;
383
883
    do
384
1.43k
    {
385
1.43k
        node<T>* next_node = cur_node->next.get();
386
1.43k
        disconnect_all_nodes(cur_node);
387
1.43k
        cur_node = next_node;
388
1.43k
    }
389
1.43k
    while (cur_node != right_node);
390
391
883
    disconnect_all_nodes(right_node);
392
883
}
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
198
{
378
198
    if (!left_node || !right_node)
379
0
        return;
380
381
    // Go through all leaf nodes, and disconnect their links.
382
198
    node<T>* cur_node = left_node;
383
198
    do
384
198
    {
385
198
        node<T>* next_node = cur_node->next.get();
386
198
        disconnect_all_nodes(cur_node);
387
198
        cur_node = next_node;
388
198
    }
389
198
    while (cur_node != right_node);
390
391
198
    disconnect_all_nodes(right_node);
392
198
}
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
198
{
378
198
    if (!left_node || !right_node)
379
0
        return;
380
381
    // Go through all leaf nodes, and disconnect their links.
382
198
    node<T>* cur_node = left_node;
383
198
    do
384
271
    {
385
271
        node<T>* next_node = cur_node->next.get();
386
271
        disconnect_all_nodes(cur_node);
387
271
        cur_node = next_node;
388
271
    }
389
271
    while (cur_node != right_node);
390
391
198
    disconnect_all_nodes(right_node);
392
198
}
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
487
{
378
487
    if (!left_node || !right_node)
379
0
        return;
380
381
    // Go through all leaf nodes, and disconnect their links.
382
487
    node<T>* cur_node = left_node;
383
487
    do
384
967
    {
385
967
        node<T>* next_node = cur_node->next.get();
386
967
        disconnect_all_nodes(cur_node);
387
967
        cur_node = next_node;
388
967
    }
389
967
    while (cur_node != right_node);
390
391
487
    disconnect_all_nodes(right_node);
392
487
}
393
394
template<typename T>
395
size_t count_leaf_nodes(const node<T>* left_end, const node<T>* right_end)
396
114
{
397
114
    size_t leaf_count = 1;
398
114
    const node<T>* p = left_end;
399
114
    const node<T>* p_end = right_end;
400
454
    for (; p != p_end; p = p->next.get(), ++leaf_count)
401
340
        ;
402
403
114
    return leaf_count;
404
114
}
405
406
inline size_t count_needed_nonleaf_nodes(size_t leaf_count)
407
114
{
408
114
    size_t nonleaf_count = 0;
409
341
    while (true)
410
341
    {
411
341
        if (leaf_count == 1)
412
114
            break;
413
414
227
        if ((leaf_count % 2) == 1)
415
            // Add one to make it an even number.
416
0
            ++leaf_count;
417
418
227
        leaf_count /= 2;
419
227
        nonleaf_count += leaf_count;
420
227
    }
421
422
114
    return nonleaf_count;
423
114
}
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