Boost.Intrusive also offers hashed containers
that can be very useful to implement fast-lookup containers. These containers
(unordered_set
and unordered_multiset)
are semi-intrusive containers: they need additional memory apart from the hook
stored in the value_type. This
additional memory must be passed in the constructor of the container.

Unlike C++ TR1 unordered associative containers (which are also hashed containers),
the contents of these semi-intrusive containers are not rehashed to maintain
a load factor: that would require memory management and intrusive containers
don't implement any memory management at all. However, the user can request
an explicit rehashing passing a new bucket array. This also offers an additional
guarantee over TR1 unordered associative containers: iterators
are not invalidated when inserting an element in the container.

As with TR1 unordered associative containers, rehashing invalidates iterators,
changes ordering between elements and changes which buckets elements appear
in, but does not invalidate pointers or references to elements.

Apart from expected hash and equality function objects, Boost.Intrusive
unordered associative containers' constructors take an argument specifying
an auxiliary bucket vector to be used by the container.

The size overhead for a hashed container is moderate: 1 pointer per value
plus a bucket array per container. The size of an element of the bucket array
is usually one pointer. To obtain a good performance hashed container, the
bucket length is usually the same as the number of elements that the container
contains, so a well-balanced hashed container (bucket_count() is equal to size() ) will have an equivalent overhead of two
pointers per element.

Insertions, erasures, and searches, have amortized constant-time complexity
in hashed containers. However, some worst-case guarantees are linear. See
unordered_set
or unordered_multiset
for complexity guarantees of each operation.

Be careful with non constant-time size hashed containers:
some operations, like empty(), have linear complexity, unlike other
Boost.Intrusive containers.

void_pointer<classVoidPointer>:
The pointer type to be used internally in the hook and propagated to the
container. Default: void_pointer<void*>.

Apart from them, these hooks offer additional options:

store_hash<boolEnabled>:
This option reserves additional space in the hook to store the hash value
of the object once it's introduced in the container. When this option is
used, the unordered container will store the calculated hash value in the
hook and rehashing operations won't need to recalculate the hash of the
value. This option will improve the performance of unordered containers
when rehashing is frequent or hashing the value is a slow operation. Default:
store_hash<false>.

optimize_multikey<boolEnabled>:
This option reserves additional space in the hook that will be used to
group equal elements in unordered multisets, improving significantly the
performance when many equal values are inserted in these containers. Default:
optimize_multikey<false>.

As mentioned, unordered containers need an auxiliary array to work. Boost.Intrusive unordered containers receive this
auxiliary array packed in a type called bucket_traits
(which can be also customized by a container option). All unordered containers
receive a bucket_traits object
in their constructors. The default bucket_traits
class is initialized with a pointer to an array of buckets and its size:

Each hashed container needs its own bucket traits,
that is, its own bucket vector. Two hashed
containers can't share the same bucket_type elements. The bucket array
must be destroyed after
the container using it is destroyed, otherwise, the result is undefined.

base_hook<classHook>
/ member_hook<classT,classHook,HookT::*PtrToMember> / value_traits<classValueTraits>: To specify the hook type
or value traits used to configure the container. (To learn about value
traits go to the section Containers
with custom ValueTraits.)

size_type<boolEnabled>:
To specify the type that will be used to store the size of the container.
Default: size_type<std::size_t>

And they also can receive additional options:

equal<classEqual>:
Equality function for the objects to be inserted in containers. Default:
equal<std::equal_to<T>>

hash<classHash>:
Hash function to be used in the container. Default: hash<boost::hash<T>>

bucket_traits<classBucketTraits>:
A type that wraps the bucket vector to be used by the unordered container.
Default: a type initialized by the address and size of a bucket array and
stores both variables internally.

power_2_buckets<boolEnabled>:
The user guarantees that only bucket arrays with power of two length will
be used. The container will then use masks instead of modulo operations
to obtain the bucket number from the hash value. Masks are faster than
modulo operations and for some applications modulo operations can impose
a considerable overhead. In debug mode an assertion will be raised if the
user provides a bucket length that is not power of two. Default: power_2_buckets<false>.

cache_begin<boolEnabled>:
Note: this option is not compatible with auto_unlink hooks. Due to
its internal structure, finding the first element of an unordered container
(begin()
operation) is amortized constant-time. It's possible to speed up begin()
and other operations related to it (like clear()) if the container caches internally the
position of the first element. This imposes the overhead of one pointer
to the size of the container. Default: cache_begin<false>.

compare_hash<boolEnabled>:
Note: this option requires store_hash<true> option in the hook. When
the comparison function is expensive, (e.g. strings with a long common
predicate) sometimes (specially when the load factor is high or we have
many equivalent elements in an unordered_multiset
and no optimize_multikey<> is activated in the hook) the equality
function is a performance problem. Two equal values must have equal hashes,
so comparing the hash values of two elements before using the comparison
functor can speed up some implementations.

