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>
21 template <typename Key, typename T>
24 typedef node<Key, T> node_type;
25 typedef uint32_t version_type;
31 version_flags = shrinking | unlinked
32 // the rest is version counter
35 atomics::atomic< int > m_nHeight; ///< Node height
36 atomics::atomic<version_type> m_nVersion; ///< Version bits
37 atomics::atomic<node_type *> m_pParent; ///< Parent node
38 atomics::atomic<node_type *> m_pLeft; ///< Left child
39 atomics::atomic<node_type *> m_pRight; ///< Right child
41 node_type * m_pNextRemoved; ///< thread-local list o removed node
46 , m_pParent( nullptr )
49 , m_pNextRemoved( nullptr )
52 link( int nHeight, version_type version, node_type * pParent, node_type * pLeft, node_type * pRight )
53 : m_nHeight( nHeight )
54 , m_nVersion( version )
55 , m_pParent( pParent )
58 , m_pNextRemoved( nullptr )
61 atomics::atomic<node_type *>& child( int nDirection ) const
63 assert( nDirection != 0 );
64 return nDirection < 0 ? m_pLeft : m_pRight;
67 void child( node_type * pChild, int nDirection, atomics::memory_order order )
69 assert( nDirection != 0 );
71 m_pLeft.store( pChild, order );
73 m_pRight.store( pChild, order );
76 version_type version( atomics::memory_order order ) const
78 return m_nVersion.load( order );
81 void version( version_type ver, atomics::memory_order order )
83 m_nVersion.store( ver, order );
86 int height( atomics::memory_order order ) const
88 return m_nHeight.load( order );
91 void height( int h, atomics::memory_order order )
93 m_nHeight.store( h, order );
96 template <typename BackOff>
97 void wait_until_shrink_completed( atomics::memory_order order ) const
100 while ( is_shrinking( order ))
104 bool is_unlinked( atomics::memory_order order ) const
106 return m_nVersion.load( order ) == unlinked;
109 bool is_shrinking( atomics::memory_order order ) const
111 return (m_nVersion.load( order ) & shrinking) != 0;
115 template <typename Key, typename T>
116 struct node : public link< Key, T >
118 typedef Key key_type;
119 typedef T mapped_type;
120 typedef link< key_type, mapped_type > base_class;
122 key_type const m_key;
123 atomics::atomic<mapped_type *> m_pValue;
125 template <typename Q>
127 : m_key( std::forward<Q>(key) )
128 , m_pValue( nullptr )
131 template <typename Q>
132 node( Q&& key, int nHeight, version_type version, node_type * pParent, node_type * pLeft, node_type * pRight )
133 : base_class( nHeight, version, pParent, pLeft, pRight )
134 , m_key( std::forward<Q>( key ) )
135 , m_pValue( nullptr )
138 T * value( atomics::memory_order order ) const
140 return m_pValue.load( order );
143 bool is_valued( atomics::memory_order order ) const
145 return value( order ) != nullptr;
150 /// BronsonAVLTreeMap internal statistics
151 template <typename Counter = cds::atomicity::event_counter>
153 typedef Counter event_counter; ///< Event counter type
155 event_counter m_nFindSuccess; ///< Count of success \p find() call
156 event_counter m_nFindFailed; ///< Count of failed \p find() call
157 event_counter m_nFindRetry; ///< Count of retries during \p find()
158 event_counter m_nFindWaitShrinking; ///< Count of waiting until shrinking completed duting \p find() call
160 event_counter m_nInsertSuccess; ///< Count of inserting data node
161 event_counter m_nRelaxedInsertFailed; ///< Count of false creating of data nodes (only if @ref bronson_avltree::relaxed_insert "relaxed insertion" is enabled)
162 event_counter m_nInsertRetry; ///< Count of insert retries via concurrent operations
163 event_counter m_nUpdateWaitShrinking; ///< Count of waiting until shrinking completed duting \p update() call
164 event_counter m_nUpdateRetry; ///< Count of update retries via concurrent operations
165 event_counter m_nUpdateRootWaitShrinking; ///< Count of waiting until root shrinking completed duting \p update() call
166 event_counter m_nUpdateSuccess; ///< Count of updating data node
167 event_counter m_nUpdateUnlinked; ///< Count of updating of unlinked node attempts
168 event_counter m_nDisposedValue; ///< Count of disposed value
171 void onFindSuccess() { ++m_nFindSuccess ; }
172 void onFindFailed() { ++m_nFindFailed ; }
173 void onFindRetry() { ++m_nFindRetry ; }
174 void onFindWaitShrinking() { ++m_nFindWaitShrinking; }
176 void onInsertSuccess() { ++m_nInsertSuccess ; }
177 void onRelaxedInsertFailed() { ++m_nRelaxedInsertFailed; }
178 void onInsertRetry() { ++m_nInsertRetry ; }
179 void onUpdateWaitShrinking() { ++m_nUpdateWaitShrinking; }
180 void onUpdateRetry() { ++m_nUpdateRetry; }
181 void onUpdateRootWaitShrinking() { ++m_nUpdateRootWaitShrinking; }
182 void onUpdateSuccess() { ++m_nUpdateSuccess; }
183 void onUpdateUnlinked() { ++m_nUpdateUnlinked; }
184 void onDisposeValue() { ++m_nDisposedValue; }
189 /// BronsonAVLTreeMap empty statistics
192 void onFindSuccess() const {}
193 void onFindFailed() const {}
194 void onFindRetry() const {}
195 void onFindWaitShrinking() const {}
197 void onInsertSuccess() const {}
198 void onRelaxedInsertFailed() const {}
199 void onInsertRetry() const {}
200 void onUpdateWaitShrinking() const {}
201 void onUpdateRetry() const {}
202 void onUpdateRootWaitShrinking() const {}
203 void onUpdateSuccess() const {}
204 void onUpdateUnlinked() const {}
205 void onDisposeValue() const {}
210 /// Option to allow relaxed insert into Bronson et al AVL-tree
212 By default, this opton is disabled and the new node is created under its parent lock.
213 In this case, it is guaranteed the new node will be attached to its parent.
214 On the other hand, constructing of the new node can be too complex to make it under the lock,
215 that can lead to lock contention.
217 When this option is enabled, the new node is created before locking the parent node.
218 After that, the parent is locked and checked whether the new node can be attached to the parent.
219 In this case, false node creating can be performed, but locked section can be significantly small.
221 template <bool Enable>
222 struct relaxed_insert {
224 template <typename Base> struct pack : public Base
226 enum { relaxed_insert = Enable };
231 /// BronsnAVLTreeMap traits
233 Note that there are two main specialization of Bronson et al AVL-tree:
234 - pointer-oriented - the tree node stores an user-provided pointer to value: <tt>BronsonAVLTreeMap<GC, Key, T *, Traits> </tt>
235 - 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.
237 Depends on tree specialization, different traits member can be used.
241 /// Key comparison functor
243 No default functor is provided. If the option is not specified, the \p less is used.
245 See \p cds::opt::compare option description for functor interface.
247 You should provide \p compare or \p less functor.
249 typedef opt::none compare;
251 /// Specifies binary predicate used for key compare.
253 See \p cds::opt::less option description for predicate interface.
255 You should provide \p compare or \p less functor.
257 typedef opt::none less;
259 /// Allocator for internal node
260 typedef CDS_DEFAULT_ALLOCATOR node_allocator;
262 /// Disposer (only for pointer-oriented tree specialization)
264 The functor used for dispose removed values.
265 The user-provided disposer is used only for pointer-oriented tree specialization
266 like \p BronsonAVLTreeMap<GC, Key, T*, Traits>. When the node becomes the rounting node without value,
267 the disposer will be called to signal that the memory for the value can be safely freed.
268 Default is \ref cds::intrusive::opt::delete_disposer "cds::container::opt::v::delete_disposer<>" which calls \p delete operator.
270 typedef opt::v::delete_disposer<> disposer;
272 /// @ref cds_sync_monitor "Synchronization monitor" type for node-level locking
273 typedef cds::sync::injecting_monitor<cds::sync::spin> sync_monitor;
275 /// Enable relaxed insertion.
277 About relaxed insertion see \p bronson_avltree::relaxed_insert option.
278 By default, this option is disabled.
280 static bool const relaxed_insert = false;
284 The type for item counter, by default it is disabled (\p atomicity::empty_item_counter).
285 To enable it use \p atomicity::item_counter
287 typedef atomicity::empty_item_counter item_counter;
289 /// C++ memory ordering model
291 List of available memory ordering see \p opt::memory_model
293 typedef opt::v::relaxed_ordering memory_model;
295 /// Internal statistics
297 By default, internal statistics is disabled (\p ellen_bintree::empty_stat).
298 To enable it use \p ellen_bintree::stat.
300 typedef empty_stat stat;
302 /// Back-off strategy
303 typedef cds::backoff::empty back_off;
305 /// RCU deadlock checking policy (only for \ref cds_container_BronsonAVLTreeMap_rcu "RCU-based BronsonAVLTree")
307 List of available options see \p opt::rcu_check_deadlock
309 typedef cds::opt::v::rcu_throw_deadlock rcu_check_deadlock;
312 /// Metafunction converting option list to BronsonAVLTreeMap traits
314 Note that there are two main specialization of Bronson et al AVL-tree:
315 - pointer-oriented - the tree node stores an user-provided pointer to value: <tt>BronsonAVLTreeMap<GC, Key, T *, Traits> </tt>
316 - 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.
318 Depends on tree specialization, different options can be specified.
321 - \p opt::compare - key compare functor. No default functor is provided.
322 If the option is not specified, \p %opt::less is used.
323 - \p opt::less - specifies binary predicate used for key compare. At least \p %opt::compare or \p %opt::less should be defined.
324 - \p opt::node_allocator - the allocator for internal nodes. Default is \ref CDS_DEFAULT_ALLOCATOR.
325 - \ref cds::intrusive::opt::disposer "container::opt::disposer" - the functor used for dispose removed values.
326 The user-provided disposer is used only for pointer-oriented tree specialization
327 like \p BronsonAVLTreeMap<GC, Key, T*, Traits>. When the node becomes the rounting node without value,
328 the disposer will be called to signal that the memory for the value can be safely freed.
329 Default is \ref cds::intrusive::opt::delete_disposer "cds::container::opt::v::delete_disposer<>" which calls \p delete operator.
330 Due the nature of GC schema the disposer may be called asynchronously.
331 - \p opt::sync_monitor - @ref cds_sync_monitor "synchronization monitor" type for node-level locking,
332 default is cds::sync::injecting_monitor<cds::sync::spin>
333 - \p bronson_avltree::relaxed_insert - enable (\p true) or disable (\p false, the default)
334 @ref bronson_avltree::relaxed_insert "relaxed insertion"
335 - \p opt::item_counter - the type of item counting feature, by default it is disabled (\p atomicity::empty_item_counter)
336 To enable it use \p atomicity::item_counter
337 - \p opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
338 or \p opt::v::sequential_consistent (sequentially consisnent memory model).
339 - \p opt::stat - internal statistics, by default it is disabled (\p bronson_avltree::empty_stat)
340 To enable statistics use \p \p bronson_avltree::stat
341 - \p opt::backoff - back-off strategy, by default no strategy is used (\p cds::backoff::empty)
342 - \p opt::rcu_check_deadlock - a deadlock checking policy for RCU-based tree, default is \p opt::v::rcu_throw_deadlock
344 template <typename... Options>
346 # ifdef CDS_DOXYGEN_INVOKED
347 typedef implementation_defined type ; ///< Metafunction result
349 typedef typename cds::opt::make_options<
350 typename cds::opt::find_type_traits< traits, Options... >::type
355 } // namespace bronson_avltree
358 template < class GC, typename Key, typename T, class Traits = bronson_avltree::traits >
359 class BronsonAVLTreeMap;
361 }} // namespace cds::container
364 #endif // #ifndef CDSLIB_CONTAINER_DETAILS_BRONSON_AVLTREE_BASE_H