1 /* Copyright 2003-2020 Joaquin M Lopez Munoz.
2 * Distributed under the Boost Software License, Version 1.0.
3 * (See accompanying file LICENSE_1_0.txt or copy at
4 * http://www.boost.org/LICENSE_1_0.txt)
6 * See http://www.boost.org/libs/multi_index for library home page.
8 * The internal implementation of red-black trees is based on that of SGI STL
11 * Copyright (c) 1996,1997
12 * Silicon Graphics Computer Systems, Inc.
14 * Permission to use, copy, modify, distribute and sell this software
15 * and its documentation for any purpose is hereby granted without fee,
16 * provided that the above copyright notice appear in all copies and
17 * that both that copyright notice and this permission notice appear
18 * in supporting documentation. Silicon Graphics makes no
19 * representations about the suitability of this software for any
20 * purpose. It is provided "as is" without express or implied warranty.
24 * Hewlett-Packard Company
26 * Permission to use, copy, modify, distribute and sell this software
27 * and its documentation for any purpose is hereby granted without fee,
28 * provided that the above copyright notice appear in all copies and
29 * that both that copyright notice and this permission notice appear
30 * in supporting documentation. Hewlett-Packard Company makes no
31 * representations about the suitability of this software for any
32 * purpose. It is provided "as is" without express or implied warranty.
36 #ifndef BOOST_MULTI_INDEX_DETAIL_ORD_INDEX_NODE_HPP
37 #define BOOST_MULTI_INDEX_DETAIL_ORD_INDEX_NODE_HPP
43 #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
45 #include <boost/multi_index/detail/allocator_traits.hpp>
46 #include <boost/multi_index/detail/raw_ptr.hpp>
48 #if !defined(BOOST_MULTI_INDEX_DISABLE_COMPRESSED_ORDERED_INDEX_NODES)
49 #include <boost/mpl/and.hpp>
50 #include <boost/mpl/if.hpp>
51 #include <boost/multi_index/detail/uintptr_type.hpp>
52 #include <boost/type_traits/alignment_of.hpp>
53 #include <boost/type_traits/is_same.hpp>
58 namespace multi_index{
62 /* definition of red-black nodes for ordered_index */
64 enum ordered_index_color{red=false,black=true};
65 enum ordered_index_side{to_left=false,to_right=true};
67 template<typename AugmentPolicy,typename Allocator>
68 struct ordered_index_node_impl; /* fwd decl. */
70 template<typename AugmentPolicy,typename Allocator>
71 struct ordered_index_node_traits
73 typedef typename rebind_alloc_for<
75 ordered_index_node_impl<AugmentPolicy,Allocator>
77 typedef allocator_traits<allocator> alloc_traits;
78 typedef typename alloc_traits::pointer pointer;
79 typedef typename alloc_traits::const_pointer const_pointer;
80 typedef typename alloc_traits::difference_type difference_type;
81 typedef typename alloc_traits::size_type size_type;
84 template<typename AugmentPolicy,typename Allocator>
85 struct ordered_index_node_std_base
87 typedef ordered_index_node_traits<
88 AugmentPolicy,Allocator> node_traits;
89 typedef typename node_traits::allocator node_allocator;
90 typedef typename node_traits::pointer pointer;
91 typedef typename node_traits::const_pointer const_pointer;
92 typedef typename node_traits::difference_type difference_type;
93 typedef typename node_traits::size_type size_type;
94 typedef ordered_index_color& color_ref;
95 typedef pointer& parent_ref;
97 ordered_index_color& color(){return color_;}
98 ordered_index_color color()const{return color_;}
99 pointer& parent(){return parent_;}
100 pointer parent()const{return parent_;}
101 pointer& left(){return left_;}
102 pointer left()const{return left_;}
103 pointer& right(){return right_;}
104 pointer right()const{return right_;}
107 ordered_index_color color_;
113 #if !defined(BOOST_MULTI_INDEX_DISABLE_COMPRESSED_ORDERED_INDEX_NODES)
114 /* If ordered_index_node_impl has even alignment, we can use the least
115 * significant bit of one of the ordered_index_node_impl pointers to
116 * store color information. This typically reduces the size of
117 * ordered_index_node_impl by 25%.
120 #if defined(BOOST_MSVC)
121 /* This code casts pointers to an integer type that has been computed
122 * to be large enough to hold the pointer, however the metaprogramming
123 * logic is not always spotted by the VC++ code analyser that issues a
124 * long list of warnings.
127 #pragma warning(push)
128 #pragma warning(disable:4312 4311)
131 template<typename AugmentPolicy,typename Allocator>
132 struct ordered_index_node_compressed_base
134 typedef ordered_index_node_traits<
135 AugmentPolicy,Allocator> node_traits;
136 typedef ordered_index_node_impl<
137 AugmentPolicy,Allocator>* pointer;
138 typedef const ordered_index_node_impl<
139 AugmentPolicy,Allocator>* const_pointer;
140 typedef typename node_traits::difference_type difference_type;
141 typedef typename node_traits::size_type size_type;
145 color_ref(uintptr_type* r_):r(r_){}
146 color_ref(const color_ref& x):r(x.r){}
148 operator ordered_index_color()const
150 return ordered_index_color(*r&uintptr_type(1));
153 color_ref& operator=(ordered_index_color c)
155 *r&=~uintptr_type(1);
160 color_ref& operator=(const color_ref& x)
162 return operator=(x.operator ordered_index_color());
171 parent_ref(uintptr_type* r_):r(r_){}
172 parent_ref(const parent_ref& x):r(x.r){}
174 operator pointer()const
176 return (pointer)(void*)(*r&~uintptr_type(1));
179 parent_ref& operator=(pointer p)
181 *r=((uintptr_type)(void*)p)|(*r&uintptr_type(1));
185 parent_ref& operator=(const parent_ref& x)
187 return operator=(x.operator pointer());
190 pointer operator->()const
192 return operator pointer();
199 color_ref color(){return color_ref(&parentcolor_);}
200 ordered_index_color color()const
202 return ordered_index_color(parentcolor_&uintptr_type(1));
205 parent_ref parent(){return parent_ref(&parentcolor_);}
206 pointer parent()const
208 return (pointer)(void*)(parentcolor_&~uintptr_type(1));
211 pointer& left(){return left_;}
212 pointer left()const{return left_;}
213 pointer& right(){return right_;}
214 pointer right()const{return right_;}
217 uintptr_type parentcolor_;
221 #if defined(BOOST_MSVC)
226 template<typename AugmentPolicy,typename Allocator>
227 struct ordered_index_node_impl_base:
229 #if !defined(BOOST_MULTI_INDEX_DISABLE_COMPRESSED_ORDERED_INDEX_NODES)
230 AugmentPolicy::template augmented_node<
232 !(has_uintptr_type::value)||
234 ordered_index_node_compressed_base<AugmentPolicy,Allocator>
237 typename ordered_index_node_traits<AugmentPolicy,Allocator>::pointer,
238 ordered_index_node_impl<AugmentPolicy,Allocator>*>::value),
239 ordered_index_node_std_base<AugmentPolicy,Allocator>,
240 ordered_index_node_compressed_base<AugmentPolicy,Allocator>
244 AugmentPolicy::template augmented_node<
245 ordered_index_node_std_base<AugmentPolicy,Allocator>
251 template<typename AugmentPolicy,typename Allocator>
252 struct ordered_index_node_impl:
253 ordered_index_node_impl_base<AugmentPolicy,Allocator>
256 typedef ordered_index_node_impl_base<AugmentPolicy,Allocator> super;
259 typedef typename super::color_ref color_ref;
260 typedef typename super::parent_ref parent_ref;
261 typedef typename super::pointer pointer;
262 typedef typename super::const_pointer const_pointer;
264 /* interoperability with bidir_node_iterator */
266 static void increment(pointer& x)
268 if(x->right()!=pointer(0)){
270 while(x->left()!=pointer(0))x=x->left();
273 pointer y=x->parent();
274 while(x==y->right()){
278 if(x->right()!=y)x=y;
282 static void decrement(pointer& x)
284 if(x->color()==red&&x->parent()->parent()==x){
287 else if(x->left()!=pointer(0)){
289 while(y->right()!=pointer(0))y=y->right();
292 pointer y=x->parent();
301 /* algorithmic stuff */
303 static void rotate_left(pointer x,parent_ref root)
305 pointer y=x->right();
306 x->right()=y->left();
307 if(y->left()!=pointer(0))y->left()->parent()=x;
308 y->parent()=x->parent();
311 else if(x==x->parent()->left())x->parent()->left()=y;
312 else x->parent()->right()=y;
315 AugmentPolicy::rotate_left(x,y);
318 static pointer minimum(pointer x)
320 while(x->left()!=pointer(0))x=x->left();
324 static pointer maximum(pointer x)
326 while(x->right()!=pointer(0))x=x->right();
330 static void rotate_right(pointer x,parent_ref root)
333 x->left()=y->right();
334 if(y->right()!=pointer(0))y->right()->parent()=x;
335 y->parent()=x->parent();
338 else if(x==x->parent()->right())x->parent()->right()=y;
339 else x->parent()->left()=y;
342 AugmentPolicy::rotate_right(x,y);
345 static void rebalance(pointer x,parent_ref root)
348 while(x!=root&&x->parent()->color()==red){
349 if(x->parent()==x->parent()->parent()->left()){
350 pointer y=x->parent()->parent()->right();
351 if(y!=pointer(0)&&y->color()==red){
352 x->parent()->color()=black;
354 x->parent()->parent()->color()=red;
355 x=x->parent()->parent();
358 if(x==x->parent()->right()){
362 x->parent()->color()=black;
363 x->parent()->parent()->color()=red;
364 rotate_right(x->parent()->parent(),root);
368 pointer y=x->parent()->parent()->left();
369 if(y!=pointer(0)&&y->color()==red){
370 x->parent()->color()=black;
372 x->parent()->parent()->color()=red;
373 x=x->parent()->parent();
376 if(x==x->parent()->left()){
378 rotate_right(x,root);
380 x->parent()->color()=black;
381 x->parent()->parent()->color()=red;
382 rotate_left(x->parent()->parent(),root);
390 pointer x,ordered_index_side side,pointer position,pointer header)
393 position->left()=x; /* also makes leftmost=x when parent==header */
394 if(position==header){
398 else if(position==header->left()){
399 header->left()=x; /* maintain leftmost pointing to min node */
404 if(position==header->right()){
405 header->right()=x; /* maintain rightmost pointing to max node */
408 x->parent()=position;
409 x->left()=pointer(0);
410 x->right()=pointer(0);
411 AugmentPolicy::add(x,pointer(header->parent()));
412 ordered_index_node_impl::rebalance(x,header->parent());
415 static pointer rebalance_for_extract(
416 pointer z,parent_ref root,pointer& leftmost,pointer& rightmost)
419 pointer x=pointer(0);
420 pointer x_parent=pointer(0);
421 if(y->left()==pointer(0)){ /* z has at most one non-null child. y==z. */
422 x=y->right(); /* x might be null */
425 if(y->right()==pointer(0)){ /* z has exactly one non-null child. y==z. */
426 x=y->left(); /* x is not null */
428 else{ /* z has two non-null children. Set y to */
429 y=y->right(); /* z's successor. x might be null. */
430 while(y->left()!=pointer(0))y=y->left();
434 AugmentPolicy::remove(y,pointer(root));
436 AugmentPolicy::copy(z,y);
437 z->left()->parent()=y; /* relink y in place of z. y is z's successor */
440 x_parent=y->parent();
441 if(x!=pointer(0))x->parent()=y->parent();
442 y->parent()->left()=x; /* y must be a child of left */
443 y->right()=z->right();
444 z->right()->parent()=y;
451 else if(z->parent()->left()==z)z->parent()->left()=y;
452 else z->parent()->right()=y;
453 y->parent()=z->parent();
454 ordered_index_color c=y->color();
455 y->color()=z->color();
457 y=z; /* y now points to node to be actually deleted */
460 x_parent=y->parent();
461 if(x!=pointer(0))x->parent()=y->parent();
466 if(z->parent()->left()==z)z->parent()->left()=x;
467 else z->parent()->right()=x;
470 if(z->right()==pointer(0)){ /* z->left() must be null also */
471 leftmost=z->parent();
474 leftmost=minimum(x); /* makes leftmost==header if z==root */
478 if(z->left()==pointer(0)){ /* z->right() must be null also */
479 rightmost=z->parent();
481 else{ /* x==z->left() */
482 rightmost=maximum(x); /* makes rightmost==header if z==root */
487 while(x!=root&&(x==pointer(0)|| x->color()==black)){
488 if(x==x_parent->left()){
489 pointer w=x_parent->right();
492 x_parent->color()=red;
493 rotate_left(x_parent,root);
496 if((w->left()==pointer(0)||w->left()->color()==black) &&
497 (w->right()==pointer(0)||w->right()->color()==black)){
500 x_parent=x_parent->parent();
503 if(w->right()==pointer(0 )
504 || w->right()->color()==black){
505 if(w->left()!=pointer(0)) w->left()->color()=black;
507 rotate_right(w,root);
510 w->color()=x_parent->color();
511 x_parent->color()=black;
512 if(w->right()!=pointer(0))w->right()->color()=black;
513 rotate_left(x_parent,root);
517 else{ /* same as above,with right <-> left */
518 pointer w=x_parent->left();
521 x_parent->color()=red;
522 rotate_right(x_parent,root);
525 if((w->right()==pointer(0)||w->right()->color()==black) &&
526 (w->left()==pointer(0)||w->left()->color()==black)){
529 x_parent=x_parent->parent();
532 if(w->left()==pointer(0)||w->left()->color()==black){
533 if(w->right()!=pointer(0))w->right()->color()=black;
538 w->color()=x_parent->color();
539 x_parent->color()=black;
540 if(w->left()!=pointer(0))w->left()->color()=black;
541 rotate_right(x_parent,root);
546 if(x!=pointer(0))x->color()=black;
551 static void restore(pointer x,pointer position,pointer header)
553 if(position->left()==pointer(0)||position->left()==header){
554 link(x,to_left,position,header);
558 link(x,to_right,position,header);
562 #if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)
563 /* invariant stuff */
565 static std::size_t black_count(pointer node,pointer root)
567 if(node==pointer(0))return 0;
570 if(node->color()==black)++sum;
579 template<typename AugmentPolicy,typename Super>
580 struct ordered_index_node_trampoline:
581 ordered_index_node_impl<
583 typename rebind_alloc_for<
584 typename Super::allocator_type,
589 typedef ordered_index_node_impl<
591 typename rebind_alloc_for<
592 typename Super::allocator_type,
598 template<typename AugmentPolicy,typename Super>
599 struct ordered_index_node:
600 Super,ordered_index_node_trampoline<AugmentPolicy,Super>
603 typedef ordered_index_node_trampoline<AugmentPolicy,Super> trampoline;
606 typedef typename trampoline::impl_type impl_type;
607 typedef typename trampoline::color_ref impl_color_ref;
608 typedef typename trampoline::parent_ref impl_parent_ref;
609 typedef typename trampoline::pointer impl_pointer;
610 typedef typename trampoline::const_pointer const_impl_pointer;
611 typedef typename trampoline::difference_type difference_type;
612 typedef typename trampoline::size_type size_type;
614 impl_color_ref color(){return trampoline::color();}
615 ordered_index_color color()const{return trampoline::color();}
616 impl_parent_ref parent(){return trampoline::parent();}
617 impl_pointer parent()const{return trampoline::parent();}
618 impl_pointer& left(){return trampoline::left();}
619 impl_pointer left()const{return trampoline::left();}
620 impl_pointer& right(){return trampoline::right();}
621 impl_pointer right()const{return trampoline::right();}
625 return static_cast<impl_pointer>(
626 static_cast<impl_type*>(static_cast<trampoline*>(this)));
629 const_impl_pointer impl()const
631 return static_cast<const_impl_pointer>(
632 static_cast<const impl_type*>(static_cast<const trampoline*>(this)));
635 static ordered_index_node* from_impl(impl_pointer x)
638 static_cast<ordered_index_node*>(
639 static_cast<trampoline*>(
640 raw_ptr<impl_type*>(x)));
643 static const ordered_index_node* from_impl(const_impl_pointer x)
646 static_cast<const ordered_index_node*>(
647 static_cast<const trampoline*>(
648 raw_ptr<const impl_type*>(x)));
651 /* interoperability with bidir_node_iterator */
653 static void increment(ordered_index_node*& x)
655 impl_pointer xi=x->impl();
656 trampoline::increment(xi);
660 static void decrement(ordered_index_node*& x)
662 impl_pointer xi=x->impl();
663 trampoline::decrement(xi);
668 } /* namespace multi_index::detail */
670 } /* namespace multi_index */
672 } /* namespace boost */