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