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