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 >
135 typedef link_node< node<Key, T*, SyncMonitor>, T, SyncMonitor > base_class;
137 typedef Key key_type; ///< key type
138 typedef T mapped_type; ///< value type
139 typedef typename base_class::version_type version_type;
141 key_type const m_key; ///< Key
142 node * m_pNextRemoved; ///< thread-local list of removed node
146 template <typename Q>
149 , m_key( std::forward<Q>( key ) )
150 , m_pNextRemoved( nullptr )
153 template <typename Q>
154 node( Q&& key, int nHeight, version_type version, node * pParent, node * pLeft, node * pRight )
155 : base_class( nHeight, version, pParent, pLeft, pRight )
156 , m_key( std::forward<Q>( key ) )
157 , m_pNextRemoved( nullptr )
162 /// BronsonAVLTreeMap internal statistics
163 template <typename Counter = cds::atomicity::event_counter>
165 typedef Counter event_counter; ///< Event counter type
167 event_counter m_nFindSuccess; ///< Count of success \p find() call
168 event_counter m_nFindFailed; ///< Count of failed \p find() call
169 event_counter m_nFindRetry; ///< Count of retries during \p find()
170 event_counter m_nFindWaitShrinking; ///< Count of waiting until shrinking completed duting \p find() call
172 event_counter m_nInsertSuccess; ///< Count of inserting data node
173 event_counter m_nRelaxedInsertFailed; ///< Count of false creating of data nodes (only if @ref bronson_avltree::relaxed_insert "relaxed insertion" is enabled)
174 event_counter m_nInsertRetry; ///< Count of insert retries via concurrent operations
175 event_counter m_nUpdateWaitShrinking; ///< Count of waiting until shrinking completed during \p update() call
176 event_counter m_nUpdateRetry; ///< Count of update retries via concurrent operations
177 event_counter m_nUpdateRootWaitShrinking; ///< Count of waiting until root shrinking completed duting \p update() call
178 event_counter m_nUpdateSuccess; ///< Count of updating data node
179 event_counter m_nUpdateUnlinked; ///< Count of updating of unlinked node attempts
180 event_counter m_nDisposedNode; ///< Count of disposed node
181 event_counter m_nDisposedValue; ///< Count of disposed value
182 event_counter m_nExtractedValue; ///< Count of extracted value
183 event_counter m_nRemoveRetry; ///< Count o erase/extract retries
184 event_counter m_nRemoveWaitShrinking; ///< ount of waiting until shrinking completed during \p erase() or \p extract() call
185 event_counter m_nRemoveRootWaitShrinking; ///< Count of waiting until root shrinking completed duting \p erase() or \p extract() call
187 event_counter m_nRightRotation; ///< Count of single right rotation
188 event_counter m_nLeftRotation; ///< Count of single left rotation
189 event_counter m_nLeftRightRotation; ///< Count of double left-over-right rotation
190 event_counter m_nRightLeftRotation; ///< Count of double right-over-left rotation
193 void onFindSuccess() { ++m_nFindSuccess ; }
194 void onFindFailed() { ++m_nFindFailed ; }
195 void onFindRetry() { ++m_nFindRetry ; }
196 void onFindWaitShrinking() { ++m_nFindWaitShrinking; }
198 void onInsertSuccess() { ++m_nInsertSuccess ; }
199 void onRelaxedInsertFailed() { ++m_nRelaxedInsertFailed; }
200 void onInsertRetry() { ++m_nInsertRetry ; }
201 void onUpdateWaitShrinking() { ++m_nUpdateWaitShrinking; }
202 void onUpdateRetry() { ++m_nUpdateRetry; }
203 void onUpdateRootWaitShrinking() { ++m_nUpdateRootWaitShrinking; }
204 void onUpdateSuccess() { ++m_nUpdateSuccess; }
205 void onUpdateUnlinked() { ++m_nUpdateUnlinked; }
206 void onDisposeNode() { ++m_nDisposedNode; }
207 void onDisposeValue() { ++m_nDisposedValue; }
208 void onExtractValue() { ++m_nExtractedValue; }
209 void onRemoveRetry() { ++m_nRemoveRetry; }
210 void onRemoveWaitShrinking() { ++m_nRemoveWaitShrinking; }
212 void onRotateRight() { ++m_nRightRotation; }
213 void onRotateLeft() { ++m_nLeftRotation; }
214 void onRotateRightOverLeft() { ++m_nRightLeftRotation; }
215 void onRotateLeftOverRight() { ++m_nLeftRghtRotation; }
219 /// BronsonAVLTreeMap empty statistics
222 void onFindSuccess() const {}
223 void onFindFailed() const {}
224 void onFindRetry() const {}
225 void onFindWaitShrinking() const {}
227 void onInsertSuccess() const {}
228 void onRelaxedInsertFailed() const {}
229 void onInsertRetry() const {}
230 void onUpdateWaitShrinking() const {}
231 void onUpdateRetry() const {}
232 void onUpdateRootWaitShrinking() const {}
233 void onUpdateSuccess() const {}
234 void onUpdateUnlinked() const {}
235 void onDisposeNode() const {}
236 void onDisposeValue() const {}
237 void onExtractValue() const {}
238 void onRemoveRetry() const {}
239 void onRemoveWaitShrinking() const {}
240 void onRemoveRootWaitShrinking() const {}
242 void onRotateRight() const {}
243 void onRotateLeft() const {}
244 void onRotateRightOverLeft() const {}
245 void onRotateLeftOverRight() const {}
249 /// Option to allow relaxed insert into Bronson et al AVL-tree
251 By default, this opton is disabled and the new node is created under its parent lock.
252 In this case, it is guaranteed the new node will be attached to its parent.
253 On the other hand, constructing of the new node can be too complex to make it under the lock,
254 that can lead to lock contention.
256 When this option is enabled, the new node is created before locking the parent node.
257 After that, the parent is locked and checked whether the new node can be attached to the parent.
258 In this case, false node creating can be performed, but locked section can be significantly small.
260 template <bool Enable>
261 struct relaxed_insert {
263 template <typename Base> struct pack : public Base
265 enum { relaxed_insert = Enable };
270 /// BronsnAVLTreeMap traits
272 Note that there are two main specialization of Bronson et al AVL-tree:
273 - pointer-oriented - the tree node stores an user-provided pointer to value: <tt>BronsonAVLTreeMap<GC, Key, T *, Traits> </tt>
274 - 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.
276 Depends on tree specialization, different traits member can be used.
280 /// Key comparison functor
282 No default functor is provided. If the option is not specified, the \p less is used.
284 See \p cds::opt::compare option description for functor interface.
286 You should provide \p compare or \p less functor.
288 typedef opt::none compare;
290 /// Specifies binary predicate used for key compare.
292 See \p cds::opt::less option description for predicate interface.
294 You should provide \p compare or \p less functor.
296 typedef opt::none less;
298 /// Allocator for internal node
299 typedef CDS_DEFAULT_ALLOCATOR node_allocator;
301 /// Allocator for node's value (not used in \p BronsonAVLTreeMap<RCU, Key, T*, Traits> specialisation)
302 typedef CDS_DEFAULT_ALLOCATOR allocator;
304 /// Disposer (only for pointer-oriented tree specialization)
306 The functor used for dispose removed values.
307 The user-provided disposer is used only for pointer-oriented tree specialization
308 like \p BronsonAVLTreeMap<GC, Key, T*, Traits>. When the node becomes the rounting node without value,
309 the disposer will be called to signal that the memory for the value can be safely freed.
310 Default is \ref cds::intrusive::opt::delete_disposer "cds::container::opt::v::delete_disposer<>" which calls \p delete operator.
312 typedef opt::v::delete_disposer<> disposer;
314 /// @ref cds_sync_monitor "Synchronization monitor" type for node-level locking
315 typedef cds::sync::injecting_monitor<cds::sync::spin> sync_monitor;
317 /// Enable relaxed insertion.
319 About relaxed insertion see \p bronson_avltree::relaxed_insert option.
320 By default, this option is disabled.
322 static bool const relaxed_insert = false;
326 The type for item counter, by default it is disabled (\p atomicity::empty_item_counter).
327 To enable it use \p atomicity::item_counter
329 typedef atomicity::empty_item_counter item_counter;
331 /// C++ memory ordering model
333 List of available memory ordering see \p opt::memory_model
335 typedef opt::v::relaxed_ordering memory_model;
337 /// Internal statistics
339 By default, internal statistics is disabled (\p ellen_bintree::empty_stat).
340 To enable it use \p ellen_bintree::stat.
342 typedef empty_stat stat;
344 /// Back-off strategy
345 typedef cds::backoff::empty back_off;
347 /// RCU deadlock checking policy (only for \ref cds_container_BronsonAVLTreeMap_rcu "RCU-based BronsonAVLTree")
349 List of available options see \p opt::rcu_check_deadlock
351 typedef cds::opt::v::rcu_throw_deadlock rcu_check_deadlock;
354 /// Metafunction converting option list to BronsonAVLTreeMap traits
356 Note that there are two main specialization of Bronson et al AVL-tree:
357 - pointer-oriented - the tree node stores an user-provided pointer to value: <tt>BronsonAVLTreeMap<GC, Key, T *, Traits> </tt>
358 - 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.
360 Depends on tree specialization, different options can be specified.
363 - \p opt::compare - key compare functor. No default functor is provided.
364 If the option is not specified, \p %opt::less is used.
365 - \p opt::less - specifies binary predicate used for key compare. At least \p %opt::compare or \p %opt::less should be defined.
366 - \p opt::node_allocator - the allocator for internal nodes. Default is \ref CDS_DEFAULT_ALLOCATOR.
367 - \p opt::allocator - the allocator for node's value. Default is \ref CDS_DEFAULT_ALLOCATOR.
368 This option is not used in \p BronsonAVLTreeMap<RCU, Key, T*, Traits> specialisation
369 - \ref cds::intrusive::opt::disposer "container::opt::disposer" - the functor used for dispose removed values.
370 The user-provided disposer is used only for pointer-oriented tree specialization
371 like \p BronsonAVLTreeMap<GC, Key, T*, Traits>. When the node becomes the rounting node without value,
372 the disposer will be called to signal that the memory for the value can be safely freed.
373 Default is \ref cds::intrusive::opt::delete_disposer "cds::container::opt::v::delete_disposer<>" which calls \p delete operator.
374 Due the nature of GC schema the disposer may be called asynchronously.
375 - \p opt::sync_monitor - @ref cds_sync_monitor "synchronization monitor" type for node-level locking,
376 default is \p cds::sync::injecting_monitor<cds::sync::spin>
377 - \p bronson_avltree::relaxed_insert - enable (\p true) or disable (\p false, the default)
378 @ref bronson_avltree::relaxed_insert "relaxed insertion"
379 - \p opt::item_counter - the type of item counting feature, by default it is disabled (\p atomicity::empty_item_counter)
380 To enable it use \p atomicity::item_counter
381 - \p opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
382 or \p opt::v::sequential_consistent (sequentially consisnent memory model).
383 - \p opt::stat - internal statistics, by default it is disabled (\p bronson_avltree::empty_stat)
384 To enable statistics use \p \p bronson_avltree::stat
385 - \p opt::backoff - back-off strategy, by default no strategy is used (\p cds::backoff::empty)
386 - \p opt::rcu_check_deadlock - a deadlock checking policy for RCU-based tree, default is \p opt::v::rcu_throw_deadlock
388 template <typename... Options>
390 # ifdef CDS_DOXYGEN_INVOKED
391 typedef implementation_defined type ; ///< Metafunction result
393 typedef typename cds::opt::make_options<
394 typename cds::opt::find_type_traits< traits, Options... >::type
399 } // namespace bronson_avltree
402 template < class GC, typename Key, typename T, class Traits = bronson_avltree::traits >
403 class BronsonAVLTreeMap;
405 }} // namespace cds::container
408 #endif // #ifndef CDSLIB_CONTAINER_DETAILS_BRONSON_AVLTREE_BASE_H