Intel Threading Building Blocks 2.1 for Open Source

Classes | Public Types | Public Member Functions | Protected Types | Protected Member Functions | Protected Attributes | Friends

tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator > Class Template Reference
[Containers]

#include <concurrent_hash_map.h>

Inheritance diagram for tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >:
Inheritance graph
[legend]

List of all members.

Classes

class  accessor
 Allows write access to elements and combines data access, locking, and garbage collection. More...
class  bucket_accessor
 bucket accessor is to find, rehash, acquire a lock, and access a bucket More...
class  const_accessor
 Combines data access, locking, and garbage collection. More...
struct  node

Public Types

typedef Allocator allocator_type
typedef
internal::hash_map_iterator
< concurrent_hash_map, const
value_type
const_iterator
typedef const value_typeconst_pointer
typedef
internal::hash_map_range
< const_iterator
const_range_type
typedef const value_typeconst_reference
typedef ptrdiff_t difference_type
typedef
internal::hash_map_iterator
< concurrent_hash_map,
value_type
iterator
typedef Key key_type
typedef T mapped_type
typedef value_typepointer
typedef
internal::hash_map_range
< iterator
range_type
typedef value_typereference
typedef hash_map_base::size_type size_type
typedef std::pair< const Key, Tvalue_type

Public Member Functions

iterator begin ()
const_iterator begin () const
size_type bucket_count () const
 Returns the current number of buckets.
void clear ()
 Clear table.
template<typename I >
 concurrent_hash_map (I first, I last, const allocator_type &a=allocator_type())
 Construction with copying iteration range and given allocator instance.
 concurrent_hash_map (size_type n, const allocator_type &a=allocator_type())
 Construct empty table with n preallocated buckets. This number serves also as initial concurrency level.
 concurrent_hash_map (const allocator_type &a=allocator_type())
 Construct empty table.
 concurrent_hash_map (const concurrent_hash_map &table, const allocator_type &a=allocator_type())
 Copy constructor.
size_type count (const Key &key) const
 Return count of items (0 or 1).
bool empty () const
 True if size()==0.
iterator end ()
const_iterator end () const
std::pair< const_iterator,
const_iterator
equal_range (const Key &key) const
std::pair< iterator, iteratorequal_range (const Key &key)
bool erase (const Key &key)
 Erase item.
bool erase (accessor &item_accessor)
 Erase item by accessor.
bool erase (const_accessor &item_accessor)
 Erase item by const_accessor.
bool find (const_accessor &result, const Key &key) const
 Find item and acquire a read lock on the item.
bool find (accessor &result, const Key &key)
 Find item and acquire a write lock on the item.
allocator_type get_allocator () const
 return allocator object
bool insert (const_accessor &result, const value_type &value)
 Insert item by copying if there is no such key present already and acquire a read lock on the item.
bool insert (const value_type &value)
 Insert item by copying if there is no such key present already.
bool insert (accessor &result, const Key &key)
 Insert item (if not already present) and acquire a write lock on the item.
template<typename I >
void insert (I first, I last)
 Insert range [first, last).
bool insert (const_accessor &result, const Key &key)
 Insert item (if not already present) and acquire a read lock on the item.
bool insert (accessor &result, const value_type &value)
 Insert item by copying if there is no such key present already and acquire a write lock on the item.
size_type max_size () const
 Upper bound on size.
concurrent_hash_mapoperator= (const concurrent_hash_map &table)
 Assignment.
const_range_type range (size_type grainsize=1) const
range_type range (size_type grainsize=1)
void rehash (size_type n=0)
 Rehashes and optionally resizes the whole table.
size_type size () const
 Number of items in table.
void swap (concurrent_hash_map &table)
 swap two instances. Iterators are invalidated
 ~concurrent_hash_map ()
 Clear table and destroy it.

Protected Types

typedef Allocator::template
rebind< node >::other 
node_allocator_type

Protected Member Functions

void delete_node (node_base *n)
bool exclude (const_accessor &item_accessor, bool readonly)
 delete item by accessor
template<typename I >
void internal_copy (I first, I last)
void internal_copy (const concurrent_hash_map &source)
 Copy "source" to *this, where *this must start out empty.
template<typename I >
std::pair< I, I > internal_equal_range (const Key &key, I end) const
 Returns an iterator for an item defined by the key, or for the next item after it (if upper==true).
const_pointer internal_fast_find (const Key &key) const
 Fast find when no concurrent erasure is used. For internal use inside TBB only!
bool lookup (bool op_insert, const Key &key, const T *t, const_accessor *result, bool write)
 Insert or find item and optionally acquire a lock on the item.
void rehash_bucket (bucket *b_new, const hashcode_t h)
nodesearch_bucket (const key_type &key, bucket *b) const

Protected Attributes

node_allocator_type my_allocator
HashCompare my_hash_compare

Friends

