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_SET_TEST_INTRUSIVE_FELDMAN_HASHSET_H
32 #define CDSUNIT_SET_TEST_INTRUSIVE_FELDMAN_HASHSET_H
34 #include <cds_test/check_size.h>
35 #include <cds_test/fixture.h>
37 #include <cds/opt/hash.h>
38 #include <functional> // ref
40 // forward declaration
41 namespace cds { namespace intrusive {}}
45 namespace ci = cds::intrusive;
46 namespace co = cds::opt;
48 class intrusive_feldman_hashset: public fixture
53 unsigned int nDisposeCount ; // count of disposer calling
54 unsigned int nFindCount ; // count of find-functor calling
55 unsigned int nInsertCount ;
56 mutable unsigned int nEraseCount;
65 memset( this, 0, sizeof( *this ) );
69 struct int_item: public stat
77 explicit int_item( int key )
82 int_item(int key, int val)
87 int_item( int_item const& v )
99 struct hash_accessor {
100 int operator()( int_item const& v ) const
106 struct simple_item_counter {
109 simple_item_counter()
128 operator size_t() const
135 int operator ()( int lhs, int rhs ) const
139 return lhs > rhs ? 1 : 0;
145 template <typename T>
146 void operator ()( T * p )
156 // Precondition: set is empty
157 // Postcondition: set is empty
159 ASSERT_TRUE( s.empty() );
160 ASSERT_CONTAINER_SIZE( s, 0 );
161 size_t const nSetSize = std::max( s.head_size() * 2, static_cast<size_t>(100) );
163 typedef typename Set::value_type value_type;
165 std::vector< value_type > data;
166 std::vector< size_t> indices;
167 data.reserve( nSetSize );
168 indices.reserve( nSetSize );
169 for ( size_t key = 0; key < nSetSize; ++key ) {
170 data.push_back( value_type( static_cast<int>( key )));
171 indices.push_back( key );
173 shuffle( indices.begin(), indices.end() );
176 for ( auto idx : indices ) {
177 auto& i = data[ idx ];
179 ASSERT_FALSE( s.contains( i.nKey ));
180 ASSERT_FALSE( s.find( i.nKey, []( value_type& ) {} ));
182 std::pair<bool, bool> updResult;
184 updResult = s.update( i, false );
185 EXPECT_FALSE( updResult.first );
186 EXPECT_FALSE( updResult.second );
188 switch ( i.key() % 3 ) {
190 ASSERT_TRUE( s.insert( i ));
191 ASSERT_FALSE( s.insert( i ));
192 updResult = s.update( i, false );
193 EXPECT_TRUE( updResult.first );
194 EXPECT_FALSE( updResult.second );
197 EXPECT_EQ( i.nInsertCount, 0 );
198 ASSERT_TRUE( s.insert( i, []( value_type& v ) { ++v.nInsertCount;} ));
199 EXPECT_EQ( i.nInsertCount, 1 );
200 ASSERT_FALSE( s.insert( i, []( value_type& v ) { ++v.nInsertCount;} ) );
201 EXPECT_EQ( i.nInsertCount, 1 );
205 updResult = s.update( i );
206 EXPECT_TRUE( updResult.first );
207 EXPECT_TRUE( updResult.second );
211 ASSERT_TRUE( s.contains( i.nKey ) );
212 EXPECT_EQ( i.nFindCount, 0 );
213 ASSERT_TRUE( s.find( i.nKey, []( value_type& v ) { ++v.nFindCount; } ));
214 EXPECT_EQ( i.nFindCount, 1 );
216 ASSERT_FALSE( s.empty() );
217 ASSERT_CONTAINER_SIZE( s, nSetSize );
219 std::for_each( data.begin(), data.end(), []( value_type& v ) { v.clear_stat(); });
222 shuffle( indices.begin(), indices.end() );
223 for ( auto idx : indices ) {
224 auto& i = data[ idx ];
226 ASSERT_TRUE( s.contains( i.nKey ) );
227 EXPECT_EQ( i.nFindCount, 0 );
228 ASSERT_TRUE( s.find( i.nKey, []( value_type& v ) { ++v.nFindCount; } ) );
229 EXPECT_EQ( i.nFindCount, 1 );
232 switch ( i.key() % 3 ) {
234 ASSERT_FALSE( s.unlink( v ));
235 ASSERT_TRUE( s.unlink( i ));
236 ASSERT_FALSE( s.unlink( i ) );
239 ASSERT_TRUE( s.erase( i.key()));
240 ASSERT_FALSE( s.erase( i.key() ) );
243 EXPECT_EQ( i.nEraseCount, 0 );
244 ASSERT_TRUE( s.erase( v.key(), []( value_type& val ) { ++val.nEraseCount; } ));
245 EXPECT_EQ( i.nEraseCount, 1 );
246 ASSERT_FALSE( s.erase( v.key(), []( value_type& val ) { ++val.nEraseCount; } ));
247 EXPECT_EQ( i.nEraseCount, 1 );
251 ASSERT_FALSE( s.contains( i.nKey ));
252 ASSERT_FALSE( s.find( i.nKey, []( value_type const& ) {} ));
254 ASSERT_TRUE( s.empty() );
255 ASSERT_CONTAINER_SIZE( s, 0 );
257 // Force retiring cycle
258 Set::gc::force_dispose();
259 for ( auto& i : data ) {
260 EXPECT_EQ( i.nDisposeCount, 1 );
263 // erase_at( iterator )
264 for ( auto& i : data ) {
266 ASSERT_TRUE( s.insert( i ) );
268 ASSERT_FALSE( s.empty() );
269 ASSERT_CONTAINER_SIZE( s, nSetSize );
271 for ( auto it = s.begin(); it != s.end(); ++it ) {
272 ASSERT_TRUE( s.erase_at( it ));
273 ASSERT_FALSE( s.erase_at( it ));
275 ASSERT_TRUE( s.empty() );
276 ASSERT_CONTAINER_SIZE( s, 0 );
278 // Force retiring cycle
279 Set::gc::force_dispose();
280 for ( auto& i : data ) {
281 EXPECT_EQ( i.nDisposeCount, 1 );
284 // erase_at( reverse_iterator )
285 for ( auto& i : data ) {
287 ASSERT_TRUE( s.insert( i ) );
289 ASSERT_FALSE( s.empty() );
290 ASSERT_CONTAINER_SIZE( s, nSetSize );
292 for ( auto it = s.rbegin(); it != s.rend(); ++it ) {
293 ASSERT_TRUE( s.erase_at( it ) );
294 ASSERT_FALSE( s.erase_at( it ) );
296 ASSERT_TRUE( s.empty() );
297 ASSERT_CONTAINER_SIZE( s, 0 );
299 // Force retiring cycle
300 Set::gc::force_dispose();
301 for ( auto& i : data ) {
302 EXPECT_EQ( i.nDisposeCount, 1 );
306 for ( auto& i : data ) {
308 ASSERT_TRUE( s.insert( i ));
310 ASSERT_FALSE( s.empty() );
311 ASSERT_CONTAINER_SIZE( s, nSetSize );
313 // Forward iterator test
314 for ( auto it = s.begin(); it != s.end(); ++it ) {
317 for ( auto it = s.cbegin(); it != s.cend(); ++it ) {
318 EXPECT_EQ( it->nFindCount, 1 );
321 // Reverse iterator test
322 for ( auto it = s.rbegin(); it != s.rend(); ++it ) {
325 for ( auto it = s.crbegin(); it != s.crend(); ++it ) {
326 EXPECT_EQ( it->nFindCount, 2 );
329 for ( auto& i : data ) {
330 EXPECT_EQ( i.nFindCount, 2 );
336 ASSERT_TRUE( s.empty());
337 ASSERT_CONTAINER_SIZE( s, 0 );
338 ASSERT_TRUE( s.begin() == s.end() );
339 ASSERT_TRUE( s.cbegin() == s.cend() );
341 // Force retiring cycle
342 Set::gc::force_dispose();
343 for ( auto& i : data ) {
344 EXPECT_EQ( i.nDisposeCount, 1 );
349 } // namespace cds_test
351 #endif // #ifndef CDSUNIT_SET_TEST_INTRUSIVE_FELDMAN_HASHSET_H