1[/ 2 / Copyright (c) 2006-2013 Ion Gaztanaga 3 / 4 / Distributed under the Boost Software License, Version 1.0. (See accompanying 5 / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 /] 7 8[library Boost.Intrusive 9 [quickbook 1.6] 10 [authors [Krzikalla, Olaf], [Gaztanaga, Ion]] 11 [copyright 2005 Olaf Krzikalla, 2006-2015 Ion Gaztanaga] 12 [id intrusive] 13 [dirname intrusive] 14 [purpose Intrusive containers] 15 [license 16 Distributed under the Boost Software License, Version 1.0. 17 (See accompanying file LICENSE_1_0.txt or copy at 18 [@http://www.boost.org/LICENSE_1_0.txt]) 19 ] 20] 21 22[section:introduction Introduction] 23 24[section:introduction_presenting Presenting Boost.Intrusive] 25 26[*Boost.Intrusive] is a library presenting some intrusive containers to 27the world of C++. Intrusive containers are special containers 28that offer [link intrusive.performance better performance] 29and exception safety guarantees than non-intrusive containers (like STL containers). 30 31The performance benefits of intrusive containers makes them ideal as a building 32block to efficiently construct complex containers like multi-index containers or 33to design high performance code like memory allocation algorithms. 34 35While intrusive containers were and are widely used in C, they 36became more and more forgotten in C++ due to the presence of the standard 37containers which don't support intrusive techniques.[*Boost.Intrusive] wants to 38push intrusive containers usage encapsulating the implementation in 39STL-like interfaces. Hence anyone familiar with standard containers can easily use 40[*Boost.Intrusive]. 41 42[endsect] 43 44[section:introduction_building_intrusive Building Boost.Intrusive] 45 46There is no need to compile anything to use [*Boost.Intrusive], since it's 47a header only library. Just include your Boost header directory in your 48compiler include path. 49 50[endsect] 51 52[section:tested_compilers Tested compilers] 53 54[*Boost.Intrusive] has been tested on the following compilers/platforms: 55 56* Visual C++ >= 7.1. 57* GCC >= 4.1. 58 59[warning GCC < 4.3 and MSVC < 9.0 are deprecated and will be removed in the next version.] 60 61[endsect] 62 63[endsect] 64 65[section:intrusive_vs_nontrusive Intrusive and non-intrusive containers] 66 67[section:differences_intrusive_vs_nontrusive Differences between intrusive and non-intrusive containers] 68 69The main difference between intrusive containers and non-intrusive containers is 70that in C++ non-intrusive containers store [*copies] of values passed by the user. 71Containers use the `Allocator` template parameter to allocate the stored values: 72 73[c++] 74 75 #include <list> 76 #include <assert.h> 77 78 int main() 79 { 80 std::list<MyClass> myclass_list; 81 82 MyClass myclass(...); 83 myclass_list.push_back(myclass); 84 85 //The stored object is different from the original object 86 assert(&myclass != &myclass_list.front()); 87 return 0; 88 } 89 90 91To store the newly allocated copy of `myclass`, the container needs additional 92data: `std::list` usually allocates nodes that contain pointers to the 93next and previous node and the value itself. Something similar to: 94 95[c++] 96 97 //A possible implementation of a std::list<MyClass> node 98 class list_node 99 { 100 list_node *next; 101 list_node *previous; 102 MyClass value; 103 }; 104 105 106On the other hand, an intrusive container does not store copies of passed objects, 107but it stores the objects themselves. The additional data needed to insert the object 108in the container must be provided by the object itself. For example, to insert `MyClass` 109in an intrusive container that implements a linked list, `MyClass` must contain the 110needed ['next] and ['previous] pointers: 111 112[c++] 113 114 class MyClass 115 { 116 MyClass *next; 117 MyClass *previous; 118 //Other members... 119 }; 120 121 int main() 122 { 123 acme_intrusive_list<MyClass> list; 124 125 MyClass myclass; 126 list.push_back(myclass); 127 128 //"myclass" object is stored in the list 129 assert(&myclass == &list.front()); 130 return 0; 131 } 132 133As we can see, knowing which additional data the class should contain is not 134an easy task. [*Boost.Intrusive] offers several intrusive containers and an easy 135way to make user classes compatible with those containers. 136 137[endsect] 138 139[section:properties_of_intrusive Properties of Boost.Intrusive containers] 140 141Semantically, a [*Boost.Intrusive] container is similar to a STL container 142holding pointers to objects. That is, if you have an intrusive list holding 143objects of type `T`, then `std::list<T*>` would allow you to do quite the 144same operations (maintaining and navigating a set of objects of type T and 145types derived from it). 146 147A non-intrusive container has some limitations: 148 149* An object can only belong to one container: If you want to share an object 150 between two containers, you either have to store multiple copies of those 151 objects or you need to use containers of pointers: `std::list<Object*>`. 152 153* The use of dynamic allocation to create copies of passed values can be a performance 154 and size bottleneck in some applications. Normally, dynamic allocation imposes 155 a size overhead for each allocation to store bookkeeping information and a 156 synchronization to protected concurrent allocation from different threads. 157 158* Before C++11, only copies of objects could be stored in non-intrusive containers. Still 159 copy or move constructors and copy or move assignment operators are required 160 and non-copyable and non-movable objects can't be stored in some containers. In any case, 161 [*new] objects have to be created inside the container using constructors and the same 162 object can't be shared between two containers. 163 164* It's not possible to store a derived object in a STL-container while 165 retaining its original type. 166 167Intrusive containers have some important advantages: 168 169* Operating with intrusive containers doesn't invoke any memory management at all. 170 The time and size overhead associated with dynamic memory can be minimized. 171 172* The same object can be inserted in more than one container at the same time with 173 a tiny overhead in the object size. 174 175* Iterating an Intrusive container needs less memory accesses than the semantically 176 equivalent container of pointers: iteration is faster. 177 178* Intrusive containers offer better exception guarantees than non-intrusive containers. 179 In some situations intrusive containers offer a no-throw guarantee that can't be 180 achieved with non-intrusive containers. 181 182* The computation of an iterator to an element from a pointer or reference to that element 183 is a constant time operation (computing the position of `T*` in a `std::list<T*>` has 184 linear complexity). 185 186* Intrusive containers offer predictability when inserting and erasing objects since no 187 memory management is done with intrusive containers. Memory management usually is not a predictable 188 operation so complexity guarantees from non-intrusive containers are looser than the guarantees 189 offered by intrusive containers. 190 191Intrusive containers have also downsides: 192 193* Each type stored in an intrusive container needs additional memory holding the 194 maintenance information needed by the container. Hence, whenever a certain type will 195 be stored in an intrusive container [*you have to change the definition of that type] 196 appropriately. Although this task is easy with [*Boost.Intrusive], touching the 197 definition of a type is sometimes a crucial issue. 198 199* In intrusive containers you don't store a copy of an object, [*but rather the original object 200 is linked with other objects in the container]. Objects don't need copy-constructors or assignment 201 operators to be stored in intrusive containers. But you have to take care of possible side effects, 202 whenever you change the contents of an object (this is especially important for 203 associative containers). 204 205* The user [*has to manage the lifetime of inserted objects] independently from the 206 containers. 207 208* Again you have to be [*careful]: in contrast to STL containers [*it's easy to render an 209 iterator invalid] without touching the intrusive container directly, because the object 210 can be disposed before is erased from the container. 211 212* [*Boost.Intrusive] containers are [*non-copyable and non-assignable]. Since intrusive 213 containers don't have allocation capabilities, these operations make no sense. However, 214 swapping can be used to implement move capabilities. To ease the implementation of 215 copy constructors and assignment operators of classes storing [*Boost.Intrusive] 216 containers, [*Boost.Intrusive] offers special cloning functions. See 217 [link intrusive.clone_from Cloning Boost.Intrusive containers] section for more information. 218 219* Analyzing the thread safety of a program that uses containers is harder with intrusive containers, because 220 the container might be modified indirectly without an explicit call to a container member. 221 222[table Summary of intrusive containers advantages and disadvantages 223 [[Issue] [Intrusive] [Non-intrusive]] 224 [[Memory management] [External] [Internal through allocator]] 225 [[Insertion/Erasure time] [Faster] [Slower]] 226 [[Memory locality] [Better] [Worse]] 227 [[Can insert the same object in more than one container] [Yes] [No]] 228 [[Exception guarantees] [Better] [Worse]] 229 [[Computation of iterator from value] [Constant] [Non-constant]] 230 [[Insertion/erasure predictability] [High] [Low]] 231 [[Memory use] [Minimal] [More than minimal]] 232 [[Insert objects by value retaining polymorphic behavior] [Yes] [No (slicing)]] 233 [[User must modify the definition of the values to insert] [Yes] [No]] 234 [[Containers are copyable] [No] [Yes]] 235 [[Inserted object's lifetime managed by] [User (more complex)] [Container (less complex)]] 236 [[Container invariants can be broken without using the container] [Easier] [Harder (only with containers of pointers)]] 237 [[Thread-safety analysis] [Harder] [Easier]] 238] 239 240For a performance comparison between Intrusive and Non-intrusive containers see 241[link intrusive.performance Performance] section. 242 243[endsect] 244 245[endsect] 246 247[section:usage How to use Boost.Intrusive] 248 249If you plan to insert a class in an intrusive container, you have to make some decisions 250influencing the class definition itself. Each class that will be used in an intrusive 251container needs some appropriate data members storing the information needed by the 252container. We will take a simple intrusive container, the intrusive list 253([classref boost::intrusive::list boost::intrusive::list]), for the following 254examples, but all [*Boost.Intrusive] containers are very similar. To compile 255the example using [classref boost::intrusive::list boost::intrusive::list], 256just include: 257 258[c++] 259 260 #include <boost/intrusive/list.hpp> 261 262Every class to be inserted in an intrusive container, needs to contain a hook that 263will offer the necessary data and resources to be insertable in the container. 264With [*Boost.Intrusive] you just choose the hook to be a public base class or 265a public member of the class to be inserted. [*Boost.Intrusive] also offers 266more flexible hooks for advanced users, as explained in the chapter 267[link intrusive.function_hooks Using function hooks], but usually base or member 268hooks are good enough for most users. 269 270[section:usage_base_hook Using base hooks] 271 272For [classref boost::intrusive::list list], you can publicly derive from 273[classref boost::intrusive::list_base_hook list_base_hook]. 274 275[c++] 276 277 template <class ...Options> 278 class list_base_hook; 279 280The class can take several options. [*Boost.Intrusive] classes receive arguments in the 281form `option_name<option_value>`. You can specify the following options: 282 283* [*`tag<class Tag>`]: this argument serves as a tag, so you can derive from more than one 284 [classref boost::intrusive::list_base_hook list_base_hook] and hence put an object in 285 multiple intrusive lists at the same time. An incomplete type can serve as a tag. 286 If you specify two base hooks, you [*must] specify a different 287 tag for each one. Example: `list_base_hook< tag<tag1> >`. If no tag is specified 288 a default one will be used (more on default tags later). 289 290* [*`link_mode<link_mode_type LinkMode>`]: The second template argument controls the 291 linking policy. [*Boost.Intrusive] currently supports 292 3 modes: `normal_link`, `safe_link` and `auto_unlink`. By default, `safe_link` 293 mode is used. More about these in sections 294 [link intrusive.safe_hook Safe hooks] and [link intrusive.auto_unlink_hooks Auto-unlink hooks]. 295 Example: `list_base_hook< link_mode<auto_unlink> >` 296 297* [*`void_pointer<class VoidPointer>`]: this option is the pointer type to be used 298 internally in the hook. The default value is `void *`, which means that raw pointers 299 will be used in the hook. More about this in the section titled 300 [link intrusive.using_smart_pointers Using smart pointers with Boost.Intrusive containers]. 301 Example: `list_base_hook< void_pointer< my_smart_ptr<void> >` 302 303For the following examples, let's forget the options and use the default values: 304 305[c++] 306 307 #include <boost/intrusive/list.hpp> 308 309 using namespace boost::intrusive; 310 311 class Foo 312 //Base hook with default tag, raw pointers and safe_link mode 313 : public list_base_hook<> 314 { /**/ }; 315 316After that, we can define the intrusive list: 317 318[c++] 319 320 template <class T, class ...Options> 321 class list; 322 323`list` receives the type to be inserted in the container (`T`) as the first parameter 324and optionally, the user can specify options. We have 3 option types: 325 326* [*`base_hook<class Hook>`] / [*`member_hook<class T, class Hook, Hook T::* PtrToMember>`] / 327 [*`value_traits<class ValueTraits>`]: All these options specify the relationship 328 between the type `T` to be inserted in the list and the hook (since we can 329 have several hooks in the same `T` type). `member_hook` will be explained 330 a bit later and `value_traits` will be explained in the 331 [link intrusive.value_traits Containers with custom ValueTraits] section. 332 [*If no option is specified, the container will be configured to use the base 333 hook with the default tag]. 334 Some options configured for the hook (the type of the pointers, link mode, etc.) 335 will be propagated to the container. 336 337* [*`constant_time_size<bool Enabled>`]: Specifies if a constant time `size()` 338 function is demanded for the container. This will instruct the intrusive 339 container to store an additional member to keep track of the current size of the 340 container. By default, constant-time size is activated. 341 342* [*`size_type<class SizeType>`]: Specifies an unsigned type that can hold 343 the size of the container. This type will be the type returned by `list.size()` 344 and the type stored in the intrusive container if `constant_time_size<true>` 345 is requested. 346 The user normally will not need to change this type, but some 347 containers can have a `size_type` that might be different from `std::size_t` 348 (for example, STL-like containers use the `size_type` defined by their allocator). 349 [*Boost.Intrusive] can be used to implement such containers specifying the 350 type of the size. By default the type is `std::size_t`. 351 352Example of a constant-time size intrusive list that will store Foo objects, using 353the base hook with the default tag: 354 355[c++] 356 357 typedef list<Foo> FooList; 358 359Example of an intrusive list with non constant-time size that will store Foo objects: 360 361[c++] 362 363 typedef list<Foo, constant_time_size<false> > FooList; 364 365Remember that the user must specify the base hook in the container declaration 366if the base hook has no default tag, because that usually means that the type 367has more than one base hook, and a container shall know which hook will be 368using: 369 370[c++] 371 372 #include <boost/intrusive/list.hpp> 373 374 using namespace boost::intrusive; 375 376 struct my_tag1; 377 struct my_tag2; 378 379 typedef list_base_hook< tag<my_tag> > BaseHook; 380 typedef list_base_hook< tag<my_tag2> > BaseHook2; 381 class Foo : public BaseHook, public BaseHook2 382 { /**/ }; 383 384 typedef list< Foo, base_hook<BaseHook> > FooList; 385 typedef list< Foo, base_hook<BaseHook2> > FooList2; 386 387Once the list is defined, we can use it: 388 389[c++] 390 391 //An object to be inserted in the list 392 Foo foo_object; 393 FooList list; 394 395 list.push_back(object); 396 397 assert(&list.front() == &foo_object); 398 399[endsect] 400 401[section:usage_member_hook Using member hooks] 402 403Sometimes an 'is-a' relationship between list hooks and the list value types 404is not desirable. In this case, using a member hook as a data member instead of 405'disturbing' the hierarchy might be the right way: you can add a public data 406member `list_member_hook<...>` to your class. 407This class can be configured with the same options as `list_base_hook` 408except the option `tag`: 409 410[c++] 411 412 template <class ...Options> 413 class list_member_hook; 414 415Example: 416 417[c++] 418 419 #include <boost/intrusive/list.hpp> 420 421 class Foo 422 { 423 public: 424 list_member_hook<> hook_; 425 //... 426 }; 427 428When member hooks are used, the `member_hook` option is used to configure the 429list: 430 431[c++] 432 433 //This option will configure "list" to use the member hook 434 typedef member_hook<Foo, list_member_hook<>, &Foo::hook_> MemberHookOption; 435 436 //This list will use the member hook 437 typedef list<Foo, MemberHookOption> FooList; 438 439Now we can use the container: 440 441[c++] 442 443 //An object to be inserted in the list 444 Foo foo_object; 445 FooList list; 446 447 list.push_back(object); 448 449 assert(&list.front() == &foo_object); 450 451[endsect] 452 453However, member hooks have some implementation limitations: If there is a virtual inheritance 454relationship between the parent and the member hook, then the distance between the parent 455and the hook is not a compile-time fixed value so obtaining the address of 456the parent from the member hook is not possible without reverse engineering compiler 457produced RTTI. Apart from this, the non-standard pointer to member implementation for classes 458with complex inheritance relationships in MSVC ABI compatible-compilers is not supported 459by member hooks since it also depends on compiler-produced RTTI information. 460 461[section:usage_both_hooks Using both hooks] 462 463You can insert the same object in several intrusive containers at the same time, 464using one hook per container. This is a full example using base and member hooks: 465 466[import ../example/doc_how_to_use.cpp] 467[doc_how_to_use_code] 468 469[endsect] 470 471[section:usage_lifetime Object lifetime] 472 473Even if the interface of [classref boost::intrusive::list list] is similar to 474`std::list`, its usage is a bit different: You always have to keep in mind that 475you directly store objects in intrusive containers, not copies. The lifetime of a 476stored object is not bound to or managed by the container: 477 478* When the container gets destroyed before the object, the object is not destroyed, 479 so you have to be careful to avoid resource leaks. 480 481* When the object is destroyed before the container, your program is likely to crash, 482 because the container contains a pointer to an non-existing object. 483 484[endsect] 485 486 487[endsect] 488 489[section:usage_when When to use?] 490 491Intrusive containers can be used for highly optimized algorithms, where speed is a crucial 492issue and: 493 494* additional memory management should be avoided. 495* the programmer needs to efficiently track the construction and destruction of objects. 496* exception safety, especially the no-throw guarantee, is needed. 497* the computation of an iterator to an element from a pointer or reference 498 to that element should be a constant time operation. 499* it's important to achieve a well-known worst-time system response. 500* localization of data (e.g. for cache hit optimization) leads to measurable effects. 501 502The last point is important if you have a lot of containers over a set of elements. E.g. if 503you have a vector of objects (say, `std::vector<Object>`), and you also have a list 504storing a subset of those objects (`std::list<Object*>`), then operating on an Object 505from the list iterator (`std::list<Object*>::iterator`) requires two steps: 506 507* Access from the iterator (usually on the stack) to the list node storing a pointer to `Object`. 508* Access from the pointer to `Object` to the Object stored in the vector. 509 510While the objects themselves are tightly packed in the memory of the vector 511(a vector's memory is guaranteed to be contiguous), and form something 512like a data block, list nodes may be dispersed in the heap memory. 513Hence depending on your system you might get a lot of cache misses. The same doesn't hold 514for an intrusive list. Indeed, dereferencing an iterator from an intrusive list is performed in 515the same two steps as described above. But the list node is already embedded in the Object, so 516the memory is directly tracked from the iterator to the Object. 517 518It's also possible to use intrusive containers when the objects to be stored can 519have different or unknown size. This allows storing base and derived objects 520in the same container, as shown in the following example: 521 522[import ../example/doc_window.cpp] 523[doc_window_code] 524 525Due to certain properties of intrusive containers 526they are often more difficult to use than their STL-counterparts. That's why you 527should avoid them in public interfaces of libraries. Classes to be stored in intrusive 528containers must change their implementation to store the hook and this is not always 529possible or desirable. 530 531[endsect] 532 533[section:concepts_summary Concept summary] 534 535Here is a small summary of the basic concepts that will be used in the following 536chapters: 537 538[variablelist Brief Concepts Summary 539[[Node Algorithms][A class containing typedefs and static functions that define 540 basic operations that can be applied to a group of `node`s. It's independent 541 from the node definition and configured using a NodeTraits template 542 parameter that describes the node.]] 543[[Node Traits][A class that stores basic information and operations to insert a node into a group of nodes.]] 544[[Hook][A class that a user must add as a base class or as a member to make the user class compatible with intrusive containers. A Hook encapsulates a `node`]] 545[[Intrusive Container][A class that stores user classes that have the needed hooks. It takes a ValueTraits template parameter as configuration information.]] 546[[Semi-Intrusive Container][Similar to an intrusive container but a semi-intrusive container needs additional memory (e.g. an auxiliary array) to work.]] 547[[Value Traits][A class containing typedefs and operations to obtain the node to be used by Node Algorithms from the user class and the inverse.]] 548] 549 550[endsect] 551 552[section:presenting_containers Presenting Boost.Intrusive containers] 553 554[*Boost.Intrusive] offers a wide range of intrusive containers: 555 556* [*slist]: An intrusive singly linked list. The size overhead is very small 557 for user classes (usually the size of one pointer) but many operations have linear 558 time complexity, so the user must be careful if he wants to avoid performance problems. 559 560* [*list]: A `std::list` like intrusive linked list. The size overhead is quite 561 small for user classes (usually the size of two pointers). Many operations have 562 constant time complexity. 563 564* [*set/multiset/rbtree]: `std::set/std::multiset` like intrusive associative containers 565 based on red-black trees. 566 The size overhead is moderate for user classes (usually the size of three pointers). 567 Many operations have logarithmic time complexity. 568 569* [*avl_set/avl_multiset/avltree]: A `std::set/std::multiset` like intrusive associative 570 containers based on AVL trees. 571 The size overhead is moderate for user classes (usually the size of three pointers). 572 Many operations have logarithmic time complexity. 573 574* [*splay_set/splay_multiset/splaytree]: `std::set/std::multiset` like intrusive associative 575 containers based on splay trees. Splay trees have no constant operations, but they 576 have some interesting caching properties. 577 The size overhead is moderate for user classes (usually the size of three pointers). 578 Many operations have logarithmic time complexity. 579 580* [*sg_set/sg_multiset/sgtree]: A `std::set/std::multiset` like intrusive associative 581 containers based on scapegoat trees. Scapegoat can be configured with the desired 582 balance factor to achieve the desired rebalancing frequency/search time compromise. 583 The size overhead is moderate for user classes (usually the size of three pointers). 584 Many operations have logarithmic time complexity. 585 586[*Boost.Intrusive] also offers semi-intrusive containers: 587 588* [*unordered_set/unordered_multiset]: `std::tr1::unordered_set/std::tr1::unordered_multiset` 589 like intrusive unordered associative containers. 590 The size overhead is moderate for user classes (an average of two pointers per element). 591 Many operations have amortized constant time complexity. 592 593Most of these intrusive containers can be configured with constant or linear time 594size: 595 596* [*Linear time size]: The intrusive container doesn't hold a size member that is 597updated with every insertion/erasure. This implies that the `size()` function doesn't have constant 598time complexity. On the other hand, the container is smaller, and some operations, like 599`splice()` taking a range of iterators in linked lists, have constant time complexity 600instead of linear complexity. 601 602* [*Constant time size]: The intrusive container holds a size member that is updated 603with every insertion/erasure. This implies that the `size()` function has constant time 604complexity. On the other hand, increases the size of the container, and some operations, 605like `splice()` taking a range of iterators, have linear time complexity in linked lists. 606 607To make user classes compatible with these intrusive containers [*Boost.Intrusive] 608offers two types of hooks for each container type: 609 610* [*Base hook]: The hook is stored as a public base class of the user class. 611 612* [*Member hook]: The hook is stored as a public member of the user class. 613 614Apart from that, [*Boost.Intrusive] offers additional features: 615 616* [*Safe mode hooks]: Hook constructor initializes the internal `node` to a well-known 617 safe state and intrusive containers check that state before inserting a value in the 618 container using that hook. When erasing an element from the container, the container 619 puts the `node` of the hook in the safe state again. This allows a safer use mode and it can 620 be used to detect programming errors. It implies a slight performance overhead in some 621 operations and can convert some constant time operations to linear time operations. 622 623* [*Auto-unlink hooks]: The hook destructor removes the object from the container 624 automatically and the user can safely unlink the object from the container without 625 referring to the container. 626 627* [*Non-raw pointers]: If the user wants to use smart pointers instead of raw pointers, 628 [*Boost.Intrusive] hooks can 629 be configured to use any type of pointer. This configuration information is also 630 transmitted to the containers, so all the internal pointers used by intrusive containers 631 configured with these hooks will be smart pointers. As an example, 632 [*Boost.Interprocess] defines a smart pointer compatible with shared memory, 633 called `offset_ptr`. [*Boost.Intrusive] can be configured to use this smart pointer 634 to allow shared memory intrusive containers. 635 636[endsect] 637 638[section:safe_hook Safe hooks] 639 640[section:features Features of the safe mode] 641 642[*Boost.Intrusive] hooks can be configured to operate in safe-link mode. 643The safe mode is activated by default, but it can be also explicitly activated: 644 645[c++] 646 647 //Configuring the safe mode explicitly 648 class Foo : public list_base_hook< link_mode<safe_link> > 649 {}; 650 651With the safe mode the user can detect if the object 652is actually inserted in a container without any external reference. Let's review the basic features of the safe mode: 653 654* Hook's constructor puts the hook in a well-known default state. 655 656* Hook's destructor checks if the hook is in the well-known default state. If not, 657 an assertion is raised. 658 659* Every time an object is inserted in the intrusive container, the container 660 checks if the hook is in the well-known default state. If not, 661 an assertion is raised. 662 663* Every time an object is being erased from the intrusive container, the container 664 puts the erased object in the well-known default state. 665 666With these features, without any external reference the user can know if the object 667has been inserted in a container by calling the `is_linked()` member function. 668If the object is not actually inserted 669in a container, the hook is in the default state, and if it is inserted in a container, the 670hook is not in the default state. 671 672[endsect] 673 674[section:configuring Configuring safe-mode assertions] 675 676By default, all safe-mode assertions raised by [*Boost-Intrusive] hooks 677and containers in are implemented using `BOOST_ASSERT`, which can be configured by 678the user. See [@http://www.boost.org/libs/utility/assert.html] for more 679information about `BOOST_ASSERT`. 680 681`BOOST_ASSERT` is globally configured, so the user might 682want to redefine intrusive safe-mode assertions without modifying the global 683`BOOST_ASSERT`. This can be achieved redefining the following macros: 684 685* `BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT`: This assertion will be 686 used in insertion functions of the intrusive containers to check that 687 the hook of the value to be inserted is default constructed. 688* `BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT`: This assertion will be 689 used in hooks' destructors to check that the hook is in a default state. 690 691If any of these macros is not redefined, the assertion will default to `BOOST_ASSERT`. 692If `BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT` or `BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT` 693is defined and the programmer needs to include a file to configure that assertion, it can define 694`BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT_INCLUDE` or `BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT_INCLUDE` 695with the name of the file to include: 696 697[c++] 698 699 #define BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT MYASSERT 700 #define BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT_INCLUDE <myassert.h> 701 702[endsect] 703 704[endsect] 705 706[section:auto_unlink_hooks Auto-unlink hooks] 707 708[section:auto_unlink_hooks_what What's an auto-unlink hook?] 709 710[*Boost.Intrusive] offers additional hooks with unique features: 711 712* When the destructor of the hook is called, the hook checks if the node is inserted 713 in a container. If so, the hook removes the node from the container. 714* The hook has a member function called `unlink()` that can be used to unlink the 715 node from the container at any time, without having any reference to the container, 716 if the user wants to do so. 717 718These hooks have exactly the same size overhead as their analog non auto-unlinking 719hooks, but they have a restriction: they can only be used with 720[link intrusive.presenting_containers non-constant time size containers]. 721There is a reason for this: 722 723* Auto-unlink hooks don't store any reference to the container where they are inserted. 724* Only containers with non constant-time `size()` allow removing an object from the container 725 without referring to the container. 726 727This auto-unlink feature is useful in certain applications 728but it must be used [*very carefully]: 729 730* If several threads are using the same container the destructor of the auto-unlink 731 hook will be called without any thread synchronization so removing the object is 732 thread-unsafe. 733 734* Container contents change silently without modifying the container directly. 735 This can lead to surprising effects. 736 737These auto-unlink hooks have also safe-mode properties: 738 739* Hooks' constructors put the hook in a well-known default state. 740 741* Every time an object is inserted in the intrusive container, the container 742 checks if the hook is in the well-known default state. If not, 743 an assertion is raised. 744 745* Every time an object is erased from an intrusive container, the container 746 puts the erased object in the well-known default state. 747 748[endsect] 749 750[section:auto_unlink_hooks_example Auto-unlink hook example] 751 752Let's see an example of an auto-unlink hook: 753 754[import ../example/doc_auto_unlink.cpp] 755[doc_auto_unlink_code] 756 757[endsect] 758 759[section:auto_unlink_and_constant_time Auto-unlink hooks and containers with constant-time `size()`] 760 761As explained, [*Boost.Intrusive] auto-unlink hooks are incompatible with containers 762that have constant-time `size()`, so if you try to define such container with an 763auto-unlink hook's value_traits, you will get a static assertion: 764 765[c++] 766 767 #include <boost/intrusive/list.hpp> 768 769 using boost::intrusive; 770 771 struct MyTag; 772 773 class MyClass : public list_base_hook< link_mode<auto_unlink> > 774 {/**/}; 775 776 list <MyClass, constant_time_size<true> > bad_list; 777 778 int main() 779 { 780 bad_list list; 781 return 0; 782 } 783 784leads to an error similar to: 785 786[pre 787 error : use of undefined type 'boost::STATIC_ASSERTION_FAILURE<false>' 788] 789 790Pointing to code like this: 791 792[c++] 793 794 //Constant-time size is incompatible with auto-unlink hooks! 795 BOOST_STATIC_ASSERT(!(constant_time_size && ((int)value_traits::link_mode == (int)auto_unlink))); 796 797This way, there is no way to compile a program if you try to use auto-unlink hooks 798in constant-time size containers. 799 800[endsect] 801 802[endsect] 803 804[section:slist Intrusive singly linked list: slist] 805 806[classref boost::intrusive::slist slist] is the simplest intrusive container of 807[*Boost.Intrusive]: a singly linked list. The memory overhead 808it imposes is 1 pointer per node. The size of an empty, non constant-time size 809[classref boost::intrusive::slist slist] is the size of 1 pointer. This 810lightweight memory overhead comes with drawbacks, though: many operations have 811linear time complexity, even some that usually are constant time, like 812[classref boost::intrusive::slist::swap swap]. [classref boost::intrusive::slist slist] 813only provides forward iterators. 814 815For most cases, a doubly linked list is preferable because it offers more 816constant-time functions with a slightly bigger size overhead. 817However, for some applications like 818constructing more elaborate containers, singly linked lists are essential 819because of their low size overhead. 820 821[section:slist_hooks slist hooks] 822 823Like the rest of [*Boost.Intrusive] containers, 824[classref boost::intrusive::slist slist] has two hook types: 825 826[c++] 827 828 template <class ...Options> 829 class slist_base_hook; 830 831* [classref boost::intrusive::slist_base_hook slist_base_hook]: 832 the user class derives publicly from 833 [classref boost::intrusive::slist_base_hook slist_base_hook] to make 834 it [classref boost::intrusive::slist slist]-compatible. 835 836[c++] 837 838 template <class ...Options> 839 class slist_member_hook; 840 841* [classref boost::intrusive::slist_member_hook slist_member_hook]: 842 the user class contains a public 843 [classref boost::intrusive::slist_member_hook slist_member_hook] to make 844 it [classref boost::intrusive::slist slist]-compatible. 845 846[classref boost::intrusive::slist_base_hook slist_base_hook] and 847[classref boost::intrusive::slist_member_hook slist_member_hook] 848receive the same options explained in 849the section [link intrusive.usage How to use Boost.Intrusive]: 850 851* [*`tag<class Tag>`] (for base hooks only): This argument serves as a tag, 852 so you can derive from more than one slist hook. 853 Default: `tag<default_tag>`. 854 855* [*`link_mode<link_mode_type LinkMode>`]: The linking policy. 856 Default: `link_mode<safe_link>`. 857 858* [*`void_pointer<class VoidPointer>`]: The pointer type to be used 859 internally in the hook and propagated to the container. 860 Default: `void_pointer<void*>`. 861 862[endsect] 863 864[section:slist_container slist container] 865 866[c++] 867 868 template <class T, class ...Options> 869 class slist; 870 871[classref boost::intrusive::slist slist] receives the options explained in 872the section [link intrusive.usage How to use Boost.Intrusive]: 873 874* [*`base_hook<class Hook>`] / [*`member_hook<class T, class Hook, Hook T::* PtrToMember>`] / 875 [*`value_traits<class ValueTraits>`]: To specify the hook type or value traits used 876 to configure the container. (To learn about value traits go to the section 877 [link intrusive.value_traits Containers with custom ValueTraits].) 878 879* [*`constant_time_size<bool Enabled>`]: To activate the constant-time `size()` operation. 880 Default: `constant_time_size<true>` 881 882* [*`size_type<typename SizeType>`]: To specify the type that will be used to store the size 883 of the container. Default: `size_type<std::size_t>`. 884 885[classref boost::intrusive::slist slist] can receive additional options: 886 887* [*`linear<bool Enable>`]: the singly linked list is implemented as a 888 null-terminated list instead of a circular list. This allows `O(1)` swap, 889 but losses some operations like `container_from_end_iterator`. 890* [*`cache_last<bool Enable>`]: `slist` also stores a pointer to the 891 last element of the singly linked list. This allows `O(1)` swap, 892 `splice_after(iterator, slist &)` and makes the list offer new functions 893 like `push_back(reference)` and `back()`. Logically, the size an empty list is 894 increased in `sizeof(void_pointer)` and the cached last node pointer must 895 be updated in every operation, and that might incur in a slight performance impact. 896 897`auto_unlink` hooks are not usable if `linear<true>` and/or `cache_last<true>` options are 898used. If `auto_unlink` hooks are used and those options are specified, a static 899assertion will be raised. 900 901[endsect] 902 903[section:slist_example Example] 904 905Now let's see a small example using both hooks: 906 907[import ../example/doc_slist.cpp] 908[doc_slist_code] 909 910[endsect] 911 912[endsect] 913 914[section:list Intrusive doubly linked list: list] 915 916[classref boost::intrusive::list list] is a doubly linked list. The memory overhead 917it imposes is 2 pointers per node. An empty, non constant-time size [classref boost::intrusive::list list] 918also has the size of 2 pointers. [classref boost::intrusive::list list] 919has many more constant-time operations than [classref boost::intrusive::slist slist] 920and provides a bidirectional iterator. It is recommended to use 921[classref boost::intrusive::list list] instead of 922[classref boost::intrusive::slist slist] if the size overhead is acceptable: 923 924[section:list_hooks list hooks] 925 926Like the rest of [*Boost.Intrusive] containers, 927[classref boost::intrusive::list list] has two hook types: 928 929[c++] 930 931 template <class ...Options> 932 class list_base_hook; 933 934* [classref boost::intrusive::list_base_hook list_base_hook]: the user class 935 derives publicly from [classref boost::intrusive::list_base_hook list_base_hook] 936 to make it [classref boost::intrusive::list list]-compatible. 937 938[c++] 939 940 template <class ...Options> 941 class list_member_hook; 942 943* [classref boost::intrusive::list_member_hook list_member_hook]: 944 the user class contains a public 945 [classref boost::intrusive::list_member_hook list_member_hook] to make 946 it [classref boost::intrusive::list list]-compatible. 947 948[classref boost::intrusive::list_base_hook list_base_hook] and 949[classref boost::intrusive::list_member_hook list_member_hook] receive 950the same options explained in the section 951[link intrusive.usage How to use Boost.Intrusive]: 952 953* [*`tag<class Tag>`] (for base hooks only): This argument serves as a tag, 954 so you can derive from more than one list hook. 955 Default: `tag<default_tag>`. 956 957* [*`link_mode<link_mode_type LinkMode>`]: The linking policy. 958 Default: `link_mode<safe_link>`. 959 960* [*`void_pointer<class VoidPointer>`]: The pointer type to be used 961 internally in the hook and propagated to the container. 962 Default: `void_pointer<void*>`. 963 964[endsect] 965 966[section:list_container list container] 967 968[c++] 969 970 template <class T, class ...Options> 971 class list; 972 973[classref boost::intrusive::list list] receives the same options explained in 974the section [link intrusive.usage How to use Boost.Intrusive]: 975 976* [*`base_hook<class Hook>`] / [*`member_hook<class T, class Hook, Hook T::* PtrToMember>`] / 977 [*`value_traits<class ValueTraits>`]: To specify the hook type or value traits used 978 to configure the container. (To learn about value traits go to the section 979 [link intrusive.value_traits Containers with custom ValueTraits].) 980 981* [*`constant_time_size<bool Enabled>`]: To activate the constant-time `size()` operation. 982 Default: `constant_time_size<true>` 983 984* [*`size_type<typename SizeType>`]: To specify the type that will be used to store the size 985 of the container. Default: `size_type<std::size_t>` 986 987[endsect] 988 989[section:list_example Example] 990 991Now let's see a small example using both hooks: 992 993[import ../example/doc_list.cpp] 994[doc_list_code] 995 996[endsect] 997 998[endsect] 999 1000[section:set_multiset Intrusive associative containers: set, multiset, rbtree] 1001 1002[*Boost.Intrusive] also offers associative containers that can be very useful 1003when creating more complex associative containers, like containers maintaining 1004one or more indices with different sorting semantics. Boost.Intrusive associative 1005containers, like most STL associative container implementations are based on 1006red-black trees. 1007 1008The memory overhead of these containers is usually 3 pointers and a bit (with 1009alignment issues, this means 3 pointers and an integer). 1010This size can be reduced to 3 pointers if pointers have even alignment 1011(which is usually true in most systems). 1012 1013An empty, non constant-time size [classref boost::intrusive::set set], 1014[classref boost::intrusive::multiset multiset] or 1015[classref boost::intrusive::rbtree rbtree] 1016has also the size of 3 pointers and an integer (3 pointers when optimized for size). 1017These containers have logarithmic complexity in many 1018operations like 1019searches, insertions, erasures, etc. [classref boost::intrusive::set set] and 1020[classref boost::intrusive::multiset multiset] are the 1021intrusive equivalents of standard `std::set` and `std::multiset` containers. 1022 1023[classref boost::intrusive::rbtree rbtree] is a superset of 1024[classref boost::intrusive::set set] and 1025[classref boost::intrusive::multiset multiset] containers that offers 1026functions to insert unique and multiple keys. 1027 1028[section:set_multiset_hooks set, multiset and rbtree hooks] 1029 1030[classref boost::intrusive::set set], 1031[classref boost::intrusive::multiset multiset] and 1032[classref boost::intrusive::rbtree rbtree] share the same hooks. 1033This is an advantage, because the same 1034user type can be inserted first in a [classref boost::intrusive::multiset multiset] 1035and after that in [classref boost::intrusive::set set] without 1036changing the definition of the user class. 1037 1038[c++] 1039 1040 template <class ...Options> 1041 class set_base_hook; 1042 1043* [classref boost::intrusive::set_base_hook set_base_hook]: 1044 the user class derives publicly from 1045 [classref boost::intrusive::set_base_hook set_base_hook] to make 1046 it [classref boost::intrusive::set set]/[classref boost::intrusive::multiset multiset]-compatible. 1047 1048[c++] 1049 1050 template <class ...Options> 1051 class set_member_hook; 1052 1053* [classref boost::intrusive::set_member_hook set_member_hook]: 1054 the user class contains a public 1055 [classref boost::intrusive::set_member_hook set_member_hook] to make 1056 it [classref boost::intrusive::set set]/[classref boost::intrusive::multiset multiset]-compatible. 1057 1058[classref boost::intrusive::set_base_hook set_base_hook] and 1059[classref boost::intrusive::set_member_hook set_member_hook] receive 1060the same options explained in the section 1061[link intrusive.usage How to use Boost.Intrusive] plus a size optimization option: 1062 1063* [*`tag<class Tag>`] (for base hooks only): This argument serves as a tag, 1064 so you can derive from more than one base hook. 1065 Default: `tag<default_tag>`. 1066 1067* [*`link_mode<link_mode_type LinkMode>`]: The linking policy. 1068 Default: `link_mode<safe_link>`. 1069 1070* [*`void_pointer<class VoidPointer>`]: The pointer type to be used 1071 internally in the hook and propagated to the container. 1072 Default: `void_pointer<void*>`. 1073 1074* [*`optimize_size<bool Enable>`]: The hook will be optimized for size 1075 instead of speed. The hook will embed the color bit of the red-black 1076 tree node in the parent pointer if pointer alignment is even. 1077 In some platforms, optimizing the size might reduce speed performance a bit 1078 since masking operations will be needed to access parent pointer and color attributes, 1079 in other platforms this option improves performance due to improved memory locality. 1080 Default: `optimize_size<false>`. 1081 1082[endsect] 1083 1084[section:set_multiset_containers set, multiset and rbtree containers] 1085 1086[c++] 1087 1088 template <class T, class ...Options> 1089 class set; 1090 1091 template <class T, class ...Options> 1092 class multiset; 1093 1094 template <class T, class ...Options> 1095 class rbtree; 1096 1097These containers receive the same options explained in the section 1098[link intrusive.usage How to use Boost.Intrusive]: 1099 1100* [*`base_hook<class Hook>`] / [*`member_hook<class T, class Hook, Hook T::* PtrToMember>`] / 1101 [*`value_traits<class ValueTraits>`]: To specify the hook type or value traits used 1102 to configure the container. (To learn about value traits go to the section 1103 [link intrusive.value_traits Containers with custom ValueTraits].) 1104 1105* [*`constant_time_size<bool Enabled>`]: To activate the constant-time `size()` operation. 1106 Default: `constant_time_size<true>` 1107 1108* [*`size_type<typename SizeType>`]: To specify the type that will be used to store the size 1109 of the container. Default: `size_type<std::size_t>` 1110 1111And they also can receive an additional option: 1112 1113* [*`compare<class Compare>`]: Comparison function for the objects to be inserted 1114 in containers. The comparison functor must induce a strict weak ordering. 1115 Default: `compare< std::less<key_type> >` 1116 1117* [*`key_of_value<class KeyOfValueFunctionObject>`]: A function object that will 1118 define the `key_type` of the value type to be stored. This type will allow a map-like interface. See 1119 [link intrusive.map_multimap Map and multimap-like interface with set and multiset] 1120 for details. Default: `key_type` is equal to `value_type` (set-like interface). 1121 1122[endsect] 1123 1124[section:set_multiset_example Example] 1125 1126Now let's see a small example using both hooks and both containers: 1127 1128[import ../example/doc_set.cpp] 1129[doc_set_code] 1130 1131[endsect] 1132 1133[endsect] 1134 1135[section:unordered_set_unordered_multiset Semi-Intrusive unordered associative containers: unordered_set, unordered_multiset] 1136 1137[*Boost.Intrusive] also offers hashed containers that can be very useful to implement 1138fast-lookup containers. These containers 1139([classref boost::intrusive::unordered_set unordered_set] and [classref boost::intrusive::unordered_multiset unordered_multiset]) 1140are semi-intrusive containers: they need additional memory apart from the hook 1141stored in the `value_type`. This additional 1142memory must be passed in the constructor of the container. 1143 1144Unlike C++ TR1 unordered associative containers (which are also hashed containers), 1145the contents of these semi-intrusive containers are not rehashed to maintain a 1146load factor: that would require memory management and intrusive containers don't 1147implement any memory management at all. However, the user can request an explicit 1148rehashing passing a new bucket array. 1149This also offers an additional guarantee over TR1 unordered associative containers: 1150[*iterators are not invalidated when inserting an element] in the container. 1151 1152As with TR1 unordered associative containers, rehashing invalidates iterators, 1153changes ordering between elements and changes which buckets elements appear in, 1154but does not invalidate pointers or references to elements. 1155 1156Apart from expected hash and equality function objects, [*Boost.Intrusive] unordered 1157associative containers' constructors take an argument specifying an auxiliary 1158bucket vector to be used by the container. 1159 1160[section:unordered_set_unordered_multiset_performance unordered_set and unordered_multiset performance notes] 1161 1162The size overhead for a hashed container is moderate: 1 pointer per value plus 1163a bucket array per container. The size of an element of the bucket array 1164is usually one pointer. To obtain a good performance hashed container, 1165the bucket length is usually the same as the number of elements that the 1166container contains, so a well-balanced hashed container (`bucket_count()` is 1167equal to `size()` ) will have an equivalent overhead of two pointers per element. 1168 1169An empty, non constant-time size [classref boost::intrusive::unordered_set unordered_set] or 1170[classref boost::intrusive::unordered_multiset unordered_multiset] 1171has also the size of `bucket_count()` pointers. 1172 1173Insertions, erasures, and searches, have amortized constant-time complexity in 1174hashed containers. However, some worst-case guarantees are linear. See 1175[classref boost::intrusive::unordered_set unordered_set] or 1176[classref boost::intrusive::unordered_multiset unordered_multiset] for complexity guarantees 1177of each operation. 1178 1179[*Be careful with non constant-time size hashed containers]: some operations, like 1180`empty()`, have linear complexity, unlike other [*Boost.Intrusive] containers. 1181 1182[endsect] 1183 1184[section:unordered_set_unordered_multiset_hooks unordered_set and unordered_multiset hooks] 1185 1186[classref boost::intrusive::unordered_set unordered_set] and [classref boost::intrusive::unordered_multiset unordered_multiset] share the same hooks. This is an advantage, because the same 1187user type can be inserted first in a [classref boost::intrusive::unordered_multiset unordered_multiset] and after that in [classref boost::intrusive::unordered_set unordered_set] without 1188changing the definition of the user class. 1189 1190[c++] 1191 1192 template <class ...Options> 1193 class unordered_set_base_hook; 1194 1195* [classref boost::intrusive::unordered_set_base_hook unordered_set_base_hook]: 1196 the user class derives publicly from 1197 [classref boost::intrusive::unordered_set_base_hook unordered_set_base_hook] to make 1198 it [classref boost::intrusive::unordered_set unordered_set]/[classref boost::intrusive::unordered_multiset unordered_multiset]-compatible. 1199 1200[c++] 1201 1202 template <class ...Options> 1203 class unordered_set_member_hook; 1204 1205* [classref boost::intrusive::unordered_set_member_hook unordered_set_member_hook]: 1206 the user class contains a public 1207 [classref boost::intrusive::unordered_set_member_hook unordered_set_member_hook] to make 1208 it [classref boost::intrusive::unordered_set unordered_set]/[classref boost::intrusive::unordered_multiset unordered_multiset]-compatible. 1209 1210[classref boost::intrusive::unordered_set_base_hook unordered_set_base_hook] and 1211[classref boost::intrusive::unordered_set_member_hook unordered_set_member_hook] receive 1212the same options explained in the section 1213[link intrusive.usage How to use Boost.Intrusive]: 1214 1215* [*`tag<class Tag>`] (for base hooks only): This argument serves as a tag, 1216 so you can derive from more than one base hook. 1217 Default: `tag<default_tag>`. 1218 1219* [*`link_mode<link_mode_type LinkMode>`]: The linking policy. 1220 Default: `link_mode<safe_link>`. 1221 1222* [*`void_pointer<class VoidPointer>`]: The pointer type to be used 1223 internally in the hook and propagated to the container. 1224 Default: `void_pointer<void*>`. 1225 1226Apart from them, these hooks offer additional options: 1227 1228* [*`store_hash<bool Enabled>`]: This option reserves additional space in 1229 the hook to store the hash value of the object once it's introduced in the 1230 container. When this option is used, the unordered container will store 1231 the calculated hash value in the hook and rehashing operations won't need 1232 to recalculate the hash of the value. 1233 This option will improve the performance of unordered containers when 1234 rehashing is frequent or hashing the value is a slow operation. 1235 Default: `store_hash<false>`. 1236 1237* [*`optimize_multikey<bool Enabled>`]: This option reserves additional space in 1238 the hook that will be used to group equal elements in unordered multisets, 1239 improving significantly the performance when many equal values are inserted 1240 in these containers. Default: `optimize_multikey<false>`. 1241 1242[endsect] 1243 1244[section:unordered_set_unordered_multiset_containers unordered_set and unordered_multiset containers] 1245 1246[c++] 1247 1248 template<class T, class ...Options> 1249 class unordered_set; 1250 1251 template<class T, class ...Options> 1252 class unordered_multiset; 1253 1254As mentioned, unordered containers need an auxiliary array to work. [*Boost.Intrusive] 1255unordered containers receive this auxiliary array packed in a type called `bucket_traits` 1256(which can be also customized by a container option). All unordered containers receive 1257a `bucket_traits` object in their constructors. The default `bucket_traits` class 1258is initialized with a pointer to an array of buckets and its size: 1259 1260[c++] 1261 1262 #include <boost/intrusive/unordered_set.hpp> 1263 1264 using namespace boost::intrusive; 1265 1266 struct MyClass : public unordered_set_base_hook<> 1267 {}; 1268 1269 typedef unordered_set<MyClass>::bucket_type bucket_type; 1270 typedef unordered_set<MyClass>::bucket_traits bucket_traits; 1271 1272 int main() 1273 { 1274 bucket_type buckets[100]; 1275 unordered_set<MyClass> uset(bucket_traits(buckets, 100)); 1276 return 0; 1277 } 1278 1279Each hashed container needs [*its own bucket traits], that is, [*its own 1280bucket vector]. Two hashed containers 1281[*can't] share the same `bucket_type` elements. The bucket array [*must] be 1282destroyed [*after] the container using it is destroyed, otherwise, the result 1283is undefined. 1284 1285[classref boost::intrusive::unordered_set unordered_set] and 1286[classref boost::intrusive::unordered_multiset unordered_multiset] 1287receive the same options explained in the section 1288[link intrusive.usage How to use Boost.Intrusive]: 1289 1290* [*`base_hook<class Hook>`] / [*`member_hook<class T, class Hook, Hook T::* PtrToMember>`] / 1291 [*`value_traits<class ValueTraits>`]: To specify the hook type or value traits used 1292 to configure the container. (To learn about value traits go to the section 1293 [link intrusive.value_traits Containers with custom ValueTraits].) 1294 1295* [*`constant_time_size<bool Enabled>`]: To activate the constant-time `size()` operation. 1296 Default: `constant_time_size<true>` 1297 1298* [*`size_type<typename SizeType>`]: To specify the type that will be used to store the size 1299 of the container. Default: `size_type<std::size_t>` 1300 1301And they also can receive additional options: 1302 1303* [*`equal<class Equal>`]: Equality function for the objects to be inserted 1304 in containers. Default: `equal< std::equal_to<T> >` 1305 1306* [*`hash<class Hash>`]: Hash function to be used in the container. 1307 Default: `hash< boost::hash<T> >` 1308 1309* [*`bucket_traits<class BucketTraits>`]: A type that wraps the bucket vector to 1310 be used by the unordered container. Default: a type initialized by the address 1311 and size of a bucket array and stores both variables internally. 1312 1313* [*`power_2_buckets<bool Enabled>`]: The user guarantees that only bucket arrays 1314 with power of two length will be used. The container will then use masks instead of modulo 1315 operations to obtain the bucket number from the hash value. Masks are faster than 1316 modulo operations and for some applications modulo operations can impose 1317 a considerable overhead. In debug mode an assertion will be raised if the user 1318 provides a bucket length that is not power of two. 1319 Default: `power_2_buckets<false>`. 1320 1321* [*`cache_begin<bool Enabled>`]: 1322 [*Note: this option is not compatible with `auto_unlink` hooks]. 1323 Due to its internal structure, finding the first 1324 element of an unordered container (`begin()` operation) is 1325 amortized constant-time. It's possible to speed up `begin()` and other operations 1326 related to it (like `clear()`) if the container caches internally the position 1327 of the first element. This imposes the overhead of one pointer to the size 1328 of the container. Default: `cache_begin<false>`. 1329 1330* [*`compare_hash<bool Enabled>`]: 1331 [*Note: this option requires `store_hash<true>` option in the hook]. 1332 When the comparison function is expensive, 1333 (e.g. strings with a long common predicate) sometimes (specially when the 1334 load factor is high or we have many equivalent elements in an 1335 [classref boost::intrusive::unordered_multiset unordered_multiset] and 1336 no `optimize_multikey<>` is activated in the hook) 1337 the equality function is a performance problem. Two equal values must have 1338 equal hashes, so comparing the hash values of two elements before using the 1339 comparison functor can speed up some implementations. 1340 1341* [*`incremental<bool Enabled>`]: Activates incremental hashing (also known as Linear Hashing). 1342 This option implies `power_2_buckets<true>` and the container will require power of two buckets. 1343 For more information on incremental hashing, see 1344 [@http://en.wikipedia.org/wiki/Linear_hashing `Linear hash` on Wikipedia] 1345 Default: `incremental<false>` 1346 1347* [*`key_of_value<class KeyOfValueFunctionObject>`]: A function object that will 1348 define the `key_type` of the value type to be stored. This type will allow a map-like interface. See 1349 [link intrusive.map_multimap Map and multimap-like interface with set and multiset] 1350 for details. Default: `key_type` is equal to `value_type` (set-like interface). 1351 1352[endsect] 1353 1354[section:unordered_set_unordered_multiset_example Example] 1355 1356Now let's see a small example using both hooks and both containers: 1357 1358[import ../example/doc_unordered_set.cpp] 1359[doc_unordered_set_code] 1360 1361[endsect] 1362 1363[section:custom_bucket_traits Custom bucket traits] 1364 1365Instead of using the default `bucket_traits` class to store the bucket array, a user 1366can define his own class to store the bucket array using the [*['bucket_traits<>]] 1367option. A user-defined bucket-traits must fulfill the following interface: 1368 1369[c++] 1370 1371 class my_bucket_traits 1372 { 1373 bucket_ptr bucket_begin(); 1374 const_bucket_ptr bucket_begin() const; 1375 std::size_t bucket_count() const; 1376 }; 1377 1378 1379The following bucket traits just stores a pointer to the bucket 1380array but the size is a compile-time constant. Note the use of the auxiliary 1381[classref boost::intrusive::unordered_bucket unordered_bucket] and 1382[classref boost::intrusive::unordered_bucket_ptr unordered_bucket_ptr] 1383utilities to obtain the type of the bucket and its pointer before defining 1384the unordered container: 1385 1386[import ../example/doc_bucket_traits.cpp] 1387[doc_bucket_traits] 1388 1389[endsect] 1390 1391[endsect] 1392 1393[section:map_multimap Map and multimap-like interface for associative containers] 1394 1395Implementing map-like intrusive containers is not a trivial task as 1396STL's `std::map` and `std::multimap` containers store copies of a `value_type` which is defined 1397as `std::pair<const key_type, mapped_type>`. In order to reproduce this interface in [*Boost.Intrusive] 1398it shall require that objects stored in the intrusive containers contain that `std::pair` member with 1399`pair.first` hardcoded as the key part and `pair.second` hardcoded as the `mapped_type`, which 1400is limiting and also not very useful in practice. Any intrusive associative container can be used like 1401a map using [link intrusive.advanced_lookups_insertions advanced lookup and insertions] and the user 1402can change the key type in each lookup/insertion check call. 1403 1404On the other hand, in many cases containers are indexed by a well-known key type, and the user is forced 1405to write some repetitive code using advanced lookup and insertions. [*Boost.Intrusive] 1406associative containers offer an alternative to build a useful map-like lookup interfaces 1407without forcing users to define `value_type`s containing `std::pair`-like classes. 1408The option is called [classref boost::intrusive::key_of_value]. 1409 1410If a user specifies that option when defining a `set/multiset` intrusive container, it specifies a function object 1411that will tell the container which is the type of the ['key] that `value_type` holds and how to obtain it. This 1412function object must be: 1413 1414* Lightweight to copy. 1415* Default constructible (when the container constructor overload requires it). 1416* It shall define: 1417 * A `type` member that defines the type of the key 1418 * A member function that returns the key derived a `value_type`, either by value or by const-reference. 1419 1420Let's see an example of how a set can be configured as a map indexed by an integer stored in the `value_type`: 1421 1422[import ../example/doc_map.cpp] 1423[doc_map_code] 1424 1425[endsect] 1426 1427[section:avl_set_multiset Intrusive avl tree based associative containers: avl_set, avl_multiset and avltree] 1428 1429Similar to red-black trees, AVL trees are balanced binary trees. 1430AVL trees are often compared with red-black trees because they support the same set of operations 1431and because both take O(log n) time for basic operations. 1432AVL trees are more rigidly balanced than Red-Black trees, leading to slower insertion and 1433removal but faster retrieval, so AVL trees perform better 1434than red-black trees for lookup-intensive applications. 1435 1436[*Boost.Intrusive] offers 3 containers based on avl trees: 1437[classref boost::intrusive::avl_set avl_set], 1438[classref boost::intrusive::avl_multiset avl_multiset] and 1439[classref boost::intrusive::avltree avltree]. The first two are similar to 1440[classref boost::intrusive::set set] or 1441[classref boost::intrusive::multiset multiset] and the latter is a generalization 1442that offers functions both to insert unique and multiple keys. 1443 1444The memory overhead of these containers with Boost.Intrusive hooks is usually 3 1445pointers and 2 bits (due to alignment, this usually means 3 pointers plus an integer). 1446This size can be reduced to 3 pointers if pointers have 4 byte alignment 1447(which is usually true in 32 bit systems). 1448 1449An empty, non constant-time size [classref boost::intrusive::avl_set avl_set], 1450[classref boost::intrusive::avl_multiset avl_multiset] or 1451[classref boost::intrusive::avltree avltree] 1452also has a size of 3 pointers and an integer (3 pointers when optimized for size). 1453 1454[section:avl_set_multiset_hooks avl_set, avl_multiset and avltree hooks] 1455 1456[classref boost::intrusive::avl_set avl_set], 1457[classref boost::intrusive::avl_multiset avl_multiset] and 1458[classref boost::intrusive::avltree avltree] 1459share the same hooks. 1460 1461[c++] 1462 1463 template <class ...Options> 1464 class avl_set_base_hook; 1465 1466* [classref boost::intrusive::avl_set_base_hook avl_set_base_hook]: 1467 the user class derives publicly from this class to make 1468 it compatible with avl tree based containers. 1469 1470[c++] 1471 1472 template <class ...Options> 1473 class avl_set_member_hook; 1474 1475* [classref boost::intrusive::set_member_hook set_member_hook]: 1476 the user class contains a public member of this class to make 1477 it compatible with avl tree based containers. 1478 1479[classref boost::intrusive::avl_set_base_hook avl_set_base_hook] and 1480[classref boost::intrusive::avl_set_member_hook avl_set_member_hook] receive 1481the same options explained in the section 1482[link intrusive.usage How to use Boost.Intrusive] plus an option to optimize 1483the size of the node: 1484 1485* [*`tag<class Tag>`] (for base hooks only): This argument serves as a tag, 1486 so you can derive from more than one base hook. 1487 Default: `tag<default_tag>`. 1488 1489* [*`link_mode<link_mode_type LinkMode>`]: The linking policy. 1490 Default: `link_mode<safe_link>`. 1491 1492* [*`void_pointer<class VoidPointer>`]: The pointer type to be used 1493 internally in the hook and propagated to the container. 1494 Default: `void_pointer<void*>`. 1495 1496* [*`optimize_size<bool Enable>`]: The hook will be optimized for size 1497 instead of speed. The hook will embed the balance bits of the AVL 1498 tree node in the parent pointer if pointer alignment is multiple of 4. 1499 In some platforms, optimizing the size might reduce speed performance a bit 1500 since masking operations will be needed to access parent pointer and balance factor attributes, 1501 in other platforms this option improves performance due to improved memory locality. 1502 Default: `optimize_size<false>`. 1503 1504[endsect] 1505 1506[section:set_multiset_containers avl_set, avl_multiset and avltree containers] 1507 1508[c++] 1509 1510 template <class T, class ...Options> 1511 class avl_set; 1512 1513 template <class T, class ...Options> 1514 class avl_multiset; 1515 1516 template <class T, class ...Options> 1517 class avltree; 1518 1519These containers receive the same options explained in the section 1520[link intrusive.usage How to use Boost.Intrusive]: 1521 1522* [*`base_hook<class Hook>`] / [*`member_hook<class T, class Hook, Hook T::* PtrToMember>`] / 1523 [*`value_traits<class ValueTraits>`]: To specify the hook type or value traits used 1524 to configure the container. (To learn about value traits go to the section 1525 [link intrusive.value_traits Containers with custom ValueTraits].) 1526 1527* [*`constant_time_size<bool Enabled>`]: To activate the constant-time `size()` operation. 1528 Default: `constant_time_size<true>` 1529 1530* [*`size_type<typename SizeType>`]: To specify the type that will be used to store the size 1531 of the container. Default: `size_type<std::size_t>` 1532 1533And they also can receive an additional option: 1534 1535* [*`compare<class Compare>`]: Comparison function for the objects to be inserted 1536 in containers. The comparison functor must induce a strict weak ordering. 1537 Default: `compare< std::less<key_type> >` 1538 1539* [*`key_of_value<class KeyOfValueFunctionObject>`]: A function object that will 1540 define the `key_type` of the value type to be stored. This type will allow a map-like interface. See 1541 [link intrusive.map_multimap Map and multimap-like interface with set and multiset] 1542 for details. Default: `key_type` is equal to `value_type` (set-like interface). 1543 1544[endsect] 1545 1546[section:avl_set_multiset_example Example] 1547 1548Now let's see a small example using both hooks and 1549[classref boost::intrusive::avl_set avl_set]/ 1550[classref boost::intrusive::avl_multiset avl_multiset] 1551containers: 1552 1553[import ../example/doc_avl_set.cpp] 1554[doc_avl_set_code] 1555 1556[endsect] 1557 1558[endsect] 1559 1560[section:splay_set_multiset Intrusive splay tree based associative containers: splay_set, splay_multiset and , splay_tree] 1561 1562C++ associative containers are usually based on red-black tree implementations (e.g.: STL, 1563Boost.Intrusive associative containers). However, there are other interesting data 1564structures that offer some advantages (and also disadvantages). 1565 1566Splay trees are self-adjusting binary search trees used typically in caches, memory 1567allocators and other applications, because splay trees have a "caching effect": recently 1568accessed elements have better access times than elements accessed less frequently. 1569For more information on splay trees see [@http://en.wikipedia.org/wiki/Splay_tree the corresponding Wikipedia entry]. 1570 1571[*Boost.Intrusive] offers 3 containers based on splay trees: 1572[classref boost::intrusive::splay_set splay_set], 1573[classref boost::intrusive::splay_multiset splay_multiset] and 1574[classref boost::intrusive::splaytree splaytree]. The first two are similar to 1575[classref boost::intrusive::set set] or 1576[classref boost::intrusive::multiset multiset] and the latter is a generalization 1577that offers functions both to insert unique and multiple keys. 1578 1579The memory overhead of these containers with Boost.Intrusive hooks is usually 3 pointers. 1580An empty, non constant-time size splay container has also a size of 3 pointers. 1581 1582[section:splay_set_multiset_disadvantages Advantages and disadvantages of splay tree based containers] 1583 1584Splay tree based intrusive containers have logarithmic complexity in many 1585operations like searches, insertions, erasures, etc., but if some elements are 1586more frequently accessed than others, splay trees perform faster searches than equivalent 1587balanced binary trees (such as red-black trees). 1588 1589The caching effect offered by splay trees comes with a cost: the tree must be 1590rebalanced when an element is searched. To maintain const-correctness and thread-safety 1591guarantees, this caching effect is not updated when const versions of 1592search functions like `find()`, `lower_bound()`, `upper_bound()`, `equal_range()`, 1593`count()`... are called. This means that using splay-tree based associative containers as drop-in 1594replacements of [classref boost::intrusive::set set]/ 1595[classref boost::intrusive::multiset multiset], specially for const search functions, 1596might not result in desired performance improvements. 1597 1598If element searches are randomized, the tree will be continuously srebalanced 1599without taking advantage of the cache effect, so splay trees can offer worse 1600performance than other balanced trees for several search patterns. 1601 1602[*Boost.Intrusive] splay associative containers don't use their own hook types but plain Binary search tree hooks. 1603See [link intrusive.bst_hooks Binary search tree hooks: bs_set_base_hook and bs_set_member_hook] section for more 1604information about these hooks. 1605 1606[endsect] 1607 1608[section:set_multiset_containers splay_set, splay_multiset and splaytree containers] 1609 1610[c++] 1611 1612 template <class T, class ...Options> 1613 class splay_set; 1614 1615 template <class T, class ...Options> 1616 class splay_multiset; 1617 1618 template <class T, class ...Options> 1619 class splaytree; 1620 1621These containers receive the same options explained in the section 1622[link intrusive.usage How to use Boost.Intrusive]: 1623 1624* [*`base_hook<class Hook>`] / [*`member_hook<class T, class Hook, Hook T::* PtrToMember>`] / 1625 [*`value_traits<class ValueTraits>`]: To specify the hook type or value traits used 1626 to configure the container. (To learn about value traits go to the section 1627 [link intrusive.value_traits Containers with custom ValueTraits].) 1628 1629* [*`constant_time_size<bool Enabled>`]: To activate the constant-time `size()` operation. 1630 Default: `constant_time_size<true>` 1631 1632* [*`size_type<typename SizeType>`]: To specify the type that will be used to store the size 1633 of the container. Default: `size_type<std::size_t>` 1634 1635And they also can receive an additional option: 1636 1637* [*`compare<class Compare>`]: Comparison function for the objects to be inserted 1638 in containers. The comparison functor must induce a strict weak ordering. 1639 Default: `compare< std::less<key_type> >` 1640 1641* [*`key_of_value<class KeyOfValueFunctionObject>`]: A function object that will 1642 define the `key_type` of the value type to be stored. This type will allow a map-like interface. See 1643 [link intrusive.map_multimap Map and multimap-like interface with set and multiset] 1644 for details. Default: `key_type` is equal to `value_type` (set-like interface). 1645 1646[endsect] 1647 1648[section:splay_set_multiset_example Example] 1649 1650Now let's see a small example using 1651[classref boost::intrusive::splay_set splay_set]/ 1652[classref boost::intrusive::splay_multiset splay_multiset] 1653containers: 1654 1655[import ../example/doc_splay_set.cpp] 1656[doc_splay_set_code] 1657 1658[endsect] 1659 1660[endsect] 1661 1662 1663[section:sg_set_multiset Intrusive scapegoat tree based associative containers: sg_set, sg_multiset and sgtree] 1664 1665A scapegoat tree is a self-balancing binary search tree, that provides worst-case O(log n) 1666lookup time, and O(log n) amortized insertion and deletion time. 1667Unlike other self-balancing binary search trees that provide worst case O(log n) lookup 1668time, scapegoat trees have no additional per-node overhead compared to a regular binary 1669search tree. 1670 1671A binary search tree is said to be weight balanced if half the nodes are on the left 1672of the root, and half on the right. An a-height-balanced tree is defined with defined 1673with the following equation: 1674 1675[*['height(tree) <= log1/a(tree.size())]] 1676 1677* [*['a == 1]]: A tree forming a linked list is considered balanced. 1678* [*['a == 0.5]]: Only a perfectly balanced binary is considered balanced. 1679 1680Scapegoat trees are loosely ['a-height-balanced] so: 1681 1682[*['height(tree) <= log1/a(tree.size()) + 1]] 1683 1684Scapegoat trees support any a between 0.5 and 1. If a is higher, the tree is rebalanced 1685less often, obtaining quicker insertions but slower searches. Lower 1686a values improve search times. Scapegoat-trees implemented in [*Boost.Intrusive] offer the possibility of 1687[*changing a at run-time] taking advantage of the flexibility of scapegoat trees. 1688For more information on scapegoat trees see [@http://en.wikipedia.org/wiki/Scapegoat_tree Wikipedia entry]. 1689 1690Scapegoat trees also have downsides: 1691 1692* They need additional storage of data on the 1693 root (the size of the tree, for example) to achieve logarithmic complexity operations 1694 so it's not possible to offer `auto_unlink` hooks. The size of an empty scapegoat 1695 tree is also considerably increased. 1696 1697* The operations needed to determine if the tree is unbalanced require floating-point 1698 operations like ['log1/a]. If the system has no floating point operations (like some 1699 embedded systems), scapegoat tree operations might become slow. 1700 1701[*Boost.Intrusive] offers 3 containers based on scapegoat trees: 1702[classref boost::intrusive::sg_set sg_set], 1703[classref boost::intrusive::sg_multiset sg_multiset] and 1704[classref boost::intrusive::sgtree sgtree]. The first two are similar to 1705[classref boost::intrusive::set set] or 1706[classref boost::intrusive::multiset multiset] and the latter is a generalization 1707that offers functions both to insert unique and multiple keys. 1708 1709The memory overhead of these containers with Boost.Intrusive hooks is 3 1710pointers. 1711 1712An empty, [classref boost::intrusive::sg_set sg_set], 1713[classref boost::intrusive::sg_multiset sg_multiset] or 1714[classref boost::intrusive::sgtree sgtree] 1715has also the size of 3 pointers, two integers and two floating point values 1716(equivalent to the size of 7 pointers on most systems). 1717 1718[*Boost.Intrusive] scapegoat associative containers don't use their own hook types but plain Binary search tree hooks. 1719See [link intrusive.bst_hooks Binary search tree hooks: bs_set_base_hook and bs_set_member_hook] section for more 1720information about these hooks. 1721 1722[section:sg_set_multiset_containers sg_set, sg_multiset and sgtree containers] 1723 1724[c++] 1725 1726 template <class T, class ...Options> 1727 class sg_set; 1728 1729 template <class T, class ...Options> 1730 class sg_multiset; 1731 1732 template <class T, class ...Options> 1733 class sgtree; 1734 1735These containers receive the same options explained in the section 1736[link intrusive.usage How to use Boost.Intrusive]: 1737 1738* [*`base_hook<class Hook>`] / [*`member_hook<class T, class Hook, Hook T::* PtrToMember>`] / 1739 [*`value_traits<class ValueTraits>`]: To specify the hook type or value traits used 1740 to configure the container. (To learn about value traits go to the section 1741 [link intrusive.value_traits Containers with custom ValueTraits].) 1742 1743* [*`size_type<typename SizeType>`]: To specify the type that will be used to store the size 1744 of the container. Default: `size_type<std::size_t>` 1745 1746And they also can receive additional options: 1747 1748* [*`compare<class Compare>`]: Comparison function for the objects to be inserted 1749 in containers. The comparison functor must induce a strict weak ordering. 1750 Default: `compare< std::less<key_type> >` 1751 1752* [*`floating_point<bool Enable>`]: 1753 When this option is deactivated, the scapegoat tree loses the ability to change 1754 the balance factor a at run-time, but the size of an empty container is reduced 1755 and no floating point operations are performed, normally increasing container 1756 performance. The fixed a factor that is used when this option is activated 1757 is ['1/sqrt(2) ~ 0,70711]. Default: `floating_point<true>` 1758 1759* [*`key_of_value<class KeyOfValueFunctionObject>`]: A function object that will 1760 define the `key_type` of the value type to be stored. This type will allow a map-like interface. See 1761 [link intrusive.map_multimap Map and multimap-like interface with set and multiset] 1762 for details. Default: `key_type` is equal to `value_type` (set-like interface). 1763 1764[endsect] 1765 1766[section:sg_set_multiset_example Example] 1767 1768Now let's see a small example using binary search tree hooks and 1769[classref boost::intrusive::sg_set sg_set]/ 1770[classref boost::intrusive::sg_multiset sg_multiset] 1771containers: 1772 1773[import ../example/doc_sg_set.cpp] 1774[doc_sg_set_code] 1775 1776[endsect] 1777 1778[endsect] 1779 1780 1781[section:treap_set_multiset Intrusive treap based associative containers: treap_set, treap_multiset and treap] 1782 1783The name ['treap] is a mixture of ['tree] and ['heap] indicating that Treaps exhibit the properties of both 1784binary search trees and heaps. A treap is a binary search tree that orders the nodes 1785by a key but also by a priority attribute. The nodes are ordered so that the keys form a binary search tree and 1786the priorities obey the max heap order property. 1787 1788* If v is a left descendant of u, then key[v] < key[u]; 1789* If v is a right descendant of u, then key[v] > key[u]; 1790* If v is a child of u, then priority[v] <= priority[u]; 1791 1792If priorities are non-random, the tree will usually be unbalanced; this worse theoretical average-case 1793behavior may be outweighed by better expected-case behavior, as the most important items will be near the root. 1794This means most important objects will be retrieved faster than less important items and for items keys with equal keys 1795most important objects will be found first. These properties are important for some applications. 1796 1797The priority comparison will be provided just like the key comparison, via a function object that will be 1798stored in the intrusive container. This means that the priority can be stored in the value to be introduced 1799in the treap or computed on flight (via hashing or similar). 1800 1801[*Boost.Intrusive] offers 3 containers based on treaps: 1802[classref boost::intrusive::treap_set treap_set], 1803[classref boost::intrusive::treap_multiset treap_multiset] and 1804[classref boost::intrusive::treap treap]. The first two are similar to 1805[classref boost::intrusive::set set] or 1806[classref boost::intrusive::multiset multiset] and the latter is a generalization 1807that offers functions both to insert unique and multiple keys. 1808 1809The memory overhead of these containers with Boost.Intrusive hooks is 3 1810pointers. 1811 1812An empty, [classref boost::intrusive::treap_set treap_set], 1813[classref boost::intrusive::treap_multiset treap_multiset] or 1814[classref boost::intrusive::treap treap] 1815has also the size of 3 pointers and an integer (supposing empty function objects for key and priority 1816comparison and constant-time size). 1817 1818[*Boost.Intrusive] treap associative containers don't use their own hook types but plain Binary search tree hooks. 1819See [link intrusive.bst_hooks Binary search tree hooks: bs_set_base_hook and bs_set_member_hook] section for more 1820information about these hooks. 1821 1822[section:treap_set_multiset_containers treap_set, treap_multiset and treap containers] 1823 1824[c++] 1825 1826 template <class T, class ...Options> 1827 class treap_set; 1828 1829 template <class T, class ...Options> 1830 class treap_multiset; 1831 1832 template <class T, class ...Options> 1833 class treap; 1834 1835These containers receive the same options explained in the section 1836[link intrusive.usage How to use Boost.Intrusive]: 1837 1838* [*`base_hook<class Hook>`] / [*`member_hook<class T, class Hook, Hook T::* PtrToMember>`] / 1839 [*`value_traits<class ValueTraits>`]: To specify the hook type or value traits used 1840 to configure the container. (To learn about value traits go to the section 1841 [link intrusive.value_traits Containers with custom ValueTraits].) 1842 1843* [*`constant_time_size<bool Enabled>`]: To activate the constant-time `size()` operation. 1844 Default: `constant_time_size<true>` 1845 1846* [*`size_type<typename SizeType>`]: To specify the type that will be used to store the size 1847 of the container. Default: `size_type<std::size_t>` 1848 1849And they also can receive additional options: 1850 1851* [*`compare<class Compare>`]: Comparison function for the objects to be inserted 1852 in containers. The comparison functor must induce a strict weak ordering. 1853 Default: `compare< std::less<key_type> >` 1854 1855* [*`priority_of_value<class PriorityOfValue>`]: A function object 1856 that specifies the type of the priority (`priority_type`) of a treap 1857 container and an operator to obtain it from a value type. 1858 Default: `priority_type` is equal to `value_type` (set-like interface). 1859 1860* [*`priority<class PriorityCompare>`]: Priority Comparison function for the objects to be inserted 1861 in containers. The comparison functor must induce a strict weak ordering. 1862 Default: `priority< priority_compare<priority_type> >` 1863 1864* [*`key_of_value<class KeyOfValueFunctionObject>`]: A function object that will 1865 define the `key_type` of the value type to be stored. This type will allow a map-like interface. See 1866 [link intrusive.map_multimap Map and multimap-like interface with set and multiset] 1867 for details. Default: `key_type` is equal to `value_type` (set-like interface). 1868 1869The default `priority_compare<T>` object function will call an unqualified function `priority_order` 1870passing two constant `T` references as arguments and should return true if the first argument has 1871higher priority (it will be searched faster), inducing strict weak ordering. 1872The function will be found using ADL lookup so that 1873the user just needs to define a `priority_order` function in the same namespace as the class: 1874 1875[c++] 1876 1877 struct MyType 1878 { 1879 friend bool priority_order(const MyType &a, const MyType &b) 1880 {...} 1881 }; 1882 1883or 1884 1885 namespace mytype { 1886 1887 struct MyType{ ... }; 1888 1889 bool priority_order(const MyType &a, const MyType &b) 1890 {...} 1891 1892 } //namespace mytype { 1893 1894[endsect] 1895 1896[section:treap_set_exceptions Exception safety of treap-based intrusive containers] 1897 1898In general, intrusive containers offer strong safety guarantees, but treap containers must deal 1899with two possibly throwing functors (one for value ordering, another for priority ordering). 1900Moreover, treap erasure operations require rotations based on the priority order function and 1901this issue degrades usual `erase(const_iterator)` no-throw guarantee. However, intrusive offers 1902the strongest possible behaviour in these situations. In summary: 1903 1904* If the priority order functor does not throw, treap-based containers, offer exactly the same 1905 guarantees as other tree-based containers. 1906 1907* If the priority order functor throws, treap-based containers offer strong guarantee. 1908 1909[endsect] 1910 1911[section:treap_set_multiset_example Example] 1912 1913Now let's see a small example using binary search tree hooks and 1914[classref boost::intrusive::treap_set treap_set]/ 1915[classref boost::intrusive::treap_multiset treap_multiset] 1916containers: 1917 1918[import ../example/doc_treap_set.cpp] 1919[doc_treap_set_code] 1920 1921[endsect] 1922 1923[endsect] 1924 1925[section:bst_hooks Binary search tree hooks: bs_set_base_hook and bs_set_member_hook] 1926 1927Binary search tree hooks can be used with several tree-like containers that don't 1928need any additional metadata for rebalancing operations. This has many advantages 1929since binary search tree hooks can also be used to insert values in 1930plain binary search tree, splay tree, scapegoat tree, and treap containers. 1931 1932[c++] 1933 1934 template <class ...Options> 1935 class bs_set_base_hook; 1936 1937* [classref boost::intrusive::bs_set_base_hook bs_set_base_hook]: 1938 the user class derives publicly from this class to make 1939 it compatible with the mentioned tree based containers. 1940 1941[c++] 1942 1943 template <class ...Options> 1944 class bs_set_member_hook; 1945 1946* [classref boost::intrusive::bs_set_member_hook bs_set_member_hook]: 1947 the user class contains a public member of this class to make 1948 it compatible with the mentioned tree based containers. 1949 1950[classref boost::intrusive::bs_set_base_hook bs_set_base_hook] and 1951[classref boost::intrusive::bs_set_member_hook bs_set_member_hook] receive 1952the same options explained in the section 1953[link intrusive.usage How to use Boost.Intrusive]: 1954 1955* [*`tag<class Tag>`] (for base hooks only): This argument serves as a tag, 1956 so you can derive from more than one base hook. 1957 Default: `tag<default_tag>`. 1958 1959* [*`link_mode<link_mode_type LinkMode>`]: The linking policy. 1960 Default: `link_mode<safe_link>`. 1961 1962* [*`void_pointer<class VoidPointer>`]: The pointer type to be used 1963 internally in the hook and propagated to the container. 1964 Default: `void_pointer<void*>`. 1965 1966[endsect] 1967 1968[section:advanced_lookups_insertions Advanced lookup and insertion functions for associative containers] 1969 1970[section:advanced_lookups Advanced lookups] 1971 1972[*Boost.Intrusive] associative containers offer an interface similar to STL associative 1973containers. However, STL's ordered and unordered simple associative containers 1974(`std::set`, `std::multiset`, `std::unordered_set` and `std::unordered_multiset`) 1975have some inefficiencies caused by the interface in several search, insertion or erasure functions 1976(`equal_range`, `lower_bound`, `upper_bound`, `find`, `insert`, `erase`...): the user can only operate 1977with `value_type` objects or (starting from C++11), 1978[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3657.htm heterogeneous comparison lookups] 1979which are not flexible enough as `key_compare` shall support the comparison between the provided 1980key and `value_type`, which precludes the use of user-defined comparison objects that can partition the 1981search in a compatible but advanced way. 1982 1983To solve these problems, [*Boost.Intrusive] containers offers functions where a key type different 1984from `key_type` and a comparison object are provided by the user. This applies to: 1985 * equal_range 1986 * lower_bound 1987 * upper_bound 1988 * count 1989 * find 1990 * erase 1991 1992Requirements for such functions are: 1993 1994* For unordered container the provided comparison and hashing 1995 function with the given key shall induce the same hash and equivalence as `key_compare` and `hasher`. 1996 1997* For ordered associative containers, lookup and erasure functions, the container to be searched shall 1998 be partitioned in regards to the supplied comparison object and key. 1999 2000For more details, see [*Requires] clauses of such functions in the reference. 2001 2002[section:advanced_lookups_example Example] 2003 2004Imagine that the object to be searched is quite expensive to construct (called `Expensive` in the example): 2005 2006[import ../example/doc_assoc_optimized_code.cpp] 2007[doc_assoc_optimized_code_normal_find] 2008 2009If "key" c-string is quite long 2010`Expensive` has to construct a `std::string` using heap memory. Like 2011`Expensive`, many times the only member taking part in ordering issues is just 2012a small part of the class. E.g.: with `Expensive`, only the internal 2013`std::string` is needed to compare the object. 2014 2015In both containers, if we call `get_from_set/get_from_unordered_set` in a loop, we might get a performance penalty, 2016because we are forced to create a whole `Expensive` object to be able to find an 2017equivalent one. 2018 2019Sometimes the problem is not only performance-related, as 2020we [*might not have enough information to construct the object] but we might 2021[*have enough information to find the object]. In this case, a name is enough 2022to search `Expensive` objects in the container but constructing an `Expensive` 2023object might require more information that the searcher might not have. 2024 2025To solve this, we can use the functions that take any type comparable with the value and a 2026the 'compatible' comparison object (and hash, when the associative container is unordered) 2027Let's see optimized search function: 2028 2029[doc_assoc_optimized_code_optimized_find] 2030 2031[endsect] 2032 2033[endsect] 2034 2035[section:advanced_insertions Advanced insertions] 2036 2037A similar issue happens with insertions in simple ordered and unordered associative 2038containers with unique keys (`std::set` and `std::unordered_set`). In these containers, 2039if a value is already present, the value to be inserted is discarded. With expensive 2040values, if the value is already present, we can suffer efficiency problems. 2041 2042[classref boost::intrusive::set set] and [classref boost::intrusive::unordered_set unordered_set]-like 2043containers have insertion functions (`insert_check`, `insert_unique_check`,...) to check efficiently, without 2044constructing the value, if a value is present or not and if it's not present, a 2045function to insert it immediately (`insert_commit`) without any further lookup. Requirements for functions 2046that check the existence of such value are: 2047 2048* For unordered container the provided comparison and hashing 2049 function with the given key shall induce the same hash and equivalence as `key_compare` and `hasher`. 2050 2051* For ordered associative containers, the provided comparison function with the given key, shall induce the same 2052strict weak order as `key_compare`. 2053 2054To sum up, `insert_check` is similar to a normal `insert` but: 2055 2056* `insert_check` can be used with arbitrary keys 2057* if the insertion is possible (there is no equivalent value) `insert_check` collects all the needed information 2058in an `insert_commit_data` structure, so that `insert_commit`: 2059 * [*does not execute] further comparisons 2060 * can be executed with [*constant-time complexity] 2061 * has [*no-throw guarantee]. 2062 2063These functions must be used with care, 2064no other insertion or erasure must be executed between an `insert_check` and an `insert_commit` 2065pair. Otherwise, the behaviour is undefined. 2066 2067See [classref boost::intrusive::set set] 2068and [classref boost::intrusive::unordered_set unordered_set]-like containers' reference 2069for more information about `insert_check` and `insert_commit`. 2070 2071With multiple ordered and unordered associative containers 2072([classref boost::intrusive::multiset multiset] and 2073[classref boost::intrusive::unordered_multiset unordered_multiset]) there is 2074no need for these advanced insertion functions, since insertions are always successful. 2075 2076[section:advanced_insertions_example Example] 2077 2078For example, using the same `Expensive` class, 2079this function can be inefficient: 2080 2081[doc_assoc_optimized_code_normal_insert] 2082 2083If the object is already present, we are constructing an `Expensive` that 2084will be discarded, and this is a waste of resources. Instead of that, let's use 2085`insert_check` and `insert_commit` functions: 2086 2087[doc_assoc_optimized_code_optimized_insert] 2088 2089[endsect] 2090 2091[endsect] 2092 2093[section:positional_insertions Positional insertions] 2094 2095Some ordered associative containers offer low-level functions to bypass ordering 2096checks and insert nodes directly in desired tree positions. These functions are 2097provided for performance reasons when values to be inserted in the container are 2098known to fulfill order (sets and multisets) and uniqueness (sets) invariants. A 2099typical usage of these functions is when intrusive associative containers are used 2100to build non-intrusive containers and the programmer wants to speed up assignments 2101from other associative containers: if the ordering and uniqueness properties are the same, 2102there is no need to waste time checking the position of each source value, because values 2103are already ordered: back insertions will be much more efficient. 2104 2105[*Note:] These functions [*don't check preconditions] so they must used with care. They 2106are low-level operations that [*will break container invariants if 2107ordering and uniqueness preconditions are not assured by the caller.] 2108 2109Let's see an example: 2110 2111[import ../example/doc_positional_insertion.cpp] 2112[doc_positional_insertion] 2113 2114[endsect] 2115 2116For more information about advanced lookup and insertion functions see 2117associative containers' documentation (e.g. 2118[classref boost::intrusive::set set], 2119[classref boost::intrusive::multiset multiset], 2120[classref boost::intrusive::unordered_set unordered_set] and 2121[classref boost::intrusive::unordered_multiset unordered_multiset] references). 2122 2123[endsect] 2124 2125[section:erasing_and_disposing Erasing and disposing values from Boost.Intrusive containers] 2126 2127One of the most tedious tasks when using intrusive containers is the management of the erased elements. 2128When using STL containers, the container itself unlinks and destroys the contained elements, but with 2129intrusive containers, the user must explicitly destroy the object after erasing an element from the container. 2130This makes STL-like functions erasing multiple objects unhelpful: the user can't destroy every erased element. 2131For example, let's take the function `remove_if` from [classref boost::intrusive::list list]: 2132 2133[c++] 2134 2135 template<class Pred> 2136 void remove_if(Pred pred); 2137 2138How can the user destroy the elements (say, using `operator delete`) that will be erased according 2139to the predicate? [*Boost.Intrusive] containers offer additional functions that take a function 2140object that will be called after the element has been erased from the container. For example, 2141[classref boost::intrusive::list list] offers: 2142 2143[c++] 2144 2145 template<class Pred, class Disposer> 2146 void remove_and_dispose_if(Pred pred, Disposer disposer) 2147 2148With this function the user can efficiently remove and destroy elements if the disposer 2149function destroys an object: `remove_and_dispose_if` 2150will call the "disposer" function object for every removed element. [classref boost::intrusive::list list] offers 2151more functions taking a disposer function object as argument, like `erase_and_dispose`, `clear_and_dispose`, 2152`remove_and_dispose`, etc. 2153 2154Note that the disposing function does not need to just destroy the object. It can 2155implement any other operation like inserting the remove object in another container. 2156Let's see a small example: 2157 2158[import ../example/doc_erasing_and_disposing.cpp] 2159[doc_erasing_and_disposing] 2160 2161All [*Boost.Intrusive] containers offer these "erase + dispose" additional members for all functions 2162that erase an element from the container. 2163 2164 2165 2166[endsect] 2167 2168[section:clone_from Cloning Boost.Intrusive containers] 2169 2170As previously mentioned, [*Boost.Intrusive] containers are [*non-copyable and non-assignable], because 2171intrusive containers don't allocate memory at all. To implement a copy-constructor or assignment operator, 2172the user must clone one by one all the elements of the container and insert them in another intrusive container. 2173However, cloning by hand is usually more inefficient than a member cloning function and a specialized cloning 2174function can offer more guarantees than the manual cloning (better exception safety guarantees, for example). 2175 2176To ease the implementation of copy constructors and assignment operators of classes containing [*Boost.Intrusive] 2177containers, all [*Boost.Intrusive] containers offer a special cloning function called `clone_from`. 2178 2179Apart from the container to be cloned, `clone_from` takes two function objects as arguments. For example, consider the 2180`clone_from` member function of [classref boost::intrusive::list list]: 2181 2182[c++] 2183 2184 template <class Cloner, class Disposer> 2185 void clone_from(const list &src, Cloner cloner, Disposer disposer); 2186 2187This function will make `*this` a clone of `src`. Let's explain the arguments: 2188 2189* The first parameter is the list to be cloned. 2190* The second parameter is a function object that will clone `value_type` objects and 2191 return a pointer to the clone. It must implement the following function: 2192 `pointer operator()(const value_type &)`. 2193* The second parameter is a function object that will dispose `value_type` objects. It's used first 2194 to empty the container before cloning and to dispose the elements if an exception is thrown. 2195 2196The cloning function works as follows: 2197 2198* First it clears and disposes all the elements from *this using the disposer function object. 2199* After that it starts cloning all the elements of the source container using the cloner function object. 2200* If any operation in the cloning function (for example, the cloner function object) throws, 2201 all the constructed elements are disposed using the disposer function object. 2202 2203 2204Here is an example of `clone_from`: 2205 2206[import ../example/doc_clone_from.cpp] 2207[doc_clone_from] 2208 2209[endsect] 2210 2211[section:function_hooks Using function hooks] 2212 2213A programmer might find that base or member hooks are not flexible enough in some situations. 2214In some applications it would be optimal to put a hook deep inside a member of a class or just outside the class. 2215[*Boost.Intrusive] has an easy option to allow such cases: [classref boost::intrusive::function_hook function_hook]. 2216 2217This option is similar to [classref boost::intrusive::member_hook member_hook] or 2218[classref boost::intrusive::base_hook base_hook], but the programmer can specify a function 2219object that tells the container how to obtain a hook from a value and vice versa. 2220The programmer just needs to define the following function object: 2221 2222[c++] 2223 2224 //This functor converts between value_type and a hook_type 2225 struct Functor 2226 { 2227 //Required types 2228 typedef /*impl-defined*/ hook_type; 2229 typedef /*impl-defined*/ hook_ptr; 2230 typedef /*impl-defined*/ const_hook_ptr; 2231 typedef /*impl-defined*/ value_type; 2232 typedef /*impl-defined*/ pointer; 2233 typedef /*impl-defined*/ const_pointer; 2234 //Required static functions 2235 static hook_ptr to_hook_ptr (value_type &value); 2236 static const_hook_ptr to_hook_ptr(const value_type &value); 2237 static pointer to_value_ptr(hook_ptr n); 2238 static const_pointer to_value_ptr(const_hook_ptr n); 2239 }; 2240 2241Converting from values to hooks is generally easy, since most hooks are 2242in practice members or base classes of class data members. The inverse operation 2243is a bit more complicated, but [*Boost.Intrusive] offers a bit of help with the function 2244[funcref boost::intrusive::get_parent_from_member get_parent_from_member], 2245which allows easy conversions from the address of a data member to the address of 2246the parent holding that member. Let's see a little example of 2247[classref boost::intrusive::function_hook function_hook]: 2248 2249[import ../example/doc_function_hooks.cpp] 2250[doc_function_hooks] 2251 2252[endsect] 2253 2254 2255[section:recursive Recursive Boost.Intrusive containers] 2256 2257[*Boost.Intrusive] containers can be used to define recursive structures very easily, 2258allowing complex data structures with very low overhead. Let's see an example: 2259 2260[import ../example/doc_recursive.cpp] 2261[doc_recursive] 2262 2263Recursive data structures using [*Boost.Intrusive] containers must avoid using hook deduction to avoid early type 2264instantiation: 2265 2266[c++] 2267 2268 //This leads to compilation error (Recursive is instantiated by 2269 //'list' to deduce hook properties (pointer type, tag, safe-mode...) 2270 class Recursive 2271 { //... 2272 2273 list< Recursive > l; 2274 //... 2275 }; 2276 2277 //Ok, programmer must specify the hook type to avoid early Recursive instantiation 2278 class Recursive 2279 { //... 2280 list< Recursive, base_hook<BaseHook> > l; 2281 //... 2282 }; 2283 2284 2285Member hooks are not suitable for recursive structures: 2286 2287[c++] 2288 2289 class Recursive 2290 { 2291 private: 2292 Recursive(const Recursive&); 2293 Recursive & operator=(const Recursive&); 2294 2295 public: 2296 list_member_hook<> memhook; 2297 list< Recursive, member_hook<Recursive, list_member_hook<>, &Recursive::memhook> > children; 2298 }; 2299 2300Specifying `&Recursive::memhook` (that is, the offset between memhook and Recursive) provokes an early 2301instantiation of `Recursive`. To define recursive structures using member hooks, a programmer should use 2302[classref ::boost::interprocess::function_hook function_hook]: 2303 2304[import ../example/doc_recursive_member.cpp] 2305[doc_recursive_member] 2306 2307[endsect] 2308 2309 2310[section:using_smart_pointers Using smart pointers with Boost.Intrusive containers] 2311 2312[*Boost.Intrusive] hooks can be configured to use other pointers than raw pointers. 2313When a [*Boost.Intrusive] hook is configured with a smart pointer as an argument, 2314this pointer configuration is passed to the containers. For example, if the following 2315hook is configured with a smart pointer (for example, an offset pointer from 2316[*Boost.Interprocess]): 2317 2318[import ../example/doc_offset_ptr.cpp] 2319[doc_offset_ptr_0] 2320 2321Any intrusive list constructed using this hook will be ready for shared memory, 2322because the intrusive list will also use offset pointers internally. For example, 2323we can create an intrusive list in shared memory combining [*Boost.Interprocess] 2324and [*Boost.Intrusive]: 2325 2326[doc_offset_ptr_1] 2327 2328[section:smart_pointers_requirements Requirements for smart pointers compatible with Boost.Intrusive] 2329 2330Not every smart pointer is compatible with [*Boost.Intrusive]: 2331 2332* It must be compatible with C++11 [@http://en.cppreference.com/w/cpp/memory/pointer_traits `std::pointer_traits`] 2333 requirements. [*Boost.Intrusive] uses its own [classref boost::intrusive::pointer_traits pointer_traits] 2334 class to implement those features in both C++11 and C++03 compilers. 2335* It must have the same ownership semantics as a raw pointer. This means that 2336 resource management smart pointers (like `boost::shared_ptr`) can't be used. 2337 2338The conversion from the smart pointer to a raw pointer will be implemented as a recursive call to 2339`operator->()` until the function returns a raw pointer. 2340 2341[endsect] 2342 2343[endsect] 2344 2345[section:obtaining_iterators_from_values Obtaining iterators from values] 2346 2347[*Boost.Intrusive] offers another useful feature that's not present in STL 2348containers: it's possible to obtain an iterator to a value from the value itself. 2349This feature is implemented in [*Boost.Intrusive] containers by a 2350function called `iterator_to`: 2351 2352[c++] 2353 2354 iterator iterator_to(reference value); 2355 const_iterator iterator_to(const_reference value); 2356 2357For [*Boost.Intrusive] containers that have local iterators, like unordered 2358associative containers, we can also obtain local iterators: 2359 2360[c++] 2361 2362 local_iterator local_iterator_to(reference value); 2363 const_local_iterator local_iterator_to(const_reference value) const; 2364 2365For most [*Boost.Intrusive] containers 2366([classref boost::intrusive::list list], 2367[classref boost::intrusive::slist slist], 2368[classref boost::intrusive::set set], 2369[classref boost::intrusive::multiset multiset]) we have an alternative 2370static `s_iterator_to` function. 2371 2372For unordered associative containers 2373([classref boost::intrusive::unordered_set unordered_set], 2374[classref boost::intrusive::multiset multiset]), 2375`iterator_to` has no static alternative function. 2376On the other hand, `local_iterator_to` functions 2377have their `s_local_iterator_to` static alternatives. 2378 2379Alternative static functions are available under certain circumstances 2380explained in the [link intrusive.value_traits.stateful_value_traits Stateful value traits] section; 2381if the programmer uses hooks provided by [*Boost.Intrusive], those functions 2382will be available. 2383 2384Let's see a small function that shows the use of `iterator_to` and 2385`local_iterator_to`: 2386 2387[import ../example/doc_iterator_from_value.cpp] 2388[doc_iterator_from_value] 2389 2390[endsect] 2391 2392[section:any_hooks Any Hooks: A single hook for any Intrusive container] 2393 2394Sometimes, a class programmer wants to place a class in several intrusive 2395containers but no at the same time. In this case, the programmer might 2396decide to insert two hooks in the same class. 2397 2398[c++] 2399 2400 class MyClass 2401 : public list_base_hook<>, public slist_base_hook<> //... 2402 {}; 2403 2404However, there is a more size-efficient alternative in [*Boost.Intrusive]: "any" hooks 2405([classref boost::intrusive::any_base_hook any_base_hook] and 2406[classref boost::intrusive::any_member_hook any_member_hook]). 2407These hooks can be used to store a type in several containers 2408offered by [*Boost.Intrusive] minimizing the size of the class. 2409 2410These hooks support these options: 2411 2412* [*`tag<class Tag>`] (for base hooks only): This argument serves as a tag, 2413 so you can derive from more than one slist hook. 2414 Default: `tag<default_tag>`. 2415 2416* [*`link_mode<link_mode_type LinkMode>`]: The linking policy. 2417 `link_mode<auto_unlink>` is [*not] supported and `link_mode<safe_mode>` 2418 might offer weaker error detection in any hooks than in other hooks. 2419 Default: `link_mode<safe_link>`. 2420 2421* [*`void_pointer<class VoidPointer>`]: The pointer type to be used 2422 internally in the hook and propagated to the container. 2423 Default: `void_pointer<void*>`. 2424 2425`auto_unlink` can't be supported because the hook does not know in which type of 2426container might be currently inserted. Additionally, these hooks don't support `unlink()` and 2427`swap_nodes()` operations for the same reason. 2428 2429Here is an example that creates a class with two any hooks, and uses one to insert the 2430class in a [classref slist] and the other one in a [classref list]. 2431 2432[import ../example/doc_any_hook.cpp] 2433[doc_any_hook] 2434 2435[endsect] 2436 2437[section:concepts Concepts explained] 2438 2439This section will expand the explanation of previously presented basic concepts 2440before explaining the customization options of [*Boost.Intrusive]. 2441 2442* [*Node Algorithms]: A set of static functions that implement basic operations 2443 on a group of nodes: initialize a node, link a node to a group of nodes, 2444 unlink a node from another group of nodes, etc. For example, a circular 2445 singly linked list is a group of nodes, where each node has a pointer to the 2446 next node. [*Node Algorithms] just require a [*NodeTraits] 2447 template parameter and they can work with any [*NodeTraits] class that fulfills 2448 the needed interface. As an example, here is a class that implements operations 2449 to manage a group of nodes forming a circular singly linked list: 2450 2451[c++] 2452 2453 template<class NodeTraits> 2454 struct my_slist_algorithms 2455 { 2456 typedef typename NodeTraits::node_ptr node_ptr; 2457 typedef typename NodeTraits::const_node_ptr const_node_ptr; 2458 2459 //Get the previous node of "this_node" 2460 static node_ptr get_prev_node(node_ptr this_node) 2461 { 2462 node_ptr p = this_node; 2463 while (this_node != NodeTraits::get_next(p)) 2464 p = NodeTraits::get_next(p); 2465 return p; 2466 } 2467 2468 // number of elements in the group of nodes containing "this_node" 2469 static std::size_t count(const_node_ptr this_node) 2470 { 2471 std::size_t result = 0; 2472 const_node_ptr p = this_node; 2473 do{ 2474 p = NodeTraits::get_next(p); 2475 ++result; 2476 } while (p != this_node); 2477 return result; 2478 } 2479 2480 // More operations 2481 // ... 2482 }; 2483 2484* [*Node Traits]: A class that encapsulates the basic information and 2485 operations on a node within a group of nodes: 2486 the type of the node, a function to obtain the pointer to the next node, etc. 2487 [*Node Traits] specify the configuration information [*Node Algorithms] 2488 need. Each type of [*Node Algorithm] expects an interface that compatible 2489 [*Node Traits] classes must implement. 2490 As an example, this is the definition of a [*Node Traits] class that 2491 is compatible with the previously presented `my_slist_algorithms`: 2492 2493[c++] 2494 2495 struct my_slist_node_traits 2496 { 2497 //The type of the node 2498 struct node 2499 { 2500 node *next_; 2501 }; 2502 2503 typedef node * node_ptr; 2504 typedef const node * const_node_ptr; 2505 2506 //A function to obtain a pointer to the next node 2507 static node_ptr get_next(const_node_ptr n) 2508 { return n->next_; } 2509 2510 //A function to set the pointer to the next node 2511 static void set_next(node_ptr n, node_ptr next) 2512 { n->next_ = next; } 2513 }; 2514 2515 2516* [*Hook]: A class that the user must add as a base class or as a member to his own 2517 class to make that class insertable in an intrusive container. Usually the hook 2518 contains a node object that will be used to form the group of nodes: 2519 For example, the following class is a [*Hook] that the user can add as a base class, 2520 to make the user class compatible with a singly linked list container: 2521 2522[c++] 2523 2524 class my_slist_base_hook 2525 //This hook contains a node, that will be used 2526 //to link the user object in the group of nodes 2527 : private my_slist_node_traits::node 2528 { 2529 typedef my_slist_node_traits::node_ptr node_ptr; 2530 typedef my_slist_node_traits::const_node_ptr const_node_ptr; 2531 2532 //Converts the generic node to the hook 2533 static my_slist_base_hook *to_hook_ptr(node_ptr p) 2534 { return static_cast<my_slist_base_hook*>(p); } 2535 2536 //Returns the generic node stored by this hook 2537 node_ptr to_node_ptr() 2538 { return static_cast<node *const>(this); } 2539 2540 // More operations 2541 // ... 2542 }; 2543 2544 //To make MyClass compatible with an intrusive singly linked list 2545 //derive our class from the hook. 2546 class MyClass 2547 : public my_slist_base_hook 2548 { 2549 void set(int value); 2550 int get() const; 2551 2552 private: 2553 int value_; 2554 }; 2555 2556* [*Intrusive Container]: A container that offers a STL-like interface to store 2557 user objects. An intrusive container can be templatized to store different 2558 value types that use different hooks. An intrusive container is also more elaborate 2559 than a group of nodes: it can store the number of elements to achieve constant-time 2560 size information, it can offer debugging facilities, etc. 2561 For example, an [classref boost::intrusive::slist slist] container 2562 (intrusive singly linked list) should 2563 be able to hold `MyClass` objects that might have decided to store the hook 2564 as a base class or as a member. Internally, the container will use [*Node Algorithms] 2565 to implement its operations, and an intrusive container is configured using 2566 a template parameter called [*ValueTraits]. [*ValueTraits] will contain 2567 the information to convert user classes in nodes compatible with [*Node Algorithms]. 2568 For example, this a possible [classref boost::intrusive::slist slist] implementation: 2569 2570[c++] 2571 2572 template<class ValueTraits, ...> 2573 class slist 2574 { 2575 public: 2576 typedef typename ValueTraits::value_type value_type; 2577 2578 //More typedefs and functions 2579 // ... 2580 2581 //Insert the value as the first element of the list 2582 void push_front (reference value) 2583 { 2584 node_ptr to_insert(ValueTraits::to_node_ptr(value)); 2585 circular_list_algorithms::link_after(to_insert, get_root_node()); 2586 } 2587 2588 // More operations 2589 // ... 2590 }; 2591 2592* [*Semi-Intrusive Container]: A semi-intrusive container is similar to an 2593 intrusive container, but apart from the values to be inserted in the container, 2594 it needs additional memory (for example, auxiliary arrays or indexes). 2595 2596* [*Value Traits]: As we can see, to make our classes intrusive-friendly we add 2597 a simple hook as a member or base class. The hook contains a generic node 2598 that will be inserted in a group of nodes. [*Node Algorithms] just work 2599 with nodes and don't know anything about user classes. On the other 2600 hand, an intrusive container needs to know how to obtain a node from a user class, 2601 and also the inverse operation. 2602 So we can define [*ValueTraits] as the glue between user classes and nodes 2603 required by [*Node Algorithms]. 2604 Let's see a possible implementation of a value traits class that glues MyClass 2605 and the node stored in the hook: 2606 2607[c++] 2608 2609 struct my_slist_derivation_value_traits 2610 { 2611 public: 2612 typedef slist_node_traits node_traits; 2613 typedef MyClass value_type; 2614 typedef node_traits::node_ptr node_ptr; 2615 typedef value_type* pointer; 2616 //... 2617 2618 //Converts user's value to a generic node 2619 static node_ptr to_node_ptr(reference value) 2620 { return static_cast<slist_base_hook &>(value).to_node_ptr(); } 2621 2622 //Converts a generic node into user's value 2623 static value_type *to_value_ptr(node_traits::node *n) 2624 { static_cast<value_type*>(slist_base_hook::to_hook_ptr(n)); } 2625 2626 // More operations 2627 // ... 2628 }; 2629 2630[endsect] 2631 2632[section:node_algorithms Node algorithms with custom NodeTraits] 2633 2634As explained in the [link intrusive.concepts Concepts] section, [*Boost.Intrusive] 2635containers are implemented using node algorithms that work on generic nodes. 2636 2637Sometimes, the use of intrusive containers is expensive for some environments 2638and the programmer might want to avoid all the template instantiations 2639related to [*Boost.Intrusive] containers. However, the user can still benefit 2640from [*Boost.Intrusive] using the node algorithms, because some of those algorithms, 2641like red-black tree algorithms, are not trivial to write. 2642 2643All node algorithm classes are 2644templatized by a `NodeTraits` class. This class encapsulates the needed internal 2645type declarations and operations to make a node compatible with node algorithms. 2646Each type of node algorithms has its own requirements: 2647 2648[section:circular_slist_algorithms Intrusive singly linked list algorithms] 2649 2650These algorithms are static 2651members of the [classref boost::intrusive::circular_slist_algorithms circular_slist_algorithms] class: 2652 2653[c++] 2654 2655 template<class NodeTraits> 2656 struct circular_slist_algorithms; 2657 2658An empty list is formed by a node whose pointer to the next node points 2659to itself. [classref boost::intrusive::circular_slist_algorithms circular_slist_algorithms] 2660is configured with a NodeTraits class, which encapsulates 2661the information about the node to be manipulated. NodeTraits must support the 2662following interface: 2663 2664[*Typedefs]: 2665 2666* `node`: The type of the node that forms the circular list 2667 2668* `node_ptr`: The type of a pointer to a node (usually node*) 2669 2670* `const_node_ptr`: The type of a pointer to a const node (usually const node*) 2671 2672[*Static functions]: 2673 2674* `static node_ptr get_next(const_node_ptr n);`: 2675 Returns a pointer to the next node stored in "n". 2676 2677* `static void set_next(node_ptr n, node_ptr next);`: 2678 Sets the pointer to the next node stored in "n" to "next". 2679 2680Once we have a node traits configuration we can use [*Boost.Intrusive] algorithms 2681with our nodes: 2682 2683[import ../example/doc_slist_algorithms.cpp] 2684[doc_slist_algorithms_code] 2685 2686For a complete list of functions see 2687[classref boost::intrusive::circular_slist_algorithms circular_slist_algorithms reference]. 2688 2689[endsect] 2690 2691[section:circular_list_algorithms Intrusive doubly linked list algorithms] 2692 2693These algorithms are static 2694members of the [classref boost::intrusive::circular_list_algorithms circular_list_algorithms] class: 2695 2696[c++] 2697 2698 template<class NodeTraits> 2699 struct circular_list_algorithms; 2700 2701An empty list is formed by a node whose pointer to the next node points 2702to itself. [classref boost::intrusive::circular_list_algorithms circular_list_algorithms] 2703is configured with a NodeTraits class, which encapsulates 2704the information about the node to be manipulated. NodeTraits must support the 2705following interface: 2706 2707[*Typedefs]: 2708 2709* `node`: The type of the node that forms the circular list 2710 2711* `node_ptr`: The type of a pointer to a node (usually node*) 2712 2713* `const_node_ptr`: The type of a pointer to a const node (usually const node*) 2714 2715[*Static functions]: 2716 2717* `static node_ptr get_next(const_node_ptr n);`: 2718 Returns a pointer to the next node stored in "n". 2719 2720* `static void set_next(node_ptr n, node_ptr next);`: 2721 Sets the pointer to the next node stored in "n" to "next". 2722 2723* `static node_ptr get_previous(const_node_ptr n);`: 2724 Returns a pointer to the previous node stored in "n". 2725 2726* `static void set_previous(node_ptr n, node_ptr prev);`: 2727 Sets the pointer to the previous node stored in "n" to "prev". 2728 2729Once we have a node traits configuration we can use [*Boost.Intrusive] algorithms 2730with our nodes: 2731 2732[import ../example/doc_list_algorithms.cpp] 2733[doc_list_algorithms_code] 2734 2735For a complete list of functions see 2736[classref boost::intrusive::circular_list_algorithms circular_list_algorithms reference]. 2737 2738[endsect] 2739 2740[section:rbtree_algorithms Intrusive red-black tree algorithms] 2741 2742These algorithms are static 2743members of the [classref boost::intrusive::rbtree_algorithms rbtree_algorithms] class: 2744 2745[c++] 2746 2747 template<class NodeTraits> 2748 struct rbtree_algorithms; 2749 2750 2751An empty tree is formed by a node whose pointer to the parent node is null, 2752the left and right node pointers point to itself, and whose color is red. 2753[classref boost::intrusive::rbtree_algorithms rbtree_algorithms] 2754is configured with a NodeTraits class, which encapsulates 2755the information about the node to be manipulated. NodeTraits must support the 2756following interface: 2757 2758[*Typedefs]: 2759 2760* `node`: The type of the node that forms the circular rbtree 2761 2762* `node_ptr`: The type of a pointer to a node (usually node*) 2763 2764* `const_node_ptr`: The type of a pointer to a const node (usually const node*) 2765 2766* `color`: The type that can store the color of a node 2767 2768[*Static functions]: 2769 2770* `static node_ptr get_parent(const_node_ptr n);`: 2771 Returns a pointer to the parent node stored in "n". 2772 2773* `static void set_parent(node_ptr n, node_ptr p);`: 2774 Sets the pointer to the parent node stored in "n" to "p". 2775 2776* `static node_ptr get_left(const_node_ptr n);`: 2777 Returns a pointer to the left node stored in "n". 2778 2779* `static void set_left(node_ptr n, node_ptr l);`: 2780 Sets the pointer to the left node stored in "n" to "l". 2781 2782* `static node_ptr get_right(const_node_ptr n);`: 2783 Returns a pointer to the right node stored in "n". 2784 2785* `static void set_right(node_ptr n, node_ptr r);`: 2786 Sets the pointer to the right node stored in "n" to "r". 2787 2788* `static color get_color(const_node_ptr n);`: 2789 Returns the color stored in "n". 2790 2791* `static void set_color(node_ptr n, color c);`: 2792 Sets the color stored in "n" to "c". 2793 2794* `static color black();`: 2795 Returns a value representing the black color. 2796 2797* `static color red();`: 2798 Returns a value representing the red color. 2799 2800Once we have a node traits configuration we can use [*Boost.Intrusive] algorithms 2801with our nodes: 2802 2803[import ../example/doc_rbtree_algorithms.cpp] 2804[doc_rbtree_algorithms_code] 2805 2806For a complete list of functions see 2807[classref boost::intrusive::rbtree_algorithms rbtree_algorithms reference]. 2808 2809[endsect] 2810 2811[section:splaytree_algorithms Intrusive splay tree algorithms] 2812 2813These algorithms are static 2814members of the [classref boost::intrusive::splaytree_algorithms splaytree_algorithms] class: 2815 2816[c++] 2817 2818 template<class NodeTraits> 2819 struct splaytree_algorithms; 2820 2821 2822An empty tree is formed by a node whose pointer to the parent node is null, 2823and whose left and right nodes pointers point to itself. 2824[classref boost::intrusive::splaytree_algorithms splaytree_algorithms] 2825is configured with a NodeTraits class, which encapsulates 2826the information about the node to be manipulated. NodeTraits must support the 2827following interface: 2828 2829[*Typedefs]: 2830 2831* `node`: The type of the node that forms the circular splaytree 2832 2833* `node_ptr`: The type of a pointer to a node (usually node*) 2834 2835* `const_node_ptr`: The type of a pointer to a const node (usually const node*) 2836 2837[*Static functions]: 2838 2839* `static node_ptr get_parent(const_node_ptr n);`: 2840 Returns a pointer to the parent node stored in "n". 2841 2842* `static void set_parent(node_ptr n, node_ptr p);`: 2843 Sets the pointer to the parent node stored in "n" to "p". 2844 2845* `static node_ptr get_left(const_node_ptr n);`: 2846 Returns a pointer to the left node stored in "n". 2847 2848* `static void set_left(node_ptr n, node_ptr l);`: 2849 Sets the pointer to the left node stored in "n" to "l". 2850 2851* `static node_ptr get_right(const_node_ptr n);`: 2852 Returns a pointer to the right node stored in "n". 2853 2854* `static void set_right(node_ptr n, node_ptr r);`: 2855 Sets the pointer to the right node stored in "n" to "r". 2856 2857Once we have a node traits configuration we can use [*Boost.Intrusive] algorithms 2858with our nodes: 2859 2860[import ../example/doc_splaytree_algorithms.cpp] 2861[doc_splaytree_algorithms_code] 2862 2863For a complete list of functions see 2864[classref boost::intrusive::splaytree_algorithms splaytree_algorithms reference]. 2865 2866[endsect] 2867 2868[section:avltree_algorithms Intrusive avl tree algorithms] 2869 2870[classref boost::intrusive::avltree_algorithms avltree_algorithms] have the same 2871interface as [classref boost::intrusive::rbtree_algorithms rbtree_algorithms]. 2872 2873[c++] 2874 2875 template<class NodeTraits> 2876 struct avltree_algorithms; 2877 2878[classref boost::intrusive::avltree_algorithms avltree_algorithms] 2879is configured with a NodeTraits class, which encapsulates 2880the information about the node to be manipulated. NodeTraits must support the 2881following interface: 2882 2883[*Typedefs]: 2884 2885* `node`: The type of the node that forms the circular avltree 2886 2887* `node_ptr`: The type of a pointer to a node (usually node*) 2888 2889* `const_node_ptr`: The type of a pointer to a const node (usually const node*) 2890 2891* `balance`: A type that can represent 3 balance types (usually an integer) 2892 2893[*Static functions]: 2894 2895* `static node_ptr get_parent(const_node_ptr n);`: 2896 Returns a pointer to the parent node stored in "n". 2897 2898* `static void set_parent(node_ptr n, node_ptr p);`: 2899 Sets the pointer to the parent node stored in "n" to "p". 2900 2901* `static node_ptr get_left(const_node_ptr n);`: 2902 Returns a pointer to the left node stored in "n". 2903 2904* `static void set_left(node_ptr n, node_ptr l);`: 2905 Sets the pointer to the left node stored in "n" to "l". 2906 2907* `static node_ptr get_right(const_node_ptr n);`: 2908 Returns a pointer to the right node stored in "n". 2909 2910* `static void set_right(node_ptr n, node_ptr r);`: 2911 Sets the pointer to the right node stored in "n" to "r". 2912 2913* `static balance get_balance(const_node_ptr n);`: 2914 Returns the balance factor stored in "n". 2915 2916* `static void set_balance(node_ptr n, balance b);`: 2917 Sets the balance factor stored in "n" to "b". 2918 2919* `static balance negative();`: 2920 Returns a value representing a negative balance factor. 2921 2922* `static balance zero();`: 2923 Returns a value representing a zero balance factor. 2924 2925* `static balance positive();`: 2926 Returns a value representing a positive balance factor. 2927 2928Once we have a node traits configuration we can use [*Boost.Intrusive] algorithms 2929with our nodes: 2930 2931[import ../example/doc_avltree_algorithms.cpp] 2932[doc_avltree_algorithms_code] 2933 2934For a complete list of functions see 2935[classref boost::intrusive::avltree_algorithms avltree_algorithms reference]. 2936 2937[endsect] 2938 2939 2940[section:treap_algorithms Intrusive treap algorithms] 2941 2942[classref boost::intrusive::treap_algorithms treap_algorithms] have the same 2943interface as [classref boost::intrusive::rbtree_algorithms rbtree_algorithms]. 2944 2945[c++] 2946 2947 template<class NodeTraits> 2948 struct treap_algorithms; 2949 2950[classref boost::intrusive::treap_algorithms treap_algorithms] 2951is configured with a NodeTraits class, which encapsulates 2952the information about the node to be manipulated. NodeTraits must support the 2953following interface: 2954 2955[*Typedefs]: 2956 2957* `node`: The type of the node that forms the circular treap 2958 2959* `node_ptr`: The type of a pointer to a node (usually node*) 2960 2961* `const_node_ptr`: The type of a pointer to a const node (usually const node*) 2962 2963[*Static functions]: 2964 2965* `static node_ptr get_parent(const_node_ptr n);`: 2966 Returns a pointer to the parent node stored in "n". 2967 2968* `static void set_parent(node_ptr n, node_ptr p);`: 2969 Sets the pointer to the parent node stored in "n" to "p". 2970 2971* `static node_ptr get_left(const_node_ptr n);`: 2972 Returns a pointer to the left node stored in "n". 2973 2974* `static void set_left(node_ptr n, node_ptr l);`: 2975 Sets the pointer to the left node stored in "n" to "l". 2976 2977* `static node_ptr get_right(const_node_ptr n);`: 2978 Returns a pointer to the right node stored in "n". 2979 2980* `static void set_right(node_ptr n, node_ptr r);`: 2981 Sets the pointer to the right node stored in "n" to "r". 2982 2983Once we have a node traits configuration we can use [*Boost.Intrusive] algorithms 2984with our nodes: 2985 2986[import ../example/doc_treap_algorithms.cpp] 2987[doc_treap_algorithms_code] 2988 2989For a complete list of functions see 2990[classref boost::intrusive::treap_algorithms treap_algorithms reference]. 2991 2992[endsect] 2993 2994 2995[/ 2996/ 2997/[section:sgtree_algorithms Intrusive sg tree algorithms] 2998/ 2999/ 3000/[classref boost::intrusive::sgtree_algorithms sgtree_algorithms] have the same 3001/interface as [classref boost::intrusive::rbtree_algorithms rbtree_algorithms]. 3002/ 3003/[c++] 3004/ 3005/ template<class NodeTraits> 3006/ struct sgtree_algorithms; 3007/ 3008/[classref boost::intrusive::sgtree_algorithms sgtree_algorithms] 3009/is configured with a NodeTraits class, which encapsulates 3010/the information about the node to be manipulated. NodeTraits must support the 3011/following interface: 3012/ 3013/[*Typedefs]: 3014/ 3015/* `node`: The type of the node that forms the circular sgtree 3016/ 3017/* `node_ptr`: The type of a pointer to a node (usually node*) 3018/ 3019/* `const_node_ptr`: The type of a pointer to a const node (usually const node*) 3020/ 3021/[*Static functions]: 3022/ 3023/* `static node_ptr get_parent(const_node_ptr n);`: 3024/ Returns a pointer to the parent node stored in "n". 3025/ 3026/* `static void set_parent(node_ptr n, node_ptr p);`: 3027/ Sets the pointer to the parent node stored in "n" to "p". 3028/ 3029/* `static node_ptr get_left(const_node_ptr n);`: 3030/ Returns a pointer to the left node stored in "n". 3031/ 3032/* `static void set_left(node_ptr n, node_ptr l);`: 3033/ Sets the pointer to the left node stored in "n" to "l". 3034/ 3035/* `static node_ptr get_right(const_node_ptr n);`: 3036/ Returns a pointer to the right node stored in "n". 3037/ 3038/* `static void set_right(node_ptr n, node_ptr r);`: 3039/ Sets the pointer to the right node stored in "n" to "r". 3040/ 3041/Once we have a node traits configuration we can use [*Boost.Intrusive] algorithms 3042/with our nodes: 3043/ 3044/[import ../example/doc_sgtree_algorithms.cpp] 3045/[doc_sgtree_algorithms_code] 3046/ 3047/For a complete list of functions see 3048/[classref boost::intrusive::sgtree_algorithms sgtree_algorithms reference]. 3049/ 3050/[endsect] 3051/] 3052 3053[endsect] 3054 3055[section:value_traits Containers with custom ValueTraits] 3056 3057As explained in the [link intrusive.concepts Concepts] section, [*Boost.Intrusive] 3058containers need a `ValueTraits` class to perform transformations between nodes and 3059user values. `ValueTraits` can be explicitly configured (using the `value_traits<>` option) 3060or implicitly configured (using hooks and their `base_hook<>`/`member_hook<>` options). 3061`ValueTraits` contains 3062all the information to glue the `value_type` of the containers and the node to be 3063used in node algorithms, since these types can be different. Apart from this, 3064`ValueTraits` also stores information about the link policy of the values to be inserted. 3065 3066Instead of using [*Boost.Intrusive] predefined hooks 3067a user might want to develop customized containers, for example, using nodes that are 3068optimized for a specific 3069application or that are compatible with a legacy ABI. A user might want 3070to have only two additional pointers in his class and insert the class in a doubly 3071linked list sometimes and in a singly linked list in other situations. You can't 3072achieve this using [*Boost.Intrusive] predefined hooks. Now, instead of using 3073`base_hook<...>` or `member_hook<...>` options the user will specify the 3074`value_traits<...>` options. Let's see how we can do this: 3075 3076[section:value_traits_interface ValueTraits interface] 3077 3078`ValueTraits` has the following interface: 3079 3080[c++] 3081 3082 #include <boost/intrusive/pointer_traits.hpp> 3083 #include <boost/intrusive/link_mode.hpp> 3084 3085 struct my_value_traits 3086 { 3087 typedef implementation_defined node_traits; 3088 typedef implementation_defined value_type; 3089 typedef node_traits::node_ptr node_ptr; 3090 typedef node_traits::const_node_ptr const_node_ptr; 3091 typedef boost::intrusive::pointer_traits<node_ptr>::rebind_traits 3092 <value_type>::type::pointer pointer; 3093 typedef boost::intrusive::pointer_traits<node_ptr>::rebind_traits 3094 <const value_type>::type::pointer const_pointer; 3095 3096 static const link_mode_type link_mode = some_linking_policy; 3097 3098 static node_ptr to_node_ptr (value_type &value); 3099 static const_node_ptr to_node_ptr (const value_type &value); 3100 static pointer to_value_ptr (node_ptr n); 3101 static const_pointer to_value_ptr (const_node_ptr n); 3102 }; 3103 3104Let's explain each type and function: 3105 3106* [*['node_traits]]: The node configuration that is needed by node algorithms. 3107 These node traits and algorithms are 3108 described in the previous chapter: [link intrusive.node_algorithms Node Algorithms]. 3109 3110 * If my_value_traits is meant to be used with [classref boost::intrusive::slist slist], 3111 `node_traits` should follow 3112 the interface needed by [classref boost::intrusive::circular_slist_algorithms circular_slist_algorithms]. 3113 3114 * If my_value_traits is meant to be used with [classref boost::intrusive::list list], 3115 `node_traits` should follow 3116 the interface needed by [classref boost::intrusive::circular_list_algorithms circular_list_algorithms]. 3117 3118 * If my_value_traits is meant to be used with [classref boost::intrusive::set set]/[classref boost::intrusive::multiset multiset], 3119 `node_traits` should follow 3120 the interface needed by [classref boost::intrusive::rbtree_algorithms rbtree_algorithms]. 3121 3122 * If my_value_traits is meant to be used with [classref boost::intrusive::unordered_set unordered_set]/ 3123 [classref boost::intrusive::unordered_multiset unordered_multiset], `node_traits` 3124 should follow the interface needed by [classref boost::intrusive::circular_slist_algorithms circular_slist_algorithms]. 3125 3126* [*['node_ptr]]: A typedef for `node_traits::node_ptr`. 3127 3128* [*['const_node_ptr]]: A typedef for `node_traits::const_node_ptr`. 3129 3130* [*['value_type]]: The type that the user wants to insert in the container. This type can be 3131 the same as `node_traits::node` but it can be different (for example, `node_traits::node` 3132 can be a member type of `value_type`). If `value_type` and `node_traits::node` are the 3133 same type, the `to_node_ptr` and `to_value_ptr` functions are trivial. 3134 3135* [*['pointer]]: The type of a pointer to a `value_type`. It must be the same pointer type 3136 as `node_ptr`: If `node_ptr` is `node*`, `pointer` must be `value_type*`. If 3137 `node_ptr` is `smart_ptr<node_traits::node>`, `pointer` must be `smart_ptr<value_type>`. 3138 This can be generically achieved using `boost::intrusive::pointer_traits` (portable implementation of C++11 3139 `std::pointer_traits`). 3140 3141* [*['const_pointer]]: The type of a pointer to a `const value_type`. It must be the same pointer type 3142 as `node_ptr`: If `node_ptr` is `node*`, `const_pointer` must be `const value_type*`. If 3143 `node_ptr` is `smart_ptr<node_traits::node>`, `const_pointer` must be `smart_ptr<const value_type>`. 3144 3145* [*['link_mode]]: Indicates that `value_traits` needs some additional work or checks from the 3146 container. The types are enumerations defined in the `link_mode.hpp` header. 3147 These are the possible types: 3148 3149 * [*`normal_link`]: If this linking policy is specified in a `ValueTraits` class 3150 as the link mode, containers 3151 configured with such `ValueTraits` won't set the hooks 3152 of the erased values to a default state. Containers also won't 3153 check that the hooks of the new values are default initialized. 3154 3155 * [*`safe_link`]: If this linking policy is specified as the link mode 3156 in a `ValueTraits` class, containers 3157 configured with this `ValueTraits` will set the hooks 3158 of the erased values to a default state. Containers also will 3159 check that the hooks of the new values are default initialized. 3160 3161 * [*`auto_unlink`]: Same as "safe_link" but containers with 3162 constant-time size features won't be 3163 compatible with `ValueTraits` configured with this policy. 3164 Containers also know that a value can be silently erased from 3165 the container without using any function provided by the containers. 3166 3167* [*['static node_ptr to_node_ptr (value_type &value)]] and 3168 [*['static const_node_ptr to_node_ptr (const value_type &value)]]: 3169 These functions take a reference to a value_type and return a pointer to the node 3170 to be used with node algorithms. 3171 3172* [*['static pointer to_value_ptr (node_ptr n)]] and 3173 [*['static const_pointer to_value_ptr (const_node_ptr n)]]: 3174 These functions take a pointer to a node and return a pointer to the value 3175 that contains the node. 3176 3177[endsect] 3178 3179[section:value_traits_example Custom ValueTraits example] 3180 3181Let's define our own `value_traits` class to be able to use [*Boost.Intrusive] 3182containers with an old C structure whose definition can't be changed. 3183That legacy type has two pointers that can be used to build singly and doubly linked 3184lists: in singly linked lists we only need a pointer, whereas in doubly 3185linked lists, we need two pointers. Since we only have two pointers, we can't insert 3186the object in both a singly and a doubly linked list at the same time. 3187This is the definition of the old node: 3188 3189[import ../example/doc_value_traits.cpp] 3190[doc_value_traits_code_legacy] 3191 3192Now we have to define a NodeTraits class that will implement the functions/typedefs 3193that will make the legacy node compatible with [*Boost.Intrusive] algorithms. After that, 3194we'll define a ValueTraits class that will configure [*Boost.Intrusive] containers: 3195 3196[doc_value_traits_value_traits] 3197 3198Defining a value traits class that simply defines `value_type` as 3199`legacy_node_traits::node` is a common approach when defining customized 3200intrusive containers, so [*Boost.Intrusive] offers a templatized 3201[classref boost::intrusive::trivial_value_traits trivial_value_traits] class 3202that does exactly what we want: 3203 3204[doc_value_traits_trivial] 3205 3206Now we can just define the containers that will store the legacy abi objects and write 3207a little test: 3208 3209[doc_value_traits_test] 3210 3211As seen, several key elements of [*Boost.Intrusive] can be reused with custom user types, 3212if the user does not want to use the provided [*Boost.Intrusive] facilities. 3213 3214[endsect] 3215 3216[section:reusing_node_algorithms Reusing node algorithms for different values] 3217 3218In the previous example, `legacy_node_traits::node` type and 3219`legacy_value_traits::value_type` are the same type, but this is not necessary. It's possible 3220to have several `ValueTraits` defining the same `node_traits` type (and thus, the same `node_traits::node`). 3221This reduces the number of node algorithm instantiations, but 3222now `ValueTraits::to_node_ptr` and `ValueTraits::to_value_ptr` functions need to offer 3223conversions between both types. Let's see a small example: 3224 3225First, we'll define the node to be used in the algorithms. For a linked list, 3226we just need a node that stores two pointers: 3227 3228[import ../example/doc_advanced_value_traits.cpp] 3229[doc_advanced_value_traits_code] 3230 3231Now we'll define two different types that will be inserted in intrusive lists and 3232a templatized `ValueTraits` that will work for both types: 3233 3234[doc_advanced_value_traits_value_traits] 3235 3236Now define two containers. Both containers will instantiate the same list algorithms 3237(`circular_list_algorithms<simple_node_traits>`), 3238due to the fact that the value traits used to define the containers provide the same `node_traits` type: 3239 3240[doc_advanced_value_traits_containers] 3241 3242All [*Boost.Intrusive] containers using predefined hooks use this technique to minimize code size: 3243all possible [classref boost::intrusive::list list] containers 3244created with predefined hooks that define the same `VoidPointer` type 3245share the same list algorithms. 3246 3247[endsect] 3248 3249[section:simplifying_value_traits Simplifying value traits definition] 3250 3251The previous example can be further simplified using the 3252[classref boost::intrusive::derivation_value_traits derivation_value_traits] 3253class to define a value traits class with a value that stores the 3254`simple_node` as a base class: 3255 3256[import ../example/doc_derivation_value_traits.cpp] 3257[doc_derivation_value_traits_value_traits] 3258 3259We can even choose to store `simple_node` as a member of `value_1` and `value_2` 3260classes and use [classref boost::intrusive::member_value_traits member_value_traits] 3261to define the needed value traits classes: 3262 3263[import ../example/doc_member_value_traits.cpp] 3264[doc_member_value_traits_value_traits] 3265 3266[endsect] 3267 3268[section:stateful_value_traits Stateful value traits] 3269 3270Until now all shown custom value traits are stateless, that is, [*the transformation between nodes 3271and values is implemented in terms of static functions]. It's possible to use [*stateful] value traits 3272so that we can separate nodes and values and [*avoid modifying types to insert nodes]. 3273[*Boost.Intrusive] differentiates between stateful and stateless value traits by checking if all 3274Node <-> Value transformation functions are static or not (except for Visual 7.1, since overloaded 3275static function detection is not possible, in this case the implementation checks if the class is empty): 3276 3277* If all Node <-> Value transformation functions are static , a [*stateless] 3278 value traits is assumed. transformations must be static functions. 3279* Otherwise a [*stateful] value traits is assumed. 3280 3281Using stateful value traits it's possible to create containers of non-copyable/movable objects [*without modifying] 3282the definition of the class to be inserted. This interesting property is achieved without using global variables 3283(stateless value traits could use global variables to achieve the same goal), so: 3284 3285* [*Thread-safety guarantees]: Better thread-safety guarantees can be achieved with stateful 3286 value traits, since accessing global resources might require synchronization primitives that 3287 can be avoided when using internal state. 3288* [*Flexibility]: A stateful value traits type can be configured at run-time. 3289* [*Run-time polymorphism]: A value traits might implement node <-> value 3290 transformations as virtual functions. A single container type could be 3291 configured at run-time to use different node <-> value relationships. 3292 3293Stateful value traits have many advantages but also some downsides: 3294 3295* [*Performance]: Value traits operations should be very efficient since they are basic operations used by containers. 3296 [*A heavy node <-> value transformation will hurt intrusive containers' performance]. 3297* [*Exception guarantees]: The stateful ValueTraits must maintain no-throw guarantees, otherwise, the 3298 container invariants won't be preserved. 3299* [*Static functions]: Some static functions offered by intrusive containers are not 3300 available because node <-> value transformations are not static. 3301* [*Bigger iterators]: The size of some iterators is increased because the iterator 3302 needs to store a pointer to the stateful value traits to implement node to value 3303 transformations (e.g. `operator*()` and `operator->()`). 3304 3305An easy and useful example of stateful value traits is when an array of values can be indirectly introduced 3306in a list guaranteeing no additional allocation apart from the initial resource reservation: 3307 3308[import ../example/doc_stateful_value_traits.cpp] 3309[doc_stateful_value_traits] 3310 3311[endsect] 3312 3313[endsect] 3314 3315[section:thread_safety Thread safety guarantees] 3316 3317Intrusive containers have thread safety guarantees similar to STL containers. 3318 3319* Several threads having read or write access to different instances is safe as long as inserted 3320 objects are different. 3321* Concurrent read-only access to the same container is safe. 3322 3323Some Intrusive hooks (auto-unlink hooks, for example) modify containers without 3324having a reference to them: this is considered a write access to the container. 3325 3326Other functions, like checking if an object is already inserted in a container using the `is_linked()` 3327member of safe hooks, constitute read access on the container without having a reference to it, so no other 3328thread should have write access (direct or indirect) to that container. 3329 3330Since the same object can be inserted in several containers at the same time using different hooks, 3331the thread safety of [*Boost.Intrusive] is related to the containers and also to the object whose lifetime 3332is manually managed by the user. 3333 3334As we can see, the analysis of the thread-safety of a program using [*Boost.Intrusive] is harder 3335than with non-intrusive containers. 3336 3337To analyze the thread safety, consider the following points: 3338 3339* The auto-unlink hook's destructor and `unlink()` functions modify the container indirectly. 3340* The safe mode and auto-unlink hooks' `is_linked()` functions are a read access to the container. 3341* Inserting an object in containers that will be modified by different threads has no thread safety 3342 guarantee, although in most platforms it will be thread-safe without locking. 3343 3344[endsect] 3345 3346[section:boost_intrusive_iterators Boost.Intrusive Iterator features] 3347 3348[section:null_forward_iterators Null forward iterators] 3349 3350[*Boost.Intrusive] implements 3351[@http://www.open-std.org/JTC1/sc22/WG21/docs/papers/2013/n3644.pdf C++14 Null Forward Iterators], 3352a feature that was introduced with C++14. This means that equality and inequality comparison are defined 3353over all iterators for the same underlying sequence and the value initialized-iterators. 3354 3355Value initialized iterators behave as if they refer past the end of the same empty sequence: 3356 3357[c++] 3358 3359 list<MyType> l = { ... }; 3360 auto ni = list<MyType>::iterator(); 3361 auto nd = list<MyType2>::iterator(); 3362 ni == ni; // True. 3363 nd != nd; // False. 3364 ni == nd; // Won't compile. 3365 3366[endsect] 3367 3368[section:scary_iterators Scary Iterators] 3369 3370The paper N2913, titled [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2913.pdf, 3371SCARY Iterator Assignment and Initialization], proposed a requirement that a standard container's 3372iterator types have no dependency on any type argument apart from the container's `value_type`, 3373`difference_type`, `pointer type`, and `const_pointer` type. In particular, according to the proposal, 3374the types of a standard container's iterators should not depend on the container's `key_compare`, 3375`hasher`, `key_equal`, or `allocator` types. 3376 3377That paper demonstrated that SCARY operations were crucial to the performant implementation of common 3378design patterns using STL components. It showed that implementations that support SCARY operations reduce 3379object code bloat by eliminating redundant specializations of iterator and algorithm templates. 3380 3381[*Boost.Intrusive] containers are a bit different from standard containers. In particular, they have no 3382allocator parameter and they can be configured with additional options not present in STL-like containers. 3383Thus [*Boost.Intrusive] offers its own `SCARY iterator` implementation, where iterator types don't 3384change when the container is configured with an option that does not alter the value <-> node transformation. 3385More concretely, the following options and conditions guarantee that iterator types are unchanged: 3386 3387* [*All containers]: `size_type<>`, `constant_time_size<>`, 3388* [*`slist`]: `cache_last<>`, `linear<>`, 3389* [*`unordered_[multi]set`]: `hash<>`, `equal<>`, `power_2_buckets<>`, `cache_begin<>`. 3390* [*All tree-like containers] (`[multi]set`, `avl_[multi]set`, `sg_[multi]set`, `bs_[multi]set`, 3391 `splay_[multi]set`, `treap_[multi]set`): `compare<>`. 3392* [*`treap_[multi]set`]: `priority<>` 3393* [*`bs_[multi]set`, `sg_[multi]set`, `treap_[multi]set`, `splay_[multi]set`]: 3394 They share the same iterator type when configured with the same options. 3395 3396[endsect] 3397 3398[endsect] 3399 3400[section:equal_range_stability Stability and insertion with hint in ordered associative containers with equivalent keys] 3401 3402[*Boost.Intrusive] ordered associative containers with equivalent keys offer stability guarantees, following 3403[@http://open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#233 C++ standard library's defect #233 resolution], 3404explained in document [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1780.html Comments on LWG issue 233: Insertion hints in associative containers]. 3405This means that: 3406 3407* A ['Insert without hint] member function always insert at the upper bound of an equal range. 3408* A ['Insert with hint] member function inserts the new value [*before the hint] if hint's and new node's keys are equivalent. 3409* Implements Andrew Koenig ['as close as possible to hint] proposal. A new element is always be inserted as close to the hint as possible. 3410 So, for example, if there is a subsequence of equivalent values, `a.begin()` as the hint means that the new element should be inserted 3411 before the subsequence even if `a.begin()` is far away. This allows code to always append (or prepend) an equal range with something 3412 as simple as: `m.insert(m.end(), new_node);` or `m.insert(m.begin(), new_node);` 3413 3414[endsect] 3415 3416[section:obtaining_same_type_reducing_space Obtaining the same types and reducing symbol length] 3417 3418The flexible option specification mechanism used by [*Boost.Intrusive] for hooks and containers 3419has a couple of downsides: 3420 3421* If a user specifies the same options in different order or specifies some options and leaves the 3422 rest as defaults, the type of the created container/hook will be different. Sometimes 3423 this is annoying, because two programmers specifying the same options might end up with incompatible 3424 types. For example, the following two lists, although using the same options, do not have 3425 the same type: 3426 3427[c++] 3428 3429 #include <boost/intrusive/list.hpp> 3430 3431 using namespace boost::intrusive; 3432 3433 //Explicitly specify constant-time size and size type 3434 typedef list<T, constant_time_size<true>, size_type<std::size_t> List1; 3435 3436 //Implicitly specify constant-time size and size type 3437 typedef list<T> List2; 3438 3439* Option specifiers lead to long template symbols for classes and functions. Option specifiers themselves 3440 are verbose and without variadic templates, several default template parameters are assigned for 3441 non-specified options. Object and debugging information files can grow and compilation times 3442 may suffer if long names are produced. 3443 3444To solve these issues [*Boost.Intrusive] offers some helper metafunctions that reduce symbol lengths 3445and create the same type if the same options (either explicitly or implicitly) are used. These also 3446improve compilation times. All containers and hooks have their respective `make_xxx` versions. 3447The previously shown example can be rewritten like this to obtain the same list type: 3448 3449[c++] 3450 3451 #include <boost/intrusive/list.hpp> 3452 3453 using namespace boost::intrusive; 3454 3455 #include <boost/intrusive/list.hpp> 3456 3457 using namespace boost::intrusive; 3458 3459 //Explicitly specify constant-time size and size type 3460 typedef make_list<T, constant_time_size<true>, size_type<std::size_t>::type List1; 3461 3462 //Implicitly specify constant-time size and size type 3463 typedef make_list<T>::type List2; 3464 3465Produced symbol lengths and compilation times will usually be shorter and object/debug files smaller. 3466If you are concerned with file sizes and compilation times, this option is your best choice. 3467 3468[endsect] 3469 3470[section:design_notes Design Notes] 3471 3472When designing [*Boost.Intrusive] the following guidelines have been taken into account: 3473 3474[section:performance_sensitive Boost.Intrusive in performance sensitive environments] 3475 3476[*Boost.Intrusive] should be a valuable tool in performance sensitive environments, 3477and following this guideline, [*Boost.Intrusive] has been designed to offer well 3478known complexity guarantees. Apart from that, some options, like optional 3479constant-time, have been designed to offer faster complexity guarantees in some 3480functions, like `slist::splice`. 3481 3482The advanced lookup and insertion functions for associative containers, taking 3483an arbitrary key type and predicates, were designed to avoid unnecessary object 3484constructions. 3485 3486[endsect] 3487 3488[section:space_constrained Boost.Intrusive in space constrained environments] 3489 3490[*Boost.Intrusive] should be useful in space constrained environments, 3491and following this guideline [*Boost.Intrusive] separates node algorithms 3492and intrusive containers to avoid instantiating node algorithms for each 3493user type. For example, a single class of red-black algorithms will be instantiated 3494to implement all set and multiset containers using raw pointers. This way, 3495[*Boost.Intrusive] seeks to avoid any code size overhead associated with templates. 3496 3497Apart from that, [*Boost.Intrusive] implements some size improvements: for example, 3498red-black trees embed the color bit in the parent pointer lower bit, if nodes 3499are two-byte aligned. The option to forgo constant-time size operations can 3500reduce container size, and this extra size optimization is noticeable 3501when the container is empty or contains few values. 3502 3503[endsect] 3504 3505[section:basic_building_block Boost.Intrusive as a basic building block] 3506 3507[*Boost.Intrusive] can be a basic building block to build more complex containers 3508and this potential has motivated many design decisions. For example, the ability 3509to have more than one hook per user type opens the opportunity to implement multi-index 3510containers on top of [*Boost.Intrusive]. 3511 3512[*Boost.Intrusive] containers implement advanced functions taking function objects 3513as arguments (`clone_from`, `erase_and_dispose`, `insert_check`, etc.). These 3514functions come in handy when implementing non-intrusive containers 3515(for example, STL-like containers) on top of intrusive containers. 3516 3517[endsect] 3518 3519[section:extending_intrusive Extending Boost.Intrusive] 3520 3521[*Boost.Intrusive] offers a wide range of containers but also allows the 3522construction of custom containers reusing [*Boost.Intrusive] elements. 3523The programmer might want to use node algorithms directly or 3524build special hooks that take advantage of an application environment. 3525 3526For example, the programmer can customize parts of [*Boost.Intrusive] 3527to manage old data structures whose definition can't be changed. 3528 3529[endsect] 3530 3531[endsect] 3532 3533[section:performance Performance] 3534 3535[*Boost.Intrusive] containers offer speed improvements compared to non-intrusive containers 3536primarily because: 3537 3538* They minimize memory allocation/deallocation calls. 3539* They obtain better memory locality. 3540 3541This section will show performance tests comparing some operations on 3542`boost::intrusive::list` and `std::list`: 3543 3544* Insertions using `push_back` and container destruction will show the 3545 overhead associated with memory allocation/deallocation. 3546* The `reverse` member function will show the advantages of the compact 3547 memory representation that can be achieved with intrusive containers. 3548* The `sort` and `write access` tests will show the advantage of intrusive containers 3549 minimizing memory accesses compared to containers of pointers. 3550 3551Given an object of type `T`, [classref boost::intrusive::list boost::intrusive::list<T>] 3552can replace `std::list<T>` to avoid memory allocation overhead, 3553or it can replace `std::list<T*>` when the user wants containers with 3554polymorphic values or wants to share values between several containers. 3555Because of this versatility, the performance tests will be executed for 6 different 3556list types: 3557 3558* 3 intrusive lists holding a class named `itest_class`, 3559 each one with a different linking policy (`normal_link`, `safe_link`, `auto_unlink`). 3560 The `itest_class` objects will be tightly packed in a `std::vector<itest_class>` object. 3561 3562* `std::list<test_class>`, where `test_class` is exactly the same as `itest_class`, 3563 but without the intrusive hook. 3564 3565* `std::list<test_class*>`. The list will contain pointers to `test_class` objects 3566 tightly packed in a `std::vector<test_class>` object. We'll call this configuration ['compact pointer list] 3567 3568* `std::list<test_class*>`. The list will contain pointers to `test_class` objects owned by a 3569 `std::list<test_class>` object. We'll call this configuration ['disperse pointer list]. 3570 3571Both `test_class` and `itest_class` are templatized classes that can be configured with 3572a boolean to increase the size of the object. This way, the tests can be executed with 3573small and big objects. Here is the first part of the testing code, which shows 3574the definitions of `test_class` and `itest_class` classes, and some other 3575utilities: 3576 3577[import ../perf/perf_list.cpp] 3578[perf_list_value_type] 3579 3580As we can see, `test_class` is a very simple class holding an `int`. `itest_class` 3581is just a class that has a base hook ([classref boost::intrusive::list_base_hook list_base_hook]) 3582and also derives from `test_class`. 3583 3584`func_ptr_adaptor` is just a functor adaptor to convert function objects taking 3585`test_list` objects to function objects taking pointers to them. 3586 3587You can find the full test code in the 3588[@../../libs/intrusive/perf/perf_list.cpp perf_list.cpp] source file. 3589 3590[section:performance_results_push_back Back insertion and destruction] 3591 3592The first test will measure the benefits we can obtain with intrusive containers 3593avoiding memory allocations and deallocations. All the objects to be 3594inserted in intrusive containers are allocated in a single allocation call, 3595whereas `std::list` will need to allocate memory for each object and deallocate it 3596for every erasure (or container destruction). 3597 3598Let's compare the code to be executed for each container type for different insertion tests: 3599 3600[perf_list_push_back_intrusive] 3601 3602For intrusive containers, all the values are created in a vector and after that 3603inserted in the intrusive list. 3604 3605[perf_list_push_back_stdlist] 3606 3607For a standard list, elements are pushed back using push_back(). 3608 3609[perf_list_push_back_stdptrlist] 3610 3611For a standard compact pointer list, elements are created in a vector and pushed back 3612in the pointer list using push_back(). 3613 3614[perf_list_push_back_disperse_stdptrlist] 3615 3616For a ['disperse pointer list], elements are created in a list and pushed back 3617in the pointer list using push_back(). 3618 3619These are the times in microseconds for each case, and the normalized time: 3620 3621[table Back insertion + destruction times for Visual C++ 7.1 / Windows XP 3622 [[Container] [Time in us/iteration (small object / big object)] [Normalized time (small object / big object)]] 3623 [[`normal_link` intrusive list] [5000 / 22500] [1 / 1]] 3624 [[`safe_link` intrusive list] [7812 / 32187] [1.56 / 1.43]] 3625 [[`auto_unlink` intrusive list] [10156 / 41562] [2.03 / 1.84]] 3626 [[Standard list] [26875 / 97500] [5.37 / 4.33]] 3627 [[Standard compact pointer list] [76406 / 86718] [15.28 / 3.85]] 3628 [[Standard disperse pointer list] [146562 / 175625] [29.31 / 7.80]] 3629] 3630 3631[table Back insertion + destruction times for GCC 4.1.1 / MinGW over Windows XP 3632 [[Container] [Time in us/iteration (small object / big object)] [Normalized time (small object / big object)]] 3633 [[`normal_link` intrusive list] [4375 / 22187] [1 / 1]] 3634 [[`safe_link` intrusive list] [7812 / 32812] [1.78 / 1.47]] 3635 [[`auto_unlink` intrusive list] [10468 / 42031] [2.39 / 1.89]] 3636 [[Standard list] [81250 / 98125] [18.57 / 4.42]] 3637 [[Standard compact pointer list] [83750 / 94218] [19.14 / 4.24]] 3638 [[Standard disperse pointer list] [155625 / 175625] [35.57 / 7.91]] 3639] 3640 3641[table Back insertion + destruction times for GCC 4.1.2 / Linux Kernel 2.6.18 (OpenSuse 10.2) 3642 [[Container] [Time in us/iteration (small object / big object)] [Normalized time (small object / big object)]] 3643 [[`normal_link` intrusive list] [4792 / 20495] [1 / 1]] 3644 [[`safe_link` intrusive list] [7709 / 30803] [1.60 / 1.5]] 3645 [[`auto_unlink` intrusive list] [10180 / 41183] [2.12 / 2.0]] 3646 [[Standard list] [17031 / 32586] [3.55 / 1.58]] 3647 [[Standard compact pointer list] [27221 / 34823] [5.68 / 1.69]] 3648 [[Standard disperse pointer list] [102272 / 60056] [21.34 / 2.93]] 3649] 3650 3651The results are logical: intrusive lists just need one allocation. The destruction 3652time of the `normal_link` intrusive container is trivial (complexity: `O(1)`), 3653whereas `safe_link` and `auto_unlink` intrusive containers need to put the hooks of 3654erased values in the default state (complexity: `O(NumElements)`). That's why 3655`normal_link` intrusive list shines in this test. 3656 3657Non-intrusive containers need to make many more allocations and that's why they 3658lag behind. The `disperse pointer list` needs to make `NumElements*2` allocations, 3659so the result is not surprising. 3660 3661The Linux test shows that standard containers perform very well against intrusive containers 3662with big objects. Nearly the same GCC version in MinGW performs worse, so maybe 3663a good memory allocator is the reason for these excellent results. 3664 3665[endsect] 3666 3667[section:performance_results_reversing Reversing] 3668 3669The next test measures the time needed to complete calls to the member function `reverse()`. 3670Values (`test_class` and `itest_class`) and lists are created as explained in the 3671previous section. 3672 3673Note that for pointer lists, `reverse` [*does not need to access `test_class` values 3674stored in another list or vector], 3675since this function just needs to adjust internal pointers, so in theory all tested 3676lists need to perform the same operations. 3677 3678These are the results: 3679 3680[table Reverse times for Visual C++ 7.1 / Windows XP 3681 [[Container] [Time in us/iteration (small object / big object)] [Normalized time (small object / big object)]] 3682 [[`normal_link` intrusive list] [2656 / 10625] [1 / 1.83]] 3683 [[`safe_link` intrusive list] [2812 / 10937] [1.05 / 1.89]] 3684 [[`auto_unlink` intrusive list] [2710 / 10781] [1.02 / 1.86]] 3685 [[Standard list] [5781 / 14531] [2.17 / 2.51]] 3686 [[Standard compact pointer list] [5781 / 5781] [2.17 / 1]] 3687 [[Standard disperse pointer list] [10781 / 15781] [4.05 / 2.72]] 3688] 3689 3690[table Reverse times for GCC 4.1.1 / MinGW over Windows XP 3691 [[Container] [Time in us/iteration (small object / big object)] [Normalized time (small object / big object)]] 3692 [[`normal_link` intrusive list] [2656 / 10781] [1 / 2.22]] 3693 [[`safe_link` intrusive list] [2656 / 10781] [1 / 2.22]] 3694 [[`auto_unlink` intrusive list] [2812 / 10781] [1.02 / 2.22]] 3695 [[Standard list] [4843 / 12500] [1.82 / 2.58]] 3696 [[Standard compact pointer list] [4843 / 4843] [1.82 / 1]] 3697 [[Standard disperse pointer list] [9218 / 12968] [3.47 / 2.67]] 3698] 3699 3700[table Reverse times for GCC 4.1.2 / Linux Kernel 2.6.18 (OpenSuse 10.2) 3701 [[Container] [Time in us/iteration (small object / big object)] [Normalized time (small object / big object)]] 3702 [[`normal_link` intrusive list] [2742 / 10847] [1 / 3.41]] 3703 [[`safe_link` intrusive list] [2742 / 10847] [1 / 3.41]] 3704 [[`auto_unlink` intrusive list] [2742 / 11027] [1 / 3.47]] 3705 [[Standard list] [3184 / 10942] [1.16 / 3.44]] 3706 [[Standard compact pointer list] [3207 / 3176] [1.16 / 1]] 3707 [[Standard disperse pointer list] [5814 / 13381] [2.12 / 4.21]] 3708] 3709 3710For small objects the results show that the compact storage of values in intrusive 3711containers improve locality and reversing is faster than with standard containers, 3712whose values might be dispersed in memory because each value is independently 3713allocated. Note that the dispersed pointer list (a list of pointers to values 3714allocated in another list) suffers more because nodes of the pointer list 3715might be more dispersed, since allocations from both lists are interleaved 3716in the code: 3717 3718[c++] 3719 3720 //Object list (holding `test_class`) 3721 stdlist objects; 3722 3723 //Pointer list (holding `test_class` pointers) 3724 stdptrlist l; 3725 3726 for(int i = 0; i < NumElements; ++i){ 3727 //Allocation from the object list 3728 objects.push_back(stdlist::value_type(i)); 3729 //Allocation from the pointer list 3730 l.push_back(&objects.back()); 3731 } 3732 3733For big objects the compact pointer list wins because the reversal test doesn't need access 3734to values stored in another container. Since all the allocations for nodes of 3735this pointer list are likely to be close (since there is no other allocation in the 3736process until the pointer list is created) locality is better than with intrusive 3737containers. The dispersed pointer list, as with small values, has poor locality. 3738 3739[endsect] 3740 3741[section:performance_results_sorting Sorting] 3742 3743The next test measures the time needed to complete calls to the member function 3744`sort(Pred pred)`. Values (`test_class` and `itest_class`) and lists are created as explained in the 3745first section. The values will be sorted in ascending and descending order each 3746iteration. For example, if ['l] is a list: 3747 3748[c++] 3749 3750 for(int i = 0; i < NumIter; ++i){ 3751 if(!(i % 2)) 3752 l.sort(std::greater<stdlist::value_type>()); 3753 else 3754 l.sort(std::less<stdlist::value_type>()); 3755 } 3756 3757For a pointer list, the function object will be adapted using `func_ptr_adaptor`: 3758 3759[c++] 3760 3761 for(int i = 0; i < NumIter; ++i){ 3762 if(!(i % 2)) 3763 l.sort(func_ptr_adaptor<std::greater<stdlist::value_type> >()); 3764 else 3765 l.sort(func_ptr_adaptor<std::less<stdlist::value_type> >()); 3766 } 3767 3768Note that for pointer lists, `sort` will take a function object that [*will access 3769`test_class` values stored in another list or vector], so pointer lists will suffer 3770an extra indirection: they will need to access the `test_class` values stored in 3771another container to compare two elements. 3772 3773These are the results: 3774 3775[table Sort times for Visual C++ 7.1 / Windows XP 3776 [[Container] [Time in us/iteration (small object / big object)] [Normalized time (small object / big object)]] 3777 [[`normal_link` intrusive list] [16093 / 38906] [1 / 1]] 3778 [[`safe_link` intrusive list] [16093 / 39062] [1 / 1]] 3779 [[`auto_unlink` intrusive list] [16093 / 38906] [1 / 1]] 3780 [[Standard list] [32343 / 56406] [2.0 / 1.44]] 3781 [[Standard compact pointer list] [33593 / 46093] [2.08 / 1.18]] 3782 [[Standard disperse pointer list] [46875 / 68593] [2.91 / 1.76]] 3783] 3784 3785[table Sort times for GCC 4.1.1 / MinGW over Windows XP 3786 [[Container] [Time in us/iteration (small object / big object)] [Normalized time (small object / big object)]] 3787 [[`normal_link` intrusive list] [15000 / 39218] [1 / 1]] 3788 [[`safe_link` intrusive list] [15156 / 39531] [1.01 / 1.01]] 3789 [[`auto_unlink` intrusive list] [15156 / 39531] [1.01 / 1.01]] 3790 [[Standard list] [34218 / 56875] [2.28 / 1.45]] 3791 [[Standard compact pointer list] [35468 / 49218] [2.36 / 1.25]] 3792 [[Standard disperse pointer list] [47656 / 70156] [3.17 / 1.78]] 3793] 3794 3795[table Sort times for GCC 4.1.2 / Linux Kernel 2.6.18 (OpenSuse 10.2) 3796 [[Container] [Time in us/iteration (small object / big object)] [Normalized time (small object / big object)]] 3797 [[`normal_link` intrusive list] [18003 / 40795] [1 / 1]] 3798 [[`safe_link` intrusive list] [18003 / 41017] [1 / 1]] 3799 [[`auto_unlink` intrusive list] [18230 / 40941] [1.01 / 1]] 3800 [[Standard list] [26273 / 49643] [1.45 / 1.21]] 3801 [[Standard compact pointer list] [28540 / 43172] [1.58 / 1.05]] 3802 [[Standard disperse pointer list] [35077 / 57638] [1.94 / 1.41]] 3803] 3804 3805The results show that intrusive containers are faster than standard 3806containers. We can see that the pointer 3807list holding pointers to values stored in a vector is quite fast, so the extra 3808indirection that is needed to access the value is minimized because all the values 3809are tightly stored, improving caching. The disperse list, on the other hand, is 3810slower because the indirection to access values stored in the object list is 3811more expensive than accessing values stored in a vector. 3812 3813[endsect] 3814 3815[section:performance_results_write_access Write access] 3816 3817The next test measures the time needed to iterate through all the elements of a list, and 3818increment the value of the internal `i_` member: 3819 3820[c++] 3821 3822 stdlist::iterator it(l.begin()), end(l.end()); 3823 for(; it != end; ++it) 3824 ++(it->i_); 3825 3826Values (`test_class` and `itest_class`) and lists are created as explained in 3827the first section. Note that for pointer lists, the iteration will suffer 3828an extra indirection: they will need to access the `test_class` values stored in 3829another container: 3830 3831[c++] 3832 3833 stdptrlist::iterator it(l.begin()), end(l.end()); 3834 for(; it != end; ++it) 3835 ++((*it)->i_); 3836 3837These are the results: 3838 3839[table Write access times for Visual C++ 7.1 / Windows XP 3840 [[Container] [Time in us/iteration (small object / big object)] [Normalized time (small object / big object)]] 3841 [[`normal_link` intrusive list] [2031 / 8125] [1 / 1]] 3842 [[`safe_link` intrusive list] [2031 / 8281] [1 / 1.01]] 3843 [[`auto_unlink` intrusive list] [2031 / 8281] [1 / 1.01]] 3844 [[Standard list] [4218 / 10000] [2.07 / 1.23]] 3845 [[Standard compact pointer list] [4062 / 8437] [2.0 / 1.03]] 3846 [[Standard disperse pointer list] [8593 / 13125] [4.23 / 1.61]] 3847] 3848 3849[table Write access times for GCC 4.1.1 / MinGW over Windows XP 3850 [[Container] [Time in us/iteration (small object / big object)] [Normalized time (small object / big object)]] 3851 [[`normal_link` intrusive list] [2343 / 8281] [1 / 1]] 3852 [[`safe_link` intrusive list] [2500 / 8281] [1.06 / 1]] 3853 [[`auto_unlink` intrusive list] [2500 / 8281] [1.06 / 1]] 3854 [[Standard list] [4218 / 10781] [1.8 / 1.3]] 3855 [[Standard compact pointer list] [3906 / 8281] [1.66 / 1]] 3856 [[Standard disperse pointer list] [8281 / 13750] [3.53 / 1.66]] 3857] 3858 3859[table Write access times for GCC 4.1.2 / Linux Kernel 2.6.18 (OpenSuse 10.2) 3860 [[Container] [Time in us/iteration (small object / big object)] [Normalized time (small object / big object)]] 3861 [[`normal_link` intrusive list] [2286 / 8468] [1 / 1.1]] 3862 [[`safe_link` intrusive list] [2381 / 8412] [1.04 / 1.09]] 3863 [[`auto_unlink` intrusive list] [2301 / 8437] [1.01 / 1.1]] 3864 [[Standard list] [3044 / 9061] [1.33 / 1.18]] 3865 [[Standard compact pointer list] [2755 / 7660] [1.20 / 1]] 3866 [[Standard disperse pointer list] [6118 / 12453] [2.67 / 1.62]] 3867] 3868 3869As with the read access test, the results show that intrusive containers outperform 3870all other containers if the values are tightly packed in a vector. 3871The disperse list is again the slowest. 3872 3873[endsect] 3874 3875[section:performance_results_conclusions Conclusions] 3876 3877Intrusive containers can offer performance benefits that cannot be achieved with 3878equivalent non-intrusive containers. Memory locality improvements are noticeable 3879when the objects to be inserted are small. Minimizing memory allocation/deallocation calls is also 3880an important factor and intrusive containers make this simple if all objects 3881to be inserted in intrusive containers are allocated using `std::vector` or `std::deque`. 3882 3883[endsect] 3884 3885[endsect] 3886 3887[section:release_notes Release Notes] 3888 3889[section:release_notes_boost_1_73_00 Boost 1.73 Release] 3890 3891* Fixed bugs: 3892 * [@https://github.com/boostorg/intrusive/issues/46 GitHub #46: ['UB due to union based type punning]] 3893 3894[endsect] 3895 3896[section:release_notes_boost_1_71_00 Boost 1.71 Release] 3897 3898* Fixed bugs: 3899 * [@https://github.com/boostorg/intrusive/pull/42 GitHub #42: ['Documentation does not describe treap priority_of_value changes]] 3900 * [@https://github.com/boostorg/intrusive/pull/43 GitHub #43: ['Fix tests with BOOST_INTRUSIVE_VARIADIC_TEMPLATES enabled]] 3901 * [@https://github.com/boostorg/intrusive/pull/45 GitHub #45: ['Disable variadic templates for MSVC-12 to avoid ICEs]] 3902 3903[endsect] 3904 3905[section:release_notes_boost_1_70_00 Boost 1.70 Release] 3906 3907* Fixed bugs: 3908 * [@https://github.com/boostorg/intrusive/pull/33 GitHub Pull #33: ['Fix compilation in case if key is void*, again]] 3909 * [@https://github.com/boostorg/intrusive/issues/34 GitHub Issue #34: ['-Wdeprecated-copy on gcc9]] 3910 * [@https://github.com/boostorg/intrusive/issues/35 GitHub Issue #35: ['key_of_value on treap_set seems to be broken in 1.69]] 3911 * [@https://github.com/boostorg/intrusive/issues/38 GitHub Issue #38: ['treap: Same type for priority and key comparison leads to ambiguous base class error]] 3912 * [@https://github.com/boostorg/intrusive/pull/39 GitHub Pull #39: ['Fix -Wextra-semi clang warnings]] 3913 3914[endsect] 3915 3916[section:release_notes_boost_1_67_00 Boost 1.67 Release] 3917 3918* Fixed bugs: 3919 * [@https://github.com/boostorg/intrusive/issues/29 GitHub Issues #29: ['Uninitialized variable warning pointer_plus_bits.hpp]] 3920 3921[endsect] 3922 3923[section:release_notes_boost_1_65_00 Boost 1.65 Release] 3924 3925* Fixed bugs: 3926 * [@https://svn.boost.org/trac/boost/ticket/12894 Boost Trac #12894: ['Allow non std::size_t size_type]] 3927 * [@https://svn.boost.org/trac/boost/ticket/12698 Boost Trac #12698: ['base64 iterators can't be used with iterator_advance]] 3928 * [@https://github.com/boostorg/intrusive/pull/23 GitHub Pull #23: ['Conditionally replace deprecated/removed C++98 std::random_shuffle by...]] 3929 * [@https://github.com/boostorg/intrusive/pull/24 GitHub Pull #24: ['Adds support for MSVC ARM64 target]] 3930 3931[endsect] 3932 3933[section:release_notes_boost_1_64_00 Boost 1.64 Release] 3934 3935* Fixed bugs: 3936 * [@https://svn.boost.org/trac/boost/ticket/12745 Boost Trac #12745: ['key_nodeptr_comp broken if the key type is void*]] 3937 * [@https://svn.boost.org/trac/boost/ticket/12761 Boost Trac #12761: ['intrusive::set::swap doesn't swap the comparison function*]] 3938 3939[endsect] 3940 3941[section:release_notes_boost_1_63_00 Boost 1.63 Release] 3942 3943* Fixed bugs: 3944 * [@https://svn.boost.org/trac/boost/ticket/12556 Boost Trac #12556: ['member_value_traits.hpp has a missing #include]] 3945 3946[endsect] 3947 3948[section:release_notes_boost_1_62_00 Boost 1.62 Release] 3949 3950* Fixed bugs: 3951 * [@https://svn.boost.org/trac/boost/ticket/11476 Boost Trac #11476: ['has_member_function_callable_with.hpp is massively broken with BOOST_NO_CXX11_DECLTYPE]] 3952 * [@https://svn.boost.org/trac/boost/ticket/11994 Boost Trac #11994: ['Support intrusive container key extractors that return the key by value]] 3953 * [@https://svn.boost.org/trac/boost/ticket/12184 Boost Trac #12184: ['clang -Wdocumentation warning]] 3954 * [@https://svn.boost.org/trac/boost/ticket/12190 Boost Trac #12190: ['Intrusive List + Flat Map combination crashes]] 3955 * [@https://svn.boost.org/trac/boost/ticket/12229 Boost Trac #12229: ['intrusive::unordered_set<T>::rehash() broken]] 3956 * [@https://svn.boost.org/trac/boost/ticket/12245 Boost Trac #12245: ['bstree uses a shared static size_traits for constant_time_size<false>]] 3957 * [@https://svn.boost.org/trac/boost/ticket/12432 Boost Trac #12432: ['Forced KeyOfValue creation when using custom compare on insert_check]] 3958 3959* Implemented `merge` functions in ordered associative containers. 3960* Officially documented `root()` function for tree-based containers. 3961 3962[endsect] 3963 3964[section:release_notes_boost_1_61_00 Boost 1.61 Release] 3965 3966* Fixed bugs: 3967 * [@https://svn.boost.org/trac/boost/ticket/11832 Boost Trac #11832: ['clang-cl + boost intrusive = miscompile]] 3968 * [@https://svn.boost.org/trac/boost/ticket/11865 Boost Trac #11865: ['Intrusive list explicit ctor error with Clang 3.6 (C++11/14)]] 3969 * [@https://svn.boost.org/trac/boost/ticket/11992 Boost Trac #11992: ['Add an overload of insert_check taking a key_type]] 3970 * [@https://github.com/boostorg/intrusive/pull/19 GitHub Pull #19: ['ebo_functor_holder: compile fix for copy constructor]] 3971 3972[endsect] 3973 3974[section:release_notes_boost_1_60_00 Boost 1.60 Release] 3975 3976* [link intrusive.advanced_lookups_insertions Advanced lookup and insertions] in ordered associative containers 3977 now support comparison functions that are not required to offer the same strict weak ordering as `key_compare`, 3978 the container must be partitioned in regards to the passed comparison object. 3979* Fixed bugs: 3980 * [@https://svn.boost.org/trac/boost/ticket/11701 Boost Trac #11701: ['Regression in boost::intrusive::set::equal_range]] 3981 * [@https://svn.boost.org/trac/boost/ticket/11765 Boost Trac #11765: ['sgtree.hpp:830: bad if test ?]] 3982 3983[endsect] 3984 3985[section:release_notes_boost_1_59_00 Boost 1.59 Release] 3986 3987* Implemented [link intrusive.map_multimap map and multimap-like interfaces]. 3988* Refactored hashtable containers to reduce template instantiations. 3989* Fixed bugs: 3990 * [@https://svn.boost.org/trac/boost/ticket/11222 Boost Trac #11222: ['intrusive/pointer_traits.hpp fails to compile with C++98]] 3991 3992[endsect] 3993 3994[section:release_notes_boost_1_58_00 Boost 1.58 Release] 3995 3996* Reduced compile-time dependencies, headers, and the use of Boost.Preprocessor, specially for hooks and iterators. 3997* Fixed bugs: 3998 * [@https://svn.boost.org/trac/boost/ticket/6720 Boost Trac #6720: ['intrusive::unordered_set::clear_and_dispose does not compile on VC11 Beta when passed a stateless lambda]] 3999 * [@https://svn.boost.org/trac/boost/ticket/10771 Boost Trac #10771: ['remove_if is broken for slist]] 4000 * [@https://svn.boost.org/trac/boost/ticket/10853 Boost Trac #10853: ['problem with detection of const_cast_from]] 4001 * [@https://svn.boost.org/trac/boost/ticket/10987 Boost Trac #10987: ['bug in any_xxx_node_traits, returning by reference]] 4002 4003[endsect] 4004 4005[section:release_notes_boost_1_57_00 Boost 1.57 Release] 4006 4007* Experimental version of node checkers, contributed by Matei David. Many thanks! 4008* Implemented [@http://www.open-std.org/JTC1/sc22/WG21/docs/papers/2013/n3644.pdf N3644: Null Forward Iterators] from C++14. 4009* Fixed bugs: 4010 * [@https://github.com/boostorg/intrusive/pull/12 GitHub Pull #12: ['Fix MSVC14 warning C4456: declaration of 'x_parent_right' hides previous local declaration]] 4011 * [@https://svn.boost.org/trac/boost/ticket/10520 Boost Trac #10520: ['Conversion warning in intrusive/detail/utilities.hpp]] 4012 * [@https://svn.boost.org/trac/boost/ticket/10469 Boost Trac #10469: ['Erasing from intrusive unordered_multiset with optimize_multikey goes into an infinite loop]] 4013 4014[endsect] 4015 4016[section:release_notes_boost_1_56_00 Boost 1.56 Release] 4017 4018* Improved Doxygen generated reference and updated and fixed forward-declaration header. 4019 4020* [*ABI breaking]: Fixed ABI regression introduced in Boost 1.55 version, mainly noticeable on MSVC compilers. 4021 4022* [*Source breaking]: Removed previously deprecated `xxx_dont_splay` functions from splay containers, 4023 `splay_set_base_hook` and `splay_set_member_hook`from splay containers and `bool splay = true` 4024 extra parameter in `splaytree_algorithms` functions. 4025 4026* Fixed bugs: 4027 * [@https://svn.boost.org/trac/boost/ticket/8468 #8468: Compile error on visual studio 2010/2012 using vector with custom allocator and aligned types] 4028 * [@https://svn.boost.org/trac/boost/ticket/9332 #9332: ['"has_member_function_callable_with.hpp compile error on msvc-12.0"]]. 4029 * [@https://svn.boost.org/trac/boost/ticket/9650 #9650: ['"intrusive list with stateful value traits"]]. 4030 * [@https://svn.boost.org/trac/boost/ticket/9746 #9746: Modern Sun CC compiler detects error in intrusive library header] 4031 * [@https://svn.boost.org/trac/boost/ticket/9940 #9940: bad bug in intrusive list with safe_link (or auto_unlink) hooks] 4032 * [@https://svn.boost.org/trac/boost/ticket/9948 #9948: remove use of const_cast in intrusive containers] 4033 * [@https://svn.boost.org/trac/boost/ticket/9949 #9949: clear header node hooks upon intrusive container destruction] 4034 * [@https://svn.boost.org/trac/boost/ticket/9961 #9961: tests for hooks not derived frorm generic_hook] 4035 4036* Optimized tree rebalancing code to avoid redundant assignments. 4037 4038* Added 64 bit prime values for `suggested_upper_bucket_count`/`suggested_lower_bucket_count` in 64 bit platforms. 4039 4040* Deleted workarounds for old SUN_CC compilers, those are now unsupported as modern SunPro compilers are standard-corforming enough. 4041 4042[endsect] 4043 4044[section:release_notes_boost_1_55_00 Boost 1.55 Release] 4045 4046* [*Source breaking]: Deprecated `xxx_dont_splay` functions from splay containers. 4047 Deprecated `splay_set_base_hook` and `splay_set_member_hook`from splay containers, use 4048 `bs_set_base_hook` or `bs_set_member_hook` instead. 4049 Both will be removed in Boost 1.56. 4050 4051* [*ABI breaking]: Hash containers' end iterator was implemented pointing to one-past the end of the bucket array 4052 (see [@https://svn.boost.org/trac/boost/ticket/8698 #8698]) causing severe bugs when values to be inserted 4053 where allocated next to the bucket array. End iterator implementation was changed to point to the beginning 4054 of the bucket array. 4055 4056* Big refactoring in order to reduce template and debug symbol bloat. Test object files have been slashed 4057 to half in MSVC compilers in Debug mode. Toolchains without Identical COMDAT Folding (ICF) should notice size improvements. 4058 4059* Implemented [link intrusive.scary_iterators SCARY iterators]. 4060 4061[endsect] 4062 4063[section:release_notes_boost_1_54_00 Boost 1.54 Release] 4064 4065* Added `BOOST_NO_EXCEPTIONS` support (bug [@https://svn.boost.org/trac/boost/ticket/7849 #7849]). 4066 4067[endsect] 4068 4069[section:release_notes_boost_1_53_00 Boost 1.53 Release] 4070 4071* Fixed bugs 4072 [@https://svn.boost.org/trac/boost/ticket/7174 #7174], 4073 [@https://svn.boost.org/trac/boost/ticket/7529 #7529], 4074 [@https://svn.boost.org/trac/boost/ticket/7815 #7815]. 4075* Fixed GCC -Wshadow warnings. 4076* Added missing `explicit` keyword in several intrusive container constructors. 4077* Replaced deprecated BOOST_NO_XXXX with newer BOOST_NO_CXX11_XXX macros. 4078* Small documentation fixes. 4079 4080[endsect] 4081 4082[section:release_notes_boost_1_51_00 Boost 1.51 Release] 4083 4084* Fixed bugs 4085 [@https://svn.boost.org/trac/boost/ticket/6841 #6841], 4086 [@https://svn.boost.org/trac/boost/ticket/6907 #6907], 4087 [@https://svn.boost.org/trac/boost/ticket/6922 #6922], 4088 [@https://svn.boost.org/trac/boost/ticket/7033 #7033], 4089 4090* Added `bounded_range` function to trees. 4091 4092[endsect] 4093 4094[section:release_notes_boost_1_49_00 Boost 1.49 Release] 4095 4096* Fixed bugs 4097 [@https://svn.boost.org/trac/boost/ticket/6347 #6347], 4098 [@https://svn.boost.org/trac/boost/ticket/6223 #6223], 4099 [@https://svn.boost.org/trac/boost/ticket/6153 #6153]. 4100 4101 4102[endsect] 4103 4104[section:release_notes_boost_1_48_00 Boost 1.48 Release] 4105 4106* Fixed bugs 4107 [@https://svn.boost.org/trac/boost/ticket/4797 #4797], 4108 [@https://svn.boost.org/trac/boost/ticket/5165 #5165], 4109 [@https://svn.boost.org/trac/boost/ticket/5183 #5183], 4110 [@https://svn.boost.org/trac/boost/ticket/5191 #5191]. 4111 4112[endsect] 4113 4114[section:release_notes_boost_1_46_00 Boost 1.46 Release] 4115 4116* Fixed bug 4117 [@https://svn.boost.org/trac/boost/ticket/4980 #4980], 4118 4119[endsect] 4120 4121[section:release_notes_boost_1_45_00 Boost 1.45 Release] 4122 4123* Added `function_hook` option. 4124* Fixed bugs 4125 [@https://svn.boost.org/trac/boost/ticket/2611 #2611], 4126 [@https://svn.boost.org/trac/boost/ticket/3288 #3288], 4127 [@https://svn.boost.org/trac/boost/ticket/3304 #3304], 4128 [@https://svn.boost.org/trac/boost/ticket/3489 #3489], 4129 [@https://svn.boost.org/trac/boost/ticket/3668 #3668], 4130 [@https://svn.boost.org/trac/boost/ticket/3339 #3688], 4131 [@https://svn.boost.org/trac/boost/ticket/3698 #3698], 4132 [@https://svn.boost.org/trac/boost/ticket/3706 #3706], 4133 [@https://svn.boost.org/trac/boost/ticket/3721 #3721]. 4134 [@https://svn.boost.org/trac/boost/ticket/3729 #3729], 4135 [@https://svn.boost.org/trac/boost/ticket/3746 #3746], 4136 [@https://svn.boost.org/trac/boost/ticket/3781 #3781], 4137 [@https://svn.boost.org/trac/boost/ticket/3840 #3840], 4138 [@https://svn.boost.org/trac/boost/ticket/3849 #3849], 4139 [@https://svn.boost.org/trac/boost/ticket/3339 #3339], 4140 [@https://svn.boost.org/trac/boost/ticket/3419 #3419], 4141 [@https://svn.boost.org/trac/boost/ticket/3431 #3431], 4142 [@https://svn.boost.org/trac/boost/ticket/4021 #4021]. 4143 4144[endsect] 4145 4146 4147[section:release_notes_boost_1_40_00 Boost 1.40 Release] 4148 4149* Code cleanup in bstree_algorithms.hpp and avl_tree_algorithms.hpp 4150* Fixed bug 4151 [@https://svn.boost.org/trac/boost/ticket/3164 #3164]. 4152 4153[endsect] 4154 4155 4156[section:release_notes_boost_1_39_00 Boost 1.39 Release] 4157 4158* Optimized `list::merge` and `slist::merge` 4159* `list::sort` and `slist::sort` are now stable. 4160* Fixed bugs 4161 [@https://svn.boost.org/trac/boost/ticket/2689 #2689], 4162 [@https://svn.boost.org/trac/boost/ticket/2755 #2755], 4163 [@https://svn.boost.org/trac/boost/ticket/2786 #2786], 4164 [@https://svn.boost.org/trac/boost/ticket/2807 #2807], 4165 [@https://svn.boost.org/trac/boost/ticket/2810 #2810], 4166 [@https://svn.boost.org/trac/boost/ticket/2862 #2862]. 4167 4168[endsect] 4169 4170[section:release_notes_boost_1_38_00 Boost 1.38 Release] 4171 4172* New treap-based containers: treap, treap_set, treap_multiset. 4173* Corrected compilation bug for Windows-based 64 bit compilers. 4174* Corrected exception-safety bugs in container constructors. 4175* Updated documentation to show rvalue-references functions instead of emulation functions. 4176 4177[endsect] 4178 4179[section:release_notes_boost_1_37_00 Boost 1.37 Release] 4180 4181* Intrusive now takes advantage of compilers with variadic templates. 4182* `clone_from` functions now copy predicates and hash functions of associative containers. 4183* Added incremental hashing to unordered containers via `incremental<>` option. 4184* Update some function parameters from `iterator` to `const_iterator` in containers 4185 to keep up with the draft of the next standard. 4186* Added an option to specify include files for intrusive configurable assertion macros. 4187 4188[endsect] 4189 4190[section:release_notes_boost_1_36_00 Boost 1.36 Release] 4191 4192* Added `linear<>` and `cache_last<>` options to singly linked lists. 4193* Added `optimize_multikey<>` option to unordered container hooks. 4194* Optimized unordered containers when `store_hash` option is used in the hook. 4195* Implementation changed to be exception agnostic so that it can be used 4196 in environments without exceptions. 4197* Added `container_from_iterator` function to tree-based containers. 4198 4199[endsect] 4200 4201[endsect] 4202 4203[section:references References] 4204 4205* SGI's [@http://www.sgi.com/tech/stl/ STL Programmer's Guide]. 4206 [*Boost.Intrusive] is based on STL concepts and interfaces. 4207 4208* Dr. Dobb's, September 1, 2005: [@http://www.ddj.com/architect/184402007 ['Implementing Splay Trees in C++] ]. 4209 [*Boost.Intrusive] splay containers code is based on this article. 4210 4211* Olaf's original intrusive container library: [@http://freenet-homepage.de/turtle++/intrusive.html ['STL-like intrusive containers] ]. 4212 4213[endsect] 4214 4215[section:acknowledgements Acknowledgements] 4216 4217[*Olaf Krzikalla] would like to thank: 4218 4219* [*Markus Schaaf] for pointing out the possibility and the advantages of the derivation 4220approach. 4221 4222* [*Udo Steinbach] for encouragements to present this work for boost, a lot of fixes and 4223helpful discussions. 4224 4225* [*Jaap Suter] for the initial hint, which eventually lead to the member value_traits. 4226 4227[*Ion Gaztanaga] would like to thank: 4228 4229* [*Olaf Krzikalla] for the permission to continue his great work. 4230 4231* [*Joaquin M. Lopez Munoz] for his thorough review, help, and ideas. 4232 4233* [*Cory Nelson], [*Daniel James], [*Dave Harris], [*Guillaume Melquiond], 4234 [*Henri Bavestrello], [*Hervé Bronnimann], [*Kai Bruning], [*Kevin Sopp], 4235 [*Paul Rose], [*Pavel Vozelinek], [*Howard Hinnant], [*Olaf Krzikalla], 4236 [*Samuel Debionne], [*Stjepan Rajko], [*Thorsten Ottosen], [*Tobias Schwinger], 4237 [*Tom Brinkman] and [*Steven Watanabe] 4238 for their comments and reviews in the Boost.Intrusive formal review. 4239 4240* Thanks to [*Julienne Walker] and [*The EC Team] ([@http://eternallyconfuzzled.com]) 4241 for their great algorithms. 4242 4243* Thanks to [*Daniel K. O.] for his AVL tree rebalancing code. 4244 4245* Thanks to [*Ralf Mattethat] for his splay tree article and code. 4246 4247* Special thanks to [*Steven Watanabe] and [*Tobias Schwinger] for their 4248 invaluable suggestions and improvements. 4249 4250[endsect] 4251 4252[include auto_index_helpers.qbk] 4253 4254[section:index Indexes] 4255 4256[named_index class_name Class Index] 4257[named_index typedef_name Typedef Index] 4258[named_index function_name Function Index] 4259[named_index macro_name Macro Index] 4260[/index] 4261 4262[endsect] 4263 4264[xinclude autodoc.xml] 4265