class const_accessor
class internal::hash_map_iterator
class internal::hash_map_range

Detailed Description

template<typename Key, typename T, typename HashCompare, typename Allocator>
class tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >

Unordered map from Key to T. concurrent_hash_map is associative container with concurrent access.

Compatibility
The class meets all Container Requirements from C++ Standard (See ISO/IEC 14882:2003(E), clause 23.1).
Exception Safety
  • Hash function is not permitted to throw an exception. User-defined types Key and T are forbidden from throwing an exception in destructors.
  • If exception happens during insert() operations, it has no effect (unless exception raised by HashCompare::hash() function during grow_segment).
  • If exception happens during operator=() operation, the container can have a part of source items, and methods size() and empty() can return wrong results.
Changes since TBB 2.1
  • Replaced internal algorithm and data structure. Patent is pending.
  • Added buckets number argument for constructor
Changes since TBB 2.0

Definition at line 571 of file concurrent_hash_map.h.


Member Typedef Documentation

template<typename Key , typename T , typename HashCompare , typename Allocator >
typedef Allocator tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::allocator_type

Definition at line 592 of file concurrent_hash_map.h.

template<typename Key , typename T , typename HashCompare , typename Allocator >
typedef internal::hash_map_iterator<concurrent_hash_map,const value_type> tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::const_iterator

Definition at line 589 of file concurrent_hash_map.h.

template<typename Key , typename T , typename HashCompare , typename Allocator >
typedef const value_type* tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::const_pointer

Definition at line 585 of file concurrent_hash_map.h.

template<typename Key , typename T , typename HashCompare , typename Allocator >
typedef internal::hash_map_range<const_iterator> tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::const_range_type

Definition at line 591 of file concurrent_hash_map.h.

template<typename Key , typename T , typename HashCompare , typename Allocator >
typedef const value_type& tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::const_reference

Definition at line 587 of file concurrent_hash_map.h.

template<typename Key , typename T , typename HashCompare , typename Allocator >
typedef ptrdiff_t tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::difference_type

Definition at line 583 of file concurrent_hash_map.h.

template<typename Key , typename T , typename HashCompare , typename Allocator >
typedef internal::hash_map_iterator<concurrent_hash_map,value_type> tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::iterator

Definition at line 588 of file concurrent_hash_map.h.

template<typename Key , typename T , typename HashCompare , typename Allocator >
typedef Key tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::key_type

Definition at line 579 of file concurrent_hash_map.h.

template<typename Key , typename T , typename HashCompare , typename Allocator >
typedef T tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::mapped_type

Definition at line 580 of file concurrent_hash_map.h.

template<typename Key , typename T , typename HashCompare , typename Allocator >
typedef Allocator::template rebind<node>::other tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::node_allocator_type [protected]

Definition at line 596 of file concurrent_hash_map.h.

template<typename Key , typename T , typename HashCompare , typename Allocator >
typedef value_type* tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::pointer

Definition at line 584 of file concurrent_hash_map.h.

template<typename Key , typename T , typename HashCompare , typename Allocator >
typedef internal::hash_map_range<iterator> tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::range_type

Definition at line 590 of file concurrent_hash_map.h.

template<typename Key , typename T , typename HashCompare , typename Allocator >
typedef value_type& tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::reference

Definition at line 586 of file concurrent_hash_map.h.

template<typename Key , typename T , typename HashCompare , typename Allocator >
typedef hash_map_base::size_type tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::size_type

Definition at line 582 of file concurrent_hash_map.h.

template<typename Key , typename T , typename HashCompare , typename Allocator >
typedef std::pair<const Key,T> tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::value_type

Definition at line 581 of file concurrent_hash_map.h.


Constructor & Destructor Documentation

template<typename Key , typename T , typename HashCompare , typename Allocator >
tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::concurrent_hash_map ( const allocator_type a = allocator_type()  )  [inline]

Definition at line 757 of file concurrent_hash_map.h.

        : internal::hash_map_base(), my_allocator(a)

template<typename Key , typename T , typename HashCompare , typename Allocator >
tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::concurrent_hash_map ( size_type  n,
const allocator_type a = allocator_type() 
) [inline]

Definition at line 762 of file concurrent_hash_map.h.

        : internal::hash_map_base(), my_allocator(a)
    {}

    concurrent_hash_map(size_type n, const allocator_type &a = allocator_type())

template<typename Key , typename T , typename HashCompare , typename Allocator >
tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::concurrent_hash_map ( const concurrent_hash_map< Key, T, HashCompare, Allocator > &  table,
const allocator_type a = allocator_type() 
) [inline]

Definition at line 769 of file concurrent_hash_map.h.

        : internal::hash_map_base(), my_allocator(a)

template<typename Key , typename T , typename HashCompare , typename Allocator >
template<typename I >
tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::concurrent_hash_map ( first,
last,
const allocator_type a = allocator_type() 
) [inline]

