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 duting \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
184 event_counter m_nRightRotation; ///< Count of single right rotation
185 event_counter m_nLeftRotation; ///< Count of single left rotation
186 event_counter m_nLeftRightRotation; ///< Count of double left-over-right rotation
187 event_counter m_nRightLeftRotation; ///< Count of double right-over-left rotation
190 void onFindSuccess() { ++m_nFindSuccess ; }
191 void onFindFailed() { ++m_nFindFailed ; }
192 void onFindRetry() { ++m_nFindRetry ; }
193 void onFindWaitShrinking() { ++m_nFindWaitShrinking; }
195 void onInsertSuccess() { ++m_nInsertSuccess ; }
196 void onRelaxedInsertFailed() { ++m_nRelaxedInsertFailed; }
197 void onInsertRetry() { ++m_nInsertRetry ; }
198 void onUpdateWaitShrinking() { ++m_nUpdateWaitShrinking; }
199 void onUpdateRetry() { ++m_nUpdateRetry; }
200 void onUpdateRootWaitShrinking() { ++m_nUpdateRootWaitShrinking; }
201 void onUpdateSuccess() { ++m_nUpdateSuccess; }
202 void onUpdateUnlinked() { ++m_nUpdateUnlinked; }
203 void onDisposeNode() { ++m_nDisposedNode; }
204 void onDisposeValue() { ++m_nDisposedValue; }
205 void onExtractValue() { ++m_nExtractedValue; }
207 void onRotateRight() { ++m_nRightRotation; }
208 void onRotateLeft() { ++m_nLeftRotation; }
209 void onRotateRightOverLeft() { ++m_nRightLeftRotation; }
210 void onRotateLeftOverRight() { ++m_nLeftRghtRotation; }
214 /// BronsonAVLTreeMap empty statistics
217 void onFindSuccess() const {}
218 void onFindFailed() const {}
219 void onFindRetry() const {}
220 void onFindWaitShrinking() const {}
222 void onInsertSuccess() const {}
223 void onRelaxedInsertFailed() const {}
224 void onInsertRetry() const {}
225 void onUpdateWaitShrinking() const {}
226 void onUpdateRetry() const {}
227 void onUpdateRootWaitShrinking() const {}
228 void onUpdateSuccess() const {}
229 void onUpdateUnlinked() const {}
230 void onDisposeNode() const {}
231 void onDisposeValue() const {}
232 void onExtractValue() const {}
234 void onRotateRight() const {}
235 void onRotateLeft() const {}
236 void onRotateRightOverLeft() const {}
237 void onRotateLeftOverRight() const {}
241 /// Option to allow relaxed insert into Bronson et al AVL-tree
243 By default, this opton is disabled and the new node is created under its parent lock.
244 In this case, it is guaranteed the new node will be attached to its parent.
245 On the other hand, constructing of the new node can be too complex to make it under the lock,
246 that can lead to lock contention.
248 When this option is enabled, the new node is created before locking the parent node.
249 After that, the parent is locked and checked whether the new node can be attached to the parent.
250 In this case, false node creating can be performed, but locked section can be significantly small.
252 template <bool Enable>
253 struct relaxed_insert {
255 template <typename Base> struct pack : public Base
257 enum { relaxed_insert = Enable };
262 /// BronsnAVLTreeMap traits
264 Note that there are two main specialization of Bronson et al AVL-tree:
265 - pointer-oriented - the tree node stores an user-provided pointer to value: <tt>BronsonAVLTreeMap<GC, Key, T *, Traits> </tt>
266 - 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.
268 Depends on tree specialization, different traits member can be used.
272 /// Key comparison functor
274 No default functor is provided. If the option is not specified, the \p less is used.
276 See \p cds::opt::compare option description for functor interface.
278 You should provide \p compare or \p less functor.
280 typedef opt::none compare;
282 /// Specifies binary predicate used for key compare.
284 See \p cds::opt::less option description for predicate interface.
286 You should provide \p compare or \p less functor.
288 typedef opt::none less;
290 /// Allocator for internal node
291 typedef CDS_DEFAULT_ALLOCATOR node_allocator;
293 /// Allocator for node's value (not used in \p BronsonAVLTreeMap<RCU, Key, T*, Traits> specialisation)
294 typedef CDS_DEFAULT_ALLOCATOR allocator;
296 /// Disposer (only for pointer-oriented tree specialization)
298 The functor used for dispose removed values.
299 The user-provided disposer is used only for pointer-oriented tree specialization
300 like \p BronsonAVLTreeMap<GC, Key, T*, Traits>. When the node becomes the rounting node without value,
301 the disposer will be called to signal that the memory for the value can be safely freed.
302 Default is \ref cds::intrusive::opt::delete_disposer "cds::container::opt::v::delete_disposer<>" which calls \p delete operator.
304 typedef opt::v::delete_disposer<> disposer;
306 /// @ref cds_sync_monitor "Synchronization monitor" type for node-level locking
307 typedef cds::sync::injecting_monitor<cds::sync::spin> sync_monitor;
309 /// Enable relaxed insertion.
311 About relaxed insertion see \p bronson_avltree::relaxed_insert option.
312 By default, this option is disabled.
314 static bool const relaxed_insert = false;
318 The type for item counter, by default it is disabled (\p atomicity::empty_item_counter).
319 To enable it use \p atomicity::item_counter
321 typedef atomicity::empty_item_counter item_counter;
323 /// C++ memory ordering model
325 List of available memory ordering see \p opt::memory_model
327 typedef opt::v::relaxed_ordering memory_model;
329 /// Internal statistics
331 By default, internal statistics is disabled (\p ellen_bintree::empty_stat).
332 To enable it use \p ellen_bintree::stat.
334 typedef empty_stat stat;
336 /// Back-off strategy
337 typedef cds::backoff::empty back_off;
339 /// RCU deadlock checking policy (only for \ref cds_container_BronsonAVLTreeMap_rcu "RCU-based BronsonAVLTree")
341 List of available options see \p opt::rcu_check_deadlock
343 typedef cds::opt::v::rcu_throw_deadlock rcu_check_deadlock;
346 /// Metafunction converting option list to BronsonAVLTreeMap traits
348 Note that there are two main specialization of Bronson et al AVL-tree:
349 - pointer-oriented - the tree node stores an user-provided pointer to value: <tt>BronsonAVLTreeMap<GC, Key, T *, Traits> </tt>
350 - 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.
352 Depends on tree specialization, different options can be specified.
355 - \p opt::compare - key compare functor. No default functor is provided.
356 If the option is not specified, \p %opt::less is used.
357 - \p opt::less - specifies binary predicate used for key compare. At least \p %opt::compare or \p %opt::less should be defined.
358 - \p opt::node_allocator - the allocator for internal nodes. Default is \ref CDS_DEFAULT_ALLOCATOR.
359 - \p opt::allocator - the allocator for node's value. Default is \ref CDS_DEFAULT_ALLOCATOR.
360 This option is not used in \p BronsonAVLTreeMap<RCU, Key, T*, Traits> specialisation
361 - \ref cds::intrusive::opt::disposer "container::opt::disposer" - the functor used for dispose removed values.
362 The user-provided disposer is used only for pointer-oriented tree specialization
363 like \p BronsonAVLTreeMap<GC, Key, T*, Traits>. When the node becomes the rounting node without value,
364 the disposer will be called to signal that the memory for the value can be safely freed.
365 Default is \ref cds::intrusive::opt::delete_disposer "cds::container::opt::v::delete_disposer<>" which calls \p delete operator.
366 Due the nature of GC schema the disposer may be called asynchronously.
367 - \p opt::sync_monitor - @ref cds_sync_monitor "synchronization monitor" type for node-level locking,
368 default is \p cds::sync::injecting_monitor<cds::sync::spin>
369 - \p bronson_avltree::relaxed_insert - enable (\p true) or disable (\p false, the default)
370 @ref bronson_avltree::relaxed_insert "relaxed insertion"
371 - \p opt::item_counter - the type of item counting feature, by default it is disabled (\p atomicity::empty_item_counter)
372 To enable it use \p atomicity::item_counter
373 - \p opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
374 or \p opt::v::sequential_consistent (sequentially consisnent memory model).
375 - \p opt::stat - internal statistics, by default it is disabled (\p bronson_avltree::empty_stat)
376 To enable statistics use \p \p bronson_avltree::stat
377 - \p opt::backoff - back-off strategy, by default no strategy is used (\p cds::backoff::empty)
378 - \p opt::rcu_check_deadlock - a deadlock checking policy for RCU-based tree, default is \p opt::v::rcu_throw_deadlock
380 template <typename... Options>
382 # ifdef CDS_DOXYGEN_INVOKED
383 typedef implementation_defined type ; ///< Metafunction result
385 typedef typename cds::opt::make_options<
386 typename cds::opt::find_type_traits< traits, Options... >::type
391 } // namespace bronson_avltree
394 template < class GC, typename Key, typename T, class Traits = bronson_avltree::traits >
395 class BronsonAVLTreeMap;
397 }} // namespace cds::container
400 #endif // #ifndef CDSLIB_CONTAINER_DETAILS_BRONSON_AVLTREE_BASE_H