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