CDS_UNUSED( pNode );
return cxx_allocator().New();
},
- static_cast<int>(update_flags::allow_insert)
- ) == static_cast<int>(update_flags::result_inserted);
+ update_flags::allow_insert
+ ) == update_flags::result_inserted;
}
/// Inserts new node
CDS_UNUSED( pNode );
return cxx_allocator().New( val );
},
- static_cast<int>(update_flags::allow_insert)
- ) == static_cast<int>(update_flags::result_inserted);
+ update_flags::allow_insert
+ ) == update_flags::result_inserted;
}
/// Inserts new node and initialize it by a functor
func( pNode->m_key, *pVal );
return pVal;
},
- static_cast<int>(update_flags::allow_insert)
- ) == static_cast<int>(update_flags::result_inserted);
+ update_flags::allow_insert
+ ) == update_flags::result_inserted;
}
/// For key \p key inserts data of type \p mapped_type created in-place from \p args
CDS_UNUSED( pNode );
return cxx_allocator().New( std::forward<Args>(args)...);
},
- static_cast<int>(update_flags::allow_insert)
- ) == static_cast<int>(update_flags::result_inserted);
+ update_flags::allow_insert
+ ) == update_flags::result_inserted;
}
/// Ensures that the \p key exists in the map
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
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;
+ typedef link_node< node<Key, T*, SyncMonitor>, T, SyncMonitor > base_class;
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
};
#include <memory> // unique_ptr
#include <cds/container/details/bronson_avltree_base.h>
#include <cds/urcu/details/check_deadlock.h>
-#include <cds/details/binary_functor_wrapper.h>
-
namespace cds { namespace container {
CDS_UNUSED( pred );
return do_remove(
key,
- cds::details::predicate_wrapper<key_type, Less, cds::details::trivial_accessor >(),
+ cds::opt::details::make_comparator_from_less<Less>(),
[]( mapped_type pVal ) -> bool { free_value( pVal ); return true; }
);
}
CDS_UNUSED( pred );
return do_remove(
key,
- cds::details::predicate_wrapper<key_type, Less, cds::details::trivial_accessor >(),
+ cds::opt::details::make_comparator_from_less<Less>(),
[&f]( mapped_type pVal ) -> bool {
assert( pVal );
f( *pVal );
do_remove(
key,
- cds::details::predicate_wrapper<key_type, Less, cds::details::trivial_accessor >(),
+ cds::opt::details::make_comparator_from_less<Less>(),
[&pExtracted]( mapped_type pVal ) -> bool { pExtracted.reset( pVal ); return false; }
);
return pExtracted;
bool find( K const& key, Func f )
{
return do_find( key, key_comparator(),
- [&f]( sync_monitor& monitor, node_type * pNode ) -> bool {
+ [&f]( node_type * pNode ) -> bool {
assert( pNode != nullptr );
- node_scoped_lock l( monitor, *pNode );
mapped_type pVal = pNode->m_pValue.load( memory_model::memory_order_relaxed );
if ( pVal ) {
f( pNode->m_key, *pVal );
bool find_with( K const& key, Less pred, Func f )
{
CDS_UNUSED( pred );
- return do_find( key, opt::details::make_comparator_from_less<Less>(),
- [&f]( sync_monitor& monitor, node_type * pNode ) -> bool {
+ return do_find( key, cds::opt::details::make_comparator_from_less<Less>(),
+ [&f]( node_type * pNode ) -> bool {
assert( pNode != nullptr );
- node_scoped_lock l( monitor, *pNode );
mapped_type pVal = pNode->m_pValue.load( memory_model::memory_order_relaxed );
if ( pVal ) {
f( pNode->m_key, *pVal );
template <typename K>
bool find( K const& key )
{
- return do_find( key, key_comparator(), []( sync_monitor&, node_type * ) -> bool { return true; });
+ return do_find( key, key_comparator(), []( node_type * ) -> bool { return true; });
}
/// Finds the key \p val using \p pred predicate for searching
bool find_with( K const& key, Less pred )
{
CDS_UNUSED( pred );
- return do_find( key, opt::details::make_comparator_from_less<Less>(), []( sync_monitor&, node_type * ) -> bool { return true; } );
+ return do_find( key, cds::opt::details::make_comparator_from_less<Less>(), []( node_type * ) -> bool { return true; } );
}
/// Clears the tree (thread safe, not atomic)
// key found
node_scoped_lock l( m_Monitor, *pChild );
if ( pChild->is_valued( memory_model::memory_order_relaxed )) {
- if ( f( m_Monitor, pChild ) ) {
+ if ( f( pChild ) ) {
m_stat.onFindSuccess();
return find_result::found;
}
int try_update_node( Func funcUpdate, node_type * pNode )
{
mapped_type pOld;
+ assert( pNode != nullptr );
{
- assert( pNode != nullptr );
node_scoped_lock l( m_Monitor, *pNode );
if ( pNode->is_unlinked( memory_model::memory_order_relaxed )) {
pOld = pNode->value( memory_model::memory_order_relaxed );
mapped_type pVal = funcUpdate( pNode );
- assert( pVal != nullptr );
- pNode->m_pValue.store( pVal, memory_model::memory_order_relaxed );
+ if ( pVal == pOld )
+ pOld = nullptr;
+ else {
+ assert( pVal != nullptr );
+ pNode->m_pValue.store( pVal, memory_model::memory_order_relaxed );
+ }
}
if ( pOld ) {
// Mark the node as unlinked
pNode->version( node_type::unlinked, memory_model::memory_order_release );
- mapped_type pVal = pNode->value( memory_model::memory_order_relaxed );
- if ( pVal ) {
- free_value( pVal );
- m_stat.onDisposeValue();
- pNode->m_pValue.store( nullptr, memory_model::memory_order_relaxed );
- }
+
+ // The value will be disposed by calling function
+ pNode->m_pValue.store( nullptr, memory_model::memory_order_relaxed );
+
disp.dispose( pNode );
m_stat.onDisposeNode();
stat_data stat;
value_type()
+ : nVal(0)
{}
value_type( int v )
};
template <typename Q>
- static void ensure_func( bool bNew, Q /*key*/, value_type& i )
+ static void ensure_func( bool bNew, Q key, value_type& i )
{
+ i.nVal = key * 100;
if ( bNew )
++i.stat.nEnsureNewFuncCall;
else
{
copy_found<value_type> f;
CPPUNIT_ASSERT( s.find( key, std::ref( f ) ) );
- CPPUNIT_ASSERT( f.m_found.nVal == 100 );
+ CPPUNIT_ASSERT( f.m_found.nVal == 0 );
CPPUNIT_ASSERT( f.m_found.stat.nEnsureExistFuncCall == 0 );
CPPUNIT_ASSERT( f.m_found.stat.nEnsureNewFuncCall == 0 );
}
{
copy_found<value_type> f;
CPPUNIT_ASSERT( s.find( key, std::ref( f ) ) );
- CPPUNIT_ASSERT( f.m_found.nVal == 100 );
+ CPPUNIT_ASSERT( f.m_found.nVal == 1000 );
CPPUNIT_ASSERT( f.m_found.stat.nEnsureExistFuncCall == 1 );
CPPUNIT_ASSERT( f.m_found.stat.nEnsureNewFuncCall == 0 );
}
ensureResult = s.update( 13, []( bool /*bNew*/, key_type key, value_type& v )
{
- v.nVal = key * 100;
- ++v.stat.nEnsureExistFuncCall;
+ v.nVal = key * 1000;
+ ++v.stat.nEnsureNewFuncCall;
});
CPPUNIT_ASSERT( ensureResult.first && ensureResult.second );
CPPUNIT_ASSERT( !s.empty() );
copy_found<value_type> f;
key = 13;
CPPUNIT_ASSERT( s.find( key, std::ref( f ) ) );
- CPPUNIT_ASSERT( f.m_found.nVal == 1300 );
+ CPPUNIT_ASSERT( f.m_found.nVal == 13000 );
CPPUNIT_ASSERT( f.m_found.stat.nEnsureExistFuncCall == 0 );
CPPUNIT_ASSERT( f.m_found.stat.nEnsureNewFuncCall == 1 );
}
CPPUNIT_TEST_SUITE( BronsonAVLTreeHdrTest )
CPPUNIT_TEST( BronsonAVLTree_rcu_gpb_less )
- CPPUNIT_TEST( BronsonAVLTree_rcu_gpb_cmp )
- CPPUNIT_TEST( BronsonAVLTree_rcu_gpb_cmpless )
- CPPUNIT_TEST( BronsonAVLTree_rcu_gpb_less_ic )
- CPPUNIT_TEST( BronsonAVLTree_rcu_gpb_cmp_ic )
- CPPUNIT_TEST( BronsonAVLTree_rcu_gpb_less_stat )
- CPPUNIT_TEST( BronsonAVLTree_rcu_gpb_cmp_ic_stat )
- CPPUNIT_TEST( BronsonAVLTree_rcu_gpb_cmp_ic_stat_yield )
+ //CPPUNIT_TEST( BronsonAVLTree_rcu_gpb_cmp )
+ //CPPUNIT_TEST( BronsonAVLTree_rcu_gpb_cmpless )
+ //CPPUNIT_TEST( BronsonAVLTree_rcu_gpb_less_ic )
+ //CPPUNIT_TEST( BronsonAVLTree_rcu_gpb_cmp_ic )
+ //CPPUNIT_TEST( BronsonAVLTree_rcu_gpb_less_stat )
+ //CPPUNIT_TEST( BronsonAVLTree_rcu_gpb_cmp_ic_stat )
+ //CPPUNIT_TEST( BronsonAVLTree_rcu_gpb_cmp_ic_stat_yield )
CPPUNIT_TEST_SUITE_END()
};
} // namespace tree
void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpb_less()
{
- typedef cc::BronsonAVLTreeMap< rcu_type, key_type, value_type,
+ struct traits: public
cc::bronson_avltree::make_traits<
co::less< std::less<key_type> >
>::type
- > map_type;
-
+ {};
+ typedef cc::BronsonAVLTreeMap< rcu_type, key_type, value_type, traits > map_type;
test<map_type, print_stat>();
-
}
} // namespace tree