3 #ifndef __CDS_CONTAINER_MICHAEL_LIST_NOGC_H
4 #define __CDS_CONTAINER_MICHAEL_LIST_NOGC_H
7 #include <cds/container/details/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 \pgc::nogc)
34 /** @ingroup cds_nonintrusive_list
35 \anchor cds_nonintrusive_MichaelList_nogc
37 This specialization is intended for so-called append-only 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.
45 #ifdef CDS_DOXYGEN_INVOKED
46 class Traits = michael_list::traits
51 class MichaelList<gc::nogc, T, Traits>:
52 #ifdef CDS_DOXYGEN_INVOKED
53 protected intrusive::MichaelList< gc::nogc, T, Traits >
55 protected details::make_michael_list_nogc< T, Traits >::type
59 typedef details::make_michael_list_nogc< T, Traits > options;
60 typedef typename options::type base_class;
64 typedef T value_type ; ///< Type of value stored in the list
65 typedef typename base_class::gc gc ; ///< Garbage collector used
66 typedef typename base_class::back_off back_off ; ///< Back-off strategy used
67 typedef typename options::allocator_type allocator_type ; ///< Allocator type used for allocate/deallocate the nodes
68 typedef typename base_class::item_counter item_counter ; ///< Item counting policy used
69 typedef typename options::key_comparator key_comparator ; ///< key comparison functor
70 typedef typename base_class::memory_model memory_model ; ///< Memory ordering. See cds::opt::memory_model option
74 typedef typename base_class::value_type node_type;
75 typedef typename options::cxx_allocator cxx_allocator;
76 typedef typename options::node_deallocator node_deallocator;
77 typedef typename options::type_traits::compare intrusive_key_comparator;
79 typedef typename base_class::atomic_node_ptr head_type;
84 static node_type * alloc_node()
86 return cxx_allocator().New();
89 static node_type * alloc_node( value_type const& v )
91 return cxx_allocator().New( v );
94 template <typename... Args>
95 static node_type * alloc_node( Args&&... args )
97 return cxx_allocator().MoveNew( std::forward<Args>(args)... );
100 static void free_node( node_type * pNode )
102 cxx_allocator().Delete( pNode );
105 struct node_disposer {
106 void operator()( node_type * pNode )
111 typedef std::unique_ptr< node_type, node_disposer > scoped_node_ptr;
115 return base_class::m_pHead;
118 head_type const& head() const
120 return base_class::m_pHead;
126 template <bool IsConst>
127 class iterator_type: protected base_class::template iterator_type<IsConst>
129 typedef typename base_class::template iterator_type<IsConst> iterator_base;
131 iterator_type( head_type const& pNode )
132 : iterator_base( pNode )
135 explicit iterator_type( const iterator_base& it )
136 : iterator_base( it )
139 friend class MichaelList;
142 explicit iterator_type( node_type& pNode )
143 : iterator_base( &pNode )
147 typedef typename cds::details::make_const_type<value_type, IsConst>::pointer value_ptr;
148 typedef typename cds::details::make_const_type<value_type, IsConst>::reference value_ref;
153 iterator_type( const iterator_type& src )
154 : iterator_base( src )
157 value_ptr operator ->() const
159 typename iterator_base::value_ptr p = iterator_base::operator ->();
160 return p ? &(p->m_Value) : nullptr;
163 value_ref operator *() const
165 return (iterator_base::operator *()).m_Value;
169 iterator_type& operator ++()
171 iterator_base::operator ++();
176 iterator_type operator ++(int)
178 return iterator_base::operator ++(0);
182 bool operator ==(iterator_type<C> const& i ) const
184 return iterator_base::operator ==(i);
187 bool operator !=(iterator_type<C> const& i ) const
189 return iterator_base::operator !=(i);
195 /// Returns a forward iterator addressing the first element in a list
197 For empty list \code begin() == end() \endcode
199 typedef iterator_type<false> iterator;
201 /// Const forward iterator
203 For iterator's features and requirements see \ref iterator
205 typedef iterator_type<true> const_iterator;
207 /// Returns a forward iterator addressing the first element in a list
209 For empty list \code begin() == end() \endcode
213 return iterator( head() );
216 /// Returns an iterator that addresses the location succeeding the last element in a list
218 Do not use the value returned by <tt>end</tt> function to access any item.
219 Internally, <tt>end</tt> returning value equals to \p nullptr.
221 The returned value can be used only to control reaching the end of the list.
222 For empty list \code begin() == end() \endcode
229 /// Returns a forward const iterator addressing the first element in a list
231 const_iterator begin() const
233 return const_iterator( head() );
235 const_iterator cbegin()
237 return const_iterator( head() );
241 /// Returns an const iterator that addresses the location succeeding the last element in a list
243 const_iterator end() const
245 return const_iterator();
247 const_iterator cend()
249 return const_iterator();
255 iterator node_to_iterator( node_type * pNode )
258 return iterator( *pNode );
264 /// Default constructor
266 Initialize empty list
282 The function inserts \p val in the list if the list does not contain
283 an item with key equal to \p val.
285 Return an iterator pointing to inserted item if success \ref end() otherwise
287 template <typename Q>
288 iterator insert( const Q& val )
290 return node_to_iterator( insert_at( head(), val ) );
293 /// Ensures that the item \p val exists in the list
295 The operation inserts new item if the key \p val is not found in the list.
296 Otherwise, the function returns an iterator that points to item found.
298 Returns <tt> std::pair<iterator, bool> </tt> where \p first is an iterator pointing to
299 item found or inserted, \p second is true if new item has been added or \p false if the item
300 already is in the list.
302 template <typename Q>
303 std::pair<iterator, bool> ensure( const Q& val )
305 std::pair< node_type *, bool > ret = ensure_at( head(), val );
306 return std::make_pair( node_to_iterator( ret.first ), ret.second );
309 /// Inserts data of type \ref value_type constructed with <tt>std::forward<Args>(args)...</tt>
311 Return an iterator pointing to inserted item if success \ref end() otherwise
313 template <typename... Args>
314 iterator emplace( Args&&... args )
316 return node_to_iterator( emplace_at( head(), std::forward<Args>(args)... ));
319 /// Find the key \p val
320 /** \anchor cds_nonintrusive_MichaelList_nogc_find_val
321 The function searches the item with key equal to \p val
322 and returns an iterator pointed to item found if the key is found,
323 and \ref end() otherwise
325 template <typename Q>
326 iterator find( Q const& key )
328 return node_to_iterator( find_at( head(), key, intrusive_key_comparator() ));
331 /// Finds the key \p val using \p pred predicate for searching
333 The function is an analog of \ref cds_nonintrusive_MichaelList_nogc_find_val "find(Q const&)"
334 but \p pred is used for key comparing.
335 \p Less functor has the interface like \p std::less.
336 \p pred must imply the same element order as the comparator used for building the list.
338 template <typename Q, typename Less>
339 iterator find_with( Q const& key, Less pred )
341 return node_to_iterator( find_at( head(), key, typename options::template less_wrapper<Less>::type() ));
344 /// Check if the list is empty
347 return base_class::empty();
350 /// Returns list's item count
352 The value returned depends on opt::item_counter option. For atomics::empty_item_counter,
353 this function always returns 0.
355 <b>Warning</b>: even if you use real item counter and it returns 0, this fact is not mean that the list
356 is empty. To check list emptyness use \ref empty() method.
360 return base_class::size();
365 Post-condition: the list is empty
374 node_type * insert_node_at( head_type& refHead, node_type * pNode )
376 assert( pNode != nullptr );
377 scoped_node_ptr p(pNode);
378 if ( base_class::insert_at( refHead, *pNode ))
384 template <typename Q>
385 node_type * insert_at( head_type& refHead, const Q& val )
387 return insert_node_at( refHead, alloc_node( val ));
390 template <typename Q>
391 std::pair< node_type *, bool > ensure_at( head_type& refHead, const Q& val )
393 scoped_node_ptr pNode( alloc_node( val ));
394 node_type * pItemFound = nullptr;
396 std::pair<bool, bool> ret = base_class::ensure_at( refHead, *pNode, [&pItemFound](bool, node_type& item, node_type&) { pItemFound = &item; });
397 assert( pItemFound != nullptr );
399 if ( ret.first && ret.second )
401 return std::make_pair( pItemFound, ret.second );
404 template <typename... Args>
405 node_type * emplace_at( head_type& refHead, Args&&... args )
407 return insert_node_at( refHead, alloc_node( std::forward<Args>(args)...));
410 template <typename Q, typename Compare>
411 node_type * find_at( head_type& refHead, Q const& key, Compare cmp )
413 return base_class::find_at( refHead, key, cmp );
418 }} // namespace cds::container
420 #endif // #ifndef __CDS_CONTAINER_MICHAEL_LIST_NOGC_H