Updated copyright
[libcds.git] / cds / container / lazy_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-2017
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_LAZY_LIST_NOGC_H
32 #define CDSLIB_CONTAINER_LAZY_LIST_NOGC_H
33
34 #include <memory>
35 #include <cds/container/details/lazy_list_base.h>
36 #include <cds/intrusive/lazy_list_nogc.h>
37 #include <cds/container/details/make_lazy_list.h>
38
39 namespace cds { namespace container {
40
41     /// Lazy ordered single-linked list (template specialization for gc::nogc)
42     /** @ingroup cds_nonintrusive_list
43         \anchor cds_nonintrusive_LazyList_nogc
44
45         This specialization is so-called append-only when no item
46         reclamation may be performed. The class does not support deleting of list item.
47
48         The list can be ordered if \p Traits::sort is \p true that is default
49         or unordered otherwise. Unordered list can be maintained by \p equal_to
50         relationship (\p Traits::equal_to), but for the ordered list \p less
51         or \p compare relations should be specified in \p Traits.
52
53         See @ref cds_nonintrusive_LazyList_gc "cds::container::LazyList<cds::gc::nogc, T, Traits>"
54     */
55     template <
56         typename T,
57 #ifdef CDS_DOXYGEN_INVOKED
58         typename Traits = lazy_list::traits
59 #else
60         typename Traits
61 #endif
62     >
63     class LazyList<cds::gc::nogc, T, Traits>:
64 #ifdef CDS_DOXYGEN_INVOKED
65         protected intrusive::LazyList< gc::nogc, T, Traits >
66 #else
67         protected details::make_lazy_list< cds::gc::nogc, T, Traits >::type
68 #endif
69     {
70         //@cond
71         typedef details::make_lazy_list< cds::gc::nogc, T, Traits > maker;
72         typedef typename maker::type  base_class;
73         //@endcond
74
75     public:
76         typedef cds::gc::nogc gc;  ///< Garbage collector
77         typedef T      value_type; ///< Type of value stored in the list
78         typedef Traits traits;     ///< List traits
79
80         typedef typename base_class::back_off     back_off;         ///< Back-off strategy used
81         typedef typename maker::allocator_type    allocator_type;   ///< Allocator type used for allocate/deallocate the nodes
82         typedef typename base_class::item_counter item_counter;     ///< Item counting policy used
83         typedef typename maker::key_comparator    key_comparator;   ///< key comparing functor
84         typedef typename base_class::memory_model memory_model;     ///< Memory ordering. See cds::opt::memory_model option
85         typedef typename base_class::stat         stat;             ///< Internal statistics
86
87         static CDS_CONSTEXPR bool const c_bSort = base_class::c_bSort; ///< List type: ordered (\p true) or unordered (\p false)
88
89         //@cond
90         // Rebind traits (split-list support)
91         template <typename... Options>
92         struct rebind_traits {
93             typedef LazyList<
94                 gc
95                 , value_type
96                 , typename cds::opt::make_options< traits, Options...>::type
97             > type;
98         };
99
100         // Stat selector
101         template <typename Stat>
102         using select_stat_wrapper = typename base_class::template select_stat_wrapper< Stat >;
103         //@endcond
104
105     protected:
106         //@cond
107         typedef typename base_class::value_type     node_type;
108         typedef typename maker::cxx_allocator       cxx_allocator;
109         typedef typename maker::node_deallocator    node_deallocator;
110         typedef typename base_class::key_comparator intrusive_key_comparator;
111
112         typedef typename base_class::node_type      head_type;
113
114         struct node_disposer {
115             void operator()( node_type * pNode )
116             {
117                 free_node( pNode );
118             }
119         };
120         typedef std::unique_ptr< node_type, node_disposer >     scoped_node_ptr;
121         //@endcond
122
123     protected:
124         //@cond
125         template <bool IsConst>
126         class iterator_type: protected base_class::template iterator_type<IsConst>
127         {
128             typedef typename base_class::template iterator_type<IsConst>    iterator_base;
129
130             iterator_type( head_type const& pNode )
131                 : iterator_base( const_cast<head_type *>(&pNode))
132             {}
133
134             explicit iterator_type( const iterator_base& it )
135                 : iterator_base( it )
136             {}
137
138             friend class LazyList;
139
140         protected:
141             explicit iterator_type( node_type& pNode )
142                 : iterator_base( &pNode )
143             {}
144
145         public:
146             typedef typename cds::details::make_const_type<value_type, IsConst>::pointer   value_ptr;
147             typedef typename cds::details::make_const_type<value_type, IsConst>::reference value_ref;
148
149             iterator_type()
150             {}
151
152             iterator_type( const iterator_type& src )
153                 : iterator_base( src )
154             {}
155
156             value_ptr operator ->() const
157             {
158                 typename iterator_base::value_ptr p = iterator_base::operator ->();
159                 return p ? &(p->m_Value) : nullptr;
160             }
161
162             value_ref operator *() const
163             {
164                 return (iterator_base::operator *()).m_Value;
165             }
166
167             /// Pre-increment
168             iterator_type& operator ++()
169             {
170                 iterator_base::operator ++();
171                 return *this;
172             }
173
174             /// Post-increment
175             iterator_type operator ++(int)
176             {
177                 return iterator_base::operator ++(0);
178             }
179
180             template <bool C>
181             bool operator ==(iterator_type<C> const& i ) const
182             {
183                 return iterator_base::operator ==(i);
184             }
185             template <bool C>
186             bool operator !=(iterator_type<C> const& i ) const
187             {
188                 return iterator_base::operator !=(i);
189             }
190         };
191         //@endcond
192
193     public:
194     ///@name Forward iterators
195     //@{
196         /// Returns a forward iterator addressing the first element in a list
197         /**
198             For empty list \code begin() == end() \endcode
199         */
200         typedef iterator_type<false>    iterator;
201
202         /// Const forward iterator
203         /**
204             For iterator's features and requirements see \ref iterator
205         */
206         typedef iterator_type<true>     const_iterator;
207
208         /// Returns a forward iterator addressing the first element in a list
209         /**
210             For empty list \code begin() == end() \endcode
211         */
212         iterator begin()
213         {
214             iterator it( head());
215             ++it    ;   // skip dummy head node
216             return it;
217         }
218
219         /// Returns an iterator that addresses the location succeeding the last element in a list
220         /**
221             Do not use the value returned by <tt>end</tt> function to access any item.
222
223             The returned value can be used only to control reaching the end of the list.
224             For empty list \code begin() == end() \endcode
225         */
226         iterator end()
227         {
228             return iterator( tail());
229         }
230
231         /// Returns a forward const iterator addressing the first element in a list
232         const_iterator begin() const
233         {
234             const_iterator it( head());
235             ++it    ;   // skip dummy head node
236             return it;
237         }
238
239         /// Returns a forward const iterator addressing the first element in a list
240         const_iterator cbegin() const
241         {
242             const_iterator it( head());
243             ++it    ;   // skip dummy head node
244             return it;
245         }
246
247         /// Returns an const iterator that addresses the location succeeding the last element in a list
248         const_iterator end() const
249         {
250             return const_iterator( tail());
251         }
252
253         /// Returns an const iterator that addresses the location succeeding the last element in a list
254         const_iterator cend() const
255         {
256             return const_iterator( tail());
257         }
258     //@}
259
260     public:
261         /// Default constructor
262         LazyList()
263         {}
264
265         //@cond
266         template <typename Stat, typename = std::enable_if<std::is_same<stat, lazy_list::wrapped_stat<Stat>>::value >>
267         explicit LazyList( Stat& st )
268             : base_class( st )
269         {}
270         //@endcond
271
272         /// Desctructor clears the list
273         ~LazyList()
274         {
275             clear();
276         }
277
278         /// Inserts new node
279         /**
280             The function inserts \p val in the list if the list does not contain
281             an item with key equal to \p val.
282
283             Return an iterator pointing to inserted item if success \ref end() otherwise
284         */
285         template <typename Q>
286         iterator insert( Q&& val )
287         {
288             return node_to_iterator( insert_at( head(), std::forward<Q>( val )));
289         }
290
291         /// Inserts data of type \p value_type created from \p args
292         /**
293             Return an iterator pointing to inserted item if success \ref end() otherwise
294         */
295         template <typename... Args>
296         iterator emplace( Args&&... args )
297         {
298             return node_to_iterator( emplace_at( head(), std::forward<Args>(args)... ));
299         }
300
301         /// Updates the item
302         /**
303             If \p key is not in the list and \p bAllowInsert is \p true,
304             the function inserts a new item.
305             Otherwise, the function returns an iterator pointing to the item found.
306
307             Returns <tt> std::pair<iterator, bool>  </tt> where \p first is an iterator pointing to
308             item found or inserted, \p second is true if new item has been added or \p false if the item
309             already is in the list.
310         */
311         template <typename Q>
312         std::pair<iterator, bool> update( Q&& val, bool bAllowInsert = true )
313         {
314             std::pair< node_type *, bool > ret = update_at( head(), std::forward<Q>( val ), bAllowInsert );
315             return std::make_pair( node_to_iterator( ret.first ), ret.second );
316         }
317         //@cond
318         template <typename Q>
319         CDS_DEPRECATED("ensure() is deprecated, use update()")
320         std::pair<iterator, bool> ensure( Q const& val )
321         {
322             return update( val, true );
323         }
324         //@endcond
325
326         /// Checks whether the list contains \p key
327         /**
328             The function searches the item with key equal to \p key
329             and returns an iterator pointed to item found if the key is found,
330             and \ref end() otherwise
331         */
332         template <typename Q>
333         iterator contains( Q const& key )
334         {
335             return node_to_iterator( find_at( head(), key, intrusive_key_comparator()));
336         }
337         //@cond
338         template <typename Q>
339         CDS_DEPRECATED("deprecated, use contains()")
340         iterator find( Q const& key )
341         {
342             return contains( key );
343         }
344         //@endcond
345
346         /// Checks whether the map contains \p key using \p pred predicate for searching (ordered list version)
347         /**
348             The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
349             \p Less functor has the interface like \p std::less.
350             \p Less must imply the same element order as the comparator used for building the list.
351         */
352         template <typename Q, typename Less, bool Sort = c_bSort>
353         typename std::enable_if<Sort, iterator>::type contains( Q const& key, Less pred )
354         {
355             CDS_UNUSED( pred );
356             return node_to_iterator( find_at( head(), key, typename maker::template less_wrapper<Less>::type()));
357         }
358         //@cond
359         template <typename Q, typename Less, bool Sort = c_bSort>
360         CDS_DEPRECATED("deprecated, use contains()")
361         typename std::enable_if<Sort, iterator>::type find_with( Q const& key, Less pred )
362         {
363             return contains( key, pred );
364         }
365         //@endcond
366
367         /// Finds the key \p val using \p equal predicate for searching (unordered list version)
368         /**
369             The function is an analog of <tt>contains( key )</tt> but \p equal is used for key comparing.
370             \p Equal functor has the interface like \p std::equal_to.
371         */
372         template <typename Q, typename Equal, bool Sort = c_bSort>
373         typename std::enable_if<!Sort, iterator>::type contains( Q const& key, Equal equal )
374         {
375             CDS_UNUSED( equal );
376             return node_to_iterator( find_at( head(), key, typename maker::template equal_to_wrapper<Equal>::type()));
377         }
378         //@cond
379         template <typename Q, typename Equal, bool Sort = c_bSort>
380         CDS_DEPRECATED("deprecated, use contains()")
381         typename std::enable_if<!Sort, iterator>::type find_with( Q const& key, Equal equal )
382         {
383             return contains( key, equal );
384         }
385         //@endcond
386
387         /// Check if the list is empty
388         bool empty() const
389         {
390             return base_class::empty();
391         }
392
393         /// Returns list's item count
394         /**
395             The value returned depends on \p Traits::item_counter type. For \p atomicity::empty_item_counter,
396             this function always returns 0.
397
398             @note Even if you use real item counter and it returns 0, this fact is not mean that the list
399             is empty. To check list emptyness use \ref empty() method.
400         */
401         size_t size() const
402         {
403             return base_class::size();
404         }
405
406         /// Returns const reference to internal statistics
407         stat const& statistics() const
408         {
409             return base_class::statistics();
410         }
411
412         /// Clears the list
413         void clear()
414         {
415             base_class::clear();
416         }
417
418     protected:
419         //@cond
420         static value_type& node_to_value( node_type& n )
421         {
422             return n.m_Value;
423         }
424
425         static node_type * alloc_node()
426         {
427             return cxx_allocator().New();
428         }
429
430         static node_type * alloc_node( value_type const& v )
431         {
432             return cxx_allocator().New( v );
433         }
434
435         template <typename... Args>
436         static node_type * alloc_node( Args&&... args )
437         {
438             return cxx_allocator().MoveNew( std::forward<Args>( args )... );
439         }
440
441         static void free_node( node_type * pNode )
442         {
443             cxx_allocator().Delete( pNode );
444         }
445
446         head_type& head()
447         {
448             return base_class::m_Head;
449         }
450
451         head_type const& head() const
452         {
453             return base_class::m_Head;
454         }
455
456         head_type& tail()
457         {
458             return base_class::m_Tail;
459         }
460
461         head_type const& tail() const
462         {
463             return base_class::m_Tail;
464         }
465
466         iterator node_to_iterator( node_type * pNode )
467         {
468             if ( pNode )
469                 return iterator( *pNode );
470             return end();
471         }
472
473         iterator insert_node( node_type * pNode )
474         {
475             return node_to_iterator( insert_node_at( head(), pNode ));
476         }
477
478         node_type * insert_node_at( head_type& refHead, node_type * pNode )
479         {
480             assert( pNode != nullptr );
481             scoped_node_ptr p( pNode );
482             if ( base_class::insert_at( &refHead, *p ))
483                 return p.release();
484
485             return nullptr;
486         }
487
488         template <typename Q>
489         node_type * insert_at( head_type& refHead, Q&& val )
490         {
491             return insert_node_at( refHead, alloc_node( std::forward<Q>( val )));
492         }
493
494         template <typename... Args>
495         node_type * emplace_at( head_type& refHead, Args&&... args )
496         {
497             return insert_node_at( refHead, alloc_node( std::forward<Args>(args)... ));
498         }
499
500         template <typename Q>
501         std::pair< node_type *, bool > update_at( head_type& refHead, Q&& val, bool bAllowInsert )
502         {
503             scoped_node_ptr pNode( alloc_node( std::forward<Q>( val )));
504             node_type * pItemFound = nullptr;
505
506             std::pair<bool, bool> ret = base_class::update_at( &refHead, *pNode,
507                 [&pItemFound](bool, node_type& item, node_type&) { pItemFound = &item; },
508                 bAllowInsert );
509
510             if ( ret.second )
511                 pNode.release();
512
513             return std::make_pair( pItemFound, ret.second );
514         }
515
516         template <typename Q, typename Compare>
517         node_type * find_at( head_type& refHead, Q const& key, Compare cmp )
518         {
519             return base_class::find_at( &refHead, key, cmp );
520         }
521
522         //@endcond
523     };
524 }} // namespace cds::container
525
526 #endif // #ifndef CDSLIB_CONTAINER_LAZY_LIST_NOGC_H