-//$$CDS-header$$
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
#ifndef CDSLIB_INTRUSIVE_IMPL_ELLEN_BINTREE_H
#define CDSLIB_INTRUSIVE_IMPL_ELLEN_BINTREE_H
the priority value plus some uniformly distributed random value.
@note In the current implementation we do not use helping technique described in the original paper.
- In Hazard Pointer schema helping is too complicated and does not give any observable benefits.
+ In Hazard Pointer schema the helping is too complicated and does not give any observable benefits.
Instead of helping, when a thread encounters a concurrent operation it just spins waiting for
- the operation done. Such solution allows greatly simplify the implementation of tree.
+ the operation done. Such solution allows greatly simplify implementation of the tree.
- @warning Recall the tree is <b>unbalanced</b>. The complexity of operations is <tt>O(log N)</tt>
- for uniformly distributed random keys, but in worst case the complexity is <tt>O(N)</tt>.
+ @attention Recall the tree is <b>unbalanced</b>. The complexity of operations is <tt>O(log N)</tt>
+ for uniformly distributed random keys, but in the worst case the complexity is <tt>O(N)</tt>.
@note Do not include <tt><cds/intrusive/impl/ellen_bintree.h></tt> header file explicitly.
There are header file for each GC type:
{
static internal_node const& to_internal_node( tree_node const& n )
{
- assert( n.is_internal() );
+ assert( n.is_internal());
return static_cast<internal_node const&>( n );
}
static leaf_node const& to_leaf_node( tree_node const& n )
{
- assert( n.is_leaf() );
+ assert( n.is_leaf());
return static_cast<leaf_node const&>( n );
}
};
protected:
//@cond
- static void free_leaf_node( value_type * p )
+ static void free_leaf_node( void* p )
{
- disposer()( p );
+ disposer()( reinterpret_cast<value_type*>( p ));
}
internal_node * alloc_internal_node() const
return pNode;
}
- static void free_internal_node( internal_node * pNode )
+ static void free_internal_node( void* pNode )
{
- cxx_node_allocator().Delete( pNode );
+ cxx_node_allocator().Delete( reinterpret_cast<internal_node*>( pNode ));
}
struct internal_node_deleter {
- void operator()( internal_node * p) const
+ void operator()( internal_node* p) const
{
- free_internal_node( p );
+ cxx_node_allocator().Delete( p );
}
};
return cxx_update_desc_allocator().New();
}
- static void free_update_desc( update_desc * pDesc )
+ static void free_update_desc( void* pDesc )
{
- cxx_update_desc_allocator().Delete( pDesc );
+ cxx_update_desc_allocator().Delete( reinterpret_cast<update_desc*>( pDesc ));
}
void retire_node( tree_node * pNode ) const
{
- if ( pNode->is_leaf() ) {
+ if ( pNode->is_leaf()) {
assert( static_cast<leaf_node *>( pNode ) != &m_LeafInf1 );
assert( static_cast<leaf_node *>( pNode ) != &m_LeafInf2 );
back_off bkoff;
for ( ;; ) {
- if ( search( res, val, node_compare() )) {
- if ( pNewInternal.get() )
+ if ( search( res, val, node_compare())) {
+ if ( pNewInternal.get())
m_Stat.onInternalNodeDeleted() ; // unique_internal_node_ptr deletes internal node
m_Stat.onInsertFailed();
return false;
if ( res.updGrandParent.bits() == update_desc::Clean && res.updParent.bits() == update_desc::Clean ) {
- if ( !pNewInternal.get() )
- pNewInternal.reset( alloc_internal_node() );
+ if ( !pNewInternal.get())
+ pNewInternal.reset( alloc_internal_node());
if ( try_insert( val, pNewInternal.get(), res )) {
f( val );
The functor can change non-key fields of the \p item; however, \p func must guarantee
that during changing no any other modifications could be made on this item by concurrent threads.
- Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+ Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
i.e. the node has been inserted or updated,
\p second is \p true if new item has been added or \p false if the item with \p key
already exists.
back_off bkoff;
for ( ;; ) {
- if ( search( res, val, node_compare() )) {
+ if ( search( res, val, node_compare())) {
func( false, *node_traits::to_value_ptr( res.pLeaf ), val );
- if ( pNewInternal.get() )
+ if ( pNewInternal.get())
m_Stat.onInternalNodeDeleted() ; // unique_internal_node_ptr deletes internal node
- m_Stat.onEnsureExist();
+ m_Stat.onUpdateExist();
return std::make_pair( true, false );
}
if ( !bAllowInsert )
return std::make_pair( false, false );
- if ( !pNewInternal.get() )
- pNewInternal.reset( alloc_internal_node() );
+ if ( !pNewInternal.get())
+ pNewInternal.reset( alloc_internal_node());
if ( try_insert( val, pNewInternal.get(), res )) {
func( true, val, val );
}
bkoff();
- m_Stat.onEnsureRetry();
+ m_Stat.onUpdateRetry();
}
++m_ItemCounter;
- m_Stat.onEnsureNew();
+ m_Stat.onUpdateNew();
return std::make_pair( true, true );
}
//@cond
unlinks it from the tree, and returns \p true.
If the item with key equal to \p key is not found the function return \p false.
- Note the hash functor should accept a parameter of type \p Q that can be not the same as \p value_type.
+ Note the \p Traits::less and/or \p Traits::compare predicate should accept a parameter of type \p Q
+ that can be not the same as \p value_type.
*/
template <typename Q>
bool erase( const Q& key )
If the item with key equal to \p key is not found the function return \p false.
- Note the hash functor should accept a parameter of type \p Q that can be not the same as \p value_type.
+ Note the \p Traits::less and/or \p Traits::compare predicate should accept a parameter of type \p Q
+ that can be not the same as \p value_type.
*/
template <typename Q, typename Func>
bool erase( Q const& key, Func f )
*/
guarded_ptr extract_min()
{
- guarded_ptr gp;
- extract_min_( gp.guard() );
- return gp;
+ return extract_min_();
}
/// Extracts an item with maximal key from the tree
*/
guarded_ptr extract_max()
{
- guarded_ptr gp;
- extract_max_( gp.guard());
- return gp;
+ return extract_max_();
}
/// Extracts an item from the tree
template <typename Q>
guarded_ptr extract( Q const& key )
{
- guarded_ptr gp;
- extract_( gp.guard(), key );
- return gp;
+ return extract_( key );
}
/// Extracts an item from the tree using \p pred for searching
template <typename Q, typename Less>
guarded_ptr extract_with( Q const& key, Less pred )
{
- guarded_ptr gp;
- extract_with_( gp.guard(), key, pred );
- return gp;
+ return extract_with_( key, pred );
}
/// Checks whether the set contains \p key
bool contains( Q const& key ) const
{
search_result res;
- if ( search( res, key, node_compare() )) {
+ if ( search( res, key, node_compare())) {
m_Stat.onFindSuccess();
return true;
}
> compare_functor;
search_result res;
- if ( search( res, key, compare_functor() )) {
+ if ( search( res, key, compare_functor())) {
m_Stat.onFindSuccess();
return true;
}
template <typename Q>
guarded_ptr get( Q const& key ) const
{
- guarded_ptr gp;
- get_( gp.guard(), key );
- return gp;
+ return get_( key );
}
/// Finds \p key with predicate \p pred and returns the item found
template <typename Q, typename Less>
guarded_ptr get_with( Q const& key, Less pred ) const
{
- guarded_ptr gp;
- get_with_( gp.guard(), key, pred );
- return gp;
+ return get_with_( key, pred );
}
/// Checks if the tree is empty
this sequence
\code
tree.clear();
- assert( tree.empty() );
+ assert( tree.empty());
\endcode
the assertion could be raised.
tree_node * pLeaf = const_cast<internal_node *>( &m_Root );
// Get leftmost leaf
- while ( pLeaf->is_internal() ) {
+ while ( pLeaf->is_internal()) {
pGrandParent = pParent;
pParent = static_cast<internal_node *>( pLeaf );
pLeaf = pParent->m_pLeft.load( memory_model::memory_order_relaxed );
// Remove leftmost leaf and its parent node
assert( pGrandParent );
assert( pParent );
- assert( pLeaf->is_leaf() );
+ assert( pLeaf->is_leaf());
pGrandParent->m_pLeft.store( pParent->m_pRight.load( memory_model::memory_order_relaxed ), memory_model::memory_order_relaxed );
- free_leaf_node( node_traits::to_value_ptr( static_cast<leaf_node *>( pLeaf ) ) );
+ free_leaf_node( node_traits::to_value_ptr( static_cast<leaf_node *>( pLeaf )));
free_internal_node( pParent );
}
}
&& node_compare()( *pLeft, *pRight ) < 0 )
{
bool bRet = true;
- if ( pLeft->is_internal() )
- bRet = check_consistency( static_cast<internal_node *>( pLeft ) );
+ if ( pLeft->is_internal())
+ bRet = check_consistency( static_cast<internal_node *>( pLeft ));
assert( bRet );
- if ( bRet && pRight->is_internal() )
+ if ( bRet && pRight->is_internal())
bRet = bRet && check_consistency( static_cast<internal_node *>( pRight ));
assert( bRet );
updParent = nullptr;
bRightLeaf = false;
tree_node * pLeaf = const_cast<internal_node *>( &m_Root );
- while ( pLeaf->is_internal() ) {
+ while ( pLeaf->is_internal()) {
res.guards.copy( search_result::Guard_GrandParent, search_result::Guard_Parent );
pGrandParent = pParent;
res.guards.copy( search_result::Guard_Parent, search_result::Guard_Leaf );
updParent = search_protect_update( res, pParent->m_pUpdate );
- switch ( updParent.bits() ) {
+ switch ( updParent.bits()) {
case update_desc::DFlag:
case update_desc::Mark:
m_Stat.onSearchRetry();
}
}
- assert( pLeaf->is_leaf() );
- nCmp = cmp( key, *static_cast<leaf_node *>(pLeaf) );
+ assert( pLeaf->is_leaf());
+ nCmp = cmp( key, *static_cast<leaf_node *>(pLeaf));
res.pGrandParent = pGrandParent;
res.pParent = pParent;
pGrandParent = nullptr;
updParent = nullptr;
tree_node * pLeaf = const_cast<internal_node *>( &m_Root );
- while ( pLeaf->is_internal() ) {
+ while ( pLeaf->is_internal()) {
res.guards.copy( search_result::Guard_GrandParent, search_result::Guard_Parent );
pGrandParent = pParent;
res.guards.copy( search_result::Guard_Parent, search_result::Guard_Leaf );
updParent = search_protect_update( res, pParent->m_pUpdate );
- switch ( updParent.bits() ) {
+ switch ( updParent.bits()) {
case update_desc::DFlag:
case update_desc::Mark:
m_Stat.onSearchRetry();
res.pGrandParent = pGrandParent;
res.pParent = pParent;
- assert( pLeaf->is_leaf() );
+ assert( pLeaf->is_leaf());
res.pLeaf = static_cast<leaf_node *>( pLeaf );
res.updParent = updParent;
res.updGrandParent = updGrandParent;
updParent = nullptr;
bRightLeaf = false;
tree_node * pLeaf = const_cast<internal_node *>( &m_Root );
- while ( pLeaf->is_internal() ) {
+ while ( pLeaf->is_internal()) {
res.guards.copy( search_result::Guard_GrandParent, search_result::Guard_Parent );
pGrandParent = pParent;
res.guards.copy( search_result::Guard_Parent, search_result::Guard_Leaf );
updParent = search_protect_update( res, pParent->m_pUpdate );
- switch ( updParent.bits() ) {
+ switch ( updParent.bits()) {
case update_desc::DFlag:
case update_desc::Mark:
m_Stat.onSearchRetry();
res.pGrandParent = pGrandParent;
res.pParent = pParent;
- assert( pLeaf->is_leaf() );
+ assert( pLeaf->is_leaf());
res.pLeaf = static_cast<leaf_node *>( pLeaf );
res.updParent = updParent;
res.updGrandParent = updGrandParent;
void help( update_ptr pUpdate )
{
// pUpdate must be guarded!
- switch ( pUpdate.bits() ) {
+ switch ( pUpdate.bits()) {
case update_desc::IFlag:
- help_insert( pUpdate.ptr() );
+ help_insert( pUpdate.ptr());
m_Stat.onHelpInsert();
break;
case update_desc::DFlag:
- help_delete( pUpdate.ptr() );
+ help_delete( pUpdate.ptr());
m_Stat.onHelpDelete();
break;
case update_desc::Mark:
//m_Stat.onHelpMark();
- //help_marked( pUpdate.ptr() );
+ //help_marked( pUpdate.ptr());
break;
}
}
static tree_node * protect_sibling( typename gc::Guard& guard, atomics::atomic<tree_node *>& sibling )
{
tree_node * pSibling = guard.protect( sibling, [](tree_node * p) -> internal_node* { return static_cast<internal_node *>(p); } );
- if ( pSibling->is_leaf() )
+ if ( pSibling->is_leaf())
guard.assign( node_traits::to_value_ptr( static_cast<leaf_node *>( pSibling )));
return pSibling;
}
bool try_insert( value_type& val, internal_node * pNewInternal, search_result& res )
{
assert( res.updParent.bits() == update_desc::Clean );
- assert( res.pLeaf->is_leaf() );
+ assert( res.pLeaf->is_leaf());
// check search result
if ( res.pParent->get_child( res.bRightLeaf, memory_model::memory_order_acquire ) == res.pLeaf ) {
int nCmp = node_compare()(val, *res.pLeaf);
if ( nCmp < 0 ) {
if ( res.pGrandParent ) {
- assert( !res.pLeaf->infinite_key() );
+ assert( !res.pLeaf->infinite_key());
pNewInternal->infinite_key( 0 );
key_extractor()(pNewInternal->m_Key, *node_traits::to_value_ptr( res.pLeaf ));
}
pNewInternal->m_pRight.store( static_cast<tree_node *>(res.pLeaf), memory_model::memory_order_release );
}
else {
- assert( !res.pLeaf->is_internal() );
+ assert( !res.pLeaf->is_internal());
pNewInternal->infinite_key( 0 );
key_extractor()(pNewInternal->m_Key, val);
pNewInternal->m_pLeft.store( static_cast<tree_node *>(res.pLeaf), memory_model::memory_order_relaxed );
pNewInternal->m_pRight.store( static_cast<tree_node *>(pNewLeaf), memory_model::memory_order_release );
- assert( !res.pLeaf->infinite_key() );
+ assert( !res.pLeaf->infinite_key());
}
typename gc::Guard guard;
pOp->iInfo.pLeaf = res.pLeaf;
pOp->iInfo.bRightLeaf = res.bRightLeaf;
- update_ptr updCur( res.updParent.ptr() );
+ update_ptr updCur( res.updParent.ptr());
if ( res.pParent->m_pUpdate.compare_exchange_strong( updCur, update_ptr( pOp, update_desc::IFlag ),
- memory_model::memory_order_acquire, atomics::memory_order_relaxed ) ) {
+ memory_model::memory_order_acquire, atomics::memory_order_relaxed )) {
// do insert
help_insert( pOp );
retire_update_desc( pOp );
back_off bkoff;
for ( ;; ) {
- if ( !search( res, val, cmp ) || !eq( val, *res.pLeaf ) ) {
+ if ( !search( res, val, cmp ) || !eq( val, *res.pLeaf )) {
if ( pOp )
retire_update_desc( pOp );
m_Stat.onEraseFailed();
if ( res.updGrandParent.bits() == update_desc::Clean && res.updParent.bits() == update_desc::Clean ) {
if ( !pOp )
pOp = alloc_update_desc();
- if ( check_delete_precondition( res ) ) {
+ if ( check_delete_precondition( res )) {
typename gc::Guard guard;
guard.assign( pOp );
pOp->dInfo.bRightParent = res.bRightParent;
pOp->dInfo.bRightLeaf = res.bRightLeaf;
- update_ptr updGP( res.updGrandParent.ptr() );
+ update_ptr updGP( res.updGrandParent.ptr());
if ( res.pGrandParent->m_pUpdate.compare_exchange_strong( updGP, update_ptr( pOp, update_desc::DFlag ),
- memory_model::memory_order_acquire, atomics::memory_order_relaxed ) ) {
- if ( help_delete( pOp ) ) {
+ memory_model::memory_order_acquire, atomics::memory_order_relaxed )) {
+ if ( help_delete( pOp )) {
// res.pLeaf is not deleted yet since it is guarded
- f( *node_traits::to_value_ptr( res.pLeaf ) );
+ f( *node_traits::to_value_ptr( res.pLeaf ));
break;
}
pOp = nullptr;
return true;
}
+ template <typename Q, typename Compare>
+ guarded_ptr extract_item( Q const& key, Compare cmp )
+ {
+ update_desc * pOp = nullptr;
+ search_result res;
+ back_off bkoff;
+
+ for ( ;; ) {
+ if ( !search( res, key, cmp )) {
+ if ( pOp )
+ retire_update_desc( pOp );
+ m_Stat.onEraseFailed();
+ return guarded_ptr();
+ }
+
+ if ( res.updGrandParent.bits() == update_desc::Clean && res.updParent.bits() == update_desc::Clean ) {
+ if ( !pOp )
+ pOp = alloc_update_desc();
+ if ( check_delete_precondition( res )) {
+ typename gc::Guard guard;
+ guard.assign( pOp );
+
+ pOp->dInfo.pGrandParent = res.pGrandParent;
+ pOp->dInfo.pParent = res.pParent;
+ pOp->dInfo.pLeaf = res.pLeaf;
+ pOp->dInfo.pUpdateParent = res.updParent.ptr();
+ pOp->dInfo.bRightParent = res.bRightParent;
+ pOp->dInfo.bRightLeaf = res.bRightLeaf;
+
+ update_ptr updGP( res.updGrandParent.ptr());
+ if ( res.pGrandParent->m_pUpdate.compare_exchange_strong( updGP, update_ptr( pOp, update_desc::DFlag ),
+ memory_model::memory_order_acquire, atomics::memory_order_relaxed )) {
+ if ( help_delete( pOp ))
+ break;
+ pOp = nullptr;
+ }
+ }
+ }
+
+ bkoff();
+ m_Stat.onEraseRetry();
+ }
+
+ --m_ItemCounter;
+ m_Stat.onEraseSuccess();
+ return guarded_ptr( res.guards.release( search_result::Guard_Leaf ));
+ }
+
template <typename Q>
- bool extract_( typename guarded_ptr::native_guard& guard, Q const& key )
+ guarded_ptr extract_( Q const& key )
{
- return erase_( key, node_compare(),
- []( Q const&, leaf_node const& ) -> bool { return true; },
- [&guard]( value_type& found ) { guard.set( &found ); } );
+ return extract_item( key, node_compare());
}
template <typename Q, typename Less>
- bool extract_with_( typename guarded_ptr::native_guard& guard, Q const& key, Less /*pred*/ )
+ guarded_ptr extract_with_( Q const& key, Less /*pred*/ )
{
typedef ellen_bintree::details::compare<
key_type,
node_traits
> compare_functor;
- return erase_( key, compare_functor(),
- []( Q const&, leaf_node const& ) -> bool { return true; },
- [&guard]( value_type& found ) { guard.set( &found ); } );
+ return extract_item( key, compare_functor());
}
- bool extract_max_( typename guarded_ptr::native_guard& gp )
+ guarded_ptr extract_max_()
{
update_desc * pOp = nullptr;
search_result res;
if ( pOp )
retire_update_desc( pOp );
m_Stat.onExtractMaxFailed();
- return false;
+ return guarded_ptr();
}
if ( res.updGrandParent.bits() == update_desc::Clean && res.updParent.bits() == update_desc::Clean ) {
if ( !pOp )
pOp = alloc_update_desc();
- if ( check_delete_precondition( res ) ) {
+ if ( check_delete_precondition( res )) {
typename gc::Guard guard;
guard.assign( pOp );
pOp->dInfo.bRightParent = res.bRightParent;
pOp->dInfo.bRightLeaf = res.bRightLeaf;
- update_ptr updGP( res.updGrandParent.ptr() );
+ update_ptr updGP( res.updGrandParent.ptr());
if ( res.pGrandParent->m_pUpdate.compare_exchange_strong( updGP, update_ptr( pOp, update_desc::DFlag ),
- memory_model::memory_order_acquire, atomics::memory_order_relaxed ) )
+ memory_model::memory_order_acquire, atomics::memory_order_relaxed ))
{
- if ( help_delete( pOp ) )
+ if ( help_delete( pOp ))
break;
pOp = nullptr;
}
--m_ItemCounter;
m_Stat.onExtractMaxSuccess();
- gp.set( node_traits::to_value_ptr( res.pLeaf ));
- return true;
+ return guarded_ptr( res.guards.release( search_result::Guard_Leaf ));
}
- bool extract_min_( typename guarded_ptr::native_guard& gp )
+ guarded_ptr extract_min_()
{
update_desc * pOp = nullptr;
search_result res;
if ( pOp )
retire_update_desc( pOp );
m_Stat.onExtractMinFailed();
- return false;
+ return guarded_ptr();
}
if ( res.updGrandParent.bits() == update_desc::Clean && res.updParent.bits() == update_desc::Clean ) {
if ( !pOp )
pOp = alloc_update_desc();
- if ( check_delete_precondition( res ) ) {
+ if ( check_delete_precondition( res )) {
typename gc::Guard guard;
guard.assign( pOp );
pOp->dInfo.bRightParent = res.bRightParent;
pOp->dInfo.bRightLeaf = res.bRightLeaf;
- update_ptr updGP( res.updGrandParent.ptr() );
+ update_ptr updGP( res.updGrandParent.ptr());
if ( res.pGrandParent->m_pUpdate.compare_exchange_strong( updGP, update_ptr( pOp, update_desc::DFlag ),
memory_model::memory_order_acquire, atomics::memory_order_relaxed ))
{
--m_ItemCounter;
m_Stat.onExtractMinSuccess();
- gp.set( node_traits::to_value_ptr( res.pLeaf ));
- return true;
+ return guarded_ptr( res.guards.release( search_result::Guard_Leaf ));
}
template <typename Q, typename Func>
bool find_( Q& val, Func f ) const
{
search_result res;
- if ( search( res, val, node_compare() )) {
+ if ( search( res, val, node_compare())) {
assert( res.pLeaf );
f( *node_traits::to_value_ptr( res.pLeaf ), val );
> compare_functor;
search_result res;
- if ( search( res, val, compare_functor() )) {
+ if ( search( res, val, compare_functor())) {
assert( res.pLeaf );
f( *node_traits::to_value_ptr( res.pLeaf ), val );
}
template <typename Q>
- bool get_( typename guarded_ptr::native_guard& guard, Q const& val ) const
+ guarded_ptr get_( Q const& val ) const
{
- return find_( val, [&guard]( value_type& found, Q const& ) { guard.set( &found ); } );
+ search_result res;
+ if ( search( res, val, node_compare())) {
+ assert( res.pLeaf );
+ m_Stat.onFindSuccess();
+ return guarded_ptr( res.guards.release( search_result::Guard_Leaf ));
+ }
+
+ m_Stat.onFindFailed();
+ return guarded_ptr();
}
template <typename Q, typename Less>
- bool get_with_( typename guarded_ptr::native_guard& guard, Q const& val, Less pred ) const
+ guarded_ptr get_with_( Q const& val, Less pred ) const
{
- return find_with_( val, pred, [&guard]( value_type& found, Q const& ) { guard.set( &found ); } );
+ CDS_UNUSED( pred );
+
+ typedef ellen_bintree::details::compare<
+ key_type,
+ value_type,
+ opt::details::make_comparator_from_less<Less>,
+ node_traits
+ > compare_functor;
+
+ search_result res;
+ if ( search( res, val, compare_functor())) {
+ assert( res.pLeaf );
+ m_Stat.onFindSuccess();
+ return guarded_ptr( res.guards.release( search_result::Guard_Leaf ));
+ }
+
+ m_Stat.onFindFailed();
+ return guarded_ptr();
+
}
//@endcond