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.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_CONTAINER_IMPL_MICHAEL_LIST_H
typedef typename base_class::item_counter item_counter; ///< Item counting policy used
typedef typename maker::key_comparator key_comparator; ///< key comparison functor
typedef typename base_class::memory_model memory_model; ///< Memory ordering. See \p cds::opt::memory_model option
+ typedef typename base_class::stat stat; ///< Internal statistics
static CDS_CONSTEXPR const size_t c_nHazardPtrCount = base_class::c_nHazardPtrCount; ///< Count of hazard pointer required for the algorithm
+ //@cond
+ // Rebind traits (split-list support)
+ template <typename... Options>
+ struct rebind_traits {
+ typedef MichaelList<
+ gc
+ , value_type
+ , typename cds::opt::make_options< traits, Options...>::type
+ > type;
+ };
+
+ // Stat selector
+ template <typename Stat>
+ using select_stat_wrapper = typename base_class::template select_stat_wrapper< Stat >;
+ //@endcond
+
protected:
//@cond
typedef typename base_class::value_type node_type;
typedef typename maker::intrusive_traits::compare intrusive_key_comparator;
typedef typename base_class::atomic_node_ptr head_type;
- //@endcond
-
- public:
- /// Guarded pointer
- typedef typename gc::template guarded_ptr< node_type, value_type, details::guarded_ptr_cast_set<node_type, value_type> > guarded_ptr;
-
- private:
- //@cond
- static value_type& node_to_value( node_type& n )
- {
- return n.m_Value;
- }
- static value_type const& node_to_value( node_type const& n )
- {
- return n.m_Value;
- }
- //@endcond
-
- protected:
- //@cond
- template <typename Q>
- static node_type * alloc_node( Q const& v )
- {
- return cxx_allocator().New( v );
- }
-
- template <typename... Args>
- static node_type * alloc_node( Args&&... args )
- {
- return cxx_allocator().MoveNew( std::forward<Args>(args)... );
- }
-
- static void free_node( node_type * pNode )
- {
- cxx_allocator().Delete( pNode );
- }
struct node_disposer {
void operator()( node_type * pNode )
}
};
typedef std::unique_ptr< node_type, node_disposer > scoped_node_ptr;
-
- head_type& head()
- {
- return base_class::m_pHead;
- }
-
- head_type const& head() const
- {
- return base_class::m_pHead;
- }
//@endcond
+ public:
+ /// Guarded pointer
+ typedef typename gc::template guarded_ptr< node_type, value_type, details::guarded_ptr_cast_set<node_type, value_type> > guarded_ptr;
+
protected:
//@cond
template <bool IsConst>
//@endcond
public:
+ ///@name Forward iterators (only for debugging purpose)
+ //@{
/// Forward iterator
/**
The forward iterator for Michael's list has some features:
- The iterator cannot be moved across thread boundary since it contains GC's guard that is thread-private GC data.
- Iterator ensures thread-safety even if you delete the item that iterator points to. However, in case of concurrent
deleting operations it is no guarantee that you iterate all item in the list.
+ Moreover, a crash is possible when you try to iterate the next element that has been deleted by concurrent thread.
@warning Use this iterator on the concurrent container for debugging purpose only.
*/
*/
typedef iterator_type<true> const_iterator;
- ///@name Forward iterators (only for debugging purpose)
- //@{
/// Returns a forward iterator addressing the first element in a list
/**
For empty list \code begin() == end() \endcode
MichaelList()
{}
+ //@cond
+ template <typename Stat, typename = std::enable_if<std::is_same<stat, michael_list::wrapped_stat<Stat>>::value >>
+ explicit MichaelList( Stat& st )
+ : base_class( st )
+ {}
+ //@endcond
+
/// List destructor
/**
Clears the list
Returns \p true if inserting successful, \p false otherwise.
*/
template <typename Q>
- bool insert( Q const& val )
+ bool insert( Q&& val )
{
- return insert_at( head(), val );
+ return insert_at( head(), std::forward<Q>( val ));
}
/// Inserts new node
@warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
*/
template <typename Q, typename Func>
- bool insert( Q const& key, Func func )
+ bool insert( Q&& key, Func func )
{
- return insert_at( head(), key, func );
+ return insert_at( head(), std::forward<Q>(key), func );
}
/// Updates data by \p key
The functor \p Func signature is:
\code
struct my_functor {
- void operator()( bool bNew, value_type& item, Q const& val );
+ void operator()( bool bNew, value_type& item, Q const& key );
};
\endcode
with arguments:
- \p bNew - \p true if the item has been inserted, \p false otherwise
- \p item - item of the list
- - \p val - argument \p key passed into the \p %update() function
+ - \p key - argument \p key passed into the \p %update() function
The functor may 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 <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
\p second is true if new item has been added or \p false if the item with \p key
already exists.
template <typename Q>
guarded_ptr extract( Q const& key )
{
- guarded_ptr gp;
- extract_at( head(), gp.guard(), key, intrusive_key_comparator() );
- return gp;
+ return extract_at( head(), key, intrusive_key_comparator() );
}
/// Extracts the item from the list with comparing functor \p pred
guarded_ptr extract_with( Q const& key, Less pred )
{
CDS_UNUSED( pred );
- guarded_ptr gp;
- extract_at( head(), gp.guard(), key, typename maker::template less_wrapper<Less>::type() );
- return gp;
+ return extract_at( head(), key, typename maker::template less_wrapper<Less>::type() );
}
/// Checks whether the list contains \p key
//@endcond
/// Finds \p key and return the item found
- /** \anchor cds_nonintrusive_MichaelList_hp_get
+ /**
The function searches the item with key equal to \p key
and returns it as \p guarded_ptr.
If \p key is not found the function returns an empty guarded pointer.
template <typename Q>
guarded_ptr get( Q const& key )
{
- guarded_ptr gp;
- get_at( head(), gp.guard(), key, intrusive_key_comparator() );
- return gp;
+ return get_at( head(), key, intrusive_key_comparator() );
}
/// Finds \p key and return the item found
/**
- The function is an analog of \ref cds_nonintrusive_MichaelList_hp_get "get( Q const&)"
+ The function is an analog of \p get( Q const&)
but \p pred is used for comparing the keys.
\p Less functor has the semantics like \p std::less but should accept arguments of type \p value_type and \p Q
guarded_ptr get_with( Q const& key, Less pred )
{
CDS_UNUSED( pred );
- guarded_ptr gp;
- get_at( head(), gp.guard(), key, typename maker::template less_wrapper<Less>::type() );
- return gp;
+ return get_at( head(), key, typename maker::template less_wrapper<Less>::type() );
}
/// Check if the list is empty
base_class::clear();
}
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return base_class::statistics();
+ }
+
protected:
//@cond
+ static value_type& node_to_value( node_type& n )
+ {
+ return n.m_Value;
+ }
+ static value_type const& node_to_value( node_type const& n )
+ {
+ return n.m_Value;
+ }
+
+ template <typename Q>
+ static node_type * alloc_node( Q const& v )
+ {
+ return cxx_allocator().New( v );
+ }
+
+ template <typename... Args>
+ static node_type * alloc_node( Args&&... args )
+ {
+ return cxx_allocator().MoveNew( std::forward<Args>( args )... );
+ }
+
+ static void free_node( node_type * pNode )
+ {
+ cxx_allocator().Delete( pNode );
+ }
+
+ head_type& head()
+ {
+ return base_class::m_pHead;
+ }
+
+ head_type const& head() const
+ {
+ return base_class::m_pHead;
+ }
+
+ bool insert_node( node_type * pNode )
+ {
+ return insert_node_at( head(), pNode );
+ }
+
bool insert_node_at( head_type& refHead, node_type * pNode )
{
assert( pNode );
}
template <typename Q>
- bool insert_at( head_type& refHead, Q const& val )
+ bool insert_at( head_type& refHead, Q&& val )
{
- return insert_node_at( refHead, alloc_node( val ));
+ return insert_node_at( refHead, alloc_node( std::forward<Q>(val)));
}
template <typename Q, typename Func>
- bool insert_at( head_type& refHead, Q const& key, Func f )
+ bool insert_at( head_type& refHead, Q&& key, Func f )
{
- scoped_node_ptr pNode( alloc_node( key ));
+ scoped_node_ptr pNode( alloc_node( std::forward<Q>( key )));
if ( base_class::insert_at( refHead, *pNode, [&f]( node_type& node ) { f( node_to_value(node) ); } )) {
pNode.release();
}
template <typename Q, typename Compare>
- bool extract_at( head_type& refHead, typename guarded_ptr::native_guard& guard, Q const& key, Compare cmp )
+ guarded_ptr extract_at( head_type& refHead, Q const& key, Compare cmp )
{
- return base_class::extract_at( refHead, guard, key, cmp );
+ return base_class::extract_at( refHead, key, cmp );
}
template <typename Q, typename Func>
}
template <typename Q, typename Compare>
- bool get_at( head_type& refHead, typename guarded_ptr::native_guard& guard, Q const& key, Compare cmp )
+ guarded_ptr get_at( head_type& refHead, Q const& key, Compare cmp )
{
- return base_class::get_at( refHead, guard, key, cmp );
+ return base_class::get_at( refHead, key, cmp );
}
//@endcond