mdds
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 
16 namespace mdds { namespace st { namespace detail {
17 
18 #ifdef MDDS_DEBUG_NODE_BASE
19 
20 inline std::size_t node_instance_count = 0;
21 
22 #endif
23 
24 struct 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 
38 template<typename KeyT, typename ValueT>
39 struct 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 
59 public:
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 
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 
104 template<typename KeyT, typename ValueT>
105 struct 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 
137 public:
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 
195 template<typename KeyT, typename ValueT>
196 inline void intrusive_ptr_add_ref(node<KeyT, ValueT>* p)
197 {
198  ++p->refcount;
199 }
200 
201 template<typename KeyT, typename ValueT>
202 inline void intrusive_ptr_release(node<KeyT, ValueT>* p)
203 {
204  --p->refcount;
205  if (!p->refcount)
206  delete p;
207 }
208 
209 template<typename NodePtrT>
210 void link_nodes(NodePtrT& left, NodePtrT& right)
211 {
212  left->next = right;
213  right->prev = left;
214 }
215 
216 template<typename T>
218 {
219 public:
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 
253 private:
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 
356 template<typename KeyT, typename ValueT>
357 void 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 
367 template<typename KeyT, typename ValueT>
368 void 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 
385 template<typename SizeT, typename KeyT, typename ValueT>
386 SizeT 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 
398 inline 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 
417 template<typename TraitsT>
419 {
420  using node_list_type = std::vector<const node_base*>;
421  using tree_type = typename TraitsT::tree_type;
422 
423 public:
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 
434 private:
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: node.hpp:217
std::size_t refcount
next sibling leaf node.
Definition: node.hpp:127
nonleaf_node & operator=(const nonleaf_node &r)
Definition: node.hpp:73
bool is_leaf
parent nonleaf_node
Definition: node.hpp:27
Definition: node.hpp:105
node_base * right
left child nonleaf_node
Definition: node.hpp:50
node_ptr next
previous sibling leaf node.
Definition: node.hpp:125
node & operator=(const node &r)
Definition: node.hpp:160
node(const node &r)
Definition: node.hpp:149
Definition: node.hpp:418
node_base * left
high range value (non-inclusive)
Definition: node.hpp:49
Definition: global.hpp:59
key_type high
low range value (inclusive)
Definition: node.hpp:47
static constexpr bool nothrow_default_constructible_v
right child nonleaf_node
Definition: node.hpp:52
Definition: cref_wrapper.hpp:12
nonleaf_node(const nonleaf_node &r)
Definition: node.hpp:67
Definition: node.hpp:24
Definition: node.hpp:39