struct clean_disposer {
void operator()( value_type * p )
{
- lazy_list::node_cleaner<gc, node_type, memory_model>()( node_traits::to_node_ptr( p ) );
+ lazy_list::node_cleaner<gc, node_type, memory_model>()( node_traits::to_node_ptr( p ));
disposer()( p );
}
};
void retire_node( node_type * pNode )
{
assert( pNode != nullptr );
- gc::template retire<clean_disposer>( node_traits::to_value_ptr( *pNode ) );
+ gc::template retire<clean_disposer>( node_traits::to_value_ptr( *pNode ));
}
//@endcond
do {
pNext = pCur->m_pNext.load(memory_model::memory_order_relaxed).ptr();
g.assign( node_traits::to_value_ptr( pNext ));
- } while ( pNext != pCur->m_pNext.load(memory_model::memory_order_relaxed).ptr() );
+ } while ( pNext != pCur->m_pNext.load(memory_model::memory_order_relaxed).ptr());
- m_pNode = m_Guard.assign( g.template get<value_type>() );
+ m_pNode = m_Guard.assign( g.template get<value_type>());
}
}
}
node_type * pNode = node_traits::to_node_ptr( m_pNode );
// Dummy tail node could not be marked
- while ( pNode->is_marked() ) {
+ while ( pNode->is_marked()) {
node_type * p = pNode->m_pNext.load(memory_model::memory_order_relaxed).ptr();
g.assign( node_traits::to_value_ptr( p ));
- if ( p == pNode->m_pNext.load(memory_model::memory_order_relaxed).ptr() )
+ if ( p == pNode->m_pNext.load(memory_model::memory_order_relaxed).ptr())
pNode = p;
}
- if ( pNode != node_traits::to_node_ptr( m_pNode ) )
- m_pNode = m_Guard.assign( g.template get<value_type>() );
+ if ( pNode != node_traits::to_node_ptr( m_pNode ))
+ m_pNode = m_Guard.assign( g.template get<value_type>());
}
}
}
const_iterator get_const_end() const
{
- return const_iterator( const_cast<node_type *>(&m_Tail) );
+ return const_iterator( const_cast<node_type *>(&m_Tail));
}
//@endcond
template <typename Q>
bool erase( Q const& key )
{
- return erase_at( &m_Head, key, key_comparator() );
+ return erase_at( &m_Head, key, key_comparator());
}
/// Deletes the item from the list using \p pred predicate for searching
bool erase_with( Q const& key, Less pred )
{
CDS_UNUSED( pred );
- return erase_at( &m_Head, key, cds::opt::details::make_comparator_from_less<Less>() );
+ return erase_at( &m_Head, key, cds::opt::details::make_comparator_from_less<Less>());
}
/// Deletes the item from the list
guarded_ptr extract( Q const& key )
{
guarded_ptr gp;
- extract_at( &m_Head, gp.guard(), key, key_comparator() );
+ extract_at( &m_Head, gp.guard(), key, key_comparator());
return gp;
}
{
CDS_UNUSED( pred );
guarded_ptr gp;
- extract_at( &m_Head, gp.guard(), key, cds::opt::details::make_comparator_from_less<Less>() );
+ extract_at( &m_Head, gp.guard(), key, cds::opt::details::make_comparator_from_less<Less>());
return gp;
}
template <typename Q>
bool contains( Q const& key )
{
- return find_at( &m_Head, key, key_comparator() );
+ return find_at( &m_Head, key, key_comparator());
}
//@cond
template <typename Q>
bool contains( Q const& key, Less pred )
{
CDS_UNUSED( pred );
- return find_at( &m_Head, key, cds::opt::details::make_comparator_from_less<Less>() );
+ return find_at( &m_Head, key, cds::opt::details::make_comparator_from_less<Less>());
}
//@cond
template <typename Q, typename Less>
guarded_ptr get( Q const& key )
{
guarded_ptr gp;
- get_at( &m_Head, gp.guard(), key, key_comparator() );
+ get_at( &m_Head, gp.guard(), key, key_comparator());
return gp;
}
{
CDS_UNUSED( pred );
guarded_ptr gp;
- get_at( &m_Head, gp.guard(), key, cds::opt::details::make_comparator_from_less<Less>() );
+ get_at( &m_Head, gp.guard(), key, cds::opt::details::make_comparator_from_less<Less>());
return gp;
}
{
typename gc::Guard guard;
marked_node_ptr h;
- while ( !empty() ) {
+ while ( !empty()) {
h = m_Head.m_pNext.load( memory_model::memory_order_relaxed );
- guard.assign( node_traits::to_value_ptr( h.ptr() ));
+ guard.assign( node_traits::to_value_ptr( h.ptr()));
if ( m_Head.m_pNext.load(memory_model::memory_order_acquire) == h ) {
m_Head.m_Lock.lock();
h->m_Lock.lock();
h->m_Lock.unlock();
m_Head.m_Lock.unlock();
- retire_node( h.ptr() ) ; // free node
+ retire_node( h.ptr()) ; // free node
}
}
}
// Hack: convert node_type to value_type.
// In principle, auxiliary node cannot be reducible to value_type
// We assume that internal comparator can correctly distinguish aux and regular node.
- return insert_at( pHead, *node_traits::to_value_ptr( pNode ) );
+ return insert_at( pHead, *node_traits::to_value_ptr( pNode ));
}
bool insert_at( node_type * pHead, value_type& val )
{
- link_checker::is_empty( node_traits::to_node_ptr( val ) );
+ link_checker::is_empty( node_traits::to_node_ptr( val ));
position pos;
key_comparator cmp;
while ( true ) {
- search( pHead, val, pos, key_comparator() );
+ search( pHead, val, pos, key_comparator());
{
scoped_position_lock alp( pos );
if ( validate( pos.pPred, pos.pCur )) {
template <typename Func>
bool insert_at( node_type * pHead, value_type& val, Func f )
{
- link_checker::is_empty( node_traits::to_node_ptr( val ) );
+ link_checker::is_empty( node_traits::to_node_ptr( val ));
position pos;
key_comparator cmp;
while ( true ) {
- search( pHead, val, pos, key_comparator() );
+ search( pHead, val, pos, key_comparator());
{
scoped_position_lock alp( pos );
if ( validate( pos.pPred, pos.pCur )) {
key_comparator cmp;
while ( true ) {
- search( pHead, val, pos, key_comparator() );
+ search( pHead, val, pos, key_comparator());
{
scoped_position_lock alp( pos );
if ( validate( pos.pPred, pos.pCur )) {
if ( !bAllowInsert )
return std::make_pair( false, false );
- link_checker::is_empty( node_traits::to_node_ptr( val ) );
+ link_checker::is_empty( node_traits::to_node_ptr( val ));
link_node( node_traits::to_node_ptr( val ), pos.pPred, pos.pCur );
func( true, val, val );
key_comparator cmp;
while ( true ) {
- search( pHead, val, pos, key_comparator() );
+ search( pHead, val, pos, key_comparator());
{
int nResult = 0;
{
scoped_position_lock alp( pos );
- if ( validate( pos.pPred, pos.pCur ) ) {
+ if ( validate( pos.pPred, pos.pCur )) {
if ( pos.pCur != &m_Tail
&& cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0
&& node_traits::to_value_ptr( pos.pCur ) == &val )
if ( pos.pCur != &m_Tail && cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 ) {
// key found
unlink_node( pos.pPred, pos.pCur, pHead );
- f( *node_traits::to_value_ptr( *pos.pCur ) );
+ f( *node_traits::to_value_ptr( *pos.pCur ));
--m_ItemCounter;
nResult = 1;
}
{
position pos;
if ( erase_at( pHead, val, cmp, [](value_type const &){}, pos )) {
- gp.set( pos.guards.template get<value_type>(position::guard_current_item) );
+ gp.set( pos.guards.template get<value_type>(position::guard_current_item));
return true;
}
return false;
while ( pCur.ptr() != pTail ) {
if ( pCur.ptr() != pHead ) {
- if ( cmp( *node_traits::to_value_ptr( *pCur.ptr() ), key ) >= 0 )
+ if ( cmp( *node_traits::to_value_ptr( *pCur.ptr()), key ) >= 0 )
break;
}
[]( marked_node_ptr p ) { return node_traits::to_value_ptr( p.ptr()); }
);
assert( pCur.ptr() != nullptr );
- if ( pCur->is_marked())
- pCur = pHead;
+ if ( pCur.bits())
+ pPrev = pCur = pHead;
}
pos.pCur = pCur.ptr();
typedef std::unique_lock< position > scoped_position_lock;
- typedef cds::urcu::details::check_deadlock_policy< gc, rcu_check_deadlock> check_deadlock_policy;
+ typedef cds::urcu::details::check_deadlock_policy< gc, rcu_check_deadlock> deadlock_policy;
//@endcond
protected:
static void dispose_node( node_type * pNode )
{
assert( pNode );
- assert( !gc::is_locked() );
+ assert( !gc::is_locked());
- gc::template retire_ptr<clear_and_dispose>( node_traits::to_value_ptr( *pNode ) );
+ gc::template retire_ptr<clear_and_dispose>( node_traits::to_value_ptr( *pNode ));
}
static void link_node( node_type * pNode, node_type * pPred, node_type * pCur )
{
assert( pPred->m_pNext.load(memory_model::memory_order_relaxed).ptr() == pCur );
- pNode->m_pNext.store( marked_node_ptr(pCur), memory_model::memory_order_release );
+ pNode->m_pNext.store( marked_node_ptr(pCur), memory_model::memory_order_relaxed );
pPred->m_pNext.store( marked_node_ptr(pNode), memory_model::memory_order_release );
}
assert( pCur != &m_Tail );
node_type * pNext = pCur->m_pNext.load(memory_model::memory_order_relaxed).ptr();
- pCur->m_pNext.store( marked_node_ptr( pHead, 1 ), memory_model::memory_order_release ); // logical deletion + back-link for search
+ pCur->m_pNext.store( marked_node_ptr( pHead, 1 ), memory_model::memory_order_relaxed ); // logical deletion + back-link for search
pPred->m_pNext.store( marked_node_ptr( pNext ), memory_model::memory_order_release); // physically deleting
}
node_type * pNode = node_traits::to_node_ptr( m_pNode );
// Dummy tail node could not be marked
- while ( pNode->is_marked() )
+ while ( pNode->is_marked())
pNode = pNode->m_pNext.load(memory_model::memory_order_acquire).ptr();
- if ( pNode != node_traits::to_node_ptr( m_pNode ) )
+ if ( pNode != node_traits::to_node_ptr( m_pNode ))
m_pNode = node_traits::to_value_ptr( pNode );
}
}
template <typename Q>
bool erase( Q const& key )
{
- return erase_at( &m_Head, key, key_comparator() );
+ return erase_at( &m_Head, key, key_comparator());
}
/// Deletes the item from the list using \p pred predicate for searching
If the item is not found the function returns empty \p exempt_ptr.
@note The function does NOT call RCU read-side lock or synchronization,
- and does NOT dispose the item found. It just excludes the item from the list
+ and does NOT dispose the item found. It just unlinks the item from the list
and returns a pointer to it.
You should manually lock RCU before calling this function, and you should manually synchronize RCU
outside the RCU lock region before reusing returned pointer.
template <typename Q>
exempt_ptr extract( Q const& key )
{
- return exempt_ptr( extract_at( &m_Head, key, key_comparator() ));
+ return exempt_ptr( extract_at( &m_Head, key, key_comparator()));
}
/// Extracts an item from the list using \p pred predicate for searching
exempt_ptr extract_with( Q const& key, Less pred )
{
CDS_UNUSED( pred );
- return exempt_ptr( extract_at( &m_Head, key, cds::opt::details::make_comparator_from_less<Less>() ));
+ return exempt_ptr( extract_at( &m_Head, key, cds::opt::details::make_comparator_from_less<Less>()));
}
/// Finds the key \p key
template <typename Q>
bool contains( Q const& key ) const
{
- return find_at( const_cast<node_type *>( &m_Head ), key, key_comparator() );
+ return find_at( const_cast<node_type *>( &m_Head ), key, key_comparator());
}
//@cond
template <typename Q>
bool contains( Q const& key, Less pred ) const
{
CDS_UNUSED( pred );
- return find_at( const_cast<node_type *>( &m_Head ), key, cds::opt::details::make_comparator_from_less<Less>() );
+ return find_at( const_cast<node_type *>( &m_Head ), key, cds::opt::details::make_comparator_from_less<Less>());
}
//@cond
template <typename Q, typename Less>
// ...
{
// Lock RCU
- ord_list::rcu_lock lock;
+ typename ord_list::rcu_lock lock;
foo * pVal = theList.get( 5 );
if ( pVal ) {
RCU \p synchronize method can be called.
Note that depending on RCU type used the \ref disposer call can be deferred.
- The function can throw cds::urcu::rcu_deadlock exception if deadlock is encountered and
- deadlock checking policy is opt::v::rcu_throw_deadlock.
+ The function can throw \p cds::urcu::rcu_deadlock exception if deadlock is encountered and
+ deadlock checking policy is \p opt::v::rcu_throw_deadlock.
*/
void clear()
{
- if( !empty() ) {
- check_deadlock_policy::check();
+ if( !empty()) {
+ deadlock_policy::check();
node_type * pHead;
for (;;) {
// Hack: convert node_type to value_type.
// Actually, an auxiliary node should not be converted to value_type
// We assume that comparator can correctly distinguish aux and regular node.
- return insert_at( pHead, *node_traits::to_value_ptr( pNode ) );
+ return insert_at( pHead, *node_traits::to_value_ptr( pNode ));
}
bool insert_at( node_type * pHead, value_type& val )
template <typename Func>
bool insert_at( node_type * pHead, value_type& val, Func f )
{
- link_checker::is_empty( node_traits::to_node_ptr( val ) );
+ link_checker::is_empty( node_traits::to_node_ptr( val ));
position pos;
key_comparator cmp;
return false;
}
- link_node( node_traits::to_node_ptr( val ), pos.pPred, pos.pCur );
f( val );
+ link_node( node_traits::to_node_ptr( val ), pos.pPred, pos.pCur );
++m_ItemCounter;
return true;
}
{
position pos;
key_comparator cmp;
- check_deadlock_policy::check();
+ deadlock_policy::check();
while ( true ) {
int nResult = 0;
search( pHead, val, pos );
{
scoped_position_lock alp( pos );
- if ( validate( pos.pPred, pos.pCur ) ) {
+ if ( validate( pos.pPred, pos.pCur )) {
if ( pos.pCur != &m_Tail
&& cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0
&& node_traits::to_value_ptr( pos.pCur ) == &val )
template <typename Q, typename Compare, typename Func>
bool erase_at( node_type * const pHead, Q const& val, Compare cmp, Func f, position& pos )
{
- check_deadlock_policy::check();
+ deadlock_policy::check();
while ( true ) {
int nResult = 0;
if ( pos.pCur != &m_Tail && cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 ) {
// key found
unlink_node( pos.pPred, pos.pCur, pHead );
- f( *node_traits::to_value_ptr( *pos.pCur ) );
+ f( *node_traits::to_value_ptr( *pos.pCur ));
--m_ItemCounter;
nResult = 1;
}
value_type * extract_at( node_type * const pHead, Q const& val, Compare cmp )
{
position pos;
- assert( gc::is_locked() ) ; // RCU must be locked!!!
+ assert( gc::is_locked()) ; // RCU must be locked
while ( true ) {
search( pHead, val, pos, cmp );
template <typename Q, typename Compare>
const_iterator find_at_( node_type * pHead, Q& val, Compare cmp ) const
{
- assert( gc::is_locked() );
+ assert( gc::is_locked());
position pos;
template <typename Q>
void search( node_type * const pHead, Q const& key, position& pos ) const
{
- search( pHead, key, pos, key_comparator() );
+ search( pHead, key, pos, key_comparator());
}
template <typename Q, typename Compare>
void search( node_type * const pHead, Q const& key, position& pos, Compare cmp ) const
{
- // RCU should be locked!!!
- assert( gc::is_locked() );
+ // RCU should be locked
+ assert( gc::is_locked());
node_type const* pTail = &m_Tail;
while ( pCur != pTail && ( pCur == pHead || cmp( *node_traits::to_value_ptr( *pCur.ptr()), key ) < 0 )) {
pPrev = pCur;
pCur = pCur->m_pNext.load(memory_model::memory_order_acquire);
- if ( pCur->is_marked())
- pCur = pHead;
+ if ( pCur.bits())
+ pPrev = pCur = pHead;
}
pos.pCur = pCur.ptr();
static bool validate( node_type * pPred, node_type * pCur ) CDS_NOEXCEPT
{
- // RCU lock should be locked!!!
- assert( gc::is_locked() );
+ // RCU lock should be locked
+ assert( gc::is_locked());
return !pPred->is_marked()
&& !pCur->is_marked()
//@cond
bool insert_at_locked( node_type * pHead, value_type& val )
{
- // RCU lock should be locked!!!
- assert( gc::is_locked() );
+ // RCU lock should be locked
+ assert( gc::is_locked());
link_checker::is_empty( node_traits::to_node_ptr( val ));
position pos;
search( pHead, val, pos );
{
scoped_position_lock alp( pos );
- if ( validate( pos.pPred, pos.pCur ) ) {
+ if ( validate( pos.pPred, pos.pCur )) {
if ( pos.pCur != &m_Tail && cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 ) {
// failed: key already in list
return false;
template <typename Func>
std::pair<iterator, bool> update_at_locked( node_type * pHead, value_type& val, Func func, bool bAllowInsert )
{
- // RCU lock should be locked!!!
- assert( gc::is_locked() );
+ // RCU lock should be locked
+ assert( gc::is_locked());
position pos;
key_comparator cmp;
search( pHead, val, pos );
{
scoped_position_lock alp( pos );
- if ( validate( pos.pPred, pos.pCur ) ) {
+ if ( validate( pos.pPred, pos.pCur )) {
if ( pos.pCur != &m_Tail && cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 ) {
// key already in the list
if ( !bAllowInsert )
return std::make_pair( end(), false );
- link_checker::is_empty( node_traits::to_node_ptr( val ) );
+ link_checker::is_empty( node_traits::to_node_ptr( val ));
- link_node( node_traits::to_node_ptr( val ), pos.pPred, pos.pCur );
func( true, val, val );
+ link_node( node_traits::to_node_ptr( val ), pos.pPred, pos.pCur );
++m_ItemCounter;
- return std::make_pair( iterator( node_traits::to_node_ptr( val ) ), true );
+ return std::make_pair( iterator( node_traits::to_node_ptr( val )), true );
}
}
}