struct node;
//@cond
- template <typename Node, typename SyncMonitor>
+ template <typename Node, typename T, typename SyncMonitor>
struct link_node
{
- typedef Node node_type;
+ typedef Node node_type;
+ typedef T mapped_type;
typedef uint32_t version_type; ///< version type (internal)
enum
atomics::atomic<node_type *> m_pLeft; ///< Left child
atomics::atomic<node_type *> m_pRight; ///< Right child
typename SyncMonitor::node_injection m_SyncMonitorInjection; ///< @ref cds_sync_monitor "synchronization monitor" injected data
+ atomics::atomic<mapped_type *> m_pValue; ///< Value
public:
//@cond
, m_pParent( nullptr )
, m_pLeft( nullptr )
, m_pRight( nullptr )
+ , m_pValue( nullptr )
{}
link_node( int nHeight, version_type version, node_type * pParent, node_type * pLeft, node_type * pRight )
, m_pParent( pParent )
, m_pLeft( pLeft )
, m_pRight( pRight )
+ , m_pValue( nullptr )
{}
atomics::atomic<node_type *>& child( int nDirection )
{
return (m_nVersion.load( order ) & shrinking) != 0;
}
+
+ mapped_type * value( atomics::memory_order order ) const
+ {
+ return m_pValue.load( order );
+ }
+
+ bool is_valued( atomics::memory_order order ) const
+ {
+ return value( order ) != nullptr;
+ }
+
//@endcond
};
//@endcond
- // BronsonAVLTree internal node
+ /// BronsonAVLTree internal node
template <typename Key, typename T, typename SyncMonitor >
- struct node<Key, T*, SyncMonitor>: public link_node< node<Key, T*, SyncMonitor>, SyncMonitor >
+ struct node<Key, T*, SyncMonitor>: public link_node< node<Key, T*, SyncMonitor>, T, SyncMonitor >
{
- typedef link_node< node<Key, T*, SyncMonitor>, SyncMonitor > base_class;
+ //@cond
+ typedef link_node< node<Key, T*, SyncMonitor>, T, SyncMonitor > base_class;
+ //@endcond
typedef Key key_type; ///< key type
typedef T mapped_type; ///< value type
typedef typename base_class::version_type version_type;
key_type const m_key; ///< Key
- atomics::atomic<mapped_type *> m_pValue; ///< Value
node * m_pNextRemoved; ///< thread-local list of removed node
public:
node( Q&& key )
: base_class()
, m_key( std::forward<Q>( key ) )
- , m_pValue( nullptr )
, m_pNextRemoved( nullptr )
{}
node( Q&& key, int nHeight, version_type version, node * pParent, node * pLeft, node * pRight )
: base_class( nHeight, version, pParent, pLeft, pRight )
, m_key( std::forward<Q>( key ) )
- , m_pValue( nullptr )
, m_pNextRemoved( nullptr )
{}
- T * value( atomics::memory_order order ) const
- {
- return m_pValue.load( order );
- }
-
- bool is_valued( atomics::memory_order order ) const
- {
- return value( order ) != nullptr;
- }
//@endcond
};
event_counter m_nInsertSuccess; ///< Count of inserting data node
event_counter m_nRelaxedInsertFailed; ///< Count of false creating of data nodes (only if @ref bronson_avltree::relaxed_insert "relaxed insertion" is enabled)
event_counter m_nInsertRetry; ///< Count of insert retries via concurrent operations
- event_counter m_nUpdateWaitShrinking; ///< Count of waiting until shrinking completed duting \p update() call
+ event_counter m_nUpdateWaitShrinking; ///< Count of waiting until shrinking completed during \p update() call
event_counter m_nUpdateRetry; ///< Count of update retries via concurrent operations
event_counter m_nUpdateRootWaitShrinking; ///< Count of waiting until root shrinking completed duting \p update() call
event_counter m_nUpdateSuccess; ///< Count of updating data node
- event_counter m_nUpdateUnlinked; ///< Count of updating of unlinked node attempts
+ event_counter m_nUpdateUnlinked; ///< Count of attempts to update unlinked node
event_counter m_nDisposedNode; ///< Count of disposed node
+ event_counter m_nDisposedValue; ///< Count of disposed value
+ event_counter m_nExtractedValue; ///< Count of extracted value
+ event_counter m_nRemoveRetry; ///< Count o erase/extract retries
+ event_counter m_nRemoveWaitShrinking; ///< ount of waiting until shrinking completed during \p erase() or \p extract() call
+ event_counter m_nRemoveRootWaitShrinking; ///< Count of waiting until root shrinking completed duting \p erase() or \p extract() call
+
+ event_counter m_nRightRotation; ///< Count of single right rotation
+ event_counter m_nLeftRotation; ///< Count of single left rotation
+ event_counter m_nLeftRightRotation; ///< Count of double left-over-right rotation
+ event_counter m_nRightLeftRotation; ///< Count of double right-over-left rotation
//@cond
void onFindSuccess() { ++m_nFindSuccess ; }
void onUpdateSuccess() { ++m_nUpdateSuccess; }
void onUpdateUnlinked() { ++m_nUpdateUnlinked; }
void onDisposeNode() { ++m_nDisposedNode; }
-
+ void onDisposeValue() { ++m_nDisposedValue; }
+ void onExtractValue() { ++m_nExtractedValue; }
+ void onRemoveRetry() { ++m_nRemoveRetry; }
+ void onRemoveWaitShrinking() { ++m_nRemoveWaitShrinking; }
+ void onRemoveRootWaitShrinking() { ++m_nRemoveRootWaitShrinking; }
+
+ void onRotateRight() { ++m_nRightRotation; }
+ void onRotateLeft() { ++m_nLeftRotation; }
+ void onRotateRightOverLeft() { ++m_nRightLeftRotation; }
+ void onRotateLeftOverRight() { ++m_nLeftRightRotation; }
//@endcond
};
void onUpdateSuccess() const {}
void onUpdateUnlinked() const {}
void onDisposeNode() const {}
-
+ void onDisposeValue() const {}
+ void onExtractValue() const {}
+ void onRemoveRetry() const {}
+ void onRemoveWaitShrinking() const {}
+ void onRemoveRootWaitShrinking() const {}
+
+ void onRotateRight() const {}
+ void onRotateLeft() const {}
+ void onRotateRightOverLeft() const {}
+ void onRotateLeftOverRight() const {}
//@endcond
};
that can lead to lock contention.
When this option is enabled, the new node is created before locking the parent node.
- After that, the parent is locked and checked whether the new node can be attached to the parent.
+ After that, the parent is locked and checked whether the new node may be attached to the parent.
In this case, false node creating can be performed, but locked section can be significantly small.
*/
template <bool Enable>