ord_index_node.hpp 20 KB

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