2 This file is a part of libcds - Concurrent Data Structures library
4 (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
6 Source code repo: http://github.com/khizmax/libcds/
7 Download: http://sourceforge.net/projects/libcds/files/
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions are met:
12 * Redistributions of source code must retain the above copyright notice, this
13 list of conditions and the following disclaimer.
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.
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.
30 #ifndef CDSUNIT_LIST_TEST_INTRUSIVE_ITERABLE_LIST_H
31 #define CDSUNIT_LIST_TEST_INTRUSIVE_ITERABLE_LIST_H
33 #include <cds_test/check_size.h>
34 #include <cds_test/fixture.h>
38 class intrusive_iterable_list : public fixture
43 int nUpdateExistsCall;
51 , nUpdateExistsCall( 0 )
63 stat& operator =( const stat& s )
65 memcpy( this, &s, sizeof( s ) );
80 item_type( int key, int val )
86 item_type( const item_type& v )
92 const int& key() const
97 item_type& operator=( item_type const& src )
104 item_type& operator=( item_type&& src )
112 template <typename T>
115 bool operator ()( const T& v1, const T& v2 ) const
117 return v1.key() < v2.key();
120 template <typename Q>
121 bool operator ()( const T& v1, const Q& v2 ) const
123 return v1.key() < v2;
126 template <typename Q>
127 bool operator ()( const Q& v1, const T& v2 ) const
129 return v1 < v2.key();
142 template <typename T, typename Q>
143 bool operator()( T const& i1, Q const& i2 ) const
145 return i1.nKey < i2.nKey;
149 template <typename T>
151 int operator ()( const T& v1, const T& v2 ) const
153 if ( v1.key() < v2.key() )
155 return v1.key() > v2.key() ? 1 : 0;
158 template <typename Q>
159 int operator ()( const T& v1, const Q& v2 ) const
163 return v1.key() > v2 ? 1 : 0;
166 template <typename Q>
167 int operator ()( const Q& v1, const T& v2 ) const
171 return v1 > v2.key() ? 1 : 0;
177 template <typename T>
178 void operator ()( T * p )
180 ++p->s.nDisposeCount;
184 struct update_functor
186 template <typename T>
187 void operator()( T& item, T * old )
190 ++item.s.nUpdateNewCall;
192 ++item.s.nUpdateExistsCall;
198 template <typename T, typename Q>
199 void operator ()( T& item, Q& /*val*/ )
207 template <typename T>
208 void operator()( T const& item )
215 template <typename List>
216 void test_common( List& l )
218 // Precondition: list is empty
219 // Postcondition: list is empty
221 static const size_t nSize = 20;
222 typedef typename List::value_type value_type;
223 value_type arr[ nSize ];
224 value_type arr2[ nSize ];
226 for ( size_t i = 0; i < nSize; ++i ) {
227 arr[i].nKey = static_cast<int>( i );
228 arr[i].nVal = arr[i].nKey * 10;
232 shuffle( arr, arr + nSize );
233 shuffle( arr2, arr2 + nSize );
235 ASSERT_TRUE( l.empty() );
236 ASSERT_CONTAINER_SIZE( l, 0 );
238 typedef typename List::iterator iterator;
241 for ( auto& i : arr ) {
242 EXPECT_FALSE( l.contains( i.nKey ));
243 EXPECT_FALSE( l.contains( other_item( i.nKey ), other_less()));
244 EXPECT_FALSE( l.find( i.nKey, []( value_type& item, int ) { ++item.s.nFindCall; } ));
245 EXPECT_EQ( i.s.nFindCall, 0 );
246 EXPECT_FALSE( l.find_with( other_item( i.nKey ), other_less(), []( value_type& item, other_item const& ) { ++item.s.nFindCall; } ));
247 EXPECT_EQ( i.s.nFindCall, 0 );
249 switch ( i.nKey % 4 ) {
251 EXPECT_TRUE( l.insert( i ));
254 EXPECT_EQ( i.s.nInsertCall, 0 );
255 EXPECT_TRUE( l.insert( i, []( value_type& i ) { ++i.s.nInsertCall; } ));
256 EXPECT_EQ( i.s.nInsertCall, 1 );
260 std::pair<bool, bool> ret = l.update( i, []( value_type& i, value_type * old ) {
261 EXPECT_TRUE( old == nullptr );
262 EXPECT_EQ( i.s.nUpdateNewCall, 0 );
263 ++i.s.nUpdateNewCall;
265 EXPECT_EQ( i.s.nUpdateNewCall, 0 );
266 EXPECT_EQ( ret.first, false );
267 EXPECT_EQ( ret.second, false );
269 ret = l.update( i, []( value_type& i, value_type * old ) {
270 EXPECT_TRUE( old == nullptr );
271 EXPECT_EQ( i.s.nUpdateNewCall, 0 );
272 ++i.s.nUpdateNewCall;
274 EXPECT_EQ( i.s.nUpdateNewCall, 1 );
275 EXPECT_EQ( ret.first, true );
276 EXPECT_EQ( ret.second, true );
281 std::pair<bool, bool> ret = l.upsert( i, false );
282 EXPECT_EQ( ret.first, false );
283 EXPECT_EQ( ret.second, false );
286 EXPECT_EQ( ret.first, true );
287 EXPECT_EQ( ret.second, true );
292 EXPECT_TRUE( l.contains( i.nKey ));
293 EXPECT_TRUE( l.contains( i ));
294 EXPECT_TRUE( l.contains( other_item( i.nKey ), other_less()));
295 EXPECT_TRUE( l.find( i.nKey, []( value_type& item, int ) { ++item.s.nFindCall; } ));
296 EXPECT_EQ( i.s.nFindCall, 1 );
297 EXPECT_TRUE( l.find( i, []( value_type& item, value_type const& ) { ++item.s.nFindCall; } ));
298 EXPECT_EQ( i.s.nFindCall, 2 );
299 EXPECT_TRUE( l.find_with( other_item( i.nKey ), other_less(), []( value_type& item, other_item const& ) { ++item.s.nFindCall; } ));
300 EXPECT_EQ( i.s.nFindCall, 3 );
302 EXPECT_FALSE( l.insert( i ) );
303 ASSERT_FALSE( l.empty() );
305 int const ckey = i.nKey;
306 iterator it = l.find( ckey );
307 ASSERT_FALSE( it == l.end() );
308 EXPECT_EQ( it->nKey, i.nKey );
309 EXPECT_EQ( (*it).nVal, i.nVal );
310 check_ordered( it, l.end() );
312 it = l.find( i.nKey );
313 ASSERT_FALSE( it == l.end() );
314 EXPECT_EQ( it->nKey, i.nKey );
315 EXPECT_EQ( (*it).nVal, i.nVal );
316 check_ordered( it, l.end() );
318 it = l.find_with( other_item( i.nKey ), other_less() );
319 ASSERT_FALSE( it == l.end() );
320 EXPECT_EQ( it->nKey, i.nKey );
321 EXPECT_EQ( it->nVal, i.nVal );
322 check_ordered( it, l.end() );
325 ASSERT_CONTAINER_SIZE( l, nSize );
328 for ( auto const& i : arr ) {
329 EXPECT_TRUE( l.contains( i.nKey ));
330 EXPECT_TRUE( l.contains( i ));
331 EXPECT_TRUE( l.contains( other_item( i.nKey ), other_less()));
332 EXPECT_TRUE( l.find( i.nKey, []( value_type& item, int ) { ++item.s.nFindCall; } ));
333 EXPECT_EQ( i.s.nFindCall, 4 );
334 EXPECT_TRUE( l.find( i, []( value_type& item, value_type const& ) { ++item.s.nFindCall; } ));
335 EXPECT_EQ( i.s.nFindCall, 5 );
336 EXPECT_TRUE( l.find_with( other_item( i.nKey ), other_less(), []( value_type& item, other_item const& ) { ++item.s.nFindCall; } ));
337 EXPECT_EQ( i.s.nFindCall, 6 );
339 ASSERT_FALSE( l.empty() );
340 ASSERT_CONTAINER_SIZE( l, nSize );
342 // update existing test
343 for ( auto& i : arr2 ) {
344 EXPECT_EQ( i.s.nUpdateExistsCall, 0 );
345 std::pair<bool, bool> ret = l.update( i, update_functor() );
346 EXPECT_TRUE( ret.first );
347 EXPECT_FALSE( ret.second );
348 EXPECT_EQ( i.s.nUpdateExistsCall, 1 );
351 // update with the same value must be empty - no functor is called
352 for ( auto& i : arr2 ) {
353 EXPECT_EQ( i.s.nUpdateExistsCall, 1 );
354 std::pair<bool, bool> ret = l.update( i, update_functor() );
355 EXPECT_TRUE( ret.first );
356 EXPECT_FALSE( ret.second );
357 EXPECT_EQ( i.s.nUpdateExistsCall, 1 );
360 // Apply retired pointer to clean links
361 List::gc::force_dispose();
363 for ( auto& i : arr ) {
364 EXPECT_EQ( i.s.nUpdateExistsCall, 0 );
365 std::pair<bool, bool> ret = l.update( i, []( value_type& i, value_type * old ) {
366 EXPECT_FALSE( old == nullptr );
367 EXPECT_EQ( i.s.nUpdateExistsCall, 0 );
368 ++i.s.nUpdateExistsCall;
370 EXPECT_TRUE( ret.first );
371 EXPECT_FALSE( ret.second );
372 EXPECT_EQ( i.s.nUpdateExistsCall, 1 );
376 for ( auto const& i : arr ) {
378 EXPECT_TRUE( l.erase( i.nKey ));
380 EXPECT_TRUE( l.erase_with( other_item( i.nKey ), other_less() ));
382 EXPECT_FALSE( l.contains( i ));
384 EXPECT_TRUE( l.empty() );
385 EXPECT_CONTAINER_SIZE( l, 0 );
387 // Apply retired pointer to clean links
388 List::gc::force_dispose();
390 for ( auto const& i : arr )
391 EXPECT_EQ( i.s.nDisposeCount, 2 );
392 for ( auto const& i : arr2 )
393 EXPECT_EQ( i.s.nDisposeCount, 1 );
395 // erase with functor
396 for ( auto& i : arr ) {
397 int const updateNewCall = i.s.nUpdateNewCall;
398 std::pair<bool, bool> ret = l.update( i, update_functor(), false );
399 EXPECT_FALSE( ret.first );
400 EXPECT_FALSE( ret.second );
401 EXPECT_EQ( i.s.nUpdateNewCall, updateNewCall );
403 ret = l.update( i, update_functor(), true );
404 EXPECT_TRUE( ret.first );
405 EXPECT_TRUE( ret.second );
406 EXPECT_EQ( i.s.nUpdateNewCall, updateNewCall + 1 );
408 EXPECT_FALSE( l.empty() );
409 EXPECT_CONTAINER_SIZE( l, nSize );
411 for ( auto const& i : arr ) {
412 EXPECT_EQ( i.s.nEraseCall, 0 );
414 EXPECT_TRUE( l.erase_with( other_item( i.nKey ), other_less(), erase_functor()));
415 EXPECT_FALSE( l.erase_with( other_item( i.nKey ), other_less(), erase_functor()));
418 EXPECT_TRUE( l.erase( i.nKey, []( value_type& item) { ++item.s.nEraseCall; } ));
419 EXPECT_FALSE( l.erase( i.nKey, []( value_type& item) { ++item.s.nEraseCall; } ));
421 EXPECT_EQ( i.s.nEraseCall, 1 );
422 EXPECT_FALSE( l.contains( i.nKey ));
424 EXPECT_TRUE( l.empty() );
425 EXPECT_CONTAINER_SIZE( l, 0 );
427 // Apply retired pointer to clean links
428 List::gc::force_dispose();
430 for ( auto const& i : arr )
431 EXPECT_EQ( i.s.nDisposeCount, 3 );
434 for ( auto& i : arr )
435 EXPECT_TRUE( l.insert( i ));
437 EXPECT_FALSE( l.empty() );
438 EXPECT_CONTAINER_SIZE( l, nSize );
442 EXPECT_TRUE( l.empty() );
443 EXPECT_CONTAINER_SIZE( l, 0 );
445 // Apply retired pointer to clean links
446 List::gc::force_dispose();
447 for ( auto const& i : arr ) {
448 EXPECT_EQ( i.s.nDisposeCount, 4 );
449 EXPECT_FALSE( l.contains( i ));
453 for ( auto& i : arr )
454 EXPECT_TRUE( l.insert( i ) );
455 for ( auto& i : arr ) {
457 EXPECT_TRUE( l.contains( val ));
458 EXPECT_FALSE( l.unlink( val ));
459 EXPECT_TRUE( l.contains( val ) );
460 EXPECT_TRUE( l.unlink( i ));
461 EXPECT_FALSE( l.unlink( i ));
462 EXPECT_FALSE( l.contains( i ) );
464 EXPECT_TRUE( l.empty() );
465 EXPECT_CONTAINER_SIZE( l, 0 );
467 // Apply retired pointer to clean links
468 List::gc::force_dispose();
469 for ( auto const& i : arr ) {
470 EXPECT_EQ( i.s.nDisposeCount, 5 );
471 EXPECT_FALSE( l.contains( i ) );
474 // Iterators on empty list
477 auto itEnd = l.end();
478 auto cit = l.cbegin();
479 auto citEnd = l.cend();
481 EXPECT_TRUE( it == itEnd );
482 EXPECT_TRUE( it == cit );
483 EXPECT_TRUE( cit == citEnd );
488 EXPECT_TRUE( it == itEnd );
489 EXPECT_TRUE( it == cit );
490 EXPECT_TRUE( cit == citEnd );
494 template <typename List>
495 void test_ordered_iterator( List& l )
497 // Precondition: list is empty
498 // Postcondition: list is empty
500 static const size_t nSize = 20;
501 typedef typename List::value_type value_type;
502 value_type arr[nSize];
504 for ( size_t i = 0; i < nSize; ++i ) {
505 arr[i].nKey = static_cast<int>(i);
506 arr[i].nVal = arr[i].nKey * 10;
508 shuffle( arr, arr + nSize );
510 ASSERT_TRUE( l.empty() );
511 ASSERT_CONTAINER_SIZE( l, 0 );
513 for ( auto& i : arr )
514 EXPECT_TRUE( l.insert( i ) );
517 for ( auto it = l.begin(); it != l.end(); ++it ) {
518 EXPECT_EQ( it->nKey, key );
519 EXPECT_EQ( (*it).nKey, key );
524 for ( auto it = l.cbegin(); it != l.cend(); ++it ) {
525 EXPECT_EQ( it->nKey, key );
526 EXPECT_EQ( (*it).nKey, key );
531 List::gc::force_dispose();
532 for ( auto const& i : arr ) {
533 EXPECT_EQ( i.s.nDisposeCount, 1 );
534 EXPECT_FALSE( l.contains( i ) );
538 template <typename Iterator>
539 void check_ordered( Iterator first, Iterator last )
541 while ( first != last ) {
543 if ( ++it != last ) {
544 EXPECT_LT( first->nKey, it->nKey );
552 } // namespace cds_test
554 #endif // CDSUNIT_LIST_TEST_INTRUSIVE_ITERABLE_LIST_H