incremental<boolEnabled>:
Activates incremental hashing (also known as Linear Hashing). This option
implies power_2_buckets<true> and the container will require power
of two buckets. For more information on incremental hashing, see Linearhash on Wikipedia Default:
incremental<false>

#include<boost/intrusive/unordered_set.hpp>#include<vector>#include<algorithm>#include<boost/functional/hash.hpp>usingnamespaceboost::intrusive;classMyClass:publicunordered_set_base_hook<>{//This is a derivation hook
intint_;public:unordered_set_member_hook<>member_hook_;//This is a member hook
MyClass(inti):int_(i){}friendbooloperator==(constMyClass&a,constMyClass&b){returna.int_==b.int_;}friendstd::size_thash_value(constMyClass&value){returnstd::size_t(value.int_);}};//Define an unordered_set that will store MyClass objects using the base hook
typedefunordered_set<MyClass>BaseSet;//Define an unordered_multiset that will store MyClass using the member hook
typedefmember_hook<MyClass,unordered_set_member_hook<>,&MyClass::member_hook_>MemberOption;typedefunordered_multiset<MyClass,MemberOption>MemberMultiSet;intmain(){typedefstd::vector<MyClass>::iteratorVectIt;typedefstd::vector<MyClass>::reverse_iteratorVectRit;//Create a vector with 100 different MyClass objects
std::vector<MyClass>values;for(inti=0;i<100;++i)values.push_back(MyClass(i));//Create a copy of the vector
std::vector<MyClass>values2(values);//Create a bucket array for base_set
BaseSet::bucket_typebase_buckets[100];//Create a bucket array for member_multi_set
MemberMultiSet::bucket_typemember_buckets[200];//Create unordered containers taking buckets as arguments
BaseSetbase_set(BaseSet::bucket_traits(base_buckets,100));MemberMultiSetmember_multi_set(MemberMultiSet::bucket_traits(member_buckets,200));//Now insert values's elements in the unordered_set
for(VectItit(values.begin()),itend(values.end());it!=itend;++it)base_set.insert(*it);//Now insert values's and values2's elements in the unordered_multiset
for(VectItit(values.begin()),itend(values.end()),it2(values2.begin()),itend2(values2.end());it!=itend;++it,++it2){member_multi_set.insert(*it);member_multi_set.insert(*it2);}//Now find every element
{VectItit(values.begin()),itend(values.end());for(;it!=itend;++it){//base_set should contain one element for each key
if(base_set.count(*it)!=1)return1;//member_multi_set should contain two elements for each key
if(member_multi_set.count(*it)!=2)return1;}}return0;}

Instead of using the default bucket_traits
class to store the bucket array, a user can define his own class to store
the bucket array using the bucket_traits<>
option. A user-defined bucket-traits must fulfill the following interface:

The following bucket traits just stores a pointer to the bucket array but
the size is a compile-time constant. Note the use of the auxiliary unordered_bucket and
unordered_bucket_ptr
utilities to obtain the type of the bucket and its pointer before defining
the unordered container:

#include<boost/intrusive/unordered_set.hpp>#include<boost/functional/hash.hpp>#include<vector>usingnamespaceboost::intrusive;//A class to be inserted in an unordered_set
classMyClass:publicunordered_set_base_hook<>{intint_;public:MyClass(inti=0):int_(i){}friendbooloperator==(constMyClass&l,constMyClass&r){returnl.int_==r.int_;}friendstd::size_thash_value(constMyClass&v){returnboost::hash_value(v.int_);}};//Define the base hook option
typedefbase_hook<unordered_set_base_hook<>>BaseHookOption;//Obtain the types of the bucket and the bucket pointer
typedefunordered_bucket<BaseHookOption>::typeBucketType;typedefunordered_bucket_ptr<BaseHookOption>::typeBucketPtr;//The custom bucket traits.
classcustom_bucket_traits{public:staticconstintNumBuckets=100;custom_bucket_traits(BucketPtrbuckets):buckets_(buckets){}//Functions to be implemented by custom bucket traits
BucketPtrbucket_begin()const{returnbuckets_;}std::size_tbucket_count()const{returnNumBuckets;}private:BucketPtrbuckets_;};//Define the container using the custom bucket traits
typedefunordered_set<MyClass,bucket_traits<custom_bucket_traits>>BucketTraitsUset;intmain(){typedefstd::vector<MyClass>::iteratorVectIt;std::vector<MyClass>values;//Fill values
for(inti=0;i<100;++i)values.push_back(MyClass(i));//Now create the bucket array and the custom bucket traits object
BucketTypebuckets[custom_bucket_traits::NumBuckets];custom_bucket_traitsbtraits(buckets);//Now create the unordered set
BucketTraitsUsetuset(btraits);//Insert the values in the unordered set
for(VectItit(values.begin()),itend(values.end());it!=itend;++it)uset.insert(*it);return0;}