1 | /* Copyright 2003-2015 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) |
5 | * |
6 | * See http://www.boost.org/libs/multi_index for library home page. |
7 | * |
8 | * The internal implementation of red-black trees is based on that of SGI STL |
9 | * stl_tree.h file: |
10 | * |
11 | * Copyright (c) 1996,1997 |
12 | * Silicon Graphics Computer Systems, Inc. |
13 | * |
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. |
21 | * |
22 | * |
23 | * Copyright (c) 1994 |
24 | * Hewlett-Packard Company |
25 | * |
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. |
33 | * |
34 | */ |
35 | |
36 | #ifndef BOOST_MULTI_INDEX_DETAIL_ORD_INDEX_NODE_HPP |
37 | #define BOOST_MULTI_INDEX_DETAIL_ORD_INDEX_NODE_HPP |
38 | |
39 | #if defined(_MSC_VER) |
40 | #pragma once |
41 | #endif |
42 | |
43 | #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */ |
44 | #include <cstddef> |
45 | #include <boost/detail/allocator_utilities.hpp> |
46 | #include <boost/multi_index/detail/raw_ptr.hpp> |
47 | |
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> |
54 | #endif |
55 | |
56 | namespace boost{ |
57 | |
58 | namespace multi_index{ |
59 | |
60 | namespace detail{ |
61 | |
62 | /* definition of red-black nodes for ordered_index */ |
63 | |
64 | enum ordered_index_color{red=false,black=true}; |
65 | enum ordered_index_side{to_left=false,to_right=true}; |
66 | |
67 | template<typename AugmentPolicy,typename Allocator> |
68 | struct ordered_index_node_impl; /* fwd decl. */ |
69 | |
70 | template<typename AugmentPolicy,typename Allocator> |
71 | struct ordered_index_node_std_base |
72 | { |
73 | typedef typename |
74 | boost::detail::allocator::rebind_to< |
75 | Allocator, |
76 | ordered_index_node_impl<AugmentPolicy,Allocator> |
77 | >::type::pointer pointer; |
78 | typedef typename |
79 | boost::detail::allocator::rebind_to< |
80 | Allocator, |
81 | ordered_index_node_impl<AugmentPolicy,Allocator> |
82 | >::type::const_pointer const_pointer; |
83 | typedef ordered_index_color& color_ref; |
84 | typedef pointer& parent_ref; |
85 | |
86 | ordered_index_color& color(){return color_;} |
87 | ordered_index_color color()const{return color_;} |
88 | pointer& parent(){return parent_;} |
89 | pointer parent()const{return parent_;} |
90 | pointer& left(){return left_;} |
91 | pointer left()const{return left_;} |
92 | pointer& right(){return right_;} |
93 | pointer right()const{return right_;} |
94 | |
95 | private: |
96 | ordered_index_color color_; |
97 | pointer parent_; |
98 | pointer left_; |
99 | pointer right_; |
100 | }; |
101 | |
102 | #if !defined(BOOST_MULTI_INDEX_DISABLE_COMPRESSED_ORDERED_INDEX_NODES) |
103 | /* If ordered_index_node_impl has even alignment, we can use the least |
104 | * significant bit of one of the ordered_index_node_impl pointers to |
105 | * store color information. This typically reduces the size of |
106 | * ordered_index_node_impl by 25%. |
107 | */ |
108 | |
109 | #if defined(BOOST_MSVC) |
110 | /* This code casts pointers to an integer type that has been computed |
111 | * to be large enough to hold the pointer, however the metaprogramming |
112 | * logic is not always spotted by the VC++ code analyser that issues a |
113 | * long list of warnings. |
114 | */ |
115 | |
116 | #pragma warning(push) |
117 | #pragma warning(disable:4312 4311) |
118 | #endif |
119 | |
120 | template<typename AugmentPolicy,typename Allocator> |
121 | struct ordered_index_node_compressed_base |
122 | { |
123 | typedef ordered_index_node_impl< |
124 | AugmentPolicy,Allocator>* pointer; |
125 | typedef const ordered_index_node_impl< |
126 | AugmentPolicy,Allocator>* const_pointer; |
127 | |
128 | struct color_ref |
129 | { |
130 | color_ref(uintptr_type* r_):r(r_){} |
131 | |
132 | operator ordered_index_color()const |
133 | { |
134 | return ordered_index_color(*r&uintptr_type(1)); |
135 | } |
136 | |
137 | color_ref& operator=(ordered_index_color c) |
138 | { |
139 | *r&=~uintptr_type(1); |
140 | *r|=uintptr_type(c); |
141 | return *this; |
142 | } |
143 | |
144 | color_ref& operator=(const color_ref& x) |
145 | { |
146 | return operator=(x.operator ordered_index_color()); |
147 | } |
148 | |
149 | private: |
150 | uintptr_type* r; |
151 | }; |
152 | |
153 | struct parent_ref |
154 | { |
155 | parent_ref(uintptr_type* r_):r(r_){} |
156 | |
157 | operator pointer()const |
158 | { |
159 | return (pointer)(void*)(*r&~uintptr_type(1)); |
160 | } |
161 | |
162 | parent_ref& operator=(pointer p) |
163 | { |
164 | *r=((uintptr_type)(void*)p)|(*r&uintptr_type(1)); |
165 | return *this; |
166 | } |
167 | |
168 | parent_ref& operator=(const parent_ref& x) |
169 | { |
170 | return operator=(x.operator pointer()); |
171 | } |
172 | |
173 | pointer operator->()const |
174 | { |
175 | return operator pointer(); |
176 | } |
177 | |
178 | private: |
179 | uintptr_type* r; |
180 | }; |
181 | |
182 | color_ref color(){return color_ref(&parentcolor_);} |
183 | ordered_index_color color()const |
184 | { |
185 | return ordered_index_color(parentcolor_&uintptr_type(1)); |
186 | } |
187 | |
188 | parent_ref parent(){return parent_ref(&parentcolor_);} |
189 | pointer parent()const |
190 | { |
191 | return (pointer)(void*)(parentcolor_&~uintptr_type(1)); |
192 | } |
193 | |
194 | pointer& left(){return left_;} |
195 | pointer left()const{return left_;} |
196 | pointer& right(){return right_;} |
197 | pointer right()const{return right_;} |
198 | |
199 | private: |
200 | uintptr_type parentcolor_; |
201 | pointer left_; |
202 | pointer right_; |
203 | }; |
204 | #if defined(BOOST_MSVC) |
205 | #pragma warning(pop) |
206 | #endif |
207 | #endif |
208 | |
209 | template<typename AugmentPolicy,typename Allocator> |
210 | struct ordered_index_node_impl_base: |
211 | |
212 | #if !defined(BOOST_MULTI_INDEX_DISABLE_COMPRESSED_ORDERED_INDEX_NODES) |
213 | AugmentPolicy::template augmented_node< |
214 | typename mpl::if_c< |
215 | !(has_uintptr_type::value)|| |
216 | (alignment_of< |
217 | ordered_index_node_compressed_base<AugmentPolicy,Allocator> |
218 | >::value%2)|| |
219 | !(is_same< |
220 | typename boost::detail::allocator::rebind_to< |
221 | Allocator, |
222 | ordered_index_node_impl<AugmentPolicy,Allocator> |
223 | >::type::pointer, |
224 | ordered_index_node_impl<AugmentPolicy,Allocator>*>::value), |
225 | ordered_index_node_std_base<AugmentPolicy,Allocator>, |
226 | ordered_index_node_compressed_base<AugmentPolicy,Allocator> |
227 | >::type |
228 | >::type |
229 | #else |
230 | AugmentPolicy::template augmented_node< |
231 | ordered_index_node_std_base<AugmentPolicy,Allocator> |
232 | >::type |
233 | #endif |
234 | |
235 | {}; |
236 | |
237 | template<typename AugmentPolicy,typename Allocator> |
238 | struct ordered_index_node_impl: |
239 | ordered_index_node_impl_base<AugmentPolicy,Allocator> |
240 | { |
241 | private: |
242 | typedef ordered_index_node_impl_base<AugmentPolicy,Allocator> super; |
243 | |
244 | public: |
245 | typedef typename super::color_ref color_ref; |
246 | typedef typename super::parent_ref parent_ref; |
247 | typedef typename super::pointer pointer; |
248 | typedef typename super::const_pointer const_pointer; |
249 | |
250 | /* interoperability with bidir_node_iterator */ |
251 | |
252 | static void increment(pointer& x) |
253 | { |
254 | if(x->right()!=pointer(0)){ |
255 | x=x->right(); |
256 | while(x->left()!=pointer(0))x=x->left(); |
257 | } |
258 | else{ |
259 | pointer y=x->parent(); |
260 | while(x==y->right()){ |
261 | x=y; |
262 | y=y->parent(); |
263 | } |
264 | if(x->right()!=y)x=y; |
265 | } |
266 | } |
267 | |
268 | static void decrement(pointer& x) |
269 | { |
270 | if(x->color()==red&&x->parent()->parent()==x){ |
271 | x=x->right(); |
272 | } |
273 | else if(x->left()!=pointer(0)){ |
274 | pointer y=x->left(); |
275 | while(y->right()!=pointer(0))y=y->right(); |
276 | x=y; |
277 | }else{ |
278 | pointer y=x->parent(); |
279 | while(x==y->left()){ |
280 | x=y; |
281 | y=y->parent(); |
282 | } |
283 | x=y; |
284 | } |
285 | } |
286 | |
287 | /* algorithmic stuff */ |
288 | |
289 | static void rotate_left(pointer x,parent_ref root) |
290 | { |
291 | pointer y=x->right(); |
292 | x->right()=y->left(); |
293 | if(y->left()!=pointer(0))y->left()->parent()=x; |
294 | y->parent()=x->parent(); |
295 | |
296 | if(x==root) root=y; |
297 | else if(x==x->parent()->left())x->parent()->left()=y; |
298 | else x->parent()->right()=y; |
299 | y->left()=x; |
300 | x->parent()=y; |
301 | AugmentPolicy::rotate_left(x,y); |
302 | } |
303 | |
304 | static pointer minimum(pointer x) |
305 | { |
306 | while(x->left()!=pointer(0))x=x->left(); |
307 | return x; |
308 | } |
309 | |
310 | static pointer maximum(pointer x) |
311 | { |
312 | while(x->right()!=pointer(0))x=x->right(); |
313 | return x; |
314 | } |
315 | |
316 | static void rotate_right(pointer x,parent_ref root) |
317 | { |
318 | pointer y=x->left(); |
319 | x->left()=y->right(); |
320 | if(y->right()!=pointer(0))y->right()->parent()=x; |
321 | y->parent()=x->parent(); |
322 | |
323 | if(x==root) root=y; |
324 | else if(x==x->parent()->right())x->parent()->right()=y; |
325 | else x->parent()->left()=y; |
326 | y->right()=x; |
327 | x->parent()=y; |
328 | AugmentPolicy::rotate_right(x,y); |
329 | } |
330 | |
331 | static void rebalance(pointer x,parent_ref root) |
332 | { |
333 | x->color()=red; |
334 | while(x!=root&&x->parent()->color()==red){ |
335 | if(x->parent()==x->parent()->parent()->left()){ |
336 | pointer y=x->parent()->parent()->right(); |
337 | if(y!=pointer(0)&&y->color()==red){ |
338 | x->parent()->color()=black; |
339 | y->color()=black; |
340 | x->parent()->parent()->color()=red; |
341 | x=x->parent()->parent(); |
342 | } |
343 | else{ |
344 | if(x==x->parent()->right()){ |
345 | x=x->parent(); |
346 | rotate_left(x,root); |
347 | } |
348 | x->parent()->color()=black; |
349 | x->parent()->parent()->color()=red; |
350 | rotate_right(x->parent()->parent(),root); |
351 | } |
352 | } |
353 | else{ |
354 | pointer y=x->parent()->parent()->left(); |
355 | if(y!=pointer(0)&&y->color()==red){ |
356 | x->parent()->color()=black; |
357 | y->color()=black; |
358 | x->parent()->parent()->color()=red; |
359 | x=x->parent()->parent(); |
360 | } |
361 | else{ |
362 | if(x==x->parent()->left()){ |
363 | x=x->parent(); |
364 | rotate_right(x,root); |
365 | } |
366 | x->parent()->color()=black; |
367 | x->parent()->parent()->color()=red; |
368 | rotate_left(x->parent()->parent(),root); |
369 | } |
370 | } |
371 | } |
372 | root->color()=black; |
373 | } |
374 | |
375 | static void link( |
376 | pointer x,ordered_index_side side,pointer position,pointer ) |
377 | { |
378 | if(side==to_left){ |
379 | position->left()=x; /* also makes leftmost=x when parent==header */ |
380 | if(position==header){ |
381 | header->parent()=x; |
382 | header->right()=x; |
383 | } |
384 | else if(position==header->left()){ |
385 | header->left()=x; /* maintain leftmost pointing to min node */ |
386 | } |
387 | } |
388 | else{ |
389 | position->right()=x; |
390 | if(position==header->right()){ |
391 | header->right()=x; /* maintain rightmost pointing to max node */ |
392 | } |
393 | } |
394 | x->parent()=position; |
395 | x->left()=pointer(0); |
396 | x->right()=pointer(0); |
397 | AugmentPolicy::add(x,pointer(header->parent())); |
398 | ordered_index_node_impl::rebalance(x,header->parent()); |
399 | } |
400 | |
401 | static pointer rebalance_for_erase( |
402 | pointer z,parent_ref root,pointer& leftmost,pointer& rightmost) |
403 | { |
404 | pointer y=z; |
405 | pointer x=pointer(0); |
406 | pointer x_parent=pointer(0); |
407 | if(y->left()==pointer(0)){ /* z has at most one non-null child. y==z. */ |
408 | x=y->right(); /* x might be null */ |
409 | } |
410 | else{ |
411 | if(y->right()==pointer(0)){ /* z has exactly one non-null child. y==z. */ |
412 | x=y->left(); /* x is not null */ |
413 | } |
414 | else{ /* z has two non-null children. Set y to */ |
415 | y=y->right(); /* z's successor. x might be null. */ |
416 | while(y->left()!=pointer(0))y=y->left(); |
417 | x=y->right(); |
418 | } |
419 | } |
420 | AugmentPolicy::remove(y,pointer(root)); |
421 | if(y!=z){ |
422 | AugmentPolicy::copy(z,y); |
423 | z->left()->parent()=y; /* relink y in place of z. y is z's successor */ |
424 | y->left()=z->left(); |
425 | if(y!=z->right()){ |
426 | x_parent=y->parent(); |
427 | if(x!=pointer(0))x->parent()=y->parent(); |
428 | y->parent()->left()=x; /* y must be a child of left */ |
429 | y->right()=z->right(); |
430 | z->right()->parent()=y; |
431 | } |
432 | else{ |
433 | x_parent=y; |
434 | } |
435 | |
436 | if(root==z) root=y; |
437 | else if(z->parent()->left()==z)z->parent()->left()=y; |
438 | else z->parent()->right()=y; |
439 | y->parent()=z->parent(); |
440 | ordered_index_color c=y->color(); |
441 | y->color()=z->color(); |
442 | z->color()=c; |
443 | y=z; /* y now points to node to be actually deleted */ |
444 | } |
445 | else{ /* y==z */ |
446 | x_parent=y->parent(); |
447 | if(x!=pointer(0))x->parent()=y->parent(); |
448 | if(root==z){ |
449 | root=x; |
450 | } |
451 | else{ |
452 | if(z->parent()->left()==z)z->parent()->left()=x; |
453 | else z->parent()->right()=x; |
454 | } |
455 | if(leftmost==z){ |
456 | if(z->right()==pointer(0)){ /* z->left() must be null also */ |
457 | leftmost=z->parent(); |
458 | } |
459 | else{ |
460 | leftmost=minimum(x); /* makes leftmost==header if z==root */ |
461 | } |
462 | } |
463 | if(rightmost==z){ |
464 | if(z->left()==pointer(0)){ /* z->right() must be null also */ |
465 | rightmost=z->parent(); |
466 | } |
467 | else{ /* x==z->left() */ |
468 | rightmost=maximum(x); /* makes rightmost==header if z==root */ |
469 | } |
470 | } |
471 | } |
472 | if(y->color()!=red){ |
473 | while(x!=root&&(x==pointer(0)|| x->color()==black)){ |
474 | if(x==x_parent->left()){ |
475 | pointer w=x_parent->right(); |
476 | if(w->color()==red){ |
477 | w->color()=black; |
478 | x_parent->color()=red; |
479 | rotate_left(x_parent,root); |
480 | w=x_parent->right(); |
481 | } |
482 | if((w->left()==pointer(0)||w->left()->color()==black) && |
483 | (w->right()==pointer(0)||w->right()->color()==black)){ |
484 | w->color()=red; |
485 | x=x_parent; |
486 | x_parent=x_parent->parent(); |
487 | } |
488 | else{ |
489 | if(w->right()==pointer(0 ) |
490 | || w->right()->color()==black){ |
491 | if(w->left()!=pointer(0)) w->left()->color()=black; |
492 | w->color()=red; |
493 | rotate_right(w,root); |
494 | w=x_parent->right(); |
495 | } |
496 | w->color()=x_parent->color(); |
497 | x_parent->color()=black; |
498 | if(w->right()!=pointer(0))w->right()->color()=black; |
499 | rotate_left(x_parent,root); |
500 | break; |
501 | } |
502 | } |
503 | else{ /* same as above,with right <-> left */ |
504 | pointer w=x_parent->left(); |
505 | if(w->color()==red){ |
506 | w->color()=black; |
507 | x_parent->color()=red; |
508 | rotate_right(x_parent,root); |
509 | w=x_parent->left(); |
510 | } |
511 | if((w->right()==pointer(0)||w->right()->color()==black) && |
512 | (w->left()==pointer(0)||w->left()->color()==black)){ |
513 | w->color()=red; |
514 | x=x_parent; |
515 | x_parent=x_parent->parent(); |
516 | } |
517 | else{ |
518 | if(w->left()==pointer(0)||w->left()->color()==black){ |
519 | if(w->right()!=pointer(0))w->right()->color()=black; |
520 | w->color()=red; |
521 | rotate_left(w,root); |
522 | w=x_parent->left(); |
523 | } |
524 | w->color()=x_parent->color(); |
525 | x_parent->color()=black; |
526 | if(w->left()!=pointer(0))w->left()->color()=black; |
527 | rotate_right(x_parent,root); |
528 | break; |
529 | } |
530 | } |
531 | } |
532 | if(x!=pointer(0))x->color()=black; |
533 | } |
534 | return y; |
535 | } |
536 | |
537 | static void restore(pointer x,pointer position,pointer ) |
538 | { |
539 | if(position->left()==pointer(0)||position->left()==header){ |
540 | link(x,to_left,position,header); |
541 | } |
542 | else{ |
543 | decrement(position); |
544 | link(x,to_right,position,header); |
545 | } |
546 | } |
547 | |
548 | #if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING) |
549 | /* invariant stuff */ |
550 | |
551 | static std::size_t black_count(pointer node,pointer root) |
552 | { |
553 | if(node==pointer(0))return 0; |
554 | std::size_t sum=0; |
555 | for(;;){ |
556 | if(node->color()==black)++sum; |
557 | if(node==root)break; |
558 | node=node->parent(); |
559 | } |
560 | return sum; |
561 | } |
562 | #endif |
563 | }; |
564 | |
565 | template<typename AugmentPolicy,typename Super> |
566 | struct ordered_index_node_trampoline: |
567 | ordered_index_node_impl< |
568 | AugmentPolicy, |
569 | typename boost::detail::allocator::rebind_to< |
570 | typename Super::allocator_type, |
571 | char |
572 | >::type |
573 | > |
574 | { |
575 | typedef ordered_index_node_impl< |
576 | AugmentPolicy, |
577 | typename boost::detail::allocator::rebind_to< |
578 | typename Super::allocator_type, |
579 | char |
580 | >::type |
581 | > impl_type; |
582 | }; |
583 | |
584 | template<typename AugmentPolicy,typename Super> |
585 | struct ordered_index_node: |
586 | Super,ordered_index_node_trampoline<AugmentPolicy,Super> |
587 | { |
588 | private: |
589 | typedef ordered_index_node_trampoline<AugmentPolicy,Super> trampoline; |
590 | |
591 | public: |
592 | typedef typename trampoline::impl_type impl_type; |
593 | typedef typename trampoline::color_ref impl_color_ref; |
594 | typedef typename trampoline::parent_ref impl_parent_ref; |
595 | typedef typename trampoline::pointer impl_pointer; |
596 | typedef typename trampoline::const_pointer const_impl_pointer; |
597 | |
598 | impl_color_ref color(){return trampoline::color();} |
599 | ordered_index_color color()const{return trampoline::color();} |
600 | impl_parent_ref parent(){return trampoline::parent();} |
601 | impl_pointer parent()const{return trampoline::parent();} |
602 | impl_pointer& left(){return trampoline::left();} |
603 | impl_pointer left()const{return trampoline::left();} |
604 | impl_pointer& right(){return trampoline::right();} |
605 | impl_pointer right()const{return trampoline::right();} |
606 | |
607 | impl_pointer impl() |
608 | { |
609 | return static_cast<impl_pointer>( |
610 | static_cast<impl_type*>(static_cast<trampoline*>(this))); |
611 | } |
612 | |
613 | const_impl_pointer impl()const |
614 | { |
615 | return static_cast<const_impl_pointer>( |
616 | static_cast<const impl_type*>(static_cast<const trampoline*>(this))); |
617 | } |
618 | |
619 | static ordered_index_node* from_impl(impl_pointer x) |
620 | { |
621 | return |
622 | static_cast<ordered_index_node*>( |
623 | static_cast<trampoline*>( |
624 | raw_ptr<impl_type*>(x))); |
625 | } |
626 | |
627 | static const ordered_index_node* from_impl(const_impl_pointer x) |
628 | { |
629 | return |
630 | static_cast<const ordered_index_node*>( |
631 | static_cast<const trampoline*>( |
632 | raw_ptr<const impl_type*>(x))); |
633 | } |
634 | |
635 | /* interoperability with bidir_node_iterator */ |
636 | |
637 | static void increment(ordered_index_node*& x) |
638 | { |
639 | impl_pointer xi=x->impl(); |
640 | trampoline::increment(xi); |
641 | x=from_impl(xi); |
642 | } |
643 | |
644 | static void decrement(ordered_index_node*& x) |
645 | { |
646 | impl_pointer xi=x->impl(); |
647 | trampoline::decrement(xi); |
648 | x=from_impl(xi); |
649 | } |
650 | }; |
651 | |
652 | } /* namespace multi_index::detail */ |
653 | |
654 | } /* namespace multi_index */ |
655 | |
656 | } /* namespace boost */ |
657 | |
658 | #endif |
659 | |