hash_index_node.hpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790
  1. /* Copyright 2003-2018 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. #ifndef BOOST_MULTI_INDEX_DETAIL_HASH_INDEX_NODE_HPP
  9. #define BOOST_MULTI_INDEX_DETAIL_HASH_INDEX_NODE_HPP
  10. #if defined(_MSC_VER)
  11. #pragma once
  12. #endif
  13. #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
  14. #include <boost/detail/allocator_utilities.hpp>
  15. #include <boost/multi_index/detail/raw_ptr.hpp>
  16. #include <utility>
  17. #include <memory>
  18. namespace boost{
  19. namespace multi_index{
  20. namespace detail{
  21. /* Certain C++ requirements on unordered associative containers (see LWG issue
  22. * #579) imply a data structure where nodes are linked in a single list, which
  23. * in its turn forces implementors to add additional overhed per node to
  24. * associate each with its corresponding bucket. Others resort to storing hash
  25. * values, we use an alternative structure providing unconditional O(1)
  26. * manipulation, even in situations of unfair hash distribution, plus some
  27. * lookup speedups. For unique indices we maintain a doubly linked list of
  28. * nodes except that if N is the first node of a bucket its associated
  29. * bucket node is embedded between N and the preceding node in the following
  30. * manner:
  31. *
  32. * +---+ +---+ +---+ +---+
  33. * <--+ |<--+ | <--+ |<--+ |
  34. * ... | B0| | B1| ... | B1| | B2| ...
  35. * | |-+ | +--> | |-+ | +-->
  36. * +-+-+ | +---+ +-+-+ | +---+
  37. * | ^ | ^
  38. * | | | |
  39. * | +-+ | +-+
  40. * | | | |
  41. * v | v |
  42. * --+---+---+---+-- --+---+---+---+--
  43. * ... | | B1| | ... | | B2| | ...
  44. * --+---+---+---+-- --+---+---+---+--
  45. *
  46. *
  47. * The fist and last nodes of buckets can be checked with
  48. *
  49. * first node of a bucket: Npn != N
  50. * last node of a bucket: Nnp != N
  51. *
  52. * (n and p short for ->next(), ->prior(), bucket nodes have prior pointers
  53. * only). Pure insert and erase (without lookup) can be unconditionally done
  54. * in O(1).
  55. * For non-unique indices we add the following additional complexity: when
  56. * there is a group of 3 or more equivalent elements, they are linked as
  57. * follows:
  58. *
  59. * +-----------------------+
  60. * | v
  61. * +---+ | +---+ +---+ +---+
  62. * | | +-+ | | |<--+ |
  63. * | F | | S | ... | P | | L |
  64. * | +-->| | | +-+ | |
  65. * +---+ +---+ +---+ | +---+
  66. * ^ |
  67. * +-----------------------+
  68. *
  69. * F, S, P and L are the first, second, penultimate and last node in the
  70. * group, respectively (S and P can coincide if the group has size 3.) This
  71. * arrangement is used to skip equivalent elements in O(1) when doing lookup,
  72. * while preserving O(1) insert/erase. The following invariants identify
  73. * special positions (some of the operations have to be carefully implemented
  74. * as Xnn is not valid if Xn points to a bucket):
  75. *
  76. * first node of a bucket: Npnp == N
  77. * last node of a bucket: Nnpp == N
  78. * first node of a group: Nnp != N && Nnppn == N
  79. * second node of a group: Npn != N && Nppnn == N
  80. * n-1 node of a group: Nnp != N && Nnnpp == N
  81. * last node of a group: Npn != N && Npnnp == N
  82. *
  83. * The memory overhead is one pointer per bucket plus two pointers per node,
  84. * probably unbeatable. The resulting structure is bidirectonally traversable,
  85. * though currently we are just providing forward iteration.
  86. */
  87. template<typename Allocator>
  88. struct hashed_index_node_impl;
  89. /* half-header (only prior() pointer) to use for the bucket array */
  90. template<typename Allocator>
  91. struct hashed_index_base_node_impl
  92. {
  93. typedef typename
  94. boost::detail::allocator::rebind_to<
  95. Allocator,hashed_index_base_node_impl
  96. >::type base_allocator;
  97. typedef typename
  98. boost::detail::allocator::rebind_to<
  99. Allocator,
  100. hashed_index_node_impl<Allocator>
  101. >::type node_allocator;
  102. #ifdef BOOST_NO_CXX11_ALLOCATOR
  103. typedef typename base_allocator::pointer base_pointer;
  104. typedef typename base_allocator::const_pointer const_base_pointer;
  105. typedef typename node_allocator::pointer pointer;
  106. typedef typename node_allocator::const_pointer const_pointer;
  107. #else
  108. typedef typename std::allocator_traits<
  109. base_allocator
  110. >::pointer base_pointer;
  111. typedef typename std::allocator_traits<
  112. base_allocator
  113. >::const_pointer const_base_pointer;
  114. typedef typename std::allocator_traits<
  115. node_allocator
  116. >::pointer pointer;
  117. typedef typename std::allocator_traits<
  118. node_allocator
  119. >::const_pointer const_pointer;
  120. #endif
  121. pointer& prior(){return prior_;}
  122. pointer prior()const{return prior_;}
  123. private:
  124. pointer prior_;
  125. };
  126. /* full header (prior() and next()) for the nodes */
  127. template<typename Allocator>
  128. struct hashed_index_node_impl:hashed_index_base_node_impl<Allocator>
  129. {
  130. private:
  131. typedef hashed_index_base_node_impl<Allocator> super;
  132. public:
  133. typedef typename super::base_pointer base_pointer;
  134. typedef typename super::const_base_pointer const_base_pointer;
  135. typedef typename super::pointer pointer;
  136. typedef typename super::const_pointer const_pointer;
  137. base_pointer& next(){return next_;}
  138. base_pointer next()const{return next_;}
  139. static pointer pointer_from(base_pointer x)
  140. {
  141. return static_cast<pointer>(
  142. static_cast<hashed_index_node_impl*>(
  143. raw_ptr<super*>(x)));
  144. }
  145. static base_pointer base_pointer_from(pointer x)
  146. {
  147. return static_cast<base_pointer>(
  148. raw_ptr<hashed_index_node_impl*>(x));
  149. }
  150. private:
  151. base_pointer next_;
  152. };
  153. /* Boost.MultiIndex requires machinery to reverse unlink operations. A simple
  154. * way to make a pointer-manipulation function undoable is to templatize
  155. * its internal pointer assignments with a functor that, besides doing the
  156. * assignment, keeps track of the original pointer values and can later undo
  157. * the operations in reverse order.
  158. */
  159. struct default_assigner
  160. {
  161. template<typename T> void operator()(T& x,const T& val){x=val;}
  162. };
  163. template<typename Node>
  164. struct unlink_undo_assigner
  165. {
  166. typedef typename Node::base_pointer base_pointer;
  167. typedef typename Node::pointer pointer;
  168. unlink_undo_assigner():pointer_track_count(0),base_pointer_track_count(0){}
  169. void operator()(pointer& x,pointer val)
  170. {
  171. pointer_tracks[pointer_track_count].x=&x;
  172. pointer_tracks[pointer_track_count++].val=x;
  173. x=val;
  174. }
  175. void operator()(base_pointer& x,base_pointer val)
  176. {
  177. base_pointer_tracks[base_pointer_track_count].x=&x;
  178. base_pointer_tracks[base_pointer_track_count++].val=x;
  179. x=val;
  180. }
  181. void operator()() /* undo op */
  182. {
  183. /* in the absence of aliasing, restitution order is immaterial */
  184. while(pointer_track_count--){
  185. *(pointer_tracks[pointer_track_count].x)=
  186. pointer_tracks[pointer_track_count].val;
  187. }
  188. while(base_pointer_track_count--){
  189. *(base_pointer_tracks[base_pointer_track_count].x)=
  190. base_pointer_tracks[base_pointer_track_count].val;
  191. }
  192. }
  193. struct pointer_track {pointer* x; pointer val;};
  194. struct base_pointer_track{base_pointer* x; base_pointer val;};
  195. /* We know the maximum number of pointer and base pointer assignments that
  196. * the two unlink versions do, so we can statically reserve the needed
  197. * storage.
  198. */
  199. pointer_track pointer_tracks[3];
  200. int pointer_track_count;
  201. base_pointer_track base_pointer_tracks[2];
  202. int base_pointer_track_count;
  203. };
  204. /* algorithmic stuff for unique and non-unique variants */
  205. struct hashed_unique_tag{};
  206. struct hashed_non_unique_tag{};
  207. template<typename Node,typename Category>
  208. struct hashed_index_node_alg;
  209. template<typename Node>
  210. struct hashed_index_node_alg<Node,hashed_unique_tag>
  211. {
  212. typedef typename Node::base_pointer base_pointer;
  213. typedef typename Node::const_base_pointer const_base_pointer;
  214. typedef typename Node::pointer pointer;
  215. typedef typename Node::const_pointer const_pointer;
  216. static bool is_first_of_bucket(pointer x)
  217. {
  218. return x->prior()->next()!=base_pointer_from(x);
  219. }
  220. static pointer after(pointer x)
  221. {
  222. return is_last_of_bucket(x)?x->next()->prior():pointer_from(x->next());
  223. }
  224. static pointer after_local(pointer x)
  225. {
  226. return is_last_of_bucket(x)?pointer(0):pointer_from(x->next());
  227. }
  228. static pointer next_to_inspect(pointer x)
  229. {
  230. return is_last_of_bucket(x)?pointer(0):pointer_from(x->next());
  231. }
  232. static void link(pointer x,base_pointer buc,pointer end)
  233. {
  234. if(buc->prior()==pointer(0)){ /* empty bucket */
  235. x->prior()=end->prior();
  236. x->next()=end->prior()->next();
  237. x->prior()->next()=buc;
  238. buc->prior()=x;
  239. end->prior()=x;
  240. }
  241. else{
  242. x->prior()=buc->prior()->prior();
  243. x->next()=base_pointer_from(buc->prior());
  244. buc->prior()=x;
  245. x->next()->prior()=x;
  246. }
  247. }
  248. static void unlink(pointer x)
  249. {
  250. default_assigner assign;
  251. unlink(x,assign);
  252. }
  253. typedef unlink_undo_assigner<Node> unlink_undo;
  254. template<typename Assigner>
  255. static void unlink(pointer x,Assigner& assign)
  256. {
  257. if(is_first_of_bucket(x)){
  258. if(is_last_of_bucket(x)){
  259. assign(x->prior()->next()->prior(),pointer(0));
  260. assign(x->prior()->next(),x->next());
  261. assign(x->next()->prior()->prior(),x->prior());
  262. }
  263. else{
  264. assign(x->prior()->next()->prior(),pointer_from(x->next()));
  265. assign(x->next()->prior(),x->prior());
  266. }
  267. }
  268. else if(is_last_of_bucket(x)){
  269. assign(x->prior()->next(),x->next());
  270. assign(x->next()->prior()->prior(),x->prior());
  271. }
  272. else{
  273. assign(x->prior()->next(),x->next());
  274. assign(x->next()->prior(),x->prior());
  275. }
  276. }
  277. /* used only at rehashing */
  278. static void append(pointer x,pointer end)
  279. {
  280. x->prior()=end->prior();
  281. x->next()=end->prior()->next();
  282. x->prior()->next()=base_pointer_from(x);
  283. end->prior()=x;
  284. }
  285. static bool unlink_last(pointer end)
  286. {
  287. /* returns true iff bucket is emptied */
  288. pointer x=end->prior();
  289. if(x->prior()->next()==base_pointer_from(x)){
  290. x->prior()->next()=x->next();
  291. end->prior()=x->prior();
  292. return false;
  293. }
  294. else{
  295. x->prior()->next()->prior()=pointer(0);
  296. x->prior()->next()=x->next();
  297. end->prior()=x->prior();
  298. return true;
  299. }
  300. }
  301. private:
  302. static pointer pointer_from(base_pointer x)
  303. {
  304. return Node::pointer_from(x);
  305. }
  306. static base_pointer base_pointer_from(pointer x)
  307. {
  308. return Node::base_pointer_from(x);
  309. }
  310. static bool is_last_of_bucket(pointer x)
  311. {
  312. return x->next()->prior()!=x;
  313. }
  314. };
  315. template<typename Node>
  316. struct hashed_index_node_alg<Node,hashed_non_unique_tag>
  317. {
  318. typedef typename Node::base_pointer base_pointer;
  319. typedef typename Node::const_base_pointer const_base_pointer;
  320. typedef typename Node::pointer pointer;
  321. typedef typename Node::const_pointer const_pointer;
  322. static bool is_first_of_bucket(pointer x)
  323. {
  324. return x->prior()->next()->prior()==x;
  325. }
  326. static bool is_first_of_group(pointer x)
  327. {
  328. return
  329. x->next()->prior()!=x&&
  330. x->next()->prior()->prior()->next()==base_pointer_from(x);
  331. }
  332. static pointer after(pointer x)
  333. {
  334. if(x->next()->prior()==x)return pointer_from(x->next());
  335. if(x->next()->prior()->prior()==x)return x->next()->prior();
  336. if(x->next()->prior()->prior()->next()==base_pointer_from(x))
  337. return pointer_from(x->next());
  338. return pointer_from(x->next())->next()->prior();
  339. }
  340. static pointer after_local(pointer x)
  341. {
  342. if(x->next()->prior()==x)return pointer_from(x->next());
  343. if(x->next()->prior()->prior()==x)return pointer(0);
  344. if(x->next()->prior()->prior()->next()==base_pointer_from(x))
  345. return pointer_from(x->next());
  346. return pointer_from(x->next())->next()->prior();
  347. }
  348. static pointer next_to_inspect(pointer x)
  349. {
  350. if(x->next()->prior()==x)return pointer_from(x->next());
  351. if(x->next()->prior()->prior()==x)return pointer(0);
  352. if(x->next()->prior()->next()->prior()!=x->next()->prior())
  353. return pointer(0);
  354. return pointer_from(x->next()->prior()->next());
  355. }
  356. static void link(pointer x,base_pointer buc,pointer end)
  357. {
  358. if(buc->prior()==pointer(0)){ /* empty bucket */
  359. x->prior()=end->prior();
  360. x->next()=end->prior()->next();
  361. x->prior()->next()=buc;
  362. buc->prior()=x;
  363. end->prior()=x;
  364. }
  365. else{
  366. x->prior()=buc->prior()->prior();
  367. x->next()=base_pointer_from(buc->prior());
  368. buc->prior()=x;
  369. x->next()->prior()=x;
  370. }
  371. };
  372. static void link(pointer x,pointer first,pointer last)
  373. {
  374. x->prior()=first->prior();
  375. x->next()=base_pointer_from(first);
  376. if(is_first_of_bucket(first)){
  377. x->prior()->next()->prior()=x;
  378. }
  379. else{
  380. x->prior()->next()=base_pointer_from(x);
  381. }
  382. if(first==last){
  383. last->prior()=x;
  384. }
  385. else if(first->next()==base_pointer_from(last)){
  386. first->prior()=last;
  387. first->next()=base_pointer_from(x);
  388. }
  389. else{
  390. pointer second=pointer_from(first->next()),
  391. lastbutone=last->prior();
  392. second->prior()=first;
  393. first->prior()=last;
  394. lastbutone->next()=base_pointer_from(x);
  395. }
  396. }
  397. static void unlink(pointer x)
  398. {
  399. default_assigner assign;
  400. unlink(x,assign);
  401. }
  402. typedef unlink_undo_assigner<Node> unlink_undo;
  403. template<typename Assigner>
  404. static void unlink(pointer x,Assigner& assign)
  405. {
  406. if(x->prior()->next()==base_pointer_from(x)){
  407. if(x->next()->prior()==x){
  408. left_unlink(x,assign);
  409. right_unlink(x,assign);
  410. }
  411. else if(x->next()->prior()->prior()==x){ /* last of bucket */
  412. left_unlink(x,assign);
  413. right_unlink_last_of_bucket(x,assign);
  414. }
  415. else if(x->next()->prior()->prior()->next()==
  416. base_pointer_from(x)){ /* first of group size */
  417. left_unlink(x,assign);
  418. right_unlink_first_of_group(x,assign);
  419. }
  420. else{ /* n-1 of group */
  421. unlink_last_but_one_of_group(x,assign);
  422. }
  423. }
  424. else if(x->prior()->next()->prior()==x){ /* first of bucket */
  425. if(x->next()->prior()==x){
  426. left_unlink_first_of_bucket(x,assign);
  427. right_unlink(x,assign);
  428. }
  429. else if(x->next()->prior()->prior()==x){ /* last of bucket */
  430. assign(x->prior()->next()->prior(),pointer(0));
  431. assign(x->prior()->next(),x->next());
  432. assign(x->next()->prior()->prior(),x->prior());
  433. }
  434. else{ /* first of group */
  435. left_unlink_first_of_bucket(x,assign);
  436. right_unlink_first_of_group(x,assign);
  437. }
  438. }
  439. else if(x->next()->prior()->prior()==x){ /* last of group and bucket */
  440. left_unlink_last_of_group(x,assign);
  441. right_unlink_last_of_bucket(x,assign);
  442. }
  443. else if(pointer_from(x->prior()->prior()->next())
  444. ->next()==base_pointer_from(x)){ /* second of group */
  445. unlink_second_of_group(x,assign);
  446. }
  447. else{ /* last of group, ~(last of bucket) */
  448. left_unlink_last_of_group(x,assign);
  449. right_unlink(x,assign);
  450. }
  451. }
  452. /* used only at rehashing */
  453. static void link_range(
  454. pointer first,pointer last,base_pointer buc,pointer cend)
  455. {
  456. if(buc->prior()==pointer(0)){ /* empty bucket */
  457. first->prior()=cend->prior();
  458. last->next()=cend->prior()->next();
  459. first->prior()->next()=buc;
  460. buc->prior()=first;
  461. cend->prior()=last;
  462. }
  463. else{
  464. first->prior()=buc->prior()->prior();
  465. last->next()=base_pointer_from(buc->prior());
  466. buc->prior()=first;
  467. last->next()->prior()=last;
  468. }
  469. }
  470. static void append_range(pointer first,pointer last,pointer cend)
  471. {
  472. first->prior()=cend->prior();
  473. last->next()=cend->prior()->next();
  474. first->prior()->next()=base_pointer_from(first);
  475. cend->prior()=last;
  476. }
  477. static std::pair<pointer,bool> unlink_last_group(pointer end)
  478. {
  479. /* returns first of group true iff bucket is emptied */
  480. pointer x=end->prior();
  481. if(x->prior()->next()==base_pointer_from(x)){
  482. x->prior()->next()=x->next();
  483. end->prior()=x->prior();
  484. return std::make_pair(x,false);
  485. }
  486. else if(x->prior()->next()->prior()==x){
  487. x->prior()->next()->prior()=pointer(0);
  488. x->prior()->next()=x->next();
  489. end->prior()=x->prior();
  490. return std::make_pair(x,true);
  491. }
  492. else{
  493. pointer y=pointer_from(x->prior()->next());
  494. if(y->prior()->next()==base_pointer_from(y)){
  495. y->prior()->next()=x->next();
  496. end->prior()=y->prior();
  497. return std::make_pair(y,false);
  498. }
  499. else{
  500. y->prior()->next()->prior()=pointer(0);
  501. y->prior()->next()=x->next();
  502. end->prior()=y->prior();
  503. return std::make_pair(y,true);
  504. }
  505. }
  506. }
  507. static void unlink_range(pointer first,pointer last)
  508. {
  509. if(is_first_of_bucket(first)){
  510. if(is_last_of_bucket(last)){
  511. first->prior()->next()->prior()=pointer(0);
  512. first->prior()->next()=last->next();
  513. last->next()->prior()->prior()=first->prior();
  514. }
  515. else{
  516. first->prior()->next()->prior()=pointer_from(last->next());
  517. last->next()->prior()=first->prior();
  518. }
  519. }
  520. else if(is_last_of_bucket(last)){
  521. first->prior()->next()=last->next();
  522. last->next()->prior()->prior()=first->prior();
  523. }
  524. else{
  525. first->prior()->next()=last->next();
  526. last->next()->prior()=first->prior();
  527. }
  528. }
  529. private:
  530. static pointer pointer_from(base_pointer x)
  531. {
  532. return Node::pointer_from(x);
  533. }
  534. static base_pointer base_pointer_from(pointer x)
  535. {
  536. return Node::base_pointer_from(x);
  537. }
  538. static bool is_last_of_bucket(pointer x)
  539. {
  540. return x->next()->prior()->prior()==x;
  541. }
  542. template<typename Assigner>
  543. static void left_unlink(pointer x,Assigner& assign)
  544. {
  545. assign(x->prior()->next(),x->next());
  546. }
  547. template<typename Assigner>
  548. static void right_unlink(pointer x,Assigner& assign)
  549. {
  550. assign(x->next()->prior(),x->prior());
  551. }
  552. template<typename Assigner>
  553. static void left_unlink_first_of_bucket(pointer x,Assigner& assign)
  554. {
  555. assign(x->prior()->next()->prior(),pointer_from(x->next()));
  556. }
  557. template<typename Assigner>
  558. static void right_unlink_last_of_bucket(pointer x,Assigner& assign)
  559. {
  560. assign(x->next()->prior()->prior(),x->prior());
  561. }
  562. template<typename Assigner>
  563. static void right_unlink_first_of_group(pointer x,Assigner& assign)
  564. {
  565. pointer second=pointer_from(x->next()),
  566. last=second->prior(),
  567. lastbutone=last->prior();
  568. if(second==lastbutone){
  569. assign(second->next(),base_pointer_from(last));
  570. assign(second->prior(),x->prior());
  571. }
  572. else{
  573. assign(lastbutone->next(),base_pointer_from(second));
  574. assign(second->next()->prior(),last);
  575. assign(second->prior(),x->prior());
  576. }
  577. }
  578. template<typename Assigner>
  579. static void left_unlink_last_of_group(pointer x,Assigner& assign)
  580. {
  581. pointer lastbutone=x->prior(),
  582. first=pointer_from(lastbutone->next()),
  583. second=pointer_from(first->next());
  584. if(lastbutone==second){
  585. assign(lastbutone->prior(),first);
  586. assign(lastbutone->next(),x->next());
  587. }
  588. else{
  589. assign(second->prior(),lastbutone);
  590. assign(lastbutone->prior()->next(),base_pointer_from(first));
  591. assign(lastbutone->next(),x->next());
  592. }
  593. }
  594. template<typename Assigner>
  595. static void unlink_last_but_one_of_group(pointer x,Assigner& assign)
  596. {
  597. pointer first=pointer_from(x->next()),
  598. second=pointer_from(first->next()),
  599. last=second->prior();
  600. if(second==x){
  601. assign(last->prior(),first);
  602. assign(first->next(),base_pointer_from(last));
  603. }
  604. else{
  605. assign(last->prior(),x->prior());
  606. assign(x->prior()->next(),base_pointer_from(first));
  607. }
  608. }
  609. template<typename Assigner>
  610. static void unlink_second_of_group(pointer x,Assigner& assign)
  611. {
  612. pointer last=x->prior(),
  613. lastbutone=last->prior(),
  614. first=pointer_from(lastbutone->next());
  615. if(lastbutone==x){
  616. assign(first->next(),base_pointer_from(last));
  617. assign(last->prior(),first);
  618. }
  619. else{
  620. assign(first->next(),x->next());
  621. assign(x->next()->prior(),last);
  622. }
  623. }
  624. };
  625. template<typename Super>
  626. struct hashed_index_node_trampoline:
  627. hashed_index_node_impl<
  628. typename boost::detail::allocator::rebind_to<
  629. typename Super::allocator_type,
  630. char
  631. >::type
  632. >
  633. {
  634. typedef typename boost::detail::allocator::rebind_to<
  635. typename Super::allocator_type,
  636. char
  637. >::type impl_allocator_type;
  638. typedef hashed_index_node_impl<impl_allocator_type> impl_type;
  639. };
  640. template<typename Super,typename Category>
  641. struct hashed_index_node:
  642. Super,hashed_index_node_trampoline<Super>
  643. {
  644. private:
  645. typedef hashed_index_node_trampoline<Super> trampoline;
  646. public:
  647. typedef typename trampoline::impl_type impl_type;
  648. typedef hashed_index_node_alg<
  649. impl_type,Category> node_alg;
  650. typedef typename trampoline::base_pointer impl_base_pointer;
  651. typedef typename trampoline::const_base_pointer const_impl_base_pointer;
  652. typedef typename trampoline::pointer impl_pointer;
  653. typedef typename trampoline::const_pointer const_impl_pointer;
  654. impl_pointer& prior(){return trampoline::prior();}
  655. impl_pointer prior()const{return trampoline::prior();}
  656. impl_base_pointer& next(){return trampoline::next();}
  657. impl_base_pointer next()const{return trampoline::next();}
  658. impl_pointer impl()
  659. {
  660. return static_cast<impl_pointer>(
  661. static_cast<impl_type*>(static_cast<trampoline*>(this)));
  662. }
  663. const_impl_pointer impl()const
  664. {
  665. return static_cast<const_impl_pointer>(
  666. static_cast<const impl_type*>(static_cast<const trampoline*>(this)));
  667. }
  668. static hashed_index_node* from_impl(impl_pointer x)
  669. {
  670. return
  671. static_cast<hashed_index_node*>(
  672. static_cast<trampoline*>(
  673. raw_ptr<impl_type*>(x)));
  674. }
  675. static const hashed_index_node* from_impl(const_impl_pointer x)
  676. {
  677. return
  678. static_cast<const hashed_index_node*>(
  679. static_cast<const trampoline*>(
  680. raw_ptr<const impl_type*>(x)));
  681. }
  682. /* interoperability with hashed_index_iterator */
  683. static void increment(hashed_index_node*& x)
  684. {
  685. x=from_impl(node_alg::after(x->impl()));
  686. }
  687. static void increment_local(hashed_index_node*& x)
  688. {
  689. x=from_impl(node_alg::after_local(x->impl()));
  690. }
  691. };
  692. } /* namespace multi_index::detail */
  693. } /* namespace multi_index */
  694. } /* namespace boost */
  695. #endif