Removed redundant spaces
[libcds.git] / cds / container / michael_list_nogc.h
1 /*
2     This file is a part of libcds - Concurrent Data Structures library
3
4     (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
5
6     Source code repo: http://github.com/khizmax/libcds/
7     Download: http://sourceforge.net/projects/libcds/files/
8
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions are met:
11
12     * Redistributions of source code must retain the above copyright notice, this
13       list of conditions and the following disclaimer.
14
15     * Redistributions in binary form must reproduce the above copyright notice,
16       this list of conditions and the following disclaimer in the documentation
17       and/or other materials provided with the distribution.
18
19     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23     FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #ifndef CDSLIB_CONTAINER_MICHAEL_LIST_NOGC_H
32 #define CDSLIB_CONTAINER_MICHAEL_LIST_NOGC_H
33
34 #include <memory>
35 #include <cds/container/details/michael_list_base.h>
36 #include <cds/intrusive/michael_list_nogc.h>
37 #include <cds/container/details/make_michael_list.h>
38
39 namespace cds { namespace container {
40
41     //@cond
42     namespace details {
43
44         template <typename T, class Traits>
45         struct make_michael_list_nogc: public make_michael_list<gc::nogc, T, Traits>
46         {
47             typedef make_michael_list<cds::gc::nogc, T, Traits>  base_maker;
48             typedef typename base_maker::node_type node_type;
49
50             struct intrusive_traits: public base_maker::intrusive_traits
51             {
52                 typedef typename base_maker::node_deallocator    disposer;
53             };
54
55             typedef intrusive::MichaelList<cds::gc::nogc, node_type, intrusive_traits>  type;
56         };
57
58     }   // namespace details
59     //@endcond
60
61     /// Michael's lock-free ordered single-linked list (template specialization for \p gc::nogc)
62     /** @ingroup cds_nonintrusive_list
63         \anchor cds_nonintrusive_MichaelList_nogc
64
65         This specialization is intended for so-called append-only usage when no item
66         reclamation may be performed. The class does not support deleting of list item.
67         Usually, ordered single-linked list is used as a building block for the hash table implementation.
68         The complexity of searching is <tt>O(N)</tt>.
69
70         See \ref cds_nonintrusive_MichaelList_gc "MichaelList" for description of template parameters.
71     */
72     template <typename T,
73 #ifdef CDS_DOXYGEN_INVOKED
74         class Traits = michael_list::traits
75 #else
76         class Traits
77 #endif
78     >
79     class MichaelList<gc::nogc, T, Traits>:
80 #ifdef CDS_DOXYGEN_INVOKED
81         protected intrusive::MichaelList< gc::nogc, T, Traits >
82 #else
83         protected details::make_michael_list_nogc< T, Traits >::type
84 #endif
85     {
86         //@cond
87         typedef details::make_michael_list_nogc< T, Traits > maker;
88         typedef typename maker::type  base_class;
89         //@endcond
90
91     public:
92         typedef cds::gc::nogc gc;         ///< Garbage collector used
93         typedef T             value_type; ///< Type of value stored in the list
94         typedef Traits        traits;     ///< List traits
95
96         typedef typename base_class::back_off     back_off;       ///< Back-off strategy used
97         typedef typename maker::allocator_type    allocator_type; ///< Allocator type used for allocate/deallocate the nodes
98         typedef typename base_class::item_counter item_counter;   ///< Item counting policy used
99         typedef typename maker::key_comparator    key_comparator; ///< key comparison functor
100         typedef typename base_class::memory_model memory_model;   ///< Memory ordering. See cds::opt::memory_model option
101         typedef typename base_class::stat         stat;           ///< Internal statistics
102
103         //@cond
104         // Rebind traits (split-list support)
105         template <typename... Options>
106         struct rebind_traits {
107             typedef MichaelList<
108                 gc
109                 , value_type
110                 , typename cds::opt::make_options< traits, Options...>::type
111             > type;
112         };
113
114         // Stat selector
115         template <typename Stat>
116         using select_stat_wrapper = typename base_class::template select_stat_wrapper< Stat >;
117         //@endcond
118
119     protected:
120         //@cond
121         typedef typename base_class::value_type   node_type;
122         typedef typename maker::cxx_allocator     cxx_allocator;
123         typedef typename maker::node_deallocator  node_deallocator;
124         typedef typename maker::intrusive_traits::compare  intrusive_key_comparator;
125
126         typedef typename base_class::atomic_node_ptr head_type;
127
128         struct node_disposer {
129             void operator()( node_type * pNode )
130             {
131                 free_node( pNode );
132             }
133         };
134
135         typedef std::unique_ptr< node_type, node_disposer >     scoped_node_ptr;
136         //@endcond
137
138     protected:
139         //@cond
140         template <bool IsConst>
141         class iterator_type: protected base_class::template iterator_type<IsConst>
142         {
143             typedef typename base_class::template iterator_type<IsConst>    iterator_base;
144
145             iterator_type( head_type const& pNode )
146                 : iterator_base( pNode )
147             {}
148
149             explicit iterator_type( const iterator_base& it )
150                 : iterator_base( it )
151             {}
152
153             friend class MichaelList;
154
155         protected:
156             explicit iterator_type( node_type& pNode )
157                 : iterator_base( &pNode )
158             {}
159
160         public:
161             typedef typename cds::details::make_const_type<value_type, IsConst>::pointer   value_ptr;
162             typedef typename cds::details::make_const_type<value_type, IsConst>::reference value_ref;
163
164             iterator_type()
165             {}
166
167             iterator_type( const iterator_type& src )
168                 : iterator_base( src )
169             {}
170
171             value_ptr operator ->() const
172             {
173                 typename iterator_base::value_ptr p = iterator_base::operator ->();
174                 return p ? &(p->m_Value) : nullptr;
175             }
176
177             value_ref operator *() const
178             {
179                 return (iterator_base::operator *()).m_Value;
180             }
181
182             /// Pre-increment
183             iterator_type& operator ++()
184             {
185                 iterator_base::operator ++();
186                 return *this;
187             }
188
189             /// Post-increment
190             iterator_type operator ++(int)
191             {
192                 return iterator_base::operator ++(0);
193             }
194
195             template <bool C>
196             bool operator ==(iterator_type<C> const& i ) const
197             {
198                 return iterator_base::operator ==(i);
199             }
200             template <bool C>
201             bool operator !=(iterator_type<C> const& i ) const
202             {
203                 return iterator_base::operator !=(i);
204             }
205         };
206         //@endcond
207
208     public:
209    ///@name Forward iterators
210    //@{
211         /// Returns a forward iterator addressing the first element in a list
212         /**
213             For empty list \code begin() == end() \endcode
214         */
215         typedef iterator_type<false>    iterator;
216
217         /// Const forward iterator
218         /**
219             For iterator's features and requirements see \ref iterator
220         */
221         typedef iterator_type<true>     const_iterator;
222
223         /// Returns a forward iterator addressing the first element in a list
224         /**
225             For empty list \code begin() == end() \endcode
226         */
227         iterator begin()
228         {
229             return iterator( head());
230         }
231
232         /// Returns an iterator that addresses the location succeeding the last element in a list
233         /**
234             Do not use the value returned by <tt>end</tt> function to access any item.
235             Internally, <tt>end</tt> returning value equals to \p nullptr.
236
237             The returned value can be used only to control reaching the end of the list.
238             For empty list \code begin() == end() \endcode
239         */
240         iterator end()
241         {
242             return iterator();
243         }
244
245         /// Returns a forward const iterator addressing the first element in a list
246         const_iterator begin() const
247         {
248             return const_iterator( head());
249         }
250
251         /// Returns a forward const iterator addressing the first element in a list
252         const_iterator cbegin() const
253         {
254             return const_iterator( head());
255         }
256
257         /// Returns an const iterator that addresses the location succeeding the last element in a list
258         const_iterator end() const
259         {
260             return const_iterator();
261         }
262
263         /// Returns an const iterator that addresses the location succeeding the last element in a list
264         const_iterator cend() const
265         {
266             return const_iterator();
267         }
268     //@}
269
270     public:
271         /// Default constructor
272         /**
273             Initialize empty list
274         */
275         MichaelList()
276         {}
277
278         //@cond
279         template <typename Stat, typename = std::enable_if<std::is_same<stat, michael_list::wrapped_stat<Stat>>::value >>
280         explicit MichaelList( Stat& st )
281             : base_class( st )
282         {}
283         //@endcond
284
285         /// List destructor
286         /**
287             Clears the list
288         */
289         ~MichaelList()
290         {
291             clear();
292         }
293
294         /// Inserts new node
295         /**
296             The function inserts \p val in the list if the list does not contain
297             an item with key equal to \p val.
298
299             Return an iterator pointing to inserted item if success \ref end() otherwise
300         */
301         template <typename Q>
302         iterator insert( Q&& val )
303         {
304             return node_to_iterator( insert_at( head(), std::forward<Q>( val )));
305         }
306
307         /// Updates the item
308         /**
309             If \p key is not in the list and \p bAllowInsert is \p true,
310             the function inserts a new item.
311             Otherwise, the function returns an iterator pointing to the item found.
312
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.
316         */
317         template <typename Q>
318         std::pair<iterator, bool> update( Q&& key, bool bAllowInsert = true )
319         {
320             std::pair< node_type *, bool > ret = update_at( head(), std::forward<Q>( key ), bAllowInsert );
321             return std::make_pair( node_to_iterator( ret.first ), ret.second );
322         }
323         //@cond
324         template <typename Q>
325         CDS_DEPRECATED("ensure() is deprecated, use update()")
326         std::pair<iterator, bool> ensure( const Q& val )
327         {
328             return update( val, true );
329         }
330         //@endcond
331
332         /// Inserts data of type \ref value_type constructed with <tt>std::forward<Args>(args)...</tt>
333         /**
334             Return an iterator pointing to inserted item if success \ref end() otherwise
335         */
336         template <typename... Args>
337         iterator emplace( Args&&... args )
338         {
339             return node_to_iterator( emplace_at( head(), std::forward<Args>(args)... ));
340         }
341
342         /// Checks whether the list contains \p key
343         /**
344             The function searches the item with key equal to \p key
345             and returns an iterator pointed to item found if the key is found,
346             and \ref end() otherwise
347         */
348         template <typename Q>
349         iterator contains( Q const& key )
350         {
351             return node_to_iterator( find_at( head(), key, intrusive_key_comparator()));
352         }
353         //@cond
354         template <typename Q>
355         CDS_DEPRECATED("deprecated, use contains()")
356         iterator find( Q const& key )
357         {
358             return contains( key );
359         }
360         //@endcond
361
362         /// Checks whether the map contains \p key using \p pred predicate for searching
363         /**
364             The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
365             \p Less functor has the interface like \p std::less.
366             \p Less must imply the same element order as the comparator used for building the list.
367         */
368         template <typename Q, typename Less>
369         iterator contains( Q const& key, Less pred )
370         {
371             CDS_UNUSED( pred );
372             return node_to_iterator( find_at( head(), key, typename maker::template less_wrapper<Less>::type()));
373         }
374         //@cond
375         template <typename Q, typename Less>
376         CDS_DEPRECATED("deprecated, use contains()")
377         iterator find_with( Q const& key, Less pred )
378         {
379             return contains( key, pred );
380         }
381         //@endcond
382
383         /// Check if the list is empty
384         bool empty() const
385         {
386             return base_class::empty();
387         }
388
389         /// Returns list's item count
390         /**
391             The value returned depends on item counter provided by \p Traits. For \p atomicity::empty_item_counter,
392             this function always returns 0.
393
394             @note Even if you use real item counter and it returns 0, this fact does not mean that the list
395             is empty. To check list emptyness use \p empty() method.
396         */
397         size_t size() const
398         {
399             return base_class::size();
400         }
401
402         /// Returns const reference to internal statistics
403         stat const& statistics() const
404         {
405             return base_class::statistics();
406         }
407
408         /// Clears the list
409         void clear()
410         {
411             base_class::clear();
412         }
413
414     protected:
415         //@cond
416         static value_type& node_to_value( node_type& n )
417         {
418             return n.m_Value;
419         }
420
421         static node_type * alloc_node()
422         {
423             return cxx_allocator().New();
424         }
425
426         static node_type * alloc_node( value_type const& v )
427         {
428             return cxx_allocator().New( v );
429         }
430
431         template <typename... Args>
432         static node_type * alloc_node( Args&&... args )
433         {
434             return cxx_allocator().MoveNew( std::forward<Args>( args )... );
435         }
436
437         static void free_node( node_type * pNode )
438         {
439             cxx_allocator().Delete( pNode );
440         }
441
442         head_type& head()
443         {
444             return base_class::m_pHead;
445         }
446
447         head_type const& head() const
448         {
449             return base_class::m_pHead;
450         }
451
452         iterator node_to_iterator( node_type * pNode )
453         {
454             if ( pNode )
455                 return iterator( *pNode );
456             return end();
457         }
458
459         iterator insert_node( node_type * pNode )
460         {
461             return node_to_iterator( insert_node_at( head(), pNode ));
462         }
463
464         node_type * insert_node_at( head_type& refHead, node_type * pNode )
465         {
466             assert( pNode != nullptr );
467             scoped_node_ptr p(pNode);
468             if ( base_class::insert_at( refHead, *pNode ))
469                 return p.release();
470
471             return nullptr;
472         }
473
474         template <typename Q>
475         node_type * insert_at( head_type& refHead, Q&& val )
476         {
477             return insert_node_at( refHead, alloc_node( std::forward<Q>( val )));
478         }
479
480         template <typename Q>
481         std::pair< node_type *, bool > update_at( head_type& refHead, Q&& val, bool bAllowInsert )
482         {
483             scoped_node_ptr pNode( alloc_node( std::forward<Q>( val )));
484             node_type * pItemFound = nullptr;
485
486             std::pair<bool, bool> ret = base_class::update_at( refHead, *pNode,
487                 [&pItemFound](bool, node_type& item, node_type&) { pItemFound = &item; },
488                 bAllowInsert );
489
490             if ( ret.second )
491                 pNode.release();
492             return std::make_pair( pItemFound, ret.second );
493         }
494
495         template <typename... Args>
496         node_type * emplace_at( head_type& refHead, Args&&... args )
497         {
498             return insert_node_at( refHead, alloc_node( std::forward<Args>(args)...));
499         }
500
501         template <typename Q, typename Compare>
502         node_type * find_at( head_type& refHead, Q const& key, Compare cmp )
503         {
504             return base_class::find_at( refHead, key, cmp );
505         }
506         //@endcond
507     };
508 }} // namespace cds::container
509
510 #endif // #ifndef CDSLIB_CONTAINER_MICHAEL_LIST_NOGC_H