Added copyright and license
[libcds.git] / tests / test-hdr / list / hdr_intrusive_lazy.h
1 /*
2     This file is a part of libcds - Concurrent Data Structures library
3
4     (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
5
6     Source code repo: http://github.com/khizmax/libcds/
7     Download: http://sourceforge.net/projects/libcds/files/
8     
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions are met:
11
12     * Redistributions of source code must retain the above copyright notice, this
13       list of conditions and the following disclaimer.
14
15     * Redistributions in binary form must reproduce the above copyright notice,
16       this list of conditions and the following disclaimer in the documentation
17       and/or other materials provided with the distribution.
18
19     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23     FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
29 */
30
31 #ifndef CDSTEST_HDR_INTRUSIVE_LAZY_H
32 #define CDSTEST_HDR_INTRUSIVE_LAZY_H
33
34 #include "cppunit/cppunit_proxy.h"
35 #include <cds/intrusive/details/lazy_list_base.h>
36
37 namespace ordlist {
38     namespace ci = cds::intrusive;
39     namespace co = cds::opt;
40
41     class IntrusiveLazyListHeaderTest: public CppUnitMini::TestCase
42     {
43     public:
44
45         struct stat {
46             int nDisposeCount;
47             int nUpdateExistsCall;
48             int nUpdateNewCall;
49             int nFindCall;
50             int nEraseCall;
51
52             stat()
53                 : nDisposeCount(0)
54                 , nUpdateExistsCall(0)
55                 , nUpdateNewCall(0)
56                 , nFindCall(0)
57                 , nEraseCall(0)
58             {}
59
60             stat( const stat& s )
61             {
62                 *this = s;
63             }
64
65             stat& operator =(const stat& s)
66             {
67                 memcpy( this, &s, sizeof(s));
68                 return *this;
69             }
70         };
71
72         template <typename GC>
73         struct base_int_item: public ci::lazy_list::node< GC >
74         {
75             int nKey;
76             int nVal;
77
78             mutable stat    s;
79
80             base_int_item()
81             {}
82
83             base_int_item(int key, int val)
84                 : nKey( key )
85                 , nVal(val)
86                 , s()
87             {}
88
89             base_int_item(const base_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 GC>
102         struct member_int_item
103         {
104             int nKey;
105             int nVal;
106
107             ci::lazy_list::node< GC > hMember;
108
109             mutable stat s;
110
111             member_int_item()
112             {}
113
114             member_int_item(int key, int val)
115                 : nKey( key )
116                 , nVal(val)
117                 , s()
118             {}
119
120             member_int_item(const member_int_item& v )
121                 : nKey( v.nKey )
122                 , nVal( v.nVal )
123                 , s()
124             {}
125
126             const int& key() const
127             {
128                 return nKey;
129             }
130         };
131
132         template <typename T>
133         struct less
134         {
135             bool operator ()(const T& v1, const T& v2 ) const
136             {
137                 return v1.key() < v2.key();
138             }
139
140             template <typename Q>
141             bool operator ()(const T& v1, const Q& v2 ) const
142             {
143                 return v1.key() < v2;
144             }
145
146             template <typename Q>
147             bool operator ()(const Q& v1, const T& v2 ) const
148             {
149                 return v1 < v2.key();
150             }
151         };
152
153         template <typename T>
154         struct cmp {
155             int operator ()(const T& v1, const T& v2 ) const
156             {
157                 if ( v1.key() < v2.key() )
158                     return -1;
159                 return v1.key() > v2.key() ? 1 : 0;
160             }
161
162             template <typename Q>
163             int operator ()(const T& v1, const Q& v2 ) const
164             {
165                 if ( v1.key() < v2 )
166                     return -1;
167                 return v1.key() > v2 ? 1 : 0;
168             }
169
170             template <typename Q>
171             int operator ()(const Q& v1, const T& v2 ) const
172             {
173                 if ( v1 < v2.key() )
174                     return -1;
175                 return v1 > v2.key() ? 1 : 0;
176             }
177         };
178
179         template <typename T>
180         struct equal_to {
181             bool operator ()(const T& v1, const T& v2 ) const
182             {
183                 return v1.key() == v2.key();
184             }
185
186             template <typename Q>
187             bool operator ()(const T& v1, const Q& v2 ) const
188             {
189                 return v1.key() == v2;
190             }
191
192             template <typename Q>
193             bool operator ()(const Q& v1, const T& v2 ) const
194             {
195                 return v1 == v2.key();
196             }
197         };
198
199         struct other_item {
200             int nKey;
201
202             other_item( int n )
203                 : nKey(n)
204             {}
205         };
206
207         struct other_less {
208             template <typename T, typename Q>
209             bool operator()( T const& i1, Q const& i2) const
210             {
211                 return i1.nKey < i2.nKey;
212             }
213         };
214
215         struct other_equal {
216             template <typename T, typename Q>
217             bool operator()( T const& i1, Q const& i2) const
218             {
219                 return i1.nKey == i2.nKey;
220             }
221         };
222
223         struct faked_disposer
224         {
225             template <typename T>
226             void operator ()( T * p )
227             {
228                 ++p->s.nDisposeCount;
229             }
230         };
231
232         struct update_functor
233         {
234             template <typename T>
235             void operator ()(bool bNew, T& item, T& /*val*/ )
236             {
237                 if ( bNew )
238                     ++item.s.nUpdateNewCall;
239                 else
240                     ++item.s.nUpdateExistsCall;
241             }
242         };
243
244         struct find_functor
245         {
246             template <typename T, typename Q>
247             void operator ()( T& item, Q& /*val*/ )
248             {
249                 ++item.s.nFindCall;
250             }
251         };
252
253         struct erase_functor
254         {
255             template <typename T>
256             void operator()( T const& item )
257             {
258                 item.s.nEraseCall++;
259             }
260         };
261
262         template <class OrdList>
263         void test_int_common()
264         {
265             typedef typename OrdList::value_type    value_type;
266
267             value_type v1( 10, 50 );
268             value_type v2( 5, 25  );
269             value_type v3( 20, 100 );
270             {
271                 OrdList l;
272                 CPPUNIT_ASSERT( l.empty() );
273
274                 CPPUNIT_ASSERT( l.insert( v1 ))     ;   // true
275                 CPPUNIT_ASSERT( l.contains( v1.key() ));
276
277                 CPPUNIT_ASSERT( v1.s.nFindCall == 0 );
278                 CPPUNIT_ASSERT( l.find( v1.key(), find_functor() ));
279                 CPPUNIT_ASSERT( v1.s.nFindCall == 1 );
280
281                 CPPUNIT_ASSERT( !l.contains( v2.key(), less<value_type>() ));
282                 CPPUNIT_ASSERT( !l.find( v3.key(), find_functor() ));
283                 CPPUNIT_ASSERT( !l.empty() );
284
285                 //CPPUNIT_ASSERT( !l.insert( v1 ))    ;   // assertion "is_empty" is raised
286
287                 {
288                     value_type v( v1 );
289                     CPPUNIT_ASSERT( !l.insert( v )) ;   // false
290                 }
291
292                 std::pair<bool, bool> ret = l.update( v2, update_functor() );
293                 CPPUNIT_ASSERT( ret.first );
294                 CPPUNIT_ASSERT( ret.second );
295                 CPPUNIT_ASSERT( v2.s.nUpdateNewCall == 1 );
296                 CPPUNIT_ASSERT( v2.s.nUpdateExistsCall == 0 );
297
298                 //CPPUNIT_ASSERT( !l.insert( v2 ))    ;   // assertion "is_empty"
299
300                 CPPUNIT_ASSERT( l.contains( v1.key() )) ;   // true
301
302                 CPPUNIT_ASSERT( v1.s.nFindCall == 1 );
303                 CPPUNIT_ASSERT( l.find( v1.key(), find_functor() ));
304                 CPPUNIT_ASSERT( v1.s.nFindCall == 2 );
305
306                 CPPUNIT_ASSERT( l.contains( v2.key() ));
307
308                 CPPUNIT_ASSERT( v2.s.nFindCall == 0 );
309                 CPPUNIT_ASSERT( l.find_with( v2.key(), less<value_type>(), find_functor() ));
310                 CPPUNIT_ASSERT( v2.s.nFindCall == 1 );
311
312                 CPPUNIT_ASSERT( !l.contains( v3.key() ));
313
314                 {
315                     CPPUNIT_ASSERT( v2.s.nUpdateExistsCall == 0 );
316                     CPPUNIT_ASSERT( v2.s.nUpdateNewCall == 1 );
317
318                     value_type v( v2 );
319                     ret = l.update( v, update_functor() );
320
321                     CPPUNIT_ASSERT( ret.first );
322                     CPPUNIT_ASSERT( !ret.second );
323                     CPPUNIT_ASSERT( v2.s.nUpdateExistsCall == 1 );
324                     CPPUNIT_ASSERT( v2.s.nUpdateNewCall == 1 );
325                     CPPUNIT_ASSERT( v.s.nUpdateExistsCall == 0 );
326                     CPPUNIT_ASSERT( v.s.nUpdateNewCall == 0 );
327                 }
328
329                 CPPUNIT_ASSERT( !l.empty() );
330
331                 CPPUNIT_ASSERT( l.insert( v3 ))     ;   // true
332                 CPPUNIT_ASSERT( l.contains( v3.key() ));
333
334                 CPPUNIT_ASSERT( v3.s.nFindCall == 0 );
335                 CPPUNIT_ASSERT( l.find( v3.key(), find_functor() ));
336                 CPPUNIT_ASSERT( v3.s.nFindCall == 1 );
337
338                 CPPUNIT_ASSERT( l.unlink( v2 ) );
339                 CPPUNIT_ASSERT( l.contains( v1.key() )) ;   // true
340                 CPPUNIT_ASSERT( !l.contains( v2.key() )) ;   // true
341                 CPPUNIT_ASSERT( l.contains( v3.key() )) ;   // true
342                 CPPUNIT_ASSERT( !l.empty() );
343                 CPPUNIT_ASSERT( !l.unlink( v2 ) );
344
345                 {
346                     // v1 key is in the list but v NODE is not in the list
347                     value_type v( v1 );
348                     CPPUNIT_ASSERT( !l.unlink( v ) );
349                 }
350
351                 CPPUNIT_ASSERT( l.unlink( v1 ) );
352                 CPPUNIT_ASSERT( !l.unlink( v1 ) );
353                 CPPUNIT_ASSERT( !l.contains( v1.key() ));
354                 CPPUNIT_ASSERT( !l.contains( v2.key() ));
355                 CPPUNIT_ASSERT( l.contains( v3.key() ));
356                 CPPUNIT_ASSERT( !l.empty() );
357                 CPPUNIT_ASSERT( !l.unlink( v1 ) );
358                 CPPUNIT_ASSERT( !l.unlink( v2 ) );
359
360                 CPPUNIT_ASSERT( l.unlink( v3 ) );
361                 CPPUNIT_ASSERT( !l.contains( v1.key() ));
362                 CPPUNIT_ASSERT( !l.contains( v2.key(), less<value_type>() ));
363                 CPPUNIT_ASSERT( !l.contains( v3.key() ));
364                 CPPUNIT_ASSERT( l.empty() );
365                 CPPUNIT_ASSERT( !l.unlink( v1 ) );
366                 CPPUNIT_ASSERT( !l.unlink( v2 ) );
367                 CPPUNIT_ASSERT( !l.unlink( v3 ) );
368
369                 // Apply retired pointer to clean links
370                 OrdList::gc::force_dispose();
371
372                 stat s( v3.s );
373                 ret = l.update( v3, update_functor() );
374                 CPPUNIT_ASSERT( ret.first );
375                 CPPUNIT_ASSERT( ret.second );
376                 CPPUNIT_ASSERT( v3.s.nUpdateNewCall == s.nUpdateNewCall + 1);
377                 CPPUNIT_ASSERT( v3.s.nUpdateExistsCall == s.nUpdateExistsCall );
378                 CPPUNIT_ASSERT( !l.empty() );
379
380                 s = v2.s;
381                 ret = l.update( v2, update_functor() );
382                 CPPUNIT_ASSERT( ret.first );
383                 CPPUNIT_ASSERT( ret.second );
384                 CPPUNIT_ASSERT( v2.s.nUpdateNewCall == s.nUpdateNewCall + 1);
385                 CPPUNIT_ASSERT( v2.s.nUpdateExistsCall == s.nUpdateExistsCall );
386                 CPPUNIT_ASSERT( !l.empty() );
387
388                 s = v1.s;
389                 ret = l.update( v1, update_functor() );
390                 CPPUNIT_ASSERT( ret.first );
391                 CPPUNIT_ASSERT( ret.second );
392                 CPPUNIT_ASSERT( v1.s.nUpdateNewCall == s.nUpdateNewCall + 1);
393                 CPPUNIT_ASSERT( v1.s.nUpdateExistsCall == s.nUpdateExistsCall );
394                 CPPUNIT_ASSERT( !l.empty() );
395
396                 // Erase test
397                 CPPUNIT_ASSERT( l.erase( v1.key()) );
398                 //CPPUNIT_ASSERT( v1.s.nDisposeCount == 0 );
399                 CPPUNIT_ASSERT( !l.empty() );
400
401                 CPPUNIT_ASSERT( v2.s.nEraseCall == 0 );
402                 CPPUNIT_ASSERT( l.erase_with( v2.key(), less<value_type>(), erase_functor()) );
403                 CPPUNIT_ASSERT( v2.s.nEraseCall == 1 );
404                 CPPUNIT_ASSERT( !l.erase_with( v2.key(), less<value_type>()));
405                 CPPUNIT_ASSERT( v2.s.nEraseCall == 1 );
406                 //CPPUNIT_ASSERT( v2.s.nDisposeCount == 0 );
407                 CPPUNIT_ASSERT( !l.empty() );
408
409                 CPPUNIT_ASSERT( !l.erase( v2 ));
410                 CPPUNIT_ASSERT( !l.erase( v1 ));
411                 //CPPUNIT_ASSERT( v2.s.nDisposeCount == 0 );
412                 CPPUNIT_ASSERT( !l.empty() );
413
414                 CPPUNIT_ASSERT( v3.s.nEraseCall == 0 );
415                 CPPUNIT_ASSERT( l.erase( v3, erase_functor() ));
416                 CPPUNIT_ASSERT( v3.s.nEraseCall == 1 );
417                 //CPPUNIT_ASSERT( v3.s.nDisposeCount == 0 );
418                 CPPUNIT_ASSERT( l.empty() );
419
420                 // Apply retired pointer to clean links
421                 OrdList::gc::force_dispose();
422
423                 // Unlink test
424                 CPPUNIT_ASSERT( l.insert( v1 ));
425                 CPPUNIT_ASSERT( l.insert( v3 ));
426                 CPPUNIT_ASSERT( !l.empty() );
427                 CPPUNIT_ASSERT( !l.unlink( v2 ));
428                 CPPUNIT_ASSERT( l.unlink( v1 ));
429                 CPPUNIT_ASSERT( !l.unlink( v1 ));
430                 CPPUNIT_ASSERT( l.unlink( v3 ));
431                 CPPUNIT_ASSERT( !l.unlink( v3 ));
432                 CPPUNIT_ASSERT( l.empty() );
433
434                 // Apply retired pointer
435                 OrdList::gc::force_dispose();
436                 CPPUNIT_ASSERT( v1.s.nDisposeCount == 3 );
437                 CPPUNIT_ASSERT( v2.s.nDisposeCount == 2 );
438                 CPPUNIT_ASSERT( v3.s.nDisposeCount == 3 );
439
440                 // Destructor test (call disposer)
441                 CPPUNIT_ASSERT( l.insert( v1 ));
442                 CPPUNIT_ASSERT( l.insert( v3 ));
443                 CPPUNIT_ASSERT( l.insert( v2 ));
444
445                 // Iterator test
446                 {
447                     typename OrdList::iterator it = l.begin();
448                     typename OrdList::const_iterator cit = l.cbegin();
449                     CPPUNIT_ASSERT( it != l.end() );
450                     CPPUNIT_ASSERT( it != l.cend() );
451                     CPPUNIT_ASSERT( cit != l.end() );
452                     CPPUNIT_ASSERT( cit != l.cend() );
453                     CPPUNIT_ASSERT( cit == it );
454
455                     CPPUNIT_ASSERT( it->nKey == v2.nKey );
456                     CPPUNIT_ASSERT( it->nVal == v2.nVal );
457                     CPPUNIT_ASSERT( ++it != l.end() );
458                     CPPUNIT_ASSERT( it->nKey == v1.nKey );
459                     CPPUNIT_ASSERT( it->nVal == v1.nVal );
460                     CPPUNIT_ASSERT( ++it != l.end() );
461                     CPPUNIT_ASSERT( it->nKey == v3.nKey );
462                     CPPUNIT_ASSERT( it->nVal == v3.nVal );
463                     CPPUNIT_ASSERT( ++it == l.end() );
464                 }
465
466                 {
467                     OrdList const & lref = l;
468                     typename OrdList::const_iterator it = lref.begin();
469                     CPPUNIT_ASSERT( it != l.end() );
470                     CPPUNIT_ASSERT( it->nKey == v2.nKey );
471                     CPPUNIT_ASSERT( it->nVal == v2.nVal );
472                     CPPUNIT_ASSERT( ++it != lref.end() );
473                     CPPUNIT_ASSERT( it->nKey == v1.nKey );
474                     CPPUNIT_ASSERT( it->nVal == v1.nVal );
475                     CPPUNIT_ASSERT( ++it != l.end() );
476                     CPPUNIT_ASSERT( it->nKey == v3.nKey );
477                     CPPUNIT_ASSERT( it->nVal == v3.nVal );
478                     CPPUNIT_ASSERT( ++it == l.end() );
479                 }
480             }
481
482             // Apply retired pointer
483             OrdList::gc::force_dispose();
484
485             CPPUNIT_ASSERT( v1.s.nDisposeCount == 4 );
486             CPPUNIT_ASSERT( v2.s.nDisposeCount == 3 );
487             CPPUNIT_ASSERT( v3.s.nDisposeCount == 4 );
488         }
489
490         template <class OrdList>
491         void test_int()
492         {
493             test_int_common<OrdList>();
494
495             OrdList l;
496             typename OrdList::guarded_ptr gp;
497
498             static int const nLimit = 20;
499             typename OrdList::value_type arrItem[nLimit];
500
501             {
502                 int a[nLimit];
503                 for (int i = 0; i < nLimit; ++i)
504                     a[i]=i;
505                 shuffle( a, a + nLimit );
506
507                 for (int i = 0; i < nLimit; ++i) {
508                     arrItem[i].nKey = a[i];
509                     arrItem[i].nVal = a[i] * 2;
510                 }
511
512                 // extract/get
513                 for ( int i = 0; i < nLimit; ++i )
514                     CPPUNIT_ASSERT( l.insert( arrItem[i] ) );
515
516                 for ( int i=0; i < nLimit; ++i ) {
517                     gp = l.get( arrItem[i].nKey );
518                     CPPUNIT_ASSERT( gp );
519                     CPPUNIT_ASSERT( !gp.empty());
520                     CPPUNIT_ASSERT( gp->nKey == arrItem[i].nKey );
521                     CPPUNIT_ASSERT( gp->nVal == arrItem[i].nVal );
522
523                     gp = l.extract( arrItem[i].nKey );
524                     CPPUNIT_ASSERT( gp );
525                     CPPUNIT_ASSERT( !gp.empty());
526                     CPPUNIT_ASSERT( gp->nKey == arrItem[i].nKey );
527                     CPPUNIT_ASSERT( gp->nVal == arrItem[i].nVal );
528
529                     gp = l.get( arrItem[i].nKey );
530                     CPPUNIT_ASSERT( !gp );
531                     CPPUNIT_ASSERT( gp.empty());
532                     CPPUNIT_ASSERT( !l.extract( arrItem[i].nKey ));
533                     CPPUNIT_ASSERT( gp.empty());
534                 }
535                 CPPUNIT_ASSERT( l.empty() );
536                 CPPUNIT_ASSERT( !l.get( nLimit/2 ));
537                 CPPUNIT_ASSERT( !l.extract( nLimit/2 ));
538
539                 // Apply retired pointer
540                 OrdList::gc::force_dispose();
541
542                 // extract_with/get_with
543                 for ( int i = 0; i < nLimit; ++i )
544                     CPPUNIT_ASSERT( l.insert( arrItem[i] ) );
545
546                 for ( int i=0; i < nLimit; ++i ) {
547                     other_item itm( arrItem[i].nKey );
548                     gp = l.get_with( itm, other_less() );
549                     CPPUNIT_ASSERT( gp );
550                     CPPUNIT_ASSERT( !gp.empty());
551                     CPPUNIT_ASSERT( gp->nKey == arrItem[i].nKey );
552                     CPPUNIT_ASSERT( gp->nVal == arrItem[i].nVal );
553
554                     gp = l.extract_with( itm, other_less() );
555                     CPPUNIT_ASSERT( gp );
556                     CPPUNIT_ASSERT( !gp.empty());
557                     CPPUNIT_ASSERT( gp->nKey == arrItem[i].nKey );
558                     CPPUNIT_ASSERT( gp->nVal == arrItem[i].nVal );
559
560                     gp = l.get_with( itm, other_less() );
561                     CPPUNIT_ASSERT( !gp );
562                     CPPUNIT_ASSERT( gp.empty());
563                     CPPUNIT_ASSERT( !l.extract_with( itm, other_less() ));
564                     CPPUNIT_ASSERT( gp.empty());
565                 }
566                 CPPUNIT_ASSERT( l.empty() );
567                 CPPUNIT_ASSERT( !l.get_with( other_item(nLimit/2), other_less() ));
568                 CPPUNIT_ASSERT( gp.empty());
569                 CPPUNIT_ASSERT( !l.extract_with( other_item(nLimit/2), other_less() ));
570                 CPPUNIT_ASSERT( gp.empty());
571
572                 // Apply retired pointer
573                 OrdList::gc::force_dispose();
574
575                 for ( int i=0; i < nLimit; i++ ) {
576                     CPPUNIT_ASSERT( arrItem[i].s.nDisposeCount == 2 );
577                 }
578             }
579         }
580
581         template <class OrdList>
582         void test_rcu_int()
583         {
584             test_int_common<OrdList>();
585
586             OrdList l;
587             static int const nLimit = 20;
588             typename OrdList::value_type arrItem[nLimit];
589
590             typedef typename OrdList::rcu_lock rcu_lock;
591             typedef typename OrdList::value_type value_type;
592             typedef typename OrdList::gc rcu_type;
593
594             {
595                 int a[nLimit];
596                 for (int i = 0; i < nLimit; ++i)
597                     a[i]=i;
598                 shuffle( a, a + nLimit );
599
600                 for (int i = 0; i < nLimit; ++i) {
601                     arrItem[i].nKey = a[i];
602                     arrItem[i].nVal = a[i] * 2;
603                 }
604
605                 typename OrdList::exempt_ptr ep;
606
607                 // extract/get
608                 for ( int i = 0; i < nLimit; ++i )
609                     CPPUNIT_ASSERT( l.insert( arrItem[i] ) );
610
611                 for ( int i = 0; i < nLimit; ++i ) {
612                     {
613                         rcu_lock lock;
614                         value_type * pGet = l.get( a[i] );
615                         CPPUNIT_ASSERT( pGet != nullptr );
616                         CPPUNIT_CHECK( pGet->nKey == a[i] );
617                         CPPUNIT_CHECK( pGet->nVal == a[i] * 2 );
618
619                         ep = l.extract( a[i] );
620                         CPPUNIT_ASSERT( ep );
621                         CPPUNIT_ASSERT( !ep.empty() );
622                         CPPUNIT_CHECK( ep->nKey == a[i] );
623                         CPPUNIT_CHECK( (*ep).nVal == a[i] * 2 );
624                     }
625                     ep.release();
626                     {
627                         rcu_lock lock;
628                         CPPUNIT_CHECK( l.get( a[i] ) == nullptr );
629                         CPPUNIT_CHECK( !l.extract( a[i] ) );
630                         CPPUNIT_CHECK( ep.empty() );
631                     }
632                 }
633                 CPPUNIT_ASSERT( l.empty() );
634
635                 {
636                     rcu_lock lock;
637                     CPPUNIT_CHECK( l.get( a[0] ) == nullptr );
638                     ep = l.extract( a[0] );
639                     CPPUNIT_CHECK( !ep );
640                     CPPUNIT_CHECK( ep.empty() );
641                 }
642                 // Apply retired pointer
643                 OrdList::gc::force_dispose();
644
645                 // extract_with/get_with
646                 for ( int i = 0; i < nLimit; ++i ) {
647                     CPPUNIT_ASSERT( l.insert( arrItem[i] ) );
648                 }
649
650                 for ( int i = 0; i < nLimit; ++i ) {
651                     other_item itm( a[i] );
652                     {
653                         rcu_lock lock;
654                         value_type * pGet = l.get_with( itm, other_less() );
655                         CPPUNIT_ASSERT( pGet != nullptr );
656                         CPPUNIT_CHECK( pGet->nKey == a[i] );
657                         CPPUNIT_CHECK( pGet->nVal == a[i] * 2 );
658
659                         ep = l.extract_with( itm, other_less() );
660                         CPPUNIT_ASSERT( ep );
661                         CPPUNIT_ASSERT( !ep.empty() );
662                         CPPUNIT_CHECK( ep->nKey == a[i] );
663                         CPPUNIT_CHECK( ep->nVal == a[i] * 2 );
664                     }
665                     ep.release();
666                     {
667                         rcu_lock lock;
668                         CPPUNIT_CHECK( l.get_with( itm, other_less() ) == nullptr );
669                         ep = l.extract_with( itm, other_less() );
670                         CPPUNIT_CHECK( !ep );
671                         CPPUNIT_CHECK( ep.empty() );
672                     }
673                 }
674                 CPPUNIT_ASSERT( l.empty() );
675
676                 {
677                     rcu_lock lock;
678                     CPPUNIT_CHECK( l.get_with( other_item( 0 ), other_less() ) == nullptr );
679                     CPPUNIT_CHECK( !l.extract_with( other_item(0), other_less() ));
680                     CPPUNIT_CHECK( ep.empty() );
681                 }
682                 // Apply retired pointer
683                 OrdList::gc::force_dispose();
684             }
685         }
686
687         template <class OrdList>
688         void test_nogc_int()
689         {
690             typedef typename OrdList::value_type    value_type;
691
692             {
693                 value_type v1( 10, 50 );
694                 value_type v2( 5, 25  );
695                 value_type v3( 20, 100 );
696                 {
697                     OrdList l;
698                     CPPUNIT_ASSERT( l.empty() );
699
700                     CPPUNIT_ASSERT( l.insert( v1 ))     ;   // true
701                     CPPUNIT_ASSERT( l.contains( v1.key() ) == &v1 );
702
703                     CPPUNIT_ASSERT( v1.s.nFindCall == 0 );
704                     CPPUNIT_ASSERT( l.find( v1.key(), find_functor() ));
705                     CPPUNIT_ASSERT( v1.s.nFindCall == 1 );
706
707                     CPPUNIT_ASSERT( l.contains( v2.key(), less<value_type>() ) == nullptr );
708                     CPPUNIT_ASSERT( l.contains( v3.key() ) == nullptr );
709                     CPPUNIT_ASSERT( !l.empty() );
710
711                     //CPPUNIT_ASSERT( !l.insert( v1 ))    ;   // assertion "is_empty" is raised
712
713                     {
714                         value_type v( v1 );
715                         CPPUNIT_ASSERT( !l.insert( v )) ;   // false
716                     }
717
718                     std::pair<bool, bool> ret = l.update( v2, update_functor() );
719                     CPPUNIT_ASSERT( ret.first );
720                     CPPUNIT_ASSERT( ret.second );
721                     CPPUNIT_ASSERT( v2.s.nUpdateNewCall == 1 );
722                     CPPUNIT_ASSERT( v2.s.nUpdateExistsCall == 0 );
723
724                     //CPPUNIT_ASSERT( !l.insert( v2 ))    ;   // assertion "is_empty"
725
726                     CPPUNIT_ASSERT( l.contains( v1.key() ) == &v1 ) ;   // true
727
728                     CPPUNIT_ASSERT( v1.s.nFindCall == 1 );
729                     CPPUNIT_ASSERT( l.find( v1.key(), find_functor() ));
730                     CPPUNIT_ASSERT( v1.s.nFindCall == 2 );
731
732                     CPPUNIT_ASSERT( l.contains( v2.key(), less<value_type>() ) == &v2 );
733
734                     CPPUNIT_ASSERT( v2.s.nFindCall == 0 );
735                     CPPUNIT_ASSERT( l.find_with( v2.key(), less<value_type>(), find_functor() ));
736                     CPPUNIT_ASSERT( v2.s.nFindCall == 1 );
737
738                     CPPUNIT_ASSERT( !l.contains( v3.key() ));
739
740                     {
741                         value_type v( v2 );
742                         ret = l.update( v, update_functor() );
743
744                         CPPUNIT_ASSERT( ret.first );
745                         CPPUNIT_ASSERT( !ret.second );
746                         CPPUNIT_ASSERT( v2.s.nUpdateExistsCall == 1 );
747                         CPPUNIT_ASSERT( v.s.nUpdateExistsCall == 0 && v.s.nUpdateNewCall == 0 );
748                     }
749
750                     CPPUNIT_ASSERT( !l.empty() );
751
752                     CPPUNIT_ASSERT( l.insert( v3 ))     ;   // true
753                     CPPUNIT_ASSERT( l.contains( v3.key() ) == &v3 );
754
755                     CPPUNIT_ASSERT( v3.s.nFindCall == 0 );
756                     CPPUNIT_ASSERT( l.find( v3.key(), find_functor() ));
757                     CPPUNIT_ASSERT( v3.s.nFindCall == 1 );
758
759                     {
760                         typename OrdList::iterator it = l.begin();
761                         typename OrdList::const_iterator cit = l.cbegin();
762                         CPPUNIT_ASSERT( it != l.end() );
763                         CPPUNIT_ASSERT( it != l.cend() );
764                         CPPUNIT_ASSERT( cit != l.end() );
765                         CPPUNIT_ASSERT( cit != l.cend() );
766                         CPPUNIT_ASSERT( cit == it );
767
768                         CPPUNIT_ASSERT( it->nKey == v2.nKey );
769                         CPPUNIT_ASSERT( it->nVal == v2.nVal );
770                         CPPUNIT_ASSERT( ++it != l.end() );
771                         CPPUNIT_ASSERT( it->nKey == v1.nKey );
772                         CPPUNIT_ASSERT( it->nVal == v1.nVal );
773                         CPPUNIT_ASSERT( it++ != l.end() );
774                         CPPUNIT_ASSERT( it->nKey == v3.nKey );
775                         CPPUNIT_ASSERT( it->nVal == v3.nVal );
776                         CPPUNIT_ASSERT( it++ != l.end() );
777                         CPPUNIT_ASSERT( it == l.end() );
778                     }
779
780                     {
781                         OrdList const & lref = l;
782                         typename OrdList::const_iterator it = lref.begin();
783                         CPPUNIT_ASSERT( it != l.end() );
784                         CPPUNIT_ASSERT( it->nKey == v2.nKey );
785                         CPPUNIT_ASSERT( it->nVal == v2.nVal );
786                         CPPUNIT_ASSERT( ++it != lref.end() );
787                         CPPUNIT_ASSERT( it->nKey == v1.nKey );
788                         CPPUNIT_ASSERT( it->nVal == v1.nVal );
789                         CPPUNIT_ASSERT( it++ != l.end() );
790                         CPPUNIT_ASSERT( it->nKey == v3.nKey );
791                         CPPUNIT_ASSERT( it->nVal == v3.nVal );
792                         CPPUNIT_ASSERT( it++ != lref.end() );
793                         CPPUNIT_ASSERT( it == l.end() );
794                     }
795                 }
796
797                 // Disposer called on list destruction
798                 CPPUNIT_ASSERT( v1.s.nDisposeCount == 1 );
799                 CPPUNIT_ASSERT( v2.s.nDisposeCount == 1 );
800                 CPPUNIT_ASSERT( v3.s.nDisposeCount == 1 );
801             }
802         }
803
804         template <class UnordList>
805         void test_nogc_int_unordered()
806         {
807             typedef typename UnordList::value_type    value_type;
808             {
809                 value_type v1( 10, 50 );
810                 value_type v2( 5, 25  );
811                 value_type v3( 20, 100 );
812                 {
813                     UnordList l;
814                     CPPUNIT_ASSERT( l.empty() );
815
816                     CPPUNIT_ASSERT( l.insert( v1 ));   // true
817                     CPPUNIT_ASSERT( l.contains( v1.key() ) == &v1 );
818
819                     CPPUNIT_ASSERT( v1.s.nFindCall == 0 );
820                     CPPUNIT_ASSERT( l.find( v1.key(), find_functor() ));
821                     CPPUNIT_ASSERT( v1.s.nFindCall == 1 );
822
823                     CPPUNIT_ASSERT( l.contains( v2.key(), equal_to<value_type>() ) == nullptr );
824                     CPPUNIT_ASSERT( l.contains( v3.key() ) == nullptr );
825                     CPPUNIT_ASSERT( !l.empty() );
826
827                     //CPPUNIT_ASSERT( !l.insert( v1 ))    ;   // assertion "is_empty" is raised
828
829                     {
830                         value_type v( v1 );
831                         CPPUNIT_ASSERT( !l.insert( v )) ;   // false
832                     }
833
834                     std::pair<bool, bool> ret = l.update( v2, update_functor() );
835                     CPPUNIT_ASSERT( ret.first );
836                     CPPUNIT_ASSERT( ret.second );
837                     CPPUNIT_ASSERT( v2.s.nUpdateNewCall == 1 );
838                     CPPUNIT_ASSERT( v2.s.nUpdateExistsCall == 0 );
839
840                     //CPPUNIT_ASSERT( !l.insert( v2 ))    ;   // assertion "is_empty"
841
842                     CPPUNIT_ASSERT( l.contains( v1.key() ) == &v1 ) ;   // true
843
844                     CPPUNIT_ASSERT( v1.s.nFindCall == 1 );
845                     CPPUNIT_ASSERT( l.find( v1.key(), find_functor() ));
846                     CPPUNIT_ASSERT( v1.s.nFindCall == 2 );
847
848                     CPPUNIT_ASSERT( l.contains( v2.key(), equal_to<value_type>() ) == &v2 );
849
850                     CPPUNIT_ASSERT( v2.s.nFindCall == 0 );
851                     CPPUNIT_ASSERT( l.find_with( v2.key(), equal_to<value_type>(), find_functor() ));
852                     CPPUNIT_ASSERT( v2.s.nFindCall == 1 );
853
854                     CPPUNIT_ASSERT( !l.contains( v3.key() ));
855
856                     {
857                         value_type v( v2 );
858                         ret = l.update( v, update_functor() );
859
860                         CPPUNIT_ASSERT( ret.first );
861                         CPPUNIT_ASSERT( !ret.second );
862                         CPPUNIT_ASSERT( v2.s.nUpdateExistsCall == 1 );
863                         CPPUNIT_ASSERT( v.s.nUpdateExistsCall == 0 && v.s.nUpdateNewCall == 0 );
864                     }
865
866                     CPPUNIT_ASSERT( !l.empty() );
867
868                     CPPUNIT_ASSERT( l.insert( v3 ))     ;   // true
869                     CPPUNIT_ASSERT( l.contains( v3.key() ) == &v3 );
870
871                     CPPUNIT_ASSERT( v3.s.nFindCall == 0 );
872                     CPPUNIT_ASSERT( l.find( v3.key(), find_functor() ));
873                     CPPUNIT_ASSERT( v3.s.nFindCall == 1 );
874
875                     {
876                         typename UnordList::iterator it = l.begin();
877                         typename UnordList::const_iterator cit = l.cbegin();
878                         CPPUNIT_ASSERT( it != l.end() );
879                         CPPUNIT_ASSERT( it != l.cend() );
880                         CPPUNIT_ASSERT( cit != l.end() );
881                         CPPUNIT_ASSERT( cit != l.cend() );
882                         CPPUNIT_ASSERT( cit == it );
883
884                         CPPUNIT_ASSERT( it->nKey == v1.nKey );
885                         CPPUNIT_ASSERT( it->nVal == v1.nVal );
886                         CPPUNIT_ASSERT( ++it != l.end() );
887                         CPPUNIT_ASSERT( it->nKey == v2.nKey );
888                         CPPUNIT_ASSERT( it->nVal == v2.nVal );
889                         CPPUNIT_ASSERT( it++ != l.end() );
890                         CPPUNIT_ASSERT( it->nKey == v3.nKey );
891                         CPPUNIT_ASSERT( it->nVal == v3.nVal );
892                         CPPUNIT_ASSERT( it++ != l.end() );
893                         CPPUNIT_ASSERT( it == l.end() );
894                     }
895
896                     {
897                         UnordList const & lref = l;
898                         typename UnordList::const_iterator it = lref.begin();
899                         CPPUNIT_ASSERT( it != l.end() );
900                         CPPUNIT_ASSERT( it->nKey == v1.nKey );
901                         CPPUNIT_ASSERT( it->nVal == v1.nVal );
902                         CPPUNIT_ASSERT( ++it != lref.end() );
903                         CPPUNIT_ASSERT( it->nKey == v2.nKey );
904                         CPPUNIT_ASSERT( it->nVal == v2.nVal );
905                         CPPUNIT_ASSERT( it++ != l.end() );
906                         CPPUNIT_ASSERT( it->nKey == v3.nKey );
907                         CPPUNIT_ASSERT( it->nVal == v3.nVal );
908                         CPPUNIT_ASSERT( it++ != lref.end() );
909                         CPPUNIT_ASSERT( it == l.end() );
910                     }
911                 }
912
913                 // Disposer called on list destruction
914                 CPPUNIT_ASSERT( v1.s.nDisposeCount == 1 );
915                 CPPUNIT_ASSERT( v2.s.nDisposeCount == 1 );
916                 CPPUNIT_ASSERT( v3.s.nDisposeCount == 1 );
917             }
918         }
919
920
921         void HP_base_cmp();
922         void HP_base_less();
923         void HP_base_cmpmix();
924         void HP_base_ic();
925         void HP_member_cmp();
926         void HP_member_less();
927         void HP_member_cmpmix();
928         void HP_member_ic();
929
930         void DHP_base_cmp();
931         void DHP_base_less();
932         void DHP_base_cmpmix();
933         void DHP_base_ic();
934         void DHP_member_cmp();
935         void DHP_member_less();
936         void DHP_member_cmpmix();
937         void DHP_member_ic();
938
939         void RCU_GPI_base_cmp();
940         void RCU_GPI_base_less();
941         void RCU_GPI_base_cmpmix();
942         void RCU_GPI_base_ic();
943         void RCU_GPI_member_cmp();
944         void RCU_GPI_member_less();
945         void RCU_GPI_member_cmpmix();
946         void RCU_GPI_member_ic();
947
948         void RCU_GPB_base_cmp();
949         void RCU_GPB_base_less();
950         void RCU_GPB_base_cmpmix();
951         void RCU_GPB_base_ic();
952         void RCU_GPB_member_cmp();
953         void RCU_GPB_member_less();
954         void RCU_GPB_member_cmpmix();
955         void RCU_GPB_member_ic();
956
957         void RCU_GPT_base_cmp();
958         void RCU_GPT_base_less();
959         void RCU_GPT_base_cmpmix();
960         void RCU_GPT_base_ic();
961         void RCU_GPT_member_cmp();
962         void RCU_GPT_member_less();
963         void RCU_GPT_member_cmpmix();
964         void RCU_GPT_member_ic();
965
966         void RCU_SHB_base_cmp();
967         void RCU_SHB_base_less();
968         void RCU_SHB_base_cmpmix();
969         void RCU_SHB_base_ic();
970         void RCU_SHB_member_cmp();
971         void RCU_SHB_member_less();
972         void RCU_SHB_member_cmpmix();
973         void RCU_SHB_member_ic();
974
975         void RCU_SHT_base_cmp();
976         void RCU_SHT_base_less();
977         void RCU_SHT_base_cmpmix();
978         void RCU_SHT_base_ic();
979         void RCU_SHT_member_cmp();
980         void RCU_SHT_member_less();
981         void RCU_SHT_member_cmpmix();
982         void RCU_SHT_member_ic();
983
984         void nogc_base_cmp();
985         void nogc_base_less();
986         void nogc_base_cmpmix();
987         void nogc_base_ic();
988         void nogc_member_cmp();
989         void nogc_member_less();
990         void nogc_member_cmpmix();
991         void nogc_member_ic();
992
993         void nogc_base_cmp_unord();
994         void nogc_base_less_unord();
995         void nogc_base_equal_to_unord();
996         void nogc_base_cmpmix_unord();
997         void nogc_base_equal_to_mix_unord();
998         void nogc_base_ic_unord();
999         void nogc_member_cmp_unord();
1000         void nogc_member_less_unord();
1001         void nogc_member_equal_to_unord();
1002         void nogc_member_cmpmix_unord();
1003         void nogc_member_equal_to_mix_unord();
1004         void nogc_member_ic_unord();
1005
1006         CPPUNIT_TEST_SUITE(IntrusiveLazyListHeaderTest)
1007             CPPUNIT_TEST(HP_base_cmp)
1008             CPPUNIT_TEST(HP_base_less)
1009             CPPUNIT_TEST(HP_base_cmpmix)
1010             CPPUNIT_TEST(HP_base_ic)
1011             CPPUNIT_TEST(HP_member_cmp)
1012             CPPUNIT_TEST(HP_member_less)
1013             CPPUNIT_TEST(HP_member_cmpmix)
1014             CPPUNIT_TEST(HP_member_ic)
1015
1016             CPPUNIT_TEST(DHP_base_cmp)
1017             CPPUNIT_TEST(DHP_base_less)
1018             CPPUNIT_TEST(DHP_base_cmpmix)
1019             CPPUNIT_TEST(DHP_base_ic)
1020             CPPUNIT_TEST(DHP_member_cmp)
1021             CPPUNIT_TEST(DHP_member_less)
1022             CPPUNIT_TEST(DHP_member_cmpmix)
1023             CPPUNIT_TEST(DHP_member_ic)
1024
1025             CPPUNIT_TEST(RCU_GPI_base_cmp)
1026             CPPUNIT_TEST(RCU_GPI_base_less)
1027             CPPUNIT_TEST(RCU_GPI_base_cmpmix)
1028             CPPUNIT_TEST(RCU_GPI_base_ic)
1029             CPPUNIT_TEST(RCU_GPI_member_cmp)
1030             CPPUNIT_TEST(RCU_GPI_member_less)
1031             CPPUNIT_TEST(RCU_GPI_member_cmpmix)
1032             CPPUNIT_TEST(RCU_GPI_member_ic)
1033
1034             CPPUNIT_TEST(RCU_GPB_base_cmp)
1035             CPPUNIT_TEST(RCU_GPB_base_less)
1036             CPPUNIT_TEST(RCU_GPB_base_cmpmix)
1037             CPPUNIT_TEST(RCU_GPB_base_ic)
1038             CPPUNIT_TEST(RCU_GPB_member_cmp)
1039             CPPUNIT_TEST(RCU_GPB_member_less)
1040             CPPUNIT_TEST(RCU_GPB_member_cmpmix)
1041             CPPUNIT_TEST(RCU_GPB_member_ic)
1042
1043             CPPUNIT_TEST(RCU_GPT_base_cmp)
1044             CPPUNIT_TEST(RCU_GPT_base_less)
1045             CPPUNIT_TEST(RCU_GPT_base_cmpmix)
1046             CPPUNIT_TEST(RCU_GPT_base_ic)
1047             CPPUNIT_TEST(RCU_GPT_member_cmp)
1048             CPPUNIT_TEST(RCU_GPT_member_less)
1049             CPPUNIT_TEST(RCU_GPT_member_cmpmix)
1050             CPPUNIT_TEST(RCU_GPT_member_ic)
1051
1052             CPPUNIT_TEST(RCU_SHB_base_cmp)
1053             CPPUNIT_TEST(RCU_SHB_base_less)
1054             CPPUNIT_TEST(RCU_SHB_base_cmpmix)
1055             CPPUNIT_TEST(RCU_SHB_base_ic)
1056             CPPUNIT_TEST(RCU_SHB_member_cmp)
1057             CPPUNIT_TEST(RCU_SHB_member_less)
1058             CPPUNIT_TEST(RCU_SHB_member_cmpmix)
1059             CPPUNIT_TEST(RCU_SHB_member_ic)
1060
1061             CPPUNIT_TEST(RCU_SHT_base_cmp)
1062             CPPUNIT_TEST(RCU_SHT_base_less)
1063             CPPUNIT_TEST(RCU_SHT_base_cmpmix)
1064             CPPUNIT_TEST(RCU_SHT_base_ic)
1065             CPPUNIT_TEST(RCU_SHT_member_cmp)
1066             CPPUNIT_TEST(RCU_SHT_member_less)
1067             CPPUNIT_TEST(RCU_SHT_member_cmpmix)
1068             CPPUNIT_TEST(RCU_SHT_member_ic)
1069
1070             CPPUNIT_TEST(nogc_base_cmp)
1071             CPPUNIT_TEST(nogc_base_less)
1072             CPPUNIT_TEST(nogc_base_cmpmix)
1073             CPPUNIT_TEST(nogc_base_ic)
1074             CPPUNIT_TEST(nogc_member_cmp)
1075             CPPUNIT_TEST(nogc_member_less)
1076             CPPUNIT_TEST(nogc_member_cmpmix)
1077             CPPUNIT_TEST(nogc_member_ic)
1078
1079             CPPUNIT_TEST(nogc_base_cmp_unord)
1080             CPPUNIT_TEST(nogc_base_less_unord)
1081             CPPUNIT_TEST(nogc_base_equal_to_unord)
1082             CPPUNIT_TEST(nogc_base_cmpmix_unord)
1083             CPPUNIT_TEST(nogc_base_equal_to_mix_unord)
1084             CPPUNIT_TEST(nogc_base_ic_unord)
1085             CPPUNIT_TEST(nogc_member_cmp_unord)
1086             CPPUNIT_TEST(nogc_member_less_unord)
1087             CPPUNIT_TEST(nogc_member_equal_to_unord)
1088             CPPUNIT_TEST(nogc_member_cmpmix_unord)
1089             CPPUNIT_TEST(nogc_member_equal_to_mix_unord)
1090             CPPUNIT_TEST(nogc_member_ic_unord)
1091
1092         CPPUNIT_TEST_SUITE_END()
1093     };
1094 }   // namespace ordlist
1095
1096 #endif // #ifndef CDSTEST_HDR_INTRUSIVE_LAZY_H