Added new option hash_size for FeldmanHashSet
authorkhizmax <khizmax@gmail.com>
Fri, 11 Nov 2016 15:14:10 +0000 (18:14 +0300)
committerkhizmax <khizmax@gmail.com>
Fri, 11 Nov 2016 15:14:10 +0000 (18:14 +0300)
15 files changed:
cds/algo/split_bitstring.h
cds/container/details/feldman_hashset_base.h
cds/container/feldman_hashset_rcu.h
cds/container/impl/feldman_hashset.h
cds/intrusive/details/feldman_hashset_base.h
cds/intrusive/feldman_hashset_rcu.h
cds/intrusive/impl/feldman_hashset.h
test/unit/intrusive-set/intrusive_feldman_hashset_dhp.cpp
test/unit/intrusive-set/intrusive_feldman_hashset_hp.cpp
test/unit/intrusive-set/test_intrusive_feldman_hashset.h
test/unit/intrusive-set/test_intrusive_feldman_hashset_rcu.h
test/unit/set/feldman_hashset_dhp.cpp
test/unit/set/feldman_hashset_hp.cpp
test/unit/set/test_feldman_hashset.h
test/unit/set/test_feldman_hashset_rcu.h

index 738accbb6c25ba42f3df20873c4c184491c2a478..f74d4ea7aabd5f992a38d663f6f1aa043f0735cc 100644 (file)
@@ -43,19 +43,25 @@ namespace cds { namespace algo {
 
         The splitter stores a const reference to bit-string, not a copy.
         The maximum count of bits that can be cut in a single call is <tt> sizeof(UInt) * 8 </tt>
 
         The splitter stores a const reference to bit-string, not a copy.
         The maximum count of bits that can be cut in a single call is <tt> sizeof(UInt) * 8 </tt>
+
+        Template parameters:
+        - \p BitString - a fixed-sized type that interprets as bit string
+        - \p BitStringSize - the siZe of \p BitString in bytes, default is <tt>sizeof( BitString )</tt>
+        - \p UInt - an unsigned integer, return type of \p cut()
     */
     */
-    template <typename BitString, typename UInt = typename std::conditional< sizeof(BitString) % sizeof(size_t) == 0, size_t, unsigned >::type >
+    template <typename BitString, size_t BitStringSize = sizeof( BitString ), typename UInt = typename std::conditional< BitStringSize % sizeof(size_t) == 0, size_t, unsigned >::type >
     class split_bitstring
     {
     public:
         typedef BitString bitstring;    ///< Bit-string type
         typedef UInt      uint_type;    ///< Bit-string portion type
     class split_bitstring
     {
     public:
         typedef BitString bitstring;    ///< Bit-string type
         typedef UInt      uint_type;    ///< Bit-string portion type
+        static CDS_CONSTEXPR size_t const c_bitstring_size = BitStringSize; ///< size of \p BitString in bytes
 
         //@cond
 
         //@cond
-        static CDS_CONSTEXPR size_t const c_nHashSize   = (sizeof(bitstring) + sizeof(uint_type) - 1) / sizeof(uint_type);
+        static CDS_CONSTEXPR size_t const c_nHashSize   = (c_bitstring_size + sizeof(uint_type) - 1) / sizeof(uint_type);
         static CDS_CONSTEXPR size_t const c_nBitPerByte = 8;
         static CDS_CONSTEXPR size_t const c_nBitPerByte = 8;
-        static CDS_CONSTEXPR size_t const c_nBitPerHash = sizeof(bitstring) * c_nBitPerByte;
-        static CDS_CONSTEXPR size_t const c_nBitPerInt  = sizeof(uint_type) * c_nBitPerByte;
+        static CDS_CONSTEXPR size_t const c_nBitPerHash = c_bitstring_size * c_nBitPerByte;
+        static CDS_CONSTEXPR size_t const c_nBitPerInt  = sizeof( uint_type ) * c_nBitPerByte;
         //@endcond
 
     public:
         //@endcond
 
     public:
index cbdd143125f81cb79564b35cd4bc0bc7ea76b9e5..3f2ab94b9a8c215f138c241339e7c2ec0e961b8f 100644 (file)
@@ -46,6 +46,13 @@ namespace cds { namespace container {
         template <typename Accessor>
         using hash_accessor = cds::intrusive::feldman_hashset::hash_accessor< Accessor >;
 
         template <typename Accessor>
         using hash_accessor = cds::intrusive::feldman_hashset::hash_accessor< Accessor >;
 
+        /// Hash size option
+        /**
+            @copydetails cds::intrusive::feldman_hashset::traits::hash_size
+        */
+        template <size_t Size>
+        using hash_size = cds::intrusive::feldman_hashset::hash_size< Size >;
+
         /// \p FeldmanHashSet internal statistics, see cds::intrusive::feldman_hashset::stat
         template <typename EventCounter = cds::atomicity::event_counter>
         using stat = cds::intrusive::feldman_hashset::stat< EventCounter >;
         /// \p FeldmanHashSet internal statistics, see cds::intrusive::feldman_hashset::stat
         template <typename EventCounter = cds::atomicity::event_counter>
         using stat = cds::intrusive::feldman_hashset::stat< EventCounter >;
@@ -69,6 +76,14 @@ namespace cds { namespace container {
             */
             typedef cds::opt::none hash_accessor;
 
             */
             typedef cds::opt::none hash_accessor;
 
+            /// The size of hash value in bytes
+            /**
+                @copydetails cds::intrusive::feldman_hashset::traits::hash_size
+            */
+            enum : size_t {
+                hash_size = 0
+            };
+
             /// Hash comparing functor
             /**
                 @copydetails cds::intrusive::feldman_hashset::traits::compare
             /// Hash comparing functor
             /**
                 @copydetails cds::intrusive::feldman_hashset::traits::compare
@@ -126,6 +141,8 @@ namespace cds { namespace container {
             Supported \p Options are:
             - \p feldman_hashset::hash_accessor - mandatory option, hash accessor functor.
                 @copydetails traits::hash_accessor
             Supported \p Options are:
             - \p feldman_hashset::hash_accessor - mandatory option, hash accessor functor.
                 @copydetails traits::hash_accessor
+            - \p feldman_hashset::hash_size - the size of hash value in bytes.
+                @copydetails traits::hash_size
             - \p opt::allocator - item allocator
                 @copydetails traits::allocator
             - \p opt::node_allocator - array node allocator.
             - \p opt::allocator - item allocator
                 @copydetails traits::allocator
             - \p opt::node_allocator - array node allocator.
index 82d3b6dc478d8e4454ee3d159b85f73dc016f8bb..dc4e48a14721e1c455d3acd0d830e287dd3718d6 100644 (file)
@@ -112,6 +112,9 @@ namespace cds { namespace container {
         static CDS_CONSTEXPR const bool c_bExtractLockExternal = false; ///< Group of \p extract_xxx functions does not require external locking
         typedef typename base_class::exempt_ptr exempt_ptr; ///< pointer to extracted node
 
         static CDS_CONSTEXPR const bool c_bExtractLockExternal = false; ///< Group of \p extract_xxx functions does not require external locking
         typedef typename base_class::exempt_ptr exempt_ptr; ///< pointer to extracted node
 
+        /// The size of hash_type in bytes, see \p feldman_hashset::traits::hash_size for explanation
+        static CDS_CONSTEXPR size_t const c_hash_size = base_class::c_hash_size;
+
         /// Level statistics
         typedef feldman_hashset::level_statistics level_statistics;
 
         /// Level statistics
         typedef feldman_hashset::level_statistics level_statistics;
 
index d0ca0d5a1670721c0328ed1c8dcc94c5d7aa54d5..69ef63081d04dc5c8cd0d14e24cfcca8d41d3510 100644 (file)
@@ -148,6 +148,9 @@ namespace cds { namespace container {
         /// Count of hazard pointers required
         static CDS_CONSTEXPR size_t const c_nHazardPtrCount = base_class::c_nHazardPtrCount;
 
         /// Count of hazard pointers required
         static CDS_CONSTEXPR size_t const c_nHazardPtrCount = base_class::c_nHazardPtrCount;
 
+        /// The size of hash_type in bytes, see \p feldman_hashset::traits::hash_size for explanation
+        static CDS_CONSTEXPR size_t const c_hash_size = base_class::c_hash_size;
+
         /// Level statistics
         typedef feldman_hashset::level_statistics level_statistics;
 
         /// Level statistics
         typedef feldman_hashset::level_statistics level_statistics;
 
index 94902af2c7b9e25209dc5f82583faae986eb606c..9d167a5b0783075e21fd7eb0ded57dabbf020386 100644 (file)
@@ -61,6 +61,22 @@ namespace cds { namespace intrusive {
             //@endcond
         };
 
             //@endcond
         };
 
+        // Hash size option
+        /**
+            @copydetails traits::hash_size
+        */
+        template <size_t Size>
+        struct hash_size {
+            //@cond
+            template <typename Base> struct pack: public Base
+            {
+                enum: size_t {
+                    hash_size = Size
+                };
+            };
+            //@endcond
+        };
+
         /// \p FeldmanHashSet internal statistics
         template <typename EventCounter = cds::atomicity::event_counter>
         struct stat {
         /// \p FeldmanHashSet internal statistics
         template <typename EventCounter = cds::atomicity::event_counter>
         struct stat {
@@ -163,6 +179,26 @@ namespace cds { namespace intrusive {
             */
             typedef cds::opt::none hash_accessor;
 
             */
             typedef cds::opt::none hash_accessor;
 
+            /// The size of hash value in bytes
+            /**
+                By default, the size of hash value is <tt>sizeof( hash_type )</tt>.
+                Sometimes it is not correct, for example, for that 6-byte struct \p static_assert will be thrown:
+                \code
+                struct key_type {
+                    uint32_t    key1;
+                    uint16_t    subkey;
+                };
+
+                static_assert( sizeof( key_type ) == 6, "Key type size mismatch" );
+                \endcode
+                For that case you can specify \p hash_size explicitly.
+
+                Value \p 0 means <tt>sizeof( hash_type )</tt>.
+            */
+            enum : size_t {
+                hash_size = 0
+            };
+
             /// Disposer for removing data nodes
             typedef cds::intrusive::opt::v::empty_disposer disposer;
 
             /// Disposer for removing data nodes
             typedef cds::intrusive::opt::v::empty_disposer disposer;
 
@@ -192,7 +228,7 @@ namespace cds { namespace intrusive {
 
             /// Array node allocator
             /**
 
             /// Array node allocator
             /**
-                Allocator for array nodes. That allocator is used for creating \p headNode and \p arrayNode when the set grows.
+                Allocator for array nodes. The allocator is used for creating \p headNode and \p arrayNode when the set grows.
                 Default is \ref CDS_DEFAULT_ALLOCATOR
             */
             typedef CDS_DEFAULT_ALLOCATOR node_allocator;
                 Default is \ref CDS_DEFAULT_ALLOCATOR
             */
             typedef CDS_DEFAULT_ALLOCATOR node_allocator;
@@ -226,6 +262,8 @@ namespace cds { namespace intrusive {
             Supported \p Options are:
             - \p feldman_hashset::hash_accessor - mandatory option, hash accessor functor.
                 @copydetails traits::hash_accessor
             Supported \p Options are:
             - \p feldman_hashset::hash_accessor - mandatory option, hash accessor functor.
                 @copydetails traits::hash_accessor
+            - \p feldman_hashset::hash_size - the size of hash value in bytes.
+                @copydetails traits::hash_size
             - \p opt::node_allocator - array node allocator.
                 @copydetails traits::node_allocator
             - \p opt::compare - hash comparison functor. No default functor is provided.
             - \p opt::node_allocator - array node allocator.
                 @copydetails traits::node_allocator
             - \p opt::compare - hash comparison functor. No default functor is provided.
@@ -300,8 +338,8 @@ namespace cds { namespace intrusive {
 
         //@cond
         namespace details {
 
         //@cond
         namespace details {
-            template <typename HashType >
-            using hash_splitter = cds::algo::split_bitstring< HashType >;
+            template <typename HashType, size_t HashSize >
+            using hash_splitter = cds::algo::split_bitstring< HashType, HashSize >;
 
             struct metrics {
                 size_t  head_node_size;     // power-of-two
 
             struct metrics {
                 size_t  head_node_size;     // power-of-two
@@ -365,7 +403,10 @@ namespace cds { namespace intrusive {
                 feldman_hashset::bitwise_compare< hash_type >
             >::type hash_comparator;
 
                 feldman_hashset::bitwise_compare< hash_type >
             >::type hash_comparator;
 
-            typedef feldman_hashset::details::hash_splitter< hash_type > hash_splitter;
+            /// The size of hash_type in bytes, see \p traits::hash_size for explanation
+            static CDS_CONSTEXPR size_t const c_hash_size = traits::hash_size == 0 ? sizeof( hash_type ) : traits::hash_size;
+
+            typedef feldman_hashset::details::hash_splitter< hash_type, c_hash_size > hash_splitter;
 
             enum node_flags {
                 flag_array_converting = 1,   ///< the cell is converting from data node to an array node
 
             enum node_flags {
                 flag_array_converting = 1,   ///< the cell is converting from data node to an array node
@@ -422,7 +463,7 @@ namespace cds { namespace intrusive {
 
         public:
             multilevel_array(size_t head_bits, size_t array_bits )
 
         public:
             multilevel_array(size_t head_bits, size_t array_bits )
-                : m_Metrics(feldman_hashset::details::metrics::make(head_bits, array_bits, sizeof(hash_type)))
+                : m_Metrics(feldman_hashset::details::metrics::make( head_bits, array_bits, c_hash_size ))
                 , m_Head( alloc_head_node())
             {}
 
                 , m_Head( alloc_head_node())
             {}
 
index b0b5f512a61744c17efbb42de1af06c452f9804a..af4519901be1aaadbf8893c9c91a6a784b1cab10 100644 (file)
@@ -113,6 +113,9 @@ namespace cds { namespace intrusive {
 
         using exempt_ptr = cds::urcu::exempt_ptr< gc, value_type, value_type, disposer, void >; ///< pointer to extracted node
 
 
         using exempt_ptr = cds::urcu::exempt_ptr< gc, value_type, value_type, disposer, void >; ///< pointer to extracted node
 
+        /// The size of hash_type in bytes, see \p feldman_hashset::traits::hash_size for explanation
+        static CDS_CONSTEXPR size_t const c_hash_size = base_class::c_hash_size;
+
         //@cond
         typedef feldman_hashset::level_statistics level_statistics;
         //@endcond
         //@cond
         typedef feldman_hashset::level_statistics level_statistics;
         //@endcond
index bcebf4fd44d0b88b9dcd5c0d0d93aef68d20a0e9..9b6d9b807c5615263652c1afe64ee35295751b7c 100644 (file)
@@ -145,6 +145,9 @@ namespace cds { namespace intrusive {
         /// Count of hazard pointers required
         static CDS_CONSTEXPR size_t const c_nHazardPtrCount = 2;
 
         /// Count of hazard pointers required
         static CDS_CONSTEXPR size_t const c_nHazardPtrCount = 2;
 
+        /// The size of hash_type in bytes, see \p feldman_hashset::traits::hash_size for explanation
+        static CDS_CONSTEXPR size_t const c_hash_size = base_class::c_hash_size;
+
         /// Level statistics
         typedef feldman_hashset::level_statistics level_statistics;
 
         /// Level statistics
         typedef feldman_hashset::level_statistics level_statistics;
 
index 95377f40c7d5372b6d8cbfbf92216cd509299a3e..fffa02f9de42d0df78124a943081b044d606416e 100644 (file)
@@ -143,4 +143,23 @@ namespace {
         test( s );
     }
 
         test( s );
     }
 
+    TEST_F( IntrusiveFeldmanHashSet_DHP, explicit_hash_size )
+    {
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef base_class::hash_accessor2 hash_accessor;
+            enum: size_t {
+                hash_size = sizeof( std::declval<key_val>().nKey )
+            };
+            typedef base_class::cmp2 compare;
+            typedef mock_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+
+        typedef ci::FeldmanHashSet< gc_type, int_item2, traits > set_type;
+
+        set_type s( 8, 3 );
+        test( s );
+    }
+
 } // namespace
 } // namespace
index 6e65a08e710c552f1d749944b281318f1730a3c4..c8e9e534a982385a30af2ef16fce2a03bc0e5485 100644 (file)
@@ -144,4 +144,23 @@ namespace {
         test( s );
     }
 
         test( s );
     }
 
+    TEST_F( IntrusiveFeldmanHashSet_HP, explicit_hash_size )
+    {
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef base_class::hash_accessor2 hash_accessor;
+            enum: size_t {
+                hash_size = sizeof( std::declval<key_val>().nKey )
+            };
+            typedef base_class::cmp2 compare;
+            typedef mock_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+
+        typedef ci::FeldmanHashSet< gc_type, int_item2, traits > set_type;
+
+        set_type s( 8, 3 );
+        test( s );
+    }
+
 } // namespace
 } // namespace
index 1409e8a9a29b711667477963c4fe6a83a53e86b4..da71af1c4b64a03421fb6866083d1cf3cf9e7bce 100644 (file)
@@ -47,8 +47,8 @@ namespace cds_test {
     public:
         struct stat
         {
     public:
         struct stat
         {
-            unsigned int nDisposeCount  ;   // count of disposer calling
-            unsigned int nFindCount     ;   // count of find-functor calling
+            unsigned int nDisposeCount;   // count of disposer calling
+            unsigned int nFindCount;   // count of find-functor calling
             unsigned int nInsertCount;
             mutable unsigned int nEraseCount;
 
             unsigned int nInsertCount;
             mutable unsigned int nEraseCount;
 
@@ -59,7 +59,7 @@ namespace cds_test {
 
             void clear_stat()
             {
 
             void clear_stat()
             {
-                memset( this, 0, sizeof( *this ));
+                memset( this, 0, sizeof( *this ) );
             }
         };
 
             }
         };
 
@@ -76,9 +76,9 @@ namespace cds_test {
                 , nVal( key )
             {}
 
                 , nVal( key )
             {}
 
-            int_item(int key, int val)
+            int_item( int key, int val )
                 : nKey( key )
                 : nKey( key )
-                , nVal(val)
+                , nVal( val )
             {}
 
             int_item( int_item const& v )
             {}
 
             int_item( int_item const& v )
@@ -93,6 +93,53 @@ namespace cds_test {
             }
         };
 
             }
         };
 
+        struct key_val {
+            int nKey;
+            int nVal;
+
+            key_val()
+            {}
+
+            key_val( int key )
+                : nKey( key )
+                , nVal( key )
+            {}
+
+            key_val( int key, int val )
+                : nKey( key )
+                , nVal( val )
+            {}
+
+            key_val( key_val const& v )
+                : nKey( v.nKey )
+                , nVal( v.nVal )
+            {}
+
+            int key() const
+            {
+                return nKey;
+            }
+        };
+
+        struct int_item2: public key_val, public stat
+        {
+            int_item2()
+            {}
+
+            explicit int_item2( int key )
+                : key_val( key )
+            {}
+
+            int_item2( int key, int val )
+                : key_val( key, val )
+            {}
+
+            int_item2( int_item2 const& v )
+                : key_val( v )
+                , stat()
+            {}
+        };
+
         struct hash_accessor {
             int operator()( int_item const& v ) const
             {
         struct hash_accessor {
             int operator()( int_item const& v ) const
             {
@@ -100,6 +147,13 @@ namespace cds_test {
             }
         };
 
             }
         };
 
+        struct hash_accessor2 {
+            key_val const& operator()( int_item2 const& v ) const
+            {
+                return v;
+            }
+        };
+
         struct simple_item_counter {
             size_t  m_nCount;
 
         struct simple_item_counter {
             size_t  m_nCount;
 
@@ -137,6 +191,15 @@ namespace cds_test {
             }
         };
 
             }
         };
 
+        struct cmp2 {
+            int operator ()( key_val const& lhs, key_val const& rhs ) const
+            {
+                if ( lhs.key() < rhs.key() )
+                    return -1;
+                return lhs.key() > rhs.key() ? 1 : 0;
+            }
+        };
+
         struct mock_disposer
         {
             template <typename T>
         struct mock_disposer
         {
             template <typename T>
index 6b5c1fc270055ebc08f42dafc84afb9db0871b2a..3f9436328c8c172f9b01f50cb1f296d6cf5912ad 100644 (file)
@@ -223,10 +223,29 @@ TYPED_TEST_P( IntrusiveFeldmanHashSet, stat )
     this->test( s );
 }
 
     this->test( s );
 }
 
+TYPED_TEST_P( IntrusiveFeldmanHashSet, explicit_hash_size )
+{
+    struct traits: public ci::feldman_hashset::traits
+    {
+        typedef typename TestFixture::hash_accessor2 hash_accessor;
+        enum: size_t {
+            hash_size = sizeof( std::declval<key_val>().nKey )
+        };
+        typedef typename TestFixture::cmp2 compare;
+        typedef typename TestFixture::mock_disposer disposer;
+        typedef ci::feldman_hashset::stat<> stat;
+    };
+
+    typedef ci::FeldmanHashSet< typename TestFixture::rcu_type, typename TestFixture::int_item2, traits > set_type;
+
+    set_type s( 8, 3 );
+    this->test( s );
+}
+
 // GCC 5: All test names should be written on single line, otherwise a runtime error will be encountered like as
 // "No test named <test_name> can be found in this test case"
 REGISTER_TYPED_TEST_CASE_P( IntrusiveFeldmanHashSet,
 // GCC 5: All test names should be written on single line, otherwise a runtime error will be encountered like as
 // "No test named <test_name> can be found in this test case"
 REGISTER_TYPED_TEST_CASE_P( IntrusiveFeldmanHashSet,
-    compare, less, cmpmix, backoff, stat
+    compare, less, cmpmix, backoff, stat, explicit_hash_size
     );
 
 
     );
 
 
index 8d96bf8e501506360414dcc95eba33a930b761ba..9c4269a8d288cce1c172cbcbd6b5d1a4d56aed86 100644 (file)
@@ -156,4 +156,21 @@ namespace {
         test( s );
     }
 
         test( s );
     }
 
+    TEST_F( FeldmanHashSet_DHP, explicit_hash_size )
+    {
+        struct set_traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash2 hash_accessor;
+            enum: size_t {
+                hash_size = sizeof( std::declval<key_val>().nKey )
+            };
+            typedef cmp2 compare;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< gc_type, int_item2, set_traits > set_type;
+
+        set_type s( 1, 1 );
+        test( s );
+    }
+
 } // namespace
 } // namespace
index 0c07155291570f4a607df18fb4453d6f83248871..43d888df1ad9ded396ce42b5a94c4faccb33127d 100644 (file)
@@ -157,4 +157,21 @@ namespace {
         test( s );
     }
 
         test( s );
     }
 
+    TEST_F( FeldmanHashSet_HP, explicit_hash_size )
+    {
+        struct set_traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash2 hash_accessor;
+            enum: size_t {
+                hash_size = sizeof( std::declval<key_val>(). nKey )
+            };
+            typedef cmp2 compare;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< gc_type, int_item2, set_traits > set_type;
+
+        set_type s( 1, 1 );
+        test( s );
+    }
+
 } // namespace
 } // namespace
index 4536455d36f24968abb8b5cd620983804bd589de..a7d88bbd135bd8f803a9abc9a35e8f95093a8d6b 100644 (file)
@@ -129,6 +129,72 @@ namespace cds_test {
             }
         };
 
             }
         };
 
+        struct key_val {
+            int nKey;
+            int nVal;
+
+            key_val()
+            {}
+
+            key_val( int key )
+                : nKey( key )
+                , nVal( key )
+            {}
+
+            key_val( int key, int val )
+                : nKey( key )
+                , nVal( val )
+            {}
+
+            key_val( key_val const& v )
+                : nKey( v.nKey )
+                , nVal( v.nVal )
+            {}
+
+            int key() const
+            {
+                return nKey;
+            }
+        };
+
+        struct int_item2: public key_val, public stat
+        {
+            std::string strVal;
+
+            int_item2()
+            {}
+
+            explicit int_item2( int key )
+                : key_val( key )
+            {}
+
+            int_item2( int key, int val )
+                : key_val( key, val )
+            {}
+
+            int_item2( int_item2 const& v )
+                : key_val( v )
+                , stat()
+                , strVal( v.strVal )
+            {}
+
+            int_item2( int_item2&& v )
+                : key_val( v )
+                , stat()
+                , strVal( std::move( v.strVal ))
+            {}
+
+            int_item2( int k, std::string&& s )
+                : key_val( k, k * 2 )
+                , strVal( std::move( s ) )
+            {}
+
+            explicit int_item2( other_item const& s )
+                : key_val( s.key(), s.key() * 2 )
+            {}
+        };
+
+
         struct get_hash {
             int operator()( int_item const& i ) const
             {
         struct get_hash {
             int operator()( int_item const& i ) const
             {
@@ -146,6 +212,23 @@ namespace cds_test {
             }
         };
 
             }
         };
 
+        struct get_hash2 {
+            key_val const& operator()( int_item2 const& i ) const
+            {
+                return i;
+            }
+
+            key_val operator()( other_item const& i ) const
+            {
+                return key_val( i.key() );
+            }
+
+            key_val operator()( int i ) const
+            {
+                return key_val( i );
+            }
+        };
+
         struct simple_item_counter {
             size_t  m_nCount;
 
         struct simple_item_counter {
             size_t  m_nCount;
 
@@ -184,6 +267,15 @@ namespace cds_test {
             }
         };
 
             }
         };
 
+        struct cmp2 {
+            int operator ()( key_val const& v1, key_val const& v2 ) const
+            {
+                if ( v1.key() < v2.key() )
+                    return -1;
+                return v1.key() > v2.key() ? 1 : 0;
+            }
+        };
+
         struct other_less {
             template <typename Q, typename T>
             bool operator()( Q const& lhs, T const& rhs ) const
         struct other_less {
             template <typename Q, typename T>
             bool operator()( Q const& lhs, T const& rhs ) const
index 2ecc1bfdc004742aa5835c7b3469c7d1fad8dc83..e7016faefe8e531331de6e48f1aa5133f13a581e 100644 (file)
@@ -280,10 +280,30 @@ namespace {
         this->test( s );
     }
 
         this->test( s );
     }
 
+    TYPED_TEST_P( FeldmanHashSet, explicit_hash_size )
+    {
+        typedef typename TestFixture::rcu_type rcu_type;
+        typedef typename TestFixture::int_item2 int_item;
+        typedef typename TestFixture::get_hash2 get_hash2;
+
+        struct set_traits: public cc::feldman_hashset::traits
+        {
+            enum: size_t {
+                hash_size = sizeof( std::declval<int_item2>().nKey )
+            };
+            typedef get_hash2 hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< rcu_type, int_item2, set_traits > set_type;
+
+        set_type s( 8, 4 );
+        this->test( s );
+    }
+
     // GCC 5: All test names should be written on single line, otherwise a runtime error will be encountered like as
     // "No test named <test_name> can be found in this test case"
     REGISTER_TYPED_TEST_CASE_P( FeldmanHashSet,
     // GCC 5: All test names should be written on single line, otherwise a runtime error will be encountered like as
     // "No test named <test_name> can be found in this test case"
     REGISTER_TYPED_TEST_CASE_P( FeldmanHashSet,
-        defaulted, compare, less, cmpmix, item_counting, backoff, stat
+        defaulted, compare, less, cmpmix, item_counting, backoff, stat, explicit_hash_size
         );
 } // namespace
 
         );
 } // namespace