36 #ifndef ORBTREE_NODE_H 37 #define ORBTREE_NODE_H 41 #include <type_traits> 48 #include "vector_stacked.h" 51 #include "vector_realloc.h" 56 #if __cplusplus >= 201703L 57 #define CONSTEXPR constexpr 66 template<
class T1,
class T2>
71 trivial_pair(
const T1& x,
const T2& y):first(x),second(y) { }
72 trivial_pair(
const T1& x, T2&& y):first(x),second(std::move(y)) { }
73 trivial_pair(T1&& x,
const T2& y):first(std::move(x)),second(y) { }
74 trivial_pair(T1&& x, T2&& y):first(std::move(x)),second(std::move(y)) { }
75 trivial_pair(
const std::pair<T1,T2>& p):first(p.first),second(p.second) { }
76 operator std::pair<T1,T2>()
const {
return std::pair<T1,T2>(first,second); }
87 typedef const Key ValueType;
89 explicit KeyOnly(
const Key& k_):k(k_) { }
90 explicit KeyOnly(Key&& k_):k(std::move(k_)) { }
91 template<
class... T>
explicit KeyOnly(T&&... args) : k(std::forward<T...>(args...)) { }
94 const Key&
key()
const {
return k; }
99 static const Key&
key(
const ValueType& k) {
return k; }
101 static const bool keyonly =
true;
103 void swap(KeyOnly& k_) {
111 pair_type<Key, Value>
p;
114 typedef Value MappedType;
116 typedef pair_type<Key, Value> ValueType;
118 explicit KeyValue(
const std::pair<Key,Value>& kv):p(kv) { }
119 explicit KeyValue(pair_type<Key,Value>&& kv):p(std::move(kv)) { }
120 explicit KeyValue(
const pair_type<Key,Value>& kv):p(kv) { }
123 const Key&
key()
const {
return p.first; }
127 const Value&
value()
const {
return p.second; }
133 static const Key&
key(
const ValueType& kv) {
return kv.first; }
135 static const bool keyonly =
false;
147 template<
class Key,
class Value>
161 template<
class KeyValueT,
class NVTypeT,
bool simple = false>
165 typedef KeyValueT KeyValue;
166 typedef NVTypeT NVType;
175 typename std::conditional<simple, NVType, NVType*>::type partialsum;
184 Node(
const KeyValue& kv_) : kv(kv_), partialsum(0) { }
185 Node(KeyValue&& kv_) : kv(std::move(kv_)), partialsum(0) { }
186 Node():kv(), partialsum(0) { }
187 template<
class... T>
Node(T&&... args) : kv(std::forward<T...>(args...)), partialsum(0) { }
189 template<
bool simple_ = simple>
void do_delete(
typename std::enable_if<simple_,void*>::type = 0) { }
190 template<
bool simple_ = simple>
void do_delete(
typename std::enable_if<!simple_,void*>::type = 0) {
191 if(partialsum)
delete[]partialsum;
193 ~Node() { do_delete(); }
195 KeyValue& get_key_value() {
return kv; }
196 const KeyValue& get_key_value()
const {
return kv; }
208 void set_parent(
const Node* p) { parent =
const_cast<Node*
>(p); }
209 void set_left(
const Node* x) { left =
const_cast<Node*
>(x); }
210 void set_right(
const Node* x) { right =
const_cast<Node*
>(x); }
228 unsigned int get_nv_per_node()
const {
return nv_per_node; }
234 explicit NodeAllocatorPtr(
unsigned int nv_per_node_):root(0),nil(0),nv_per_node(nv_per_node_) {
235 if CONSTEXPR (simple)
if(nv_per_node != 1)
236 throw std::runtime_error(
"For simple tree, weight function can only return one component!\n");
241 if(root) free_tree_nodes_r(root);
251 constexpr
static Node* Invalid = 0;
253 const static size_t max_nodes = 0;
275 if(n->left && n->left != nil) free_tree_nodes_r((
Node*)(n->left));
276 if(n->right && n->right != nil) free_tree_nodes_r((
Node*)(n->right));
284 if(n->left && n->left != nil) free_tree_nodes_r((
Node*)(n->left));
285 if(n->right && n->right != nil) free_tree_nodes_r((
Node*)(n->right));
290 template <
bool simple_ = simple>
291 void init_node(
typename std::enable_if<simple_, Node*>::type n) {
297 if(!n)
throw std::runtime_error(
"NodeAllocatorPtr::init_node(): out of memory!\n");
300 template <
bool simple_ = simple>
301 void init_node(
typename std::enable_if<!simple_, Node*>::type n) {
306 n->partialsum =
new NVType[nv_per_node];
308 if( !n || ! (n->partialsum) )
throw std::runtime_error(
"NodeAllocatorPtr::init_node(): out of memory!\n");
312 template<
bool simple_ = simple>
313 void get_node_sum(NodeHandle n,
typename std::enable_if<simple_,NVType*>::type s)
const {
317 template<
bool simple_ = simple>
318 void get_node_sum(NodeHandle n,
typename std::enable_if<!simple_,NVType*>::type s)
const {
319 for(
unsigned int i = 0; i < nv_per_node; i++) s[i] = n->
partialsum[i];
322 template<
bool simple_ = simple>
323 void set_node_sum(NodeHandle n1,
typename std::enable_if<simple_,const NVType*>::type s) {
328 template<
bool simple_ = simple>
329 void set_node_sum(NodeHandle n1,
typename std::enable_if<!simple_,const NVType*>::type s) {
331 for(
unsigned int i = 0; i < nv_per_node; i++) n->
partialsum[i] = s[i];
354 template<
class KeyValueT,
class NVTypeT,
class IndexType>
359 typedef IndexType NodeHandle;
360 typedef KeyValueT KeyValue;
361 typedef NVTypeT NVType;
364 static constexpr IndexType redbit = 1U << (std::numeric_limits<IndexType>::digits - 1);
365 static constexpr IndexType max_nodes = redbit - 1;
366 static constexpr IndexType deleted_indicator = (max_nodes | redbit);
390 KeyValue& get_key_value() {
return kv; }
391 const KeyValue& get_key_value()
const {
return kv; }
392 bool is_red()
const {
return parent & NodeAllocatorCompact::redbit; }
393 bool is_black()
const {
return !is_red(); }
394 void set_red() { parent |= NodeAllocatorCompact::redbit; }
398 NodeHandle get_left()
const {
return left; }
399 NodeHandle get_right()
const {
return right; }
400 void set_parent(NodeHandle p) {
401 if(p > NodeAllocatorCompact::max_nodes)
throw std::runtime_error(
"NodeAllocatorCompact::Node::set_parent(): parent ID too large!\n");
402 parent = p | (parent & NodeAllocatorCompact::redbit);
404 void set_left(NodeHandle x) { left = x; }
405 void set_right(NodeHandle x) { right = x; }
408 void set_deleted() { parent = NodeAllocatorCompact::deleted_indicator; }
410 bool is_deleted()
const {
return (parent == NodeAllocatorCompact::deleted_indicator); }
426 #ifdef USE_STACKED_VECTOR 429 typedef typename std::conditional< std::is_trivially_copyable<KeyValueT>::value,
434 node_vector_type nodes;
435 const unsigned int nv_per_node;
437 NodeHandle deleted_nodes_head;
441 static constexpr NodeHandle Invalid = max_nodes;
450 deleted_nodes_head(Invalid),root(Invalid),nil(Invalid) {
464 bool try_get_node(NodeHandle& n) {
465 if(deleted_nodes_head != Invalid) {
466 if(!n_del)
throw std::runtime_error(
"NodeAllocatorCompact::alloc_node(): inconsistent deleted nodes!\n");
468 n = deleted_nodes_head;
469 nodes[n].set_parent(Invalid);
470 deleted_nodes_head = nodes[deleted_nodes_head].get_left();
471 if(deleted_nodes_head != Invalid) nodes[deleted_nodes_head].set_right(Invalid);
478 void move_nv(IndexType x, IndexType y) {
479 size_t xbase = ((size_t)x)*nv_per_node;
480 size_t ybase = ((size_t)y)*nv_per_node;
481 for(
unsigned int i=0;i<nv_per_node;i++) nvarray[xbase + i] = nvarray[ybase + i];
489 void move_node(NodeHandle x, NodeHandle y) {
490 nodes[x] = std::move(nodes[y]);
493 if(y == root || y == nil)
throw std::runtime_error(
"NodeAllocatorCompact::move_node(): root or nil is moved!\n");
495 if(nodes[x].get_parent() != Invalid && nodes[x].get_parent() != nil) {
496 if(nodes[nodes[x].get_parent()].get_left() == y) nodes[nodes[x].get_parent()].set_left(x);
498 if(nodes[nodes[x].get_parent()].get_right() == y) nodes[nodes[x].get_parent()].set_right(x);
499 else throw std::runtime_error(
"NodeAllocatorCompact::move_node(): inconsistent tree detected!\n");
502 else throw std::runtime_error(
"NodeAllocatorCompact::move_node(): node with no parent!\n");
503 if(nodes[x].get_left() != Invalid && nodes[x].get_left() != nil) {
504 if(nodes[nodes[x].get_left()].get_parent() != y)
505 throw std::runtime_error(
"NodeAllocatorCompact::move_node(): inconsistent tree detected!\n");
506 nodes[nodes[x].get_left()].set_parent(x);
508 if(nodes[x].get_right() != Invalid && nodes[x].get_right() != nil) {
509 if(nodes[nodes[x].get_right()].get_parent() != y)
510 throw std::runtime_error(
"NodeAllocatorCompact::move_node(): inconsistent tree detected!\n");
511 nodes[nodes[x].get_right()].set_parent(x);
516 void shrink_memory(IndexType new_capacity = 0) {
517 nodes.shrink_to_fit(new_capacity);
524 NodeHandle n = nodes.size();
526 if(try_get_node(n)) nodes[n] =
Node();
529 if(n == max_nodes)
throw std::runtime_error(
"NodeAllocatorFlat::new_node(): reached maximum number of nodes!\n");
530 nodes.emplace_back();
531 nvarray.
resize(((
size_t)(n+1))*nv_per_node,NVType());
537 NodeHandle n = nodes.size();
538 if(try_get_node(n)) nodes[n] =
Node(kv);
540 if(n == max_nodes)
throw std::runtime_error(
"NodeAllocatorFlat::new_node(): reached maximum number of nodes!\n");
541 nodes.emplace_back(kv);
542 nvarray.
resize(((
size_t)(n+1))*nv_per_node,NVType());
548 NodeHandle n = nodes.size();
549 if(try_get_node(n)) nodes[n] =
Node(std::forward<KeyValue>(kv));
551 if(n == max_nodes)
throw std::runtime_error(
"NodeAllocatorFlat::new_node(): reached maximum number of nodes!\n");
552 nodes.emplace_back(std::forward<KeyValue>(kv));
553 nvarray.
resize(((
size_t)(n+1))*nv_per_node,NVType());
558 template<
class... T> NodeHandle
new_node(T&&... kv) {
559 NodeHandle n = nodes.size();
560 if(try_get_node(n)) nodes[n] =
Node(std::forward<T>(kv)...);
562 if(n == max_nodes)
throw std::runtime_error(
"NodeAllocatorFlat::new_node(): reached maximum number of nodes!\n");
563 nodes.emplace_back(std::forward<T>(kv)...);
564 nvarray.
resize(((
size_t)(n+1))*nv_per_node,NVType());
572 nodes[n].set_deleted();
573 nodes[n].set_right(Invalid);
574 nodes[n].set_left(deleted_nodes_head);
575 if(deleted_nodes_head != Invalid) nodes[deleted_nodes_head].set_right(n);
576 deleted_nodes_head = n;
586 nodes[root] =
Node();
597 size_t base = ((size_t)n)*nv_per_node;
598 for(
unsigned int i=0;i<nv_per_node;i++) s[i] = nvarray[base+i];
602 size_t base = ((size_t)n)*nv_per_node;
603 for(
unsigned int i=0;i<nv_per_node;i++) nvarray[base+i] = s[i];
609 size_t capacity()
const {
return nodes.capacity(); }
615 while(deleted_nodes_head != Invalid) {
617 NodeHandle size = nodes.size();
618 if(size == 0)
throw std::runtime_error(
"NodeAllocatorCompact::shrink_size(): ran out of nodes!\n");
620 if(nodes[size].is_deleted()) {
622 NodeHandle left = nodes[size].get_left();
623 NodeHandle right = nodes[size].get_right();
624 if(left != Invalid) nodes[left].set_right(right);
625 if(right != Invalid) nodes[right].set_left(left);
626 if(deleted_nodes_head == size) deleted_nodes_head = left;
630 NodeHandle n = deleted_nodes_head;
632 throw std::runtime_error(
"NodeAllocatorCompact::shrink_size(): inconsistent deleted nodes!\n");
633 deleted_nodes_head = nodes[deleted_nodes_head].get_left();
634 nodes[deleted_nodes_head].set_right(Invalid);
638 nvarray.
resize(((
size_t)size)*nv_per_node);
639 if(!n_del)
throw std::runtime_error(
"NodeAllocatorCompact::shrink_size(): inconsistent deleted nodes!\n");
static const Key & key(const ValueType &k)
helper to extract the key from ValueType – contrast it with KeyValue
Definition: orbtree_node.h:99
KeyValue kv
key and (optionally) value stored
Definition: orbtree_node.h:174
const Node * NodeHandle
Node handle type to be used by tree implementation.
Definition: orbtree_node.h:220
Node & get_node(NodeHandle x)
get reference to a modifiable node
Definition: orbtree_node.h:246
void init_node(typename std::enable_if<!simple_, Node *>::type n)
safely initialize new node, throw an exception if memory allocation failed
Definition: orbtree_node.h:301
const ValueType & keyvalue() const
universal access to key / key-value pair
Definition: orbtree_node.h:130
void clear_tree()
clear tree, to be reused
Definition: orbtree_node.h:580
const Node * get_left() const
get handle for left child
Definition: orbtree_node.h:206
void free_node(NodeHandle n)
delete node – tree is not traversed, the caller must arrange to "cut" out the node in question (othe...
Definition: orbtree_node.h:270
void init_node(typename std::enable_if< simple_, Node *>::type n)
safely initialize new node, throw an exception if memory allocation failed
Definition: orbtree_node.h:291
const Key & key() const
access key value – only const access is possible, key should not change
Definition: orbtree_node.h:94
Node * new_node()
get new node
Definition: orbtree_node.h:259
trivially copyable pair, similar to std::pair
Definition: orbtree_node.h:67
void get_node_sum(NodeHandle n, typename std::enable_if<!simple_, NVType *>::type s) const
get the value of the partial sum of weights stored in this node – case when the weight function retu...
Definition: orbtree_node.h:318
wrapper class for a key-value pair
Definition: orbtree_node.h:109
NodeHandle new_node(KeyValue &&kv)
get new node – note that it is the callers responsibility to store the handle in the tree ...
Definition: orbtree_node.h:547
void clear_tree()
clear tree, i.e. free all nodes, but keep root (sentinel) and nil, so that tree can be used again ...
Definition: orbtree_node.h:272
pair_type< Key, Value > p
key and value, key should not change – not const to allow swapping / moving nodes ...
Definition: orbtree_node.h:111
void shrink_to_fit(size_t new_capacity=0)
Free up unused memory.
Definition: vector_realloc.h:423
Node * new_node(T &&... kv)
get new node
Definition: orbtree_node.h:266
const Node * get_parent() const
get handle for parent
Definition: orbtree_node.h:205
Node * new_node(KeyValue &&kv)
get new node
Definition: orbtree_node.h:263
bool is_red() const
test if this node is red
Definition: orbtree_node.h:198
void set_red()
set this node red
Definition: orbtree_node.h:200
unsigned int get_nv_per_node() const
each node has nv_per_node values calculated and stored in it
Definition: orbtree_node.h:593
void reserve(size_t n)
Reserve memory for at least n elements. Throws an exception if memory allocation is not successful...
Definition: vector_realloc.h:242
IndexType right
Right child.
Definition: orbtree_node.h:377
const Node * get_right() const
get handle for right child
Definition: orbtree_node.h:207
NodeAllocatorCompact()
Nil sentinel.
Definition: orbtree_node.h:445
Alternate node allocator with the aim to use less memory.
Definition: orbtree_node.h:355
bool is_black() const
test if this node is black
Definition: orbtree_node.h:199
Node & get_node(NodeHandle x)
get reference to a modifiable node
Definition: orbtree_node.h:457
NodeHandle nil
Root sentinel.
Definition: orbtree_node.h:443
wrapper class for key that can go in sets and multisets
Definition: orbtree_node.h:82
ValueType & keyvalue()
universal access to key / key-value pair
Definition: orbtree_node.h:129
ValueType & keyvalue() const
universal access to key / key-value pair
Definition: orbtree_node.h:96
void set_parent(const Node *p)
set handle for parent
Definition: orbtree_node.h:208
static const Key & key(const ValueType &kv)
helper to extract only the key from ValueType
Definition: orbtree_node.h:133
Node * new_node(const KeyValue &kv)
get new node
Definition: orbtree_node.h:261
Basic allocator that allocates each node individually, using C++ new / delete and pointers...
Definition: orbtree_node.h:162
const Key & key() const
access key – only const access is possible, key should not change
Definition: orbtree_node.h:123
void set_deleted()
Set a flag indicating this node has been deleted (but memory has not been freed yet).
Definition: orbtree_node.h:408
node class
Definition: orbtree_node.h:172
Key k
actual key; should not change during a node's lifetime – not const to allow swapping / moving nodes ...
Definition: orbtree_node.h:84
const Node & get_node(const NodeHandle x) const
get reference to a const node
Definition: orbtree_node.h:248
size_t capacity() const
get the current capacity of the underlying storage
Definition: orbtree_node.h:609
void reserve(size_t size)
Reserve storage for at least the requested number of elements. It can throw an exception on failure t...
Definition: orbtree_node.h:647
void shrink_to_fit()
Free up memory taken up by deleted nodes by rearranging storage.
Definition: orbtree_node.h:614
void set_black()
set this node black
Definition: orbtree_node.h:201
static constexpr NodeHandle Invalid
invalid handle
Definition: orbtree_node.h:441
KeyValue kv
Key and (optionally) value stored in this node.
Definition: orbtree_node.h:373
const unsigned int nv_per_node
each node has nv_per_node values calculated and stored in it
Definition: orbtree_node.h:227
void free_tree_nodes_r(Node *n)
free whole tree (starting from root)
Definition: orbtree_node.h:283
void free_node(NodeHandle n)
delete node – tree is not traversed, the caller must arrange to "cut" out the node in question ...
Definition: orbtree_node.h:570
bool is_deleted() const
Check if this node is deleted.
Definition: orbtree_node.h:410
C++ vector-like container that internally maintains a "stack" of vectors instead of having one large ...
Definition: vector_stacked.h:171
const Node & get_node(NodeHandle x) const
get reference to a const node
Definition: orbtree_node.h:459
void set_node_sum(NodeHandle n, const NVType *s)
set the partial sum stored in node n
Definition: orbtree_node.h:601
C++ vector-like container for trivially moveable types, using realloc() for growing memory...
Definition: vector_realloc.h:115
NodeHandle new_node(const KeyValue &kv)
get new node – note that it is the callers responsibility to store the handle in the tree ...
Definition: orbtree_node.h:536
NodeHandle new_node(T &&... kv)
get new node – note that it is the callers responsibility to store the handle in the tree ...
Definition: orbtree_node.h:558
std::conditional< simple, NVType, NVType * >::type partialsum
partial sum (sum of this node's children's weight + this node's weight)
Definition: orbtree_node.h:176
IndexType left
Left child.
Definition: orbtree_node.h:376
Value & value()
access value
Definition: orbtree_node.h:125
const Value & value() const
access value
Definition: orbtree_node.h:127
IndexType parent
Parent node reference, actually an index in a vector; also stores red-black flag. ...
Definition: orbtree_node.h:375
size_t deleted_nodes() const
get the number of deleted nodes
Definition: orbtree_node.h:611
void set_left(const Node *x)
set handle for left child
Definition: orbtree_node.h:209
void get_node_sum(NodeHandle n, typename std::enable_if< simple_, NVType *>::type s) const
get the value of the partial sum of weights stored in this node – simple case when the weight functi...
Definition: orbtree_node.h:313
void resize(size_t count)
Resize vector. If new size is larger than current size, new elements are default constructed. Can throw an exception on memory allocation error.
Definition: vector_realloc.h:278
void set_right(const Node *x)
set handle for right child
Definition: orbtree_node.h:210
Node * nil
Sentinel for nil.
Definition: orbtree_node.h:224
Node * root
Root sentinel, allocated automatically, used when freeing the tree.
Definition: orbtree_node.h:223
void set_node_sum(NodeHandle n1, typename std::enable_if< simple_, const NVType *>::type s)
set the value of the partial sum stored in this node – simple case when the weight function returns ...
Definition: orbtree_node.h:323
Node object.
Definition: orbtree_node.h:370
NodeHandle new_node()
get new node – note that it is the callers responsibility to store the handle in the tree ...
Definition: orbtree_node.h:523
void set_node_sum(NodeHandle n1, typename std::enable_if<!simple_, const NVType *>::type s)
set the value of the partial sum stored in this node – case when the weight function returns a vecto...
Definition: orbtree_node.h:329
void get_node_sum(NodeHandle n, NVType *s) const
get the partial sum stored in node n
Definition: orbtree_node.h:596