0f14a6af2e13a16b2ea59ede607fe6eeac8374b1
[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_nLoadFactor = 2;
132         std::vector<size_t>     m_arrData;
133
134     protected:
135         typedef CppUnitMini::TestCase Base;
136         typedef key_thread  key_type;
137         typedef size_t      value_type;
138
139         atomics::atomic<size_t>      m_nInsThreadCount;
140
141         // Inserts keys from [0..N)
142         template <class Set>
143         class InsertThread: public CppUnitMini::TestThread
144         {
145             Set&     m_Set;
146
147             virtual InsertThread *    clone()
148             {
149                 return new InsertThread( *this );
150             }
151
152             struct update_functor
153             {
154                 template <typename Q>
155                 void operator()( bool /*bNew*/, key_value_pair const&, Q const& )
156                 {}
157             };
158         public:
159             size_t  m_nInsertSuccess;
160             size_t  m_nInsertFailed;
161
162         public:
163             InsertThread( CppUnitMini::ThreadPool& pool, Set& rMap )
164                 : CppUnitMini::TestThread( pool )
165                 , m_Set( rMap )
166             {}
167             InsertThread( InsertThread& src )
168                 : CppUnitMini::TestThread( src )
169                 , m_Set( src.m_Set )
170             {}
171
172             Set_DelOdd&  getTest()
173             {
174                 return reinterpret_cast<Set_DelOdd&>( m_Pool.m_Test );
175             }
176
177             virtual void init() { cds::threading::Manager::attachThread()   ; }
178             virtual void fini() { cds::threading::Manager::detachThread()   ; }
179
180             virtual void test()
181             {
182                 Set& rSet = m_Set;
183
184                 m_nInsertSuccess =
185                     m_nInsertFailed = 0;
186
187                 std::vector<size_t>& arrData = getTest().m_arrData;
188                 for ( size_t i = 0; i < arrData.size(); ++i ) {
189                     if ( rSet.insert( key_type( arrData[i], m_nThreadNo )))
190                         ++m_nInsertSuccess;
191                     else
192                         ++m_nInsertFailed;
193                 }
194
195                 update_functor f;
196                 for ( size_t i = arrData.size() - 1; i > 0; --i ) {
197                     if ( arrData[i] & 1 ) {
198                         rSet.update( key_type( arrData[i], m_nThreadNo ), f, true );
199                     }
200                 }
201
202                 getTest().m_nInsThreadCount.fetch_sub( 1, atomics::memory_order_release );
203             }
204         };
205
206         struct key_equal {
207             bool operator()( key_type const& k1, key_type const& k2 ) const
208             {
209                 return k1.nKey == k2.nKey;
210             }
211             bool operator()( size_t k1, key_type const& k2 ) const
212             {
213                 return k1 == k2.nKey;
214             }
215             bool operator()( key_type const& k1, size_t k2 ) const
216             {
217                 return k1.nKey == k2;
218             }
219             bool operator ()( key_value_pair const& k1, key_value_pair const& k2 ) const
220             {
221                 return operator()( k1.key, k2.key );
222             }
223             bool operator ()( key_value_pair const& k1, key_type const& k2 ) const
224             {
225                 return operator()( k1.key, k2 );
226             }
227             bool operator ()( key_type const& k1, key_value_pair const& k2 ) const
228             {
229                 return operator()( k1, k2.key );
230             }
231             bool operator ()( key_value_pair const& k1, size_t k2 ) const
232             {
233                 return operator()( k1.key, k2 );
234             }
235             bool operator ()( size_t k1, key_value_pair const& k2 ) const
236             {
237                 return operator()( k1, k2.key );
238             }
239         };
240
241         struct key_less {
242             bool operator()( key_type const& k1, key_type const& k2 ) const
243             {
244                 return k1.nKey < k2.nKey;
245             }
246             bool operator()( size_t k1, key_type const& k2 ) const
247             {
248                 return k1 < k2.nKey;
249             }
250             bool operator()( key_type const& k1, size_t k2 ) const
251             {
252                 return k1.nKey < k2;
253             }
254             bool operator ()( key_value_pair const& k1, key_value_pair const& k2 ) const
255             {
256                 return operator()( k1.key, k2.key );
257             }
258             bool operator ()( key_value_pair const& k1, key_type const& k2 ) const
259             {
260                 return operator()( k1.key, k2 );
261             }
262             bool operator ()( key_type const& k1, key_value_pair const& k2 ) const
263             {
264                 return operator()( k1, k2.key );
265             }
266             bool operator ()( key_value_pair const& k1, size_t k2 ) const
267             {
268                 return operator()( k1.key, k2 );
269             }
270             bool operator ()( size_t k1, key_value_pair const& k2 ) const
271             {
272                 return operator()( k1, k2.key );
273             }
274
275             typedef key_equal   equal_to;
276         };
277
278         // Deletes odd keys from [0..N)
279         template <class Set>
280         class DeleteThread: public CppUnitMini::TestThread
281         {
282             Set&     m_Set;
283
284             virtual DeleteThread *    clone()
285             {
286                 return new DeleteThread( *this );
287             }
288         public:
289             size_t  m_nDeleteSuccess;
290             size_t  m_nDeleteFailed;
291
292         public:
293             DeleteThread( CppUnitMini::ThreadPool& pool, Set& rMap )
294                 : CppUnitMini::TestThread( pool )
295                 , m_Set( rMap )
296             {}
297             DeleteThread( DeleteThread& src )
298                 : CppUnitMini::TestThread( src )
299                 , m_Set( src.m_Set )
300             {}
301
302             Set_DelOdd&  getTest()
303             {
304                 return reinterpret_cast<Set_DelOdd&>( m_Pool.m_Test );
305             }
306
307             virtual void init() { cds::threading::Manager::attachThread()   ; }
308             virtual void fini() { cds::threading::Manager::detachThread()   ; }
309
310             virtual void test()
311             {
312                 Set& rSet = m_Set;
313
314                 m_nDeleteSuccess =
315                     m_nDeleteFailed = 0;
316
317                 size_t const nInsThreadCount = getTest().c_nInsThreadCount;
318                 std::vector<size_t>& arrData = getTest().m_arrData;
319
320                 if ( m_nThreadNo & 1 ) {
321                     for ( size_t k = 0; k < nInsThreadCount; ++k ) {
322                         for ( size_t i = 0; i < arrData.size(); ++i ) {
323                             if ( arrData[i] & 1 ) {
324                                 if ( rSet.erase_with( arrData[i], key_less() ))
325                                     ++m_nDeleteSuccess;
326                                 else
327                                     ++m_nDeleteFailed;
328                             }
329                         }
330                         if ( getTest().m_nInsThreadCount.load( atomics::memory_order_acquire ) == 0 )
331                             break;
332                     }
333                 }
334                 else {
335                     for ( size_t k = 0; k < nInsThreadCount; ++k ) {
336                         for ( size_t i = arrData.size() - 1; i > 0; --i ) {
337                             if ( arrData[i] & 1 ) {
338                                 if ( rSet.erase_with( arrData[i], key_less() ))
339                                     ++m_nDeleteSuccess;
340                                 else
341                                     ++m_nDeleteFailed;
342                             }
343                         }
344                         if ( getTest().m_nInsThreadCount.load( atomics::memory_order_acquire ) == 0 )
345                             break;
346                     }
347                 }
348             }
349         };
350
351         // Extracts odd keys from [0..N)
352         template <typename GC, class Set>
353         class ExtractThread: public CppUnitMini::TestThread
354         {
355             Set&     m_Set;
356
357             virtual ExtractThread *    clone()
358             {
359                 return new ExtractThread( *this );
360             }
361         public:
362             size_t  m_nExtractSuccess;
363             size_t  m_nExtractFailed;
364
365         public:
366             ExtractThread( CppUnitMini::ThreadPool& pool, Set& rMap )
367                 : CppUnitMini::TestThread( pool )
368                 , m_Set( rMap )
369             {}
370             ExtractThread( ExtractThread& src )
371                 : CppUnitMini::TestThread( src )
372                 , m_Set( src.m_Set )
373             {}
374
375             Set_DelOdd&  getTest()
376             {
377                 return reinterpret_cast<Set_DelOdd&>( m_Pool.m_Test );
378             }
379
380             virtual void init() { cds::threading::Manager::attachThread()   ; }
381             virtual void fini() { cds::threading::Manager::detachThread()   ; }
382
383             virtual void test()
384             {
385                 Set& rSet = m_Set;
386
387                 m_nExtractSuccess =
388                     m_nExtractFailed = 0;
389
390                 typename Set::guarded_ptr gp;
391
392                 std::vector<size_t>& arrData = getTest().m_arrData;
393                 size_t const nInsThreadCount = getTest().c_nInsThreadCount;
394
395                 if ( m_nThreadNo & 1 ) {
396                     for ( size_t k = 0; k < nInsThreadCount; ++k ) {
397                         for ( size_t i = 0; i < arrData.size(); ++i ) {
398                             if ( arrData[i] & 1 ) {
399                                 gp = rSet.extract_with( arrData[i], key_less());
400                                 if ( gp )
401                                     ++m_nExtractSuccess;
402                                 else
403                                     ++m_nExtractFailed;
404                                 gp.release();
405                             }
406                         }
407                         if ( getTest().m_nInsThreadCount.load( atomics::memory_order_acquire ) == 0 )
408                             break;
409                     }
410                 }
411                 else {
412                     for ( size_t k = 0; k < nInsThreadCount; ++k ) {
413                         for ( size_t i = arrData.size() - 1; i > 0; --i ) {
414                             if ( arrData[i] & 1 ) {
415                                 gp = rSet.extract_with( arrData[i], key_less());
416                                 if ( gp )
417                                     ++m_nExtractSuccess;
418                                 else
419                                     ++m_nExtractFailed;
420                                 gp.release();
421                             }
422                         }
423                         if ( getTest().m_nInsThreadCount.load( atomics::memory_order_acquire ) == 0 )
424                             break;
425                     }
426                 }
427             }
428         };
429
430         template <typename RCU, class Set>
431         class ExtractThread< cds::urcu::gc<RCU>, Set >: public CppUnitMini::TestThread
432         {
433             Set&     m_Set;
434
435             virtual ExtractThread *    clone()
436             {
437                 return new ExtractThread( *this );
438             }
439         public:
440             size_t  m_nExtractSuccess;
441             size_t  m_nExtractFailed;
442
443         public:
444             ExtractThread( CppUnitMini::ThreadPool& pool, Set& rMap )
445                 : CppUnitMini::TestThread( pool )
446                 , m_Set( rMap )
447             {}
448             ExtractThread( ExtractThread& src )
449                 : CppUnitMini::TestThread( src )
450                 , m_Set( src.m_Set )
451             {}
452
453             Set_DelOdd&  getTest()
454             {
455                 return reinterpret_cast<Set_DelOdd&>( m_Pool.m_Test );
456             }
457
458             virtual void init() { cds::threading::Manager::attachThread()   ; }
459             virtual void fini() { cds::threading::Manager::detachThread()   ; }
460
461             virtual void test()
462             {
463                 Set& rSet = m_Set;
464
465                 m_nExtractSuccess =
466                     m_nExtractFailed = 0;
467
468                 typename Set::exempt_ptr xp;
469
470                 std::vector<size_t>& arrData = getTest().m_arrData;
471                 size_t const nInsThreadCount = getTest().c_nInsThreadCount;
472
473                 if ( m_nThreadNo & 1 ) {
474                     for ( size_t k = 0; k < nInsThreadCount; ++k ) {
475                         for ( size_t i = 0; i < arrData.size(); ++i ) {
476                             if ( arrData[i] & 1 ) {
477                                 if ( Set::c_bExtractLockExternal ) {
478                                     typename Set::rcu_lock l;
479                                     xp = rSet.extract_with( arrData[i], key_less() );
480                                     if ( xp )
481                                         ++m_nExtractSuccess;
482                                     else
483                                         ++m_nExtractFailed;
484                                 }
485                                 else {
486                                     xp = rSet.extract_with( arrData[i], key_less() );
487                                     if ( xp )
488                                         ++m_nExtractSuccess;
489                                     else
490                                         ++m_nExtractFailed;
491                                 }
492                                 xp.release();
493                             }
494                         }
495                         if ( getTest().m_nInsThreadCount.load( atomics::memory_order_acquire ) == 0 )
496                             break;
497                     }
498                 }
499                 else {
500                     for ( size_t k = 0; k < nInsThreadCount; ++k ) {
501                         for ( size_t i = arrData.size() - 1; i > 0; --i ) {
502                             if ( arrData[i] & 1 ) {
503                                 if ( Set::c_bExtractLockExternal ) {
504                                     typename Set::rcu_lock l;
505                                     xp = rSet.extract_with( arrData[i], key_less() );
506                                     if ( xp )
507                                         ++m_nExtractSuccess;
508                                     else
509                                         ++m_nExtractFailed;
510                                 }
511                                 else {
512                                     xp = rSet.extract_with( arrData[i], key_less() );
513                                     if ( xp )
514                                         ++m_nExtractSuccess;
515                                     else
516                                         ++m_nExtractFailed;
517                                 }
518                                 xp.release();
519                             }
520                         }
521                         if ( getTest().m_nInsThreadCount.load( atomics::memory_order_acquire ) == 0 )
522                             break;
523                     }
524                 }
525             }
526         };
527
528     protected:
529         template <class Set>
530         void do_test( size_t nLoadFactor )
531         {
532             Set  testSet( c_nSetSize, nLoadFactor );
533             do_test_with( testSet );
534             analyze( testSet );
535         }
536
537         template <class Set>
538         void do_test_extract( size_t nLoadFactor )
539         {
540             Set  testSet( c_nSetSize, nLoadFactor );
541             do_test_extract_with( testSet );
542             analyze( testSet );
543         }
544
545         template <class Set>
546         void do_test_with( Set& testSet )
547         {
548             typedef InsertThread<Set> insert_thread;
549             typedef DeleteThread<Set> delete_thread;
550
551             m_nInsThreadCount.store( c_nInsThreadCount, atomics::memory_order_release );
552
553             CppUnitMini::ThreadPool pool( *this );
554             pool.add( new insert_thread( pool, testSet ), c_nInsThreadCount );
555             pool.add( new delete_thread( pool, testSet ), c_nDelThreadCount ? c_nDelThreadCount : cds::OS::topology::processor_count());
556             pool.run();
557             CPPUNIT_MSG( "   Duration=" << pool.avgDuration() );
558
559             size_t nInsertSuccess = 0;
560             size_t nInsertFailed = 0;
561             size_t nDeleteSuccess = 0;
562             size_t nDeleteFailed = 0;
563             for ( CppUnitMini::ThreadPool::iterator it = pool.begin(); it != pool.end(); ++it ) {
564                 insert_thread * pThread = dynamic_cast<insert_thread *>( *it );
565                 if ( pThread ) {
566                     nInsertSuccess += pThread->m_nInsertSuccess;
567                     nInsertFailed += pThread->m_nInsertFailed;
568                 }
569                 else {
570                     delete_thread * p = static_cast<delete_thread *>( *it );
571                     nDeleteSuccess += p->m_nDeleteSuccess;
572                     nDeleteFailed += p->m_nDeleteFailed;
573                 }
574             }
575
576             CPPUNIT_CHECK( nInsertSuccess == c_nSetSize * c_nInsThreadCount );
577             CPPUNIT_CHECK( nInsertFailed == 0 );
578
579             CPPUNIT_MSG( "  Totals (success/failed): \n\t"
580                       << "      Insert=" << nInsertSuccess << '/' << nInsertFailed << "\n\t"
581                       << "      Delete=" << nDeleteSuccess << '/' << nDeleteFailed << "\n\t"
582             );
583         }
584
585         template <class Set>
586         void do_test_extract_with( Set& testSet )
587         {
588             typedef InsertThread<Set> insert_thread;
589             typedef DeleteThread<Set> delete_thread;
590             typedef ExtractThread< typename Set::gc, Set > extract_thread;
591
592             m_nInsThreadCount.store( c_nInsThreadCount, atomics::memory_order_release );
593
594             CppUnitMini::ThreadPool pool( *this );
595             pool.add( new insert_thread( pool, testSet ), c_nInsThreadCount );
596             if ( c_nDelThreadCount )
597                 pool.add( new delete_thread( pool, testSet ), c_nDelThreadCount );
598             if ( c_nExtractThreadCount )
599                 pool.add( new extract_thread( pool, testSet ), c_nExtractThreadCount );
600             pool.run();
601             CPPUNIT_MSG( "   Duration=" << pool.avgDuration() );
602
603             size_t nInsertSuccess = 0;
604             size_t nInsertFailed = 0;
605             size_t nDeleteSuccess = 0;
606             size_t nDeleteFailed = 0;
607             size_t nExtractSuccess = 0;
608             size_t nExtractFailed = 0;
609             for ( CppUnitMini::ThreadPool::iterator it = pool.begin(); it != pool.end(); ++it ) {
610                 insert_thread * pThread = dynamic_cast<insert_thread *>( *it );
611                 if ( pThread ) {
612                     nInsertSuccess += pThread->m_nInsertSuccess;
613                     nInsertFailed += pThread->m_nInsertFailed;
614                 }
615                 else {
616                     delete_thread * p = dynamic_cast<delete_thread *>( *it );
617                     if ( p ) {
618                         nDeleteSuccess += p->m_nDeleteSuccess;
619                         nDeleteFailed += p->m_nDeleteFailed;
620                     }
621                     else {
622                         extract_thread * pExt = dynamic_cast<extract_thread *>( *it );
623                         assert( pExt );
624                         nExtractSuccess += pExt->m_nExtractSuccess;
625                         nExtractFailed += pExt->m_nExtractFailed;
626                     }
627                 }
628             }
629
630             CPPUNIT_CHECK( nInsertSuccess == c_nSetSize * c_nInsThreadCount );
631             CPPUNIT_CHECK( nInsertFailed == 0 );
632
633             CPPUNIT_MSG( "  Totals (success/failed): \n\t"
634                 << "      Insert=" << nInsertSuccess << '/' << nInsertFailed << "\n\t"
635                 << "      Delete=" << nDeleteSuccess << '/' << nDeleteFailed << "\n\t"
636                 << "      Extract=" << nExtractSuccess << '/' << nExtractFailed << "\n\t"
637                 );
638         }
639
640         template <typename Set>
641         void analyze( Set& testSet )
642         {
643             // All even keys must be in the set
644             {
645                 CPPUNIT_MSG( "  Check even keys..." );
646                 size_t nErrorCount = 0;
647                 for ( size_t n = 0; n < c_nSetSize; n +=2 ) {
648                     for ( size_t i = 0; i < c_nInsThreadCount; ++i ) {
649                         if ( !testSet.contains( key_type(n, i) ) ) {
650                             if ( ++nErrorCount < 10 ) {
651                                 CPPUNIT_MSG( "key " << n << "-" << i << " is not found!");
652                             }
653                         }
654                     }
655                 }
656                 CPPUNIT_CHECK_EX( nErrorCount == 0, "Totals: " << nErrorCount << " keys is not found");
657             }
658
659             check_before_clear( testSet );
660
661             CPPUNIT_MSG( "  Clear map (single-threaded)..." );
662             cds::OS::Timer    timer;
663             testSet.clear();
664             CPPUNIT_MSG( "   Duration=" << timer.duration() );
665             CPPUNIT_CHECK_EX( testSet.empty(), ((long long) testSet.size()) );
666
667             additional_check( testSet );
668             print_stat( testSet );
669             additional_cleanup( testSet );
670         }
671
672         template <class Set>
673         void run_test()
674         {
675             static_assert( !Set::c_bExtractSupported, "Set class must not support extract() method" );
676
677             CPPUNIT_MSG( "Insert thread count=" << c_nInsThreadCount
678                 << " delete thread count=" << c_nDelThreadCount
679                 << " set size=" << c_nSetSize
680                 );
681
682             if ( Set::c_bLoadFactorDepended ) {
683                 for ( c_nLoadFactor = 1; c_nLoadFactor <= c_nMaxLoadFactor; c_nLoadFactor *= 2 ) {
684                     CPPUNIT_MSG( "Load factor=" << c_nLoadFactor );
685
686                     Set  testSet( *this );
687                     do_test_with( testSet );
688                     analyze( testSet );
689
690                     if ( c_bPrintGCState )
691                         print_gc_state();
692                 }
693             }
694             else {
695                 Set  testSet( *this );
696                 do_test_with( testSet );
697                 analyze( testSet );
698
699                 if ( c_bPrintGCState )
700                     print_gc_state();
701             }
702         }
703
704         template <class Set>
705         void run_test_extract()
706         {
707             static_assert( Set::c_bExtractSupported, "Set class must support extract() method" );
708
709             CPPUNIT_MSG( "Insert thread count=" << c_nInsThreadCount
710                 << " delete thread count=" << c_nDelThreadCount
711                 << " extract thread count=" << c_nExtractThreadCount
712                 << " set size=" << c_nSetSize
713                 );
714
715             if ( Set::c_bLoadFactorDepended ) {
716                 for ( c_nLoadFactor = 1; c_nLoadFactor <= c_nMaxLoadFactor; c_nLoadFactor *= 2 ) {
717                     CPPUNIT_MSG( "Load factor=" << c_nLoadFactor );
718
719                     Set  testSet( *this );
720                     do_test_extract_with( testSet );
721                     analyze( testSet );
722
723                     if ( c_bPrintGCState )
724                         print_gc_state();
725                 }
726             }
727             else {
728                 Set  testSet( *this );
729                 do_test_extract_with( testSet );
730                 analyze( testSet );
731
732                 if ( c_bPrintGCState )
733                     print_gc_state();
734             }
735         }
736
737         void setUpParams( const CppUnitMini::TestCfg& cfg );
738
739 #   include "set2/set_defs.h"
740         CDSUNIT_DECLARE_MichaelSet
741         CDSUNIT_DECLARE_SplitList
742         CDSUNIT_DECLARE_SkipListSet
743         CDSUNIT_DECLARE_EllenBinTreeSet
744         CDSUNIT_DECLARE_CuckooSet
745
746         CPPUNIT_TEST_SUITE_(Set_DelOdd, "Map_DelOdd")
747             CDSUNIT_TEST_MichaelSet
748             CDSUNIT_TEST_SplitList
749             CDSUNIT_TEST_SkipListSet
750             CDSUNIT_TEST_EllenBinTreeSet
751             CDSUNIT_TEST_CuckooSet
752
753             //CDSUNIT_TEST_MultiLevelHashSet // the test is not suitable
754         CPPUNIT_TEST_SUITE_END();
755     };
756 } // namespace set2