3 #ifndef CDSTEST_HDR_MULTILEVEL_HASHSET_H
4 #define CDSTEST_HDR_MULTILEVEL_HASHSET_H
6 #include "cppunit/cppunit_proxy.h"
10 namespace container {}
15 namespace cc = cds::container;
16 namespace co = cds::opt;
18 class MultiLevelHashSetHdrTest : public CppUnitMini::TestCase
20 template <typename Hash>
26 Arg( size_t k, Hash const& h )
32 template <typename Hash>
35 unsigned int nInsertCall;
36 unsigned int nFindCall;
37 unsigned int nEraseCall;
38 mutable unsigned int nIteratorCall;
42 Item( size_t k, Hash const& h )
51 explicit Item( Arg<Hash> const& arg )
70 template <typename Hash>
73 Hash const& operator()( Item<Hash> const& i ) const
85 hash128(size_t l, size_t h) : lo(l), hi(h) {}
86 hash128( hash128 const& h) : lo(h.lo), hi(h.hi) {}
89 hash128 operator()( size_t n ) const
91 return hash128( std::hash<size_t>()( n ), std::hash<size_t>()( ~n ));
93 hash128 operator()( hash128 const& n ) const
95 return hash128( std::hash<size_t>()( n.lo ), std::hash<size_t>()( ~n.hi ));
100 bool operator()( hash128 const& lhs, hash128 const& rhs ) const
102 if ( lhs.hi != rhs.hi )
103 return lhs.hi < rhs.hi;
104 return lhs.lo < rhs.lo;
109 int operator()( hash128 const& lhs, hash128 const& rhs ) const
111 if ( lhs.hi != rhs.hi )
112 return lhs.hi < rhs.hi ? -1 : 1;
113 return lhs.lo < rhs.lo ? -1 : lhs.lo == rhs.lo ? 0 : 1;
117 friend bool operator==( hash128 const& lhs, hash128 const& rhs )
119 return cmp()( lhs, rhs ) == 0;
121 friend bool operator!=(hash128 const& lhs, hash128 const& rhs)
123 return !( lhs == rhs );
127 template <typename Set, typename Hasher>
128 void test_hp( size_t nHeadBits, size_t nArrayBits )
130 typedef typename Set::hash_type hash_type;
131 typedef typename Set::value_type value_type;
132 typedef Arg<hash_type> arg_type;
133 typedef typename Set::guarded_ptr guarded_ptr;
137 size_t const capacity = 1000;
139 Set s( nHeadBits, nArrayBits );
140 CPPUNIT_MSG("Array size: head=" << s.head_size() << ", array_node=" << s.array_node_size());
141 CPPUNIT_ASSERT(s.head_size() >= (size_t(1) << nHeadBits));
142 CPPUNIT_ASSERT(s.array_node_size() == (size_t(1) << nArrayBits));
144 CPPUNIT_ASSERT( s.empty() );
145 CPPUNIT_ASSERT(s.size() == 0);
148 for ( size_t i = 0; i < capacity; ++i ) {
149 hash_type h = hasher(i);
150 CPPUNIT_ASSERT( !s.contains( h ));
151 CPPUNIT_ASSERT( s.insert( value_type( i, h )));
152 CPPUNIT_ASSERT(s.contains( h ));
154 CPPUNIT_ASSERT( !s.empty() );
155 CPPUNIT_ASSERT( s.size() == i + 1);
157 CPPUNIT_ASSERT( !s.insert( arg_type(i, h) ));
158 CPPUNIT_ASSERT( s.size() == i + 1);
161 // update existing test
162 for ( size_t i = 0; i < capacity; ++i ) {
163 hash_type h = hasher(i);
164 CPPUNIT_ASSERT( s.contains( h ));
165 std::pair<bool, bool> ret = s.update( arg_type( i, h ),
166 [](value_type& i, value_type * prev ) {
167 CPPUNIT_ASSERT_CURRENT( prev != nullptr );
168 CPPUNIT_ASSERT_CURRENT( i.key == prev->key );
169 CPPUNIT_ASSERT_CURRENT( i.hash == prev->hash );
172 CPPUNIT_ASSERT( ret.first );
173 CPPUNIT_ASSERT( !ret.second );
174 CPPUNIT_ASSERT( s.contains( h ));
175 CPPUNIT_ASSERT( s.size() == capacity );
177 guarded_ptr gp(s.get( h ));
178 CPPUNIT_ASSERT( gp );
179 CPPUNIT_ASSERT( gp->nInsertCall == 1 );
180 CPPUNIT_ASSERT( gp->key == i );
181 CPPUNIT_ASSERT( gp->hash == h );
185 for ( size_t i = 0; i < capacity; ++i ) {
186 CPPUNIT_ASSERT( !s.empty() );
187 CPPUNIT_ASSERT( s.size() == capacity - i );
188 CPPUNIT_ASSERT(s.find(hasher(i), []( value_type &) {}));
189 CPPUNIT_ASSERT( s.erase(hasher(i)) );
190 CPPUNIT_ASSERT( !s.find(hasher(i), []( value_type &) {}));
191 CPPUNIT_ASSERT( s.size() == capacity - i - 1);
193 CPPUNIT_ASSERT( s.empty() );
195 // Iterators on empty set
196 CPPUNIT_ASSERT(s.begin() == s.end());
197 CPPUNIT_ASSERT(s.cbegin() == s.cend());
198 CPPUNIT_ASSERT(s.rbegin() == s.rend());
199 CPPUNIT_ASSERT(s.crbegin() == s.crend());
201 // insert with functor
202 for ( size_t i = capacity; i > 0; --i ) {
203 CPPUNIT_ASSERT( s.size() == capacity - i );
204 CPPUNIT_ASSERT(s.insert( arg_type( i, hasher(i)), []( value_type& val ) { val.nInsertCall += 1; } ));
205 CPPUNIT_ASSERT( s.size() == capacity - i + 1 );
206 CPPUNIT_ASSERT( !s.empty() );
208 CPPUNIT_ASSERT(s.find( hasher(i), []( value_type& val ) {
209 CPPUNIT_ASSERT_CURRENT( val.nInsertCall == 1 );
213 CPPUNIT_ASSERT( s.size() == capacity );
215 // for-each iterator test
216 for ( auto& el : s ) {
217 CPPUNIT_ASSERT( el.nInsertCall == 1 );
218 CPPUNIT_ASSERT( el.nFindCall == 1 );
223 for ( auto it = s.begin(), itEnd = s.end(); it != itEnd; ++it ) {
224 CPPUNIT_ASSERT( it->nInsertCall == 1 );
225 CPPUNIT_ASSERT( it->nFindCall == 2 );
229 // reverse iterator test
230 for ( auto it = s.rbegin(), itEnd = s.rend(); it != itEnd; ++it ) {
231 CPPUNIT_ASSERT( it->nInsertCall == 1 );
232 CPPUNIT_ASSERT( it->nFindCall == 3 );
236 // const iterator test
237 for ( auto it = s.cbegin(), itEnd = s.cend(); it != itEnd; ++it ) {
238 CPPUNIT_ASSERT( it->nInsertCall == 1 );
239 CPPUNIT_ASSERT( it->nFindCall == 4 );
240 it->nIteratorCall += 1;
243 // const reverse iterator test
244 for ( auto it = s.rbegin(), itEnd = s.rend(); it != itEnd; ++it ) {
245 CPPUNIT_ASSERT( it->nInsertCall == 1 );
246 CPPUNIT_ASSERT( it->nFindCall == 4 );
247 CPPUNIT_ASSERT( it->nIteratorCall == 1 );
248 it->nIteratorCall += 1;
251 // check completeness
252 for ( size_t i = 1; i <= capacity; ++i ) {
253 CPPUNIT_ASSERT( s.find( hasher( i ), []( value_type const& el ) {
254 CPPUNIT_ASSERT_CURRENT( el.nInsertCall == 1 );
255 CPPUNIT_ASSERT_CURRENT( el.nFindCall == 4 );
256 CPPUNIT_ASSERT_CURRENT( el.nIteratorCall == 2 );
260 // erase with functor test
263 for ( size_t i = 1; i <= capacity; ++i ) {
264 CPPUNIT_ASSERT( s.size() == capacity - i + 1 );
265 CPPUNIT_ASSERT(s.erase(hasher(i), [&nSum]( value_type const& val ) {
266 CPPUNIT_ASSERT_CURRENT( val.nInsertCall == 1 );
267 CPPUNIT_ASSERT_CURRENT( val.nFindCall == 4 );
268 CPPUNIT_ASSERT_CURRENT( val.nIteratorCall == 2 );
271 CPPUNIT_ASSERT( s.size() == capacity - i );
272 CPPUNIT_ASSERT( !s.erase(hasher(i), [&nSum]( value_type const& val ) { nSum += val.key; } ))
274 CPPUNIT_ASSERT(s.empty() );
275 CPPUNIT_ASSERT(nSum == (1 + capacity) * capacity / 2 );
278 // update test with insert allowing
279 for ( size_t i = 0; i < capacity; ++i ) {
280 hash_type h = hasher(i);
281 CPPUNIT_ASSERT( !s.contains( h ));
282 guarded_ptr gp(s.get( h ));
283 CPPUNIT_ASSERT( !gp );
284 std::pair<bool, bool> ret = s.update( arg_type( i, h ),
285 [](value_type& i, value_type * prev ) {
286 CPPUNIT_ASSERT_CURRENT( prev == nullptr );
289 CPPUNIT_ASSERT( ret.first );
290 CPPUNIT_ASSERT( ret.second );
291 CPPUNIT_ASSERT( s.contains( h ));
292 CPPUNIT_ASSERT( s.size() == i + 1 );
295 CPPUNIT_ASSERT( gp );
296 CPPUNIT_ASSERT( gp->nInsertCall == 1 );
297 CPPUNIT_ASSERT( gp->key == i );
298 CPPUNIT_ASSERT( gp->hash == h );
300 CPPUNIT_ASSERT( !s.empty() );
301 CPPUNIT_ASSERT(s.size() == capacity );
303 // erase_at( iterator ) test
304 for ( auto it = s.begin(), itEnd = s.end(); it != itEnd; ++it ) {
305 CPPUNIT_ASSERT( s.erase_at( it ));
307 CPPUNIT_ASSERT( s.empty() );
308 CPPUNIT_ASSERT( s.size() == 0 );
311 for ( size_t i = 0; i < capacity; ++i ) {
312 hash_type h = hasher(i);
313 CPPUNIT_ASSERT( !s.contains( h ));
314 CPPUNIT_ASSERT( s.emplace( i, hasher(i) ));
315 CPPUNIT_ASSERT(s.contains( h ));
317 CPPUNIT_ASSERT( !s.empty() );
318 CPPUNIT_ASSERT( s.size() == i + 1);
320 CPPUNIT_ASSERT( !s.emplace( arg_type(i, h) ));
321 CPPUNIT_ASSERT( s.size() == i + 1);
323 CPPUNIT_ASSERT( !s.empty() );
324 CPPUNIT_ASSERT(s.size() == capacity );
326 // erase_at( reverse_iterator ) test
327 for ( auto it = s.rbegin(), itEnd = s.rend(); it != itEnd; ++it ) {
328 CPPUNIT_ASSERT( s.erase_at( it ));
330 CPPUNIT_ASSERT( s.empty() );
331 CPPUNIT_ASSERT( s.size() == 0 );
334 for ( size_t i = 0; i < capacity; ++i ) {
335 hash_type h = hasher(i);
336 CPPUNIT_ASSERT( !s.contains( h ));
337 CPPUNIT_ASSERT( s.emplace( arg_type( i, hasher(i) )));
338 CPPUNIT_ASSERT(s.contains( h ));
340 CPPUNIT_ASSERT( !s.empty() );
341 CPPUNIT_ASSERT( s.size() == i + 1);
343 CPPUNIT_ASSERT( !s.emplace( i, h ));
344 CPPUNIT_ASSERT( s.size() == i + 1);
346 CPPUNIT_ASSERT( !s.empty() );
347 CPPUNIT_ASSERT(s.size() == capacity );
349 for ( size_t i = capacity; i != 0; --i ) {
350 CPPUNIT_ASSERT( !s.empty() );
351 CPPUNIT_ASSERT( s.size() == i );
353 guarded_ptr gp{ s.extract( hasher(i-1)) };
354 CPPUNIT_ASSERT( gp );
355 CPPUNIT_ASSERT( gp->key == i - 1);
356 CPPUNIT_ASSERT(gp->hash == hasher(i-1));
357 CPPUNIT_ASSERT( !s.contains(hasher(i-1)));
359 gp = s.get(hasher(i-1));
360 CPPUNIT_ASSERT( !gp );
362 CPPUNIT_ASSERT( s.size() == i - 1 );
364 CPPUNIT_ASSERT( s.empty() );
365 CPPUNIT_ASSERT(s.size() == 0 );
368 for ( size_t i = 0; i < capacity; ++i ) {
369 hash_type h = hasher(i);
370 CPPUNIT_ASSERT( !s.contains( h ));
371 CPPUNIT_ASSERT( s.emplace( arg_type( i, hasher(i) )));
372 CPPUNIT_ASSERT(s.contains( h ));
374 CPPUNIT_ASSERT( !s.empty() );
375 CPPUNIT_ASSERT( s.size() == i + 1);
377 CPPUNIT_ASSERT( !s.emplace( i, h ));
378 CPPUNIT_ASSERT( s.size() == i + 1);
380 CPPUNIT_ASSERT( !s.empty() );
381 CPPUNIT_ASSERT(s.size() == capacity );
384 CPPUNIT_ASSERT( s.empty() );
385 CPPUNIT_ASSERT(s.size() == 0 );
387 CPPUNIT_MSG( s.statistics() );
391 void hp_stdhash_stat();
392 void hp_stdhash_5_3();
393 void hp_stdhash_5_3_stat();
395 void hp_hash128_stat();
396 void hp_hash128_4_3();
397 void hp_hash128_4_3_stat();
400 void dhp_stdhash_stat();
401 void dhp_stdhash_5_3();
402 void dhp_stdhash_5_3_stat();
404 void dhp_hash128_stat();
405 void dhp_hash128_4_3();
406 void dhp_hash128_4_3_stat();
408 CPPUNIT_TEST_SUITE(MultiLevelHashSetHdrTest)
409 CPPUNIT_TEST(hp_stdhash)
410 CPPUNIT_TEST(hp_stdhash_stat)
411 CPPUNIT_TEST(hp_stdhash_5_3)
412 CPPUNIT_TEST(hp_stdhash_5_3_stat)
413 CPPUNIT_TEST(hp_hash128)
414 CPPUNIT_TEST(hp_hash128_stat)
415 CPPUNIT_TEST(hp_hash128_4_3)
416 CPPUNIT_TEST(hp_hash128_4_3_stat)
418 CPPUNIT_TEST(dhp_stdhash)
419 CPPUNIT_TEST(dhp_stdhash_stat)
420 CPPUNIT_TEST(dhp_stdhash_5_3)
421 CPPUNIT_TEST(dhp_stdhash_5_3_stat)
422 CPPUNIT_TEST(dhp_hash128)
423 CPPUNIT_TEST(dhp_hash128_stat)
424 CPPUNIT_TEST(dhp_hash128_4_3)
425 CPPUNIT_TEST(dhp_hash128_4_3_stat)
426 CPPUNIT_TEST_SUITE_END()
431 #endif // #ifndef CDSTEST_HDR_MULTILEVEL_HASHSET_H