orbtree
orbtree_base.h
1 /* -*- C++ -*-
2  * orbtree_base.h -- generalized order statistic red-black tree implementation
3  * main definition of tree and functionality
4  *
5  * Copyright 2019 Daniel Kondor <kondor.dani@gmail.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are
9  * met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following disclaimer
15  * in the documentation and/or other materials provided with the
16  * distribution.
17  * * Neither the name of the nor the names of its
18  * contributors may be used to endorse or promote products derived from
19  * this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  *
34  */
35 
36 #ifndef ORBTREE_BASE_H
37 #define ORBTREE_BASE_H
38 #include "orbtree_node.h"
39 
40 namespace orbtree {
41 
42  template<class NVFunc> class NVFunc_wrapper {
43  protected:
44  NVFunc f;
45  explicit NVFunc_wrapper(const NVFunc& f_):f(f_) { }
46  explicit NVFunc_wrapper(NVFunc&& f_):f(std::move(f_)) { }
47  template<class T>
48  explicit NVFunc_wrapper(const T& t):f(t) { }
49  };
50 
62  template<class NodeAllocator, class Compare, class NVFunc, bool multi>
63  class orbtree_base : public NVFunc_wrapper<NVFunc>, NodeAllocator {
64  protected:
66  typedef typename NodeAllocator::Node Node;
67  typedef typename NodeAllocator::KeyValue KeyValue;
68  typedef typename NodeAllocator::KeyValue::KeyType KeyType;
69  typedef typename NodeAllocator::KeyValue::ValueType ValueType;
71  typedef typename NodeAllocator::NodeHandle NodeHandle;
72  using NodeAllocator::Invalid;
73 
74  public:
76  typedef typename NodeAllocator::NVType NVType;
77 
78  protected:
80  void NVAdd(NVType* x, const NVType* y) const; /* x = x + y */
82  void NVSubtract(NVType* x, const NVType* y) const; /* x = x - y */
83 
85  size_t size1;
86  NVFunc& f;
87  Compare c;
88 
89  void create_sentinels() {
90  Node& rootn = get_node(root());
91  rootn.set_parent(nil());
92  rootn.set_left(nil());
93  rootn.set_right(nil());
94  rootn.set_black();
95  Node& niln = get_node(nil());
96  niln.set_parent(nil());
97  niln.set_left(nil());
98  niln.set_right(nil());
99  niln.set_black(); /* nil should always be black */
100  size1 = 0;
101  }
102 
104  Node& get_node(NodeHandle n) { return NodeAllocator::get_node(n); }
106  const Node& get_node(NodeHandle n) const { return NodeAllocator::get_node(n); }
108  NodeHandle root() const { return NodeAllocator::root; }
110  NodeHandle nil() const { return NodeAllocator::nil; }
111 
112 
113  //~ public:
114  orbtree_base() { create_sentinels(); }
115  explicit orbtree_base(const NVFunc& f_, const Compare& c_) : NVFunc_wrapper<NVFunc>(f_),
116  NodeAllocator(NVFunc_wrapper<NVFunc>::f.get_nr()), f(NVFunc_wrapper<NVFunc>::f), c(c_) { create_sentinels(); }
117  explicit orbtree_base(NVFunc&& f_, const Compare& c_) : NVFunc_wrapper<NVFunc>(std::move(f_)),
118  NodeAllocator(NVFunc_wrapper<NVFunc>::f.get_nr()), f(NVFunc_wrapper<NVFunc>::f), c(c_) { create_sentinels(); }
119  template<class T>
120  explicit orbtree_base(const T& t, const Compare& c_) : NVFunc_wrapper<NVFunc>(t),
121  NodeAllocator(NVFunc_wrapper<NVFunc>::f.get_nr()), f(NVFunc_wrapper<NVFunc>::f), c(c_) { create_sentinels(); }
122 
123  /* copy / move constructor -- not implemented yet */
124 
125 
126  /* interface for finding elements / inserting
127  * returns position of new node (if inserted) or node with the same key (for non-multi map/set)
128  * and bool flag indicating if insert happened */
143  std::pair<NodeHandle,bool> insert(ValueType&& kv);
145  std::pair<NodeHandle,bool> insert(const ValueType& kv);
164  NodeHandle insert(NodeHandle hint, ValueType&& kv);
166  NodeHandle insert(NodeHandle hint, const ValueType& kv);
171  template<class... T> std::pair<NodeHandle,bool> emplace(T&&... t);
176  template<class... T> NodeHandle emplace_hint(NodeHandle hint, T&&... t);
177 
186  bool insert_search(const KeyType& k, NodeHandle& n, bool& insert_left) const;
191  bool insert_search_hint(NodeHandle hint, const KeyType& k, NodeHandle& n, bool& insert_left) const;
200  void insert_helper(NodeHandle n, NodeHandle n1, bool insert_left);
201 
207  template<class K> auto find(const K& key) const -> NodeHandle;
209  template<class K> auto lower_bound(const K& key) const -> NodeHandle;
211  template<class K> auto upper_bound(const K& key) const -> NodeHandle;
212 
214  const KeyType& get_node_key(NodeHandle n) const { return get_node(n).get_key_value().key(); }
215 
217  bool compare_key_equals(NodeHandle n, const KeyType& k) const {
218  return (!c(get_node_key(n),k)) && (!c(k,get_node_key(n)));
219  }
220 
227  void get_node_grvalue(NodeHandle n, NVType* res) const { f(get_node(n).get_key_value().keyvalue(), res); }
228 
230  NodeHandle first() const;
232  NodeHandle last() const;
234  NodeHandle next(NodeHandle n) const;
236  NodeHandle previous(NodeHandle n) const;
237 
239  NodeHandle erase(NodeHandle n);
240 
242  Node& get_left(NodeHandle n) { return get_node(get_node(n).get_left()); }
244  const Node& get_left(NodeHandle n) const { return get_node(get_node(n).get_left()); }
246  Node& get_right(NodeHandle n) { return get_node(get_node(n).get_right()); }
248  const Node& get_right(NodeHandle n) const { return get_node(get_node(n).get_right()); }
250  Node& get_parent(NodeHandle n) { return get_node(get_node(n).get_parent()); }
252  const Node& get_parent(NodeHandle n) const { return get_node(get_node(n).get_parent()); }
254  NodeHandle get_sibling_handle(NodeHandle n) const {
255  if(n == get_parent(n).get_left()) return get_parent(n).get_right();
256  else return get_parent(n).get_left();
257  }
259  Node& get_sibling(NodeHandle n) { return get_node(get_sibling_handle(n)); }
261  const Node& get_sibling(NodeHandle n) const { return get_node(get_sibling_handle(n)); }
263  bool is_left_side(NodeHandle n) const { return (get_parent(n).get_left() == n); }
264 
266  void update_sum(NodeHandle n);
268  void update_sum_r(NodeHandle n) { for(;n != root();n = get_node(n).get_parent()) update_sum(n); }
269 
272  template<class KeyValue_ = KeyValue>
273  void update_value(NodeHandle n, typename KeyValue_::MappedType const& v) {
274  get_node(n).get_key_value().value() = v;
275  update_sum_r(n);
276  }
279  template<class KeyValue_ = KeyValue>
280  void update_value(NodeHandle n, typename KeyValue_::MappedType&& v) {
281  get_node(n).get_key_value().value() = std::move(v);
282  update_sum_r(n);
283  }
284 
290  void rotate_left(NodeHandle x);
295  void rotate_right(NodeHandle x);
298  void rotate_parent(NodeHandle x);
299 
300  public:
302  void clear() {
303  NodeAllocator::clear_tree(); /* free up all nodes (except root and nil sentinels) */
304  create_sentinels(); /* reset sentinels */
305  }
306 
308  template<class K> void get_sum_fv(const K& k, NVType* res) const;
310  void get_sum_fv_node(NodeHandle x, NVType* res) const;
312  void get_norm_fv(NVType* res) const;
313 
320  void check_tree(double epsilon = -1.0) const;
321  protected:
323  void check_tree_r(double epsilon, NodeHandle x, size_t black_count, size_t& previous_black_count) const;
324  };
325 
326 
327  template<class NodeAllocator, class Compare, class NVFunc, bool multi> template<class K>
329  if(root() == Invalid) return nil();
330  NodeHandle n = get_node(root()).get_right();
331  if(n == Invalid || n == nil()) return nil();
332  while(true) {
333  const KeyType& k1 = get_node_key(n);
334  if(c(key,k1)) {
335  /* key < k1 */
336  n = get_node(n).get_left();
337  }
338  else {
339  if(c(k1,key)) n = get_node(n).get_right(); /* key > k1 */
340  else return n; /* key == k1 */
341  }
342  if(n == nil()) return n; /* end of search, not found */
343  }
344  }
345 
346  template<class NodeAllocator, class Compare, class NVFunc, bool multi> template<class K>
348  if(root() == Invalid) return nil();
349  NodeHandle n = get_node(root()).get_right();
350  if(n == Invalid || n == nil()) return nil();
351  NodeHandle last = nil(); /* guess of the result node */
352  while(true) {
353  const KeyType& k1 = get_node_key(n);
354  if(c(k1,key)) {
355  /* key > k1 */
356  n = get_node(n).get_right();
357  }
358  else { /* key <= k1, potential candidate */
359  last = n;
360  n = get_node(n).get_left();
361  }
362  if(n == nil()) return last; /* end of search */
363  }
364  }
365 
366  template<class NodeAllocator, class Compare, class NVFunc, bool multi> template<class K>
368  if(root() == Invalid) return nil();
369  NodeHandle n = get_node(root()).get_right();
370  if(n == Invalid || n == nil()) return nil();
371  NodeHandle last = nil(); /* guess of the result node */
372  while(true) {
373  const KeyType& k1 = get_node_key(n);
374  if(c(key,k1)) {
375  /* key < k1, potential candidate */
376  last = n;
377  n = get_node(n).left;
378  }
379  else {
380  /* key >= k1, has to go right */
381  n = get_node(n).right;
382  }
383  if(n == nil()) return last; /* end of search */
384  }
385  }
386 
387  template<class NodeAllocator, class Compare, class NVFunc, bool multi> template<class K>
389  for(unsigned int i=0; i < f.get_nr(); i++) res[i] = NVType();
390  NVType tmp[f.get_nr()];
391  if(root() == Invalid) return;
392  //~ const Node& r = get_node(root());
393  NodeHandle n = get_node(root()).get_right();
394  if(n == Invalid || n == nil()) return;
395  while(true) { /* recursive search starting from the root to find all nodes with key < k */
396  const KeyType& k1 = get_node_key(n);
397  if(c(k1,k)) {
398  /* k1 < key, we have to add the sum from the left subtree + n and continue to the right */
399  NodeHandle l = get_node(n).get_left();
400  if(l != nil()) {
401  this->get_node_sum(l,tmp);
402  NVAdd(res,tmp);
403  }
404  get_node_grvalue(n,tmp);
405  NVAdd(res,tmp);
406 
407  n = get_node(n).get_right();
408  if(n == nil()) break;
409  }
410  else {
411  /* k1 >= key, we have to continue toward the left */
412  n = get_node(n).get_left();
413  if(n == nil()) break;
414  }
415  }
416 
417  }
418  template<class NodeAllocator, class Compare, class NVFunc, bool multi>
420  for(unsigned int i=0; i < f.get_nr(); i++) res[i] = NVType();
421  NVType tmp[f.get_nr()];
422  if(x == this->Invalid || x == nil() || x == root()) return;
423  /* 1. add sum from x's left to the sum
424  * 2. go up one level
425  * 3. if x is right child, add parent's value + parent's left child's value
426  * 4. repeat until root is reached */
427  NodeHandle l = get_node(x).get_left();
428  if(l != nil()) {
429  this->get_node_sum(l,tmp);
430  NVAdd(res,tmp);
431  }
432 
433  NodeHandle p = get_node(x).get_parent();
434 
435  while(p != root()) {
436  if(x == get_node(p).get_right()) {
437  l = get_node(p).get_left();
438  if(l != nil()) {
439  this->get_node_sum(l,tmp);
440  NVAdd(res,tmp);
441  }
442  get_node_grvalue(p,tmp);
443  NVAdd(res,tmp);
444  }
445  x = p;
446  p = get_node(x).get_parent();
447  }
448  }
449 
450 
451  template<class NodeAllocator, class Compare, class NVFunc, bool multi>
453  if(root() != Invalid) {
454  NodeHandle n = get_node(root()).get_right();
455  if(n != Invalid && n != nil()) {
456  this->get_node_sum(n,res);
457  return;
458  }
459  }
460  for(unsigned int i=0; i < f.get_nr(); i++) res[i] = NVType(); /* return all zeroes for an empty tree */
461  }
462 
463 
464  /* first, last, next, previous */
465  template<class NodeAllocator, class Compare, class NVFunc, bool multi>
467  if(root() == Invalid) return nil();
468  NodeHandle n = get_node(root()).get_right();
469  if(n == Invalid || n == nil()) return nil();
470  /* keep going left until it's possible */
471  while(get_node(n).get_left() != nil()) n = get_node(n).get_left();
472  return n;
473  }
474  template<class NodeAllocator, class Compare, class NVFunc, bool multi>
476  if(root() == Invalid) return nil();
477  NodeHandle n = get_node(root()).get_right();
478  if(n == Invalid || n == nil()) return nil();
479  /* keep going right until it's possible */
480  while(get_node(n).get_right() != nil()) n = get_node(n).get_right();
481  return n;
482  }
483  template<class NodeAllocator, class Compare, class NVFunc, bool multi>
485  if(n == nil()) return n; /* incrementing nil is no-op */
486  /* try going right */
487  if(get_node(n).get_right() != nil()) {
488  n = get_node(n).get_right();
489  /* and then keep going left until possible */
490  while(get_node(n).get_left() != nil()) n = get_node(n).get_left();
491  return n;
492  }
493  /* if not possible to go right, go up until n is a right child */
494  while(true) {
495  NodeHandle p = get_node(n).get_parent();
496  if(p == root()) return nil(); /* end of search, no next node fonud */
497  if(get_node(p).get_left() == n) return p; /* found a suitable parent */
498  n = p; /* keep going */
499  }
500  }
501  template<class NodeAllocator, class Compare, class NVFunc, bool multi>
503  if(n == nil()) return last(); /* decrementing nil results in the last valid node -- this is done to make implementing the end() iterator easier */
504  /* try going left */
505  if(get_node(n).get_left() != nil()) {
506  n = get_node(n).get_left();
507  /* keep going right if possible */
508  while(get_node(n).get_right() != nil()) n = get_node(n).get_right();
509  return n;
510  }
511  /* if not possible to go left, go up until n is a left child */
512  while(true) {
513  NodeHandle p = get_node(n).get_parent();
514  if(p == root()) return nil(); /* already at the beginning */
515  if(get_node(p).get_right() == n) return p; /* found a suitable parent */
516  n = p; /* otherwise keep going */
517  }
518  }
519 
520 
521  /* rotations */
522  //~ protected:
523  /* update the sum only inside n */
524  template<class NodeAllocator, class Compare, class NVFunc, bool multi>
526  /* sum(n) = sum(n.left) + sum(n.right) + f(n.key) */
527  NVType sum[f.get_nr()];
528  NVType tmp[f.get_nr()];
529  get_node_grvalue(n,sum);
530  if(get_node(n).get_left() != nil()) {
531  this->get_node_sum(get_node(n).get_left(),tmp);
532  NVAdd(sum,tmp);
533  }
534  if(get_node(n).get_right() != nil()) {
535  this->get_node_sum(get_node(n).get_right(),tmp);
536  NVAdd(sum,tmp);
537  }
538  this->set_node_sum(n,sum);
539  }
540 
541 
542  /* left rotate:
543  * right child of x takes its place, x becomes its left child
544  * left child of x's original right child becomes x's right child
545  */
546  template<class NodeAllocator, class Compare, class NVFunc, bool multi>
548  NodeHandle y = get_node(x).get_right(); /* we assume that x != nil and y != nil */
549  get_node(x).set_right( get_node(y).get_left() ); /* x.right = y.left; -- this can be nil */
550  if(get_node(x).get_right() != nil()) get_right(x).set_parent(x); /* here we have to check -- don't want to modify parent of nil */
551  get_node(y).set_parent( get_node(x).get_parent() );
552 
553  if( x == get_parent(x).get_right() ) get_parent(x).set_right(y); /* note: parent of x can be root (sentinel) node (if x is the "real" root of the tree */
554  else get_parent(x).set_left(y);
555  get_node(y).set_left(x);
556  get_node(x).set_parent(y);
557 
558  update_sum(x); /* only these two need to be updated -- upstream of y the values stay the same */
559  update_sum(y);
560  }
561 
562  /* right rotate.
563  * left child of x takes its place, x becomes its right child
564  * right child of x's original left child becomes x's left child */
565  template<class NodeAllocator, class Compare, class NVFunc, bool multi>
567  NodeHandle y = get_node(x).get_left(); /* we assume that x != nil and y != nil */
568  get_node(x).set_left( get_node(y).get_right() );
569  if(get_node(x).get_left() != nil()) get_left(x).set_parent(x);
570  get_node(y).set_parent( get_node(x).get_parent() );
571 
572  if( x == get_parent(x).get_right() ) get_parent(x).set_right(y);
573  else get_parent(x).set_left(y);
574  get_node(y).set_right(x);
575  get_node(x).set_parent(y);
576 
577  update_sum(x);
578  update_sum(y);
579  }
580 
581  /* helper: rotate by n's parent -- either left or right, depending on n's position
582  * caller must ensure that n and its parent are not nil or root */
583  template<class NodeAllocator, class Compare, class NVFunc, bool multi>
585  if(n == get_parent(n).get_left()) rotate_right(get_node(n).get_parent());
586  else rotate_left(get_node(n).get_parent());
587  }
588 
589 
590  /* helper for insert -- find the location where to insert
591  * note: in a multi map/set, the inserted element will come after any already
592  * existing elements with the same key */
593  template<class NodeAllocator, class Compare, class NVFunc, bool multi>
594  bool orbtree_base<NodeAllocator,Compare,NVFunc,multi>::insert_search(const KeyType& k, NodeHandle& n, bool& insert_left) const {
595  n = root();
596  if(n == Invalid) throw std::runtime_error("orbtree_base::insert_search(): root is Invalid!\n");
597  if(get_node(n).get_right() == nil()) {
598  /* empty tree, insert as the dummy root node's right child */
599  insert_left = false;
600  return true;
601  }
602  n = get_node(n).get_right(); /* nonempty tree, start with the real root */
603  while(true) {
604  const KeyType& k1 = get_node_key(n);
605  if(c(k,k1)) {
606  /* should go to the left */
607  if(get_node(n).get_left() == nil()) { insert_left = true; return true; }
608  n = get_node(n).get_left();
609  }
610  else {
611  /* should go to the right */
612  /* first check if key exists (if not multimap / multiset) */
613  if(!multi) if(!c(k1,k)) return false;
614  if(get_node(n).get_right() == nil()) { insert_left = false; return true; }
615  n = get_node(n).get_right();
616  }
617  }
618  }
619 
620 
621  /* helper function to do the real work for insert -- insert n1 as the left / right child of n
622  * n1 must already contain the proper key / value, but can be uninitialized otherwise
623  * note: this function does not check for the correct relationship between the keys of n and n1,
624  * that is the caller's responsibility */
625  template<class NodeAllocator, class Compare, class NVFunc, bool multi>
627  if(insert_left) get_node(n).set_left(n1);
628  else get_node(n).set_right(n1);
629  get_node(n1).set_parent(n);
630  get_node(n1).set_left(nil());
631  get_node(n1).set_right(nil());
632  get_node(n1).set_red(); /* all new nodes are red */
633  NVType sum_add[f.get_nr()];
634  get_node_grvalue(n1,sum_add); /* calculate the new value */
635  this->set_node_sum(n1,sum_add);
636  /* update sum up the tree from n */
637  for(NodeHandle n2 = n; n2 != root(); n2 = get_node(n2).get_parent()) {
638  NVType tmp[f.get_nr()];
639  this->get_node_sum(n2,tmp);
640  NVAdd(tmp,sum_add);
641  this->set_node_sum(n2,tmp);
642  }
643 
644  while(true) {
645  if(n == root()) return; /* nothing to do if we just added one node to an empty tree */
646  /* here, n1 is always red */
647  /* has to fix red-black tree properties */
648  /* only possible problem is if n is red */
649  if(get_node(n).is_black()) return;
650 
651  /* if n is red, it can have a black other child (only after the first step though) */
652 
653  /* if n is the real root, we can fix the tree by coloring it black */
654  if(get_node(n).get_parent() == root()) { get_node(n).set_black(); return; }
655 
656  /* now, n has a valid, black parent and potentially a sibling */
657  if(get_sibling(n).is_red()) {
658  /* easier case, we can color n and its sibling black and n's parent red
659  * note: nil is always black, so this will only be true if n has a real sibling */
660  get_sibling(n).set_black();
661  get_node(n).set_black();
662  get_parent(n).set_red();
663  /* iteratoion has to continue to check if n's grandparent was red or black */
664  n1 = get_node(n).get_parent();
665  n = get_node(n1).get_parent();
666  }
667  else {
668  /* n has either a black sibling or no sibling -- here, we have to do rotations,
669  * which depends on whether n and n1 are on the same side */
670  if(is_left_side(n1) != is_left_side(n)) {
671  /* different side, we have to rotate around n first */
672  rotate_parent(n1);
673  NodeHandle tmp = n1;
674  n1 = n;
675  n = tmp;
676  }
677  /* now n and n1 are on the same side, we have to rotate around n's parent */
678  get_node(n).set_black();
679  get_parent(n).set_red();
680  rotate_parent(n);
681  return; /* in this case, we are done, the "top" node (in n's parent's place) is now black */
682  }
683  }
684  }
685 
686  template<class NodeAllocator, class Compare, class NVFunc, bool multi>
687  auto orbtree_base<NodeAllocator,Compare,NVFunc,multi>::insert(ValueType&& kv) -> std::pair<NodeHandle,bool> {
688  bool insert_left;
689  NodeHandle n = root();
690 
691  if(!insert_search(KeyValue::key(kv),n,insert_left)) return std::pair<NodeHandle,bool>(n,false);
692 
693  /* found a place to insert */
694  NodeHandle n1 = this->new_node(std::move(kv));
695  insert_helper(n,n1,insert_left);
696  size1++;
697  return std::pair<NodeHandle,bool>(n1,true);
698  }
699 
700  template<class NodeAllocator, class Compare, class NVFunc, bool multi>
701  auto orbtree_base<NodeAllocator,Compare,NVFunc,multi>::insert(const ValueType& kv) -> std::pair<NodeHandle,bool> {
702  bool insert_left;
703  NodeHandle n = root();
704  if(!insert_search(KeyValue::key(kv),n,insert_left)) return std::pair<NodeHandle,bool>(n,false);
705 
706  /* found a place to insert */
707  NodeHandle n1 = this->new_node(kv);
708  insert_helper(n,n1,insert_left);
709  size1++;
710  return std::pair<NodeHandle,bool>(n1,true);
711  }
712 
713  template<class NodeAllocator, class Compare, class NVFunc, bool multi>
714  bool orbtree_base<NodeAllocator,Compare,NVFunc,multi>::insert_search_hint(NodeHandle hint, const KeyType& k, NodeHandle& n, bool& insert_left) const {
715  if(c(k,get_node_key(hint))) {
716  /* k should go before hint, it might be a valid hint
717  * have to compare with previous value as well */
718  NodeHandle p = previous(hint);
719  if(!c(k,get_node_key(p))) {
720  /* p <= k < hint, might be good */
721  if(!multi) if(!c(get_node_key(p),k)) return p; /* p == k, cannot insert */
722  /* insert between p and hint
723  * note: either p does not have a right child or hint does not have a left child */
724  if(get_node(hint).get_left() == nil()) { n = hint; insert_left = true; return true; }
725  else {
726  if(get_node(p).get_right() == nil()) { n = p; insert_left = false; return true; }
727  else throw std::runtime_error("orbtree_base::insert(): inconsistent tree detected!\n");
728  }
729  }
730  /* here, hint is not good, but new element should go before it
731  * in this case, normal insert works in all cases (for multi,
732  * new element should be inserted after all elements with the same key) */
733  return insert_search(k,n,insert_left).first;
734  }
735  /* here, either hint is not good, or k == hint */
736  if(!c(get_node_key(hint),k)) {
737  if(!multi) { n = hint; return false; } /* hint == k, cannot insert */
738  if(get_node(hint).get_left() == nil()) { n = hint; insert_left = true; return true; }
739  else {
740  NodeHandle p = previous(hint);
741  if(get_node(p).get_right() != nil()) std::runtime_error("orbtree_base::insert(): inconsistent tree detected!\n");
742  n = p;
743  insert_left = false;
744  return true;
745  }
746  }
747  /* new element should go after hint, should be the first if elements with the same key already exist */
748  n = lower_bound(k);
749  if(n != nil()) { /* insert before n */
750  if(get_node(n).get_left() == nil()) { insert_left = true; return true; }
751  else {
752  NodeHandle p = previous(n);
753  if(get_node(p).get_right() != nil()) std::runtime_error("orbtree_base::insert(): inconsistent tree detected!\n");
754  n = p;
755  insert_left = false;
756  return true;
757  }
758  }
759  else {
760  n = last(); /* note: this is inefficient, as this case will require going through all levels twice (last() is O(logN) ) */
761  insert_left = false;
762  return true;
763  }
764  }
765 
766  template<class NodeAllocator, class Compare, class NVFunc, bool multi>
768  /* insert with a hint -- hint must be a valid node! */
769  NodeHandle n;
770  bool insert_left;
771  if(!insert_search_hint(hint,KeyValue::key(kv),n,insert_left)) return n; /* false means element with same key already exists in a non-multi tree */
772 
773  NodeHandle n1 = this->new_node(kv);
774  insert_helper(n,n1,insert_left);
775  size1++;
776  return n1;
777  }
778 
779 
780  template<class NodeAllocator, class Compare, class NVFunc, bool multi>
782  /* insert with a hint -- hint must be a valid node! */
783  NodeHandle n;
784  bool insert_left;
785  if(!insert_search_hint(hint,KeyValue::key(kv),n,insert_left)) return n; /* false means element with same key already exists in a non-multi tree */
786 
787  NodeHandle n1 = this->new_node(std::move(kv));
788  insert_helper(n,n1,insert_left);
789  size1++;
790  return n1;
791  }
792 
793 
794  template<class NodeAllocator, class Compare, class NVFunc, bool multi> template<class... T>
795  auto orbtree_base<NodeAllocator,Compare,NVFunc,multi>::emplace(T&&... t) -> std::pair<NodeHandle,bool> {
796  /* create a new node first, so constructor is only called once */
797  NodeHandle n1 = new_node(std::forward(t...));
798  NodeHandle n = root();
799  bool insert_left;
800  if(!insert_search(get_node_key(n1),n,insert_left)) {
801  free_node(n1,n1);
802  return std::pair<NodeHandle,bool>(n,false);
803  }
804  insert_helper(n,n1,insert_left);
805  size1++;
806  return std::pair<NodeHandle,bool>(n1,true);
807  }
808 
809  template<class NodeAllocator, class Compare, class NVFunc, bool multi> template<class... T>
811  /* create a new node first, so constructor is only called once */
812  NodeHandle n1 = new_node(std::forward(t...));
813  NodeHandle n;
814  bool insert_left;
815  if(!insert_search_hint(hint,get_node_key(n1),n,insert_left)) {
816  /* false means element with same key already exists in a non-multi tree
817  * need to delete node and return its position */
818  free_node(n1,n1);
819  return n;
820  }
821  insert_helper(n,n1,insert_left);
822  size1++;
823  return n1;
824  }
825 
826 
827  template<class NodeAllocator, class Compare, class NVFunc, bool multi>
829  /* delete node n, return a handle to its successor in the tree */
830  NodeHandle x = next(n);
831  /* if n has one child, we can delete n, replace it with one of its children
832  * if n has two children, then x has one child (we go right from n and keep going left as long as it's possible)
833  * in this case, we can cut out x, and then move it in place of n */
834  NodeHandle del = n;
835  if(get_node(n).get_left() != nil() && get_node(n).get_right() != nil()) del = x;
836 
837  /* delete del, replace it with its only child */
838  NodeHandle c = get_node(del).get_left();
839  if(c == nil()) c = get_node(del).get_right();
840  NodeHandle p = get_node(del).get_parent();
841  get_node(c).set_parent( p ); /* c can be nil here, its parent will be set anyway */
842  if(get_node(p).get_left() == del) get_node(p).set_left(c);
843  else get_node(p).set_right(c);
844 
845  /* subtract the rank function values up from del */
846  NVType x2[f.get_nr()];
847  get_node_grvalue(del,x2);
848  for(NodeHandle p2 = p; p2 != root(); p2 = get_node(p2).get_parent()) {
849  NVType y[f.get_nr()];
850  this->get_node_sum(p2,y);
851  NVSubtract(y,x2);
852  this->set_node_sum(p2,y);
853  }
854 
855  /* cut out del, we need to fix the tree properties */
856  /* cases:
857  * 1. del is black, c is red -> color c black
858  * 2. del is red, c is black -> no need to do anything
859  * 3. del is black, c is nil -> one less black on del's path, need to fix it
860  */
861  if(get_node(del).is_black()) {
862  if(c != nil()) {
863  get_node(c).set_black();
864  }
865  else {
866  /* here, del is black -- in this case, it must have a valid sibling */
867  while(true) {
868  NodeHandle s = get_node(p).get_left();
869  if(s == nil() || s == c) s = get_node(p).get_right();
870  if(s == nil() || s == c) throw std::runtime_error("orbtree_base::erase(): found black node with no sibling!\n");
871 
872  if(get_node(s).is_red()) {
873  /* p is black */
874  /* recolor p as red, s as black, do a rotation on p and continue from there */
875  get_node(p).set_red();
876  get_node(s).set_black();
877  rotate_parent(s);
878  continue; /* continue with the same p, which is now red and its other child is black */
879  }
880  /* here, s is black, p can be black or red */
881  if(get_left(s).is_black() && get_right(s).is_black()) {
882  /* two black children (or nil) */
883  /* we can color s red and fix things on upper level */
884  get_node(s).set_red();
885  /* if parent is red, we can fix the tree by coloring it black and s red */
886  if(get_node(p).is_red()) {
887  get_node(p).set_black();
888  break;
889  }
890  /* if p was black, we have to continue one level up */
891  c = p;
892  p = get_node(p).get_parent();
893  if(p == root()) break;
894  continue;
895  }
896  /* here, s is black and at least one child of it is red
897  * if it is on the other side as s, then we need to rotate s,
898  * so that the red child is on the same side */
899  if(s == get_node(p).get_right() && get_right(s).is_black()) {
900  /* s is right child, but left child of s is red, rotate right */
901  get_node(s).set_red();
902  get_left(s).set_black();
903  rotate_right(s);
904  continue; /* re-assign s at the top of the loop -- p did not change */
905  }
906  /* previous condition reversed */
907  if(s == get_node(p).get_left() && get_left(s).is_black()) {
908  /* s is left child, but right child of s is red, rotate left */
909  get_node(s).set_red();
910  get_right(s).set_black();
911  rotate_left(s);
912  continue;
913  }
914 
915  /* here s is black and has a red child on the same side as s
916  * in this case, the tree can be fixed by rotating s into p's position */
917  if(get_node(p).is_red()) get_node(s).set_red();
918  get_node(p).set_black();
919  if(s == get_node(p).get_right()) get_right(s).set_black();
920  else get_left(s).set_black();
921  rotate_parent(s);
922  break;
923  }
924 
925 
926  } /* else (c is nil) */
927  } /* if del is black -- need to fix the tree */
928 
929  if(del != n) {
930  /* x (n's successor) was deleted, have to put x in n's place
931  * in this case, x cannot be nil */
932  get_node(x).set_left( get_node(n).get_left() );
933  get_node(x).set_right( get_node(n).get_right() );
934  get_node(x).set_parent( get_node(n).get_parent() );
935  if(get_node(n).is_black()) get_node(x).set_black();
936  else get_node(x).set_red();
937  if(get_parent(n).get_left() == n) get_parent(n).set_left(x);
938  else {
939  if(get_parent(n).get_right() == n) get_parent(n).set_right(x);
940  else throw std::runtime_error("orbtree_base::erase(): inconsistent tree detected!\n");
941  }
942  if(get_node(x).get_left() != nil()) get_left(x).set_parent(x);
943  if(get_node(x).get_right() != nil()) get_right(x).set_parent(x);
944 
945  /* fix sums */
946  update_sum_r(x);
947  }
948  /* delete node of n -- need to give x as well as its value can potentially change */
949  this->free_node(n);
950  if(!size1) throw std::runtime_error("size1 is zero in orbtree_base::erase!\n");
951  size1--;
952  return x; /* return the successor -- it can be nil if n was the largest node */
953  }
954 
955  template<class NodeAllocator, class Compare, class NVFunc, bool multi>
957  unsigned int nr = f.get_nr();
958 
959  if(std::is_integral<NVType>::value) {
960  /* for integer types -- check for overflow */
961  NVType max = std::numeric_limits<NVType>::max();
962  NVType min = std::numeric_limits<NVType>::min();
963  for(unsigned int i = 0;i<nr;i++) {
964  if(y[i] > 0) {
965  if(max - y[i] < x[i]) throw std::runtime_error("orbtree_base::NVAdd(): overflow!\n");
966  }
967  else {
968  if(min - y[i] > x[i]) throw std::runtime_error("orbtree_base::NVAdd(): underflow!\n");
969  }
970  x[i] += y[i];
971  }
972  }
973  else {
974  /* TODO: overflow / rounding check for floats? */
975  for(unsigned int i=0;i<nr;i++) x[i] += y[i];
976  }
977  }
978 
979  template<class NodeAllocator, class Compare, class NVFunc, bool multi>
981  unsigned int nr = f.get_nr();
982 
983  if(std::is_integral<NVType>::value) {
984  /* for integer types -- check for overflow */
985  NVType max = std::numeric_limits<NVType>::max();
986  NVType min = std::numeric_limits<NVType>::min();
987  for(unsigned int i = 0;i<nr;i++) {
988  if(y[i] > 0) {
989  if(min + y[i] > x[i]) throw std::runtime_error("orbtree_base::NVSubtract(): underflow!\n");
990  }
991  else {
992  if(max + y[i] < x[i]) throw std::runtime_error("orbtree_base::NVSubtract(): overflow!\n");
993  }
994  x[i] -= y[i];
995  }
996  }
997  else {
998  /* TODO: overflow / rounding check for floats? */
999  for(unsigned int i=0;i<nr;i++) x[i] -= y[i];
1000  }
1001  }
1002 
1003  template<class NodeAllocator, class Compare, class NVFunc, bool multi>
1005  //~ if(size1 + 2 != this->size) throw std::runtime_error("orbtree_base::check_tree(): inconsistent tree size!\n");
1006  const Node& r = get_node(root());
1007  if(r.get_left() != nil() || r.get_parent() != nil()) throw std::runtime_error("orbtree_base::check_tree(): root is invalid!\n");
1008  NodeHandle x = r.get_right();
1009  if(x == nil()) return; /* empty tree nothing more to do */
1010  if(x == this->Invalid) throw std::runtime_error("orbtree_base::check_tree(): invalid node handle found!\n");
1011  if(get_node(x).get_parent() != root()) throw std::runtime_error("orbtree_base::check_tree(): inconsistent root node!\n");
1012 
1013  size_t previous_black_count = (size_t)-1;
1014  check_tree_r(epsilon,x,0,previous_black_count);
1015 
1016  }
1017 
1018  /* recursive helper function to check tree
1019  * this function checks:
1020  * -- if node x has any children, then they are consistent (i.e. have x as parent, keys are ordered properly)
1021  * -- for red x, both children have to be black or nil
1022  * -- if nil is reached, black_count has to be the same as previous_black_count
1023  * -- if epsilon >= 0.0, then than the rank function value stored in x is equal to the sum of its children + x's value
1024  * -- recurses into both children, increasing black_count if x is black
1025  * as tree height for N elements is maximum 2*log_2(N), this will not result in stack overflow
1026  * (e.g. N <~ 2^40 on a machine with few hundred GB RAM, thus tree height <~ 80, which is reasonable for recursion depth)
1027  */
1028  template<class NodeAllocator, class Compare, class NVFunc, bool multi>
1029  void orbtree_base<NodeAllocator,Compare,NVFunc,multi>::check_tree_r(double epsilon, NodeHandle x, size_t black_count, size_t& previous_black_count) const {
1030  NodeHandle l = get_node(x).get_left();
1031  NodeHandle r = get_node(x).get_right();
1032 
1033  { /* scope for sum and tmp -- no need to keep them over the recursion */
1034  NVType sum[f.get_nr()];
1035  NVType tmp[f.get_nr()];
1036 
1037  if(epsilon >= 0.0) get_node_grvalue(x,sum);
1038 
1039  if(l != nil()) {
1040  /* check if x is l's parent */
1041  if(get_node(l).get_parent() != x) throw std::runtime_error("orbtree_base::check_tree(): inconsistent node!\n");
1042  /* check that red node does not have red child */
1043  if(get_node(x).is_red() && get_node(l).is_red()) throw std::runtime_error("orbtree_base::check_tree(): inconsistent node (red parent with red child)!\n");
1044  /* check that l's key is strictly smaller than x's */
1045  if( ! c(get_node_key(l),get_node_key(x)) ) {
1046  if( !multi || c(get_node_key(x),get_node_key(l)) ) throw std::runtime_error("orbtree_base::check_tree(): inconsistent ordering!\n");
1047  }
1048  /* add l's partial sum to x's value */
1049  if(epsilon >= 0.0) {
1050  this->get_node_sum(l,tmp);
1051  NVAdd(sum,tmp);
1052  }
1053  }
1054 
1055  if(r != nil()) {
1056  /* check if x is r's parent */
1057  if(get_node(r).get_parent() != x) throw std::runtime_error("orbtree_base::check_tree(): inconsistent node!\n");
1058  /* check that red node does not have red child */
1059  if(get_node(x).is_red() && get_node(r).is_red()) throw std::runtime_error("orbtree_base::check_tree(): inconsistent node (red parent with red child)!\n");
1060  /* check that r's key is larger than x's or equal to it (if multiset / multimap) */
1061  if( c(get_node_key(r),get_node_key(x)) ) throw std::runtime_error("orbtree_base::check_tree(): inconsistent ordering!\n");
1062  if( !multi && ! c(get_node_key(x),get_node_key(r)) ) throw std::runtime_error("orbtree_base::check_tree(): non-unique key found!\n");
1063 
1064  /* add r's partial sum to x's value */
1065  if(epsilon >= 0.0) {
1066  this->get_node_sum(r,tmp);
1067  NVAdd(sum,tmp);
1068  }
1069  }
1070 
1071  if(epsilon >= 0.0) {
1072  /* check that the partial sum stored in x is consistent */
1073  this->get_node_sum(x,tmp);
1074 
1075  /* if NVType is integral, we want exact match -- otherwise, we use epsilon for comparison */
1076  if(std::is_integral<NVType>::value) { for(unsigned int i=0;i<f.get_nr();i++) if(tmp[i] != sum[i])
1077  throw std::runtime_error("orbtree_base::check_tree(): partial sums are inconsistent!\n"); }
1078  else for(unsigned int i=0;i<f.get_nr();i++) if(fabs(tmp[i]-sum[i]) > epsilon)
1079  throw std::runtime_error("orbtree_base::check_tree(): partial sums are inconsistent!\n");
1080  }
1081  }
1082 
1083  /* increase black count for recursion */
1084  if(get_node(x).is_black()) black_count++;
1085  if(r == nil() || l == nil()) {
1086  /* l or r is nil, check if black_count is same as previously */
1087  if(previous_black_count == (size_t)-1) previous_black_count = black_count;
1088  else if(previous_black_count != black_count) throw std::runtime_error("orbtree_base::check_tree(): inconsistent node (black conut differs)!\n");
1089  }
1090 
1091  /* recurse into both children (if not nil) */
1092  if(l != nil()) check_tree_r(epsilon,l,black_count,previous_black_count);
1093  if(r != nil()) check_tree_r(epsilon,r,black_count,previous_black_count);
1094  }
1095 
1096 
1097 } // namespace orbtree
1098 
1099 #endif
1100 
auto upper_bound(const K &key) const -> NodeHandle
find the first node larger than the given key – returns nil if none found
Definition: orbtree_base.h:367
NodeHandle nil() const
handle of nil sentinel
Definition: orbtree_base.h:110
auto lower_bound(const K &key) const -> NodeHandle
find the first node not less than the given key – returns nil if none found
Definition: orbtree_base.h:347
void update_value(NodeHandle n, typename KeyValue_::MappedType const &v)
update value in a node – only if this is a map; update sum recursively based on it as well ...
Definition: orbtree_base.h:273
Node & get_right(NodeHandle n)
convenience helper to get node object that is the right child of the given node handle ...
Definition: orbtree_base.h:246
Definition: orbtree_base.h:42
const KeyType & get_node_key(NodeHandle n) const
convenience function to get the key of a node
Definition: orbtree_base.h:214
Node & get_parent(NodeHandle n)
convenience helper to get node object that is the parent of the given node handle ...
Definition: orbtree_base.h:250
void rotate_right(NodeHandle x)
right rotate
Definition: orbtree_base.h:566
const Node & get_right(NodeHandle n) const
convenience helper to get node object that is the right child of the given node handle ...
Definition: orbtree_base.h:248
NodeHandle emplace_hint(NodeHandle hint, T &&... t)
Construct new element in place with hint.
void rotate_left(NodeHandle x)
left rotate
Definition: orbtree_base.h:547
void clear()
erase all nodes
Definition: orbtree_base.h:302
std::pair< NodeHandle, bool > emplace(T &&... t)
Construct new element in place.
NodeAllocator::Node Node
node objects
Definition: orbtree_base.h:66
void get_sum_fv_node(NodeHandle x, NVType *res) const
get the generalized rank for a given node, i.e. the sum of NVFunv for all nodes before it in order ...
Definition: orbtree_base.h:419
NodeHandle previous(NodeHandle n) const
get node before n (or nil) – note: previous(nil) == last() to make it easier to implement end() iter...
Definition: orbtree_base.h:502
const Node & get_parent(NodeHandle n) const
convenience helper to get node object that is the parent of the given node handle ...
Definition: orbtree_base.h:252
void check_tree(double epsilon=-1.0) const
check that the tree is valid
Definition: orbtree_base.h:1004
auto find(const K &key) const -> NodeHandle
find any node with the given key
Definition: orbtree_base.h:328
NodeHandle last() const
get last node (or nil)
Definition: orbtree_base.h:475
void update_sum(NodeHandle n)
update the sum only inside n
Definition: orbtree_base.h:525
bool compare_key_equals(NodeHandle n, const KeyType &k) const
helper for erase to compare elements
Definition: orbtree_base.h:217
void rotate_parent(NodeHandle x)
rotate by parent of x (x takes parent&#39;s place), this calls either rotate_left() or rotate_right() wit...
Definition: orbtree_base.h:584
void get_node_grvalue(NodeHandle n, NVType *res) const
get the value of NVFunc for the given node
Definition: orbtree_base.h:227
void update_value(NodeHandle n, typename KeyValue_::MappedType &&v)
update value in a node – only if this is a map; update sum recursively based on it as well ...
Definition: orbtree_base.h:280
size_t size1
keep track of the number of inserted elements
Definition: orbtree_base.h:85
const Node & get_sibling(NodeHandle n) const
convenience helper to get the node object of a node&#39;s sibling (i.e. parent&#39;s other child) ...
Definition: orbtree_base.h:261
const Key & key() const
access key – only const access is possible, key should not change
Definition: orbtree_node.h:123
void update_sum_r(NodeHandle n)
update the sum recursively up the tree
Definition: orbtree_base.h:268
void get_sum_fv(const K &k, NVType *res) const
get the generalized rank for a key, i.e. the sum of NVFunc for all nodes with node.key < k
Definition: orbtree_base.h:388
NodeHandle erase(NodeHandle n)
remove the given node – return the next node (i.e. next(n) before deleting n)
Definition: orbtree_base.h:828
std::pair< NodeHandle, bool > insert(ValueType &&kv)
Insert new element.
Definition: orbtree_base.h:687
void NVSubtract(NVType *x, const NVType *y) const
function to subtract NVType values; checks for overflow and throws exception in the case of integral ...
Definition: orbtree_base.h:980
Definition: orbtree.h:55
base class for both map and set – should not be used directly
Definition: orbtree_base.h:63
bool is_left_side(NodeHandle n) const
check which side child is n (i.e. returns true if n is the left child of its parent) – requires that...
Definition: orbtree_base.h:263
NodeHandle next(NodeHandle n) const
get node after n (or nil) – note: next(nil) == nil
Definition: orbtree_base.h:484
NodeHandle get_sibling_handle(NodeHandle n) const
convenience helper to get the handle of a node&#39;s sibling (i.e. parent&#39;s other child) ...
Definition: orbtree_base.h:254
bool insert_search(const KeyType &k, NodeHandle &n, bool &insert_left) const
helper for insert – find the location where to insert
Definition: orbtree_base.h:594
const Node & get_left(NodeHandle n) const
convenience helper to get node object that is the left child of the given node handle ...
Definition: orbtree_base.h:244
void insert_helper(NodeHandle n, NodeHandle n1, bool insert_left)
helper function to do the real work for insert
Definition: orbtree_base.h:626
NodeHandle first() const
get first node (or nil)
Definition: orbtree_base.h:466
void check_tree_r(double epsilon, NodeHandle x, size_t black_count, size_t &previous_black_count) const
recursive helper for check_tree(double)
Definition: orbtree_base.h:1029
Node & get_sibling(NodeHandle n)
convenience helper to get the node object of a node&#39;s sibling (i.e. parent&#39;s other child) ...
Definition: orbtree_base.h:259
NodeAllocator::NVType NVType
Type the function NVFunc returns.
Definition: orbtree_base.h:76
void NVAdd(NVType *x, const NVType *y) const
function to add NVType values; checks for overflow and throws exception in the case of integral types...
Definition: orbtree_base.h:956
Node & get_node(NodeHandle n)
convenience function that returns node object for a node handle
Definition: orbtree_base.h:104
const Node & get_node(NodeHandle n) const
convenience function that returns node object for a node handle
Definition: orbtree_base.h:106
void get_norm_fv(NVType *res) const
get the normalization factor, i.e. the sum of all keys
Definition: orbtree_base.h:452
NodeHandle root() const
handle of root sentinel
Definition: orbtree_base.h:108
NodeAllocator::NodeHandle NodeHandle
handle to refer nodes to (pointer or integer)
Definition: orbtree_base.h:71
bool insert_search_hint(NodeHandle hint, const KeyType &k, NodeHandle &n, bool &insert_left) const
helper for insert – find the location where to insert
Definition: orbtree_base.h:714
Node & get_left(NodeHandle n)
convenience helper to get node object that is the left child of the given node handle ...
Definition: orbtree_base.h:242