intrusive MultiLevelHashSet:
[libcds.git] / tests / test-hdr / set / hdr_intrusive_multilevel_hashset.h
1 //$$CDS-header$$
2
3 #ifndef CDSTEST_HDR_INTRUSIVE_MULTILEVEL_HASHSET_H
4 #define CDSTEST_HDR_INTRUSIVE_MULTILEVEL_HASHSET_H
5
6 #include "cppunit/cppunit_proxy.h"
7
8 // forward declaration
9 namespace cds { 
10     namespace intrusive {}
11     namespace opt {}
12 }
13
14 namespace set {
15     namespace ci = cds::intrusive;
16     namespace co = cds::opt;
17
18     class IntrusiveMultiLevelHashSetHdrTest: public CppUnitMini::TestCase
19     {
20         template <typename Hash>
21         struct Item 
22         {
23             unsigned int nDisposeCount  ;   // count of disposer calling
24             Hash hash;
25             unsigned int nInsertCall;
26             unsigned int nFindCall;
27             unsigned int nEraseCall;
28
29             Item()
30                 : nDisposeCount(0)
31                 , nInsertCall(0)
32                 , nFindCall(0)
33                 , nEraseCall(0)
34             {}
35         };
36
37         template <typename Hash>
38         struct get_hash
39         {
40             Hash const& operator()( Item<Hash> const& i ) const
41             {
42                 return i.hash;
43             }
44         };
45
46         struct item_disposer {
47             template <typename Hash>
48             void operator()( Item<Hash> * p )
49             {
50                 ++p->nDisposeCount;
51             }
52         };
53
54         template <typename Set>
55         void test_hp()
56         {
57             typedef typename Set::hash_type hash_type;
58             typedef typename Set::value_type value_type;
59
60             std::hash<hash_type> hasher;
61
62             size_t const arrCapacity = 1000;
63             std::vector< value_type > arrValue;
64             arrValue.reserve( arrCapacity );
65             for ( size_t i = 0; i < arrCapacity; ++i ) {
66                 arrValue.emplace_back( value_type() );
67                 arrValue.back().hash = hasher( i );
68             }
69             CPPUNIT_ASSERT( arrValue.size() == arrCapacity );
70
71             Set s( 4, 2 );
72             CPPUNIT_ASSERT(s.head_size() == 16 );
73             CPPUNIT_ASSERT(s.array_node_size() == 4 );
74
75             // insert() test
76             CPPUNIT_ASSERT(s.size() == 0 );
77             CPPUNIT_ASSERT(s.empty() );
78             for ( auto& el : arrValue ) {
79                 CPPUNIT_ASSERT( s.insert( el ));
80                 CPPUNIT_ASSERT(s.contains( el.hash ));
81             }
82             CPPUNIT_ASSERT(s.size() == arrCapacity );
83             for ( auto& el : arrValue ) {
84                 CPPUNIT_ASSERT(s.contains( el.hash ));
85                 CPPUNIT_ASSERT( !s.insert( el ) );
86             }
87             CPPUNIT_ASSERT(s.size() == arrCapacity );
88             CPPUNIT_ASSERT( !s.empty() );
89
90             // update() exists test
91             for ( auto& el : arrValue ) {
92                 bool bOp, bInsert;
93                 std::tie(bOp, bInsert) = s.update( el, false );
94                 CPPUNIT_ASSERT( bOp );
95                 CPPUNIT_ASSERT( !bInsert );
96                 CPPUNIT_ASSERT( el.nFindCall == 0 );
97                 CPPUNIT_ASSERT(s.find(el.hash, [](value_type& v) { v.nFindCall++; } ));
98                 CPPUNIT_ASSERT( el.nFindCall == 1 );
99             }
100
101             // unlink test
102             CPPUNIT_ASSERT(s.size() == arrCapacity );
103             for ( auto const& el : arrValue ) {
104                 CPPUNIT_ASSERT(s.unlink( el ));
105                 CPPUNIT_ASSERT(!s.contains( el.hash ));
106             }
107             CPPUNIT_ASSERT(s.size() == 0 );
108             Set::gc::force_dispose();
109             for ( auto const& el : arrValue ) {
110                 CPPUNIT_ASSERT( el.nDisposeCount == 1 );
111             }
112
113             // new hash values
114             for ( auto& el : arrValue )
115                 el.hash = hasher( el.hash );
116
117             // insert( func )
118             CPPUNIT_ASSERT(s.size() == 0 );
119             for ( auto& el : arrValue ) {
120                 CPPUNIT_ASSERT( s.insert( el, []( value_type& v ) { ++v.nInsertCall; } ));
121                 CPPUNIT_ASSERT(s.contains( el.hash ));
122                 CPPUNIT_ASSERT( el.nInsertCall == 1 );
123             }
124             CPPUNIT_ASSERT(s.size() == arrCapacity );
125             for ( auto& el : arrValue ) {
126                 CPPUNIT_ASSERT(s.contains( el.hash ));
127                 CPPUNIT_ASSERT( !s.insert( el ) );
128             }
129             CPPUNIT_ASSERT(s.size() == arrCapacity );
130             CPPUNIT_ASSERT( !s.empty() );
131
132             for ( auto& el : arrValue )
133                 el.nDisposeCount = 0;
134
135             s.clear();
136             CPPUNIT_ASSERT(s.size() == 0 );
137             Set::gc::force_dispose();
138             for ( auto const& el : arrValue ) {
139                 CPPUNIT_ASSERT( el.nDisposeCount == 1 );
140             }
141
142             // new hash values
143             for ( auto& el : arrValue )
144                 el.hash = hasher( el.hash );
145
146             // update test
147             for ( auto& el : arrValue ) {
148                 bool bOp, bInsert;
149                 std::tie(bOp, bInsert) = s.update( el, false );
150                 CPPUNIT_ASSERT( !bOp );
151                 CPPUNIT_ASSERT( !bInsert );
152                 CPPUNIT_ASSERT( !s.contains( el.hash ));
153
154                 std::tie(bOp, bInsert) = s.update( el, true );
155                 CPPUNIT_ASSERT( bOp );
156                 CPPUNIT_ASSERT( bInsert );
157                 CPPUNIT_ASSERT( s.contains( el.hash ));
158             }
159             CPPUNIT_ASSERT(s.size() == arrCapacity );
160
161             // erase test
162             for ( auto& el : arrValue ) {
163                 el.nDisposeCount = 0;
164                 CPPUNIT_ASSERT( s.contains( el.hash ));
165                 CPPUNIT_ASSERT(s.erase( el.hash ));
166                 CPPUNIT_ASSERT( !s.contains( el.hash ));
167                 CPPUNIT_ASSERT( !s.erase( el.hash ));
168             }
169             CPPUNIT_ASSERT(s.size() == 0 );
170             Set::gc::force_dispose();
171             for ( auto& el : arrValue ) {
172                 CPPUNIT_ASSERT( el.nDisposeCount == 1 );
173                 CPPUNIT_ASSERT(s.insert( el ));
174             }
175
176             // erase with functor, get() test
177             for ( auto& el : arrValue ) {
178                 el.nDisposeCount = 0;
179                 CPPUNIT_ASSERT( s.contains( el.hash ) );
180                 {
181                     typename Set::guarded_ptr gp{ s.get( el.hash ) };
182                     CPPUNIT_ASSERT( gp );
183                     CPPUNIT_ASSERT( gp->nEraseCall == 0);
184                     CPPUNIT_ASSERT(s.erase( gp->hash, []( value_type& i ) { ++i.nEraseCall; } ));
185                     CPPUNIT_ASSERT( gp->nEraseCall == 1);
186                     Set::gc::force_dispose();
187                     CPPUNIT_ASSERT( gp->nDisposeCount == 0 );
188                 }
189                 CPPUNIT_ASSERT( !s.contains( el.hash ));
190                 CPPUNIT_ASSERT( !s.erase( el.hash ));
191                 CPPUNIT_ASSERT( el.nEraseCall == 1 );
192                 Set::gc::force_dispose();
193                 CPPUNIT_ASSERT( el.nDisposeCount == 1 );
194             }
195             CPPUNIT_ASSERT(s.size() == 0 );
196
197             // new hash values
198             for ( auto& el : arrValue ) {
199                 el.hash = hasher( el.hash );
200                 el.nDisposeCount = 0;
201                 bool bOp, bInsert;
202                 std::tie(bOp, bInsert) = s.update( el );
203                 CPPUNIT_ASSERT( bOp );
204                 CPPUNIT_ASSERT( bInsert );
205             }
206             CPPUNIT_ASSERT(s.size() == arrCapacity );
207
208             // extract test
209             for ( auto& el : arrValue ) {
210                 CPPUNIT_ASSERT( s.contains( el.hash ) );
211                 typename Set::guarded_ptr gp = s.extract( el.hash );
212                 CPPUNIT_ASSERT( gp );
213                 Set::gc::force_dispose();
214                 CPPUNIT_ASSERT( el.nDisposeCount == 0 );
215                 CPPUNIT_ASSERT( gp->nDisposeCount == 0 );
216                 gp = s.get( el.hash );
217                 CPPUNIT_ASSERT( !gp );
218                 Set::gc::force_dispose();
219                 CPPUNIT_ASSERT( el.nDisposeCount == 1 );
220                 CPPUNIT_ASSERT( !s.contains( el.hash ) );
221             }
222             CPPUNIT_ASSERT(s.size() == 0 );
223             CPPUNIT_ASSERT(s.empty() );
224
225             CPPUNIT_MSG( s.statistics() );
226         }
227
228         void hp_stdhash();
229         void hp_stdhash_stat();
230
231         CPPUNIT_TEST_SUITE(IntrusiveMultiLevelHashSetHdrTest)
232             CPPUNIT_TEST(hp_stdhash)
233             CPPUNIT_TEST(hp_stdhash_stat)
234         CPPUNIT_TEST_SUITE_END()
235     };
236 } // namespace set
237
238 #endif // #ifndef CDSTEST_HDR_INTRUSIVE_MULTILEVEL_HASHSET_H