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