annotate DEPENDENCIES/generic/include/boost/multi_index/detail/hash_index_node.hpp @ 125:34e428693f5d vext

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