3 #ifndef CDSLIB_INTRUSIVE_DETAILS_MULTILEVEL_HASHSET_BASE_H
4 #define CDSLIB_INTRUSIVE_DETAILS_MULTILEVEL_HASHSET_BASE_H
6 #include <memory.h> // memcmp, memcpy
9 #include <cds/intrusive/details/base.h>
10 #include <cds/opt/compare.h>
11 #include <cds/algo/atomic.h>
12 #include <cds/algo/split_bitstring.h>
13 #include <cds/details/marked_ptr.h>
14 #include <cds/urcu/options.h>
16 namespace cds { namespace intrusive {
18 /// MultiLevelHashSet ordered list related definitions
19 /** @ingroup cds_intrusive_helper
21 namespace multilevel_hashset {
23 /// Hash accessor option
25 @copydetails traits::hash_accessor
27 template <typename Accessor>
28 struct hash_accessor {
30 template <typename Base> struct pack: public Base
32 typedef Accessor hash_accessor;
37 /// Head node allocator option
39 @copydetails traits::head_node_allocator
41 template <typename Accessor>
42 struct head_node_allocator {
44 template <typename Base> struct pack: public Base
46 typedef Accessor head_node_allocator;
51 /// Array node allocator option
53 @copydetails traits::array_node_allocator
55 template <typename Accessor>
56 struct array_node_allocator {
58 template <typename Base> struct pack: public Base
60 typedef Accessor array_node_allocator;
65 /// \p MultiLevelHashSet internal statistics
66 template <typename EventCounter = cds::atomicity::event_counter>
68 typedef EventCounter event_counter ; ///< Event counter type
70 event_counter m_nInsertSuccess; ///< Number of success \p insert() operations
71 event_counter m_nInsertFailed; ///< Number of failed \p insert() operations
72 event_counter m_nInsertRetry; ///< Number of attempts to insert new item
73 event_counter m_nUpdateNew; ///< Number of new item inserted for \p update()
74 event_counter m_nUpdateExisting; ///< Number of existing item updates
75 event_counter m_nUpdateFailed; ///< Number of failed \p update() call
76 event_counter m_nUpdateRetry; ///< Number of attempts to update the item
77 event_counter m_nEraseSuccess; ///< Number of successful \p erase(), \p unlink(), \p extract() operations
78 event_counter m_nEraseFailed; ///< Number of failed \p erase(), \p unlink(), \p extract() operations
79 event_counter m_nEraseRetry; ///< Number of attempts to \p erase() an item
80 event_counter m_nFindSuccess; ///< Number of successful \p find() and \p get() operations
81 event_counter m_nFindFailed; ///< Number of failed \p find() and \p get() operations
83 event_counter m_nExpandNodeSuccess; ///< Number of succeeded attempts converting data node to array node
84 event_counter m_nExpandNodeFailed; ///< Number of failed attempts converting data node to array node
85 event_counter m_nSlotChanged; ///< Number of array node slot changing by other thread during an operation
86 event_counter m_nSlotConverting; ///< Number of events when we encounter a slot while it is converting to array node
89 void onInsertSuccess() { ++m_nInsertSuccess; }
90 void onInserFailed() { ++m_nInsertFailed; }
91 void onInsertRetry() { ++m_nInsertRetry; }
92 void onUpdateNew() { ++m_nUpdateNew; }
93 void onUpdateExisting() { ++m_nUpdateExisting; }
94 void onUpdateFailed() { ++m_nUpdateFailed; }
95 void onUpdateRetry() { ++m_nUpdateRetry; }
96 void onEraseSuccess() { ++m_nEraseSuccess; }
97 void onEraseFailed() { ++m_nEraseFailed; }
98 void onEraseRetry() { ++m_nEraseRetry; }
99 void onFindSuccess() { ++m_nFindSuccess; }
100 void onFindFailed() { ++m_nFindFailed; }
102 void onExpandNodeSuccess() { ++m_nExpandNodeSuccess; }
103 void onExpandNodeFailed() { ++m_nExpandNodeFailed; }
104 void onSlotChanged() { ++m_nSlotChanged; }
105 void onSlotConverting() { ++m_nSlotConverting; }
109 /// \p MultiLevelHashSet empty internal statistics
112 void onInsertSuccess() const {}
113 void onInsertFailed() const {}
114 void onInsertRetry() const {}
115 void onUpdateNew() const {}
116 void onUpdateExisting() const {}
117 void onUpdateFailed() const {}
118 void onUpdateRetry() const {}
119 void onEraseSuccess() const {}
120 void onEraseFailed() const {}
121 void onEraseRetry() const {}
122 void onFindSuccess() const {}
123 void onFindFailed() const {}
125 void onExpandNodeSuccess() const {}
126 void onExpandNodeFailed() const {}
127 void onSlotChanged() const {}
128 void onSlotConverting() const {}
132 /// MultiLevelHashSet traits
135 /// Mandatory functor to get hash value from data node
137 It is most-important feature of \p MultiLevelHashSet.
138 That functor must return a reference to fixed-sized hash value of data node.
139 The return value of that functor specifies the type of hash value.
143 typedef uint8_t hash_type[32]; // 256-bit hash type
145 hash_type hash; // 256-bit hash value
150 struct foo_hash_accessor {
151 hash_type const& operator()( foo const& d ) const
158 typedef opt::none hash_accessor;
160 /// Disposer for removing data nodes
161 typedef opt::v::empty_disposer disposer;
163 /// Hash comparing functor
165 No default functor is provided.
166 If the option is not specified, the \p less option is used.
168 typedef opt::none compare;
170 /// Specifies binary predicate used for hash compare.
172 If the option is not specified, \p memcmp() -like bit-wise hash comparator is used
173 because the hash value is treated as fixed-sized bit-string.
175 typedef opt::none less;
179 The item counting is an important part of \p MultiLevelHashSet algorithm:
180 the \p empty() member function depends on correct item counting.
181 Therefore, \p atomicity::empty_item_counter is not allowed as a type of the option.
183 Default is \p atomicity::item_counter.
185 typedef cds::atomicity::item_counter item_counter;
187 /// Head node allocator
189 Allocator for head node. That allocator uses only in the set's constructor for allocating
190 main head array and in the destructor for destroying the head array.
191 Default is \ref CDS_DEFAULT_ALLOCATOR
193 typedef CDS_DEFAULT_ALLOCATOR head_node_allocator;
195 /// Array node allocator
197 Allocator for array nodes. That allocator is used for creating \p arrayNode when the set grows.
198 The size of each array node is fixed.
199 Default is \ref CDS_DEFAULT_ALLOCATOR
201 typedef CDS_DEFAULT_ALLOCATOR array_node_allocator;
203 /// C++ memory ordering model
205 Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
206 or \p opt::v::sequential_consistent (sequentially consisnent memory model).
208 typedef opt::v::relaxed_ordering memory_model;
210 /// Back-off strategy
211 typedef cds::backoff::Default back_off;
213 /// Internal statistics
215 By default, internal statistics is disabled (\p multilevel_hashset::empty_stat).
216 Use \p multilevel_hashset::stat to enable it.
218 typedef empty_stat stat;
220 /// RCU deadlock checking policy (only for \ref cds_intrusive_MultilevelHashSet_rcu "RCU-based MultilevelHashSet")
222 List of available policy see \p opt::rcu_check_deadlock
224 typedef opt::v::rcu_throw_deadlock rcu_check_deadlock;
227 /// Metafunction converting option list to \p multilevel_hashset::traits
229 Supported \p Options are:
230 - \p multilevel_hashset::hash_accessor - mandatory option, hash accessor functor.
231 @copydetails traits::hash_accessor
232 - \p multilevel_hashset::head_node_allocator - head node allocator.
233 @copydetails traits::head_node_allocator
234 - \p multilevel_hashset::array_node_allocator - array node allocator.
235 @copydetails traits::array_node_allocator
236 - \p opt::compare - hash comparison functor. No default functor is provided.
237 If the option is not specified, the \p opt::less is used.
238 - \p opt::less - specifies binary predicate used for hash comparison.
239 If the option is not specified, \p memcmp() -like bit-wise hash comparator is used
240 because the hash value is treated as fixed-sized bit-string.
241 - \p opt::back_off - back-off strategy used. If the option is not specified, the \p cds::backoff::Default is used.
242 - \p opt::disposer - the functor used for disposing removed data node. Default is \p opt::v::empty_disposer. Due the nature
243 of GC schema the disposer may be called asynchronously.
244 - \p opt::item_counter - the type of item counting feature.
245 The item counting is an important part of \p MultiLevelHashSet algorithm:
246 the \p empty() member function depends on correct item counting.
247 Therefore, \p atomicity::empty_item_counter is not allowed as a type of the option.
248 Default is \p atomicity::item_counter.
249 - \p opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
250 or \p opt::v::sequential_consistent (sequentially consisnent memory model).
251 - \p opt::stat - internal statistics. By default, it is disabled (\p multilevel_hashset::empty_stat).
252 To enable it use \p multilevel_hashset::stat
253 - \p opt::rcu_check_deadlock - a deadlock checking policy for \ref cds_intrusive_MultilevelHashSet_rcu "RCU-based MultilevelHashSet"
254 Default is \p opt::v::rcu_throw_deadlock
256 template <typename... Options>
259 # ifdef CDS_DOXYGEN_INVOKED
260 typedef implementation_defined type ; ///< Metafunction result
262 typedef typename cds::opt::make_options<
263 typename cds::opt::find_type_traits< traits, Options... >::type
269 /// Bit-wise memcmp-based comparator for hash value \p T
270 template <typename T>
271 struct bitwise_compare
273 /// Compares \p lhs and \p rhs
276 - <tt> < 0</tt> if <tt>lhs < rhs</tt>
277 - <tt>0</tt> if <tt>lhs == rhs</tt>
278 - <tt> > 0</tt> if <tt>lhs > rhs</tt>
280 int operator()( T const& lhs, T const& rhs ) const
282 return memcmp( &lhs, &rhs, sizeof(T));
288 template <typename HashType, typename UInt = size_t >
289 using hash_splitter = cds::algo::split_bitstring< HashType, UInt >;
290 } // namespace details
293 } // namespace multilevel_hashset
296 // Forward declaration
297 template < class GC, typename T, class Traits = multilevel_hashset::traits >
298 class MultiLevelHashSet;
301 }} // namespace cds::intrusive
303 #endif // #ifndef CDSLIB_INTRUSIVE_DETAILS_MULTILEVEL_HASHSET_BASE_H