3 #ifndef __CDS_CONTAINER_DETAILS_BRONSON_AVLTREE_BASE_H
4 #define __CDS_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/lock/spinlock.h>
11 namespace cds { namespace container {
13 /// BronsonAVLTree related declarations
14 namespace bronson_avltree {
16 template <typename Key, typename T>
20 template <typename Key, typename T, typename Lock>
23 typedef node<Key, T> node_type;
24 typedef uint32_t version_type;
25 typedef Lock lock_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
40 lock_type m_Lock; ///< Node-level lock
45 , m_pParent( nullptr )
50 link( int nHeight, version_type version, node_type * pParent, node_type * pLeft, node_type * pRight )
51 : m_nHeight( nHeight )
52 , m_nVersion( version )
53 , m_pParent( pParent )
58 atomics::atomic<node_type *>& child( int nDirection ) const
60 assert( nDirection != 0 );
61 return nDirection < 0 ? m_pLeft : m_pRight;
64 void child( node_type * pChild, int nDirection, atomics::memory_order order )
66 assert( nDirection != 0 );
68 m_pLeft.store( pChild, order );
70 m_pRight.store( pChild, order );
73 version_type version( atomics::memory_order order ) const
75 return m_nVersion.load( order );
78 void version( version_type ver, atomics::memory_order order )
80 m_nVersion.store( ver, order );
83 int height( atomics::memory_order order ) const
85 return m_nHeight.load( order );
88 void height( int h, atomics::memory_order order )
90 m_nHeight.store( h, order );
92 template <typename BackOff>
93 void wait_until_shrink_completed( atomics::memory_order order ) const
96 while ( is_shrinking( order ))
100 bool is_unlinked( atomics::memory_order order ) const
102 return (m_nVersion.load( order ) & unlinked) != 0;
105 bool is_shrinking( atomics::memory_order order ) const
107 return (m_nVersion.load( order ) & shrinking) != 0;
111 template <typename Key, typename T, typename Lock>
112 struct node : public link< Key, T, Lock >
114 typedef Key key_type;
115 typedef T mapped_type;
116 typedef link< key_type, mapped_type, Lock > base_class;
118 key_type const m_key;
119 atomics::atomic<mapped_type *> m_pValue;
121 template <typename Q>
123 : m_key( std::forward<Q>(key) )
124 , m_pValue( nullptr )
127 template <typename Q>
128 node( Q&& key, int nHeight, version_type version, node_type * pParent, node_type * pLeft, node_type * pRight )
129 : base_class( nHeight, version, pParent, pLeft, pRight )
130 , m_key( std::forward<Q>( key ) )
131 , m_pValue( nullptr )
134 T * value( atomics::memory_order order ) const
136 return m_pValue.load( order );
141 /// BronsonAVLTreeMap internal statistics
142 template <typename Counter = cds::atomicity::event_counter>
144 typedef Counter event_counter; ///< Event counter type
146 event_counter m_nFindSuccess; ///< Count of success \p find() call
147 event_counter m_nFindFailed; ///< Count of failed \p find() call
148 event_counter m_nFindRetry; ///< Count of retries during \p find()
149 event_counter m_nFindWaitShrinking; ///< Count of waiting until shrinking completed duting \p find() call
151 event_counter m_nInsertSuccess; ///< Count of inserting data node
152 event_counter m_nRelaxedInsertFailed; ///< Count of false creating of data nodes (only if @ref bronson_avltree::relaxed_insert "relaxed insertion" is enabled)
153 event_counter m_nInsertRetry; ///< Count of insert retries via concurrent operations
156 void onFindSuccess() { ++m_nFindSuccess ; }
157 void onFindFailed() { ++m_nFindFailed ; }
158 void onFindRetry() { ++m_nFindRetry ; }
159 void onFindWaitShrinking() { ++m_nFindWaitShrinking; }
161 void onInsertSuccess() { ++m_nInsertSuccess ; }
162 void onRelaxedInsertFailed() { ++m_nRelaxedInsertFailed; }
163 void onInsertRetry() { ++m_nInsertRetry ; }
168 /// BronsonAVLTreeMap empty statistics
171 void onFindSuccess() const {}
172 void onFindFailed() const {}
173 void onFindRetry() const {}
174 void onFindWaitShrinking() const {}
176 void onInsertSuccess() const {}
177 void onRelaxedInsertFailed() const {}
178 void onInsertRetry() const {}
183 /// Option to allow relaxed insert into Bronson et al AVL-tree
185 By default, this opton is disabled and the new node is created under its parent lock.
186 In this case, it is guaranteed the new node will be attached to its parent.
187 On the other hand, constructing of the new node can be too complex to make it under the lock,
188 that can lead to lock contention.
190 When this option is enabled, the new node is created before locking the parent node.
191 After that, the parent is locked and checked whether the new node can be attached to the parent.
192 In this case, false node creating can be performed, but locked section can be significantly small.
194 template <bool Enable>
195 struct relaxed_insert {
197 template <typename Base> struct pack : public Base
199 enum { relaxed_insert = Enable };
204 /// BronsnAVLTreeMap traits
206 Note that there are two main specialization of Bronson et al AVL-tree:
207 - pointer-oriented - the tree node stores an user-provided pointer to value: <tt>BronsonAVLTreeMap<GC, Key, T *, Traits> </tt>
208 - 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.
210 Depends on tree specialization, different traits member can be used.
214 /// Key comparison functor
216 No default functor is provided. If the option is not specified, the \p less is used.
218 See \p cds::opt::compare option description for functor interface.
220 You should provide \p compare or \p less functor.
222 typedef opt::none compare;
224 /// Specifies binary predicate used for key compare.
226 See \p cds::opt::less option description for predicate interface.
228 You should provide \p compare or \p less functor.
230 typedef opt::none less;
232 /// Allocator for internal node
233 typedef CDS_DEFAULT_ALLOCATOR allocator;
235 /// Disposer (only for pointer-oriented tree specialization)
237 The functor used for dispose removed values.
238 The user-provided disposer is used only for pointer-oriented tree specialization
239 like \p BronsonAVLTreeMap<GC, Key, T*, Traits>. When the node becomes the rounting node without value,
240 the disposer will be called to signal that the memory for the value can be safely freed.
241 Default is \ref cds::intrusive::opt::delete_disposer "cds::container::opt::v::delete_disposer<>" which calls \p delete operator.
243 typedef opt::v::delete_disposer<> disposer;
246 typedef std::mutex lock_type;
248 /// Enable relaxed insertion.
250 About relaxed insertion see \p bronson_avltree::relaxed_insert option.
251 By default, this option is disabled.
253 static bool const relaxed_insert = false;
257 The type for item counter, by default it is disabled (\p atomicity::empty_item_counter).
258 To enable it use \p atomicity::item_counter
260 typedef atomicity::empty_item_counter item_counter;
262 /// C++ memory ordering model
264 List of available memory ordering see \p opt::memory_model
266 typedef opt::v::relaxed_ordering memory_model;
268 /// Internal statistics
270 By default, internal statistics is disabled (\p ellen_bintree::empty_stat).
271 To enable it use \p ellen_bintree::stat.
273 typedef empty_stat stat;
275 /// Back-off strategy
276 typedef cds::backoff::empty back_off;
278 /// RCU deadlock checking policy (only for \ref cds_container_BronsonAVLTreeMap_rcu "RCU-based BronsonAVLTree")
280 List of available options see \p opt::rcu_check_deadlock
282 typedef cds::opt::v::rcu_throw_deadlock rcu_check_deadlock;
285 // Internal traits, not for direct usage
286 typedef opt::none node_type;
290 /// Metafunction converting option list to BronsonAVLTreeMap traits
292 Note that there are two main specialization of Bronson et al AVL-tree:
293 - pointer-oriented - the tree node stores an user-provided pointer to value: <tt>BronsonAVLTreeMap<GC, Key, T *, Traits> </tt>
294 - 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.
296 Depends on tree specialization, different options can be specified.
299 - \p opt::compare - key compare functor. No default functor is provided.
300 If the option is not specified, \p %opt::less is used.
301 - \p opt::less - specifies binary predicate used for key compare. At least \p %opt::compare or \p %opt::less should be defined.
302 - \p opt::allocator - the allocator for internal nodes. Default is \ref CDS_DEFAULT_ALLOCATOR.
303 - \ref cds::intrusive::opt::disposer "container::opt::disposer" - the functor used for dispose removed values.
304 The user-provided disposer is used only for pointer-oriented tree specialization
305 like \p BronsonAVLTreeMap<GC, Key, T*, Traits>. When the node becomes the rounting node without value,
306 the disposer will be called to signal that the memory for the value can be safely freed.
307 Default is \ref cds::intrusive::opt::delete_disposer "cds::container::opt::v::delete_disposer<>" which calls \p delete operator.
308 Due the nature of GC schema the disposer may be called asynchronously.
309 - \p opt::lock_type - node lock type, default is \p std::mutex
310 - \p bronson_avltree::relaxed_insert - enable (\p true) or disable (\p false, the default)
311 @ref bronson_avltree::relaxed_insert "relaxed insertion"
312 - \p opt::item_counter - the type of item counting feature, by default it is disabled (\p atomicity::empty_item_counter)
313 To enable it use \p atomicity::item_counter
314 - \p opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
315 or \p opt::v::sequential_consistent (sequentially consisnent memory model).
316 - \p opt::stat - internal statistics, by default it is disabled (\p bronson_avltree::empty_stat)
317 To enable statistics use \p \p bronson_avltree::stat
318 - \p opt::backoff - back-off strategy, by default no strategy is used (\p cds::backoff::empty)
319 - \p opt::rcu_check_deadlock - a deadlock checking policy for RCU-based tree, default is \p opt::v::rcu_throw_deadlock
321 template <typename... Options>
323 # ifdef CDS_DOXYGEN_INVOKED
324 typedef implementation_defined type ; ///< Metafunction result
326 typedef typename cds::opt::make_options<
327 typename cds::opt::find_type_traits< traits, Options... >::type
334 } // namespace bronson_avltree
337 template < class GC, typename Key, typename T, class Traits = bronson_avltree::traits >
338 class BronsonAVLTreeMap;
340 }} // namespace cds::container
343 #endif // #ifndef __CDS_CONTAINER_DETAILS_BRONSON_AVLTREE_BASE_H