rename michael_kvlist_pth.h to michael_kvlist_dhp.h
[libcds.git] / tests / test-hdr / ordered_list / hdr_intrusive_lazy.h
1 //$$CDS-header$$
2
3 #include "cppunit/cppunit_proxy.h"
4 #include <cds/intrusive/details/lazy_list_base.h>
5
6 namespace ordlist {
7     namespace ci = cds::intrusive;
8     namespace co = cds::opt;
9
10     class IntrusiveLazyListHeaderTest: public CppUnitMini::TestCase
11     {
12     public:
13
14         struct stat {
15             int nDisposeCount;
16             int nEnsureExistsCall;
17             int nEnsureNewCall;
18             int nFindCall;
19             int nEraseCall;
20
21             stat()
22                 : nDisposeCount(0)
23                 , nEnsureExistsCall(0)
24                 , nEnsureNewCall(0)
25                 , nFindCall(0)
26                 , nEraseCall(0)
27             {}
28
29             stat( const stat& s )
30             {
31                 *this = s;
32             }
33
34             stat& operator =(const stat& s)
35             {
36                 memcpy( this, &s, sizeof(s));
37                 return *this;
38             }
39         };
40
41         template <typename GC>
42         struct base_int_item: public ci::lazy_list::node< GC >
43         {
44             int nKey;
45             int nVal;
46
47             mutable stat    s;
48
49             base_int_item()
50             {}
51
52             base_int_item(int key, int val)
53                 : nKey( key )
54                 , nVal(val)
55                 , s()
56             {}
57
58             base_int_item(const base_int_item& v )
59                 : nKey( v.nKey )
60                 , nVal( v.nVal )
61                 , s()
62             {}
63
64             const int& key() const
65             {
66                 return nKey;
67             }
68         };
69
70         template <typename GC>
71         struct member_int_item
72         {
73             int nKey;
74             int nVal;
75
76             ci::lazy_list::node< GC > hMember;
77
78             mutable stat s;
79
80             member_int_item()
81             {}
82
83             member_int_item(int key, int val)
84                 : nKey( key )
85                 , nVal(val)
86                 , s()
87             {}
88
89             member_int_item(const member_int_item& v )
90                 : nKey( v.nKey )
91                 , nVal( v.nVal )
92                 , s()
93             {}
94
95             const int& key() const
96             {
97                 return nKey;
98             }
99         };
100
101         template <typename T>
102         struct less
103         {
104             bool operator ()(const T& v1, const T& v2 ) const
105             {
106                 return v1.key() < v2.key();
107             }
108
109             template <typename Q>
110             bool operator ()(const T& v1, const Q& v2 ) const
111             {
112                 return v1.key() < v2;
113             }
114
115             template <typename Q>
116             bool operator ()(const Q& v1, const T& v2 ) const
117             {
118                 return v1 < v2.key();
119             }
120         };
121
122         template <typename T>
123         struct cmp {
124             int operator ()(const T& v1, const T& v2 ) const
125             {
126                 if ( v1.key() < v2.key() )
127                     return -1;
128                 return v1.key() > v2.key() ? 1 : 0;
129             }
130
131             template <typename Q>
132             int operator ()(const T& v1, const Q& v2 ) const
133             {
134                 if ( v1.key() < v2 )
135                     return -1;
136                 return v1.key() > v2 ? 1 : 0;
137             }
138
139             template <typename Q>
140             int operator ()(const Q& v1, const T& v2 ) const
141             {
142                 if ( v1 < v2.key() )
143                     return -1;
144                 return v1 > v2.key() ? 1 : 0;
145             }
146         };
147
148         struct other_item {
149             int nKey;
150
151             other_item( int n )
152                 : nKey(n)
153             {}
154         };
155
156         struct other_less {
157             template <typename T, typename Q>
158             bool operator()( T const& i1, Q const& i2) const
159             {
160                 return i1.nKey < i2.nKey;
161             }
162         };
163
164         struct faked_disposer
165         {
166             template <typename T>
167             void operator ()( T * p )
168             {
169                 ++p->s.nDisposeCount;
170             }
171         };
172
173         struct ensure_functor
174         {
175             template <typename T>
176             void operator ()(bool bNew, T& item, T& val )
177             {
178                 if ( bNew )
179                     ++item.s.nEnsureNewCall;
180                 else
181                     ++item.s.nEnsureExistsCall;
182             }
183         };
184
185         struct find_functor
186         {
187             template <typename T, typename Q>
188             void operator ()( T& item, Q& val )
189             {
190                 ++item.s.nFindCall;
191             }
192         };
193
194         struct erase_functor
195         {
196             template <typename T>
197             void operator()( T const& item )
198             {
199                 item.s.nEraseCall++;
200             }
201         };
202
203         template <class OrdList>
204         void test_int_common()
205         {
206             typedef typename OrdList::value_type    value_type;
207
208             value_type v1( 10, 50 );
209             value_type v2( 5, 25  );
210             value_type v3( 20, 100 );
211             {
212                 OrdList l;
213                 CPPUNIT_ASSERT( l.empty() );
214
215                 CPPUNIT_ASSERT( l.insert( v1 ))     ;   // true
216                 CPPUNIT_ASSERT( l.find( v1.key() ));
217
218                 CPPUNIT_ASSERT( v1.s.nFindCall == 0 );
219                 CPPUNIT_ASSERT( l.find( v1.key(), find_functor() ));
220                 CPPUNIT_ASSERT( v1.s.nFindCall == 1 );
221
222                 CPPUNIT_ASSERT( !l.find_with( v2.key(), less<value_type>() ));
223                 CPPUNIT_ASSERT( !l.find( v3.key(), find_functor() ));
224                 CPPUNIT_ASSERT( !l.empty() );
225
226                 //CPPUNIT_ASSERT( !l.insert( v1 ))    ;   // assertion "is_empty" is raised
227
228                 {
229                     value_type v( v1 );
230                     CPPUNIT_ASSERT( !l.insert( v )) ;   // false
231                 }
232
233                 std::pair<bool, bool> ret = l.ensure( v2, ensure_functor() );
234                 CPPUNIT_ASSERT( ret.first );
235                 CPPUNIT_ASSERT( ret.second );
236                 CPPUNIT_ASSERT( v2.s.nEnsureNewCall == 1 );
237                 CPPUNIT_ASSERT( v2.s.nEnsureExistsCall == 0 );
238
239                 //CPPUNIT_ASSERT( !l.insert( v2 ))    ;   // assertion "is_empty"
240
241                 CPPUNIT_ASSERT( l.find( v1.key() )) ;   // true
242
243                 CPPUNIT_ASSERT( v1.s.nFindCall == 1 );
244                 CPPUNIT_ASSERT( l.find( v1.key(), find_functor() ));
245                 CPPUNIT_ASSERT( v1.s.nFindCall == 2 );
246
247                 CPPUNIT_ASSERT( l.find( v2.key() ));
248
249                 CPPUNIT_ASSERT( v2.s.nFindCall == 0 );
250                 CPPUNIT_ASSERT( l.find_with( v2.key(), less<value_type>(), find_functor() ));
251                 CPPUNIT_ASSERT( v2.s.nFindCall == 1 );
252
253                 CPPUNIT_ASSERT( !l.find( v3.key() ));
254
255                 {
256                     CPPUNIT_ASSERT( v2.s.nEnsureExistsCall == 0 );
257                     CPPUNIT_ASSERT( v2.s.nEnsureNewCall == 1 );
258
259                     value_type v( v2 );
260                     ret = l.ensure( v, ensure_functor() );
261
262                     CPPUNIT_ASSERT( ret.first );
263                     CPPUNIT_ASSERT( !ret.second );
264                     CPPUNIT_ASSERT( v2.s.nEnsureExistsCall == 1 );
265                     CPPUNIT_ASSERT( v2.s.nEnsureNewCall == 1 );
266                     CPPUNIT_ASSERT( v.s.nEnsureExistsCall == 0 );
267                     CPPUNIT_ASSERT( v.s.nEnsureNewCall == 0 );
268                 }
269
270                 CPPUNIT_ASSERT( !l.empty() );
271
272                 CPPUNIT_ASSERT( l.insert( v3 ))     ;   // true
273                 CPPUNIT_ASSERT( l.find( v3.key() ));
274
275                 CPPUNIT_ASSERT( v3.s.nFindCall == 0 );
276                 CPPUNIT_ASSERT( l.find( v3.key(), find_functor() ));
277                 CPPUNIT_ASSERT( v3.s.nFindCall == 1 );
278
279                 CPPUNIT_ASSERT( l.unlink( v2 ) );
280                 CPPUNIT_ASSERT( l.find( v1.key() )) ;   // true
281                 CPPUNIT_ASSERT( !l.find( v2.key() )) ;   // true
282                 CPPUNIT_ASSERT( l.find( v3.key() )) ;   // true
283                 CPPUNIT_ASSERT( !l.empty() );
284                 CPPUNIT_ASSERT( !l.unlink( v2 ) );
285
286                 {
287                     // v1 key is in the list but v NODE is not in the list
288                     value_type v( v1 );
289                     CPPUNIT_ASSERT( !l.unlink( v ) );
290                 }
291
292                 CPPUNIT_ASSERT( l.unlink( v1 ) );
293                 CPPUNIT_ASSERT( !l.unlink( v1 ) );
294                 CPPUNIT_ASSERT( !l.find( v1.key() ));
295                 CPPUNIT_ASSERT( !l.find( v2.key() ));
296                 CPPUNIT_ASSERT( l.find( v3.key() ));
297                 CPPUNIT_ASSERT( !l.empty() );
298                 CPPUNIT_ASSERT( !l.unlink( v1 ) );
299                 CPPUNIT_ASSERT( !l.unlink( v2 ) );
300
301                 CPPUNIT_ASSERT( l.unlink( v3 ) );
302                 CPPUNIT_ASSERT( !l.find( v1.key() ));
303                 CPPUNIT_ASSERT( !l.find_with( v2.key(), less<value_type>() ));
304                 CPPUNIT_ASSERT( !l.find( v3.key() ));
305                 CPPUNIT_ASSERT( l.empty() );
306                 CPPUNIT_ASSERT( !l.unlink( v1 ) );
307                 CPPUNIT_ASSERT( !l.unlink( v2 ) );
308                 CPPUNIT_ASSERT( !l.unlink( v3 ) );
309
310                 // Apply retired pointer to clean links
311                 OrdList::gc::force_dispose();
312
313                 stat s( v3.s );
314                 ret = l.ensure( v3, ensure_functor() );
315                 CPPUNIT_ASSERT( ret.first );
316                 CPPUNIT_ASSERT( ret.second );
317                 CPPUNIT_ASSERT( v3.s.nEnsureNewCall == s.nEnsureNewCall + 1);
318                 CPPUNIT_ASSERT( v3.s.nEnsureExistsCall == s.nEnsureExistsCall );
319                 CPPUNIT_ASSERT( !l.empty() );
320
321                 s = v2.s;
322                 ret = l.ensure( v2, ensure_functor() );
323                 CPPUNIT_ASSERT( ret.first );
324                 CPPUNIT_ASSERT( ret.second );
325                 CPPUNIT_ASSERT( v2.s.nEnsureNewCall == s.nEnsureNewCall + 1);
326                 CPPUNIT_ASSERT( v2.s.nEnsureExistsCall == s.nEnsureExistsCall );
327                 CPPUNIT_ASSERT( !l.empty() );
328
329                 s = v1.s;
330                 ret = l.ensure( v1, ensure_functor() );
331                 CPPUNIT_ASSERT( ret.first );
332                 CPPUNIT_ASSERT( ret.second );
333                 CPPUNIT_ASSERT( v1.s.nEnsureNewCall == s.nEnsureNewCall + 1);
334                 CPPUNIT_ASSERT( v1.s.nEnsureExistsCall == s.nEnsureExistsCall );
335                 CPPUNIT_ASSERT( !l.empty() );
336
337                 // Erase test
338                 CPPUNIT_ASSERT( l.erase( v1.key()) );
339                 //CPPUNIT_ASSERT( v1.s.nDisposeCount == 0 );
340                 CPPUNIT_ASSERT( !l.empty() );
341
342                 CPPUNIT_ASSERT( v2.s.nEraseCall == 0 );
343                 CPPUNIT_ASSERT( l.erase_with( v2.key(), less<value_type>(), erase_functor()) );
344                 CPPUNIT_ASSERT( v2.s.nEraseCall == 1 );
345                 CPPUNIT_ASSERT( !l.erase_with( v2.key(), less<value_type>()));
346                 CPPUNIT_ASSERT( v2.s.nEraseCall == 1 );
347                 //CPPUNIT_ASSERT( v2.s.nDisposeCount == 0 );
348                 CPPUNIT_ASSERT( !l.empty() );
349
350                 CPPUNIT_ASSERT( !l.erase( v2 ));
351                 CPPUNIT_ASSERT( !l.erase( v1 ));
352                 //CPPUNIT_ASSERT( v2.s.nDisposeCount == 0 );
353                 CPPUNIT_ASSERT( !l.empty() );
354
355                 CPPUNIT_ASSERT( v3.s.nEraseCall == 0 );
356                 CPPUNIT_ASSERT( l.erase( v3, erase_functor() ));
357                 CPPUNIT_ASSERT( v3.s.nEraseCall == 1 );
358                 //CPPUNIT_ASSERT( v3.s.nDisposeCount == 0 );
359                 CPPUNIT_ASSERT( l.empty() );
360
361                 // Apply retired pointer to clean links
362                 OrdList::gc::force_dispose();
363
364                 // Unlink test
365                 CPPUNIT_ASSERT( l.insert( v1 ));
366                 CPPUNIT_ASSERT( l.insert( v3 ));
367                 CPPUNIT_ASSERT( !l.empty() );
368                 CPPUNIT_ASSERT( !l.unlink( v2 ));
369                 CPPUNIT_ASSERT( l.unlink( v1 ));
370                 CPPUNIT_ASSERT( !l.unlink( v1 ));
371                 CPPUNIT_ASSERT( l.unlink( v3 ));
372                 CPPUNIT_ASSERT( !l.unlink( v3 ));
373                 CPPUNIT_ASSERT( l.empty() );
374
375                 // Apply retired pointer
376                 OrdList::gc::force_dispose();
377                 CPPUNIT_ASSERT( v1.s.nDisposeCount == 3 );
378                 CPPUNIT_ASSERT( v2.s.nDisposeCount == 2 );
379                 CPPUNIT_ASSERT( v3.s.nDisposeCount == 3 );
380
381                 // Destructor test (call disposer)
382                 CPPUNIT_ASSERT( l.insert( v1 ));
383                 CPPUNIT_ASSERT( l.insert( v3 ));
384                 CPPUNIT_ASSERT( l.insert( v2 ));
385
386                 // Iterator test
387                 {
388                     typename OrdList::iterator it = l.begin();
389                     CPPUNIT_ASSERT( it != l.end() );
390                     CPPUNIT_ASSERT( it->nKey == v2.nKey );
391                     CPPUNIT_ASSERT( it->nVal == v2.nVal );
392                     CPPUNIT_ASSERT( ++it != l.end() );
393                     CPPUNIT_ASSERT( it->nKey == v1.nKey );
394                     CPPUNIT_ASSERT( it->nVal == v1.nVal );
395                     CPPUNIT_ASSERT( ++it != l.end() );
396                     CPPUNIT_ASSERT( it->nKey == v3.nKey );
397                     CPPUNIT_ASSERT( it->nVal == v3.nVal );
398                     CPPUNIT_ASSERT( ++it == l.end() );
399                 }
400
401                 {
402                     OrdList const & lref = l;
403                     typename OrdList::const_iterator it = lref.begin();
404                     CPPUNIT_ASSERT( it != l.end() );
405                     CPPUNIT_ASSERT( it->nKey == v2.nKey );
406                     CPPUNIT_ASSERT( it->nVal == v2.nVal );
407                     CPPUNIT_ASSERT( ++it != lref.end() );
408                     CPPUNIT_ASSERT( it->nKey == v1.nKey );
409                     CPPUNIT_ASSERT( it->nVal == v1.nVal );
410                     CPPUNIT_ASSERT( ++it != l.end() );
411                     CPPUNIT_ASSERT( it->nKey == v3.nKey );
412                     CPPUNIT_ASSERT( it->nVal == v3.nVal );
413                     CPPUNIT_ASSERT( ++it == l.end() );
414                 }
415             }
416
417             // Apply retired pointer
418             OrdList::gc::force_dispose();
419
420             CPPUNIT_ASSERT( v1.s.nDisposeCount == 4 );
421             CPPUNIT_ASSERT( v2.s.nDisposeCount == 3 );
422             CPPUNIT_ASSERT( v3.s.nDisposeCount == 4 );
423         }
424
425         template <class OrdList>
426         void test_int()
427         {
428             test_int_common<OrdList>();
429
430             OrdList l;
431             typename OrdList::guarded_ptr gp;
432
433             static int const nLimit = 20;
434             typename OrdList::value_type arrItem[nLimit];
435
436
437             {
438                 int a[nLimit];
439                 for (int i = 0; i < nLimit; ++i)
440                     a[i]=i;
441                 std::random_shuffle( a, a + nLimit );
442
443                 for (int i = 0; i < nLimit; ++i) {
444                     arrItem[i].nKey = a[i];
445                     arrItem[i].nVal = a[i] * 2;
446                 }
447
448                 // extract/get
449                 for ( int i = 0; i < nLimit; ++i )
450                     CPPUNIT_ASSERT( l.insert( arrItem[i] ) );
451
452                 for ( int i=0; i < nLimit; ++i ) {
453                     CPPUNIT_ASSERT( l.get( gp, arrItem[i].nKey ));
454                     CPPUNIT_ASSERT( !gp.empty());
455                     CPPUNIT_ASSERT( gp->nKey == arrItem[i].nKey );
456                     CPPUNIT_ASSERT( gp->nVal == arrItem[i].nVal );
457                     gp.release();
458
459                     CPPUNIT_ASSERT( l.extract( gp, arrItem[i].nKey ));
460                     CPPUNIT_ASSERT( !gp.empty());
461                     CPPUNIT_ASSERT( gp->nKey == arrItem[i].nKey );
462                     CPPUNIT_ASSERT( gp->nVal == arrItem[i].nVal );
463                     gp.release();
464
465                     CPPUNIT_ASSERT( !l.get( gp, arrItem[i].nKey ));
466                     CPPUNIT_ASSERT( gp.empty());
467                     CPPUNIT_ASSERT( !l.extract( gp, arrItem[i].nKey ));
468                     CPPUNIT_ASSERT( gp.empty());
469                 }
470                 CPPUNIT_ASSERT( l.empty() );
471                 CPPUNIT_ASSERT( !l.get( gp, nLimit/2 ));
472                 CPPUNIT_ASSERT( gp.empty());
473                 CPPUNIT_ASSERT( !l.extract( gp, nLimit/2 ));
474                 CPPUNIT_ASSERT( gp.empty());
475
476                 // Apply retired pointer
477                 OrdList::gc::force_dispose();
478
479                 // extract_with/get_with
480                 for ( int i = 0; i < nLimit; ++i )
481                     CPPUNIT_ASSERT( l.insert( arrItem[i] ) );
482
483                 for ( int i=0; i < nLimit; ++i ) {
484                     other_item itm( arrItem[i].nKey );
485                     CPPUNIT_ASSERT( l.get_with( gp, itm, other_less() ));
486                     CPPUNIT_ASSERT( !gp.empty());
487                     CPPUNIT_ASSERT( gp->nKey == arrItem[i].nKey );
488                     CPPUNIT_ASSERT( gp->nVal == arrItem[i].nVal );
489                     gp.release();
490
491                     CPPUNIT_ASSERT( l.extract_with( gp, itm, other_less() ));
492                     CPPUNIT_ASSERT( !gp.empty());
493                     CPPUNIT_ASSERT( gp->nKey == arrItem[i].nKey );
494                     CPPUNIT_ASSERT( gp->nVal == arrItem[i].nVal );
495                     gp.release();
496
497                     CPPUNIT_ASSERT( !l.get_with( gp, itm, other_less() ));
498                     CPPUNIT_ASSERT( gp.empty());
499                     CPPUNIT_ASSERT( !l.extract_with( gp, itm, other_less() ));
500                     CPPUNIT_ASSERT( gp.empty());
501                 }
502                 CPPUNIT_ASSERT( l.empty() );
503                 CPPUNIT_ASSERT( !l.get_with( gp, other_item(nLimit/2), other_less() ));
504                 CPPUNIT_ASSERT( gp.empty());
505                 CPPUNIT_ASSERT( !l.extract_with( gp, other_item(nLimit/2), other_less() ));
506                 CPPUNIT_ASSERT( gp.empty());
507
508                 // Apply retired pointer
509                 OrdList::gc::force_dispose();
510
511                 for ( int i=0; i < nLimit; i++ ) {
512                     CPPUNIT_ASSERT( arrItem[i].s.nDisposeCount == 2 );
513                 }
514             }
515         }
516
517         template <class OrdList>
518         void test_rcu_int()
519         {
520             test_int_common<OrdList>();
521
522             OrdList l;
523             static int const nLimit = 20;
524             typename OrdList::value_type arrItem[nLimit];
525
526             typedef typename OrdList::rcu_lock rcu_lock;
527             typedef typename OrdList::value_type value_type;
528             typedef typename OrdList::gc rcu_type;
529
530             {
531                 int a[nLimit];
532                 for (int i = 0; i < nLimit; ++i)
533                     a[i]=i;
534                 std::random_shuffle( a, a + nLimit );
535
536                 for (int i = 0; i < nLimit; ++i) {
537                     arrItem[i].nKey = a[i];
538                     arrItem[i].nVal = a[i] * 2;
539                 }
540
541                 typename OrdList::exempt_ptr ep;
542
543                 // extract/get
544                 for ( int i = 0; i < nLimit; ++i )
545                     CPPUNIT_ASSERT( l.insert( arrItem[i] ) );
546
547                 for ( int i = 0; i < nLimit; ++i ) {
548                     {
549                         rcu_lock lock;
550                         value_type * pGet = l.get( a[i] );
551                         CPPUNIT_ASSERT( pGet != nullptr );
552                         CPPUNIT_CHECK( pGet->nKey == a[i] );
553                         CPPUNIT_CHECK( pGet->nVal == a[i] * 2 );
554
555                         CPPUNIT_ASSERT( l.extract( ep, a[i] ));
556                         CPPUNIT_ASSERT( !ep.empty() );
557                         CPPUNIT_CHECK( ep->nKey == a[i] );
558                         CPPUNIT_CHECK( (*ep).nVal == a[i] * 2 );
559                     }
560                     ep.release();
561                     {
562                         rcu_lock lock;
563                         CPPUNIT_CHECK( l.get( a[i] ) == nullptr );
564                         CPPUNIT_CHECK( !l.extract( ep, a[i] ) );
565                         CPPUNIT_CHECK( ep.empty() );
566                     }
567                 }
568                 CPPUNIT_ASSERT( l.empty() );
569
570                 {
571                     rcu_lock lock;
572                     CPPUNIT_CHECK( l.get( a[0] ) == nullptr );
573                     CPPUNIT_CHECK( !l.extract( ep, a[0] ));
574                     CPPUNIT_CHECK( ep.empty() );
575                 }
576                 // Apply retired pointer
577                 OrdList::gc::force_dispose();
578
579                 // extract_with/get_with
580                 for ( int i = 0; i < nLimit; ++i ) {
581                     CPPUNIT_ASSERT( l.insert( arrItem[i] ) );
582                 }
583
584                 for ( int i = 0; i < nLimit; ++i ) {
585                     other_item itm( a[i] );
586                     {
587                         rcu_lock lock;
588                         value_type * pGet = l.get_with( itm, other_less() );
589                         CPPUNIT_ASSERT( pGet != nullptr );
590                         CPPUNIT_CHECK( pGet->nKey == a[i] );
591                         CPPUNIT_CHECK( pGet->nVal == a[i] * 2 );
592
593                         CPPUNIT_ASSERT( l.extract_with( ep, itm, other_less() ) );
594                         CPPUNIT_ASSERT( !ep.empty() );
595                         CPPUNIT_CHECK( ep->nKey == a[i] );
596                         CPPUNIT_CHECK( ep->nVal == a[i] * 2 );
597                     }
598                     ep.release();
599                     {
600                         rcu_lock lock;
601                         CPPUNIT_CHECK( l.get_with( itm, other_less() ) == nullptr );
602                         CPPUNIT_CHECK( !l.extract_with( ep, itm, other_less() ));
603                         CPPUNIT_CHECK( ep.empty() );
604                     }
605                 }
606                 CPPUNIT_ASSERT( l.empty() );
607
608                 {
609                     rcu_lock lock;
610                     CPPUNIT_CHECK( l.get_with( other_item( 0 ), other_less() ) == nullptr );
611                     CPPUNIT_CHECK( !l.extract_with( ep, other_item(0), other_less() ));
612                     CPPUNIT_CHECK( ep.empty() );
613                 }
614                 // Apply retired pointer
615                 OrdList::gc::force_dispose();
616             }
617         }
618
619         template <class OrdList>
620         void test_nogc_int()
621         {
622             typedef typename OrdList::value_type    value_type;
623             {
624                 value_type v1( 10, 50 );
625                 value_type v2( 5, 25  );
626                 value_type v3( 20, 100 );
627                 {
628                     OrdList l;
629                     CPPUNIT_ASSERT( l.empty() );
630
631                     CPPUNIT_ASSERT( l.insert( v1 ))     ;   // true
632                     CPPUNIT_ASSERT( l.find( v1.key() ) == &v1 );
633
634                     CPPUNIT_ASSERT( v1.s.nFindCall == 0 );
635                     CPPUNIT_ASSERT( l.find( v1.key(), find_functor() ));
636                     CPPUNIT_ASSERT( v1.s.nFindCall == 1 );
637
638                     CPPUNIT_ASSERT( l.find_with( v2.key(), less<value_type>() ) == nullptr );
639                     CPPUNIT_ASSERT( l.find( v3.key() ) == nullptr );
640                     CPPUNIT_ASSERT( !l.empty() );
641
642                     //CPPUNIT_ASSERT( !l.insert( v1 ))    ;   // assertion "is_empty" is raised
643
644                     {
645                         value_type v( v1 );
646                         CPPUNIT_ASSERT( !l.insert( v )) ;   // false
647                     }
648
649                     std::pair<bool, bool> ret = l.ensure( v2, ensure_functor() );
650                     CPPUNIT_ASSERT( ret.first );
651                     CPPUNIT_ASSERT( ret.second );
652                     CPPUNIT_ASSERT( v2.s.nEnsureNewCall == 1 );
653                     CPPUNIT_ASSERT( v2.s.nEnsureExistsCall == 0 );
654
655                     //CPPUNIT_ASSERT( !l.insert( v2 ))    ;   // assertion "is_empty"
656
657                     CPPUNIT_ASSERT( l.find( v1.key() ) == &v1 ) ;   // true
658
659                     CPPUNIT_ASSERT( v1.s.nFindCall == 1 );
660                     CPPUNIT_ASSERT( l.find( v1.key(), find_functor() ));
661                     CPPUNIT_ASSERT( v1.s.nFindCall == 2 );
662
663                     CPPUNIT_ASSERT( l.find_with( v2.key(), less<value_type>() ) == &v2 );
664
665                     CPPUNIT_ASSERT( v2.s.nFindCall == 0 );
666                     CPPUNIT_ASSERT( l.find_with( v2.key(), less<value_type>(), find_functor() ));
667                     CPPUNIT_ASSERT( v2.s.nFindCall == 1 );
668
669                     CPPUNIT_ASSERT( !l.find( v3.key() ));
670
671                     {
672                         value_type v( v2 );
673                         ret = l.ensure( v, ensure_functor() );
674
675                         CPPUNIT_ASSERT( ret.first );
676                         CPPUNIT_ASSERT( !ret.second );
677                         CPPUNIT_ASSERT( v2.s.nEnsureExistsCall == 1 );
678                         CPPUNIT_ASSERT( v.s.nEnsureExistsCall == 0 && v.s.nEnsureNewCall == 0 );
679                     }
680
681                     CPPUNIT_ASSERT( !l.empty() );
682
683                     CPPUNIT_ASSERT( l.insert( v3 ))     ;   // true
684                     CPPUNIT_ASSERT( l.find( v3.key() ) == &v3 );
685
686                     CPPUNIT_ASSERT( v3.s.nFindCall == 0 );
687                     CPPUNIT_ASSERT( l.find( v3.key(), find_functor() ));
688                     CPPUNIT_ASSERT( v3.s.nFindCall == 1 );
689
690                     {
691                         typename OrdList::iterator it = l.begin();
692                         CPPUNIT_ASSERT( it != l.end() );
693                         CPPUNIT_ASSERT( it->nKey == v2.nKey );
694                         CPPUNIT_ASSERT( it->nVal == v2.nVal );
695                         CPPUNIT_ASSERT( ++it != l.end() );
696                         CPPUNIT_ASSERT( it->nKey == v1.nKey );
697                         CPPUNIT_ASSERT( it->nVal == v1.nVal );
698                         CPPUNIT_ASSERT( it++ != l.end() );
699                         CPPUNIT_ASSERT( it->nKey == v3.nKey );
700                         CPPUNIT_ASSERT( it->nVal == v3.nVal );
701                         CPPUNIT_ASSERT( it++ != l.end() );
702                         CPPUNIT_ASSERT( it == l.end() );
703                     }
704
705                     {
706                         OrdList const & lref = l;
707                         typename OrdList::const_iterator it = lref.begin();
708                         CPPUNIT_ASSERT( it != l.end() );
709                         CPPUNIT_ASSERT( it->nKey == v2.nKey );
710                         CPPUNIT_ASSERT( it->nVal == v2.nVal );
711                         CPPUNIT_ASSERT( ++it != lref.end() );
712                         CPPUNIT_ASSERT( it->nKey == v1.nKey );
713                         CPPUNIT_ASSERT( it->nVal == v1.nVal );
714                         CPPUNIT_ASSERT( it++ != l.end() );
715                         CPPUNIT_ASSERT( it->nKey == v3.nKey );
716                         CPPUNIT_ASSERT( it->nVal == v3.nVal );
717                         CPPUNIT_ASSERT( it++ != lref.end() );
718                         CPPUNIT_ASSERT( it == l.end() );
719                     }
720                 }
721
722                 // Disposer called on list destruction
723                 CPPUNIT_ASSERT( v1.s.nDisposeCount == 1 );
724                 CPPUNIT_ASSERT( v2.s.nDisposeCount == 1 );
725                 CPPUNIT_ASSERT( v3.s.nDisposeCount == 1 );
726             }
727         }
728
729         void HP_base_cmp();
730         void HP_base_less();
731         void HP_base_cmpmix();
732         void HP_base_ic();
733         void HP_member_cmp();
734         void HP_member_less();
735         void HP_member_cmpmix();
736         void HP_member_ic();
737
738         void PTB_base_cmp();
739         void PTB_base_less();
740         void PTB_base_cmpmix();
741         void PTB_base_ic();
742         void PTB_member_cmp();
743         void PTB_member_less();
744         void PTB_member_cmpmix();
745         void PTB_member_ic();
746
747         void HRC_base_cmp();
748         void HRC_base_less();
749         void HRC_base_cmpmix();
750         void HRC_base_ic();
751
752         void RCU_GPI_base_cmp();
753         void RCU_GPI_base_less();
754         void RCU_GPI_base_cmpmix();
755         void RCU_GPI_base_ic();
756         void RCU_GPI_member_cmp();
757         void RCU_GPI_member_less();
758         void RCU_GPI_member_cmpmix();
759         void RCU_GPI_member_ic();
760
761         void RCU_GPB_base_cmp();
762         void RCU_GPB_base_less();
763         void RCU_GPB_base_cmpmix();
764         void RCU_GPB_base_ic();
765         void RCU_GPB_member_cmp();
766         void RCU_GPB_member_less();
767         void RCU_GPB_member_cmpmix();
768         void RCU_GPB_member_ic();
769
770         void RCU_GPT_base_cmp();
771         void RCU_GPT_base_less();
772         void RCU_GPT_base_cmpmix();
773         void RCU_GPT_base_ic();
774         void RCU_GPT_member_cmp();
775         void RCU_GPT_member_less();
776         void RCU_GPT_member_cmpmix();
777         void RCU_GPT_member_ic();
778
779         void RCU_SHB_base_cmp();
780         void RCU_SHB_base_less();
781         void RCU_SHB_base_cmpmix();
782         void RCU_SHB_base_ic();
783         void RCU_SHB_member_cmp();
784         void RCU_SHB_member_less();
785         void RCU_SHB_member_cmpmix();
786         void RCU_SHB_member_ic();
787
788         void RCU_SHT_base_cmp();
789         void RCU_SHT_base_less();
790         void RCU_SHT_base_cmpmix();
791         void RCU_SHT_base_ic();
792         void RCU_SHT_member_cmp();
793         void RCU_SHT_member_less();
794         void RCU_SHT_member_cmpmix();
795         void RCU_SHT_member_ic();
796
797         void nogc_base_cmp();
798         void nogc_base_less();
799         void nogc_base_cmpmix();
800         void nogc_base_ic();
801         void nogc_member_cmp();
802         void nogc_member_less();
803         void nogc_member_cmpmix();
804         void nogc_member_ic();
805
806
807         CPPUNIT_TEST_SUITE(IntrusiveLazyListHeaderTest)
808             CPPUNIT_TEST(HP_base_cmp)
809             CPPUNIT_TEST(HP_base_less)
810             CPPUNIT_TEST(HP_base_cmpmix)
811             CPPUNIT_TEST(HP_base_ic)
812             CPPUNIT_TEST(HP_member_cmp)
813             CPPUNIT_TEST(HP_member_less)
814             CPPUNIT_TEST(HP_member_cmpmix)
815             CPPUNIT_TEST(HP_member_ic)
816
817             CPPUNIT_TEST(PTB_base_cmp)
818             CPPUNIT_TEST(PTB_base_less)
819             CPPUNIT_TEST(PTB_base_cmpmix)
820             CPPUNIT_TEST(PTB_base_ic)
821             CPPUNIT_TEST(PTB_member_cmp)
822             CPPUNIT_TEST(PTB_member_less)
823             CPPUNIT_TEST(PTB_member_cmpmix)
824             CPPUNIT_TEST(PTB_member_ic)
825
826             CPPUNIT_TEST(HRC_base_cmp)
827             CPPUNIT_TEST(HRC_base_less)
828             CPPUNIT_TEST(HRC_base_cmpmix)
829             CPPUNIT_TEST(HRC_base_ic)
830
831             CPPUNIT_TEST(RCU_GPI_base_cmp)
832             CPPUNIT_TEST(RCU_GPI_base_less)
833             CPPUNIT_TEST(RCU_GPI_base_cmpmix)
834             CPPUNIT_TEST(RCU_GPI_base_ic)
835             CPPUNIT_TEST(RCU_GPI_member_cmp)
836             CPPUNIT_TEST(RCU_GPI_member_less)
837             CPPUNIT_TEST(RCU_GPI_member_cmpmix)
838             CPPUNIT_TEST(RCU_GPI_member_ic)
839
840             CPPUNIT_TEST(RCU_GPB_base_cmp)
841             CPPUNIT_TEST(RCU_GPB_base_less)
842             CPPUNIT_TEST(RCU_GPB_base_cmpmix)
843             CPPUNIT_TEST(RCU_GPB_base_ic)
844             CPPUNIT_TEST(RCU_GPB_member_cmp)
845             CPPUNIT_TEST(RCU_GPB_member_less)
846             CPPUNIT_TEST(RCU_GPB_member_cmpmix)
847             CPPUNIT_TEST(RCU_GPB_member_ic)
848
849             CPPUNIT_TEST(RCU_GPT_base_cmp)
850             CPPUNIT_TEST(RCU_GPT_base_less)
851             CPPUNIT_TEST(RCU_GPT_base_cmpmix)
852             CPPUNIT_TEST(RCU_GPT_base_ic)
853             CPPUNIT_TEST(RCU_GPT_member_cmp)
854             CPPUNIT_TEST(RCU_GPT_member_less)
855             CPPUNIT_TEST(RCU_GPT_member_cmpmix)
856             CPPUNIT_TEST(RCU_GPT_member_ic)
857
858             CPPUNIT_TEST(RCU_SHB_base_cmp)
859             CPPUNIT_TEST(RCU_SHB_base_less)
860             CPPUNIT_TEST(RCU_SHB_base_cmpmix)
861             CPPUNIT_TEST(RCU_SHB_base_ic)
862             CPPUNIT_TEST(RCU_SHB_member_cmp)
863             CPPUNIT_TEST(RCU_SHB_member_less)
864             CPPUNIT_TEST(RCU_SHB_member_cmpmix)
865             CPPUNIT_TEST(RCU_SHB_member_ic)
866
867             CPPUNIT_TEST(RCU_SHT_base_cmp)
868             CPPUNIT_TEST(RCU_SHT_base_less)
869             CPPUNIT_TEST(RCU_SHT_base_cmpmix)
870             CPPUNIT_TEST(RCU_SHT_base_ic)
871             CPPUNIT_TEST(RCU_SHT_member_cmp)
872             CPPUNIT_TEST(RCU_SHT_member_less)
873             CPPUNIT_TEST(RCU_SHT_member_cmpmix)
874             CPPUNIT_TEST(RCU_SHT_member_ic)
875
876             CPPUNIT_TEST(nogc_base_cmp)
877             CPPUNIT_TEST(nogc_base_less)
878             CPPUNIT_TEST(nogc_base_cmpmix)
879             CPPUNIT_TEST(nogc_base_ic)
880             CPPUNIT_TEST(nogc_member_cmp)
881             CPPUNIT_TEST(nogc_member_less)
882             CPPUNIT_TEST(nogc_member_cmpmix)
883             CPPUNIT_TEST(nogc_member_ic)
884
885         CPPUNIT_TEST_SUITE_END()
886     };
887 }   // namespace ordlist