KJB
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
redblack.h
Go to the documentation of this file.
1 
15 /*
16  * $Id: redblack.h 18227 2014-11-14 19:00:04Z predoehl $
17  */
18 
19 #ifndef REDBLACK_H_PREDOEHL_12_DEC_2011_VISION
20 #define REDBLACK_H_PREDOEHL_12_DEC_2011_VISION 1
21 
22 #include <l/l_sys_lib.h>
23 #include <l/l_sys_io.h>
24 #include <l/l_debug.h>
25 #include <l_cpp/l_util.h>
26 
27 #ifdef DEBUGGING
28 #include <sstream>
29 #include <map> /* oh the irony */
30 #endif
31 
32 #include <qd_cpp/diprique.h>
33 
34 #include <iosfwd> /* std::ostream */
35 #include <algorithm> /* std::sort and several others */
36 #include <numeric> /* std::accumulate */
37 #include <limits> /* std::numeric_limits */
38 #include <new>
39 #include <iterator>
40 
42 #define REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY 1
43 
44 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
45 /* Implement location list in a std::vector. */
46 #include <vector>
47 #else
48 /* Implement location list in a std::map. */
49 #include <map>
50 #endif
51 
52 namespace kjb
53 {
54 namespace qd
55 {
56 
57 
164 template < typename SATELLITE_TYPE >
166 : public DijkstraPriorityQueue< SATELLITE_TYPE >
167 {
168 public:
169  typedef SATELLITE_TYPE Sat_tp;
172 
173 private:
174  enum
175  {
176  VERBOSE = 0,
177  TREE_THRESH = 7,
178  BLACKHEIGHT_BAD = -1,
179  LOCATOR_BASE = 987000
180  };
181 
182 #ifdef DEBUGGING
183  typedef std::map< Loc_tp, char > LocCensus_tp;
185 #endif
186 
188  struct Node
189  {
190  Key_tp key,
191  sum;
192  Sat_tp sat;
193  Loc_tp locator;
194  Node *left,
195  *right,
196  *parent;
197  bool is_black;
198 
200  Node()
201  {}
202 
204  Node(
205  const Key_tp& kk,
206  const Sat_tp& ss,
207  bool bk,
208  Node* ll,
209  Node* rr,
210  Loc_tp loc
211  )
212  : key( kk ),
213  sum( kk ),
214  sat( ss ),
215  locator( loc ),
216  left( ll ),
217  right( rr ),
218  parent( 00 ),
219  is_black( bk )
220  {}
221 
223  bool is_red() const
224  {
225  return ! is_black;
226  }
227 
229  bool operator<( const Node& other ) const
230  {
231  return key < other.key;
232  }
233 
235  void update_sum()
236  {
237  KJB(ASSERT( left && right ));
238  sum = key + left -> sum + right -> sum;
239  }
240 
242  void you_are_my_child( Node* child, Node* Node::* branch )
243  {
244  KJB(ASSERT( child ));
245  this ->* branch = child;
246  child -> parent = this;
247  }
248 
250  void link_left_child( Node* child )
251  {
252  you_are_my_child( child, & Node::left );
253  }
254 
256  void link_right_child( Node* child )
257  {
258  you_are_my_child( child, & Node::right );
259  }
260  };
261 
263  struct AddKey
264  {
266  Key_tp operator()( const Key_tp& a, const Node& n ) { return a+n.key; }
267  };
268 
269 
283  Node m_nil;
284 
286  Node *root;
287 
289  unsigned m_size;
290 
309 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
310  std::vector< Node* > location_list;
311 #else
312  typedef std::map< Loc_tp, Node* > LocationList;
313  typedef typename LocationList::const_iterator LLCI;
314 
315  LocationList location_list;
316 #endif
317 
318 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
319  std::vector< Loc_tp > free_locator_list;
321 #endif
322 
323 #ifdef DEBUGGING
324  void chatter( const char* s ) const
326  {
327  if ( VERBOSE ) KJB(TEST_PSE(( "CHATTER: %s\n", s )));
328  }
329 
331  void enter( const char* s ) const
332  {
333  if ( VERBOSE ) KJB(TEST_PSE(( "CHATTER: Entering %s\n", s )));
334  }
335 
337  bool fail( const char *s ) const
338  {
339  chatter( s );
340  return false;
341  }
342 
344  bool fail( int nnn ) const
345  {
346  KJB(TEST_PSE(( "FAIL: line %d\n", nnn )));
347  return false;
348  }
349 
350 #else
351  void chatter( const char* ) const {}
353 
355  void enter( const char* ) const {}
356 
358  bool fail( const char* ) const { return false; }
359 
361  bool fail( int ) const { return false; }
362 #endif
363 
364 
365 
367  Loc_tp obtain_avail_locator()
368  {
369 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
370  Loc_tp nuloc = location_list.size();
371 
372  if ( free_locator_list.size() )
373  {
374  // we can recycle an old one! good!
375  nuloc = free_locator_list.back();
376  free_locator_list.pop_back();
377  }
378  else
379  {
380  location_list.push_back( 00 );
381  }
382 
383  return nuloc;
384 #else
385  if (location_list.empty()) return 0;
386 
387  LLCI i = location_list.end();
388  --i;
389  return 1 + i -> first;
390 #endif
391  }
392 
393 
394 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
395 
403  void opportunistic_cleanup_of_idle_locators()
404  {
405  while ( location_list.size()
406  && 00 == location_list.back()
407  && free_locator_list.size()
408  && 1 + free_locator_list.back() == location_list.size()
409  )
410  {
411  location_list.pop_back();
412  free_locator_list.pop_back();
413  }
414  }
415 #endif
416 
418  void release_locator( Loc_tp loc )
419  {
420 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
421  KJB(ASSERT( loc < location_list.size() ));
422 
423  // also could test whether loc is in free list (shouldn't be)
424  free_locator_list.push_back( loc );
425  location_list[ loc ] = 00;
426 
427  // if location_list has A LOT of null entries, try to collapse them.
428  if ( free_locator_list.size() & ~0xFFF // more than 4095 nulls,
429  && size() < free_locator_list.size()>>3 // more than 87% nulls,
430  && 00 == location_list.back() // last entry is null.
431  )
432  {
433  std::sort(free_locator_list.begin(), free_locator_list.end());
434  opportunistic_cleanup_of_idle_locators();
435 
436  /*
437  * To encourage the use of low-value locators, put them toward the
438  * end of the free_locator_list, because we draw off the back.
439  */
440  std::reverse(free_locator_list.begin(), free_locator_list.end());
441  }
442 #else
443 #ifdef DEBUGGING
444  const size_t count =
445 #endif
446  location_list.erase(loc);
447  KJB(ASSERT(1 == count));
448 #endif
449  }
450 
451 
453  Node* new_node( const Key_tp& key, const Sat_tp& sat, bool black )
454  {
455  const Loc_tp nuloc = obtain_avail_locator();
456  Node* nn = new Node( key, sat, black, & m_nil, & m_nil, nuloc );
457 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
458  KJB(ASSERT( nuloc < location_list.size() ));
459  KJB(ASSERT( 00 == location_list.at( nuloc ) ));
460 #endif
461  KJB(ASSERT( nuloc == nn -> locator ));
462  location_list[ nuloc ] = nn;
463  return nn;
464  }
465 
466 
468  Node* new_node( const Node& old_node )
469  {
470  return new_node( old_node.key, old_node.sat, old_node.is_black );
471  }
472 
473 
475  bool loc_list_good_here( const Node* ppp ) const
476  {
477 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
478  return ppp && location_list.at( ppp -> locator ) == ppp;
479 #else
480  if (00 == ppp) return false;
481  LLCI i = location_list.find( ppp -> locator );
482  return i != location_list.end() && i -> second == ppp;
483 #endif
484  }
485 
486 
488  void dispose( Node* ppp )
489  {
490  KJB(ASSERT( ppp ));
491  KJB(ASSERT( loc_list_good_here( ppp ) ));
492  const Loc_tp ploc = ppp -> locator;
493 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
494  KJB(ASSERT( location_list.at( ploc ) == ppp ));
495 #else
496  KJB(ASSERT( location_list[ ploc ] == ppp ));
497 #endif
498  release_locator( ploc );
499  delete ppp;
500  }
501 
502 
504  bool is_nil( const Node* ppp ) const
505  {
506  return ppp == & m_nil;
507  }
508 
509 
511  bool is_not_nil( const Node* ppp ) const
512  {
513  return ppp != & m_nil;
514  }
515 
516 
518  bool are_both_children_nil( const Node* ppp ) const
519  {
520  return ppp
521  && is_not_nil( ppp )
522  && is_nil( ppp -> left )
523  && is_nil( ppp -> right );
524  }
525 
526 
533  int blackheight_in_linear_time( const Node* ppp ) const
534  {
535  KJB(ASSERT( ppp ));
536  if ( is_nil( ppp ) )
537  {
538  return 1; // because nil is black
539  }
540 
541  int bh = blackheight_in_linear_time( ppp -> left );
542 
543  if ( bh != BLACKHEIGHT_BAD
544  && bh == blackheight_in_linear_time( ppp -> right )
545  )
546  {
547  return bh + ( ppp -> is_black ? 1 : 0 );
548  }
549 
550  return BLACKHEIGHT_BAD;
551  }
552 
553 
560  void recursive_destroy( Node* ppp )
561  {
562  if ( ppp && is_not_nil( ppp ) )
563  {
564  recursive_destroy( ppp -> left );
565  recursive_destroy( ppp -> right );
566  dispose( ppp );
567  }
568  }
569 
570 
572  void make_it_a_real_tree_now()
573  {
574 #ifdef DEBUGGING
575  enter( __func__ );
576 #endif
577  std::sort( root, root + TREE_THRESH );
578  Node sorty[ TREE_THRESH ];
579  std::copy( root, root + TREE_THRESH, sorty );
580  delete[] root;
581 
582  // build tree (unfortunately, this inserts fresh, unwanted locators)
583  KJB(ASSERT( 7 == TREE_THRESH ));
584  root = new_node( sorty[ 3 ] );
585  root -> link_left_child( new_node( sorty[ 1 ] ) );
586  root -> link_right_child( new_node( sorty[ 5 ] ) );
587  root -> left -> link_left_child( new_node( sorty[ 0 ] ) );
588  root -> left -> link_right_child( new_node( sorty[ 2 ] ) );
589  root -> right -> link_left_child( new_node( sorty[ 4 ] ) );
590  root -> right -> link_right_child( new_node( sorty[ 6 ] ) );
591  root -> parent = m_nil.parent = 00;
592 
593  // unfortunately that little tree is now full of unwanted locators
594 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
595  release_locator( root -> locator );
596  release_locator( root -> left -> locator );
597  release_locator( root -> right -> locator );
598  release_locator( root -> left -> left -> locator );
599  release_locator( root -> left -> right -> locator );
600  release_locator( root -> right -> left -> locator );
601  release_locator( root -> right -> right -> locator );
602 #else
603  location_list.clear();
604 #endif
605 
606  // fix the location_list
607  location_list[ sorty[ 3 ].locator ] = root;
608  location_list[ sorty[ 1 ].locator ] = root -> left;
609  location_list[ sorty[ 5 ].locator ] = root -> right;
610  location_list[ sorty[ 0 ].locator ] = root -> left -> left;
611  location_list[ sorty[ 2 ].locator ] = root -> left -> right;
612  location_list[ sorty[ 4 ].locator ] = root -> right -> left;
613  location_list[ sorty[ 6 ].locator ] = root -> right -> right;
614 
615  // fix the tree's embedded locator indices
616  root -> locator = sorty[ 3 ].locator;
617  root -> left -> locator = sorty[ 1 ].locator;
618  root -> right -> locator = sorty[ 5 ].locator;
619  root -> left -> left -> locator = sorty[ 0 ].locator;
620  root -> left -> right -> locator = sorty[ 2 ].locator;
621  root -> right -> left -> locator = sorty[ 4 ].locator;
622  root -> right -> right -> locator = sorty[ 6 ].locator;
623 
624 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
625  // discard idle locators (loops just TREE_THRESH times)
626  opportunistic_cleanup_of_idle_locators();
627 #endif
628 
629  // update the sums
630  KJB(ASSERT( 7 == TREE_THRESH ));
631  root -> left -> update_sum();
632  root -> right -> update_sum();
633  root -> update_sum();
634  }
635 
636 
637 
638 
665  int insert_parent( Node** toparent, bool pn_left, Node* n00b )
666  {
667  KJB(ASSERT( n00b && toparent && *toparent ));
668  Node* parent = *toparent;
669 
670  Node* Node::* branch = pn_left ? & Node::left : & Node::right;
671  if ( is_nil( parent ->* branch ) )
672  {
673  KJB(ASSERT( n00b -> is_red() ));
674  parent -> you_are_my_child( n00b, branch );
675  parent -> sum += n00b -> sum;
676  return 1; // red child at depth 2 in subtree rooted at gramp
677  }
678  else
679  {
680 #ifdef DEBUGGING
681  int rc = insert_gp( toparent, pn_left, n00b );
682  /*
683  * If rc is zero, that is fine: it means no-red-red is satisfied.
684  * If rc is 2 or 4, we can handle it: it means no-red-red might
685  * be unsatisfied, but
686  */
687  KJB(ASSERT( 0 == rc || 2 == rc || 4 == rc ));
688  KJB(ASSERT( rc != 2 || ( parent ->* branch ) -> is_red() ));
689  KJB(ASSERT( rc != 4 || parent -> is_red() ));
690 
691  /*
692  * Shift that return value downwards, because it describes the tree
693  * status for a deeper context, but we want to return the tree
694  * status for the current context.
695  */
696  return rc >> 1;
697 #else
698  return insert_gp( toparent, pn_left, n00b ) >> 1;
699 #endif
700  }
701  }
702 
703 
742  int insert_gp( Node** togramp, bool gp_left, Node* n00b )
743  {
744  KJB(ASSERT( n00b && togramp && *togramp ));
745 
746  Node *gramp = *togramp,
747  **toparent = gp_left ? & gramp -> left : & gramp -> right;
748 
749  gramp -> sum += n00b -> sum;
750 
751  KJB(ASSERT( toparent ));
752  Node *parent = *toparent;
753 
754  KJB(ASSERT( parent ));
755  bool pn_left = *n00b < *parent;
756 
757  /*
758  * The semantics of the value in rc and of the value returned by this
759  * function are the same. This is important, pay attention!
760  *
761  * rc tells us about a red node that might be the child of a red node,
762  * i.e., a potential violation of the @ref redblacki2.
763  * The possible values are in the set {0, 1, 2}.
764  *
765  * If 0==rc, then the invariant is satisfied in this subtree.
766  * If 1==rc, then new node n00b is red; must check *parent.
767  * If 2==rc, then *parent is newly painted red; must check *gramp.
768  *
769  * In like wise, the value 4 would indicate *gramp is newly painted
770  * red (see below). Thus the value in rc and the return value below
771  * have consistent semantics.
772  */
773  int rc = insert_parent( toparent, pn_left, n00b );
774  KJB(ASSERT( 0 == rc || 1 == rc || 2 == rc ));
775 
776  /*
777  * The return value below is in the set {0, 2, 4}.
778  * Values 0 and 2 have the same semantics as 'rc' above.
779  * Value 4 means *gramp is newly painted red and the caller must
780  * check its parent.
781  */
782  return rb_balance( togramp, gp_left, pn_left, rc );
783  }
784 
785 
787  Node* Node::* opposite_direction( Node* Node::* some_direction ) const
788  {
789  return some_direction == & Node::left ? & Node::right : & Node::left;
790  }
791 
792 
829  void unzigzag( Node* gramp, Node* Node::* p_branch )
830  {
831  Node* Node::* u_branch = opposite_direction( p_branch );//towards uncle
832 
833  KJB(ASSERT( gramp ));
834  KJB(ASSERT( is_not_nil( gramp ->* p_branch ) ));
835  KJB(ASSERT( is_not_nil( gramp ->* p_branch ->* u_branch ) ));
836 
837  Node *oldparent = gramp ->* p_branch,
838  *oldchild = oldparent ->* u_branch,
839  *med_tree = oldchild ->* p_branch; // could be nil
840 
841  gramp -> you_are_my_child( oldchild, p_branch );
842  oldchild -> you_are_my_child( oldparent, p_branch );
843 
844  oldparent ->* u_branch = med_tree;
845  if ( is_not_nil( med_tree ) )
846  {
847  med_tree -> parent = oldparent;
848  }
849 
850  /*
851  * Now "oldparent" is the child of "oldchild" -- it's freaky friday.
852  */
853  oldparent -> update_sum();
854  oldchild -> update_sum();
855  }
856 
857 
897  void rotate( Node** togramp, Node* Node::* p_branch )
898  {
899  KJB(ASSERT( togramp && *togramp ));
900 
901  Node* Node::* u_branch = opposite_direction( p_branch ); // to uncle
902  Node* oldgramp = *togramp;
903 
904  KJB(ASSERT( is_not_nil( oldgramp ) ));
905  KJB(ASSERT( is_not_nil( oldgramp ->* p_branch ) ));
906 
907  Node *oldparent = oldgramp ->* p_branch,
908  *medmed_tree = oldparent ->* u_branch;
909 
910  KJB(ASSERT( oldparent -> parent == oldgramp ));
911 
912  // rotate the descendant relationships
913  *togramp = oldparent;
914 
915  // update the ancestor relationships
916  oldparent -> parent = oldgramp -> parent;
917  oldparent -> you_are_my_child( oldgramp, u_branch );
918 
919  oldgramp ->* p_branch = medmed_tree;
920  if ( is_not_nil( medmed_tree ) )
921  {
922  medmed_tree -> parent = oldgramp;
923  }
924 
925  /*
926  * Now "oldparent" and "oldgramp" have swapped parent-child statuses.
927  * Also they have to swap colors.
928  * The former sibling of "oldparent" is still the child of "oldgramp"
929  * and so it is now become a grandchild of "oldparent." IF ANY.
930  */
931  std::swap( oldgramp -> is_black, oldparent -> is_black );
932 
933  oldgramp -> update_sum();
934  oldparent -> update_sum();
935  }
936 
937 
966  int rb_balance( Node** togramp, bool gp_left, bool pn_left, int red_child )
967  {
968  /*
969  * On input, red_child is...
970  * 3 if n00b is newly red and that fact must be handled.
971  * 2 if parent is newly red and that fact must be handled.
972  * 1 if gramp is newly red and that fact must be handled.
973  * 0 if no one's redness must be handled.
974  */
975  if ( red_child != 1 )
976  {
977  return red_child;
978  }
979 
980  KJB(ASSERT( togramp && *togramp ));
981 
982  Node* Node::* gp_branch = gp_left ? & Node::left : & Node::right;
983 
984  Node *gramp = *togramp,
985  *parent = gramp ->* gp_branch,
986  *uncle = gramp ->* opposite_direction( gp_branch );
987 
988  KJB(ASSERT( parent ));
989  if ( parent -> is_black )
990  {
991  return 0; // if parent is black then a red child is not a problem
992  }
993  KJB(ASSERT( gramp -> is_black )); //parent and gramp cannot both be red
994 
995  if ( uncle -> is_black ) // also, uncle could be "nil" (black).
996  {
997  // unzigzag, if necessary
998  if ( gp_left != pn_left )
999  {
1000  unzigzag( gramp, gp_branch );
1001  }
1002  // rotate like alexander the great
1003  rotate( togramp, gp_branch );
1004  KJB(ASSERT( 00 == m_nil.parent ));
1005  return 0;
1006  }
1007 
1008  KJB(ASSERT( is_not_nil( uncle ) ));
1009  uncle -> is_black = parent -> is_black = true;
1010  gramp -> is_black = false;
1011  return 1 << 2; // now gramp is a red child 2 levels higher
1012  }
1013 
1014 
1015 #ifdef DEBUGGING
1016  void dbp_indent( int depth, std::ostream& os ) const
1018  {
1019  static const char* INDENT = "\t";
1020  for ( int iii = 0; iii < depth; ++iii )
1021  {
1022  os << INDENT;
1023  }
1024  }
1025 
1026 
1028  void db_print_child(
1029  const Node* ppp,
1030  int depth,
1031  Node* Node::* branchpp,
1032  const char* branchss,
1033  std::ostream& os
1034  ) const
1035  {
1036  dbp_indent( depth, os );
1037  os << branchss << " subtree:";
1038  if ( is_nil( ppp ->* branchpp ) )
1039  {
1040  os << " NIL\n";
1041  }
1042  else
1043  {
1044  if ( ppp != root && ( ppp ->* branchpp ) -> parent != ppp )
1045  {
1046  os << " BROKEN!!!! ";
1047  }
1048  os << '\n';
1049  recursive_db_print( ppp ->* branchpp, 1 + depth, os );
1050  }
1051  }
1052 
1053 
1055  void recursive_db_print(
1056  const Node* ppp,
1057  int depth,
1058  std::ostream& os
1059  ) const
1060  {
1061  if ( is_nil( ppp ) )
1062  {
1063  return;
1064  }
1065 
1066  dbp_indent( depth, os );
1067  os << "key=" << ppp -> key << ", sum=" << ppp -> sum
1068  << ", color=" << ( ppp -> is_black ? "BLACK" : "red" )
1069  << ", sat=" << ppp -> sat
1070  << ", loc=" << ppp -> locator;
1071 
1072  if ( ! dictionary_is_small_linear_array() )
1073  {
1074  os << ", blackheight=" << blackheight_in_linear_time( ppp );
1075  }
1076  else if ( ! are_both_children_nil( ppp ) )
1077  {
1078  os << ", WARNING: children are not nil";
1079  }
1080 
1081  if ( are_both_children_nil( ppp ) )
1082  {
1083  os << '\n';
1084  return;
1085  }
1086  os << ", left=" << ppp -> left << ", right=" << ppp -> right << '\n';
1087 
1088  db_print_child( ppp, depth, & Node::left, "Left", os );
1089  db_print_child( ppp, depth, & Node::right, "Right", os );
1090  }
1091 #endif
1092 
1093 
1095  bool red_node_has_red_child_in_linear_time( const Node* ppp ) const
1096  {
1097  KJB(ASSERT( ppp ));
1098  if ( is_nil( ppp ) || are_both_children_nil( ppp ) )
1099  {
1100  return false;
1101  }
1102  if ( ppp -> is_red() && ppp -> left -> is_red() )
1103  {
1104  return true;
1105  }
1106  if ( ppp -> is_red() && ppp -> right -> is_red() )
1107  {
1108  return true;
1109  }
1110  return red_node_has_red_child_in_linear_time( ppp -> left )
1111  || red_node_has_red_child_in_linear_time( ppp -> right );
1112  }
1113 
1114 
1116  bool sums_are_correct_in_linear_time( const Node* ppp ) const
1117  {
1118  KJB(ASSERT( ppp ));
1119  if ( is_nil( ppp ) ) return true;
1120  Key_tp sts = ppp -> key;
1121  if ( is_not_nil( ppp -> left ) ) sts += ppp -> left -> sum;
1122  if ( is_not_nil( ppp -> right ) ) sts += ppp -> right -> sum;
1123 #ifdef DEBUGGING
1124  if ( sts != ppp -> sum )
1125  {
1126  chatter( "internal sums are incorrect" );
1127  }
1128 #endif
1129  return sts == ppp -> sum
1130  && sums_are_correct_in_linear_time( ppp -> left )
1131  && sums_are_correct_in_linear_time( ppp -> right );
1132  }
1133 
1134 
1136  bool sums_are_close_enough_in_linear_time( const Node* ppp ) const
1137  {
1138  const Key_tp SMALL = 1e-3;
1139  KJB(ASSERT( ppp ));
1140  if ( is_nil( ppp ) )
1141  return true;
1142 
1143  Key_tp sts = ppp -> key;
1144  if ( is_not_nil( ppp -> left ) ) sts += ppp -> left -> sum;
1145  if ( is_not_nil( ppp -> right ) ) sts += ppp -> right -> sum;
1146 
1147  Key_tp rrr = fabs( sts - ppp -> sum )/(fabs( sts )+fabs( ppp -> sum ));
1148 
1149 #ifdef DEBUGGING
1150  if ( !( sts == ppp -> sum || rrr < SMALL ) )
1151  {
1152  chatter( "internal sums are inadequately accurate" );
1153  std::ostringstream ess;
1154  ess << "rrr=" <<rrr <<" which exceeds SMALL=" << SMALL << '\n';
1155  chatter( ess.str().c_str() );
1156  return fail( __LINE__ );
1157  }
1158 #endif
1159 
1160  return ( sts == ppp -> sum || rrr < SMALL )
1161  && sums_are_close_enough_in_linear_time( ppp -> left )
1162  && sums_are_close_enough_in_linear_time( ppp -> right );
1163  }
1164 
1165 
1184  bool linear_search(
1185  const Key_tp& qkey,
1186  Sat_tp* sat_out,
1187  Loc_tp* loc_out,
1188  size_t* ix
1189  )
1190  {
1191 #ifdef DEBUGGING
1192  enter( __func__ );
1193 #endif
1194  for ( size_t iii = 0; iii < m_size; ++iii )
1195  {
1196  if ( root[ iii ].key == qkey )
1197  {
1198  if ( sat_out ) *sat_out = root[ iii ].sat;
1199  if ( loc_out ) *loc_out = root[ iii ].locator;
1200  if ( ix ) *ix = iii;
1201  KJB(ASSERT( loc_list_good_here( root + iii ) ));
1202  return true;
1203  }
1204  }
1205  return false;
1206  }
1207 
1208 
1210  Node* tree_search(
1211  const Key_tp& qkey,
1212  Sat_tp* sat_out,
1213  Node* ppp,
1214  Loc_tp* loc_out
1215  )
1216  {
1217 #ifdef DEBUGGING
1218  enter( __func__ );
1219 #endif
1220  KJB(ASSERT( ppp ));
1221  if ( is_nil( ppp ) )
1222  {
1223  return 00;
1224  }
1225  if ( qkey == ppp -> key )
1226  {
1227  if ( sat_out ) *sat_out = ppp -> sat;
1228  if ( loc_out ) *loc_out = ppp -> locator;
1229  return ppp;
1230  }
1231  Node* Node::* branch= qkey < ppp -> key ? & Node::left : & Node::right;
1232  return tree_search( qkey, sat_out, ppp ->* branch, loc_out );
1233  }
1234 
1235 
1245  Node* recursive_condense( Node* tree, Node* dest )
1246  {
1247  KJB(ASSERT( tree && dest ));
1248  if ( is_nil( tree ) )
1249  {
1250  return dest;
1251  }
1252 
1253  // first, recurse on left subtree
1254  Node* d2 = recursive_condense( tree -> left, dest );
1255  // second, store the current node
1256  *d2++ = *tree;
1257  // third and last, recurse on right subtree
1258  Node* d3 = recursive_condense( tree -> right, d2 );
1259  return d3;
1260  }
1261 
1262 
1263 
1264  // trivial functor to extract locator field from Node object
1265  struct GetLocator { Loc_tp operator()(const Node& n) {return n.locator;} };
1266 
1267 
1268  /*
1269  * This is a functor to alter a node into a black, parentless leaf (i.e.,
1270  * ready to be stored in a small linear array). Also, this rebuilds the
1271  * locator - pointer links. We assume the location list holds nulls.
1272  * Only the key and sat fields are left undisturbed.
1273  */
1274  class Leafify
1275  {
1276  Redblack_subtree_sum< SATELLITE_TYPE >* const tree;
1277 
1278  public:
1279  Leafify(Redblack_subtree_sum< SATELLITE_TYPE >* t) : tree(t) {}
1280 
1281  void operator()(Node& node) const
1282  {
1283  node.left = node.right = & tree -> m_nil; // children now nil
1284  node.parent = 00; // parent now null
1285  node.is_black = true; // blacken
1286  node.sum = node.key; // sum is key
1287 
1288  // update locator
1289 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
1290  KJB(ASSERT(node.locator < tree -> location_list.size()));
1291  KJB(ASSERT( 00 == tree -> location_list[ node.locator ] ));
1292 #endif
1293  tree -> location_list[ node.locator ] = &node;
1294  }
1295  };
1296 
1297 
1298 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
1299  /*
1300  * There is a linear array in root -- small, most likely, but we do not
1301  * care about the size. The locators recorded in the array are correct,
1302  * but we assume the back-end bookkeeping is spoiled, i.e., location_list
1303  * and free_locator_list are assumed to be hopelessly wrong, and not worth
1304  * consulting. This rebuilds them.
1305  *
1306  * An earlier software revision tried to repair them, but because of the
1307  * opportunistic cleanup that was added, their state became too hard to
1308  * predict, and I decided it's safer just to trash them and start over.
1309  */
1310  void rebuild_locator_list_for_linear_array()
1311  {
1312  // First, get a sorted list of live locators.
1313  std::vector< Loc_tp > locs( size() );
1314  std::transform(root, root+size(), locs.begin(), GetLocator());
1315  std::sort(locs.begin(), locs.end());
1316 
1317  // Locators in 'locs' must be pairwise-distinct.
1318  KJB(ASSERT(std::adjacent_find(locs.begin(),locs.end()) == locs.end()));
1319 
1320  // Rebuild list of pointers, one for each possible locator.
1321  // Unfortunately, this could be a huge number even for small size().
1322  // We are currently ignoring that fact. If necessary, we could cope
1323  // with sparsity in location_list by using a std::map to get from
1324  // locator to pointer.
1325  const size_t llsz = 1 + locs.back();
1326  location_list.assign(llsz, 00);
1327 
1328  // Create list of free locators -- it's just set subtraction:
1329  // the set {0 to max live locator value} minus locs.
1330  // Store it into free_locator_list (replacing previous contents).
1331  std::vector< Loc_tp > panloc(llsz);
1332  for (size_t i = 0; i < llsz; ++i)
1333  {
1334  panloc[i] = i;
1335  }
1336  free_locator_list.resize(location_list.size() - locs.size());
1337 #ifdef DEBUGGING
1338  typename std::vector< Loc_tp >::iterator z =
1339 #endif
1340  std::set_difference(panloc.begin(), panloc.end(),
1341  locs.begin(), locs.end(),
1342  free_locator_list.begin());
1343  KJB(ASSERT(free_locator_list.end() == z));
1344  // Put small free locators at the beginning so they'll be used sooner.
1345  std::reverse(free_locator_list.begin(), free_locator_list.end());
1346  }
1347 #endif
1348 
1349 
1350 
1352  void condense_into_linear_array()
1353  {
1354 #ifdef DEBUGGING
1355  enter( __func__ );
1356 #endif
1357  KJB(ASSERT( size() ));
1358 
1359  /*
1360  * Copy tree entries into linear array. Dispose of tree.
1361  * (Unfortunately, the second step also disposes of the locators.)
1362  */
1363  Node *la = new Node[ size() ];
1364 #ifdef DEBUGGING
1365  const Node *full =
1366 #endif
1367  recursive_condense( root, la );
1368  KJB(ASSERT( full - la == int( size() ) ));
1369  recursive_destroy( root );
1370  root = la;
1371 
1372 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
1373  // The previous locators were unfairly disposed of, so restore them.
1374  rebuild_locator_list_for_linear_array();
1375 #else
1376  KJB(ASSERT(location_list.empty()));
1377 #endif
1378 
1379  // Finally, fix up the node fields in the array, and re-link locators.
1380  std::for_each(root, root + size(), Leafify(this));
1381  }
1382 
1383 
1385  Node** to_parent_link( Node* ppp )
1386  {
1387  if ( ppp == root )
1388  {
1389  return & root;
1390  }
1391 
1392  KJB(ASSERT( ppp && is_not_nil( ppp ) ));
1393 
1394  Node* parent = ppp -> parent;
1395  KJB(ASSERT( parent && is_not_nil( parent ) ));
1396  KJB(ASSERT( parent -> right == ppp || parent -> left == ppp ));
1397 
1398  return parent -> left == ppp ? & parent -> left : & parent -> right;
1399  }
1400 
1401 
1403  Node* Node::* parent_branch_to_me( Node* ppp ) const
1404  {
1405  KJB(ASSERT( ppp && ppp != root /* && is_not_nil( ppp ) */ ));
1406  KJB(ASSERT( ppp -> parent ));
1407  KJB(ASSERT( ppp -> parent -> right == ppp
1408  || ppp -> parent -> left == ppp ));
1409  return ppp -> parent -> right == ppp ? & Node::right : & Node::left;
1410  }
1411 
1412 
1435  Node* splice_me( Node* ppp, Node* Node::* par_br, Node* Node::* child_br )
1436  {
1437  KJB(ASSERT( ppp && ppp != root ));
1438 
1439  Node *child_p = ppp ->* child_br,
1440  *par_p = ppp -> parent;
1441  KJB(ASSERT( par_p && is_not_nil( par_p ) ));
1442  KJB(ASSERT( ppp == par_p ->* par_br ));
1443  KJB(ASSERT( is_nil( ppp ->* opposite_direction( child_br ) ) ));
1444  KJB(ASSERT( child_p ));
1445  KJB(ASSERT( is_nil( child_p ) || ppp == child_p -> parent ));
1446  KJB(ASSERT( 00 == m_nil.parent ));
1447 
1448  /*
1449  * NOTE WELL: we do the following EVEN WHEN CHILD IS THE NIL NODE!!
1450  * That's because it is the easiest way to remember the bereaved
1451  * parent node, an entity we often must manipulate during a deletion.
1452  * The alternative was something like the following:
1453  *
1454  par_p ->* par_br = child_p;
1455  if ( is_not_nil( child_p ) )
1456  child_p -> parent = par_p;
1457  */
1458  par_p -> you_are_my_child( child_p, par_br );
1459 
1460  KJB(ASSERT( (ppp ->* child_br) -> parent == ppp -> parent ));
1461  KJB(ASSERT( ppp -> parent ->* par_br == ppp ->* child_br ));
1462 
1463  return ppp;
1464  }
1465 
1466 
1468  Node* semiauto_splice( Node* ppp, Node* Node::* child_br )
1469  {
1470  if ( ppp == root )
1471  {
1472  KJB(ASSERT( is_nil( ppp ->* opposite_direction( child_br ) ) ));
1473  KJB(ASSERT( is_nil( ppp ->* child_br )
1474  || ppp == ( ppp ->* child_br ) -> parent ));
1475  root = ppp ->* child_br;
1476  return ppp;
1477  }
1478  return splice_me( ppp, parent_branch_to_me( ppp ), child_br );
1479  }
1480 
1481 
1493  Node* fully_auto_splice( Node* ppp, Node ** tochild )
1494  {
1495  if ( is_nil( ppp -> left ) )
1496  {
1497  *tochild = ppp -> right;
1498  return semiauto_splice( ppp, & Node::right );
1499  }
1500  if ( is_nil( ppp -> right ) )
1501  {
1502  *tochild = ppp -> left;
1503  return semiauto_splice( ppp, & Node::left );
1504  }
1505  return 00; // cannot splice ppp because it has two children
1506  }
1507 
1508 
1529  Node* del_child_not_target( Node* target, Node** to_child )
1530  {
1531 #ifdef DEBUGGING
1532  enter( __func__ );
1533 #endif
1534  KJB(ASSERT( target && is_not_nil( target ) ));
1535  KJB(ASSERT( is_not_nil( target -> right ) ));
1536  KJB(ASSERT( 00 == m_nil.parent ));
1537 
1538  // must find victim (vic)
1539  Node *vic = target -> right;
1540  for ( ; is_not_nil( vic -> left ); vic = vic -> left )
1541  ;
1542 
1543  KJB(ASSERT( is_not_nil( vic ) && is_nil( vic -> left ) ));
1544 
1545  /*
1546  * Now target assumes the identity of victim, by taking its key, its
1547  * satellite value, its locator, and its location_list entry.
1548  */
1549  target -> key = vic -> key;
1550  target -> sat = vic -> sat;
1551  Loc_tp &TaLo( target -> locator ), &ViLo( vic -> locator );
1552  std::swap( location_list[ TaLo ], location_list[ ViLo ] );
1553  std::swap( TaLo, ViLo );
1554 
1555  // update subtree-sums between target, victim (i.e., retrace the path).
1556  for ( Node* ppp = target -> right; ppp != vic; ppp = ppp -> left )
1557  {
1558  KJB(ASSERT( is_not_nil( ppp ) ));
1559  ppp -> sum -= vic -> key;
1560  }
1561 
1562  // splice out vic; vic's parent vp claims vic's right child (if any).
1563  *to_child = vic -> right;
1564  return semiauto_splice( vic, & Node::right );
1565  }
1566 
1567 
1569  void resolve_double_black( Node* xblack )
1570  {
1571 #ifdef DEBUGGING
1572  enter( __func__ );
1573 #endif
1574  KJB(ASSERT( xblack ));
1575  KJB(ASSERT( m_nil.is_black ));
1576  KJB(ASSERT( root && is_not_nil( root ) ));
1577 
1578  if ( xblack -> is_red() )
1579  {
1580  // whoa, this is too easy!
1581  xblack -> is_black = true;
1582  return;
1583  }
1584 
1585  if ( xblack == root )
1586  {
1587  return; // ignore extra black at root b/c root has no sibling
1588  }
1589 
1590  // Let "me" = xblack. Since I am black, I must have a sibling.
1591  Node* Node::* xb_br = parent_branch_to_me( xblack );
1592  Node* Node::* sib_br = opposite_direction( xb_br );
1593  Node* sib = xblack -> parent ->* sib_br;
1594  KJB(ASSERT( sib && is_not_nil( sib ) )); // CLRS page 290
1595 
1596  // If my sibling is red, it can be rotated to become my (black) parent.
1597  if ( sib -> is_red() )
1598  {
1599  return case_of_the_red_sibling(
1600  xblack,
1601  xb_br
1602 #ifdef DEBUGGING
1603  ,sib
1604 #endif
1605  );
1606  }
1607 
1608  Node *near_nephew = sib ->* xb_br,
1609  *far_nephew = sib ->* sib_br;
1610  KJB(ASSERT( far_nephew && near_nephew )); // could be nil
1611 
1612  // Resolution depends on my nephews (possibly nil). Tail recursion:
1613  if ( far_nephew -> is_red() )
1614  {
1615  return case_of_the_far_red_nephew( sib, xb_br );
1616  }
1617 
1618  if ( near_nephew -> is_black )
1619  {
1620  return case_of_the_black_sib_and_nephews( sib );
1621  }
1622 
1623  return case_of_the_near_red_nephew( xblack, sib, xb_br );
1624  }
1625 
1626 
1639  void case_of_the_black_sib_and_nephews( Node* sib )
1640  {
1641 #ifdef DEBUGGING
1642  enter( __func__ );
1643 #endif
1644  KJB(ASSERT( sib && is_not_nil( sib ) && sib -> is_black ));
1645  KJB(ASSERT( sib -> left && sib -> left -> is_black ));
1646  KJB(ASSERT( sib -> right && sib -> right -> is_black ));
1647  KJB(ASSERT( m_nil.is_black ));
1648  sib -> is_black = false;
1649  m_nil.parent = 00;
1650 
1651  return resolve_double_black( sib -> parent );
1652  }
1653 
1654 
1675  void case_of_the_far_red_nephew( Node* oldsib, Node* Node::* xb_br )
1676  {
1677 #ifdef DEBUGGING
1678  enter( __func__ );
1679 #endif
1680  KJB(ASSERT( m_nil.is_black ));
1681 
1682  Node* Node::* sib_br = opposite_direction( xb_br );
1683 
1684  KJB(ASSERT( oldsib ));
1685 
1686  Node *oldparent = oldsib -> parent,
1687  *old_far_nephew = oldsib ->* sib_br;
1688  KJB(ASSERT( oldparent && is_not_nil( oldparent ) ));
1689  KJB(ASSERT( oldsib == oldparent ->* sib_br ));
1690  KJB(ASSERT( oldsib -> is_black ));
1691  KJB(ASSERT( old_far_nephew -> is_red() ));
1692 
1693  rotate( to_parent_link( oldparent ), sib_br );
1694  old_far_nephew -> is_black = true;
1695  m_nil.parent = 00;
1696  }
1697 
1698 
1715  void case_of_the_near_red_nephew(
1716  Node* xblack,
1717  Node* oldsib,
1718  Node* Node::* xb_br
1719  )
1720  {
1721 #ifdef DEBUGGING
1722  enter( __func__ );
1723 #endif
1724  KJB(ASSERT( xblack -> parent == oldsib -> parent ));
1725  KJB(ASSERT( oldsib && is_not_nil( oldsib ) && oldsib -> is_black ));
1726  KJB(ASSERT( oldsib -> left && oldsib -> right ));
1727  KJB(ASSERT( m_nil.is_black ));
1728 
1729  Node *old_red_nef = ( oldsib ->* xb_br ),
1730  *parent = xblack -> parent;
1731 
1732  // far nephew must be black too! only the near nephew is red.
1733  KJB(ASSERT( ( oldsib ->* opposite_direction( xb_br ) ) -> is_black ));
1734  KJB(ASSERT( old_red_nef -> is_red() ));
1735 
1736  /* unzigzag xblack's parent,sib,near-nephew, make them swap colors.
1737  * oldsib becomes new far-nephew. old near-nephew becomes new sib.
1738  *
1739  * Also, unzigzag likely corrupts xblack -> parent if *xblack is nil.
1740  * However, I think we have no need to care about that anymore.
1741  */
1742  unzigzag( parent, opposite_direction( xb_br ) );
1743  m_nil.parent = 00;
1744  oldsib -> is_black = false;
1745 
1746  Node *& new_blk_sib = old_red_nef; // alias for clarity
1747  new_blk_sib -> is_black = true;
1748 
1749  // old_red_nef has become the new black sibling of xblack
1750  KJB(ASSERT( new_blk_sib == parent ->* opposite_direction( xb_br ) ));
1751  KJB(ASSERT( oldsib == new_blk_sib ->* opposite_direction( xb_br ) ));
1752  return case_of_the_far_red_nephew( new_blk_sib, xb_br );
1753  }
1754 
1755 
1778  void case_of_the_red_sibling(
1779  Node* xblack,
1780  Node* Node::* xb_br
1781 #ifdef DEBUGGING
1782  ,Node* sib
1783 #endif
1784  )
1785  {
1786 #ifdef DEBUGGING
1787  enter( __func__ );
1788  KJB(ASSERT( m_nil.is_black ));
1789  KJB(ASSERT( sib && is_not_nil( sib ) ));
1790  KJB(ASSERT( xblack -> parent == sib -> parent ));
1791  KJB(ASSERT( xblack -> is_black && sib -> is_red() ));
1792  KJB(ASSERT( xblack != root ));
1793 #endif
1794 
1795  Node* xb_parent = xblack -> parent;
1796 
1797  Node* Node::* sib_br = opposite_direction( xb_br );
1798  rotate( to_parent_link( xb_parent ), sib_br );
1799  m_nil.parent = 00;
1800 
1801  // the following can be useful if xblack is nil, otherwise is benign:
1802  xblack -> parent = xb_parent;
1803 
1804  KJB(ASSERT( xb_parent -> is_red() ));
1805 #ifdef DEBUGGING
1806  KJB(ASSERT( xb_parent == sib ->* xb_br ));
1807  KJB(ASSERT( sib -> is_black ));
1808 #endif
1809  KJB(ASSERT( (xb_parent ->* sib_br) -> is_black ));
1810  KJB(ASSERT( (xb_parent ->* xb_br ) == xblack ));
1811  KJB(ASSERT( xblack -> is_black ));
1812 
1813  resolve_double_black( xblack );
1814  }
1815 
1816 
1832  void kill_a_node( Node* target )
1833  {
1834 #ifdef DEBUGGING
1835  enter( __func__ );
1836 #endif
1837  KJB(ASSERT( 00 == m_nil.parent ));
1838  KJB(ASSERT( target && is_not_nil( target ) ));
1839  const Key_tp& query_key( target -> key );
1840 
1841  for ( Node* ppp = target; ppp != root; ppp = ppp -> parent )
1842  {
1843  ppp -> sum -= query_key;
1844  }
1845  root -> sum -= query_key;
1846 
1847  // Splice out target if possible, otherwise replace its contents
1848  Node *xblack, *tar2 = fully_auto_splice( target, & xblack );
1849 
1850  // *xblack is nil iff xblack -> parent equals tar2.
1851  KJB(ASSERT( 00 == tar2 || 00 == m_nil.parent || is_nil( xblack ) ));
1852  KJB(ASSERT( 00 == tar2 || m_nil.parent || is_not_nil( xblack ) ));
1853 
1854  if ( 00 == tar2 )
1855  {
1856  tar2 = del_child_not_target( target, & xblack );
1857  }
1858 
1859  KJB(ASSERT( tar2 ));
1860  KJB(ASSERT( is_nil( tar2 -> left ) || is_nil( tar2 -> right ) ));
1861  KJB(ASSERT( is_nil( tar2 -> left ) || xblack == tar2 -> left ));
1862  KJB(ASSERT( is_nil( tar2 -> right ) || xblack == tar2 -> right ));
1863  KJB(ASSERT( tar2 == root || xblack -> parent == tar2 -> parent ));
1864  KJB(ASSERT( tar2 == root
1865  || tar2 -> parent -> left == xblack
1866  || tar2 -> parent -> right == xblack ));
1867 
1868  if ( tar2 -> is_black )
1869  {
1870  resolve_double_black( xblack );
1871  }
1872  m_nil.parent = 00;
1873  dispose( tar2 );
1874  }
1875 
1876 
1878  bool dictionary_is_small_linear_array() const
1879  {
1880  return size() <= TREE_THRESH;
1881  }
1882 
1883 
1885  int blackheight_in_linear_time() const
1886  {
1887 #ifdef DEBUGGING
1888  enter( __func__ );
1889 #endif
1890  if ( dictionary_is_small_linear_array() )
1891  {
1892  return 0;
1893  }
1894  return blackheight_in_linear_time( root );
1895  }
1896 
1898  bool red_node_has_red_child_in_linear_time() const
1899  {
1900 #ifdef DEBUGGING
1901  enter( __func__ );
1902 #endif
1903  return red_node_has_red_child_in_linear_time( root );
1904  }
1905 
1907  bool sums_are_correct_in_linear_time() const
1908  {
1909 #ifdef DEBUGGING
1910  enter( __func__ );
1911 #endif
1912  return sums_are_correct_in_linear_time( root );
1913  }
1914 
1915 
1917  Node* recursive_copy(
1918  const Node* src,
1919  const Redblack_subtree_sum< SATELLITE_TYPE >& st
1920  )
1921  {
1922  KJB(ASSERT( src ));
1923  if ( st.is_nil( src ) ) // the other tree's nil node
1924  {
1925  return & m_nil;
1926  }
1927 
1928  Node* my_copy = new Node( *src );
1929  /* my_copy -> parent = 00; not actually necessary */
1930  my_copy -> link_left_child( recursive_copy( src -> left, st ) );
1931  my_copy -> link_right_child( recursive_copy( src -> right, st ) );
1932  m_nil.parent = 00;
1933 
1934  const Loc_tp l = src -> locator;
1935 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
1936  KJB(ASSERT( l < location_list.size() ));
1937  location_list.at( l ) = my_copy;
1938 #else
1939  location_list[ l ] = my_copy;
1940 #endif
1941 
1942  return my_copy;
1943  }
1944 
1945 
1946 
1947 #ifdef DEBUGGING
1948  bool is_bst_in_linear_time() const
1950  {
1952  enter( __func__ );
1953  return is_bst_in_linear_time( root, -KMAX, +KMAX );
1954  }
1955 
1956 
1958  bool is_bst_in_linear_time(
1959  const Node* ppp,
1960  const Key_tp& min,
1961  const Key_tp& max
1962  ) const
1963  {
1964  KJB(ASSERT( ppp ));
1965  if ( is_nil( ppp ) )
1966  {
1967  return true;
1968  }
1969  const Key_tp& kii = ppp -> key;
1970 
1971  /*
1972  * When we insert, we put equal keys in the right subtree, but when
1973  * we rotate, equal keys could end up in the left subtree too.
1974  * Thus, kii==min or kii==max is acceptable.
1975  */
1976  if ( kii < min || max < kii ) // equality is not a failure
1977  {
1978  return false;
1979  }
1980 
1981  const Node *pl = ppp -> left,
1982  *pr = ppp -> right;
1983 
1984  return ( is_nil( pl ) || pl -> parent == ppp )
1985  && ( is_nil( pr ) || pr -> parent == ppp )
1986  && is_bst_in_linear_time( pr, kii, max )
1987  && is_bst_in_linear_time( pl, min, kii );
1988  }
1989 
1990 
1992  void locators_scan_nlogn_time(
1993  LocCensus_tp* census_ptr,
1994  const Node* ppp
1995  ) const
1996  {
1997  KJB(ASSERT( census_ptr ));
1998  KJB(ASSERT( ppp ));
1999  LocCensus_tp& census( *census_ptr );
2000  if ( is_nil( ppp ) )
2001  {
2002  return;
2003  }
2004  census[ ppp -> locator ] += 1;
2005  locators_scan_nlogn_time( census_ptr, ppp -> left );
2006  locators_scan_nlogn_time( census_ptr, ppp -> right );
2007  }
2008 
2010  bool locators_valid_in_nlogn_time() const
2011  {
2012  enter( __func__ );
2013  typedef typename LocCensus_tp::iterator LCI;
2014 
2015  LocCensus_tp census;
2016 
2017  // scan dictionary and record all locators stored in the records
2018  if ( dictionary_is_small_linear_array() )
2019  {
2020  for ( size_t iii = 0; iii < size(); ++iii )
2021  {
2022  Loc_tp loc = root[ iii ].locator;
2023  census[ loc ] += 1;
2024  if ( ! loc_list_good_here( root + iii ) )
2025  {
2026  return fail( __LINE__ );
2027  }
2028  }
2029  }
2030  else
2031  {
2032  locators_scan_nlogn_time( & census, root );
2033  }
2034 
2035  /*
2036  * Look at census result. Each map entry should record a locator that
2037  * is found in exactly one node, and the node claiming the locator
2038  * should be at the address recorded in locator_list at that index.
2039  */
2040  for ( LCI iii = census.begin(); iii != census.end(); ++iii )
2041  {
2042  Loc_tp loc = iii -> first;
2043  if ( iii -> second != 1 )
2044  {
2045  return fail( __LINE__ );
2046  }
2047 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
2048  Node* ppp = location_list[ loc ];
2049  if ( 00 == ppp || ppp -> locator != loc )
2050  {
2051  return fail( __LINE__ );
2052  }
2053 #else
2054  LLCI i = location_list.find(loc);
2055  if ( location_list.end() == i
2056  || 00 == i -> second
2057  || i -> first != loc
2058  )
2059  {
2060  return fail( __LINE__ );
2061  }
2062 #endif
2063  }
2064 
2065 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
2066  // Scan the list of unused locators.
2067  LocCensus_tp unused;
2068  for ( size_t iii = 0; iii < free_locator_list.size(); ++iii )
2069  {
2070  unused[ free_locator_list[ iii ] ] += 1;
2071  }
2072 
2073  /*
2074  * Scan the results of the unused list. Each entry (if any) should
2075  * record a locator that is found just once, and it should not be
2076  * found in the tree; likewise that index should mark a NULL entry in
2077  * the table.
2078  */
2079  for ( LCI iii = unused.begin(); iii != unused.end(); ++iii )
2080  {
2081  Loc_tp loc = iii -> first;
2082  // test for free_list duplicates
2083  if ( iii -> second != 1 ) return fail( __LINE__ );
2084  // loc must not be found in tree
2085  if ( census[ loc ] != 0 )
2086  {
2087  KJB(TEST_PSE(( "census loc is %d\n", int(census[loc]) )));
2088  return fail( __LINE__ );
2089  }
2090  // loc must be valid
2091  if ( location_list.size() <= loc ) return fail( __LINE__ );
2092  // loc must be unused
2093  if ( location_list[ loc ] != 00 ) return fail( __LINE__ );
2094  }
2095 #endif
2096 
2097  /*
2098  * Scan location_list. Every entry must correspond to an entry in
2099  * census (for pointers not equal to NULL) or to unused (for pointers
2100  * equal to NULL).
2101  */
2102 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
2103  for ( Loc_tp loc = 0; loc < location_list.size(); ++loc )
2104  {
2105  if ( location_list[ loc ] )
2106  {
2107  if ( census[ loc ] != 1 )
2108  {
2109  std::ostringstream oss;
2110  oss << "locator index " << loc
2111  << " has\n\tcensus value " << int(census[loc])
2112  << "\n\tptr value " << location_list[loc]
2113  << "\n\tptr loc " << location_list[loc]->locator
2114  << '\n';
2115  KJB(TEST_PSE(( "%s\n", oss.str().c_str() )));
2116  return fail( __LINE__ );
2117  }
2118  }
2119  else if ( unused[ loc ] != 1 )
2120  {
2121  return fail( __LINE__ );
2122  }
2123  }
2124 #else
2125  for (LLCI i = location_list.begin(); i != location_list.end(); ++i)
2126  {
2127  const Loc_tp loc = i -> first;
2128  if (00 == i -> second) return fail( __LINE__ );
2129 
2130  if ( census[ loc ] != 1 )
2131  {
2132  std::ostringstream oss;
2133  oss << "locator index " << loc
2134  << " has\n\tcensus value " << int(census[loc])
2135  << "\n\tptr value " << i -> second
2136  << "\n\tptr loc " << i -> second -> locator
2137  << '\n';
2138  KJB(TEST_PSE(( "%s\n", oss.str().c_str() )));
2139  return fail( __LINE__ );
2140  }
2141  }
2142 #endif
2143 
2144  return true;
2145  }
2146 #endif
2147 
2148 
2150  Loc_tp linear_insert( const Key_tp& key, const Sat_tp& sat )
2151  {
2152  const int BLACK = 1;
2153  Loc_tp nuloc = obtain_avail_locator();
2154  root[ m_size ] = Node( key, sat, BLACK, & m_nil, & m_nil, nuloc );
2155 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
2156  KJB(ASSERT( 00 == location_list.at( nuloc ) ));
2157 #endif
2158  location_list[ nuloc ] = root + m_size;
2159  ++m_size;
2160  return nuloc;
2161  }
2162 
2163 
2165  Loc_tp tree_insert( const Key_tp& key, const Sat_tp& sat )
2166  {
2167  if ( TREE_THRESH == size() )
2168  {
2169  make_it_a_real_tree_now();
2170  }
2171  Node* n00b = new_node( key, sat, 0 ); // red
2172  insert_gp( &root, *n00b < *root, n00b );
2173  root -> is_black = true;
2174  ++m_size;
2175  KJB(ASSERT( 00 == m_nil.parent ));
2176  KJB(ASSERT( n00b ));
2177  return n00b -> locator;
2178  }
2179 
2180 
2182  void db_print_locators() const
2183  {
2184 #ifdef DEBUGGING
2185 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
2186  KJB(TEST_PSE(( "Locs in use: " )));
2187  for ( size_t iii = 0; iii < location_list.size(); ++iii )
2188  {
2189  if ( location_list.at( iii ) )
2190  {
2191  KJB(TEST_PSE(( "%s%d", (iii ? "," : ""), iii )));
2192  }
2193  }
2194  KJB(TEST_PSE(( "\nLocs avail: " )));
2195  for ( size_t iii = 0; iii < free_locator_list.size(); ++iii )
2196  {
2197  KJB(TEST_PSE(( "%s%d", (iii ? ",":""),
2198  free_locator_list.at( iii ) )));
2199  }
2200 #else
2201  KJB(TEST_PSE(( "Locs in use:" )));
2202  for (LLCI i = location_list.begin(); i != location_list.end(); ++i)
2203  {
2204  KJB(TEST_PSE((" %u", i -> first)));
2205  }
2206 #endif
2207  KJB(TEST_PSE(( "\n" )));
2208 #endif
2209  }
2210 
2211 
2213  bool del_array_elt( size_t index )
2214  {
2215  KJB(ASSERT( index < size() ));
2216 
2217  Loc_tp loc = root[ index ].locator;
2218  release_locator( loc );
2219  --m_size; // shrink the array size -- yes, a little bit premature
2220 
2221  /*
2222  * If the record we want to erase is anywhere except the last
2223  * array entry, then we clobber it with the last array entry.
2224  * The reason we already decremented m_size was to state this operation
2225  * a bit more cleanly.
2226  */
2227  if ( index < m_size )
2228  {
2229  // clobber the key and satellite data
2230  root[ index ] = root[ m_size ];
2231  // Clobbering record needs its location_list pointer updated.
2232  KJB(ASSERT( location_list[ root[index].locator ] == root+m_size ));
2233  location_list[ root[ index ].locator ] = root + index;
2234  }
2235 
2236  if ( 0 == m_size )
2237  {
2238  delete[] root;
2239  }
2240 
2241  return true;
2242  }
2243 
2244 
2246  bool del_tree_node( Node* ppp )
2247  {
2248  KJB(ASSERT( ppp && loc_list_good_here( ppp ) ));
2249  kill_a_node( ppp );
2250  --m_size;
2251  KJB(ASSERT( 00 == m_nil.parent ));
2252 
2253  // Test whether the dictionary has just now shrunk down to lin-arr size
2254  if ( TREE_THRESH == m_size )
2255  {
2256  condense_into_linear_array();
2257  }
2258  return true;
2259  }
2260 
2261 
2263  Loc_tp loc_extremum(
2264  Node* Node::* branch,
2265  const Node* ( *pf )( const Node*, const Node* )
2266  ) const
2267  {
2268  if ( 0 == size() )
2269  {
2270  return 0; // sentinel value for empty dictionaries
2271  }
2272 
2273  // handle the small linear array case
2274  if ( dictionary_is_small_linear_array() )
2275  {
2276  const Node* ppp = (*pf)( root, root + size() );
2277  return LOCATOR_BASE + ppp -> locator;
2278  }
2279 
2280  // common case: search the tree down its chosen branch
2281  KJB(ASSERT( root ));
2282  const Node* ppp;
2283  for ( ppp = root; ppp && is_not_nil( ppp ->* branch );
2284  ppp = ppp ->* branch )
2285  {
2286  KJB(ASSERT( ppp ));
2287  }
2288  KJB(ASSERT( ppp && is_nil( ppp ->* branch ) ));
2289  return LOCATOR_BASE + ppp -> locator;
2290  }
2291 
2292 
2294  Loc_tp array_seek_cukes( Key_tp cumulative_keysum ) const
2295  {
2296 #if 0
2297  std::vector< Node > dicopy( root, root + size() );
2298  std::sort( dicopy.begin(), dicopy.end() ); // sort by keys
2299 #else
2300  Node dicopy[ TREE_THRESH ];
2301  std::copy(root, root + size(), dicopy);
2302  std::sort( dicopy, dicopy + size() ); // sort by keys
2303  KJB(ASSERT(0 < size() && size() <= TREE_THRESH));
2304 #endif
2305  Key_tp sum_so_far = 0;
2306  for ( size_t iii = 0; iii < size(); ++iii )
2307  {
2308  if ( cumulative_keysum <= ( sum_so_far += dicopy[ iii ].key ) )
2309  {
2310  return dicopy[ iii ].locator;
2311  }
2312  }
2313  KJB(ASSERT( sum_so_far < cumulative_keysum ));
2314  chatter( "sought a cumulative key sum larger than sum of all keys 1" );
2315  // ret loc to last record anyway -- maybe it's a floating point glitch.
2316  // We deliberately use at() here to throw in case that size is zero.
2317 #if 0
2318  return dicopy.at( int(size()) - 1 ).locator;
2319 #else
2320  return dicopy[ size() - 1 ].locator;
2321 #endif
2322  }
2323 
2324 
2326  Loc_tp tree_seek_cukes( const Node* ppp, Key_tp cumulative_keysum ) const
2327  {
2328  KJB(ASSERT( ppp && is_not_nil( ppp ) ));
2329  if ( are_both_children_nil( ppp ) )
2330  {
2331  if ( ppp -> key < cumulative_keysum )
2332  {
2333  chatter( "sought a cumulative key sum larger than "
2334  "sum of all keys 2" );
2335  }
2336  return ppp -> locator;
2337  }
2338  const Key_tp lsum = is_not_nil( ppp -> left ) ? ppp -> left -> sum : 0;
2339  // Uncommon case: go left.
2340  if ( is_not_nil( ppp -> left ) && cumulative_keysum <= lsum )
2341  {
2342  return tree_seek_cukes( ppp -> left, cumulative_keysum );
2343  }
2344  cumulative_keysum -= lsum;
2345  // Also uncommon case: retrieve this node
2346  if ( cumulative_keysum <= ppp -> key )
2347  {
2348  return ppp -> locator;
2349  }
2350  // Degenerate case: ck is too big but we cannot go right; we forgive.
2351  if ( is_nil( ppp -> right ) )
2352  {
2353  chatter( "sought a cumulative key sum larger than "
2354  "sum of all keys 3" );
2355  return ppp -> locator;
2356  }
2357  cumulative_keysum -= ppp -> key;
2358  // Common case: go right. We have already shrunk c_k appropriately.
2359  return tree_seek_cukes( ppp -> right, cumulative_keysum );
2360  }
2361 
2362 
2373  void copy_tree_into_empty(
2374  const Redblack_subtree_sum< SATELLITE_TYPE >& tree
2375  )
2376  {
2377  KJB(ASSERT(0 == size()));
2378 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
2379  KJB(ASSERT(0 == location_list.size()));
2380  KJB(ASSERT(0 == free_locator_list.size()));
2381 #else
2382  KJB(ASSERT(location_list.empty()));
2383 #endif
2384 
2385  if ( 0 == tree.size() ) return;
2386  root = 00; // must contain a defined value, if "catch" clause runs.
2387 
2388  try
2389  {
2390 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
2391  location_list.resize(tree.location_list.size());
2392  free_locator_list.resize(tree.free_locator_list.size());
2393  std::copy(tree.free_locator_list.begin(),
2394  tree.free_locator_list.end(), free_locator_list.begin());
2395 #endif
2396  m_size = tree.size();
2397 
2398  if ( tree.dictionary_is_small_linear_array() )
2399  {
2400  root = new Node[ TREE_THRESH ];
2401  std::copy(tree.root, tree.root + tree.size(), root);
2402 
2403  for ( size_t iii = 0; iii < tree.size(); ++iii )
2404  {
2405 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
2406  const Loc_tp l = root[iii].locator;
2407  KJB(ASSERT( l < location_list.size() ));
2408  location_list.at( l ) = root + iii;
2409 #else
2410  location_list[ root[iii].locator ] = root + iii;
2411 #endif
2412  }
2413  }
2414  else
2415  {
2416  root = recursive_copy( tree.root, tree );
2417  }
2418  }
2419  catch (std::bad_alloc& e)
2420  {
2421  // If we cannot do the whole thing, retract any partial progress.
2422  clear();
2423  throw e;
2424  }
2425  }
2426 
2427 
2428 public:
2429 
2432  : m_nil( 0, Sat_tp(), true, 00, 00, 00 ),
2433  m_size( 0 )
2434  {} // root is undefined, you got a problem with that???
2435 
2436 
2442  void clear()
2443  {
2444  KJB(ASSERT( 00 == m_nil.parent ));
2445  if ( 0 == size() )
2446  {
2447  return;
2448  }
2449 
2450  if ( dictionary_is_small_linear_array() )
2451  {
2452  delete[] root;
2453  }
2454  else
2455  {
2456  recursive_destroy( root );
2457  }
2458 
2459  m_size = 0;
2460  location_list.clear();
2461 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
2462  free_locator_list.clear();
2463 #endif
2464  }
2465 
2466 
2469  : m_nil( 0, Sat_tp(), true, 00, 00, 00 ),
2470  m_size( 0 )
2471  {
2472  copy_tree_into_empty( tree );
2473  }
2474 
2475 
2483  )
2484  {
2485  if ( this != &tree )
2486  {
2487  clear();
2488  copy_tree_into_empty( tree );
2489  }
2490  return *this;
2491  }
2492 
2493 
2496  {
2497  clear();
2498  }
2499 
2500 
2506  Loc_tp insert( const Key_tp& key, const Sat_tp& sat )
2507  {
2508  KJB(ASSERT( 00 == m_nil.parent ));
2509  if ( 0 == size() )
2510  {
2511  root = new Node[ TREE_THRESH ];
2512  }
2513  // Test whether we can do the insertion and STILL remain a linear array
2514  if ( size() < TREE_THRESH )
2515  {
2516  return LOCATOR_BASE + linear_insert( key, sat );
2517  }
2518  return LOCATOR_BASE + tree_insert( key, sat );
2519  }
2520 
2522  Loc_tp ins_max_key( const Sat_tp& sat )
2523  {
2524  return insert( std::numeric_limits< Key_tp >::max(), sat );
2525  }
2526 
2527 #ifdef DEBUGGING
2528  void debug_print( std::ostream& os ) const
2530  {
2531  if ( 0 == size() )
2532  {
2533  os << "tree is empty\n";
2534  }
2535  else if ( dictionary_is_small_linear_array() )
2536  {
2537  os << "tiny tree is in an unsorted array, root=" << root << '\n';
2538  for ( size_t iii = 0; iii < size(); ++iii )
2539  {
2540  KJB(ASSERT( are_both_children_nil( root + iii ) ));
2541  recursive_db_print( root + iii, 0, os );
2542  }
2543  }
2544  else
2545  {
2546  os << "Big tree with nil at " << & m_nil
2547  << ", root=" << root << '\n';
2548  recursive_db_print( root, 0, os );
2549  }
2550  db_print_locators();
2551  }
2552 #else
2553  void debug_print( std::ostream& ) const {}
2555 #endif
2556 
2559  {
2560 #ifdef DEBUGGING
2561  enter( __func__ );
2562  if ( m_nil.is_red() )
2563  {
2564  return fail( "nil is red" );
2565  }
2566 
2567  if ( m_nil.parent )
2568  {
2569  return fail( "nil points to a parent" );
2570  }
2571 
2572  if ( ! locators_valid_in_nlogn_time() )
2573  {
2574  return fail( "locators are bad" );
2575  }
2576 
2577  if ( dictionary_is_small_linear_array() )
2578  {
2579  return true;
2580  }
2581 
2582  if ( blackheight_in_linear_time() == BLACKHEIGHT_BAD
2583  || root -> is_red()
2584  || red_node_has_red_child_in_linear_time()
2585  // || ! sums_are_correct_in_linear_time()
2586  || ! sums_are_close_enough_in_linear_time( root )
2587  || ! is_bst_in_linear_time()
2588  )
2589  {
2590  return fail( "tree structure is bad" );
2591  }
2592 #endif
2593  return true;
2594  }
2595 
2613  bool find_key( const Key_tp& key, Sat_tp* sat_out, Loc_tp* loc_out )
2614  {
2615  bool is_found;
2616  if ( dictionary_is_small_linear_array() )
2617  {
2618  is_found = linear_search( key, sat_out, loc_out, 00 );
2619  }
2620  else
2621  {
2622  is_found = tree_search( key, sat_out, root, loc_out );
2623  }
2624 
2625  // We bias the locator to make it a little bit more opaque.
2626  if ( is_found && loc_out )
2627  {
2628  *loc_out += LOCATOR_BASE;
2629  }
2630 
2631  return is_found;
2632  }
2633 
2634 
2657  bool erase_key( const Key_tp& query_key, Sat_tp* sat_out )
2658  {
2659  KJB(ASSERT( 00 == m_nil.parent ));
2660 
2661  // handle the mini-array case
2662  if ( dictionary_is_small_linear_array() )
2663  {
2664  size_t index;
2665  if ( ! linear_search( query_key, sat_out, 00, & index ) )
2666  {
2667  return false; // not found
2668  }
2669  return del_array_elt( index );
2670  }
2671 
2672  // common case: dictionary is a tree
2673  Node* ppp = tree_search( query_key, sat_out, root, 00 );
2674  if ( 00 == ppp )
2675  {
2676  return false;
2677  }
2678  KJB(ASSERT( ppp -> key == query_key ));
2679 
2680  return del_tree_node( ppp );
2681  }
2682 
2683 
2695  bool access_loc( Loc_tp query_loc, Key_tp* key_out, Sat_tp* sat_out ) const
2696  {
2697  if ( query_loc < LOCATOR_BASE )
2698  {
2699  return false;
2700  }
2701  query_loc -= LOCATOR_BASE; // this is why we pass in the loc by value
2702 
2703 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
2704  if ( location_list.size() <= query_loc )
2705  {
2706  return false;
2707  }
2708 
2709  const Node* ppp = location_list.at( query_loc );
2710  if ( 00 == ppp )
2711  {
2712  return false;
2713  }
2714 #else
2715  LLCI i = location_list.find(query_loc);
2716  if (location_list.end() == i) return false;
2717  const Node* const ppp = i -> second;
2718 #endif
2719  KJB(ASSERT( ppp -> locator == query_loc ));
2720 
2721  if ( key_out )
2722  {
2723  *key_out = ppp -> key;
2724  }
2725  if ( sat_out )
2726  {
2727  *sat_out = ppp -> sat;
2728  }
2729  return true;
2730  }
2731 
2732 
2740  bool erase_loc( Loc_tp query_loc )
2741  {
2742  KJB(ASSERT( LOCATOR_BASE <= query_loc ));
2743  query_loc -= LOCATOR_BASE; // this is why we pass in the loc by value
2744 
2745 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
2746  if ( location_list.size() <= query_loc )
2747  {
2748  return false;
2749  }
2750 #else
2751  LLCI i = location_list.find(query_loc);
2752  if (location_list.end() == i) return false;
2753 #endif
2754 
2755  Node* ppp = location_list[ query_loc ];
2756  if ( 00 == ppp )
2757  {
2758  return false;
2759  }
2760  KJB(ASSERT( ppp -> locator == query_loc ));
2761 
2762  // handle the linear array case
2763  if ( dictionary_is_small_linear_array() )
2764  {
2765  if ( ppp < root || root + size() <= ppp )
2766  {
2767  return false;
2768  }
2769  KJB(ASSERT( loc_list_good_here( ppp ) ));
2770  return del_array_elt( ppp - root );
2771  }
2772 
2773  // common case: dictionary is a tree
2774  return del_tree_node( ppp );
2775  }
2776 
2777 
2778 
2780  Loc_tp loc_min() const
2781  {
2782  return loc_extremum( & Node::left, & std::min_element< const Node* > );
2783  }
2784 
2785 
2787  Loc_tp loc_max() const
2788  {
2789  return loc_extremum( & Node::right, & std::max_element< const Node* >);
2790  }
2791 
2792 
2794  size_t size() const
2795  {
2796  return m_size;
2797  }
2798 
2799 
2801  bool is_empty() const
2802  {
2803  return 0 == m_size;
2804  }
2805 
2806 
2808  bool rekey_loc( Loc_tp query_loc, const Key_tp& newkey )
2809  {
2810 #ifdef DEBUGGING
2811  enter( __func__ );
2812 #endif
2813  if ( query_loc < LOCATOR_BASE )
2814  {
2815  return false;
2816  }
2817 
2818  query_loc -= LOCATOR_BASE; // this is why we pass in the loc by value
2819 
2820 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
2821  if ( location_list.size() <= query_loc )
2822  {
2823  return false;
2824  }
2825 
2826  Node* const ppp = location_list[ query_loc ];
2827  if ( 00 == ppp )
2828  {
2829  return false;
2830  }
2831 #else
2832  LLCI i = location_list.find(query_loc);
2833  if (location_list.end() == i) return false;
2834  Node* const ppp = i -> second;
2835 #endif
2836  KJB(ASSERT( ppp -> locator == query_loc ));
2837 
2838  // handle the linear array case: unsorted, so just update key field
2839  if ( dictionary_is_small_linear_array() )
2840  {
2841  if ( ppp < root || root + size() <= ppp )
2842  {
2843  return false;
2844  }
2845  ppp -> key = newkey;
2846  return true;
2847  }
2848 
2849  // common case: dictionary is a tree
2850  // strategy: insert an "impostor," a new node w/ new key, old sat
2851  Loc_tp newloc = insert( newkey, ppp -> sat ) - LOCATOR_BASE;
2852  Node* const qqq = location_list[ newloc ];
2853  KJB(ASSERT( qqq -> locator == newloc ));
2854 
2855  // now swap their locators, so impostor bears the query_loc locator
2856  std::swap( location_list[ query_loc ], location_list[ newloc ] );
2857  std::swap( ppp -> locator, qqq -> locator );
2858  KJB(ASSERT( loc_list_good_here( ppp ) ));
2859  KJB(ASSERT( ppp == location_list[ newloc ] ));
2860 
2861  // now we can "disappear" the old node and no one will even notice.
2862  bool ok = del_tree_node( ppp );
2863  // the perfect crime: the old locator continues to work
2864  KJB(ASSERT( newkey == location_list[ query_loc ] -> key ));
2865 
2866  /*
2867  * Warning: ppp could now be dangling, or qqq could now be dangling!
2868  * Neither is safe to use anymore!
2869  *
2870  * If *ppp had one child or was a leaf, then ppp is now dangling.
2871  * But if *ppp had two children, some other node was deleted and its
2872  * fields moved into *ppp, and the location list was also twiddled to
2873  * make *ppp look like the victim -- which is all FINE. However, it is
2874  * possible (as I learned the hard way) that *qqq was this victim!
2875  * In which case, qqq is dangling.
2876  *
2877  * Conclusion: do NOT assert qqq == location_list[ query_loc ].
2878  */
2879 
2880  return ok;
2881  }
2882 
2883 
2886  {
2887  if ( 0 == size() )
2888  {
2889  return 0;
2890  }
2891  if ( dictionary_is_small_linear_array() )
2892  {
2893  return std::accumulate( root, root+size(), Key_tp( 0 ), AddKey() );
2894  }
2895  return root -> sum;
2896  }
2897 
2929  Loc_tp loc_using_cumulative_key_sum( Key_tp cumulative_keysum ) const
2930  {
2931  if ( 0 == size() )
2932  {
2933  return 0; // obviously bad because good locators are positive
2934  }
2935  if ( dictionary_is_small_linear_array() )
2936  {
2937  return LOCATOR_BASE + array_seek_cukes( cumulative_keysum );
2938  }
2939  return LOCATOR_BASE + tree_seek_cukes( root, cumulative_keysum );
2940  }
2941 
2944  {
2945  return loc_min();
2946  }
2947 
2948 
2949  /*
2950  * ==============================
2951  * ITERATOR
2952  * ==============================
2953  *
2954  * The iterator enumerates all the nodes in the tree, using the
2955  * location_list vector. That vector, as you know, contains pointers
2956  * to tree nodes, but also unused cells that contain NULL values.
2957  * Thus, this iterator has to skip over the NULLs.
2958  */
2959  friend class const_iterator;
2960 
2963  : public std::iterator< std::bidirectional_iterator_tag, Loc_tp >
2964  {
2965 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
2966  size_t m_index;
2967 
2968  const Redblack_subtree_sum< Sat_tp > *m_tree;
2969 
2979  void advance_()
2980  {
2981  // skip index forward, over null pointers in location list
2982  while ( m_index < m_tree -> location_list.size()
2983  && 00 == m_tree -> location_list[m_index]
2984  )
2985  {
2986  ++m_index;
2987  }
2988  }
2989 
2994  void retreat_()
2995  {
2996  // skip index backward, over null pointers in location list
2997  while ( 0 < m_index && 00 == m_tree -> location_list[m_index] )
2998  {
2999  --m_index;
3000  }
3001  if (0 == m_index) advance_();
3002  }
3003 #else
3004  typedef typename Redblack_subtree_sum< Sat_tp >::LLCI RBLLI;
3005  RBLLI m_it;
3006 #endif
3007 
3008  public:
3009 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
3011  : m_index(ix),
3012  m_tree(t)
3013  {
3014  NTX(t);
3015  advance_();
3016  }
3017 #else
3018  const_iterator(RBLLI i) : m_it(i) {}
3019 #endif
3020 
3022  {
3023 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
3024  const Node* n = m_tree -> location_list[m_index];
3025  KJB(ASSERT(n && n -> locator == m_index));
3026  return LOCATOR_BASE + m_index;
3027 #else
3028  KJB(ASSERT(m_it -> second));
3029  KJB(ASSERT(m_it -> second -> locator == m_it -> first));
3030  return LOCATOR_BASE + m_it -> first;
3031 #endif
3032  }
3033 
3034  bool operator==(const const_iterator& i) const
3035  {
3036 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
3037  return m_index == i.m_index && m_tree == i.m_tree;
3038 #else
3039  return m_it == i.m_it;
3040 #endif
3041  }
3042 
3043  bool operator!=(const const_iterator& i) const
3044  {
3045  return ! operator==(i);
3046  }
3047 
3049  {
3050 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
3051  ++m_index;
3052  advance_();
3053 #else
3054  ++m_it;
3055 #endif
3056  return *this;
3057  }
3059  {
3060  const_iterator temp(*this);
3061  operator++();
3062  return temp;
3063  }
3065  {
3066 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
3067  --m_index;
3068  retreat_();
3069 #else
3070  --m_it;
3071 #endif
3072  return *this;
3073  }
3075  {
3076  const_iterator temp(*this);
3077  operator--();
3078  return temp;
3079  }
3080  };
3081 
3083  {
3084 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
3085  return const_iterator(0, this);
3086 #else
3087  return const_iterator(location_list.begin());
3088 #endif
3089  }
3090 
3092  {
3093 #if REDBLACK_H_2014_NOV_13_LOCATION_LIST_IMPL_USES_ARRAY
3094  return const_iterator(location_list.size(), this);
3095 #else
3096  return const_iterator(location_list.end());
3097 #endif
3098  }
3099 
3100 #if 0
3101  /*
3102  * DOES NOT WORK -- as designed, the tree not entirely "pimpl" since it
3103  * has a member m_nil. The leaf nodes all point to it. If we swap the
3104  * representations we would have to change all the pointers formerly to
3105  * m_nil to the new member. Otherwise, after the swap, ownership of m_nil
3106  * and ownership of the nodes pointing to it will differ, which is
3107  * intolerable.
3108  */
3110  {
3111  std::swap(m_nil, other.m_nil);
3112  std::swap(root, other.root);
3113  std::swap(m_size, other.m_size);
3114  location_list.swap(other.location_list);
3115  free_locator_list.swap(other.free_locator_list);
3116  }
3117 #endif
3118 };
3119 
3120 
3121 }
3122 }
3123 
3124 
3125 #if 0
3126 namespace std
3128 {
3130  template <typename S>
3131  inline void swap(
3134  )
3135  {
3136  rb1.swap(rb2);
3137  }
3138 }
3139 #endif
3140 
3141 #endif /* REDBLACK_H_PREDOEHL_12_DEC_2011_VISION */
bool operator!=(const const_iterator &i) const
Definition: redblack.h:3043
interface for priority queues used by Dijkstra's algorithm
Int_matrix::Value_type max(const Int_matrix &mat)
Return the maximum value in this matrix.
Definition: l_int_matrix.h:1397
double accumulate(const Matrix_d< R, C, T > &mat, double init)
Definition: m_matrix_d.impl.h:432
Loc_tp loc_min() const
return the locator for the record with the minimum key, or 0
Definition: redblack.h:2780
size_t size() const
return the number of key+value pairs in the dictionary.
Definition: redblack.h:2794
const_iterator & operator--()
Definition: redblack.h:3064
#define KJB(x)
Definition: l_util.h:9
void swap(Perspective_camera &cam1, Perspective_camera &cam2)
Swap two cameras.
Definition: perspective_camera.h:599
Loc_tp operator*() const
Definition: redblack.h:3021
bool operator==(const const_iterator &i) const
Definition: redblack.h:3034
bool access_loc(Loc_tp query_loc, Key_tp *key_out, Sat_tp *sat_out) const
access a record via its locator, a constant-time operation.
Definition: redblack.h:2695
#define ASSERT(condition, message)
Definition: Assert.h:45
const_iterator operator++(int)
Definition: redblack.h:3058
bool tree_valid_in_nlogn_time() const
scan dictionary in linear time to verify invariants are valid
Definition: redblack.h:2558
const_iterator end() const
Definition: redblack.h:3091
#define NTX(a)
Definition: l_exception.h:89
bool erase_loc(Loc_tp query_loc)
remove the record indicated by query_loc, or return false if bad
Definition: redblack.h:2740
Redblack_subtree_sum()
default ctor
Definition: redblack.h:2431
bool erase_key(const Key_tp &query_key, Sat_tp *sat_out)
erase a key+value pair from the dictionary
Definition: redblack.h:2657
pure virtual interface for priority queue in Dijkstra's algorithm
Definition: diprique.h:72
Loc_tp ins_max_key(const Sat_tp &sat)
the following is a hack to mimic StochasticPriorityQueue
Definition: redblack.h:2522
function straight edges straight lines(nlines,[x1 x2 y1 y2 theta r])%%To display result ss
Definition: APPgetLargeConnectedEdges.m:20
bool rekey_loc(Loc_tp query_loc, const Key_tp &newkey)
change the key value for a node to a new value, O(log n) time
Definition: redblack.h:2808
void debug_print(std::ostream &) const
stub: remove print code when not checking aggressively
Definition: redblack.h:2554
const Vector3 BLACK(0.0, 0.0, 0.0)
Definition: gr_opengl_color.h:33
Loc_tp loc_max() const
return the locator for the record with the maximum key, or 0
Definition: redblack.h:2787
a balanced binary search tree storing subtree sums in each node.
Definition: redblack.h:165
Loc_tp loc_using_cumulative_key_sum(Key_tp cumulative_keysum) const
fetch a node based on inorder cumulative sum of tree keys
Definition: redblack.h:2929
Redblack_subtree_sum(const Redblack_subtree_sum< SATELLITE_TYPE > &tree)
copy ctor (same locators will work in this one too)
Definition: redblack.h:2468
Loc_tp Dijkstra_extraction() const
hack proxy to make this and a stochastic pri queue work alike
Definition: redblack.h:2943
const_iterator & operator++()
Definition: redblack.h:3048
const_iterator begin() const
Definition: redblack.h:3082
bool find_key(const Key_tp &key, Sat_tp *sat_out, Loc_tp *loc_out)
search for a key in the dictionary; return first one.
Definition: redblack.h:2613
void clear()
destroy the tree or the linear array.
Definition: redblack.h:2442
friend class const_iterator
Definition: redblack.h:2959
float Key_tp
type that we use for keys
Definition: diprique.h:75
DijkstraPriorityQueue< SATELLITE_TYPE >::Key_tp Key_tp
Definition: redblack.h:170
count
Definition: APPgetLargeConnectedEdges.m:71
void swap(kjb::Gsl_Multimin_fdf &m1, kjb::Gsl_Multimin_fdf &m2)
Swap two wrapped multimin objects.
Definition: gsl_multimin.h:693
sum(zmx.*zmy) sum(zmy.^2)]
#define dest(triedge, pointptr)
Definition: triangle.c:938
SATELLITE_TYPE Sat_tp
Definition: redblack.h:169
Loc_tp insert(const Key_tp &key, const Sat_tp &sat)
insert a new key+value pair in the dictionary
Definition: redblack.h:2506
Redblack_subtree_sum & operator=(const Redblack_subtree_sum< SATELLITE_TYPE > &tree)
assignment operator (same locators will work in this one too)
Definition: redblack.h:2481
Int_matrix::Value_type min(const Int_matrix &mat)
Return the minimum value in this matrix.
Definition: l_int_matrix.h:1385
bool is_empty() const
return whether the size is zero
Definition: redblack.h:2801
size_t Loc_tp
type that we use for locators
Definition: diprique.h:76
iterator class for a tree – lets you access node locators.
Definition: redblack.h:2962
bool operator<(const RatPoint &a, const RatPoint &b)
"row-major" ordering of points
Definition: ratpoint.h:82
const_iterator(size_t ix, const Redblack_subtree_sum< Sat_tp > *t)
Definition: redblack.h:3010
get the indices of edges in each direction for i
Definition: APPgetLargeConnectedEdges.m:48
~Redblack_subtree_sum()
dtor clears the structure
Definition: redblack.h:2495
DijkstraPriorityQueue< SATELLITE_TYPE >::Loc_tp Loc_tp
Definition: redblack.h:171
SatLoc Sat_tp
type of satellite data
Definition: diprique.h:74
const_iterator operator--(int)
Definition: redblack.h:3074
Key_tp root_sum() const
return subtree sum at root node (i.e., the sum of all keys).
Definition: redblack.h:2885