-//$$CDS-header$$
+/*
+ This file is a part of libcds - Concurrent Data Structures library
-#ifndef __CDS_CONTAINER_CUCKOO_SET_H
-#define __CDS_CONTAINER_CUCKOO_SET_H
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
-#include <cds/container/cuckoo_base.h>
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSLIB_CONTAINER_CUCKOO_SET_H
+#define CDSLIB_CONTAINER_CUCKOO_SET_H
+
+#include <cds/container/details/cuckoo_base.h>
#include <cds/details/binary_functor_wrapper.h>
namespace cds { namespace container {
struct make_cuckoo_set
{
typedef T value_type;
- typedef Traits original_type_traits;
- typedef typename original_type_traits::probeset_type probeset_type;
- static bool const store_hash = original_type_traits::store_hash;
- static unsigned int const store_hash_count = store_hash ? ((unsigned int) std::tuple_size< typename original_type_traits::hash::hash_tuple_type >::value) : 0;
+ typedef Traits original_traits;
+ typedef typename original_traits::probeset_type probeset_type;
+ static bool const store_hash = original_traits::store_hash;
+ static unsigned int const store_hash_count = store_hash ? ((unsigned int) std::tuple_size< typename original_traits::hash::hash_tuple_type >::value) : 0;
struct node_type: public intrusive::cuckoo::node<probeset_type, store_hash_count>
{
template <typename Pred, typename ReturnValue>
using predicate_wrapper = cds::details::binary_functor_wrapper< ReturnValue, Pred, node_type, value_accessor >;
- struct intrusive_traits: public original_type_traits
+ struct intrusive_traits: public original_traits
{
typedef intrusive::cuckoo::base_hook<
cds::intrusive::cuckoo::probeset_type< probeset_type >
,cds::intrusive::cuckoo::store_hash< store_hash_count >
> hook;
- typedef cds::intrusive::cuckoo::type_traits::disposer disposer;
+ typedef cds::intrusive::cuckoo::traits::disposer disposer;
typedef typename std::conditional<
- std::is_same< typename original_type_traits::equal_to, opt::none >::value
+ std::is_same< typename original_traits::equal_to, opt::none >::value
, opt::none
- , predicate_wrapper< typename original_type_traits::equal_to, bool >
+ , predicate_wrapper< typename original_traits::equal_to, bool >
>::type equal_to;
typedef typename std::conditional<
- std::is_same< typename original_type_traits::compare, opt::none >::value
+ std::is_same< typename original_traits::compare, opt::none >::value
, opt::none
- , predicate_wrapper< typename original_type_traits::compare, int >
+ , predicate_wrapper< typename original_traits::compare, int >
>::type compare;
typedef typename std::conditional<
- std::is_same< typename original_type_traits::less, opt::none >::value
+ std::is_same< typename original_traits::less, opt::none >::value
,opt::none
- ,predicate_wrapper< typename original_type_traits::less, bool >
+ ,predicate_wrapper< typename original_traits::less, bool >
>::type less;
- typedef opt::details::hash_list_wrapper< typename original_type_traits::hash, node_type, value_accessor > hash;
+ typedef opt::details::hash_list_wrapper< typename original_traits::hash, node_type, value_accessor > hash;
};
typedef intrusive::CuckooSet< node_type, intrusive_traits > type;
<b>About Cuckoo hashing</b>
[From "The Art of Multiprocessor Programming"]
- Cuckoo hashing is a hashing algorithm in which a newly added item displaces any earlier item
+ <a href="https://en.wikipedia.org/wiki/Cuckoo_hashing">Cuckoo hashing</a> is a hashing algorithm in which a newly added item displaces any earlier item
occupying the same slot. For brevity, a table is a k-entry array of items. For a hash set f size
N = 2k we use a two-entry array of tables, and two independent hash functions,
<tt> h0, h1: KeyRange -> 0,...,k-1</tt>
the average search complexity is <tt>O(PROBE_SET/2)</tt>.
However, the overhead of sorting can eliminate a gain of ordered search.
- The probe set is ordered if opt::compare or opt::less is specified in \p %CuckooSet
- declaration. Otherwise, the probe set is unordered and \p %CuckooSet must contain
- opt::equal_to option.
+ The probe set is ordered if \p compare or \p less is specified in \p Traits
+ template parameter. Otherwise, the probe set is unordered and \p Traits must contain
+ \p equal_to predicate.
Template arguments:
- \p T - the type stored in the set.
- - \p Traits - type traits. See cuckoo::type_traits for explanation.
+ - \p Traits - type traits. See cuckoo::traits for explanation.
It is possible to declare option-based set with cuckoo::make_traits metafunction result as \p Traits template argument.
- Template argument list \p Options... of cuckoo::make_traits metafunction are:
- - opt::hash - hash functor tuple, mandatory option. At least, two hash functors should be provided. All hash functor
- should be orthogonal (different): for each <tt> i,j: i != j => h[i](x) != h[j](x) </tt>.
- The hash functors are passed as <tt> std::tuple< H1, H2, ... Hn > </tt>. The number of hash functors specifies
- the number \p k - the count of hash tables in cuckoo hashing. If the compiler supports variadic templates
- then k is unlimited, otherwise up to 10 different hash functors are supported.
- - opt::mutex_policy - concurrent access policy.
- Available policies: cuckoo::striping, cuckoo::refinable.
- Default is cuckoo::striping.
- - opt::equal_to - key equality functor like \p std::equal_to.
- If this functor is defined then the probe-set will be unordered.
- If opt::compare or opt::less option is specified too, then the probe-set will be ordered
- and opt::equal_to will be ignored.
- - opt::compare - key comparison functor. No default functor is provided.
- If the option is not specified, the opt::less is used.
- If opt::compare or opt::less option is specified, then the probe-set will be ordered.
- - opt::less - specifies binary predicate used for key comparison. Default is \p std::less<T>.
- If opt::compare or opt::less option is specified, then the probe-set will be ordered.
- - opt::item_counter - the type of item counting feature. Default is \ref opt::v::sequential_item_counter.
- - opt::allocator - the allocator type using for allocating bucket tables.
- Default is \p CDS_DEFAULT_ALLOCATOR
- - opt::node_allocator - the allocator type using for allocating set's items. If this option
- is not specified then the type defined in opt::allocator option is used.
- - cuckoo::store_hash - this option reserves additional space in the node to store the hash value
- of the object once it's introduced in the container. When this option is used,
- the unordered container will store the calculated hash value in the node and rehashing operations won't need
- to recalculate the hash of the value. This option will improve the performance of unordered containers
- when rehashing is frequent or hashing the value is a slow operation. Default value is \p false.
- - \ref intrusive::cuckoo::probeset_type "cuckoo::probeset_type" - type of probe set, may be \p cuckoo::list or <tt>cuckoo::vector<Capacity></tt>,
- Default is \p cuckoo::list.
- - opt::stat - internal statistics. Possibly types: cuckoo::stat, cuckoo::empty_stat.
- Default is cuckoo::empty_stat
-
<b>Examples</b>
Cuckoo-set with list-based unordered probe set and storing hash values
};
// Declare type traits
- struct my_traits: public cds::container::cuckoo::type_traits
+ struct my_traits: public cds::container::cuckoo::traits
{
typedef my_data_equa_to equal_to;
typedef std::tuple< hash1, hash2 > hash;
// Declare type traits
// We use a vector of capacity 4 as probe-set container and store hash values in the node
- struct my_traits: public cds::container::cuckoo::type_traits
+ struct my_traits: public cds::container::cuckoo::traits
{
typedef my_data_compare compare;
typedef std::tuple< hash1, hash2 > hash;
\endcode
*/
- template <typename T, typename Traits = cuckoo::type_traits>
+ template <typename T, typename Traits = cuckoo::traits>
class CuckooSet:
#ifdef CDS_DOXYGEN_INVOKED
protected intrusive::CuckooSet<T, Traits>
public:
typedef T value_type ; ///< value type stored in the container
- typedef Traits options ; ///< traits
+ typedef Traits traits ; ///< traits
- typedef typename options::hash hash ; ///< hash functor tuple wrapped for internal use
- typedef typename base_class::hash_tuple_type hash_tuple_type ; ///< Type of hash tuple
+ typedef typename traits::hash hash; ///< hash functor tuple wrapped for internal use
+ typedef typename base_class::hash_tuple_type hash_tuple_type; ///< Type of hash tuple
- typedef typename base_class::mutex_policy mutex_policy ; ///< Concurrent access policy, see cuckoo::type_traits::mutex_policy
- typedef typename base_class::stat stat ; ///< internal statistics type
+ typedef typename base_class::mutex_policy mutex_policy; ///< Concurrent access policy, see cuckoo::traits::mutex_policy
+ typedef typename base_class::stat stat; ///< internal statistics type
- static bool const c_isSorted = base_class::c_isSorted ; ///< whether the probe set should be ordered
- static size_t const c_nArity = base_class::c_nArity ; ///< the arity of cuckoo hashing: the number of hash functors provided; minimum 2.
+ static bool const c_isSorted = base_class::c_isSorted; ///< whether the probe set should be ordered
+ static size_t const c_nArity = base_class::c_nArity; ///< the arity of cuckoo hashing: the number of hash functors provided; minimum 2.
- typedef typename base_class::key_equal_to key_equal_to ; ///< Key equality functor; used only for unordered probe-set
+ typedef typename base_class::key_equal_to key_equal_to; ///< Key equality functor; used only for unordered probe-set
- typedef typename base_class::key_comparator key_comparator ; ///< key comparing functor based on opt::compare and opt::less option setter. Used only for ordered probe set
+ typedef typename base_class::key_comparator key_comparator; ///< key comparing functor based on \p Traits::compare and \p Traits::less option setter. Used only for ordered probe set
- typedef typename base_class::allocator allocator ; ///< allocator type used for internal bucket table allocations
+ typedef typename base_class::allocator allocator; ///< allocator type used for internal bucket table allocations
/// Node allocator type
typedef typename std::conditional<
- std::is_same< typename options::node_allocator, opt::none >::value,
+ std::is_same< typename traits::node_allocator, opt::none >::value,
allocator,
- typename options::node_allocator
+ typename traits::node_allocator
>::type node_allocator;
/// item counter type
- typedef typename options::item_counter item_counter;
+ typedef typename traits::item_counter item_counter;
protected:
//@cond
//@endcond
public:
- static unsigned int const c_nDefaultProbesetSize = base_class::c_nDefaultProbesetSize ; ///< default probeset size
- static size_t const c_nDefaultInitialSize = base_class::c_nDefaultInitialSize ; ///< default initial size
- static unsigned int const c_nRelocateLimit = base_class::c_nRelocateLimit ; ///< Count of attempts to relocate before giving up
+ static unsigned int const c_nDefaultProbesetSize = base_class::c_nDefaultProbesetSize; ///< default probeset size
+ static size_t const c_nDefaultInitialSize = base_class::c_nDefaultInitialSize; ///< default initial size
+ static unsigned int const c_nRelocateLimit = base_class::c_nRelocateLimit; ///< Count of attempts to relocate before giving up
protected:
//@cond
CuckooSet(
hash_tuple_type&& h ///< hash functor tuple of type <tt>std::tuple<H1, H2, ... Hn></tt> where <tt> n == \ref c_nArity </tt>
)
- : base_class( std::forward<hash_tuple_type>(h) )
+ : base_class( std::forward<hash_tuple_type>(h))
{}
/// Constructs the set object with given probe set properties and hash functor tuple (move semantics)
, unsigned int nProbesetThreshold ///< probe set threshold, <tt>nProbesetThreshold < nProbesetSize</tt>. If 0, nProbesetThreshold = nProbesetSize - 1
, hash_tuple_type&& h ///< hash functor tuple of type <tt>std::tuple<H1, H2, ... Hn></tt> where <tt> n == \ref c_nArity </tt>
)
- : base_class( nInitialSize, nProbesetSize, nProbesetThreshold, std::forward<hash_tuple_type>(h) )
+ : base_class( nInitialSize, nProbesetSize, nProbesetThreshold, std::forward<hash_tuple_type>(h))
{}
/// Destructor clears the set
The type \p Q can differ from \ref value_type of items storing in the set.
Therefore, the \p value_type should be constructible from type \p Q.
- The user-defined functor is called only if the inserting is success. It can be passed by reference
- using <tt>boost::ref</tt>
+ The user-defined functor is called only if the inserting is success.
*/
template <typename Q, typename Func>
bool insert( Q const& val, Func f )
{
scoped_node_ptr pNode( alloc_node( val ));
- if ( base_class::insert( *pNode, [&f]( node_type& node ) { cds::unref(f)( node.m_val ); } )) {
+ if ( base_class::insert( *pNode, [&f]( node_type& node ) { f( node.m_val ); } )) {
pNode.release();
return true;
}
return false;
}
- /// Ensures that the \p val exists in the set
+ /// Updates the node
/**
- The operation performs inserting or changing data.
+ The operation performs inserting or changing data with lock-free manner.
- If the \p val key not found in the set, then the new item created from \p val
- is inserted into the set. Otherwise, the functor \p func is called with the item found.
- The functor \p Func should be a function with signature:
- \code
- void func( bool bNew, value_type& item, const Q& val );
- \endcode
- or a functor:
+ If the item \p val is not found in the set, then \p val is inserted into the set
+ iff \p bAllowInsert is \p true.
+ Otherwise, the functor \p func is called with item found.
+ The functor \p func signature is:
\code
struct my_functor {
void operator()( bool bNew, value_type& item, const Q& val );
};
\endcode
-
with arguments:
- \p bNew - \p true if the item has been inserted, \p false otherwise
- \p item - item of the set
- - \p val - argument \p val passed into the \p ensure function
+ - \p val - argument \p val passed into the \p %update() function
+ If new item has been inserted (i.e. \p bNew is \p true) then \p item and \p val arguments
+ refer to the same thing.
- The functor can change non-key fields of the \p item.
-
- You can pass \p func argument by value or by reference using <tt>boost::ref</tt>.
-
- Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
- \p second is true if new item has been added or \p false if the item with \p val key
+ Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
+ i.e. the node has been inserted or updated,
+ \p second is \p true if new item has been added or \p false if the item with \p key
already exists.
*/
template <typename Q, typename Func>
- std::pair<bool, bool> ensure( Q const& val, Func func )
+ std::pair<bool, bool> update( Q const& val, Func func, bool bAllowInsert = true )
{
scoped_node_ptr pNode( alloc_node( val ));
- std::pair<bool, bool> res = base_class::ensure( *pNode,
- [&val,&func](bool bNew, node_type& item, node_type const& ){ cds::unref(func)( bNew, item.m_val, val ); }
+ std::pair<bool, bool> res = base_class::update( *pNode,
+ [&val,&func](bool bNew, node_type& item, node_type const& ){ func( bNew, item.m_val, val ); },
+ bAllowInsert
);
if ( res.first && res.second )
pNode.release();
return res;
}
+ //@cond
+ template <typename Q, typename Func>
+ CDS_DEPRECATED("ensure() is deprecated, use update()")
+ std::pair<bool, bool> ensure( Q const& val, Func func )
+ {
+ return update( val, func, true );
+ }
+ //@endcond
/// Delete \p key from the set
/** \anchor cds_nonintrusive_CuckooSet_erase
template <typename Q, typename Predicate>
bool erase_with( Q const& key, Predicate pred )
{
- node_type * pNode = base_class::erase_with( key, typename maker::template predicate_wrapper<Predicate, bool>() );
+ CDS_UNUSED( pred );
+ node_type * pNode = base_class::erase_with( key, typename maker::template predicate_wrapper<Predicate, bool>());
if ( pNode ) {
free_node( pNode );
return true;
void operator()(value_type const& val);
};
\endcode
- The functor can be passed by value or by reference using <tt>boost:ref</tt>
Return \p true if key is found and deleted, \p false otherwise
*/
{
node_type * pNode = base_class::erase( key );
if ( pNode ) {
- cds::unref(f)( pNode->m_val );
+ f( pNode->m_val );
free_node( pNode );
return true;
}
template <typename Q, typename Predicate, typename Func>
bool erase_with( Q const& key, Predicate pred, Func f )
{
- node_type * pNode = base_class::erase_with( key, typename maker::template predicate_wrapper<Predicate, bool>() );
+ CDS_UNUSED( pred );
+ node_type * pNode = base_class::erase_with( key, typename maker::template predicate_wrapper<Predicate, bool>());
if ( pNode ) {
- cds::unref(f)( pNode->m_val );
+ f( pNode->m_val );
free_node( pNode );
return true;
}
\endcode
where \p item is the item found, \p val is the <tt>find</tt> function argument.
- You can pass \p f argument by value or by reference using <tt>boost::ref</tt> or cds::ref.
-
The functor can change non-key fields of \p item.
The \p val argument is non-const since it can be used as \p f functor destination i.e., the functor
can modify both arguments.
template <typename Q, typename Func>
bool find( Q& val, Func f )
{
- return base_class::find( val, [&f](node_type& item, Q& v) { cds::unref(f)( item.m_val, v );});
+ return base_class::find( val, [&f](node_type& item, Q& v) { f( item.m_val, v );});
}
+ //@cond
+ template <typename Q, typename Func>
+ bool find( Q const& val, Func f )
+ {
+ return base_class::find( val, [&f](node_type& item, Q const& v) { f( item.m_val, v );});
+ }
+ //@endcond
/// Find the key \p val using \p pred predicate for comparing
/**
template <typename Q, typename Predicate, typename Func>
bool find_with( Q& val, Predicate pred, Func f )
{
+ CDS_UNUSED( pred );
return base_class::find_with( val, typename maker::template predicate_wrapper<Predicate, bool>(),
- [&f](node_type& item, Q& v) { cds::unref(f)( item.m_val, v );});
+ [&f](node_type& item, Q& v) { f( item.m_val, v );});
}
-
- /// Find the key \p val
- /** \anchor cds_nonintrusive_CuckooSet_find_cfunc
-
- The function searches the item with key equal to \p val and calls the functor \p f for item found.
- The interface of \p Func functor is:
- \code
- struct functor {
- void operator()( value_type& item, Q const& val );
- };
- \endcode
- where \p item is the item found, \p val is the <tt>find</tt> function argument.
-
- You can pass \p f argument by value or by reference using <tt>boost::ref</tt> or cds::ref.
-
- The functor can change non-key fields of \p item.
-
- The type \p Q can differ from \ref value_type of items storing in the container.
- Therefore, the \p value_type should be comparable with type \p Q.
-
- The function returns \p true if \p val is found, \p false otherwise.
- */
- template <typename Q, typename Func>
- bool find( Q const& val, Func f )
- {
- return base_class::find( val, [&f](node_type& item, Q const& v) { cds::unref(f)( item.m_val, v );});
- }
-
- /// Find the key \p val using \p pred predicate for comparing
- /**
- The function is an analog of \ref cds_nonintrusive_CuckooSet_find_cfunc "find(Q const&, Func)"
- but \p pred is used for key comparison.
- If you use ordered cuckoo set, then \p Predicate should have the interface and semantics like \p std::less.
- If you use unordered cuckoo set, then \p Predicate should have the interface and semantics like \p std::equal_to.
- \p pred must imply the same element order as the comparator used for building the set.
- */
+ //@cond
template <typename Q, typename Predicate, typename Func>
bool find_with( Q const& val, Predicate pred, Func f )
{
+ CDS_UNUSED( pred );
return base_class::find_with( val, typename maker::template predicate_wrapper<Predicate, bool>(),
- [&f](node_type& item, Q const& v) { cds::unref(f)( item.m_val, v );});
+ [&f](node_type& item, Q const& v) { f( item.m_val, v );});
}
+ //@endcond
- /// Find the key \p val
- /** \anchor cds_nonintrusive_CuckooSet_find_val
-
- The function searches the item with key equal to \p val
+ /// Checks whether the set contains \p key
+ /**
+ The function searches the item with key equal to \p key
and returns \p true if it is found, and \p false otherwise.
-
- Note the hash functor specified for class \p Traits template parameter
- should accept a parameter of type \p Q that can be not the same as \ref value_type.
*/
template <typename Q>
- bool find( Q const& val )
+ bool contains( Q const& key )
+ {
+ return base_class::find( key, [](node_type&, Q const&) {});
+ }
+ //@cond
+ template <typename Q>
+ CDS_DEPRECATED("the function is deprecated, use contains()")
+ bool find( Q const& key )
{
- return base_class::find( val, [](node_type&, Q const&) {});
+ return contains( key );
}
+ //@endcond
- /// Find the key \p val using \p pred predicate for comparing
+ /// Checks whether the set contains \p key using \p pred predicate for searching
/**
- The function is an analog of \ref cds_nonintrusive_CuckooSet_find_val "find(Q const&)"
- but \p pred is used for key comparison.
- If you use ordered cuckoo set, then \p Predicate should have the interface and semantics like \p std::less.
- If you use unordered cuckoo set, then \p Predicate should have the interface and semantics like \p std::equal_to.
- \p pred must imply the same element order as the comparator used for building the set.
+ The function is similar to <tt>contains( key )</tt> but \p pred is used for key comparing.
+ \p Less functor has the interface like \p std::less.
+ \p Less must imply the same element order as the comparator used for building the set.
*/
template <typename Q, typename Predicate>
- bool find_with( Q const& val, Predicate pred )
+ bool contains( Q const& key, Predicate pred )
{
- return base_class::find_with( val, typename maker::template predicate_wrapper<Predicate, bool>(), [](node_type&, Q const&) {});
+ CDS_UNUSED( pred );
+ return base_class::find_with( key, typename maker::template predicate_wrapper<Predicate, bool>(), [](node_type&, Q const&) {});
}
+ //@cond
+ template <typename Q, typename Predicate>
+ CDS_DEPRECATED("the function is deprecated, use contains()")
+ bool find_with( Q const& key, Predicate pred )
+ {
+ return contains( key, pred );
+ }
+ //@endcond
/// Clears the set
/**
*/
void clear()
{
- return base_class::clear_and_dispose( node_disposer() );
+ return base_class::clear_and_dispose( node_disposer());
}
/// Checks if the set is empty
{
return base_class::mutex_policy_statistics();
}
-
};
}} // namespace cds::container
-#endif //#ifndef __CDS_CONTAINER_CUCKOO_SET_H
+#endif //#ifndef CDSLIB_CONTAINER_CUCKOO_SET_H