Move libcds 1.6.0 from SVN
[libcds.git] / tests / test-hdr / map / hdr_striped_map.h
1 //$$CDS-header$$
2
3 #ifndef __CDSTEST_HDR_STRIPED_MAP_H
4 #define __CDSTEST_HDR_STRIPED_MAP_H
5 #include "size_check.h"
6
7 #include "cppunit/cppunit_proxy.h"
8 #include <cds/os/timer.h>
9 #include <cds/opt/hash.h>
10 #include <cds/ref.h>
11 #include <algorithm>    // random_shuffle
12
13 namespace cds { namespace container {}}
14
15 namespace map {
16     using misc::check_size;
17
18     namespace cc = cds::container;
19     namespace co = cds::opt;
20
21     class StripedMapHdrTest: public CppUnitMini::TestCase
22     {
23     public:
24         typedef int key_type;
25
26         struct value_type {
27             int m_val;
28
29             value_type()
30                 : m_val(0)
31             {}
32
33             value_type( int n )
34                 : m_val( n )
35             {}
36
37 #ifdef CDS_MOVE_SEMANTICS_SUPPORT
38             value_type( value_type&& v )
39                 : m_val( v.m_val )
40             {}
41
42             value_type( value_type const& v )
43                 : m_val( v.m_val )
44             {}
45
46             value_type& operator=( value_type const& v )
47             {
48                 m_val = v.m_val;
49                 return *this;
50             }
51 #endif
52         };
53
54         typedef std::pair<key_type const, value_type> pair_type;
55
56         struct less
57         {
58             bool operator ()(int v1, int v2 ) const
59             {
60                 return v1 < v2;
61             }
62         };
63
64         struct cmp {
65             int operator ()(int v1, int v2 ) const
66             {
67                 if ( v1 < v2 )
68                     return -1;
69                 return v1 > v2 ? 1 : 0;
70             }
71         };
72
73         struct equal {
74             bool operator ()(int v1, int v2 ) const
75             {
76                 return v1 == v2;
77             }
78         };
79
80         struct hash_int {
81             size_t operator()( int i ) const
82             {
83                 return co::v::hash<int>()( i );
84             }
85         };
86
87         struct simple_item_counter {
88             size_t  m_nCount;
89
90             simple_item_counter()
91                 : m_nCount(0)
92             {}
93
94             size_t operator ++()
95             {
96                 return ++m_nCount;
97             }
98
99             size_t operator --()
100             {
101                 return --m_nCount;
102             }
103
104             void reset()
105             {
106                 m_nCount = 0;
107             }
108
109             operator size_t() const
110             {
111                 return m_nCount;
112             }
113         };
114
115         template <typename Map>
116         struct insert_functor
117         {
118             typedef typename Map::value_type pair_type;
119
120             // insert ftor
121             void operator()( pair_type& item )
122             {
123                 item.second.m_val = item.first * 3;
124             }
125
126             // ensure ftor
127             void operator()( bool bNew, pair_type& item )
128             {
129                 if ( bNew )
130                     item.second.m_val = item.first * 2;
131                 else
132                     item.second.m_val = item.first * 5;
133             }
134         };
135
136         struct check_value {
137             int     m_nExpected;
138
139             check_value( int nExpected )
140                 : m_nExpected( nExpected )
141             {}
142
143             template <typename T>
144             void operator ()( T& pair )
145             {
146                 CPPUNIT_ASSERT_CURRENT( pair.second.m_val == m_nExpected );
147             }
148             template <typename T, typename Q>
149             void operator ()( T& pair, Q )
150             {
151                 CPPUNIT_ASSERT_CURRENT( pair.second.m_val == m_nExpected );
152             }
153         };
154
155         struct extract_functor
156         {
157             int *   m_pVal;
158             void operator()( pair_type const& val )
159             {
160                 *m_pVal = val.second.m_val;
161             }
162         };
163
164         template <class Map>
165         void test_int_with( Map& m )
166         {
167             std::pair<bool, bool> ensureResult;
168
169             // insert
170             CPPUNIT_ASSERT( m.empty() );
171             CPPUNIT_ASSERT( check_size( m, 0 ));
172             CPPUNIT_ASSERT( !m.find(25) );
173             CPPUNIT_ASSERT( m.insert( 25 ) )    ;   // value = 0
174             CPPUNIT_ASSERT( m.find(25) );
175             CPPUNIT_ASSERT( !m.empty() );
176             CPPUNIT_ASSERT( check_size( m, 1 ));
177             CPPUNIT_ASSERT( m.find(25) );
178
179             CPPUNIT_ASSERT( !m.insert( 25 ) );
180             CPPUNIT_ASSERT( !m.empty() );
181             CPPUNIT_ASSERT( check_size( m, 1 ));
182
183             CPPUNIT_ASSERT( !m.find(10) );
184             CPPUNIT_ASSERT( m.insert( 10, 10 ) );
185             CPPUNIT_ASSERT( !m.empty() );
186             CPPUNIT_ASSERT( check_size( m, 2 ));
187             CPPUNIT_ASSERT( m.find(10) );
188
189             CPPUNIT_ASSERT( !m.insert( 10, 20 ) );
190             CPPUNIT_ASSERT( !m.empty() );
191             CPPUNIT_ASSERT( check_size( m, 2 ));
192
193             CPPUNIT_ASSERT( !m.find(30) );
194             CPPUNIT_ASSERT( m.insert_key( 30, insert_functor<Map>() ) )    ; // value = 90
195             CPPUNIT_ASSERT( !m.empty() );
196             CPPUNIT_ASSERT( check_size( m, 3 ));
197             CPPUNIT_ASSERT( m.find(30) );
198
199             CPPUNIT_ASSERT( !m.insert_key( 10, insert_functor<Map>() ) );
200             CPPUNIT_ASSERT( !m.insert_key( 25, insert_functor<Map>() ) );
201             CPPUNIT_ASSERT( !m.insert_key( 30, insert_functor<Map>() ) );
202
203             // ensure (new key)
204             CPPUNIT_ASSERT( !m.find(27) );
205             ensureResult = m.ensure( 27, insert_functor<Map>() ) ;   // value = 54
206             CPPUNIT_ASSERT( ensureResult.first );
207             CPPUNIT_ASSERT( ensureResult.second );
208             CPPUNIT_ASSERT( check_size( m, 4 ));
209             CPPUNIT_ASSERT( m.find(27) );
210
211             // find test
212             check_value chk(10);
213             CPPUNIT_ASSERT( m.find( 10, cds::ref(chk) ));
214             chk.m_nExpected = 0;
215             CPPUNIT_ASSERT( m.find( 25, boost::ref(chk) ));
216             chk.m_nExpected = 90;
217             CPPUNIT_ASSERT( m.find( 30, boost::ref(chk) ));
218             chk.m_nExpected = 54;
219             CPPUNIT_ASSERT( m.find( 27, boost::ref(chk) ));
220
221             ensureResult = m.ensure( 10, insert_functor<Map>() ) ;   // value = 50
222             CPPUNIT_ASSERT( ensureResult.first );
223             CPPUNIT_ASSERT( !ensureResult.second );
224             chk.m_nExpected = 50;
225             CPPUNIT_ASSERT( m.find( 10, boost::ref(chk) ));
226
227             // erase test
228             CPPUNIT_ASSERT( !m.find(100) );
229             CPPUNIT_ASSERT( !m.erase( 100 )) ;  // not found
230
231             CPPUNIT_ASSERT( m.find(25) );
232             CPPUNIT_ASSERT( check_size( m, 4 ));
233             CPPUNIT_ASSERT( m.erase( 25 ));
234             CPPUNIT_ASSERT( !m.empty() );
235             CPPUNIT_ASSERT( check_size( m, 3 ));
236             CPPUNIT_ASSERT( !m.find(25) );
237             CPPUNIT_ASSERT( !m.erase( 25 ));
238
239             CPPUNIT_ASSERT( !m.find(258) );
240             CPPUNIT_ASSERT( m.insert(258))
241             CPPUNIT_ASSERT( check_size( m, 4 ));
242             CPPUNIT_ASSERT( m.find(258) );
243             CPPUNIT_ASSERT( m.erase( 258 ));
244             CPPUNIT_ASSERT( !m.empty() );
245             CPPUNIT_ASSERT( check_size( m, 3 ));
246             CPPUNIT_ASSERT( !m.find(258) );
247             CPPUNIT_ASSERT( !m.erase( 258 ));
248
249             int nVal;
250             extract_functor ext;
251             ext.m_pVal = &nVal;
252
253             CPPUNIT_ASSERT( !m.find(29) );
254             CPPUNIT_ASSERT( m.insert(29, 290));
255             CPPUNIT_ASSERT( check_size( m, 4 ));
256             CPPUNIT_ASSERT( m.erase( 29, boost::ref(ext)));
257             CPPUNIT_ASSERT( !m.empty() );
258             CPPUNIT_ASSERT( check_size( m, 3 ));
259             CPPUNIT_ASSERT( nVal == 290 );
260             nVal = -1;
261             CPPUNIT_ASSERT( !m.erase( 29, boost::ref(ext)));
262             CPPUNIT_ASSERT( nVal == -1 );
263
264             CPPUNIT_ASSERT( m.erase( 30, boost::ref(ext)));
265             CPPUNIT_ASSERT( !m.empty() );
266             CPPUNIT_ASSERT( check_size( m, 2 ));
267             CPPUNIT_ASSERT( nVal == 90 );
268             nVal = -1;
269             CPPUNIT_ASSERT( !m.erase( 30, boost::ref(ext)));
270             CPPUNIT_ASSERT( nVal == -1 );
271
272             m.clear();
273             CPPUNIT_ASSERT( m.empty() );
274             CPPUNIT_ASSERT( check_size( m, 0 ));
275
276 #       ifdef CDS_EMPLACE_SUPPORT
277             // emplace test
278             CPPUNIT_ASSERT( m.emplace(126) ) ; // key = 126, val = 0
279             CPPUNIT_ASSERT( m.emplace(137, 731))    ;   // key = 137, val = 731
280             CPPUNIT_ASSERT( m.emplace( 149, value_type(941) ))   ;   // key = 149, val = 941
281
282             CPPUNIT_ASSERT( !m.empty() );
283             CPPUNIT_ASSERT( check_size( m, 3 ));
284
285             chk.m_nExpected = 0;
286             CPPUNIT_ASSERT( m.find( 126, cds::ref(chk) ));
287             chk.m_nExpected = 731;
288             CPPUNIT_ASSERT( m.find( 137, cds::ref(chk) ));
289             chk.m_nExpected = 941;
290             CPPUNIT_ASSERT( m.find( 149, cds::ref(chk) ));
291
292             CPPUNIT_ASSERT( !m.emplace(126, 621)) ; // already in map
293             chk.m_nExpected = 0;
294             CPPUNIT_ASSERT( m.find( 126, cds::ref(chk) ));
295             CPPUNIT_ASSERT( !m.empty() );
296             CPPUNIT_ASSERT( check_size( m, 3 ));
297
298             m.clear();
299             CPPUNIT_ASSERT( m.empty() );
300             CPPUNIT_ASSERT( check_size( m, 0 ));
301
302 #       endif
303         }
304
305         template <class Map>
306         void test_iter( Map& s)
307         {
308             typedef typename Map::iterator          iterator;
309             typedef typename Map::const_iterator    const_iterator;
310
311             const int nMaxCount = 500;
312             for ( int i = 0; i < nMaxCount; ++i ) {
313                 CPPUNIT_ASSERT( s.insert( i, i * 2 ));
314             }
315
316             int nCount = 0;
317             for ( iterator it = s.begin(), itEnd = s.end(); it != itEnd; ++it ) {
318                 CPPUNIT_ASSERT( it->first * 2 == it->second.m_val );
319                 CPPUNIT_ASSERT( (*it).first * 2 == (*it).second.m_val );
320                 it->second.m_val = it->first;
321                 ++nCount;
322             }
323             CPPUNIT_ASSERT( nCount == nMaxCount );
324
325             Map const& refSet = s;
326             nCount = 0;
327             for ( const_iterator it = refSet.begin(), itEnd = refSet.end(); it != itEnd; ++it ) {
328                 CPPUNIT_ASSERT( it->first == it->second.m_val );
329                 CPPUNIT_ASSERT( (*it).first == (*it).second.m_val );
330                 ++nCount;
331             }
332             CPPUNIT_ASSERT( nCount == nMaxCount );
333         }
334
335         template <class Map>
336         void test_striped()
337         {
338             Map m( 30 );
339             CPPUNIT_ASSERT( m.bucket_count() == 32 );
340             CPPUNIT_ASSERT( m.lock_count() == 32 );
341
342             test_striped_with(m);
343         }
344
345         template <class Map>
346         void test_striped_with(Map& m)
347         {
348             cds::OS::Timer    timer;
349
350             test_int_with( m );
351
352             // Iterators is not yet supported
353             //m.clear();
354             //CPPUNIT_ASSERT( m.empty() );
355             //CPPUNIT_ASSERT( check_size( m, 0 ));
356             //test_iter(m);
357
358             m.clear();
359             CPPUNIT_ASSERT( m.empty() );
360             CPPUNIT_ASSERT( check_size( m, 0 ));
361
362             // Resizing test
363             for ( int i = 0; i < 40000; i++ ) {
364                 m.insert( i );
365             }
366
367             CPPUNIT_MSG( "   Duration=" << timer.duration() );
368         }
369
370         //*******************************************
371         // If erase_with && find_with are supported
372         template <class Map>
373         void test_int_with2( Map& m )
374         {
375             std::pair<bool, bool> ensureResult;
376
377             // insert
378             CPPUNIT_ASSERT( m.empty() );
379             CPPUNIT_ASSERT( check_size( m, 0 ));
380             CPPUNIT_ASSERT( !m.find(25) );
381             CPPUNIT_ASSERT( m.insert( 25 ) )    ;   // value = 0
382             CPPUNIT_ASSERT( m.find(25) );
383             CPPUNIT_ASSERT( !m.empty() );
384             CPPUNIT_ASSERT( check_size( m, 1 ));
385             CPPUNIT_ASSERT( m.find(25) );
386
387             CPPUNIT_ASSERT( !m.insert( 25 ) );
388             CPPUNIT_ASSERT( !m.empty() );
389             CPPUNIT_ASSERT( check_size( m, 1 ));
390
391             CPPUNIT_ASSERT( !m.find_with(10, less()) );
392             CPPUNIT_ASSERT( m.insert( 10, 10 ) );
393             CPPUNIT_ASSERT( !m.empty() );
394             CPPUNIT_ASSERT( check_size( m, 2 ));
395             CPPUNIT_ASSERT( m.find_with(10, less()) );
396
397             CPPUNIT_ASSERT( !m.insert( 10, 20 ) );
398             CPPUNIT_ASSERT( !m.empty() );
399             CPPUNIT_ASSERT( check_size( m, 2 ));
400
401             CPPUNIT_ASSERT( !m.find(30) );
402             CPPUNIT_ASSERT( m.insert_key( 30, insert_functor<Map>() ) )    ; // value = 90
403             CPPUNIT_ASSERT( !m.empty() );
404             CPPUNIT_ASSERT( check_size( m, 3 ));
405             CPPUNIT_ASSERT( m.find(30) );
406
407             CPPUNIT_ASSERT( !m.insert_key( 10, insert_functor<Map>() ) );
408             CPPUNIT_ASSERT( !m.insert_key( 25, insert_functor<Map>() ) );
409             CPPUNIT_ASSERT( !m.insert_key( 30, insert_functor<Map>() ) );
410
411             // ensure (new key)
412             CPPUNIT_ASSERT( !m.find(27) );
413             ensureResult = m.ensure( 27, insert_functor<Map>() ) ;   // value = 54
414             CPPUNIT_ASSERT( ensureResult.first );
415             CPPUNIT_ASSERT( ensureResult.second );
416             CPPUNIT_ASSERT( m.find(27) );
417
418             // find test
419             check_value chk(10);
420             CPPUNIT_ASSERT( m.find( 10, cds::ref(chk) ));
421             chk.m_nExpected = 0;
422             CPPUNIT_ASSERT( m.find_with( 25, less(), boost::ref(chk) ));
423             chk.m_nExpected = 90;
424             CPPUNIT_ASSERT( m.find( 30, boost::ref(chk) ));
425             chk.m_nExpected = 54;
426             CPPUNIT_ASSERT( m.find( 27, boost::ref(chk) ));
427
428             ensureResult = m.ensure( 10, insert_functor<Map>() ) ;   // value = 50
429             CPPUNIT_ASSERT( ensureResult.first );
430             CPPUNIT_ASSERT( !ensureResult.second );
431             chk.m_nExpected = 50;
432             CPPUNIT_ASSERT( m.find( 10, boost::ref(chk) ));
433
434             // erase test
435             CPPUNIT_ASSERT( !m.find(100) );
436             CPPUNIT_ASSERT( !m.erase( 100 )) ;  // not found
437
438             CPPUNIT_ASSERT( m.find(25) );
439             CPPUNIT_ASSERT( check_size( m, 4 ));
440             CPPUNIT_ASSERT( m.erase( 25 ));
441             CPPUNIT_ASSERT( !m.empty() );
442             CPPUNIT_ASSERT( check_size( m, 3 ));
443             CPPUNIT_ASSERT( !m.find(25) );
444             CPPUNIT_ASSERT( !m.erase( 25 ));
445
446             CPPUNIT_ASSERT( !m.find(258) );
447             CPPUNIT_ASSERT( m.insert(258))
448             CPPUNIT_ASSERT( check_size( m, 4 ));
449             CPPUNIT_ASSERT( m.find_with(258, less()) );
450             CPPUNIT_ASSERT( m.erase_with( 258, less() ));
451             CPPUNIT_ASSERT( !m.empty() );
452             CPPUNIT_ASSERT( check_size( m, 3 ));
453             CPPUNIT_ASSERT( !m.find(258) );
454             CPPUNIT_ASSERT( !m.erase_with( 258, less() ));
455
456             int nVal;
457             extract_functor ext;
458             ext.m_pVal = &nVal;
459
460             CPPUNIT_ASSERT( !m.find(29) );
461             CPPUNIT_ASSERT( m.insert(29, 290))
462             CPPUNIT_ASSERT( m.erase_with( 29, less(), boost::ref(ext)));
463             CPPUNIT_ASSERT( !m.empty() );
464             CPPUNIT_ASSERT( check_size( m, 3 ));
465             CPPUNIT_ASSERT( nVal == 290 );
466             nVal = -1;
467             CPPUNIT_ASSERT( !m.erase_with( 29, less(), boost::ref(ext)));
468             CPPUNIT_ASSERT( nVal == -1 );
469
470             CPPUNIT_ASSERT( m.erase( 30, boost::ref(ext)));
471             CPPUNIT_ASSERT( !m.empty() );
472             CPPUNIT_ASSERT( check_size( m, 2 ));
473             CPPUNIT_ASSERT( nVal == 90 );
474             nVal = -1;
475             CPPUNIT_ASSERT( !m.erase( 30, boost::ref(ext)));
476             CPPUNIT_ASSERT( nVal == -1 );
477
478             m.clear();
479             CPPUNIT_ASSERT( m.empty() );
480             CPPUNIT_ASSERT( check_size( m, 0 ));
481
482 #       ifdef CDS_EMPLACE_SUPPORT
483             // emplace test
484             CPPUNIT_ASSERT( m.emplace(126) ) ; // key = 126, val = 0
485             CPPUNIT_ASSERT( m.emplace(137, 731))    ;   // key = 137, val = 731
486             CPPUNIT_ASSERT( m.emplace( 149, value_type(941) ))   ;   // key = 149, val = 941
487
488             CPPUNIT_ASSERT( !m.empty() );
489             CPPUNIT_ASSERT( check_size( m, 3 ));
490
491             chk.m_nExpected = 0;
492             CPPUNIT_ASSERT( m.find( 126, cds::ref(chk) ));
493             chk.m_nExpected = 731;
494             CPPUNIT_ASSERT( m.find_with( 137, less(), cds::ref(chk) ));
495             chk.m_nExpected = 941;
496             CPPUNIT_ASSERT( m.find( 149, cds::ref(chk) ));
497
498             CPPUNIT_ASSERT( !m.emplace(126, 621)) ; // already in map
499             chk.m_nExpected = 0;
500             CPPUNIT_ASSERT( m.find( 126, cds::ref(chk) ));
501             CPPUNIT_ASSERT( !m.empty() );
502             CPPUNIT_ASSERT( check_size( m, 3 ));
503
504             m.clear();
505             CPPUNIT_ASSERT( m.empty() );
506             CPPUNIT_ASSERT( check_size( m, 0 ));
507
508 #       endif
509         }
510
511         template <class Map>
512         void test_striped_with2(Map& m)
513         {
514             cds::OS::Timer    timer;
515
516             test_int_with2( m );
517
518             // Iterators is not yet supported
519             //m.clear();
520             //CPPUNIT_ASSERT( m.empty() );
521             //CPPUNIT_ASSERT( check_size( m, 0 ));
522             //test_iter(m);
523
524             m.clear();
525             CPPUNIT_ASSERT( m.empty() );
526             CPPUNIT_ASSERT( check_size( m, 0 ));
527
528             // Resizing test
529             for ( int i = 0; i < 40000; i++ ) {
530                 m.insert( i );
531             }
532
533             CPPUNIT_MSG( "   Duration=" << timer.duration() );
534         }
535
536 #ifndef CDS_CXX11_DEFAULT_FUNCTION_TEMPLATE_ARGS_SUPPORT
537         template <class Map>
538         void test_striped2()
539         {
540             test_striped<Map>();
541         }
542 #else
543         template <class Map>
544         void test_striped2()
545         {
546             Map m( 30 );
547             CPPUNIT_ASSERT( m.bucket_count() == 32 );
548             CPPUNIT_ASSERT( m.lock_count() == 32 );
549
550             test_striped_with2(m);
551         }
552 #endif
553
554         void Striped_hashmap();
555         void Striped_list();
556         void Striped_map();
557         void Striped_slist();
558         void Striped_boost_list();
559         void Striped_boost_flat_map();
560         void Striped_boost_map();
561         void Striped_boost_unordered_map();
562
563         void Refinable_hashmap();
564         void Refinable_list();
565         void Refinable_map();
566         void Refinable_slist();
567         void Refinable_boost_list();
568         void Refinable_boost_flat_map();
569         void Refinable_boost_map();
570         void Refinable_boost_unordered_map();
571
572         CPPUNIT_TEST_SUITE(StripedMapHdrTest)
573             CPPUNIT_TEST(Striped_hashmap)
574             CPPUNIT_TEST(Striped_list)
575             CPPUNIT_TEST(Striped_map)
576             CPPUNIT_TEST(Striped_slist)
577             CPPUNIT_TEST(Striped_boost_list)
578             CPPUNIT_TEST(Striped_boost_flat_map)
579             CPPUNIT_TEST(Striped_boost_map)
580             CPPUNIT_TEST(Striped_boost_unordered_map)
581
582             CPPUNIT_TEST(Refinable_hashmap)
583             CPPUNIT_TEST(Refinable_list)
584             CPPUNIT_TEST(Refinable_map)
585             CPPUNIT_TEST(Refinable_slist)
586             CPPUNIT_TEST(Refinable_boost_list)
587             CPPUNIT_TEST(Refinable_boost_flat_map)
588             CPPUNIT_TEST(Refinable_boost_map)
589             CPPUNIT_TEST(Refinable_boost_unordered_map)
590         CPPUNIT_TEST_SUITE_END()
591
592     };
593 }   // namespace map
594
595 #endif // #ifndef __CDSTEST_HDR_STRIPED_MAP_H