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 % 3 ) {
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 EXPECT_TRUE( l.contains( i.nKey ));
282 EXPECT_TRUE( l.contains( i ));
283 EXPECT_TRUE( l.contains( other_item( i.nKey ), other_less()));
284 EXPECT_TRUE( l.find( i.nKey, []( value_type& item, int ) { ++item.s.nFindCall; } ));
285 EXPECT_EQ( i.s.nFindCall, 1 );
286 EXPECT_TRUE( l.find( i, []( value_type& item, value_type const& ) { ++item.s.nFindCall; } ));
287 EXPECT_EQ( i.s.nFindCall, 2 );
288 EXPECT_TRUE( l.find_with( other_item( i.nKey ), other_less(), []( value_type& item, other_item const& ) { ++item.s.nFindCall; } ));
289 EXPECT_EQ( i.s.nFindCall, 3 );
291 EXPECT_FALSE( l.insert( i ) );
292 ASSERT_FALSE( l.empty() );
294 int const ckey = i.nKey;
295 iterator it = l.find( ckey );
296 ASSERT_FALSE( it == l.end() );
297 EXPECT_EQ( it->nKey, i.nKey );
298 EXPECT_EQ( (*it).nVal, i.nVal );
299 check_ordered( it, l.end() );
301 it = l.find( i.nKey );
302 ASSERT_FALSE( it == l.end() );
303 EXPECT_EQ( it->nKey, i.nKey );
304 EXPECT_EQ( (*it).nVal, i.nVal );
305 check_ordered( it, l.end() );
307 it = l.find_with( other_item( i.nKey ), other_less() );
308 ASSERT_FALSE( it == l.end() );
309 EXPECT_EQ( it->nKey, i.nKey );
310 EXPECT_EQ( it->nVal, i.nVal );
311 check_ordered( it, l.end() );
314 ASSERT_CONTAINER_SIZE( l, nSize );
317 for ( auto const& i : arr ) {
318 EXPECT_TRUE( l.contains( i.nKey ));
319 EXPECT_TRUE( l.contains( i ));
320 EXPECT_TRUE( l.contains( other_item( i.nKey ), other_less()));
321 EXPECT_TRUE( l.find( i.nKey, []( value_type& item, int ) { ++item.s.nFindCall; } ));
322 EXPECT_EQ( i.s.nFindCall, 4 );
323 EXPECT_TRUE( l.find( i, []( value_type& item, value_type const& ) { ++item.s.nFindCall; } ));
324 EXPECT_EQ( i.s.nFindCall, 5 );
325 EXPECT_TRUE( l.find_with( other_item( i.nKey ), other_less(), []( value_type& item, other_item const& ) { ++item.s.nFindCall; } ));
326 EXPECT_EQ( i.s.nFindCall, 6 );
328 ASSERT_FALSE( l.empty() );
329 ASSERT_CONTAINER_SIZE( l, nSize );
331 // update existing test
332 for ( auto& i : arr2 ) {
333 EXPECT_EQ( i.s.nUpdateExistsCall, 0 );
334 std::pair<bool, bool> ret = l.update( i, update_functor() );
335 EXPECT_TRUE( ret.first );
336 EXPECT_FALSE( ret.second );
337 EXPECT_EQ( i.s.nUpdateExistsCall, 1 );
340 // update with the same value must be empty - no functor is called
341 for ( auto& i : arr2 ) {
342 EXPECT_EQ( i.s.nUpdateExistsCall, 1 );
343 std::pair<bool, bool> ret = l.update( i, update_functor() );
344 EXPECT_TRUE( ret.first );
345 EXPECT_FALSE( ret.second );
346 EXPECT_EQ( i.s.nUpdateExistsCall, 1 );
349 for ( auto& i : arr ) {
350 EXPECT_EQ( i.s.nUpdateExistsCall, 0 );
351 std::pair<bool, bool> ret = l.update( i, []( value_type& i, value_type * old ) {
352 EXPECT_FALSE( old == nullptr );
353 EXPECT_EQ( i.s.nUpdateExistsCall, 0 );
354 ++i.s.nUpdateExistsCall;
356 EXPECT_TRUE( ret.first );
357 EXPECT_FALSE( ret.second );
358 EXPECT_EQ( i.s.nUpdateExistsCall, 1 );
362 for ( auto const& i : arr ) {
364 EXPECT_TRUE( l.erase( i.nKey ));
366 EXPECT_TRUE( l.erase_with( other_item( i.nKey ), other_less() ));
368 EXPECT_FALSE( l.contains( i ));
370 EXPECT_TRUE( l.empty() );
371 EXPECT_CONTAINER_SIZE( l, 0 );
373 // Apply retired pointer to clean links
374 List::gc::force_dispose();
376 for ( auto const& i : arr )
377 EXPECT_EQ( i.s.nDisposeCount, 2 );
378 for ( auto const& i : arr2 )
379 EXPECT_EQ( i.s.nDisposeCount, 1 );
381 // erase with functor
382 for ( auto& i : arr ) {
383 int const updateNewCall = i.s.nUpdateNewCall;
384 std::pair<bool, bool> ret = l.update( i, update_functor(), false );
385 EXPECT_FALSE( ret.first );
386 EXPECT_FALSE( ret.second );
387 EXPECT_EQ( i.s.nUpdateNewCall, updateNewCall );
389 ret = l.update( i, update_functor(), true );
390 EXPECT_TRUE( ret.first );
391 EXPECT_TRUE( ret.second );
392 EXPECT_EQ( i.s.nUpdateNewCall, updateNewCall + 1 );
394 EXPECT_FALSE( l.empty() );
395 EXPECT_CONTAINER_SIZE( l, nSize );
397 for ( auto const& i : arr ) {
398 EXPECT_EQ( i.s.nEraseCall, 0 );
400 EXPECT_TRUE( l.erase_with( other_item( i.nKey ), other_less(), erase_functor()));
401 EXPECT_FALSE( l.erase_with( other_item( i.nKey ), other_less(), erase_functor()));
404 EXPECT_TRUE( l.erase( i.nKey, []( value_type& item) { ++item.s.nEraseCall; } ));
405 EXPECT_FALSE( l.erase( i.nKey, []( value_type& item) { ++item.s.nEraseCall; } ));
407 EXPECT_EQ( i.s.nEraseCall, 1 );
408 EXPECT_FALSE( l.contains( i.nKey ));
410 EXPECT_TRUE( l.empty() );
411 EXPECT_CONTAINER_SIZE( l, 0 );
413 // Apply retired pointer to clean links
414 List::gc::force_dispose();
416 for ( auto const& i : arr )
417 EXPECT_EQ( i.s.nDisposeCount, 3 );
420 for ( auto& i : arr )
421 EXPECT_TRUE( l.insert( i ));
423 EXPECT_FALSE( l.empty() );
424 EXPECT_CONTAINER_SIZE( l, nSize );
428 EXPECT_TRUE( l.empty() );
429 EXPECT_CONTAINER_SIZE( l, 0 );
431 // Apply retired pointer to clean links
432 List::gc::force_dispose();
433 for ( auto const& i : arr ) {
434 EXPECT_EQ( i.s.nDisposeCount, 4 );
435 EXPECT_FALSE( l.contains( i ));
439 for ( auto& i : arr )
440 EXPECT_TRUE( l.insert( i ) );
441 for ( auto& i : arr ) {
443 EXPECT_TRUE( l.contains( val ));
444 EXPECT_FALSE( l.unlink( val ));
445 EXPECT_TRUE( l.contains( val ) );
446 EXPECT_TRUE( l.unlink( i ));
447 EXPECT_FALSE( l.unlink( i ));
448 EXPECT_FALSE( l.contains( i ) );
450 EXPECT_TRUE( l.empty() );
451 EXPECT_CONTAINER_SIZE( l, 0 );
453 // Apply retired pointer to clean links
454 List::gc::force_dispose();
455 for ( auto const& i : arr ) {
456 EXPECT_EQ( i.s.nDisposeCount, 5 );
457 EXPECT_FALSE( l.contains( i ) );
460 // Iterators on empty list
463 auto itEnd = l.end();
464 auto cit = l.cbegin();
465 auto citEnd = l.cend();
467 EXPECT_TRUE( it == itEnd );
468 EXPECT_TRUE( it == cit );
469 EXPECT_TRUE( cit == citEnd );
474 EXPECT_TRUE( it == itEnd );
475 EXPECT_TRUE( it == cit );
476 EXPECT_TRUE( cit == citEnd );
480 template <typename List>
481 void test_ordered_iterator( List& l )
483 // Precondition: list is empty
484 // Postcondition: list is empty
486 static const size_t nSize = 20;
487 typedef typename List::value_type value_type;
488 value_type arr[nSize];
490 for ( size_t i = 0; i < nSize; ++i ) {
491 arr[i].nKey = static_cast<int>(i);
492 arr[i].nVal = arr[i].nKey * 10;
494 shuffle( arr, arr + nSize );
496 ASSERT_TRUE( l.empty() );
497 ASSERT_CONTAINER_SIZE( l, 0 );
499 for ( auto& i : arr )
500 EXPECT_TRUE( l.insert( i ) );
503 for ( auto it = l.begin(); it != l.end(); ++it ) {
504 EXPECT_EQ( it->nKey, key );
505 EXPECT_EQ( (*it).nKey, key );
510 for ( auto it = l.cbegin(); it != l.cend(); ++it ) {
511 EXPECT_EQ( it->nKey, key );
512 EXPECT_EQ( (*it).nKey, key );
517 List::gc::force_dispose();
518 for ( auto const& i : arr ) {
519 EXPECT_EQ( i.s.nDisposeCount, 1 );
520 EXPECT_FALSE( l.contains( i ) );
524 template <typename Iterator>
525 void check_ordered( Iterator first, Iterator last )
527 while ( first != last ) {
529 if ( ++it != last ) {
530 EXPECT_LT( first->nKey, it->nKey );
538 } // namespace cds_test
540 #endif // CDSUNIT_LIST_TEST_INTRUSIVE_ITERABLE_LIST_H