static void apply( const MyTable& table, int i ) { MyTable::const_accessor a; const MyTable::const_accessor& ca = a; bool b = table.find( a, MyKey::make(i) ); ASSERT( b==(table.count(MyKey::make(i))>0), NULL ); ASSERT( b==!a.empty(), NULL ); ASSERT( b==UseKey(i), NULL ); if( b ) { AssertSameType( &*ca, static_cast<const MyTable::value_type*>(0) ); ASSERT( ca->second.value_of()==~(i*i), NULL ); ASSERT( (*ca).second.value_of()==~(i*i), NULL ); } }
inline void CheckAllocator(MyTable &table, size_t expected_allocs, size_t expected_frees, bool exact = true) { size_t items_allocated = table.get_allocator().items_allocated, items_freed = table.get_allocator().items_freed; size_t allocations = table.get_allocator().allocations, frees = table.get_allocator().frees; REMARK("checking allocators: items %u/%u, allocs %u/%u\n", unsigned(items_allocated), unsigned(items_freed), unsigned(allocations), unsigned(frees) ); ASSERT( items_allocated == allocations, NULL); ASSERT( items_freed == frees, NULL); if(exact) { ASSERT( allocations == expected_allocs, NULL); ASSERT( frees == expected_frees, NULL); } else { ASSERT( allocations >= expected_allocs, NULL); ASSERT( frees >= expected_frees, NULL); ASSERT( allocations - frees == expected_allocs - expected_frees, NULL ); } }
static void FillTable( MyTable& x, int n ) { for( int i=1; i<=n; ++i ) { MyKey key( MyKey::make(-i) ); // hash values must not be specified in direct order typename MyTable::accessor a; bool b = x.insert(a,key); ASSERT(b, NULL); a->second.set_value( i*i ); } }
//! Test travering the tabel with a parallel range void ParallelTraverseTable( MyTable& table, size_t n, size_t expected_size ) { REMARK("testing parallel traversal\n"); ASSERT( table.size()==expected_size, NULL ); AtomicByte* array = new AtomicByte[n]; memset( array, 0, n*sizeof(AtomicByte) ); MyTable::range_type r = table.range(10); tbb::parallel_for( r, ParallelTraverseBody<MyTable::range_type>( array, n )); Check( array, n, expected_size ); const MyTable& const_table = table; memset( array, 0, n*sizeof(AtomicByte) ); MyTable::const_range_type cr = const_table.range(10); tbb::parallel_for( cr, ParallelTraverseBody<MyTable::const_range_type>( array, n )); Check( array, n, expected_size ); delete[] array; }
inline void CheckAllocator(MyTable &table, size_t expected_allocs, size_t expected_frees, bool exact = true, int line = 0) { typename MyTable::allocator_type a = table.get_allocator(); REMARK("#%d checking allocators: items %u/%u, allocs %u/%u\n", line, unsigned(a.items_allocated), unsigned(a.items_freed), unsigned(a.allocations), unsigned(a.frees) ); ASSERT( a.items_allocated == a.allocations, NULL); ASSERT( a.items_freed == a.frees, NULL); if(exact) { ASSERT( a.allocations == expected_allocs, NULL); ASSERT( a.frees == expected_frees, NULL); } else { ASSERT( a.allocations >= expected_allocs, NULL); ASSERT( a.frees >= expected_frees, NULL); ASSERT( a.allocations - a.frees == expected_allocs - expected_frees, NULL ); } }
static void apply( MyTable& table, int i ) { if( UseKey(i) ) { if( i&4 ) { MyTable::accessor a; table.insert( a, MyKey::make(i) ); if( i&1 ) (*a).second.set_value(i*i); else a->second.set_value(i*i); } else if( i&1 ) { MyTable::accessor a; table.insert( a, std::make_pair(MyKey::make(i), MyData(i*i)) ); ASSERT( (*a).second.value_of()==i*i, NULL ); } else { MyTable::const_accessor ca; table.insert( ca, std::make_pair(MyKey::make(i), MyData(i*i)) ); ASSERT( ca->second.value_of()==i*i, NULL ); } } }
//! Test traversing the table with an iterator. void TraverseTable( MyTable& table, size_t n, size_t expected_size ) { REMARK("testing traversal\n"); size_t actual_size = table.size(); ASSERT( actual_size==expected_size, NULL ); size_t count = 0; bool* array = new bool[n]; memset( array, 0, n*sizeof(bool) ); const MyTable& const_table = table; MyTable::const_iterator ci = const_table.begin(); for( MyTable::iterator i = table.begin(); i!=table.end(); ++i ) { // Check iterator int k = i->first.value_of(); ASSERT( UseKey(k), NULL ); ASSERT( (*i).first.value_of()==k, NULL ); ASSERT( 0<=k && size_t(k)<n, "out of bounds key" ); ASSERT( !array[k], "duplicate key" ); array[k] = true; ++count; // Check lower/upper bounds std::pair<MyTable::iterator, MyTable::iterator> er = table.equal_range(i->first); std::pair<MyTable::const_iterator, MyTable::const_iterator> cer = const_table.equal_range(i->first); ASSERT(cer.first == er.first && cer.second == er.second, NULL); ASSERT(cer.first == i, NULL); ASSERT(std::distance(cer.first, cer.second) == 1, NULL); // Check const_iterator MyTable::const_iterator cic = ci++; ASSERT( cic->first.value_of()==k, NULL ); ASSERT( (*cic).first.value_of()==k, NULL ); } ASSERT( ci==const_table.end(), NULL ); delete[] array; if( count!=expected_size ) { REPORT("Line %d: count=%ld but should be %ld\n",__LINE__,long(count),long(expected_size)); } }
static void apply( MyTable& table, int i ) { MyTable::accessor a; const MyTable::accessor& ca = a; bool b = table.find( a, MyKey::make(i) ); ASSERT( b==!a.empty(), NULL ); if( b ) { if( !UseKey(i) ) REPORT("Line %d: unexpected key %d present\n",__LINE__,i); AssertSameType( &*a, static_cast<MyTable::value_type*>(0) ); ASSERT( ca->second.value_of()==i*i, NULL ); ASSERT( (*ca).second.value_of()==i*i, NULL ); if( i&1 ) ca->second.set_value( ~ca->second.value_of() ); else (*ca).second.set_value( ~ca->second.value_of() ); } else { if( UseKey(i) ) REPORT("Line %d: key %d missing\n",__LINE__,i); } }
static void apply( MyTable& table, int i ) { bool b; if(i&4) { if(i&8) { MyTable::const_accessor a; b = table.find( a, MyKey::make(i) ) && table.erase( a ); } else { MyTable::accessor a; b = table.find( a, MyKey::make(i) ) && table.erase( a ); } } else b = table.erase( MyKey::make(i) ); if( b ) ++EraseCount; ASSERT( table.count(MyKey::make(i)) == 0, NULL ); }
static void CheckTable( const MyTable& x, int n ) { ASSERT( x.size()==size_t(n), "table is different size than expected" ); ASSERT( x.empty()==(n==0), NULL ); ASSERT( x.size()<=x.max_size(), NULL ); for( int i=1; i<=n; ++i ) { MyKey key( MyKey::make(-i) ); typename MyTable::const_accessor a; bool b = x.find(a,key); ASSERT( b, NULL ); ASSERT( a->second.value_of()==i*i, NULL ); } int count = 0; int key_sum = 0; for( typename MyTable::const_iterator i(x.begin()); i!=x.end(); ++i ) { ++count; key_sum += -i->first.value_of(); } ASSERT( count==n, NULL ); ASSERT( key_sum==n*(n+1)/2, NULL ); }
void TestRehash() { REMARK("testing rehashing\n"); MyTable w; w.insert( std::make_pair(MyKey::make(-5), MyData()) ); w.rehash(); // without this, assertion will fail MyTable::iterator it = w.begin(); int i = 0; // check for non-rehashed buckets for( ; it != w.end(); i++ ) w.count( (it++)->first ); ASSERT( i == 1, NULL ); for( i=0; i<1000; i=(i<29 ? i+1 : i*2) ) { for( int j=max(256+i, i*2); j<10000; j*=3 ) { MyTable v; FillTable( v, i ); ASSERT(int(v.size()) == i, NULL); ASSERT(int(v.bucket_count()) <= j, NULL); v.rehash( j ); ASSERT(int(v.bucket_count()) >= j, NULL); CheckTable( v, i ); } } }
void TestIteratorsAndRanges() { REMARK("testing iterators compliance\n"); TestIteratorTraits<MyTable::iterator,MyTable::value_type>(); TestIteratorTraits<MyTable::const_iterator,const MyTable::value_type>(); MyTable v; MyTable const &u = v; TestIteratorAssignment<MyTable::const_iterator>( u.begin() ); TestIteratorAssignment<MyTable::const_iterator>( v.begin() ); TestIteratorAssignment<MyTable::iterator>( v.begin() ); // doesn't compile as expected: TestIteratorAssignment<typename V::iterator>( u.begin() ); // check for non-existing ASSERT(v.equal_range(MyKey::make(-1)) == std::make_pair(v.end(), v.end()), NULL); ASSERT(u.equal_range(MyKey::make(-1)) == std::make_pair(u.end(), u.end()), NULL); REMARK("testing ranges compliance\n"); TestRangeAssignment<MyTable::const_range_type>( u.range() ); TestRangeAssignment<MyTable::const_range_type>( v.range() ); TestRangeAssignment<MyTable::range_type>( v.range() ); // doesn't compile as expected: TestRangeAssignment<typename V::range_type>( u.range() ); REMARK("testing construction and insertion from iterators range\n"); FillTable( v, 1000 ); MyTable2 t(v.begin(), v.end()); v.rehash(); CheckTable(t, 1000); t.insert(v.begin(), v.end()); // do nothing CheckTable(t, 1000); t.clear(); t.insert(v.begin(), v.end()); // restore CheckTable(t, 1000); REMARK("testing comparison\n"); typedef tbb::concurrent_hash_map<MyKey,MyData2,YourHashCompare,MyAllocator> YourTable1; typedef tbb::concurrent_hash_map<MyKey,MyData2,YourHashCompare> YourTable2; YourTable1 t1; FillTable( t1, 10 ); CheckTable(t1, 10 ); YourTable2 t2(t1.begin(), t1.end()); MyKey key( MyKey::make(-5) ); MyData2 data; ASSERT(t2.erase(key), NULL); YourTable2::accessor a; ASSERT(t2.insert(a, key), NULL); data.set_value(0); a->second = data; ASSERT( t1 != t2, NULL); data.set_value(5*5); a->second = data; ASSERT( t1 == t2, NULL); }