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