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:
, typename cds::opt::make_options< traits, Options...>::type
> type;
};
+
+ // Stat selector
+ template <typename Stat>
+ using select_stat_wrapper = iterable_list::select_stat_wrapper< Stat >;
//@endcond
protected:
+ //@cond
typedef atomics::atomic< node_type* > atomic_node_ptr; ///< Atomic node pointer
typedef atomic_node_ptr auxiliary_head; ///< Auxiliary head type (for split-list support)
item_counter m_ItemCounter; ///< Item counter
mutable stat m_Stat; ///< Internal statistics
- //@cond
typedef cds::details::Allocator< node_type, node_allocator > cxx_node_allocator;
/// Position pointer for item search
protected:
node_type* m_pNode;
- value_type* m_pVal;
- typename gc::Guard m_Guard; // for m_pVal
+ typename gc::Guard m_Guard; // data guard
void next()
{
while ( m_pNode ) {
- m_pNode = m_pNode->next.load( memory_model::memory_order_relaxed );
- if ( !m_pNode )
+ m_pNode = m_pNode->next.load( memory_model::memory_order_acquire );
+ if ( !m_pNode ) {
+ m_Guard.clear();
break;
- m_pVal = m_Guard.protect( m_pNode->data );
- if ( m_pVal )
+ }
+ if ( m_Guard.protect( m_pNode->data ))
break;
}
}
explicit iterator_type( atomic_node_ptr const& pNode )
- : m_pNode( pNode.load( memory_model::memory_order_relaxed ))
- , m_pVal( nullptr )
+ : m_pNode( pNode.load( memory_model::memory_order_acquire ))
{
if ( m_pNode ) {
- m_pVal = m_Guard.protect( m_pNode->data );
- if ( !m_pVal )
+ if ( !m_Guard.protect( m_pNode->data ))
next();
}
}
iterator_type( node_type* pNode, value_type* pVal )
: m_pNode( pNode )
- , m_pVal( pVal )
{
if ( m_pNode ) {
assert( pVal != nullptr );
iterator_type()
: m_pNode( nullptr )
- , m_pVal( nullptr )
{}
iterator_type( iterator_type const& src )
: m_pNode( src.m_pNode )
- , m_pVal( src.m_pVal )
{
- m_Guard.assign( m_pVal );
+ m_Guard.copy( src.m_Guard );
}
value_ptr operator ->() const
{
- return m_pVal;
+ return m_Guard.template get<value_type>();
}
value_ref operator *() const
{
- assert( m_pVal != nullptr );
- return *m_pVal;
+ assert( m_Guard.get_native() != nullptr );
+ return *m_Guard.template get<value_type>();
}
/// Pre-increment
iterator_type& operator = (iterator_type const& src)
{
m_pNode = src.m_pNode;
- m_pVal = src.m_pVal;
- m_Guard.assign( m_pVal );
+ m_Guard.copy( src.m_Guard );
return *this;
}
template <bool C>
bool operator !=(iterator_type<C> const& i ) const
{
- return m_pNode != i.m_pNode;
+ return !( *this == i );
}
};
//@endcond
For some GC (like as \p gc::HP), a guard is a limited resource per thread, so an exception (or assertion) "no free guard"
may be thrown if the limit of guard count per thread is exceeded.
- The iterator cannot be moved across thread boundary since it contains thread-private GC's guard.
- - Iterator is thread-safe: event if the element the iterator points to is removed, the iterator stays valid because
+ - Iterator is thread-safe: even if the element the iterator points to is removed, the iterator stays valid because
it contains the guard keeping the value from to be recycled.
The iterator interface:
return update_at( m_pHead, val, func, bInsert );
}
- /// Updates the node
+ /// Insert or update
/**
- The operation performs inserting or changing data with lock-free manner.
+ The operation performs inserting or updating data with lock-free manner.
If the item \p val is not found in the list, then \p val is inserted
iff \p bInsert is \p true.
\p second is \p true if \p val has been added or \p false if the item with that key
already in the list.
*/
- std::pair<bool, bool> update( value_type& val, bool bInsert = true )
+ std::pair<bool, bool> upsert( value_type& val, bool bInsert = true )
{
return update_at( m_pHead, val, []( value_type&, value_type* ) {}, bInsert );
}
ord_list theList;
// ...
{
- ord_list::guarded_ptr gp(theList.extract( 5 ));
+ ord_list::guarded_ptr gp( theList.extract( 5 ));
if ( gp ) {
// Deal with gp
// ...
template <typename Q>
guarded_ptr extract( Q const& key )
{
- guarded_ptr gp;
- extract_at( m_pHead, gp.guard(), key, key_comparator());
- return gp;
+ return extract_at( m_pHead, key, key_comparator());
}
/// Extracts the item using compare functor \p pred
guarded_ptr extract_with( Q const& key, Less pred )
{
CDS_UNUSED( pred );
- guarded_ptr gp;
- extract_at( m_pHead, gp.guard(), key, cds::opt::details::make_comparator_from_less<Less>());
- return gp;
+ return extract_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>());
}
/// Finds \p key in the list
If \p key is not found the function returns \p end().
*/
template <typename Q>
- iterator find( Q& key ) const
- {
- return find_iterator_at( m_pHead, key, key_comparator());
- }
- //@cond
- template <typename Q>
iterator find( Q const& key ) const
{
- return find_iterator_at( m_pHead, key, key_comparator() );
+ return find_iterator_at( m_pHead, key, key_comparator());
}
- //@endcond
/// Finds the \p key using \p pred predicate for searching
/**
If \p key is not found the function returns \p end().
*/
template <typename Q, typename Less>
- iterator find_with( Q& key, Less pred ) const
- {
- CDS_UNUSED( pred );
- return find_iterator_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>());
- }
- //@cond
- template <typename Q, typename Less>
iterator find_with( Q const& key, Less pred ) const
{
CDS_UNUSED( pred );
return find_iterator_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>());
}
- //@endcond
/// Checks whether the list contains \p key
/**
template <typename Q>
guarded_ptr get( Q const& key ) const
{
- guarded_ptr gp;
- get_at( m_pHead, gp.guard(), key, key_comparator());
- return gp;
+ return get_at( m_pHead, key, key_comparator());
}
/// Finds the \p key and return the item found
guarded_ptr get_with( Q const& key, Less pred ) const
{
CDS_UNUSED( pred );
- guarded_ptr gp;
- get_at( m_pHead, gp.guard(), key, cds::opt::details::make_comparator_from_less<Less>());
- return gp;
+ return get_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>());
}
/// Clears the list (thread safe, not atomic)
return m_ItemCounter.value();
}
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return m_Stat;
+ }
+
protected:
//@cond
#if 0
}
template <typename Q, typename Compare>
- bool extract_at( atomic_node_ptr& refHead, typename guarded_ptr::native_guard& dest, Q const& val, Compare cmp )
+ guarded_ptr extract_at( atomic_node_ptr& refHead, Q const& val, Compare cmp )
{
position pos;
back_off bkoff;
while ( search( refHead, val, pos, cmp )) {
if ( unlink_node( pos )) {
- dest.set( pos.pFound );
--m_ItemCounter;
m_Stat.onEraseSuccess();
- return true;
+ assert( pos.pFound != nullptr );
+ return guarded_ptr( std::move( pos.guard ));
}
else
bkoff();
}
m_Stat.onEraseFailed();
- return false;
+ return guarded_ptr();
}
template <typename Q, typename Compare>
}
template <typename Q, typename Compare>
- bool get_at( atomic_node_ptr const& refHead, typename guarded_ptr::native_guard& guard, Q const& val, Compare cmp ) const
+ guarded_ptr get_at( atomic_node_ptr const& refHead, Q const& val, Compare cmp ) const
{
position pos;
if ( search( refHead, val, pos, cmp )) {
- guard.set( pos.pFound );
m_Stat.onFindSuccess();
- return true;
+ return guarded_ptr( std::move( pos.guard ));
}
m_Stat.onFindFailed();
- return false;
+ return guarded_ptr();
}
//@endcond