3 #ifndef __CDS_CONTAINER_MICHAEL_LIST_NOGC_H
4 #define __CDS_CONTAINER_MICHAEL_LIST_NOGC_H
7 #include <cds/container/michael_list_base.h>
8 #include <cds/intrusive/michael_list_nogc.h>
9 #include <cds/container/details/make_michael_list.h>
11 namespace cds { namespace container {
16 template <typename T, class Traits>
17 struct make_michael_list_nogc: public make_michael_list<gc::nogc, T, Traits>
19 typedef make_michael_list<cds::gc::nogc, T, Traits> base_maker;
20 typedef typename base_maker::node_type node_type;
22 struct type_traits: public base_maker::type_traits
24 typedef typename base_maker::node_deallocator disposer;
27 typedef intrusive::MichaelList<cds::gc::nogc, node_type, type_traits> type;
30 } // namespace details
33 /// Michael's lock-free ordered single-linked list (template specialization for gc::nogc)
34 /** @ingroup cds_nonintrusive_list
35 \anchor cds_nonintrusive_MichaelList_nogc
37 This specialization is intended for so-called persistent usage when no item
38 reclamation may be performed. The class does not support deleting of list item.
39 Usually, ordered single-linked list is used as a building block for the hash table implementation.
40 The complexity of searching is <tt>O(N)</tt>.
42 See \ref cds_nonintrusive_MichaelList_gc "MichaelList" for description of template parameters.
44 The interface of the specialization is a little different.
46 template <typename T, typename Traits>
47 class MichaelList<gc::nogc, T, Traits>:
48 #ifdef CDS_DOXYGEN_INVOKED
49 protected intrusive::MichaelList< gc::nogc, T, Traits >
51 protected details::make_michael_list_nogc< T, Traits >::type
55 typedef details::make_michael_list_nogc< T, Traits > options;
56 typedef typename options::type base_class;
60 typedef T value_type ; ///< Type of value stored in the list
61 typedef typename base_class::gc gc ; ///< Garbage collector used
62 typedef typename base_class::back_off back_off ; ///< Back-off strategy used
63 typedef typename options::allocator_type allocator_type ; ///< Allocator type used for allocate/deallocate the nodes
64 typedef typename base_class::item_counter item_counter ; ///< Item counting policy used
65 typedef typename options::key_comparator key_comparator ; ///< key comparison functor
66 typedef typename base_class::memory_model memory_model ; ///< Memory ordering. See cds::opt::memory_model option
70 typedef typename base_class::value_type node_type;
71 typedef typename options::cxx_allocator cxx_allocator;
72 typedef typename options::node_deallocator node_deallocator;
73 typedef typename options::type_traits::compare intrusive_key_comparator;
75 typedef typename base_class::atomic_node_ptr head_type;
80 # ifndef CDS_CXX11_LAMBDA_SUPPORT
83 node_type * m_pItemFound;
86 : m_pItemFound( nullptr )
89 void operator ()(bool, node_type& item, node_type& )
99 static node_type * alloc_node()
101 return cxx_allocator().New();
104 static node_type * alloc_node( value_type const& v )
106 return cxx_allocator().New( v );
109 template <typename... Args>
110 static node_type * alloc_node( Args&&... args )
112 return cxx_allocator().MoveNew( std::forward<Args>(args)... );
115 static void free_node( node_type * pNode )
117 cxx_allocator().Delete( pNode );
120 struct node_disposer {
121 void operator()( node_type * pNode )
126 typedef std::unique_ptr< node_type, node_disposer > scoped_node_ptr;
130 return base_class::m_pHead;
133 head_type const& head() const
135 return base_class::m_pHead;
141 template <bool IsConst>
142 class iterator_type: protected base_class::template iterator_type<IsConst>
144 typedef typename base_class::template iterator_type<IsConst> iterator_base;
146 iterator_type( head_type const& pNode )
147 : iterator_base( pNode )
150 explicit iterator_type( const iterator_base& it )
151 : iterator_base( it )
154 friend class MichaelList;
157 explicit iterator_type( node_type& pNode )
158 : iterator_base( &pNode )
162 typedef typename cds::details::make_const_type<value_type, IsConst>::pointer value_ptr;
163 typedef typename cds::details::make_const_type<value_type, IsConst>::reference value_ref;
168 iterator_type( const iterator_type& src )
169 : iterator_base( src )
172 value_ptr operator ->() const
174 typename iterator_base::value_ptr p = iterator_base::operator ->();
175 return p ? &(p->m_Value) : nullptr;
178 value_ref operator *() const
180 return (iterator_base::operator *()).m_Value;
184 iterator_type& operator ++()
186 iterator_base::operator ++();
191 iterator_type operator ++(int)
193 return iterator_base::operator ++(0);
197 bool operator ==(iterator_type<C> const& i ) const
199 return iterator_base::operator ==(i);
202 bool operator !=(iterator_type<C> const& i ) const
204 return iterator_base::operator !=(i);
210 /// Returns a forward iterator addressing the first element in a list
212 For empty list \code begin() == end() \endcode
214 typedef iterator_type<false> iterator;
216 /// Const forward iterator
218 For iterator's features and requirements see \ref iterator
220 typedef iterator_type<true> const_iterator;
222 /// Returns a forward iterator addressing the first element in a list
224 For empty list \code begin() == end() \endcode
228 return iterator( head() );
231 /// Returns an iterator that addresses the location succeeding the last element in a list
233 Do not use the value returned by <tt>end</tt> function to access any item.
234 Internally, <tt>end</tt> returning value equals to \p nullptr.
236 The returned value can be used only to control reaching the end of the list.
237 For empty list \code begin() == end() \endcode
244 /// Returns a forward const iterator addressing the first element in a list
246 const_iterator begin() const
248 return const_iterator( head() );
250 const_iterator cbegin()
252 return const_iterator( head() );
256 /// Returns an const iterator that addresses the location succeeding the last element in a list
258 const_iterator end() const
260 return const_iterator();
262 const_iterator cend()
264 return const_iterator();
270 iterator node_to_iterator( node_type * pNode )
273 return iterator( *pNode );
279 /// Default constructor
281 Initialize empty list
297 The function inserts \p val in the list if the list does not contain
298 an item with key equal to \p val.
300 Return an iterator pointing to inserted item if success \ref end() otherwise
302 template <typename Q>
303 iterator insert( const Q& val )
305 return node_to_iterator( insert_at( head(), val ) );
308 /// Ensures that the item \p val exists in the list
310 The operation inserts new item if the key \p val is not found in the list.
311 Otherwise, the function returns an iterator that points to item found.
313 Returns <tt> std::pair<iterator, bool> </tt> where \p first is an iterator pointing to
314 item found or inserted, \p second is true if new item has been added or \p false if the item
315 already is in the list.
317 template <typename Q>
318 std::pair<iterator, bool> ensure( const Q& val )
320 std::pair< node_type *, bool > ret = ensure_at( head(), val );
321 return std::make_pair( node_to_iterator( ret.first ), ret.second );
324 /// Inserts data of type \ref value_type constructed with <tt>std::forward<Args>(args)...</tt>
326 Return an iterator pointing to inserted item if success \ref end() otherwise
328 template <typename... Args>
329 iterator emplace( Args&&... args )
331 return node_to_iterator( emplace_at( head(), std::forward<Args>(args)... ));
334 /// Find the key \p val
335 /** \anchor cds_nonintrusive_MichaelList_nogc_find_val
336 The function searches the item with key equal to \p val
337 and returns an iterator pointed to item found if the key is found,
338 and \ref end() otherwise
340 template <typename Q>
341 iterator find( Q const& key )
343 return node_to_iterator( find_at( head(), key, intrusive_key_comparator() ));
346 /// Finds the key \p val using \p pred predicate for searching
348 The function is an analog of \ref cds_nonintrusive_MichaelList_nogc_find_val "find(Q const&)"
349 but \p pred is used for key comparing.
350 \p Less functor has the interface like \p std::less.
351 \p pred must imply the same element order as the comparator used for building the list.
353 template <typename Q, typename Less>
354 iterator find_with( Q const& key, Less pred )
356 return node_to_iterator( find_at( head(), key, typename options::template less_wrapper<Less>::type() ));
359 /// Check if the list is empty
362 return base_class::empty();
365 /// Returns list's item count
367 The value returned depends on opt::item_counter option. For atomics::empty_item_counter,
368 this function always returns 0.
370 <b>Warning</b>: even if you use real item counter and it returns 0, this fact is not mean that the list
371 is empty. To check list emptyness use \ref empty() method.
375 return base_class::size();
380 Post-condition: the list is empty
389 node_type * insert_node_at( head_type& refHead, node_type * pNode )
391 assert( pNode != nullptr );
392 scoped_node_ptr p(pNode);
393 if ( base_class::insert_at( refHead, *pNode ))
399 template <typename Q>
400 node_type * insert_at( head_type& refHead, const Q& val )
402 return insert_node_at( refHead, alloc_node( val ));
405 template <typename Q>
406 std::pair< node_type *, bool > ensure_at( head_type& refHead, const Q& val )
408 scoped_node_ptr pNode( alloc_node( val ));
409 node_type * pItemFound = nullptr;
411 # ifdef CDS_CXX11_LAMBDA_SUPPORT
412 std::pair<bool, bool> ret = base_class::ensure_at( refHead, *pNode, [&pItemFound](bool, node_type& item, node_type&) { pItemFound = &item; });
415 std::pair<bool, bool> ret = base_class::ensure_at( refHead, *pNode, boost::ref(func) );
416 pItemFound = func.m_pItemFound;
418 assert( pItemFound != nullptr );
420 if ( ret.first && ret.second )
422 return std::make_pair( pItemFound, ret.second );
425 template <typename... Args>
426 node_type * emplace_at( head_type& refHead, Args&&... args )
428 return insert_node_at( refHead, alloc_node( std::forward<Args>(args)...));
431 template <typename Q, typename Compare>
432 node_type * find_at( head_type& refHead, Q const& key, Compare cmp )
434 return base_class::find_at( refHead, key, cmp );
439 }} // namespace cds::container
441 #endif // #ifndef __CDS_CONTAINER_MICHAEL_LIST_NOGC_H