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.
31 #ifndef CDSUNIT_TREE_TEST_INTRUSIVE_TREE_H
32 #define CDSUNIT_TREE_TEST_INTRUSIVE_TREE_H
34 #include <cds_test/check_size.h>
35 #include <cds_test/fixture.h>
37 #include <cds/opt/hash.h>
38 // forward declaration
39 namespace cds { namespace intrusive {}}
43 namespace ci = cds::intrusive;
45 class intrusive_tree: public fixture
48 static size_t const kSize = 1000;
52 unsigned int nDisposeCount ; // count of disposer calling
53 unsigned int nFindCount ; // count of find-functor calling
54 unsigned int nUpdateNewCount;
55 unsigned int nUpdateCount;
56 mutable unsigned int nEraseCount;
65 memset( this, 0, sizeof( *this ) );
69 template <typename Node>
81 explicit base_int_item( int key )
86 base_int_item(int key, int val)
91 base_int_item( base_int_item const& v )
104 template <typename Node>
105 struct member_int_item: public stat
117 explicit member_int_item( int key )
122 member_int_item(int key, int val)
127 member_int_item(member_int_item const& v )
139 struct simple_item_counter {
142 simple_item_counter()
161 operator size_t() const
168 template <typename T>
171 bool operator ()(T const& v1, T const& v2 ) const
173 return v1.key() < v2.key();
176 bool operator()( T const& lhs, int rhs ) const
178 return lhs.key() < rhs;
181 bool operator()( int lhs, T const& rhs ) const
183 return lhs < rhs.key();
187 template <typename T>
190 int operator ()(T const& v1, T const& v2 ) const
192 if ( v1.key() < v2.key() )
194 return v1.key() > v2.key() ? 1 : 0;
197 bool operator()( T const& lhs, int rhs ) const
199 if ( lhs.key() < rhs )
201 return lhs.key() > rhs ? 1 : 0;
204 bool operator()( int lhs, T const& rhs ) const
206 if ( lhs < rhs.key() )
208 return lhs > rhs.key() ? 1 : 0;
215 explicit other_item( int k )
226 template <typename Q, typename T>
227 bool operator()( Q const& lhs, T const& rhs ) const
229 return lhs.key() < rhs.key();
235 template <typename T>
236 void operator ()( T * p )
243 template <class Tree>
246 // Precondition: tree is empty
247 // Postcondition: tree is empty
249 ASSERT_TRUE( t.empty() );
250 ASSERT_CONTAINER_SIZE( t, 0 );
251 size_t const nTreeSize = kSize;
253 typedef typename Tree::value_type value_type;
255 std::vector< value_type > data;
256 std::vector< size_t > indices;
257 data.reserve( kSize );
258 indices.reserve( kSize );
259 for ( size_t key = 0; key < kSize; ++key ) {
260 data.push_back( value_type( static_cast<int>( key )));
261 indices.push_back( key );
263 shuffle( indices.begin(), indices.end() );
266 for ( auto idx : indices ) {
267 auto& i = data[ idx ];
269 ASSERT_FALSE( t.contains( i.nKey ));
270 ASSERT_FALSE( t.contains( i ));
271 ASSERT_FALSE( t.contains( other_item( i.key()), other_less()));
272 ASSERT_FALSE( t.find( i.nKey, []( value_type&, int ) {} ));
273 ASSERT_FALSE( t.find_with( other_item( i.key()), other_less(), []( value_type&, other_item const& ) {} ));
275 std::pair<bool, bool> updResult;
277 updResult = t.update( i, []( bool bNew, value_type&, value_type& )
279 ASSERT_TRUE( false );
281 EXPECT_FALSE( updResult.first );
282 EXPECT_FALSE( updResult.second );
284 switch ( i.key() % 3 ) {
286 ASSERT_TRUE( t.insert( i ));
287 ASSERT_FALSE( t.insert( i ));
288 updResult = t.update( i, []( bool bNew, value_type& val, value_type& arg)
290 EXPECT_FALSE( bNew );
291 EXPECT_EQ( &val, &arg );
293 EXPECT_TRUE( updResult.first );
294 EXPECT_FALSE( updResult.second );
297 EXPECT_EQ( i.nUpdateNewCount, 0 );
298 ASSERT_TRUE( t.insert( i, []( value_type& v ) { ++v.nUpdateNewCount;} ));
299 EXPECT_EQ( i.nUpdateNewCount, 1 );
300 ASSERT_FALSE( t.insert( i, []( value_type& v ) { ++v.nUpdateNewCount;} ) );
301 EXPECT_EQ( i.nUpdateNewCount, 1 );
302 i.nUpdateNewCount = 0;
305 updResult = t.update( i, []( bool bNew, value_type& val, value_type& arg )
307 EXPECT_TRUE( false );
309 EXPECT_FALSE( updResult.first );
310 EXPECT_FALSE( updResult.second );
312 EXPECT_EQ( i.nUpdateNewCount, 0 );
313 updResult = t.update( i, []( bool bNew, value_type& val, value_type& arg )
316 EXPECT_EQ( &val, &arg );
317 ++val.nUpdateNewCount;
319 EXPECT_TRUE( updResult.first );
320 EXPECT_TRUE( updResult.second );
321 EXPECT_EQ( i.nUpdateNewCount, 1 );
322 i.nUpdateNewCount = 0;
324 EXPECT_EQ( i.nUpdateCount, 0 );
325 updResult = t.update( i, []( bool bNew, value_type& val, value_type& arg )
327 EXPECT_FALSE( bNew );
328 EXPECT_EQ( &val, &arg );
331 EXPECT_TRUE( updResult.first );
332 EXPECT_TRUE( updResult.second );
333 EXPECT_EQ( i.nUpdateCount, 1 );
339 ASSERT_TRUE( t.contains( i.nKey ) );
340 ASSERT_TRUE( t.contains( i ) );
341 ASSERT_TRUE( t.contains( other_item( i.key() ), other_less()));
342 EXPECT_EQ( i.nFindCount, 0 );
343 ASSERT_TRUE( t.find( i.nKey, []( value_type& v, int ) { ++v.nFindCount; } ));
344 EXPECT_EQ( i.nFindCount, 1 );
345 ASSERT_TRUE( t.find_with( other_item( i.key() ), other_less(), []( value_type& v, other_item const& ) { ++v.nFindCount; } ));
346 EXPECT_EQ( i.nFindCount, 2 );
347 ASSERT_TRUE( t.find( i, []( value_type& v, value_type& ) { ++v.nFindCount; } ) );
348 EXPECT_EQ( i.nFindCount, 3 );
350 ASSERT_FALSE( t.empty() );
351 ASSERT_CONTAINER_SIZE( t, nTreeSize );
353 std::for_each( data.begin(), data.end(), []( value_type& v ) { v.clear_stat(); });
356 shuffle( indices.begin(), indices.end() );
357 for ( auto idx : indices ) {
358 auto& i = data[ idx ];
360 ASSERT_TRUE( t.contains( i.nKey ) );
361 ASSERT_TRUE( t.contains( i ) );
362 ASSERT_TRUE( t.contains( other_item( i.key() ), other_less() ) );
363 EXPECT_EQ( i.nFindCount, 0 );
364 ASSERT_TRUE( t.find( i.nKey, []( value_type& v, int ) { ++v.nFindCount; } ) );
365 EXPECT_EQ( i.nFindCount, 1 );
366 ASSERT_TRUE( t.find_with( other_item( i.key() ), other_less(), []( value_type& v, other_item const& ) { ++v.nFindCount; } ) );
367 EXPECT_EQ( i.nFindCount, 2 );
370 switch ( i.key() % 6 ) {
372 ASSERT_FALSE( t.unlink( v ));
373 ASSERT_TRUE( t.unlink( i ));
374 ASSERT_FALSE( t.unlink( i ) );
377 ASSERT_TRUE( t.erase( i.key()));
378 ASSERT_FALSE( t.erase( i.key() ) );
381 ASSERT_TRUE( t.erase( v ));
382 ASSERT_FALSE( t.erase( v ) );
385 ASSERT_TRUE( t.erase_with( other_item( i.key()), other_less()));
386 ASSERT_FALSE( t.erase_with( other_item( i.key() ), other_less() ) );
389 EXPECT_EQ( i.nEraseCount, 0 );
390 ASSERT_TRUE( t.erase( v, []( value_type& val ) { ++val.nEraseCount; } ));
391 EXPECT_EQ( i.nEraseCount, 1 );
392 ASSERT_FALSE( t.erase( v, []( value_type& val ) { ++val.nEraseCount; } ));
393 EXPECT_EQ( i.nEraseCount, 1 );
396 EXPECT_EQ( i.nEraseCount, 0 );
397 ASSERT_TRUE( t.erase_with( other_item( i.key() ), other_less(), []( value_type& val ) { ++val.nEraseCount; } ));
398 EXPECT_EQ( i.nEraseCount, 1 );
399 ASSERT_FALSE( t.erase_with( other_item( i.key() ), other_less(), []( value_type& val ) { ++val.nEraseCount; } ));
400 EXPECT_EQ( i.nEraseCount, 1 );
404 ASSERT_FALSE( t.contains( i.nKey ));
405 ASSERT_FALSE( t.contains( i ));
406 ASSERT_FALSE( t.contains( other_item( i.key()), other_less()));
407 ASSERT_FALSE( t.find( i.nKey, []( value_type&, int ) {} ));
408 ASSERT_FALSE( t.find( i, []( value_type&, value_type const& ) {} ));
409 ASSERT_FALSE( t.find_with( other_item( i.key()), other_less(), []( value_type&, other_item const& ) {} ));
411 ASSERT_TRUE( t.empty() );
412 ASSERT_CONTAINER_SIZE( t, 0 );
414 // Force retiring cycle
415 Tree::gc::force_dispose();
416 for ( auto& i : data ) {
417 EXPECT_EQ( i.nDisposeCount, 1 );
421 for ( auto& i : data ) {
423 ASSERT_TRUE( t.insert( i ));
425 ASSERT_FALSE( t.empty() );
426 ASSERT_CONTAINER_SIZE( t, nTreeSize );
431 ASSERT_TRUE( t.empty());
432 ASSERT_CONTAINER_SIZE( t, 0 );
433 ASSERT_TRUE( t.begin() == t.end() );
434 ASSERT_TRUE( t.cbegin() == t.cend() );
436 // Force retiring cycle
437 Tree::gc::force_dispose();
438 for ( auto& i : data ) {
439 EXPECT_EQ( i.nDisposeCount, 1 );
444 } // namespace cds_test
446 #endif // #ifndef CDSUNIT_TREE_TEST_INTRUSIVE_TREE_H