Definition at line 777 of file concurrent_hash_map.h.

template<typename Key , typename T , typename HashCompare , typename Allocator >
tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::~concurrent_hash_map (  )  [inline]

Definition at line 803 of file concurrent_hash_map.h.

{ clear(); }


Member Function Documentation

template<typename Key , typename T , typename HashCompare , typename Allocator >
iterator tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::begin (  )  [inline]

Definition at line 818 of file concurrent_hash_map.h.

{return iterator(*this,0,my_embedded_segment,my_embedded_segment->node_list);}

template<typename Key , typename T , typename HashCompare , typename Allocator >
const_iterator tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::begin (  )  const [inline]

Definition at line 820 of file concurrent_hash_map.h.

{return iterator(*this,0,my_embedded_segment,my_embedded_segment->node_list);}

template<typename Key , typename T , typename HashCompare , typename Allocator >
size_type tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::bucket_count (  )  const [inline]

Definition at line 835 of file concurrent_hash_map.h.

{return (~size_type(0))/sizeof(node);}

template<typename Key , typename T , typename HashCompare , typename A >
void tbb::interface4::concurrent_hash_map< Key, T, HashCompare, A >::clear (  ) 

Definition at line 1240 of file concurrent_hash_map.h.

                                                     {
    hashcode_t m = my_mask;
    __TBB_ASSERT((m&(m+1))==0, NULL);
#if TBB_USE_ASSERT || TBB_USE_PERFORMANCE_WARNINGS
#if TBB_USE_PERFORMANCE_WARNINGS
    int current_size = int(my_size), buckets = int(m)+1, empty_buckets = 0, overpopulated_buckets = 0; // usage statistics
    static bool reported = false;
#endif
    bucket *bp = 0;
    // check consistency
    for( segment_index_t b = 0; b <= m; b++ ) {
        if( b & (b-2) ) ++bp; // not the beginning of a segment
        else bp = get_bucket( b );
        node_base *n = bp->node_list;
        __TBB_ASSERT( is_valid(n) || n == internal::empty_rehashed || n == internal::rehash_req, "Broken internal structure" );
        __TBB_ASSERT( *reinterpret_cast<intptr_t*>(&bp->mutex) == 0, "concurrent or unexpectedly terminated operation during clear() execution" );
#if TBB_USE_PERFORMANCE_WARNINGS
        if( n == internal::empty_rehashed ) empty_buckets++;
        else if( n == internal::rehash_req ) buckets--;
        else if( n->next ) overpopulated_buckets++;
#endif
#if __TBB_EXTRA_DEBUG
        for(; is_valid(n); n = n->next ) {
            hashcode_t h = my_hash_compare.hash( static_cast<node*>(n)->item.first );
            h &= m;
            __TBB_ASSERT( h == b || get_bucket(h)->node_list == internal::rehash_req, "hash() function changed for key in table or internal error" );
        }
#endif
    }
#if TBB_USE_PERFORMANCE_WARNINGS
    if( buckets > current_size) empty_buckets -= buckets - current_size;
    else overpopulated_buckets -= current_size - buckets; // TODO: load_factor?
    if( !reported && buckets >= 512 && ( 2*empty_buckets > current_size || 2*overpopulated_buckets > current_size ) ) {
        tbb::internal::runtime_warning(
            "Performance is not optimal because the hash function produces bad randomness in lower bits in %s.\nSize: %d  Empties: %d  Overlaps: %d",
            typeid(*this).name(), current_size, empty_buckets, overpopulated_buckets );
        reported = true;
    }
#endif
#endif//TBB_USE_ASSERT || TBB_USE_PERFORMANCE_WARNINGS
    my_size = 0;
    segment_index_t s = segment_index_of( m );
    __TBB_ASSERT( s+1 == pointers_per_table || !my_table[s+1], "wrong mask or concurrent grow" );
    cache_aligned_allocator<bucket> alloc;
    do {
        __TBB_ASSERT( is_valid( my_table[s] ), "wrong mask or concurrent grow" );
        segment_ptr_t buckets_ptr = my_table[s];
        size_type sz = segment_size( s ? s : 1 );
        for( segment_index_t i = 0; i < sz; i++ )
            for( node_base *n = buckets_ptr[i].node_list; is_valid(n); n = buckets_ptr[i].node_list ) {
                buckets_ptr[i].node_list = n->next;
                delete_node( n );
            }
        if( s >= first_block) // the first segment or the next
            alloc.deallocate( buckets_ptr, sz );
        else if( s == embedded_block && embedded_block != first_block )
            alloc.deallocate( buckets_ptr, segment_size(first_block)-embedded_buckets );

template<typename Key , typename T , typename HashCompare , typename Allocator >
size_type tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::count ( const Key &  key  )  const [inline]

Definition at line 848 of file concurrent_hash_map.h.

                                            {

template<typename Key , typename T , typename HashCompare , typename Allocator >
void tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::delete_node ( node_base n  )  [inline, protected]

Definition at line 616 of file concurrent_hash_map.h.

Referenced by tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::lookup().

                                                                  {return a.deallocate(static_cast<node*>(ptr),1); }
    };

template<typename Key , typename T , typename HashCompare , typename Allocator >
bool tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::empty (  )  const [inline]

Definition at line 829 of file concurrent_hash_map.h.

{ return my_size; }

template<typename Key , typename T , typename HashCompare , typename Allocator >
iterator tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::end (  )  [inline]

Definition at line 819 of file concurrent_hash_map.h.

{return iterator(*this,0,my_embedded_segment,my_embedded_segment->node_list);}

template<typename Key , typename T , typename HashCompare , typename Allocator >
const_iterator tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::end (  )  const [inline]

Definition at line 821 of file concurrent_hash_map.h.

{return iterator(*this,0,my_embedded_segment,my_embedded_segment->node_list);}

template<typename Key , typename T , typename HashCompare , typename Allocator >
std::pair<iterator, iterator> tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::equal_range ( const Key &  key  )  [inline]

Definition at line 822 of file concurrent_hash_map.h.

{return iterator(*this,0,my_embedded_segment,my_embedded_segment->node_list);}

template<typename Key , typename T , typename HashCompare , typename Allocator >
std::pair<const_iterator, const_iterator> tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::equal_range ( const Key &  key  )  const [inline]

Definition at line 823 of file concurrent_hash_map.h.

{return iterator(*this,0,0,0);}

template<typename Key , typename T , typename HashCompare , typename Allocator >
bool tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::erase ( accessor item_accessor  )  [inline]

Return true if item was erased by particularly this call.

Definition at line 919 of file concurrent_hash_map.h.

                                          {

template<typename Key , typename T , typename HashCompare , typename Allocator >
bool tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::erase ( const_accessor item_accessor  )  [inline]

Return true if item was erased by particularly this call.

Definition at line 913 of file concurrent_hash_map.h.

                                                {

template<typename Key , typename T , typename HashCompare , typename A >
bool tbb::interface4::concurrent_hash_map< Key, T, HashCompare, A >::erase ( const Key &  key  ) 

Return true if item was erased by particularly this call.

Definition at line 1126 of file concurrent_hash_map.h.

                                                                     {
    node_base *n;
    hashcode_t const h = my_hash_compare.hash( key );
#if TBB_USE_THREADING_TOOLS
    hashcode_t m = (hashcode_t) itt_load_pointer_with_acquire_v3( &my_mask );
#else
    hashcode_t m = my_mask;
#endif
restart:
    {//lock scope
        // get bucket
        bucket_accessor b( this, h & m );
    search:
        node_base **p = &b()->node_list;
        n = *p;
        while( is_valid(n) && !my_hash_compare.equal(key, static_cast<node*>(n)->item.first ) ) {
            p = &n->next;
            n = *p;
        }
        if( !n ) { // not found, but mask could be changed
            if( check_mask_race( h, m ) )
                goto restart;
            return false;
        }
        else if( !b.is_writer() && !b.upgrade_to_writer() ) {
            if( check_mask_race( h, m ) ) // contended upgrade, check mask
                goto restart;
            goto search;
        }
        *p = n->next;
        my_size--;
    }
    {
        typename node::scoped_t item_locker( n->mutex, /*write=*/true );
    }

template<typename Key , typename T , typename HashCompare , typename A >
bool tbb::interface4::concurrent_hash_map< Key, T, HashCompare, A >::exclude ( const_accessor item_accessor,
bool  readonly 
) [protected]

Definition at line 1091 of file concurrent_hash_map.h.

                                                                                                     {
    __TBB_ASSERT( item_accessor.my_node, NULL );
    node_base *const n = item_accessor.my_node;
    item_accessor.my_node = NULL; // we ought release accessor anyway
    hashcode_t const h = item_accessor.my_hash;
#if TBB_USE_THREADING_TOOLS
    hashcode_t m = (hashcode_t) itt_load_pointer_with_acquire_v3( &my_mask );
#else
    hashcode_t m = my_mask;
#endif
    do {
        // get bucket
        bucket_accessor b( this, h & m, /*writer=*/true );
        node_base **p = &b()->node_list;
        while( *p && *p != n )
            p = &(*p)->next;
        if( !*p ) { // someone else was the first
            if( check_mask_race( h, m ) )
                continue;
            item_accessor.my_lock.release();
            return false;
        }
        __TBB_ASSERT( *p == n, NULL );
        *p = n->next; // remove from container
        my_size--;
        break;
    } while(true);
    if( readonly ) // need to get exclusive lock
        item_accessor.my_lock.upgrade_to_writer(); // return value means nothing here

template<typename Key , typename T , typename HashCompare , typename Allocator >
bool tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::find ( const_accessor result,
const Key &  key 
) const [inline]

Return true if item is found, false otherwise.

Definition at line 854 of file concurrent_hash_map.h.

                                                              {

template<typename Key , typename T , typename HashCompare , typename Allocator >
bool tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::find ( accessor result,
const Key &  key 
) [inline]

Return true if item is found, false otherwise.

Definition at line 861 of file concurrent_hash_map.h.

                                                  {

template<typename Key , typename T , typename HashCompare , typename Allocator >
allocator_type tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::get_allocator (  )  const [inline]

Definition at line 838 of file concurrent_hash_map.h.

{ return my_mask+1; }

template<typename Key , typename T , typename HashCompare , typename Allocator >
template<typename I >
void tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::insert ( first,
last 
) [inline]

Definition at line 902 of file concurrent_hash_map.h.

                                 {

template<typename Key , typename T , typename HashCompare , typename Allocator >
bool tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::insert ( const_accessor result,
const Key &  key 
) [inline]

Returns true if item is new.

Definition at line 868 of file concurrent_hash_map.h.

                                                          {

template<typename Key , typename T , typename HashCompare , typename Allocator >
bool tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::insert ( accessor result,
const Key &  key 
) [inline]

Returns true if item is new.

Definition at line 875 of file concurrent_hash_map.h.

                                                    {

template<typename Key , typename T , typename HashCompare , typename Allocator >
bool tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::insert ( const_accessor result,
const value_type value 
) [inline]

Returns true if item is new.

Definition at line 882 of file concurrent_hash_map.h.

                                                                   {

template<typename Key , typename T , typename HashCompare , typename Allocator >
bool tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::insert ( accessor result,
const value_type value 
) [inline]

Returns true if item is new.

Definition at line 889 of file concurrent_hash_map.h.

                                                             {

template<typename Key , typename T , typename HashCompare , typename Allocator >
bool tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::insert ( const value_type value  )  [inline]

Returns true if item is inserted.

Definition at line 896 of file concurrent_hash_map.h.

                                           {

template<typename Key , typename T , typename HashCompare , typename A >
void tbb::interface4::concurrent_hash_map< Key, T, HashCompare, A >::internal_copy ( const concurrent_hash_map< Key, T, HashCompare, Allocator > &  source  )  [protected]

Definition at line 1303 of file concurrent_hash_map.h.

                                                                                                {
    reserve( source.my_size ); // TODO: load_factor?
    hashcode_t mask = source.my_mask;
    if( my_mask == mask ) { // optimized version
        bucket *dst = 0, *src = 0;
        bool rehash_required = false;
        for( hashcode_t k = 0; k <= mask; k++ ) {
            if( k & (k-2) ) ++dst,src++; // not the beginning of a segment
            else { dst = get_bucket( k ); src = source.get_bucket( k ); }
            __TBB_ASSERT( dst->node_list != internal::rehash_req, "Invalid bucket in destination table");
            node *n = static_cast<node*>( src->node_list );
            if( n == internal::rehash_req ) { // source is not rehashed, items are in previous buckets
                rehash_required = true;
                dst->node_list = internal::rehash_req;
            } else for(; n; n = static_cast<node*>( n->next ) ) {
                add_to_bucket( dst, new( my_allocator ) node(n->item.first, n->item.second) );
                ++my_size; // TODO: replace by non-atomic op
            }

template<typename Key , typename T , typename HashCompare , typename A >
template<typename I >
void tbb::interface4::concurrent_hash_map< Key, T, HashCompare, A >::internal_copy ( first,
last 
) [protected]

Definition at line 1328 of file concurrent_hash_map.h.

                                                                            {
    hashcode_t m = my_mask;
    for(; first != last; ++first) {
        hashcode_t h = my_hash_compare.hash( first->first );
        bucket *b = get_bucket( h & m );
        __TBB_ASSERT( b->node_list != internal::rehash_req, "Invalid bucket in destination table");
        node *n = new( my_allocator ) node(first->first, first->second);

template<typename Key , typename T , typename HashCompare , typename A >
template<typename I >
std::pair< I, I > tbb::interface4::concurrent_hash_map< Key, T, HashCompare, A >::internal_equal_range ( const Key &  key,
end 
) const [protected]

Definition at line 1073 of file concurrent_hash_map.h.

                                                                                                           {
    hashcode_t h = my_hash_compare.hash( key );
    hashcode_t m = my_mask;
    __TBB_ASSERT((m&(m+1))==0, NULL);
    h &= m;
    bucket *b = get_bucket( h );
    while( b->node_list == internal::rehash_req ) {
        m = ( 1u<<__TBB_Log2( h ) ) - 1; // get parent mask from the topmost bit
        b = get_bucket( h &= m );
    }
    node *n = search_bucket( key, b );
    if( !n )

template<typename Key , typename T , typename HashCompare , typename Allocator >
const_pointer tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::internal_fast_find ( const Key &  key  )  const [inline, protected]

Return pointer to item with given key, or NULL if no such item exists. Must not be called concurrently with erasure operations.

Definition at line 943 of file concurrent_hash_map.h.

References __TBB_load_with_acquire(), and tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::node::item.

                                                             {
        hashcode_t h = my_hash_compare.hash( key );
#if TBB_USE_THREADING_TOOLS
        hashcode_t m = (hashcode_t) itt_load_pointer_with_acquire_v3( &my_mask );
#else
        hashcode_t m = my_mask;
#endif
        node *n;
    restart:
        __TBB_ASSERT((m&(m+1))==0, NULL);
        bucket *b = get_bucket( h & m );
#if TBB_USE_THREADING_TOOLS
        // TODO: actually, notification is unnecessary here, just hiding double-check
        if( itt_load_pointer_with_acquire_v3(&b->node_list) == internal::rehash_req )
#else
        if( __TBB_load_with_acquire(b->node_list) == internal::rehash_req )
#endif
        {
            bucket::scoped_t lock;
            if( lock.try_acquire( b->mutex, /*write=*/true ) ) {
                if( b->node_list == internal::rehash_req)
                    const_cast<concurrent_hash_map*>(this)->rehash_bucket( b, h & m ); //recursive rehashing
            }
            else lock.acquire( b->mutex, /*write=*/false );
            __TBB_ASSERT(b->node_list!=internal::rehash_req,NULL);
        }
        n = search_bucket( key, b );
        if( n )
            return &n->item;

template<typename Key , typename T , typename HashCompare , typename A >
bool tbb::interface4::concurrent_hash_map< Key, T, HashCompare, A >::lookup ( bool  op_insert,
const Key &  key,
const T t,
const_accessor result,
bool  write 
) [protected]

Definition at line 985 of file concurrent_hash_map.h.

References tbb::internal::atomic_backoff::bounded_pause(), tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::delete_node(), tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::bucket_accessor::is_writer(), tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::my_allocator, tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::my_hash_compare, tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::search_bucket(), and tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::bucket_accessor::upgrade_to_writer().

                            : 4127 )
#endif

template<typename Key, typename T, typename HashCompare, typename A>
bool concurrent_hash_map<Key,T,HashCompare,A>::lookup( bool op_insert, const Key &key, const T *t, const_accessor *result, bool write ) {
    __TBB_ASSERT( !result || !result->my_node, NULL );
    segment_index_t grow_segment;
    bool return_value;
    node *n, *tmp_n = 0;
    hashcode_t const h = my_hash_compare.hash( key );
#if TBB_USE_THREADING_TOOLS
    hashcode_t m = (hashcode_t) itt_load_pointer_with_acquire_v3( &my_mask );
#else
    hashcode_t m = my_mask;
#endif
    restart:
    {//lock scope
        __TBB_ASSERT((m&(m+1))==0, NULL);
        return_value = false;
        // get bucket
        bucket_accessor b( this, h & m );

        // find a node
        n = search_bucket( key, b() );
        if( op_insert ) {
            // [opt] insert a key
            if( !n ) {
                if( !tmp_n ) {
                    if(t) tmp_n = new( my_allocator ) node(key, *t);
                    else  tmp_n = new( my_allocator ) node(key);
                }
                if( !b.is_writer() && !b.upgrade_to_writer() ) { // TODO: improved insertion
                    // Rerun search_list, in case another thread inserted the item during the upgrade.
                    n = search_bucket( key, b() );
                    if( is_valid(n) ) { // unfortunately, it did
                        b.downgrade_to_reader();
                        goto exists;
                    }
                }
                if( check_mask_race(h, m) )
                    goto restart; // b.release() is done in ~b().
                // insert and set flag to grow the container
                grow_segment = insert_new_node( b(), n = tmp_n, m );
                tmp_n = 0;
                return_value = true;
            } else {
    exists:     grow_segment = 0;
            }
        } else { // find or count
            if( !n ) {
                if( check_mask_race( h, m ) )
                    goto restart; // b.release() is done in ~b(). TODO: replace by continue
                return false;
            }
            return_value = true;
            grow_segment = 0;
        }
        if( !result ) goto check_growth;
        // TODO: the following seems as generic/regular operation
        // acquire the item
        if( !result->my_lock.try_acquire( n->mutex, write ) ) {
            // we are unlucky, prepare for longer wait
            tbb::internal::atomic_backoff trials;
            do {
                if( !trials.bounded_pause() ) {
                    // the wait takes really long, restart the operation
                    b.release();
                    __TBB_ASSERT( !op_insert || !return_value, "Can't acquire new item in locked bucket?" );
                    __TBB_Yield();
#if TBB_USE_THREADING_TOOLS
                    m = (hashcode_t) itt_load_pointer_with_acquire_v3( &my_mask );
#else
                    m = my_mask;
#endif
                    goto restart;
                }
            } while( !result->my_lock.try_acquire( n->mutex, write ) );
        }
    }//lock scope
    result->my_node = n;
    result->my_hash = h;
check_growth:
    // [opt] grow the container
    if( grow_segment )
        enable_segment( grow_segment );

template<typename Key , typename T , typename HashCompare , typename Allocator >
size_type tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::max_size (  )  const [inline]

Definition at line 832 of file concurrent_hash_map.h.

{ return my_size == 0; }

template<typename Key , typename T , typename HashCompare , typename Allocator >
concurrent_hash_map& tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::operator= ( const concurrent_hash_map< Key, T, HashCompare, Allocator > &  table  )  [inline]

Definition at line 785 of file concurrent_hash_map.h.

                                                                       {
        if( this!=&table ) {
            clear();

template<typename Key , typename T , typename HashCompare , typename Allocator >
const_range_type tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::range ( size_type  grainsize = 1  )  const [inline]

Definition at line 811 of file concurrent_hash_map.h.

                                              {
        return range_type( *this, grainsize );

template<typename Key , typename T , typename HashCompare , typename Allocator >
range_type tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::range ( size_type  grainsize = 1  )  [inline]

Definition at line 808 of file concurrent_hash_map.h.

                                              {

template<typename Key , typename T , typename HashCompare , typename A >
void tbb::interface4::concurrent_hash_map< Key, T, HashCompare, A >::rehash ( size_type  n = 0  ) 

Useful to optimize performance before or after concurrent operations. Also enables using of find() and count() concurrent methods in serial context.

Definition at line 1174 of file concurrent_hash_map.h.

                                                                  {
    reserve( sz ); // TODO: add reduction of number of buckets as well
    hashcode_t mask = my_mask;
    hashcode_t b = (mask+1)>>1; // size or first index of the last segment
    __TBB_ASSERT((b&(b-1))==0, NULL);
    bucket *bp = get_bucket( b ); // only the last segment should be scanned for rehashing
    for(; b <= mask; b++, bp++ ) {
        node_base *n = bp->node_list;
        __TBB_ASSERT( is_valid(n) || n == internal::empty_rehashed || n == internal::rehash_req, "Broken internal structure" );
        __TBB_ASSERT( *reinterpret_cast<intptr_t*>(&bp->mutex) == 0, "concurrent or unexpectedly terminated operation during rehash() execution" );
        if( n == internal::rehash_req ) { // rehash bucket, conditional because rehashing of a previous bucket may affect this one
            hashcode_t h = b; bucket *b_old = bp;
            do {
                __TBB_ASSERT( h > 1, "The lowermost buckets can't be rehashed" );
                hashcode_t m = ( 1u<<__TBB_Log2( h ) ) - 1; // get parent mask from the topmost bit
                b_old = get_bucket( h &= m );
            } while( b_old->node_list == internal::rehash_req );
            // now h - is index of the root rehashed bucket b_old
            mark_rehashed_levels( h ); // mark all non-rehashed children recursively across all segments
            for( node_base **p = &b_old->node_list, *q = *p; is_valid(q); q = *p ) {
                hashcode_t c = my_hash_compare.hash( static_cast<node*>(q)->item.first );
                if( (c & mask) != h ) { // should be rehashed
                    *p = q->next; // exclude from b_old
                    bucket *b_new = get_bucket( c & mask );
                    __TBB_ASSERT( b_new->node_list != internal::rehash_req, "hash() function changed for key in table or internal error" );
                    add_to_bucket( b_new, q );
                } else p = &q->next; // iterate to next item
            }
        }
    }
#if TBB_USE_PERFORMANCE_WARNINGS
    int current_size = int(my_size), buckets = int(mask)+1, empty_buckets = 0, overpopulated_buckets = 0; // usage statistics
    static bool reported = false;
#endif
#if TBB_USE_ASSERT || TBB_USE_PERFORMANCE_WARNINGS
    for( b = 0; b <= mask; b++ ) {// only last segment should be scanned for rehashing
        if( b & (b-2) ) ++bp; // not the beginning of a segment
        else bp = get_bucket( b );
        node_base *n = bp->node_list;
        __TBB_ASSERT( *reinterpret_cast<intptr_t*>(&bp->mutex) == 0, "concurrent or unexpectedly terminated operation during rehash() execution" );
        __TBB_ASSERT( is_valid(n) || n == internal::empty_rehashed, "Broken internal structure" );
#if TBB_USE_PERFORMANCE_WARNINGS
        if( n == internal::empty_rehashed ) empty_buckets++;
        else if( n->next ) overpopulated_buckets++;
#endif
#if TBB_USE_ASSERT
        for( ; is_valid(n); n = n->next ) {
            hashcode_t h = my_hash_compare.hash( static_cast<node*>(n)->item.first ) & mask;
            __TBB_ASSERT( h == b, "hash() function changed for key in table or internal error" );
        }
#endif
    }
#endif // TBB_USE_ASSERT || TBB_USE_PERFORMANCE_WARNINGS
#if TBB_USE_PERFORMANCE_WARNINGS
    if( buckets > current_size) empty_buckets -= buckets - current_size;
    else overpopulated_buckets -= current_size - buckets; // TODO: load_factor?
    if( !reported && buckets >= 512 && ( 2*empty_buckets > current_size || 2*overpopulated_buckets > current_size ) ) {
        tbb::internal::runtime_warning(
            "Performance is not optimal because the hash function produces bad randomness in lower bits in %s.\nSize: %d  Empties: %d  Overlaps: %d",
            typeid(*this).name(), current_size, empty_buckets, overpopulated_buckets );

template<typename Key , typename T , typename HashCompare , typename Allocator >
void tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::rehash_bucket ( bucket *  b_new,
const hashcode_t  h 
) [inline, protected]

Definition at line 661 of file concurrent_hash_map.h.

                                 { my_is_writer = true; return bucket::scoped_t::upgrade_to_writer(); }
    };

    // TODO refactor to hash_base
    void rehash_bucket( bucket *b_new, const hashcode_t h ) {
        __TBB_ASSERT( *(intptr_t*)(&b_new->mutex), "b_new must be locked (for write)");
        __TBB_ASSERT( h > 1, "The lowermost buckets can't be rehashed" );
        __TBB_store_with_release(b_new->node_list, internal::empty_rehashed); // mark rehashed
        hashcode_t mask = ( 1u<<__TBB_Log2( h ) ) - 1; // get parent mask from the topmost bit

        bucket_accessor b_old( this, h & mask );

        mask = (mask<<1) | 1; // get full mask for new bucket
        __TBB_ASSERT( (mask&(mask+1))==0 && (h & mask) == h, NULL );
    restart:
        for( node_base **p = &b_old()->node_list, *n = __TBB_load_with_acquire(*p); is_valid(n); n = *p ) {
            hashcode_t c = my_hash_compare.hash( static_cast<node*>(n)->item.first );
#if TBB_USE_ASSERT
            hashcode_t bmask = h & (mask>>1);
            bmask = bmask==0? 1 : ( 1u<<(__TBB_Log2( bmask )+1 ) ) - 1; // minimal mask of parent bucket
            __TBB_ASSERT( (c & bmask) == (h & bmask), "hash() function changed for key in table" );
#endif
            if( (c & mask) == h ) {
                if( !b_old.is_writer() )
                    if( !b_old.upgrade_to_writer() ) {
                        goto restart; // node ptr can be invalid due to concurrent erase
                    }
                *p = n->next; // exclude from b_old

template<typename Key , typename T , typename HashCompare , typename Allocator >
node* tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::search_bucket ( const key_type key,
bucket *  b 
) const [inline, protected]

Definition at line 621 of file concurrent_hash_map.h.

Referenced by tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::lookup().

                                                                {
        node *n = static_cast<node*>( b->node_list );
        while( is_valid(n) && !my_hash_compare.equal(key, n->item.first) )

template<typename Key , typename T , typename HashCompare , typename Allocator >
size_type tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::size (  )  const [inline]

Definition at line 826 of file concurrent_hash_map.h.

{ return internal_equal_range(key, end()); }

template<typename Key , typename T , typename HashCompare , typename Allocator >
void tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::swap ( concurrent_hash_map< Key, T, HashCompare, Allocator > &  table  ) 

Friends And Related Function Documentation

template<typename Key , typename T , typename HashCompare , typename Allocator >
friend class const_accessor [friend]

Definition at line 595 of file concurrent_hash_map.h.

template<typename Key , typename T , typename HashCompare , typename Allocator >
friend class internal::hash_map_iterator [friend]

Definition at line 573 of file concurrent_hash_map.h.

template<typename Key , typename T , typename HashCompare , typename Allocator >
friend class internal::hash_map_range [friend]

Definition at line 576 of file concurrent_hash_map.h.


Member Data Documentation

template<typename Key , typename T , typename HashCompare , typename Allocator >
node_allocator_type tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::my_allocator [protected]
template<typename Key , typename T , typename HashCompare , typename Allocator >
HashCompare tbb::interface4::concurrent_hash_map< Key, T, HashCompare, Allocator >::my_hash_compare [protected]

The documentation for this class was generated from the following file:

Copyright © 2005-2010 Intel Corporation. All Rights Reserved.

Licensed under the GNU General Public License 2 with the runtime exception.

Intel, Pentium, Intel Xeon, Itanium, Intel XScale and VTune are registered trademarks or trademarks of Intel Corporation or its subsidiaries in the United States and other countries.

* Other names and brands may be claimed as the property of others.