3 #ifndef CDSLIB_CONTAINER_DETAILS_BRONSON_AVLTREE_BASE_H
4 #define CDSLIB_CONTAINER_DETAILS_BRONSON_AVLTREE_BASE_H
6 #include <cds/container/details/base.h>
7 #include <cds/opt/compare.h>
8 #include <cds/urcu/options.h>
9 #include <cds/sync/spinlock.h>
10 #include <cds/sync/injecting_monitor.h>
12 namespace cds { namespace container {
14 /// BronsonAVLTree related declarations
15 namespace bronson_avltree {
17 template <typename Key, typename T, typename SyncMonitor >
21 template <typename Node, typename T, typename SyncMonitor>
24 typedef Node node_type;
25 typedef T mapped_type;
26 typedef uint32_t version_type; ///< version type (internal)
32 version_flags = shrinking | unlinked
33 // the rest is version counter
36 atomics::atomic< int > m_nHeight; ///< Node height
37 atomics::atomic<version_type> m_nVersion; ///< Version bits
38 atomics::atomic<node_type *> m_pParent; ///< Parent node
39 atomics::atomic<node_type *> m_pLeft; ///< Left child
40 atomics::atomic<node_type *> m_pRight; ///< Right child
41 typename SyncMonitor::node_injection m_SyncMonitorInjection; ///< @ref cds_sync_monitor "synchronization monitor" injected data
42 atomics::atomic<mapped_type *> m_pValue; ///< Value
49 , m_pParent( nullptr )
55 link_node( int nHeight, version_type version, node_type * pParent, node_type * pLeft, node_type * pRight )
56 : m_nHeight( nHeight )
57 , m_nVersion( version )
58 , m_pParent( pParent )
64 atomics::atomic<node_type *>& child( int nDirection )
66 assert( nDirection != 0 );
67 return nDirection < 0 ? m_pLeft : m_pRight;
70 void child( node_type * pChild, int nDirection, atomics::memory_order order )
72 assert( nDirection != 0 );
74 m_pLeft.store( pChild, order );
76 m_pRight.store( pChild, order );
79 version_type version( atomics::memory_order order ) const
81 return m_nVersion.load( order );
84 void version( version_type ver, atomics::memory_order order )
86 m_nVersion.store( ver, order );
89 int height( atomics::memory_order order ) const
91 return m_nHeight.load( order );
94 void height( int h, atomics::memory_order order )
96 m_nHeight.store( h, order );
99 template <typename BackOff>
100 void wait_until_shrink_completed( atomics::memory_order order ) const
103 while ( is_shrinking( order ) )
107 bool is_unlinked( atomics::memory_order order ) const
109 return m_nVersion.load( order ) == unlinked;
112 bool is_shrinking( atomics::memory_order order ) const
114 return (m_nVersion.load( order ) & shrinking) != 0;
117 mapped_type * value( atomics::memory_order order ) const
119 return m_pValue.load( order );
122 bool is_valued( atomics::memory_order order ) const
124 return value( order ) != nullptr;
131 /// BronsonAVLTree internal node
132 template <typename Key, typename T, typename SyncMonitor >
133 struct node<Key, T*, SyncMonitor>: public link_node< node<Key, T*, SyncMonitor>, T, SyncMonitor >
136 typedef link_node< node<Key, T*, SyncMonitor>, T, SyncMonitor > base_class;
139 typedef Key key_type; ///< key type
140 typedef T mapped_type; ///< value type
141 typedef typename base_class::version_type version_type;
143 key_type const m_key; ///< Key
144 node * m_pNextRemoved; ///< thread-local list of removed node
148 template <typename Q>
151 , m_key( std::forward<Q>( key ) )
152 , m_pNextRemoved( nullptr )
155 template <typename Q>
156 node( Q&& key, int nHeight, version_type version, node * pParent, node * pLeft, node * pRight )
157 : base_class( nHeight, version, pParent, pLeft, pRight )
158 , m_key( std::forward<Q>( key ) )
159 , m_pNextRemoved( nullptr )
164 /// Base value type for BronsonAVLTreeMap
166 If value type for \p BronsonAVLTreeMap is based on this struct,
167 the map will support some additional methods like \p BronsonAVLTreeMap::get().
168 Moreover, the disposer behaviour is different for ordinal values and
169 values based on \p %bronson_avltree::value:
170 - for ordinal value, its disposer is called immediately after removing
171 the node from the tree. It this case it is not possible to support
172 map's methods that return raw pointer to the tree's value.
173 - if the value type is based on \p %bronson_avltree::value,
174 i.e. <tt>std::is_base_of( bronson_avltree::value, value_type )::value</tt> is \p true,
175 the disposer is called via full RCU cycle. It means that under
176 RCU lock the methods returning raw pointer can be implemented.
181 value * m_pNextRetired;
184 : m_pNextRetired(nullptr)
189 /// BronsonAVLTreeMap internal statistics
190 template <typename Counter = cds::atomicity::event_counter>
192 typedef Counter event_counter; ///< Event counter type
194 event_counter m_nFindSuccess; ///< Count of success \p find() call
195 event_counter m_nFindFailed; ///< Count of failed \p find() call
196 event_counter m_nFindRetry; ///< Count of retries during \p find()
197 event_counter m_nFindWaitShrinking; ///< Count of waiting until shrinking completed duting \p find() call
199 event_counter m_nInsertSuccess; ///< Count of inserting data node
200 event_counter m_nRelaxedInsertFailed; ///< Count of false creating of data nodes (only if @ref bronson_avltree::relaxed_insert "relaxed insertion" is enabled)
201 event_counter m_nInsertRetry; ///< Count of insert retries via concurrent operations
202 event_counter m_nUpdateWaitShrinking; ///< Count of waiting until shrinking completed during \p update() call
203 event_counter m_nUpdateRetry; ///< Count of update retries via concurrent operations
204 event_counter m_nUpdateRootWaitShrinking; ///< Count of waiting until root shrinking completed duting \p update() call
205 event_counter m_nUpdateSuccess; ///< Count of updating data node
206 event_counter m_nUpdateUnlinked; ///< Count of updating of unlinked node attempts
207 event_counter m_nDisposedNode; ///< Count of disposed node
208 event_counter m_nDisposedValue; ///< Count of disposed value
209 event_counter m_nExtractedValue; ///< Count of extracted value
210 event_counter m_nRemoveRetry; ///< Count o erase/extract retries
211 event_counter m_nRemoveWaitShrinking; ///< ount of waiting until shrinking completed during \p erase() or \p extract() call
212 event_counter m_nRemoveRootWaitShrinking; ///< Count of waiting until root shrinking completed duting \p erase() or \p extract() call
214 event_counter m_nRightRotation; ///< Count of single right rotation
215 event_counter m_nLeftRotation; ///< Count of single left rotation
216 event_counter m_nLeftRightRotation; ///< Count of double left-over-right rotation
217 event_counter m_nRightLeftRotation; ///< Count of double right-over-left rotation
220 void onFindSuccess() { ++m_nFindSuccess ; }
221 void onFindFailed() { ++m_nFindFailed ; }
222 void onFindRetry() { ++m_nFindRetry ; }
223 void onFindWaitShrinking() { ++m_nFindWaitShrinking; }
225 void onInsertSuccess() { ++m_nInsertSuccess ; }
226 void onRelaxedInsertFailed() { ++m_nRelaxedInsertFailed; }
227 void onInsertRetry() { ++m_nInsertRetry ; }
228 void onUpdateWaitShrinking() { ++m_nUpdateWaitShrinking; }
229 void onUpdateRetry() { ++m_nUpdateRetry; }
230 void onUpdateRootWaitShrinking() { ++m_nUpdateRootWaitShrinking; }
231 void onUpdateSuccess() { ++m_nUpdateSuccess; }
232 void onUpdateUnlinked() { ++m_nUpdateUnlinked; }
233 void onDisposeNode() { ++m_nDisposedNode; }
234 void onDisposeValue() { ++m_nDisposedValue; }
235 void onExtractValue() { ++m_nExtractedValue; }
236 void onRemoveRetry() { ++m_nRemoveRetry; }
237 void onRemoveWaitShrinking() { ++m_nRemoveWaitShrinking; }
239 void onRotateRight() { ++m_nRightRotation; }
240 void onRotateLeft() { ++m_nLeftRotation; }
241 void onRotateRightOverLeft() { ++m_nRightLeftRotation; }
242 void onRotateLeftOverRight() { ++m_nLeftRghtRotation; }
246 /// BronsonAVLTreeMap empty statistics
249 void onFindSuccess() const {}
250 void onFindFailed() const {}
251 void onFindRetry() const {}
252 void onFindWaitShrinking() const {}
254 void onInsertSuccess() const {}
255 void onRelaxedInsertFailed() const {}
256 void onInsertRetry() const {}
257 void onUpdateWaitShrinking() const {}
258 void onUpdateRetry() const {}
259 void onUpdateRootWaitShrinking() const {}
260 void onUpdateSuccess() const {}
261 void onUpdateUnlinked() const {}
262 void onDisposeNode() const {}
263 void onDisposeValue() const {}
264 void onExtractValue() const {}
265 void onRemoveRetry() const {}
266 void onRemoveWaitShrinking() const {}
267 void onRemoveRootWaitShrinking() const {}
269 void onRotateRight() const {}
270 void onRotateLeft() const {}
271 void onRotateRightOverLeft() const {}
272 void onRotateLeftOverRight() const {}
276 /// Option to allow relaxed insert into Bronson et al AVL-tree
278 By default, this opton is disabled and the new node is created under its parent lock.
279 In this case, it is guaranteed the new node will be attached to its parent.
280 On the other hand, constructing of the new node can be too complex to make it under the lock,
281 that can lead to lock contention.
283 When this option is enabled, the new node is created before locking the parent node.
284 After that, the parent is locked and checked whether the new node may be attached to the parent.
285 In this case, false node creating can be performed, but locked section can be significantly small.
287 template <bool Enable>
288 struct relaxed_insert {
290 template <typename Base> struct pack : public Base
292 enum { relaxed_insert = Enable };
297 /// BronsnAVLTreeMap traits
299 Note that there are two main specialization of Bronson et al AVL-tree:
300 - pointer-oriented - the tree node stores an user-provided pointer to value: <tt>BronsonAVLTreeMap<GC, Key, T *, Traits> </tt>
301 - data-oriented - the tree node contains a copy of values: <tt>BronsonAVLTreeMap<GC, Key, T, Traits> </tt> where \p T is not a pointer type.
303 Depends on tree specialization, different traits member can be used.
307 /// Key comparison functor
309 No default functor is provided. If the option is not specified, the \p less is used.
311 See \p cds::opt::compare option description for functor interface.
313 You should provide \p compare or \p less functor.
315 typedef opt::none compare;
317 /// Specifies binary predicate used for key compare.
319 See \p cds::opt::less option description for predicate interface.
321 You should provide \p compare or \p less functor.
323 typedef opt::none less;
325 /// Allocator for internal node
326 typedef CDS_DEFAULT_ALLOCATOR node_allocator;
328 /// Allocator for node's value (not used in \p BronsonAVLTreeMap<RCU, Key, T*, Traits> specialisation)
329 typedef CDS_DEFAULT_ALLOCATOR allocator;
331 /// Disposer (only for pointer-oriented tree specialization)
333 The functor used for dispose removed values.
334 The user-provided disposer is used only for pointer-oriented tree specialization
335 like \p BronsonAVLTreeMap<GC, Key, T*, Traits>. When the node becomes the rounting node without value,
336 the disposer will be called to signal that the memory for the value can be safely freed.
337 Default is \ref cds::intrusive::opt::delete_disposer "cds::container::opt::v::delete_disposer<>" which calls \p delete operator.
339 typedef opt::v::delete_disposer<> disposer;
341 /// @ref cds_sync_monitor "Synchronization monitor" type for node-level locking
342 typedef cds::sync::injecting_monitor<cds::sync::spin> sync_monitor;
344 /// Enable relaxed insertion.
346 About relaxed insertion see \p bronson_avltree::relaxed_insert option.
347 By default, this option is disabled.
349 static bool const relaxed_insert = false;
353 The type for item counter, by default it is disabled (\p atomicity::empty_item_counter).
354 To enable it use \p atomicity::item_counter
356 typedef atomicity::empty_item_counter item_counter;
358 /// C++ memory ordering model
360 List of available memory ordering see \p opt::memory_model
362 typedef opt::v::relaxed_ordering memory_model;
364 /// Internal statistics
366 By default, internal statistics is disabled (\p ellen_bintree::empty_stat).
367 To enable it use \p ellen_bintree::stat.
369 typedef empty_stat stat;
371 /// Back-off strategy
372 typedef cds::backoff::empty back_off;
374 /// RCU deadlock checking policy (only for \ref cds_container_BronsonAVLTreeMap_rcu "RCU-based BronsonAVLTree")
376 List of available options see \p opt::rcu_check_deadlock
378 typedef cds::opt::v::rcu_throw_deadlock rcu_check_deadlock;
381 /// Metafunction converting option list to BronsonAVLTreeMap traits
383 Note that there are two main specialization of Bronson et al AVL-tree:
384 - pointer-oriented - the tree node stores an user-provided pointer to value: <tt>BronsonAVLTreeMap<GC, Key, T *, Traits> </tt>
385 - data-oriented - the tree node contains a copy of values: <tt>BronsonAVLTreeMap<GC, Key, T, Traits> </tt> where \p T is not a pointer type.
387 Depends on tree specialization, different options can be specified.
390 - \p opt::compare - key compare functor. No default functor is provided.
391 If the option is not specified, \p %opt::less is used.
392 - \p opt::less - specifies binary predicate used for key compare. At least \p %opt::compare or \p %opt::less should be defined.
393 - \p opt::node_allocator - the allocator for internal nodes. Default is \ref CDS_DEFAULT_ALLOCATOR.
394 - \p opt::allocator - the allocator for node's value. Default is \ref CDS_DEFAULT_ALLOCATOR.
395 This option is not used in \p BronsonAVLTreeMap<RCU, Key, T*, Traits> specialisation
396 - \ref cds::intrusive::opt::disposer "container::opt::disposer" - the functor used for dispose removed values.
397 The user-provided disposer is used only for pointer-oriented tree specialization
398 like \p BronsonAVLTreeMap<GC, Key, T*, Traits>. When the node becomes the rounting node without value,
399 the disposer will be called to signal that the memory for the value can be safely freed.
400 Default is \ref cds::intrusive::opt::delete_disposer "cds::container::opt::v::delete_disposer<>" which calls \p delete operator.
401 Due the nature of GC schema the disposer may be called asynchronously.
402 - \p opt::sync_monitor - @ref cds_sync_monitor "synchronization monitor" type for node-level locking,
403 default is \p cds::sync::injecting_monitor<cds::sync::spin>
404 - \p bronson_avltree::relaxed_insert - enable (\p true) or disable (\p false, the default)
405 @ref bronson_avltree::relaxed_insert "relaxed insertion"
406 - \p opt::item_counter - the type of item counting feature, by default it is disabled (\p atomicity::empty_item_counter)
407 To enable it use \p atomicity::item_counter
408 - \p opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
409 or \p opt::v::sequential_consistent (sequentially consisnent memory model).
410 - \p opt::stat - internal statistics, by default it is disabled (\p bronson_avltree::empty_stat)
411 To enable statistics use \p \p bronson_avltree::stat
412 - \p opt::backoff - back-off strategy, by default no strategy is used (\p cds::backoff::empty)
413 - \p opt::rcu_check_deadlock - a deadlock checking policy for RCU-based tree, default is \p opt::v::rcu_throw_deadlock
415 template <typename... Options>
417 # ifdef CDS_DOXYGEN_INVOKED
418 typedef implementation_defined type ; ///< Metafunction result
420 typedef typename cds::opt::make_options<
421 typename cds::opt::find_type_traits< traits, Options... >::type
426 } // namespace bronson_avltree
429 template < class GC, typename Key, typename T, class Traits = bronson_avltree::traits >
430 class BronsonAVLTreeMap;
432 }} // namespace cds::container
435 #endif // #ifndef CDSLIB_CONTAINER_DETAILS_BRONSON_AVLTREE_BASE_H