Added internal statistics to MichaelList, IterableList
[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     protected:
104         //@cond
105         typedef typename base_class::value_type   node_type;
106         typedef typename maker::cxx_allocator     cxx_allocator;
107         typedef typename maker::node_deallocator  node_deallocator;
108         typedef typename maker::intrusive_traits::compare  intrusive_key_comparator;
109
110         typedef typename base_class::atomic_node_ptr head_type;
111         //@endcond
112
113     protected:
114         //@cond
115         static node_type * alloc_node()
116         {
117             return cxx_allocator().New();
118         }
119
120         static node_type * alloc_node( value_type const& v )
121         {
122             return cxx_allocator().New( v );
123         }
124
125         template <typename... Args>
126         static node_type * alloc_node( Args&&... args )
127         {
128             return cxx_allocator().MoveNew( std::forward<Args>(args)... );
129         }
130
131         static void free_node( node_type * pNode )
132         {
133             cxx_allocator().Delete( pNode );
134         }
135
136         struct node_disposer {
137             void operator()( node_type * pNode )
138             {
139                 free_node( pNode );
140             }
141         };
142         typedef std::unique_ptr< node_type, node_disposer >     scoped_node_ptr;
143
144         head_type& head()
145         {
146             return base_class::m_pHead;
147         }
148
149         head_type const& head() const
150         {
151             return base_class::m_pHead;
152         }
153         //@endcond
154
155     protected:
156         //@cond
157         template <bool IsConst>
158         class iterator_type: protected base_class::template iterator_type<IsConst>
159         {
160             typedef typename base_class::template iterator_type<IsConst>    iterator_base;
161
162             iterator_type( head_type const& pNode )
163                 : iterator_base( pNode )
164             {}
165
166             explicit iterator_type( const iterator_base& it )
167                 : iterator_base( it )
168             {}
169
170             friend class MichaelList;
171
172         protected:
173             explicit iterator_type( node_type& pNode )
174                 : iterator_base( &pNode )
175             {}
176
177         public:
178             typedef typename cds::details::make_const_type<value_type, IsConst>::pointer   value_ptr;
179             typedef typename cds::details::make_const_type<value_type, IsConst>::reference value_ref;
180
181             iterator_type()
182             {}
183
184             iterator_type( const iterator_type& src )
185                 : iterator_base( src )
186             {}
187
188             value_ptr operator ->() const
189             {
190                 typename iterator_base::value_ptr p = iterator_base::operator ->();
191                 return p ? &(p->m_Value) : nullptr;
192             }
193
194             value_ref operator *() const
195             {
196                 return (iterator_base::operator *()).m_Value;
197             }
198
199             /// Pre-increment
200             iterator_type& operator ++()
201             {
202                 iterator_base::operator ++();
203                 return *this;
204             }
205
206             /// Post-increment
207             iterator_type operator ++(int)
208             {
209                 return iterator_base::operator ++(0);
210             }
211
212             template <bool C>
213             bool operator ==(iterator_type<C> const& i ) const
214             {
215                 return iterator_base::operator ==(i);
216             }
217             template <bool C>
218             bool operator !=(iterator_type<C> const& i ) const
219             {
220                 return iterator_base::operator !=(i);
221             }
222         };
223         //@endcond
224
225     public:
226    ///@name Forward iterators
227    //@{
228         /// Returns a forward iterator addressing the first element in a list
229         /**
230             For empty list \code begin() == end() \endcode
231         */
232         typedef iterator_type<false>    iterator;
233
234         /// Const forward iterator
235         /**
236             For iterator's features and requirements see \ref iterator
237         */
238         typedef iterator_type<true>     const_iterator;
239
240         /// Returns a forward iterator addressing the first element in a list
241         /**
242             For empty list \code begin() == end() \endcode
243         */
244         iterator begin()
245         {
246             return iterator( head() );
247         }
248
249         /// Returns an iterator that addresses the location succeeding the last element in a list
250         /**
251             Do not use the value returned by <tt>end</tt> function to access any item.
252             Internally, <tt>end</tt> returning value equals to \p nullptr.
253
254             The returned value can be used only to control reaching the end of the list.
255             For empty list \code begin() == end() \endcode
256         */
257         iterator end()
258         {
259             return iterator();
260         }
261
262         /// Returns a forward const iterator addressing the first element in a list
263         const_iterator begin() const
264         {
265             return const_iterator( head() );
266         }
267
268         /// Returns a forward const iterator addressing the first element in a list
269         const_iterator cbegin() const
270         {
271             return const_iterator( head() );
272         }
273
274         /// Returns an const iterator that addresses the location succeeding the last element in a list
275         const_iterator end() const
276         {
277             return const_iterator();
278         }
279
280         /// Returns an const iterator that addresses the location succeeding the last element in a list
281         const_iterator cend() const
282         {
283             return const_iterator();
284         }
285     //@}
286
287     protected:
288         //@cond
289         iterator node_to_iterator( node_type * pNode )
290         {
291             if ( pNode )
292                 return iterator( *pNode );
293             return end();
294         }
295         //@endcond
296
297     public:
298         /// Default constructor
299         /**
300             Initialize empty list
301         */
302         MichaelList()
303         {}
304
305         //@cond
306         template <typename Stat, typename = std::enable_if<std::is_same<stat, michael_list::wrapped_stat<Stat>>::value >>
307         explicit MichaelList( Stat& st )
308             : base_class( st )
309         {}
310         //@endcond
311
312         /// List destructor
313         /**
314             Clears the list
315         */
316         ~MichaelList()
317         {
318             clear();
319         }
320
321         /// Inserts new node
322         /**
323             The function inserts \p val in the list if the list does not contain
324             an item with key equal to \p val.
325
326             Return an iterator pointing to inserted item if success \ref end() otherwise
327         */
328         template <typename Q>
329         iterator insert( const Q& val )
330         {
331             return node_to_iterator( insert_at( head(), val ) );
332         }
333
334         /// Updates the item
335         /**
336             If \p key is not in the list and \p bAllowInsert is \p true,
337             the function inserts a new item.
338             Otherwise, the function returns an iterator pointing to the item found.
339
340             Returns <tt> std::pair<iterator, bool>  </tt> where \p first is an iterator pointing to
341             item found or inserted, \p second is true if new item has been added or \p false if the item
342             already is in the list.
343         */
344         template <typename Q>
345         std::pair<iterator, bool> update( const Q& key, bool bAllowInsert = true )
346         {
347             std::pair< node_type *, bool > ret = update_at( head(), key, bAllowInsert );
348             return std::make_pair( node_to_iterator( ret.first ), ret.second );
349         }
350         //@cond
351         template <typename Q>
352         CDS_DEPRECATED("ensure() is deprecated, use update()")
353         std::pair<iterator, bool> ensure( const Q& val )
354         {
355             return update( val, true );
356         }
357         //@endcond
358
359         /// Inserts data of type \ref value_type constructed with <tt>std::forward<Args>(args)...</tt>
360         /**
361             Return an iterator pointing to inserted item if success \ref end() otherwise
362         */
363         template <typename... Args>
364         iterator emplace( Args&&... args )
365         {
366             return node_to_iterator( emplace_at( head(), std::forward<Args>(args)... ));
367         }
368
369         /// Checks whether the list contains \p key
370         /**
371             The function searches the item with key equal to \p key
372             and returns an iterator pointed to item found if the key is found,
373             and \ref end() otherwise
374         */
375         template <typename Q>
376         iterator contains( Q const& key )
377         {
378             return node_to_iterator( find_at( head(), key, intrusive_key_comparator() ));
379         }
380         //@cond
381         template <typename Q>
382         CDS_DEPRECATED("deprecated, use contains()")
383         iterator find( Q const& key )
384         {
385             return contains( key );
386         }
387         //@endcond
388
389         /// Checks whether the map contains \p key using \p pred predicate for searching
390         /**
391             The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
392             \p Less functor has the interface like \p std::less.
393             \p Less must imply the same element order as the comparator used for building the list.
394         */
395         template <typename Q, typename Less>
396         iterator contains( Q const& key, Less pred )
397         {
398             CDS_UNUSED( pred );
399             return node_to_iterator( find_at( head(), key, typename maker::template less_wrapper<Less>::type() ) );
400         }
401         //@cond
402         template <typename Q, typename Less>
403         CDS_DEPRECATED("deprecated, use contains()")
404         iterator find_with( Q const& key, Less pred )
405         {
406             return contains( key, pred );
407         }
408         //@endcond
409
410         /// Check if the list is empty
411         bool empty() const
412         {
413             return base_class::empty();
414         }
415
416         /// Returns list's item count
417         /**
418             The value returned depends on item counter provided by \p Traits. For \p atomicity::empty_item_counter,
419             this function always returns 0.
420
421             @note Even if you use real item counter and it returns 0, this fact does not mean that the list
422             is empty. To check list emptyness use \p empty() method.
423         */
424         size_t size() const
425         {
426             return base_class::size();
427         }
428
429         /// Returns const reference to internal statistics
430         stat const& statistics() const
431         {
432             return base_class::statistics();
433         }
434
435         /// Clears the list
436         void clear()
437         {
438             base_class::clear();
439         }
440
441     protected:
442         //@cond
443         static value_type& node_to_value( node_type& n )
444         {
445             return n.m_Value;
446         }
447
448         iterator insert_node( node_type * pNode )
449         {
450             return node_to_iterator( insert_node_at( head(), pNode ));
451         }
452
453         node_type * insert_node_at( head_type& refHead, node_type * pNode )
454         {
455             assert( pNode != nullptr );
456             scoped_node_ptr p(pNode);
457             if ( base_class::insert_at( refHead, *pNode ))
458                 return p.release();
459
460             return nullptr;
461         }
462
463         template <typename Q>
464         node_type * insert_at( head_type& refHead, const Q& val )
465         {
466             return insert_node_at( refHead, alloc_node( val ));
467         }
468
469         template <typename Q>
470         std::pair< node_type *, bool > update_at( head_type& refHead, const Q& val, bool bAllowInsert )
471         {
472             scoped_node_ptr pNode( alloc_node( val ));
473             node_type * pItemFound = nullptr;
474
475             std::pair<bool, bool> ret = base_class::update_at( refHead, *pNode,
476                 [&pItemFound](bool, node_type& item, node_type&) { pItemFound = &item; },
477                 bAllowInsert );
478
479             if ( ret.second )
480                 pNode.release();
481             return std::make_pair( pItemFound, ret.second );
482         }
483
484         template <typename... Args>
485         node_type * emplace_at( head_type& refHead, Args&&... args )
486         {
487             return insert_node_at( refHead, alloc_node( std::forward<Args>(args)...));
488         }
489
490         template <typename Q, typename Compare>
491         node_type * find_at( head_type& refHead, Q const& key, Compare cmp )
492         {
493             return base_class::find_at( refHead, key, cmp );
494         }
495
496         //@endcond
497     };
498 }} // namespace cds::container
499
500 #endif // #ifndef CDSLIB_CONTAINER_MICHAEL_LIST_NOGC_H