mdds
Loading...
Searching...
No Matches
node.hpp
1// SPDX-FileCopyrightText: 2008 - 2025 Kohei Yoshida
2//
3// SPDX-License-Identifier: MIT
4
5#pragma once
6
7#include "mdds/global.hpp"
8
9#include <iostream>
10#include <vector>
11#include <cassert>
12#include <sstream>
13
14#include <boost/intrusive_ptr.hpp>
15
16namespace mdds { namespace st { namespace detail {
17
18#ifdef MDDS_DEBUG_NODE_BASE
19
20inline std::size_t node_instance_count = 0;
21
22#endif
23
24struct node_base
25{
26 node_base* parent;
27 bool is_leaf;
28
29 node_base(bool _is_leaf) noexcept : parent(nullptr), is_leaf(_is_leaf)
30 {}
31 node_base(const node_base& r) noexcept : parent(nullptr), is_leaf(r.is_leaf)
32 {}
33};
34
38template<typename KeyT, typename ValueT>
39struct nonleaf_node : public node_base
40{
41 using key_type = KeyT;
42 using nonleaf_value_type = ValueT;
43
44 nonleaf_value_type value_nonleaf;
45
46 key_type low = {};
47 key_type high = {};
48
49 node_base* left = nullptr;
50 node_base* right = nullptr;
51
52 static constexpr bool nothrow_default_constructible_v = std::is_nothrow_default_constructible_v<key_type> &&
53 std::is_nothrow_default_constructible_v<nonleaf_value_type>;
54
55 static constexpr bool nothrow_eq_comparable_v =
56 noexcept(std::declval<key_type>() == std::declval<key_type>()) &&
57 noexcept(std::declval<nonleaf_value_type>() == std::declval<nonleaf_value_type>());
58
59public:
60 nonleaf_node() noexcept(nothrow_default_constructible_v) : node_base(false), value_nonleaf()
61 {}
62
67 nonleaf_node(const nonleaf_node& r) : node_base(r), value_nonleaf(r.value_nonleaf), low(r.low), high(r.high)
68 {}
69
73 nonleaf_node& operator=(const nonleaf_node& r)
74 {
75 if (this == &r)
76 // assignment to self.
77 return *this;
78
79 value_nonleaf = r.value_nonleaf;
80 return *this;
81 }
82
83 bool operator==(const nonleaf_node& r) const noexcept(nothrow_eq_comparable_v)
84 {
85 return low == r.low && high == r.high && value_nonleaf == r.value_nonleaf;
86 }
87
88 bool operator!=(const nonleaf_node& r) const noexcept(nothrow_eq_comparable_v)
89 {
90 return !operator==(r);
91 }
92
93 std::string to_string() const
94 {
95 std::ostringstream os;
96 os << "[" << low << "-" << high << ")";
97 return os.str();
98 }
99};
100
104template<typename KeyT, typename ValueT>
105struct node : node_base
106{
107 using key_type = KeyT;
108 using leaf_value_type = ValueT;
109 using node_ptr = boost::intrusive_ptr<node>;
110
111 static size_t get_instance_count()
112 {
113#ifdef MDDS_DEBUG_NODE_BASE
114 return node_instance_count;
115#else
116 return 0;
117#endif
118 }
119
120 leaf_value_type value_leaf;
121
122 key_type key = {};
123
124 node_ptr prev;
125 node_ptr next;
126
127 std::size_t refcount = 0;
128
129 static constexpr bool nothrow_default_constructible_v = std::is_nothrow_default_constructible_v<key_type> &&
130 std::is_nothrow_default_constructible_v<leaf_value_type> &&
131 std::is_nothrow_default_constructible_v<node_ptr>;
132
133 static constexpr bool nothrow_eq_comparable_v =
134 noexcept(std::declval<key_type>() == std::declval<key_type>()) &&
135 noexcept(std::declval<leaf_value_type>() == std::declval<leaf_value_type>());
136
137public:
138 node() noexcept(nothrow_default_constructible_v) : node_base(true)
139 {
140#ifdef MDDS_DEBUG_NODE_BASE
141 ++node_instance_count;
142#endif
143 }
144
149 node(const node& r) : node_base(r), key(r.key)
150 {
151#ifdef MDDS_DEBUG_NODE_BASE
152 ++node_instance_count;
153#endif
154 value_leaf = r.value_leaf;
155 }
156
160 node& operator=(const node& r)
161 {
162 if (this == &r)
163 // assignment to self.
164 return *this;
165
166 value_leaf = r.value_leaf;
167 return *this;
168 }
169
170 ~node()
171 {
172#ifdef MDDS_DEBUG_NODE_BASE
173 --node_instance_count;
174#endif
175 }
176
177 bool operator==(const node& r) const noexcept(nothrow_eq_comparable_v)
178 {
179 return key == r.key && value_leaf == r.value_leaf;
180 }
181
182 bool operator!=(const node& r) const noexcept(nothrow_eq_comparable_v)
183 {
184 return !operator==(r);
185 }
186
187 std::string to_string() const
188 {
189 std::ostringstream os;
190 os << "[" << key << "]";
191 return os.str();
192 }
193};
194
195template<typename KeyT, typename ValueT>
196inline void intrusive_ptr_add_ref(node<KeyT, ValueT>* p)
197{
198 ++p->refcount;
199}
200
201template<typename KeyT, typename ValueT>
202inline void intrusive_ptr_release(node<KeyT, ValueT>* p)
203{
204 --p->refcount;
205 if (!p->refcount)
206 delete p;
207}
208
209template<typename NodePtrT>
210void link_nodes(NodePtrT& left, NodePtrT& right)
211{
212 left->next = right;
213 right->prev = left;
214}
215
216template<typename T>
217class tree_builder
218{
219public:
220 typedef typename T::node leaf_node;
221 typedef typename leaf_node::node_ptr leaf_node_ptr;
222 typedef typename T::nonleaf_node nonleaf_node;
223 typedef std::vector<nonleaf_node> nonleaf_node_pool_type;
224
225 tree_builder(nonleaf_node_pool_type& pool) : m_pool(pool), m_pool_pos(pool.begin()), m_pool_pos_end(pool.end())
226 {}
227
228 nonleaf_node* build(const leaf_node_ptr& left_leaf_node)
229 {
230 if (!left_leaf_node)
231 // The left leaf node is empty. Nothing to build.
232 return nullptr;
233
234 leaf_node_ptr node1 = left_leaf_node;
235
236 std::vector<nonleaf_node*> node_list;
237 while (true)
238 {
239 leaf_node_ptr node2 = node1->next;
240 nonleaf_node* parent_node = make_parent_node(node1.get(), node2.get());
241 node_list.push_back(parent_node);
242
243 if (!node2 || !node2->next)
244 // no more nodes. Break out of the loop.
245 break;
246
247 node1 = node2->next;
248 }
249
250 return build_tree_non_leaf(node_list);
251 }
252
253private:
254 nonleaf_node* make_parent_node(node_base* node1, node_base* node2)
255 {
256 assert(m_pool_pos != m_pool_pos_end);
257
258 nonleaf_node* parent_node = &(*m_pool_pos);
259 ++m_pool_pos;
260 node1->parent = parent_node;
261 parent_node->left = node1;
262 if (node2)
263 {
264 node2->parent = parent_node;
265 parent_node->right = node2;
266 }
267
268 fill_nonleaf_parent_node(parent_node, node1, node2);
269 return parent_node;
270 }
271
272 void fill_nonleaf_parent_node(nonleaf_node* parent_node, const node_base* left_node, const node_base* right_node)
273 {
274 // Parent node should carry the range of all of its child nodes.
275 if (left_node)
276 {
277 parent_node->low = left_node->is_leaf ? static_cast<const leaf_node*>(left_node)->key
278 : static_cast<const nonleaf_node*>(left_node)->low;
279 }
280 else
281 {
282 // Having a left node is prerequisite.
283 throw general_error("fill_nonleaf_parent_node: Having a left node is prerequisite.");
284 }
285
286 if (right_node)
287 {
288 if (right_node->is_leaf)
289 {
290 // When the child nodes are leaf nodes, the upper bound
291 // must be the value of the node that comes after the
292 // right leaf node (if such node exists).
293
294 const auto* p = static_cast<const leaf_node*>(right_node);
295 if (p->next)
296 parent_node->high = p->next->key;
297 else
298 parent_node->high = p->key;
299 }
300 else
301 {
302 parent_node->high = static_cast<const nonleaf_node*>(right_node)->high;
303 }
304 }
305 else
306 {
307 parent_node->high = left_node->is_leaf ? static_cast<const leaf_node*>(left_node)->key
308 : static_cast<const nonleaf_node*>(left_node)->high;
309 }
310 }
311
312 nonleaf_node* build_tree_non_leaf(const std::vector<nonleaf_node*>& node_list)
313 {
314 size_t node_count = node_list.size();
315 if (node_count == 1)
316 {
317 return node_list.front();
318 }
319 else if (node_count == 0)
320 return nullptr;
321
322 std::vector<nonleaf_node*> new_node_list;
323 nonleaf_node* node1 = nullptr;
324 typename std::vector<nonleaf_node*>::const_iterator it = node_list.begin();
325 typename std::vector<nonleaf_node*>::const_iterator it_end = node_list.end();
326 for (bool even_itr = false; it != it_end; ++it, even_itr = !even_itr)
327 {
328 if (even_itr)
329 {
330 nonleaf_node* node2 = *it;
331 nonleaf_node* parent_node = make_parent_node(node1, node2);
332 new_node_list.push_back(parent_node);
333 node1 = nullptr;
334 node2 = nullptr;
335 }
336 else
337 node1 = *it;
338 }
339
340 if (node1)
341 {
342 // Un-paired node still needs a parent...
343 nonleaf_node* parent_node = make_parent_node(node1, nullptr);
344 new_node_list.push_back(parent_node);
345 }
346
347 // Move up one level, and do the same procedure until the root node is reached.
348 return build_tree_non_leaf(new_node_list);
349 }
350
351 nonleaf_node_pool_type& m_pool;
352 typename nonleaf_node_pool_type::iterator m_pool_pos;
353 typename nonleaf_node_pool_type::iterator m_pool_pos_end;
354};
355
356template<typename KeyT, typename ValueT>
357void disconnect_all_nodes(node<KeyT, ValueT>* p)
358{
359 if (!p)
360 return;
361
362 p->prev.reset();
363 p->next.reset();
364 p->parent = nullptr;
365}
366
367template<typename KeyT, typename ValueT>
368void disconnect_leaf_nodes(node<KeyT, ValueT>* left_node, node<KeyT, ValueT>* right_node)
369{
370 if (!left_node || !right_node)
371 return;
372
373 // Go through all leaf nodes, and disconnect their links.
374 auto* cur_node = left_node;
375 do
376 {
377 auto* next_node = cur_node->next.get();
378 disconnect_all_nodes(cur_node);
379 cur_node = next_node;
380 } while (cur_node != right_node);
381
382 disconnect_all_nodes(right_node);
383}
384
385template<typename SizeT, typename KeyT, typename ValueT>
386SizeT count_leaf_nodes(const node<KeyT, ValueT>* left_end, const node<KeyT, ValueT>* right_end) noexcept(
387 noexcept(++std::declval<SizeT&>()))
388{
389 SizeT leaf_count = 1;
390 const auto* p = left_end;
391 const auto* p_end = right_end;
392 for (; p != p_end; p = p->next.get(), ++leaf_count)
393 ;
394
395 return leaf_count;
396}
397
398inline size_t count_needed_nonleaf_nodes(size_t leaf_count)
399{
400 size_t nonleaf_count = 0;
401 while (true)
402 {
403 if (leaf_count == 1)
404 break;
405
406 if ((leaf_count % 2) == 1)
407 // Add one to make it an even number.
408 ++leaf_count;
409
410 leaf_count /= 2;
411 nonleaf_count += leaf_count;
412 }
413
414 return nonleaf_count;
415}
416
417template<typename TraitsT>
419{
420 using node_list_type = std::vector<const node_base*>;
421 using tree_type = typename TraitsT::tree_type;
422
423public:
424 static size_t dump(std::ostream& os, const tree_type& tree, const node_base* root_node)
425 {
426 if (!root_node)
427 return 0;
428
429 node_list_type node_list;
430 node_list.push_back(root_node);
431 return dump_layer(os, tree, node_list, 0);
432 }
433
434private:
435 static size_t dump_layer(
436 std::ostream& os, const tree_type& tree, const node_list_type& node_list, unsigned int level)
437 {
438 using leaf_type = typename TraitsT::leaf_type;
439 using nonleaf_type = typename TraitsT::nonleaf_type;
440 using to_string = typename TraitsT::to_string;
441
442 if (node_list.empty())
443 return 0;
444
445 size_t node_count = node_list.size();
446
447 bool is_leaf = node_list.front()->is_leaf;
448 os << "level " << level << ':' << std::endl;
449 os << " type: " << (is_leaf ? "leaf" : "non-leaf") << std::endl;
450 os << " nodes:" << std::endl;
451
452 node_list_type new_list;
453
454 for (const node_base* p : node_list)
455 {
456 os << " - '";
457
458 if (!p)
459 {
460 os << "*'" << std::endl;
461 continue;
462 }
463
464 if (p->is_leaf)
465 {
466 const auto* pl = static_cast<const leaf_type*>(p);
467 os << to_string{tree}(*pl) << "'" << std::endl;
468 continue;
469 }
470
471 const auto* pnl = static_cast<const nonleaf_type*>(p);
472 os << to_string{tree}(*pnl) << "'" << std::endl;
473
474 if (pnl->left)
475 {
476 new_list.push_back(pnl->left);
477 if (pnl->right)
478 new_list.push_back(pnl->right);
479 }
480 }
481
482 if (!new_list.empty())
483 node_count += dump_layer(os, tree, new_list, level + 1);
484
485 return node_count;
486 }
487};
488
489}}} // namespace mdds::st::detail
Definition global.hpp:60
Definition node.hpp:419
Definition node.hpp:25
bool is_leaf
parent nonleaf_node
Definition node.hpp:27
Definition node.hpp:106
node & operator=(const node &r)
Definition node.hpp:160
node(const node &r)
Definition node.hpp:149
std::size_t refcount
Definition node.hpp:127
Definition node.hpp:40
nonleaf_node & operator=(const nonleaf_node &r)
Definition node.hpp:73
static constexpr bool nothrow_default_constructible_v
Definition node.hpp:52
nonleaf_node(const nonleaf_node &r)
Definition node.hpp:67