00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #ifndef __TBB_concurrent_hash_map_H
00022 #define __TBB_concurrent_hash_map_H
00023
00024 #include "tbb_stddef.h"
00025
00026 #if !TBB_USE_EXCEPTIONS && _MSC_VER
00027
00028 #pragma warning (push)
00029 #pragma warning (disable: 4530)
00030 #endif
00031
00032 #include <iterator>
00033 #include <utility>
00034 #include <cstring>
00035
00036 #if !TBB_USE_EXCEPTIONS && _MSC_VER
00037 #pragma warning (pop)
00038 #endif
00039
00040 #include "cache_aligned_allocator.h"
00041 #include "tbb_allocator.h"
00042 #include "spin_rw_mutex.h"
00043 #include "atomic.h"
00044 #include "aligned_space.h"
00045 #include "tbb_exception.h"
00046 #include "_concurrent_unordered_internal.h"
00047 #if TBB_USE_PERFORMANCE_WARNINGS
00048 #include <typeinfo>
00049 #endif
00050
00051 namespace tbb {
00052
00054 namespace internal {
00056 void* __TBB_EXPORTED_FUNC itt_load_pointer_with_acquire_v3( const void* src );
00058 void __TBB_EXPORTED_FUNC itt_store_pointer_with_release_v3( void* dst, void* src );
00060 void* __TBB_EXPORTED_FUNC itt_load_pointer_v3( const void* src );
00061 }
00063
00065 template<typename Key>
00066 struct tbb_hash_compare {
00067 static size_t hash( const Key& a ) { return tbb_hasher(a); }
00068 static bool equal( const Key& a, const Key& b ) { return a == b; }
00069 };
00070
00071 namespace interface4 {
00072
00073 template<typename Key, typename T, typename HashCompare = tbb_hash_compare<Key>, typename A = tbb_allocator<std::pair<Key, T> > >
00074 class concurrent_hash_map;
00075
00077 namespace internal {
00078
00079
00081 typedef size_t hashcode_t;
00083 struct hash_map_node_base : tbb::internal::no_copy {
00085 typedef spin_rw_mutex mutex_t;
00087 typedef mutex_t::scoped_lock scoped_t;
00089 hash_map_node_base *next;
00090 mutex_t mutex;
00091 };
00093 static hash_map_node_base *const rehash_req = reinterpret_cast<hash_map_node_base*>(size_t(3));
00095 static hash_map_node_base *const empty_rehashed = reinterpret_cast<hash_map_node_base*>(size_t(0));
00097 class hash_map_base {
00098 public:
00100 typedef size_t size_type;
00102 typedef size_t hashcode_t;
00104 typedef size_t segment_index_t;
00106 typedef hash_map_node_base node_base;
00108 struct bucket : tbb::internal::no_copy {
00110 typedef spin_rw_mutex mutex_t;
00112 typedef mutex_t::scoped_lock scoped_t;
00113 mutex_t mutex;
00114 node_base *node_list;
00115 };
00117 static size_type const embedded_block = 1;
00119 static size_type const embedded_buckets = 1<<embedded_block;
00121 static size_type const first_block = 8;
00123 static size_type const pointers_per_table = sizeof(segment_index_t) * 8;
00125 typedef bucket *segment_ptr_t;
00127 typedef segment_ptr_t segments_table_t[pointers_per_table];
00129 atomic<hashcode_t> my_mask;
00131 segments_table_t my_table;
00133 atomic<size_type> my_size;
00135 bucket my_embedded_segment[embedded_buckets];
00136
00138 hash_map_base() {
00139 std::memset( this, 0, pointers_per_table*sizeof(segment_ptr_t)
00140 + sizeof(my_size) + sizeof(my_mask)
00141 + embedded_buckets*sizeof(bucket) );
00142 for( size_type i = 0; i < embedded_block; i++ )
00143 my_table[i] = my_embedded_segment + segment_base(i);
00144 my_mask = embedded_buckets - 1;
00145 __TBB_ASSERT( embedded_block <= first_block, "The first block number must include embedded blocks");
00146 }
00147
00149 static segment_index_t segment_index_of( size_type index ) {
00150 return segment_index_t( __TBB_Log2( index|1 ) );
00151 }
00152
00154 static segment_index_t segment_base( segment_index_t k ) {
00155 return (segment_index_t(1)<<k & ~segment_index_t(1));
00156 }
00157
00159 static size_type segment_size( segment_index_t k ) {
00160 return size_type(1)<<k;
00161 }
00162
00164 static bool is_valid( void *ptr ) {
00165 return reinterpret_cast<size_t>(ptr) > size_t(63);
00166 }
00167
00169 static void init_buckets( segment_ptr_t ptr, size_type sz, bool is_initial ) {
00170 if( is_initial ) std::memset(ptr, 0, sz*sizeof(bucket) );
00171 else for(size_type i = 0; i < sz; i++, ptr++) {
00172 *reinterpret_cast<intptr_t*>(&ptr->mutex) = 0;
00173 ptr->node_list = rehash_req;
00174 }
00175 }
00176
00178 static void add_to_bucket( bucket *b, node_base *n ) {
00179 __TBB_ASSERT(b->node_list != rehash_req, NULL);
00180 n->next = b->node_list;
00181 b->node_list = n;
00182 }
00183
00185 struct enable_segment_failsafe {
00186 segment_ptr_t *my_segment_ptr;
00187 enable_segment_failsafe(segments_table_t &table, segment_index_t k) : my_segment_ptr(&table[k]) {}
00188 ~enable_segment_failsafe() {
00189 if( my_segment_ptr ) *my_segment_ptr = 0;
00190 }
00191 };
00192
00194 void enable_segment( segment_index_t k, bool is_initial = false ) {
00195 __TBB_ASSERT( k, "Zero segment must be embedded" );
00196 enable_segment_failsafe watchdog( my_table, k );
00197 cache_aligned_allocator<bucket> alloc;
00198 size_type sz;
00199 __TBB_ASSERT( !is_valid(my_table[k]), "Wrong concurrent assignment");
00200 if( k >= first_block ) {
00201 sz = segment_size( k );
00095 static hash_map_node_base *const empty_rehashed = reinterpret_cast<hash_map_node_base*>(size_t(0));
00097 class hash_map_base {
00098 public:
00100 typedef size_t size_type;
00102 typedef size_t hashcode_t;
00104 typedef size_t segment_index_t;
00106 typedef hash_map_node_base node_base;
00108 struct bucket : tbb::internal::no_copy {
00110 typedef spin_rw_mutex mutex_t;
00112 typedef mutex_t::scoped_lock scoped_t;
00113 mutex_t mutex;
00114 node_base *node_list;
00115 };
00117 static size_type const embedded_block = 1;
00119 static size_type const embedded_buckets = 1<<embedded_block;
00121 static size_type const first_block = 8;
00123 static size_type const pointers_per_table = sizeof(segment_index_t) * 8;
00125 typedef bucket *segment_ptr_t;
00127 typedef segment_ptr_t segments_table_t[pointers_per_table];
00129 atomic<hashcode_t> my_mask;
00131 segments_table_t my_table;
00133 atomic<size_type> my_size;
00135 bucket my_embedded_segment[embedded_buckets];
00136
00138 hash_map_base() {
00139 std::memset( this, 0, pointers_per_table*sizeof(segment_ptr_t)
00140 + sizeof(my_size) + sizeof(my_mask)
00141 + embedded_buckets*sizeof(bucket) );
00142 for( size_type i = 0; i < embedded_block; i++ )
00143 my_table[i] = my_embedded_segment + segment_base(i);
00144 my_mask = embedded_buckets - 1;
00145 __TBB_ASSERT( embedded_block <= first_block, "The first block number must include embedded blocks");
00146 }
00147
00149 static segment_index_t segment_index_of( size_type index ) {
00150 return segment_index_t( __TBB_Log2( index|1 ) );
00151 }
00152
00154 static segment_index_t segment_base( segment_index_t k ) {
00155 return (segment_index_t(1)<<k & ~segment_index_t(1));
00156 }
00157
00159 static size_type segment_size( segment_index_t k ) {
00160 return size_type(1)<<k;
00161 }
00162
00164 static bool is_valid( void *ptr ) {
00165 return reinterpret_cast<size_t>(ptr) > size_t(63);
00166 }
00167
00169 static void init_buckets( segment_ptr_t ptr, size_type sz, bool is_initial ) {
00170 if( is_initial ) std::memset(ptr, 0, sz*sizeof(bucket) );
00171 else for(size_type i = 0; i < sz; i++, ptr++) {
00172 *reinterpret_cast<intptr_t*>(&ptr->mutex) = 0;
00173 ptr->node_list = rehash_req;
00174 }
00175 }
00176
00178 static void add_to_bucket( bucket *b, node_base *n ) {
00179 __TBB_ASSERT(b->node_list != rehash_req, NULL);
00180 n->next = b->node_list;
00181 b->node_list = n;
00182 }
00183
00185 struct enable_segment_failsafe {
00186 segment_ptr_t *my_segment_ptr;
00187 enable_segment_failsafe(segments_table_t &table, segment_index_t k) : my_segment_ptr(&table[k]) {}
00188 ~enable_segment_failsafe() {
00189 if( my_segment_ptr ) *my_segment_ptr = 0;
00190 }
00191 };
00192
00194 void enable_segment( segment_index_t k, bool is_initial = false ) {
00195 __TBB_ASSERT( k, "Zero segment must be embedded" );
00196 enable_segment_failsafe watchdog( my_table, k );
00197 cache_aligned_allocator<bucket> alloc;
00198 size_type sz;
00199 __TBB_ASSERT( !is_valid(my_table[k]), "Wrong concurrent assignment");
00200 if( k >= first_block ) {
00201 sz = segment_size( k );
00095 static hash_map_node_base *const empty_rehashed = reinterpret_cast<hash_map_node_base*>(size_t(0));
00097 class hash_map_base {
00098 public:
00100 typedef size_t size_type;
00102 typedef size_t hashcode_t;
00104 typedef size_t segment_index_t;
00106 typedef hash_map_node_base node_base;
00108 struct bucket : tbb::internal::no_copy {
00110 typedef spin_rw_mutex mutex_t;
00112 typedef mutex_t::scoped_lock scoped_t;
00113 mutex_t mutex;
00114 node_base *node_list;
00115 };
00117 static size_type const embedded_block = 1;
00119 static size_type const embedded_buckets = 1<<embedded_block;
00121 static size_type const first_block = 8;
00123 static size_type const pointers_per_table = sizeof(segment_index_t) * 8;
00125 typedef bucket *segment_ptr_t;
00127 typedef segment_ptr_t segments_table_t[pointers_per_table];
00129 atomic<hashcode_t> my_mask;
00131 segments_table_t my_table;
00133 atomic<size_type> my_size;
00135 bucket my_embedded_segment[embedded_buckets];
00136
00138 hash_map_base() {
00139 std::memset( this, 0, pointers_per_table*sizeof(segment_ptr_t)
00140 + sizeof(my_size) + sizeof(my_mask)
00141 + embedded_buckets*sizeof(bucket) );
00142 for( size_type i = 0; i < embedded_block; i++ )
00143 my_table[i] = my_embedded_segment + segment_base(i);
00144 my_mask = embedded_buckets - 1;
00145 __TBB_ASSERT( embedded_block <= first_block, "The first block number must include embedded blocks");
00146 }
00147
00149 static segment_index_t segment_index_of( size_type index ) {
00150 return segment_index_t( __TBB_Log2( index|1 ) );
00151 }
00152
00154 static segment_index_t segment_base( segment_index_t k ) {
00155 return (segment_index_t(1)<<k & ~segment_index_t(1));
00156 }
00157
00159 static size_type segment_size( segment_index_t k ) {
00160 return size_type(1)<<k;
00161 }
00162
00164 static bool is_valid( void *ptr ) {
00165 return reinterpret_cast<size_t>(ptr) > size_t(63);
00166 }
00167
00169 static void init_buckets( segment_ptr_t ptr, size_type sz, bool is_initial ) {
00170 if( is_initial ) std::memset(ptr, 0, sz*sizeof(bucket) );
00171 else for(size_type i = 0; i < sz; i++, ptr++) {
00172 *reinterpret_cast<intptr_t*>(&ptr->mutex) = 0;
00173 ptr->node_list = rehash_req;
00174 }
00175 }
00176
00178 static void add_to_bucket( bucket *b, node_base *n ) {
00179 __TBB_ASSERT(b->node_list != rehash_req, NULL);
00180 n->next = b->node_list;
00181 b->node_list = n;
00182 }
00183
00185 struct enable_segment_failsafe {
00186 segment_ptr_t *my_segment_ptr;
00187 enable_segment_failsafe(segments_table_t &table, segment_index_t k) : my_segment_ptr(&table[k]) {}
00188 ~enable_segment_failsafe() {
00189 if( my_segment_ptr ) *my_segment_ptr = 0;
00190 }
00191 };
00192
00194 void enable_segment( segment_index_t k, bool is_initial = false ) {
00195 __TBB_ASSERT( k, "Zero segment must be embedded" );
00196 enable_segment_failsafe watchdog( my_table, k );
00197 cache_aligned_allocator<bucket> alloc;
00198 size_type sz;
00199 __TBB_ASSERT( !is_valid(my_table[k]), "Wrong concurrent assignment");
00200 if( k >= first_block ) {
00201 sz = segment_size( k );
00095 static hash_map_node_base *const empty_rehashed = reinterpret_cast<hash_map_node_base*>(size_t(0));
00097 class hash_map_base {
00098 public:
00100 typedef size_t size_type;
00102 typedef size_t hashcode_t;
00104 typedef size_t segment_index_t;
00106 typedef hash_map_node_base node_base;
00108 struct bucket : tbb::internal::no_copy {
00110 typedef spin_rw_mutex mutex_t;
00112 typedef mutex_t::scoped_lock scoped_t;
00113 mutex_t mutex;
00114 node_base *node_list;
00115 };
00117 static size_type const embedded_block = 1;
00119 static size_type const embedded_buckets = 1<<embedded_block;
00121 static size_type const first_block = 8;
00123 static size_type const pointers_per_table = sizeof(segment_index_t) * 8;
00125 typedef bucket *segment_ptr_t;
00127 typedef segment_ptr_t segments_table_t[pointers_per_table];
00129 atomic<hashcode_t> my_mask;
00131 segments_table_t my_table;
00133 atomic<size_type> my_size;
00135 bucket my_embedded_segment[embedded_buckets];
00136
00138 hash_map_base() {
00139 std::memset( this, 0, pointers_per_table*sizeof(segment_ptr_t)
00140 + sizeof(my_size) + sizeof(my_mask)
00141 + embedded_buckets*sizeof(bucket) );
00142 for( size_type i = 0; i < embedded_block; i++ )
00143 my_table[i] = my_embedded_segment + segment_base(i);
00144 my_mask = embedded_buckets - 1;
00145 __TBB_ASSERT( embedded_block <= first_block, "The first block number must include embedded blocks");
00146 }
00147
00149 static segment_index_t segment_index_of( size_type index ) {
00150 return segment_index_t( __TBB_Log2( index|1 ) );
00151 }
00152
00154 static segment_index_t segment_base( segment_index_t k ) {
00155 return (segment_index_t(1)<<k & ~segment_index_t(1));
00156 }
00157
00159 static size_type segment_size( segment_index_t k ) {
00160 return size_type(1)<<k;
00161 }
00162
00164 static bool is_valid( void *ptr ) {
00165 return reinterpret_cast<size_t>(ptr) > size_t(63);
00166 }
00167
00169 static void init_buckets( segment_ptr_t ptr, size_type sz, bool is_initial ) {
00170 if( is_initial ) std::memset(ptr, 0, sz*sizeof(bucket) );
00171 else for(size_type i = 0; i < sz; i++, ptr++) {
00172 *reinterpret_cast<intptr_t*>(&ptr->mutex) = 0;
00173 ptr->node_list = rehash_req;
00174 }
00175 }
00176
00178 static void add_to_bucket( bucket *b, node_base *n ) {
00179 __TBB_ASSERT(b->node_list != rehash_req, NULL);
00180 n->next = b->node_list;
00181 b->node_list = n;
00182 }
00183
00185 struct enable_segment_failsafe {
00186 segment_ptr_t *my_segment_ptr;
00187 enable_segment_failsafe(segments_table_t &table, segment_index_t k) : my_segment_ptr(&table[k]) {}
00188 ~enable_segment_failsafe() {
00189 if( my_segment_ptr ) *my_segment_ptr = 0;
00190 }
00191 };
00192
00194 void enable_segment( segment_index_t k, bool is_initial = false ) {
00195 __TBB_ASSERT( k, "Zero segment must be embedded" );
00196 enable_segment_failsafe watchdog( my_table, k );
00197 cache_aligned_allocator<bucket> alloc;
00198 size_type sz;
00199 __TBB_ASSERT( !is_valid(my_table[k]), "Wrong concurrent assignment");
00200 if( k >= first_block ) {
00201 sz = segment_size( k );
00095 static hash_map_node_base *const empty_rehashed = reinterpret_cast<hash_map_node_base*>(size_t(0));
00097 class hash_map_base {
00098 public:
00100 typedef size_t size_type;
00102 typedef size_t hashcode_t;
00104 typedef size_t segment_index_t;
00106 typedef hash_map_node_base node_base;
00108 struct bucket : tbb::internal::no_copy {
00110 typedef spin_rw_mutex mutex_t;
00112 typedef mutex_t::scoped_lock scoped_t;
00113 mutex_t mutex;
00114 node_base *node_list;
00115 };
00117 static size_type const embedded_block = 1;
00119 static size_type const embedded_buckets = 1<<embedded_block;
00121 static size_type const first_block = 8;
00123 static size_type const pointers_per_table = sizeof(segment_index_t) * 8;
00125 typedef bucket *segment_ptr_t;
00127 typedef segment_ptr_t segments_table_t[pointers_per_table];
00129 atomic<hashcode_t> my_mask;
00131 segments_table_t my_table;
00133 atomic<size_type> my_size;
00135 bucket my_embedded_segment[embedded_buckets];
00136
00138 hash_map_base() {
00139 std::memset( this, 0, pointers_per_table*sizeof(segment_ptr_t)
00140 + sizeof(my_size) + sizeof(my_mask)
00141 + embedded_buckets*sizeof(bucket) );
00142 for( size_type i = 0; i < embedded_block; i++ )
00143 my_table[i] = my_embedded_segment + segment_base(i);
00144 my_mask = embedded_buckets - 1;
00145 __TBB_ASSERT( embedded_block <= first_block, "The first block number must include embedded blocks");
00146 }
00147
00149 static segment_index_t segment_index_of( size_type index ) {
00150 return segment_index_t( __TBB_Log2( index|1 ) );
00151 }
00152
00154 static segment_index_t segment_base( segment_index_t k ) {
00155 return (segment_index_t(1)<<k & ~segment_index_t(1));
00156 }
00157
00159 static size_type segment_size( segment_index_t k ) {
00160 return size_type(1)<<k;
00161 }
00162
00164 static bool is_valid( void *ptr ) {
00165 return reinterpret_cast<size_t>(ptr) > size_t(63);
00166 }
00167
00169 static void init_buckets( segment_ptr_t ptr, size_type sz, bool is_initial ) {
00170 if( is_initial ) std::memset(ptr, 0, sz*sizeof(bucket) );
00171 else for(size_type i = 0; i < sz; i++, ptr++) {
00172 *reinterpret_cast<intptr_t*>(&ptr->mutex) = 0;
00173 ptr->node_list = rehash_req;
00174 }
00175 }
00176
00178 static void add_to_bucket( bucket *b, node_base *n ) {
00179 __TBB_ASSERT(b->node_list != rehash_req, NULL);
00180 n->next = b->node_list;
00181 b->node_list = n;
00182 }
00183
00185 struct enable_segment_failsafe {
00186 segment_ptr_t *my_segment_ptr;
00187 enable_segment_failsafe(segments_table_t &table, segment_index_t k) : my_segment_ptr(&table[k]) {}
00188 ~enable_segment_failsafe() {
00189 if( my_segment_ptr ) *my_segment_ptr = 0;
00190 }
00191 };
00192
00194 void enable_segment( segment_index_t k, bool is_initial = false ) {
00195 __TBB_ASSERT( k, "Zero segment must be embedded" );
00196 enable_segment_failsafe watchdog( my_table, k );
00197 cache_aligned_allocator<bucket> alloc;
00198 size_type sz;
00199 __TBB_ASSERT( !is_valid(my_table[k]), "Wrong concurrent assignment");
00200 if( k >= first_block ) {
00201 sz = segment_size( k );
00095 static hash_map_node_base *const empty_rehashed = reinterpret_cast<hash_map_node_base*>(size_t(0));
00097 class hash_map_base {
00098 public:
00100 typedef size_t size_type;
00102 typedef size_t hashcode_t;
00104 typedef size_t segment_index_t;
00106 typedef hash_map_node_base node_base;
00108 struct bucket : tbb::internal::no_copy {
00110 typedef spin_rw_mutex mutex_t;
00112 typedef mutex_t::scoped_lock scoped_t;
00113 mutex_t mutex;
00114 node_base *node_list;
00115 };
00117 static size_type const embedded_block = 1;
00119 static size_type const embedded_buckets = 1<<embedded_block;
00121 static size_type const first_block = 8;
00123 static size_type const pointers_per_table = sizeof(segment_index_t) * 8;
00125 typedef bucket *segment_ptr_t;
00127 typedef segment_ptr_t segments_table_t[pointers_per_table];
00129 atomic<hashcode_t> my_mask;
00131 segments_table_t my_table;
00133 atomic<size_type> my_size;
00135 bucket my_embedded_segment[embedded_buckets];
00136
00138 hash_map_base() {
00139 std::memset( this, 0, pointers_per_table*sizeof(segment_ptr_t)
00140 + sizeof(my_size) + sizeof(my_mask)
00141 + embedded_buckets*sizeof(bucket) );
00142 for( size_type i = 0; i < embedded_block; i++ )
00143 my_table[i] = my_embedded_segment + segment_base(i);
00144 my_mask = embedded_buckets - 1;
00145 __TBB_ASSERT( embedded_block <= first_block, "The first block number must include embedded blocks");
00146 }
00147
00149 static segment_index_t segment_index_of( size_type index ) {
00150 return segment_index_t( __TBB_Log2( index|1 ) );
00151 }
00152
00154 static segment_index_t segment_base( segment_index_t k ) {
00155 return (segment_index_t(1)<<k & ~segment_index_t(1));
00156 }
00157
00159 static size_type segment_size( segment_index_t k ) {
00160 return size_type(1)<<k;
00161 }
00162
00164 static bool is_valid( void *ptr ) {
00165 return reinterpret_cast<size_t>(ptr) > size_t(63);
00166 }
00167
00169 static void init_buckets( segment_ptr_t ptr, size_type sz, bool is_initial ) {
00170 if( is_initial ) std::memset(ptr, 0, sz*sizeof(bucket) );
00171 else for(size_type i = 0; i < sz; i++, ptr++) {
00172 *reinterpret_cast<intptr_t*>(&ptr->mutex) = 0;
00173 ptr->node_list = rehash_req;
00174 }
00175 }
00176
00178 static void add_to_bucket( bucket *b, node_base *n ) {
00179 __TBB_ASSERT(b->node_list != rehash_req, NULL);
00180 n->next = b->node_list;
00181 b->node_list = n;
00182 }
00183
00185 struct enable_segment_failsafe {
00186 segment_ptr_t *my_segment_ptr;
00187 enable_segment_failsafe(segments_table_t &table, segment_index_t k) : my_segment_ptr(&table[k]) {}
00188 ~enable_segment_failsafe() {
00189 if( my_segment_ptr ) *my_segment_ptr = 0;
00190 }
00191 };
00192
00194 void enable_segment( segment_index_t k, bool is_initial = false ) {
00195 __TBB_ASSERT( k, "Zero segment must be embedded" );
00196 enable_segment_failsafe watchdog( my_table, k );
00197 cache_aligned_allocator<bucket> alloc;
00198 size_type sz;
00199 __TBB_ASSERT( !is_valid(my_table[k]), "Wrong concurrent assignment");
00200 if( k >= first_block ) {
00201 sz = segment_size( k );
00095 static hash_map_node_base *const empty_rehashed = reinterpret_cast<hash_map_node_base*>(size_t(0));
00097 class hash_map_base {
00098 public:
00100 typedef size_t size_type;
00102 typedef size_t hashcode_t;
00104 typedef size_t segment_index_t;
00106 typedef hash_map_node_base node_base;
00108 struct bucket : tbb::internal::no_copy {
00110 typedef spin_rw_mutex mutex_t;
00112 typedef mutex_t::scoped_lock scoped_t;
00113 mutex_t mutex;
00114 node_base *node_list;
00115 };
00117 static size_type const embedded_block = 1;
00119 static size_type const embedded_buckets = 1<<embedded_block;
00121 static size_type const first_block = 8;
00123 static size_type const pointers_per_table = sizeof(segment_index_t) * 8;
00125 typedef bucket *segment_ptr_t;
00127 typedef segment_ptr_t segments_table_t[pointers_per_table];
00129 atomic<hashcode_t> my_mask;
00131 segments_table_t my_table;
00133 atomic<size_type> my_size;
00135 bucket my_embedded_segment[embedded_buckets];
00136
00138 hash_map_base() {
00139 std::memset( this, 0, pointers_per_table*sizeof(segment_ptr_t)
00140 + sizeof(my_size) + sizeof(my_mask)
00141 + embedded_buckets*sizeof(bucket) );
00142 for( size_type i = 0; i < embedded_block; i++ )
00143 my_table[i] = my_embedded_segment + segment_base(i);
00144 my_mask = embedded_buckets - 1;
00145 __TBB_ASSERT( embedded_block <= first_block, "The first block number must include embedded blocks");
00146 }
00147
00149 static segment_index_t segment_index_of( size_type index ) {
00150 return segment_index_t( __TBB_Log2( index|1 ) );
00151 }
00152
00154 static segment_index_t segment_base( segment_index_t k ) {
00155 return (segment_index_t(1)<<k & ~segment_index_t(1));
00156 }
00157
00159 static size_type segment_size( segment_index_t k ) {
00160 return size_type(1)<<k;
00161 }
00162
00164 static bool is_valid( void *ptr ) {
00165 return reinterpret_cast<size_t>(ptr) > size_t(63);
00166 }
00167
00169 static void init_buckets( segment_ptr_t ptr, size_type sz, bool is_initial ) {
00170 if( is_initial ) std::memset(ptr, 0, sz*sizeof(bucket) );
00171 else for(size_type i = 0; i < sz; i++, ptr++) {
00172 *reinterpret_cast<intptr_t*>(&ptr->mutex) = 0;
00173 ptr->node_list = rehash_req;
00174 }
00175 }
00176
00178 static void add_to_bucket( bucket *b, node_base *n ) {
00179 __TBB_ASSERT(b->node_list != rehash_req, NULL);
00180 n->next = b->node_list;
00181 b->node_list = n;
00182 }
00183
00185 struct enable_segment_failsafe {
00186 segment_ptr_t *my_segment_ptr;
00187 enable_segment_failsafe(segments_table_t &table, segment_index_t k) : my_segment_ptr(&table[k]) {}
00188 ~enable_segment_failsafe() {
00189 if( my_segment_ptr ) *my_segment_ptr = 0;
00190 }
00191 };
00192
00194 void enable_segment( segment_index_t k, bool is_initial = false ) {
00195 __TBB_ASSERT( k, "Zero segment must be embedded" );
00196 enable_segment_failsafe watchdog( my_table, k );
00197 cache_aligned_allocator<bucket> alloc;
00198 size_type sz;
00199 __TBB_ASSERT( !is_valid(my_table[k]), "Wrong concurrent assignment");
00200 if( k >= first_block ) {
00201 sz = segment_size( k );
00095 static hash_map_node_base *const empty_rehashed = reinterpret_cast<hash_map_node_base*>(size_t(0));
00097 class hash_map_base {
00098 public:
00100 typedef size_t size_type;
00102 typedef size_t hashcode_t;
00104 typedef size_t segment_index_t;
00106 typedef hash_map_node_base node_base;
00108 struct bucket : tbb::internal::no_copy {
00110 typedef spin_rw_mutex mutex_t;
00112 typedef mutex_t::scoped_lock scoped_t;
00113 mutex_t mutex;
00114 node_base *node_list;
00115 };
00117 static size_type const embedded_block = 1;
00119 static size_type const embedded_buckets = 1<<embedded_block;
00121 static size_type const first_block = 8;
00123 static size_type const pointers_per_table = sizeof(segment_index_t) * 8;
00125 typedef bucket *segment_ptr_t;
00127 typedef segment_ptr_t segments_table_t[pointers_per_table];
00129 atomic<hashcode_t> my_mask;
00131 segments_table_t my_table;
00133 atomic<size_type> my_size;
00135 bucket my_embedded_segment[embedded_buckets];
00136
00138 hash_map_base() {
00139 std::memset( this, 0, pointers_per_table*sizeof(segment_ptr_t)
00140 + sizeof(my_size) + sizeof(my_mask)
00141 + embedded_buckets*sizeof(bucket) );
00142 for( size_type i = 0; i < embedded_block; i++ )
00143 my_table[i] = my_embedded_segment + segment_base(i);
00144 my_mask = embedded_buckets - 1;
00145 __TBB_ASSERT( embedded_block <= first_block, "The first block number must include embedded blocks");
00146 }
00147
00149 static segment_index_t segment_index_of( size_type index ) {
00150 return segment_index_t( __TBB_Log2( index|1 ) );
00151 }
00152
00154 static segment_index_t segment_base( segment_index_t k ) {
00155 return (segment_index_t(1)<<k & ~segment_index_t(1));
00156 }
00157
00159 static size_type segment_size( segment_index_t k ) {
00160 return size_type(1)<<k;
00161 }
00162
00164 static bool is_valid( void *ptr ) {
00165 return reinterpret_cast<size_t>(ptr) > size_t(63);
00166 }
00167
00169 static void init_buckets( segment_ptr_t ptr, size_type sz, bool is_initial ) {
00170 if( is_initial ) std::memset(ptr, 0, sz*sizeof(bucket) );
00171 else for(size_type i = 0; i < sz; i++, ptr++) {
00172 *reinterpret_cast<intptr_t*>(&ptr->mutex) = 0;
00173 ptr->node_list = rehash_req;
00174 }
00175 }
00176
00178 static void add_to_bucket( bucket *b, node_base *n ) {
00179 __TBB_ASSERT(b->node_list != rehash_req, NULL);
00180 n->next = b->node_list;
00181 b->node_list = n;
00182 }
00183
00185 struct enable_segment_failsafe {
00186 segment_ptr_t *my_segment_ptr;
00187 enable_segment_failsafe(segments_table_t &table, segment_index_t k) : my_segment_ptr(&table[k]) {}
00188 ~enable_segment_failsafe() {
00189 if( my_segment_ptr ) *my_segment_ptr = 0;
00190 }
00191 };
00192
00194 void enable_segment( segment_index_t k, bool is_initial = false ) {
00195 __TBB_ASSERT( k, "Zero segment must be embedded" );
00196 enable_segment_failsafe watchdog( my_table, k );
00197 cache_aligned_allocator<bucket> alloc;
00198 size_type sz;
00199 __TBB_ASSERT( !is_valid(my_table[k]), "Wrong concurrent assignment");
00200 if( k >= first_block ) {
00201 sz = segment_size( k );
00095 static hash_map_node_base *const empty_rehashed = reinterpret_cast<hash_map_node_base*>(size_t(0));
00097 class hash_map_base {
00098 public:
00100 typedef size_t size_type;
00102 typedef size_t hashcode_t;
00104 typedef size_t segment_index_t;
00106 typedef hash_map_node_base node_base;
00108 struct bucket : tbb::internal::no_copy {
00110 typedef spin_rw_mutex mutex_t;
00112 typedef mutex_t::scoped_lock scoped_t;
00113 mutex_t mutex;
00114 node_base *node_list;
00115 };
00117 static size_type const embedded_block = 1;
00119 static size_type const embedded_buckets = 1<<embedded_block;
00121 static size_type const first_block = 8;
00123 static size_type const pointers_per_table = sizeof(segment_index_t) * 8;
00125 typedef bucket *segment_ptr_t;
00127 typedef segment_ptr_t segments_table_t[pointers_per_table];
00129 atomic<hashcode_t> my_mask;
00131 segments_table_t my_table;
00133 atomic<size_type> my_size;
00135 bucket my_embedded_segment[embedded_buckets];
00136
00138 hash_map_base() {
00139 std::memset( this, 0, pointers_per_table*sizeof(segment_ptr_t)
00140 + sizeof(my_size) + sizeof(my_mask)
00141 + embedded_buckets*sizeof(bucket) );
00142 for( size_type i = 0; i < embedded_block; i++ )
00143 my_table[i] = my_embedded_segment + segment_base(i);
00144 my_mask = embedded_buckets - 1;
00145 __TBB_ASSERT( embedded_block <= first_block, "The first block number must include embedded blocks");
00146 }
00147
00149 static segment_index_t segment_index_of( size_type index ) {
00150 return segment_index_t( __TBB_Log2( index|1 ) );
00151 }
00152
00154 static segment_index_t segment_base( segment_index_t k ) {
00155 return (segment_index_t(1)<<k & ~segment_index_t(1));
00156 }
00157
00159 static size_type segment_size( segment_index_t k ) {
00160 return size_type(1)<<k;
00161 }
00162
00164 static bool is_valid( void *ptr ) {
00165 return reinterpret_cast<size_t>(ptr) > size_t(63);
00166 }
00167
00169 static void init_buckets( segment_ptr_t ptr, size_type sz, bool is_initial ) {
00170 if( is_initial ) std::memset(ptr, 0, sz*sizeof(bucket) );
00171 else for(size_type i = 0; i < sz; i++, ptr++) {
00172 *reinterpret_cast<intptr_t*>(&ptr->mutex) = 0;
00173 ptr->node_list = rehash_req;
00174 }
00175 }
00176
00178 static void add_to_bucket( bucket *b, node_base *n ) {
00179 __TBB_ASSERT(b->node_list != rehash_req, NULL);
00180 n->next = b->node_list;
00181 b->node_list = n;
00182 }
00183
00185 struct enable_segment_failsafe {
00186 segment_ptr_t *my_segment_ptr;
00187 enable_segment_failsafe(segments_table_t &table, segment_index_t k) : my_segment_ptr(&table[k]) {}
00188 ~enable_segment_failsafe() {
00189 if( my_segment_ptr ) *my_segment_ptr = 0;
00190 }
00191 };
00192
00194 void enable_segment( segment_index_t k, bool is_initial = false ) {
00195 __TBB_ASSERT( k, "Zero segment must be embedded" );
00196 enable_segment_failsafe watchdog( my_table, k );
00197 cache_aligned_allocator<bucket> alloc;
00198 size_type sz;
00199 __TBB_ASSERT( !is_valid(my_table[k]), "Wrong concurrent assignment");
00200 if( k >= first_block ) {
00201 sz = segment_size( k );
00095 static hash_map_node_base *const empty_rehashed = reinterpret_cast<hash_map_node_base*>(size_t(0));
00097 class hash_map_base {
00098 public:
00100 typedef size_t size_type;
00102 typedef size_t hashcode_t;
00104 typedef size_t segment_index_t;
00106 typedef hash_map_node_base node_base;
00108 struct bucket : tbb::internal::no_copy {
00110 typedef spin_rw_mutex mutex_t;
00112 typedef mutex_t::scoped_lock scoped_t;
00113 mutex_t mutex;
00114 node_base *node_list;
00115 };
00117 static size_type const embedded_block = 1;
00119 static size_type const embedded_buckets = 1<<embedded_block;
00121 static size_type const first_block = 8;
00123 static size_type const pointers_per_table = sizeof(segment_index_t) * 8;
00125 typedef bucket *segment_ptr_t;
00127 typedef segment_ptr_t segments_table_t[pointers_per_table];
00129 atomic<hashcode_t> my_mask;
00131 segments_table_t my_table;
00133 atomic<size_type> my_size;
00135 bucket my_embedded_segment[embedded_buckets];
00136
00138 hash_map_base() {
00139 std::memset( this, 0, pointers_per_table*sizeof(segment_ptr_t)
00140 + sizeof(my_size) + sizeof(my_mask)
00141 + embedded_buckets*sizeof(bucket) );
00142 for( size_type i = 0; i < embedded_block; i++ )
00143 my_table[i] = my_embedded_segment + segment_base(i);
00144 my_mask = embedded_buckets - 1;
00145 __TBB_ASSERT( embedded_block <= first_block, "The first block number must include embedded blocks");
00146 }
00147
00149 static segment_index_t segment_index_of( size_type index ) {
00150 return segment_index_t( __TBB_Log2( index|1 ) );
00151 }
00152
00154 static segment_index_t segment_base( segment_index_t k ) {
00155 return (segment_index_t(1)<<k & ~segment_index_t(1));
00156 }
00157
00159 static size_type segment_size( segment_index_t k ) {
00160 return size_type(1)<<k;
00161 }
00162
00164 static bool is_valid( void *ptr ) {
00165 return reinterpret_cast<size_t>(ptr) > size_t(63);
00166 }
00167
00169 static void init_buckets( segment_ptr_t ptr, size_type sz, bool is_initial ) {
00170 if( is_initial ) std::memset(ptr, 0, sz*sizeof(bucket) );
00171 else for(size_type i = 0; i < sz; i++, ptr++) {
00172 *reinterpret_cast<intptr_t*>(&ptr->mutex) = 0;
00173 ptr->node_list = rehash_req;
00174 }
00175 }
00176
00178 static void add_to_bucket( bucket *b, node_base *n ) {
00179 __TBB_ASSERT(b->node_list != rehash_req, NULL);
00180 n->next = b->node_list;
00181 b->node_list = n;
00182 }
00183
00185 struct enable_segment_failsafe {
00186 segment_ptr_t *my_segment_ptr;
00187 enable_segment_failsafe(segments_table_t &table, segment_index_t k) : my_segment_ptr(&table[k]) {}
00188 ~enable_segment_failsafe() {
00189 if( my_segment_ptr ) *my_segment_ptr = 0;
00190 }
00191 };
00192
00194 void enable_segment( segment_index_t k, bool is_initial = false ) {
00195 __TBB_ASSERT( k, "Zero segment must be embedded" );
00196 enable_segment_failsafe watchdog( my_table, k );
00197 cache_aligned_allocator<bucket> alloc;
00198 size_type sz;
00199 __TBB_ASSERT( !is_valid(my_table[k]), "Wrong concurrent assignment");
00200 if( k >= first_block ) {
00201 sz = segment_size( k );
00095 static hash_map_node_base *const empty_rehashed = reinterpret_cast<hash_map_node_base*>(size_t(0));
00097 class hash_map_base {
00098 public:
00100 typedef size_t size_type;
00102 typedef size_t hashcode_t;
00104 typedef size_t segment_index_t;
00106 typedef hash_map_node_base node_base;
00108 struct bucket : tbb::internal::no_copy {
00110 typedef spin_rw_mutex mutex_t;
00112 typedef mutex_t::scoped_lock scoped_t;
00113 mutex_t mutex;
00114 node_base *node_list;
00115 };
00117 static size_type const embedded_block = 1;
00119 static size_type const embedded_buckets = 1<<embedded_block;
00121 static size_type const first_block = 8;
00123 static size_type const pointers_per_table = sizeof(segment_index_t) * 8;
00125 typedef bucket *segment_ptr_t;
00127 typedef segment_ptr_t segments_table_t[pointers_per_table];
00129 atomic<hashcode_t> my_mask;
00131 segments_table_t my_table;
00133 atomic<size_type> my_size;
00135 bucket my_embedded_segment[embedded_buckets];
00136
00138 hash_map_base() {
00139 std::memset( this, 0, pointers_per_table*sizeof(segment_ptr_t)
00140 + sizeof(my_size) + sizeof(my_mask)
00141 + embedded_buckets*sizeof(bucket) );
00142 for( size_type i = 0; i < embedded_block; i++ )
00143 my_table[i] = my_embedded_segment + segment_base(i);
00144 my_mask = embedded_buckets - 1;
00145 __TBB_ASSERT( embedded_block <= first_block, "The first block number must include embedded blocks");
00146 }
00147
00149 static segment_index_t segment_index_of( size_type index ) {
00150 return segment_index_t( __TBB_Log2( index|1 ) );
00151 }
00152
00154 static segment_index_t segment_base( segment_index_t k ) {
00155 return (segment_index_t(1)<<k & ~segment_index_t(1));
00156 }
00157
00159 static size_type segment_size( segment_index_t k ) {
00160 return size_type(1)<<k;
00161 }
00162
00164 static bool is_valid( void *ptr ) {
00165 return reinterpret_cast<size_t>(ptr) > size_t(63);
00166 }
00167
00169 static void init_buckets( segment_ptr_t ptr, size_type sz, bool is_initial ) {
00170 if( is_initial ) std::memset(ptr, 0, sz*sizeof(bucket) );
00171 else for(size_type i = 0; i < sz; i++, ptr++) {
00172 *reinterpret_cast<intptr_t*>(&ptr->mutex) = 0;
00173 ptr->node_list = rehash_req;
00174 }
00175 }
00176
00178 static void add_to_bucket( bucket *b, node_base *n ) {
00179 __TBB_ASSERT(b->node_list != rehash_req, NULL);
00180 n->next = b->node_list;
00181 b->node_list = n;
00182 }
00183
00185 struct enable_segment_failsafe {
00186 segment_ptr_t *my_segment_ptr;
00187 enable_segment_failsafe(segments_table_t &table, segment_index_t k) : my_segment_ptr(&table[k]) {}
00188 ~enable_segment_failsafe() {
00189 if( my_segment_ptr ) *my_segment_ptr = 0;
00190 }
00191 };
00192
00194 void enable_segment( segment_index_t k, bool is_initial = false ) {
00195 __TBB_ASSERT( k, "Zero segment must be embedded" );
00196 enable_segment_failsafe watchdog( my_table, k );
00197 cache_aligned_allocator<bucket> alloc;
00198 size_type sz;
00199 __TBB_ASSERT( !is_valid(my_table[k]), "Wrong concurrent assignment");
00200 if( k >= first_block ) {
00201 sz = segment_size( k );
00095 static hash_map_node_base *const empty_rehashed = reinterpret_cast<hash_map_node_base*>(size_t(0));
00097 class hash_map_base {
00098 public:
00100 typedef size_t size_type;
00102 typedef size_t hashcode_t;
00104 typedef size_t segment_index_t;
00106 typedef hash_map_node_base node_base;
00108 struct bucket : tbb::internal::no_copy {
00110 typedef spin_rw_mutex mutex_t;
00112 typedef mutex_t::scoped_lock scoped_t;
00113 mutex_t mutex;
00114 node_base *node_list;
00115 };
00117 static size_type const embedded_block = 1;
00119 static size_type const embedded_buckets = 1<<embedded_block;
00121 static size_type const first_block = 8;
00123 static size_type const pointers_per_table = sizeof(segment_index_t) * 8;
00125 typedef bucket *segment_ptr_t;
00127 typedef segment_ptr_t segments_table_t[pointers_per_table];
00129 atomic<hashcode_t> my_mask;
00131 segments_table_t my_table;
00133 atomic<size_type> my_size;
00135 bucket my_embedded_segment[embedded_buckets];
00136
00138 hash_map_base() {
00139 std::memset( this, 0, pointers_per_table*sizeof(segment_ptr_t)
00140 + sizeof(my_size) + sizeof(my_mask)
00141 + embedded_buckets*sizeof(bucket) );
00142 for( size_type i = 0; i < embedded_block; i++ )
00143 my_table[i] = my_embedded_segment + segment_base(i);
00144 my_mask = embedded_buckets - 1;
00145 __TBB_ASSERT( embedded_block <= first_block, "The first block number must include embedded blocks");
00146 }
00147
00149 static segment_index_t segment_index_of( size_type index ) {
00150 return segment_index_t( __TBB_Log2( index|1 ) );
00151 }
00152
00154 static segment_index_t segment_base( segment_index_t k ) {
00155 return (segment_index_t(1)<<k & ~segment_index_t(1));
00156 }
00157
00159 static size_type segment_size( segment_index_t k ) {
00160 return size_type(1)<<k;
00161 }
00162
00164 static bool is_valid( void *ptr ) {
00165 return reinterpret_cast<size_t>(ptr) > size_t(63);
00166 }
00167
00169 static void init_buckets( segment_ptr_t ptr, size_type sz, bool is_initial ) {
00170 if( is_initial ) std::memset(ptr, 0, sz*sizeof(bucket) );
00171 else for(size_type i = 0; i < sz; i++, ptr++) {
00172 *reinterpret_cast<intptr_t*>(&ptr->mutex) = 0;
00173 ptr->node_list = rehash_req;
00174 }
00175 }
00176
00178 static void add_to_bucket( bucket *b, node_base *n ) {
00179 __TBB_ASSERT(b->node_list != rehash_req, NULL);
00180 n->next = b->node_list;
00181 b->node_list = n;
00182 }
00183
00185 struct enable_segment_failsafe {
00186 segment_ptr_t *my_segment_ptr;
00187 enable_segment_failsafe(segments_table_t &table, segment_index_t k) : my_segment_ptr(&table[k]) {}
00188 ~enable_segment_failsafe() {
00189 if( my_segment_ptr ) *my_segment_ptr = 0;
00190 }
00191 };
00192
00194 void enable_segment( segment_index_t k, bool is_initial = false ) {
00195 __TBB_ASSERT( k, "Zero segment must be embedded" );
00196 enable_segment_failsafe watchdog( my_table, k );
00197 cache_aligned_allocator<bucket> alloc;
00198 size_type sz;
00199 __TBB_ASSERT( !is_valid(my_table[k]), "Wrong concurrent assignment");
00200 if( k >= first_block ) {
00201 sz = segment_size( k );
00095 static hash_map_node_base *const empty_rehashed = reinterpret_cast<hash_map_node_base*>(size_t(0));
00097 class hash_map_base {
00098 public:
00100 typedef size_t size_type;
00102 typedef size_t hashcode_t;
00104 typedef size_t segment_index_t;
00106 typedef hash_map_node_base node_base;
00108 struct bucket : tbb::internal::no_copy {
00110 typedef spin_rw_mutex mutex_t;
00112 typedef mutex_t::scoped_lock scoped_t;
00113 mutex_t mutex;
00114 node_base *node_list;
00115 };
00117 static size_type const embedded_block = 1;
00119 static size_type const embedded_buckets = 1<<embedded_block;
00121 static size_type const first_block = 8;
00123 static size_type const pointers_per_table = sizeof(segment_index_t) * 8;
00125 typedef bucket *segment_ptr_t;
00127 typedef segment_ptr_t segments_table_t[pointers_per_table];
00129 atomic<hashcode_t> my_mask;
00131 segments_table_t my_table;
00133 atomic<size_type> my_size;
00135 bucket my_embedded_segment[embedded_buckets];
00136
00138 hash_map_base() {
00139 std::memset( this, 0, pointers_per_table*sizeof(segment_ptr_t)
00140 + sizeof(my_size) + sizeof(my_mask)
00141 + embedded_buckets*sizeof(bucket) );
00142 for( size_type i = 0; i < embedded_block; i++ )
00143 my_table[i] = my_embedded_segment + segment_base(i);
00144 my_mask = embedded_buckets - 1;
00145 __TBB_ASSERT( embedded_block <= first_block, "The first block number must include embedded blocks");
00146 }
00147
00149 static segment_index_t segment_index_of( size_type index ) {
00150 return segment_index_t( __TBB_Log2( index|1 ) );
00151 }
00152
00154 static segment_index_t segment_base( segment_index_t k ) {
00155 return (segment_index_t(1)<<k & ~segment_index_t(1));
00156 }
00157
00159 static size_type segment_size( segment_index_t k ) {
00160 return size_type(1)<<k;
00161 }
00162
00164 static bool is_valid( void *ptr ) {
00165 return reinterpret_cast<size_t>(ptr) > size_t(63);
00166 }
00167
00169 static void init_buckets( segment_ptr_t ptr, size_type sz, bool is_initial ) {
00170 if( is_initial ) std::memset(ptr, 0, sz*sizeof(bucket) );
00171 else for(size_type i = 0; i < sz; i++, ptr++) {
00172 *reinterpret_cast<intptr_t*>(&ptr->mutex) = 0;
00173 ptr->node_list = rehash_req;
00174 }
00175 }
00176
00178 static void add_to_bucket( bucket *b, node_base *n ) {
00179 __TBB_ASSERT(b->node_list != rehash_req, NULL);
00180 n->next = b->node_list;
00181 b->node_list = n;
00182 }
00183
00185 struct enable_segment_failsafe {
00186 segment_ptr_t *my_segment_ptr;
00187 enable_segment_failsafe(segments_table_t &table, segment_index_t k) : my_segment_ptr(&table[k]) {}
00188 ~enable_segment_failsafe() {
00189 if( my_segment_ptr ) *my_segment_ptr = 0;
00190 }
00191 };
00192
00194 void enable_segment( segment_index_t k, bool is_initial = false ) {
00195 __TBB_ASSERT( k, "Zero segment must be embedded" );
00196 enable_segment_failsafe watchdog( my_table, k );
00197