Renamed MultiLevelHashSet/Map to FeldmanHashSet/Map
[libcds.git] / tests / unit / set2 / set_delodd.h
1 //$$CDS-header$$
2
3 #include "cppunit/thread.h"
4 #include "set2/set_type.h"
5
6 namespace set2 {
7
8 #define TEST_CASE(TAG, X)  void X();
9
10     namespace {
11         struct key_thread
12         {
13             size_t  nKey;
14             size_t  nThread;
15
16             key_thread( size_t key, size_t threadNo )
17                 : nKey( key )
18                 , nThread( threadNo )
19             {}
20
21             key_thread()
22             {}
23         };
24
25         typedef set_type_base<key_thread, size_t>::key_val     key_value_pair;
26     }
27
28     template <>
29     struct cmp<key_thread> {
30         int operator ()(key_thread const& k1, key_thread const& k2) const
31         {
32             if ( k1.nKey < k2.nKey )
33                 return -1;
34             if ( k1.nKey > k2.nKey )
35                 return 1;
36             if ( k1.nThread < k2.nThread )
37                 return -1;
38             if ( k1.nThread > k2.nThread )
39                 return 1;
40             return 0;
41         }
42         int operator ()(key_thread const& k1, size_t k2) const
43         {
44             if ( k1.nKey < k2 )
45                 return -1;
46             if ( k1.nKey > k2 )
47                 return 1;
48             return 0;
49         }
50         int operator ()(size_t k1, key_thread const& k2) const
51         {
52             if ( k1 < k2.nKey )
53                 return -1;
54             if ( k1 > k2.nKey )
55                 return 1;
56             return 0;
57         }
58     };
59
60 } // namespace set2
61
62 namespace std {
63     template <>
64     struct less<set2::key_thread>
65     {
66         bool operator()(set2::key_thread const& k1, set2::key_thread const& k2) const
67         {
68             if ( k1.nKey <= k2.nKey )
69                 return k1.nKey < k2.nKey || k1.nThread < k2.nThread;
70             return false;
71         }
72     };
73
74     template <>
75     struct hash<set2::key_thread>
76     {
77         typedef size_t              result_type;
78         typedef set2::key_thread    argument_type;
79
80         size_t operator()( set2::key_thread const& k ) const
81         {
82             return std::hash<size_t>()(k.nKey);
83         }
84         size_t operator()( size_t k ) const
85         {
86             return std::hash<size_t>()(k);
87         }
88     };
89
90 } // namespace std
91
92 namespace boost {
93     inline size_t hash_value( set2::key_thread const& k )
94     {
95         return std::hash<size_t>()( k.nKey );
96     }
97
98     template <>
99     struct hash<set2::key_thread>
100     {
101         typedef size_t              result_type;
102         typedef set2::key_thread    argument_type;
103
104         size_t operator()(set2::key_thread const& k) const
105         {
106             return boost::hash<size_t>()( k.nKey );
107         }
108         size_t operator()(size_t k) const
109         {
110             return boost::hash<size_t>()( k );
111         }
112     };
113 } // namespace boost
114
115 namespace set2 {
116
117     class Set_DelOdd: public CppUnitMini::TestCase
118     {
119     public:
120         size_t  c_nSetSize =1000000;          // max set size
121         size_t  c_nInsThreadCount = 4;   // insert thread count
122         size_t  c_nDelThreadCount = 4;   // delete thread count
123         size_t  c_nExtractThreadCount = 4;  // extract thread count
124         size_t  c_nMaxLoadFactor = 8;    // maximum load factor
125         bool    c_bPrintGCState = true;
126
127         size_t  c_nCuckooInitialSize = 1024;// initial size for CuckooSet
128         size_t  c_nCuckooProbesetSize = 16; // CuckooSet probeset size (only for list-based probeset)
129         size_t  c_nCuckooProbesetThreshold = 0; // CUckooSet probeset threshold (0 - use default)
130
131         size_t c_nFeldmanSet_HeadBits = 10;
132         size_t c_nFeldmanSet_ArrayBits = 4;
133
134         size_t c_nLoadFactor = 2;
135         std::vector<size_t>     m_arrData;
136
137     protected:
138         typedef key_thread  key_type;
139         typedef size_t      value_type;
140
141         atomics::atomic<size_t>      m_nInsThreadCount;
142
143         // Inserts keys from [0..N)
144         template <class Set>
145         class InsertThread: public CppUnitMini::TestThread
146         {
147             Set&     m_Set;
148
149             virtual InsertThread *    clone()
150             {
151                 return new InsertThread( *this );
152             }
153
154             struct update_functor
155             {
156                 template <typename Q>
157                 void operator()( bool /*bNew*/, key_value_pair const&, Q const& )
158                 {}
159
160                 void operator()(key_value_pair& /*cur*/, key_value_pair * /*prev*/)
161                 {}
162             };
163         public:
164             size_t  m_nInsertSuccess;
165             size_t  m_nInsertFailed;
166
167         public:
168             InsertThread( CppUnitMini::ThreadPool& pool, Set& rMap )
169                 : CppUnitMini::TestThread( pool )
170                 , m_Set( rMap )
171             {}
172             InsertThread( InsertThread& src )
173                 : CppUnitMini::TestThread( src )
174                 , m_Set( src.m_Set )
175             {}
176
177             Set_DelOdd&  getTest()
178             {
179                 return reinterpret_cast<Set_DelOdd&>( m_Pool.m_Test );
180             }
181
182             virtual void init() { cds::threading::Manager::attachThread()   ; }
183             virtual void fini() { cds::threading::Manager::detachThread()   ; }
184
185             virtual void test()
186             {
187                 Set& rSet = m_Set;
188
189                 m_nInsertSuccess =
190                     m_nInsertFailed = 0;
191
192                 std::vector<size_t>& arrData = getTest().m_arrData;
193                 for ( size_t i = 0; i < arrData.size(); ++i ) {
194                     if ( rSet.insert( key_type( arrData[i], m_nThreadNo )))
195                         ++m_nInsertSuccess;
196                     else
197                         ++m_nInsertFailed;
198                 }
199
200                 update_functor f;
201                 for ( size_t i = arrData.size() - 1; i > 0; --i ) {
202                     if ( arrData[i] & 1 ) {
203                         rSet.update( key_type( arrData[i], m_nThreadNo ), f, true );
204                     }
205                 }
206
207                 getTest().m_nInsThreadCount.fetch_sub( 1, atomics::memory_order_release );
208             }
209         };
210
211         struct key_equal {
212             bool operator()( key_type const& k1, key_type const& k2 ) const
213             {
214                 return k1.nKey == k2.nKey;
215             }
216             bool operator()( size_t k1, key_type const& k2 ) const
217             {
218                 return k1 == k2.nKey;
219             }
220             bool operator()( key_type const& k1, size_t k2 ) const
221             {
222                 return k1.nKey == k2;
223             }
224             bool operator ()( key_value_pair const& k1, key_value_pair const& k2 ) const
225             {
226                 return operator()( k1.key, k2.key );
227             }
228             bool operator ()( key_value_pair const& k1, key_type const& k2 ) const
229             {
230                 return operator()( k1.key, k2 );
231             }
232             bool operator ()( key_type const& k1, key_value_pair const& k2 ) const
233             {
234                 return operator()( k1, k2.key );
235             }
236             bool operator ()( key_value_pair const& k1, size_t k2 ) const
237             {
238                 return operator()( k1.key, k2 );
239             }
240             bool operator ()( size_t k1, key_value_pair const& k2 ) const
241             {
242                 return operator()( k1, k2.key );
243             }
244         };
245
246         struct key_less {
247             bool operator()( key_type const& k1, key_type const& k2 ) const
248             {
249                 return k1.nKey < k2.nKey;
250             }
251             bool operator()( size_t k1, key_type const& k2 ) const
252             {
253                 return k1 < k2.nKey;
254             }
255             bool operator()( key_type const& k1, size_t k2 ) const
256             {
257                 return k1.nKey < k2;
258             }
259             bool operator ()( key_value_pair const& k1, key_value_pair const& k2 ) const
260             {
261                 return operator()( k1.key, k2.key );
262             }
263             bool operator ()( key_value_pair const& k1, key_type const& k2 ) const
264             {
265                 return operator()( k1.key, k2 );
266             }
267             bool operator ()( key_type const& k1, key_value_pair const& k2 ) const
268             {
269                 return operator()( k1, k2.key );
270             }
271             bool operator ()( key_value_pair const& k1, size_t k2 ) const
272             {
273                 return operator()( k1.key, k2 );
274             }
275             bool operator ()( size_t k1, key_value_pair const& k2 ) const
276             {
277                 return operator()( k1, k2.key );
278             }
279
280             typedef key_equal   equal_to;
281         };
282
283         // Deletes odd keys from [0..N)
284         template <class Set>
285         class DeleteThread: public CppUnitMini::TestThread
286         {
287             Set&     m_Set;
288
289             virtual DeleteThread *    clone()
290             {
291                 return new DeleteThread( *this );
292             }
293         public:
294             size_t  m_nDeleteSuccess;
295             size_t  m_nDeleteFailed;
296
297         public:
298             DeleteThread( CppUnitMini::ThreadPool& pool, Set& rMap )
299                 : CppUnitMini::TestThread( pool )
300                 , m_Set( rMap )
301             {}
302             DeleteThread( DeleteThread& src )
303                 : CppUnitMini::TestThread( src )
304                 , m_Set( src.m_Set )
305             {}
306
307             Set_DelOdd&  getTest()
308             {
309                 return reinterpret_cast<Set_DelOdd&>( m_Pool.m_Test );
310             }
311
312             virtual void init() { cds::threading::Manager::attachThread()   ; }
313             virtual void fini() { cds::threading::Manager::detachThread()   ; }
314
315             template <typename SetType, bool>
316             struct eraser {
317                 static bool erase( SetType& s, size_t key, size_t /*thread*/)
318                 {
319                     return s.erase_with( key, key_less() );
320                 }
321             };
322
323             template <typename SetType>
324             struct eraser<SetType, true> {
325                 static bool erase(SetType& s, size_t key, size_t thread)
326                 {
327                     return s.erase( key_type(key, thread));
328                 }
329             };
330
331             virtual void test()
332             {
333                 Set& rSet = m_Set;
334
335                 m_nDeleteSuccess =
336                     m_nDeleteFailed = 0;
337
338                 size_t const nInsThreadCount = getTest().c_nInsThreadCount;
339                 std::vector<size_t>& arrData = getTest().m_arrData;
340
341                 if ( m_nThreadNo & 1 ) {
342                     for (size_t i = 0; i < arrData.size(); ++i) {
343                         if (arrData[i] & 1) {
344                             for ( size_t k = 0; k < nInsThreadCount; ++k ) {
345                                 if ( eraser<Set, Set::c_bEraseExactKey>::erase( rSet, arrData[i], k ))
346                                     ++m_nDeleteSuccess;
347                                 else
348                                     ++m_nDeleteFailed;
349                             }
350                         }
351                         if ( getTest().m_nInsThreadCount.load( atomics::memory_order_acquire ) == 0 )
352                             break;
353                     }
354                 }
355                 else {
356                     for (size_t i = arrData.size() - 1; i > 0; --i) {
357                         if (arrData[i] & 1) {
358                             for ( size_t k = 0; k < nInsThreadCount; ++k ) {
359                                 if (eraser<Set, Set::c_bEraseExactKey>::erase(rSet, arrData[i], k))
360                                     ++m_nDeleteSuccess;
361                                 else
362                                     ++m_nDeleteFailed;
363                             }
364                         }
365                         if ( getTest().m_nInsThreadCount.load( atomics::memory_order_acquire ) == 0 )
366                             break;
367                     }
368                 }
369             }
370         };
371
372         // Extracts odd keys from [0..N)
373         template <typename GC, class Set>
374         class ExtractThread: public CppUnitMini::TestThread
375         {
376             Set&     m_Set;
377
378             virtual ExtractThread *    clone()
379             {
380                 return new ExtractThread( *this );
381             }
382         public:
383             size_t  m_nExtractSuccess;
384             size_t  m_nExtractFailed;
385
386         public:
387             ExtractThread( CppUnitMini::ThreadPool& pool, Set& rMap )
388                 : CppUnitMini::TestThread( pool )
389                 , m_Set( rMap )
390             {}
391             ExtractThread( ExtractThread& src )
392                 : CppUnitMini::TestThread( src )
393                 , m_Set( src.m_Set )
394             {}
395
396             Set_DelOdd&  getTest()
397             {
398                 return reinterpret_cast<Set_DelOdd&>( m_Pool.m_Test );
399             }
400
401             virtual void init() { cds::threading::Manager::attachThread()   ; }
402             virtual void fini() { cds::threading::Manager::detachThread()   ; }
403
404             template <typename SetType, bool>
405             struct extractor {
406                 static typename SetType::guarded_ptr extract(SetType& s, size_t key, size_t /*thread*/)
407                 {
408                     return s.extract_with( key, key_less());
409                 }
410             };
411
412             template <typename SetType>
413             struct extractor<SetType, true> {
414                 static typename SetType::guarded_ptr extract(SetType& s, size_t key, size_t thread)
415                 {
416                     return s.extract( key_type(key, thread));
417                 }
418             };
419
420             virtual void test()
421             {
422                 Set& rSet = m_Set;
423
424                 m_nExtractSuccess =
425                     m_nExtractFailed = 0;
426
427                 typename Set::guarded_ptr gp;
428
429                 std::vector<size_t>& arrData = getTest().m_arrData;
430                 size_t const nInsThreadCount = getTest().c_nInsThreadCount;
431
432                 if ( m_nThreadNo & 1 ) {
433                     for ( size_t i = 0; i < arrData.size(); ++i ) {
434                         if (arrData[i] & 1) {
435                             for ( size_t k = 0; k < nInsThreadCount; ++k ) {
436                                 gp = extractor<Set, Set::c_bEraseExactKey>::extract( rSet, arrData[i], k );
437                                 if ( gp )
438                                     ++m_nExtractSuccess;
439                                 else
440                                     ++m_nExtractFailed;
441                                 gp.release();
442                             }
443                         }
444                         if ( getTest().m_nInsThreadCount.load( atomics::memory_order_acquire ) == 0 )
445                             break;
446                     }
447                 }
448                 else {
449                     for (size_t i = arrData.size() - 1; i > 0; --i) {
450                         if (arrData[i] & 1) {
451                             for ( size_t k = 0; k < nInsThreadCount; ++k ) {
452                                 gp = extractor<Set, Set::c_bEraseExactKey>::extract( rSet, arrData[i], k);
453                                 if ( gp )
454                                     ++m_nExtractSuccess;
455                                 else
456                                     ++m_nExtractFailed;
457                                 gp.release();
458                             }
459                         }
460                         if ( getTest().m_nInsThreadCount.load( atomics::memory_order_acquire ) == 0 )
461                             break;
462                     }
463                 }
464             }
465         };
466
467         template <typename RCU, class Set>
468         class ExtractThread< cds::urcu::gc<RCU>, Set >: public CppUnitMini::TestThread
469         {
470             Set&     m_Set;
471
472             virtual ExtractThread *    clone()
473             {
474                 return new ExtractThread( *this );
475             }
476         public:
477             size_t  m_nExtractSuccess;
478             size_t  m_nExtractFailed;
479
480         public:
481             ExtractThread( CppUnitMini::ThreadPool& pool, Set& rMap )
482                 : CppUnitMini::TestThread( pool )
483                 , m_Set( rMap )
484             {}
485             ExtractThread( ExtractThread& src )
486                 : CppUnitMini::TestThread( src )
487                 , m_Set( src.m_Set )
488             {}
489
490             Set_DelOdd&  getTest()
491             {
492                 return reinterpret_cast<Set_DelOdd&>( m_Pool.m_Test );
493             }
494
495             virtual void init() { cds::threading::Manager::attachThread()   ; }
496             virtual void fini() { cds::threading::Manager::detachThread()   ; }
497
498             template <typename SetType, bool>
499             struct extractor {
500                 static typename SetType::exempt_ptr extract(SetType& s, size_t key, size_t /*thread*/)
501                 {
502                     return s.extract_with(key, key_less());
503                 }
504             };
505
506             template <typename SetType>
507             struct extractor<SetType, true> {
508                 static typename SetType::exempt_ptr extract(SetType& s, size_t key, size_t thread)
509                 {
510                     return s.extract(key_type(key, thread));
511                 }
512             };
513
514             virtual void test()
515             {
516                 Set& rSet = m_Set;
517
518                 m_nExtractSuccess =
519                     m_nExtractFailed = 0;
520
521                 typename Set::exempt_ptr xp;
522
523                 std::vector<size_t>& arrData = getTest().m_arrData;
524                 size_t const nInsThreadCount = getTest().c_nInsThreadCount;
525
526                 if ( m_nThreadNo & 1 ) {
527                     for (size_t i = 0; i < arrData.size(); ++i) {
528                         if (arrData[i] & 1) {
529                             for ( size_t k = 0; k < nInsThreadCount; ++k ) {
530                                 if ( Set::c_bExtractLockExternal ) {
531                                     typename Set::rcu_lock l;
532                                     xp = extractor<Set, Set::c_bEraseExactKey>::extract( rSet, arrData[i], k);
533                                     if ( xp )
534                                         ++m_nExtractSuccess;
535                                     else
536                                         ++m_nExtractFailed;
537                                 }
538                                 else {
539                                     xp = extractor<Set, Set::c_bEraseExactKey>::extract(rSet, arrData[i], k);
540                                     if ( xp )
541                                         ++m_nExtractSuccess;
542                                     else
543                                         ++m_nExtractFailed;
544                                 }
545                                 xp.release();
546                             }
547                         }
548                         if ( getTest().m_nInsThreadCount.load( atomics::memory_order_acquire ) == 0 )
549                             break;
550                     }
551                 }
552                 else {
553                     for (size_t i = arrData.size() - 1; i > 0; --i) {
554                         if (arrData[i] & 1) {
555                             for ( size_t k = 0; k < nInsThreadCount; ++k ) {
556                                 if ( Set::c_bExtractLockExternal ) {
557                                     typename Set::rcu_lock l;
558                                     xp = extractor<Set, Set::c_bEraseExactKey>::extract(rSet, arrData[i], k);
559                                     if ( xp )
560                                         ++m_nExtractSuccess;
561                                     else
562                                         ++m_nExtractFailed;
563                                 }
564                                 else {
565                                     xp = extractor<Set, Set::c_bEraseExactKey>::extract(rSet, arrData[i], k);
566                                     if ( xp )
567                                         ++m_nExtractSuccess;
568                                     else
569                                         ++m_nExtractFailed;
570                                 }
571                                 xp.release();
572                             }
573                         }
574                         if ( getTest().m_nInsThreadCount.load( atomics::memory_order_acquire ) == 0 )
575                             break;
576                     }
577                 }
578             }
579         };
580
581     protected:
582         template <class Set>
583         void do_test( size_t nLoadFactor )
584         {
585             Set  testSet( c_nSetSize, nLoadFactor );
586             do_test_with( testSet );
587             analyze( testSet );
588         }
589
590         template <class Set>
591         void do_test_extract( size_t nLoadFactor )
592         {
593             Set  testSet( c_nSetSize, nLoadFactor );
594             do_test_extract_with( testSet );
595             analyze( testSet );
596         }
597
598         template <class Set>
599         void do_test_with( Set& testSet )
600         {
601             typedef InsertThread<Set> insert_thread;
602             typedef DeleteThread<Set> delete_thread;
603
604             m_nInsThreadCount.store( c_nInsThreadCount, atomics::memory_order_release );
605
606             CppUnitMini::ThreadPool pool( *this );
607             pool.add( new insert_thread( pool, testSet ), c_nInsThreadCount );
608             pool.add( new delete_thread( pool, testSet ), c_nDelThreadCount ? c_nDelThreadCount : cds::OS::topology::processor_count());
609             pool.run();
610             CPPUNIT_MSG( "   Duration=" << pool.avgDuration() );
611
612             size_t nInsertSuccess = 0;
613             size_t nInsertFailed = 0;
614             size_t nDeleteSuccess = 0;
615             size_t nDeleteFailed = 0;
616             for ( CppUnitMini::ThreadPool::iterator it = pool.begin(); it != pool.end(); ++it ) {
617                 insert_thread * pThread = dynamic_cast<insert_thread *>( *it );
618                 if ( pThread ) {
619                     nInsertSuccess += pThread->m_nInsertSuccess;
620                     nInsertFailed += pThread->m_nInsertFailed;
621                 }
622                 else {
623                     delete_thread * p = static_cast<delete_thread *>( *it );
624                     nDeleteSuccess += p->m_nDeleteSuccess;
625                     nDeleteFailed += p->m_nDeleteFailed;
626                 }
627             }
628
629             CPPUNIT_CHECK( nInsertSuccess == c_nSetSize * c_nInsThreadCount );
630             CPPUNIT_CHECK( nInsertFailed == 0 );
631
632             CPPUNIT_MSG( "  Totals (success/failed): \n\t"
633                       << "      Insert=" << nInsertSuccess << '/' << nInsertFailed << "\n\t"
634                       << "      Delete=" << nDeleteSuccess << '/' << nDeleteFailed << "\n\t"
635             );
636         }
637
638         template <class Set>
639         void do_test_extract_with( Set& testSet )
640         {
641             typedef InsertThread<Set> insert_thread;
642             typedef DeleteThread<Set> delete_thread;
643             typedef ExtractThread< typename Set::gc, Set > extract_thread;
644
645             m_nInsThreadCount.store( c_nInsThreadCount, atomics::memory_order_release );
646
647             CppUnitMini::ThreadPool pool( *this );
648             pool.add( new insert_thread( pool, testSet ), c_nInsThreadCount );
649             if ( c_nDelThreadCount )
650                 pool.add( new delete_thread( pool, testSet ), c_nDelThreadCount );
651             if ( c_nExtractThreadCount )
652                 pool.add( new extract_thread( pool, testSet ), c_nExtractThreadCount );
653             pool.run();
654             CPPUNIT_MSG( "   Duration=" << pool.avgDuration() );
655
656             size_t nInsertSuccess = 0;
657             size_t nInsertFailed = 0;
658             size_t nDeleteSuccess = 0;
659             size_t nDeleteFailed = 0;
660             size_t nExtractSuccess = 0;
661             size_t nExtractFailed = 0;
662             for ( CppUnitMini::ThreadPool::iterator it = pool.begin(); it != pool.end(); ++it ) {
663                 insert_thread * pThread = dynamic_cast<insert_thread *>( *it );
664                 if ( pThread ) {
665                     nInsertSuccess += pThread->m_nInsertSuccess;
666                     nInsertFailed += pThread->m_nInsertFailed;
667                 }
668                 else {
669                     delete_thread * p = dynamic_cast<delete_thread *>( *it );
670                     if ( p ) {
671                         nDeleteSuccess += p->m_nDeleteSuccess;
672                         nDeleteFailed += p->m_nDeleteFailed;
673                     }
674                     else {
675                         extract_thread * pExt = dynamic_cast<extract_thread *>( *it );
676                         assert( pExt );
677                         nExtractSuccess += pExt->m_nExtractSuccess;
678                         nExtractFailed += pExt->m_nExtractFailed;
679                     }
680                 }
681             }
682
683             CPPUNIT_CHECK( nInsertSuccess == c_nSetSize * c_nInsThreadCount );
684             CPPUNIT_CHECK( nInsertFailed == 0 );
685
686             CPPUNIT_MSG( "  Totals (success/failed): \n\t"
687                 << "      Insert=" << nInsertSuccess << '/' << nInsertFailed << "\n\t"
688                 << "      Delete=" << nDeleteSuccess << '/' << nDeleteFailed << "\n\t"
689                 << "      Extract=" << nExtractSuccess << '/' << nExtractFailed << "\n\t"
690                 );
691         }
692
693         template <typename Set>
694         void analyze( Set& testSet )
695         {
696             // All even keys must be in the set
697             {
698                 CPPUNIT_MSG( "  Check even keys..." );
699                 size_t nErrorCount = 0;
700                 for ( size_t n = 0; n < c_nSetSize; n +=2 ) {
701                     for ( size_t i = 0; i < c_nInsThreadCount; ++i ) {
702                         if ( !testSet.contains( key_type(n, i) ) ) {
703                             if ( ++nErrorCount < 10 ) {
704                                 CPPUNIT_MSG( "key " << n << "-" << i << " is not found!");
705                             }
706                         }
707                     }
708                 }
709                 CPPUNIT_CHECK_EX( nErrorCount == 0, "Totals: " << nErrorCount << " keys is not found");
710             }
711
712             check_before_clear( testSet );
713
714             CPPUNIT_MSG( "  Clear map (single-threaded)..." );
715             cds::OS::Timer    timer;
716             testSet.clear();
717             CPPUNIT_MSG( "   Duration=" << timer.duration() );
718             CPPUNIT_CHECK_EX( testSet.empty(), ((long long) testSet.size()) );
719
720             additional_check( testSet );
721             print_stat( testSet );
722             additional_cleanup( testSet );
723         }
724
725         template <class Set>
726         void run_test()
727         {
728             static_assert( !Set::c_bExtractSupported, "Set class must not support extract() method" );
729
730             CPPUNIT_MSG( "Insert thread count=" << c_nInsThreadCount
731                 << " delete thread count=" << c_nDelThreadCount
732                 << " set size=" << c_nSetSize
733                 );
734
735             if ( Set::c_bLoadFactorDepended ) {
736                 for ( c_nLoadFactor = 1; c_nLoadFactor <= c_nMaxLoadFactor; c_nLoadFactor *= 2 ) {
737                     CPPUNIT_MSG( "Load factor=" << c_nLoadFactor );
738
739                     Set  testSet( *this );
740                     do_test_with( testSet );
741                     analyze( testSet );
742
743                     if ( c_bPrintGCState )
744                         print_gc_state();
745                 }
746             }
747             else {
748                 Set  testSet( *this );
749                 do_test_with( testSet );
750                 analyze( testSet );
751
752                 if ( c_bPrintGCState )
753                     print_gc_state();
754             }
755         }
756
757         template <class Set>
758         void run_test_extract()
759         {
760             static_assert( Set::c_bExtractSupported, "Set class must support extract() method" );
761
762             CPPUNIT_MSG( "Insert thread count=" << c_nInsThreadCount
763                 << " delete thread count=" << c_nDelThreadCount
764                 << " extract thread count=" << c_nExtractThreadCount
765                 << " set size=" << c_nSetSize
766                 );
767
768             if ( Set::c_bLoadFactorDepended ) {
769                 for ( c_nLoadFactor = 1; c_nLoadFactor <= c_nMaxLoadFactor; c_nLoadFactor *= 2 ) {
770                     CPPUNIT_MSG( "Load factor=" << c_nLoadFactor );
771
772                     Set  testSet( *this );
773                     do_test_extract_with( testSet );
774                     analyze( testSet );
775
776                     if ( c_bPrintGCState )
777                         print_gc_state();
778                 }
779             }
780             else {
781                 Set  testSet( *this );
782                 do_test_extract_with( testSet );
783                 analyze( testSet );
784
785                 if ( c_bPrintGCState )
786                     print_gc_state();
787             }
788         }
789
790         void setUpParams( const CppUnitMini::TestCfg& cfg );
791
792 #   include "set2/set_defs.h"
793         CDSUNIT_DECLARE_MichaelSet
794         CDSUNIT_DECLARE_SplitList
795         CDSUNIT_DECLARE_SkipListSet
796         CDSUNIT_DECLARE_EllenBinTreeSet
797         CDSUNIT_DECLARE_CuckooSet
798         CDSUNIT_DECLARE_FeldmanHashSet_fixed
799         CDSUNIT_DECLARE_FeldmanHashSet_city
800
801         CPPUNIT_TEST_SUITE_(Set_DelOdd, "Map_DelOdd")
802             CDSUNIT_TEST_MichaelSet
803             CDSUNIT_TEST_SplitList
804             CDSUNIT_TEST_SkipListSet
805             CDSUNIT_TEST_EllenBinTreeSet
806             CDSUNIT_TEST_FeldmanHashSet_fixed
807             CDSUNIT_TEST_FeldmanHashSet_city
808             CDSUNIT_TEST_CuckooSet
809         CPPUNIT_TEST_SUITE_END();
810     };
811 } // namespace set2