Merged branch 'master' of https://github.com/Nemo1369/libcds
[libcds.git] / cds / container / lazy_kvlist_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_KVLIST_NOGC_H
32 #define CDSLIB_CONTAINER_LAZY_KVLIST_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_kvlist.h>
38
39 namespace cds { namespace container {
40
41     /// Lazy ordered list (key-value pair, template specialization for gc::nogc)
42     /** @ingroup cds_nonintrusive_list
43         @anchor cds_nonintrusive_LazyKVList_nogc
44
45         This specialization is append-only list when no item
46         reclamation may be performed. The class does not support deleting of list's item.
47
48         See @ref cds_nonintrusive_LazyList_gc "cds::container::LazyList<cds::gc::nogc, T, Traits>"
49     */
50     template <
51         typename Key,
52         typename Value,
53 #ifdef CDS_DOXYGEN_INVOKED
54         typename Traits = lazy_list::traits
55 #else
56         typename Traits
57 #endif
58     >
59     class LazyKVList<gc::nogc, Key, Value, Traits>:
60 #ifdef CDS_DOXYGEN_INVOKED
61         protected intrusive::LazyList< gc::nogc, implementation_defined, Traits >
62 #else
63         protected details::make_lazy_kvlist< cds::gc::nogc, Key, Value, Traits >::type
64 #endif
65     {
66         //@cond
67         typedef details::make_lazy_kvlist< cds::gc::nogc, Key, Value, Traits > maker;
68         typedef typename maker::type  base_class;
69         //@endcond
70
71     public:
72         typedef Traits traits;    ///< List traits
73         typedef cds::gc::nogc gc; ///< Garbage collector
74 #ifdef CDS_DOXYGEN_INVOKED
75         typedef Key                                 key_type        ;   ///< Key type
76         typedef Value                               mapped_type     ;   ///< Type of value stored in the list
77         typedef std::pair<key_type const, mapped_type> value_type   ;   ///< key/value pair stored in the list
78 #else
79         typedef typename maker::key_type    key_type;
80         typedef typename maker::mapped_type mapped_type;
81         typedef typename maker::value_type  value_type;
82 #endif
83         typedef typename base_class::back_off     back_off;       ///< Back-off strategy used
84         typedef typename maker::allocator_type    allocator_type; ///< Allocator type used for allocate/deallocate the nodes
85         typedef typename base_class::item_counter item_counter;   ///< Item counting policy used
86         typedef typename maker::key_comparator    key_comparator; ///< key comparison functor
87         typedef typename base_class::memory_model memory_model;   ///< Memory ordering. See cds::opt::memory_model option
88         typedef typename base_class::stat         stat;           ///< Internal statistics
89         static CDS_CONSTEXPR bool const c_bSort = base_class::c_bSort; ///< List type: ordered (\p true) or unordered (\p false)
90
91         //@cond
92         // Rebind traits (split-list support)
93         template <typename... Options>
94         struct rebind_traits {
95             typedef LazyKVList<
96                 gc
97                 , key_type, mapped_type
98                 , typename cds::opt::make_options< traits, Options...>::type
99             > type;
100         };
101
102         // Stat selector
103         template <typename Stat>
104         using select_stat_wrapper = typename base_class::template select_stat_wrapper< Stat >;
105         //@endcond
106
107     protected:
108         //@cond
109         typedef typename base_class::value_type     node_type;
110         typedef typename maker::cxx_allocator       cxx_allocator;
111         typedef typename maker::node_deallocator    node_deallocator;
112         typedef typename base_class::key_comparator intrusive_key_comparator;
113         typedef typename base_class::node_type      head_type;
114         //@endcond
115
116     protected:
117         //@cond
118         template <typename K>
119         static node_type * alloc_node(const K& key)
120         {
121             return cxx_allocator().New( key );
122         }
123
124         template <typename K, typename V>
125         static node_type * alloc_node( const K& key, const V& val )
126         {
127             return cxx_allocator().New( key, val );
128         }
129
130         template <typename... Args>
131         static node_type * alloc_node( Args&&... args )
132         {
133             return cxx_allocator().MoveNew( std::forward<Args>(args)... );
134         }
135
136         static void free_node( node_type * pNode )
137         {
138             cxx_allocator().Delete( pNode );
139         }
140
141         struct node_disposer {
142             void operator()( node_type * pNode )
143             {
144                 free_node( pNode );
145             }
146         };
147         typedef std::unique_ptr< node_type, node_disposer >     scoped_node_ptr;
148
149         head_type& head()
150         {
151             return base_class::m_Head;
152         }
153
154         head_type const& head() const
155         {
156             return base_class::m_Head;
157         }
158
159         head_type& tail()
160         {
161             return base_class::m_Tail;
162         }
163
164         head_type const& tail() const
165         {
166             return base_class::m_Tail;
167         }
168         //@endcond
169
170     protected:
171         //@cond
172         template <bool IsConst>
173         class iterator_type: protected base_class::template iterator_type<IsConst>
174         {
175             typedef typename base_class::template iterator_type<IsConst>    iterator_base;
176
177             iterator_type( head_type const& refNode )
178                 : iterator_base( const_cast<head_type *>( &refNode ))
179             {}
180
181             explicit iterator_type( const iterator_base& it )
182                 : iterator_base( it )
183             {}
184
185             friend class LazyKVList;
186
187         protected:
188             explicit iterator_type( node_type& pNode )
189                 : iterator_base( &pNode )
190             {}
191
192         public:
193             typedef typename cds::details::make_const_type<mapped_type, IsConst>::reference  value_ref;
194             typedef typename cds::details::make_const_type<mapped_type, IsConst>::pointer    value_ptr;
195
196             typedef typename cds::details::make_const_type<value_type,  IsConst>::reference  pair_ref;
197             typedef typename cds::details::make_const_type<value_type,  IsConst>::pointer    pair_ptr;
198
199             iterator_type()
200                 : iterator_base()
201             {}
202
203             iterator_type( const iterator_type& src )
204                 : iterator_base( src )
205             {}
206
207             key_type const& key() const
208             {
209                 typename iterator_base::value_ptr p = iterator_base::operator ->();
210                 assert( p != nullptr );
211                 return p->m_Data.first;
212             }
213
214             value_ref val() const
215             {
216                 typename iterator_base::value_ptr p = iterator_base::operator ->();
217                 assert( p != nullptr );
218                 return p->m_Data.second;
219             }
220
221             pair_ptr operator ->() const
222             {
223                 typename iterator_base::value_ptr p = iterator_base::operator ->();
224                 return p ? &(p->m_Data) : nullptr;
225             }
226
227             pair_ref operator *() const
228             {
229                 typename iterator_base::value_ref p = iterator_base::operator *();
230                 return p.m_Data;
231             }
232
233             /// Pre-increment
234             iterator_type& operator ++()
235             {
236                 iterator_base::operator ++();
237                 return *this;
238             }
239
240             /// Post-increment
241             iterator_type operator ++(int)
242             {
243                 return iterator_base::operator ++(0);
244             }
245
246             template <bool C>
247             bool operator ==(iterator_type<C> const& i ) const
248             {
249                 return iterator_base::operator ==(i);
250             }
251             template <bool C>
252             bool operator !=(iterator_type<C> const& i ) const
253             {
254                 return iterator_base::operator !=(i);
255             }
256         };
257         //@endcond
258
259     public:
260     ///@name Forward iterators
261     //@{
262         /// Forward iterator
263         /**
264         The forward iterator is safe: you may use it in multi-threaded enviromnent without any synchronization.
265
266         The forward iterator for lazy list based on \p gc::nogc has pre- and post-increment operators.
267
268             The iterator interface to access item data:
269             - <tt> operator -> </tt> - returns a pointer to \p value_type
270             - <tt> operator *</tt> - returns a reference (a const reference for \p const_iterator) to \p value_type
271             - <tt> const key_type& key() </tt> - returns a key reference for iterator
272             - <tt> mapped_type& val() </tt> - retuns a value reference for iterator (const reference for \p const_iterator)
273
274             For both functions the iterator should not be equal to \p end()
275         */
276         typedef iterator_type<false>    iterator;
277
278         /// Const forward iterator
279         /**
280             For iterator's features and requirements see \ref iterator
281         */
282         typedef iterator_type<true>     const_iterator;
283
284         /// Returns a forward iterator addressing the first element in a list
285         /**
286             For empty list \code begin() == end() \endcode
287         */
288         iterator begin()
289         {
290             iterator it( head());
291             ++it ;  // skip dummy head
292             return it;
293         }
294
295         /// Returns an iterator that addresses the location succeeding the last element in a list
296         /**
297             Do not use the value returned by <tt>end</tt> function to access any item.
298             Internally, <tt>end</tt> returning value equals to nullptr.
299
300             The returned value can be used only to control reaching the end of the list.
301             For empty list \code begin() == end() \endcode
302         */
303         iterator end()
304         {
305             return iterator( tail());
306         }
307
308         /// Returns a forward const iterator addressing the first element in a list
309         const_iterator begin() const
310         {
311             const_iterator it( head());
312             ++it ;  // skip dummy head
313             return it;
314         }
315         /// Returns a forward const iterator addressing the first element in a list
316         const_iterator cbegin() const
317         {
318             const_iterator it( head());
319             ++it ;  // skip dummy head
320             return it;
321         }
322
323         /// Returns an const iterator that addresses the location succeeding the last element in a list
324         const_iterator end() const
325         {
326             return const_iterator( tail());
327         }
328         /// Returns an const iterator that addresses the location succeeding the last element in a list
329         const_iterator cend() const
330         {
331             return const_iterator( tail());
332         }
333     //@}
334
335     protected:
336         //@cond
337         iterator node_to_iterator( node_type * pNode )
338         {
339             if ( pNode )
340                 return iterator( *pNode );
341             return end();
342         }
343         //@endcond
344
345     public:
346         /// Default constructor
347         LazyKVList()
348         {}
349
350         //@cond
351         template <typename Stat, typename = std::enable_if<std::is_same<stat, lazy_list::wrapped_stat<Stat>>::value >>
352         explicit LazyKVList( Stat& st )
353             : base_class( st )
354         {}
355         //@endcond
356
357         /// Desctructor clears the list
358         ~LazyKVList()
359         {
360             clear();
361         }
362
363         /// Inserts new node with key and default value
364         /**
365             The function creates a node with \p key and default value, and then inserts the node created into the list.
366
367             Preconditions:
368             - The \ref key_type should be constructible from value of type \p K.
369                 In trivial case, \p K is equal to \ref key_type.
370             - The \ref mapped_type should be default-constructible.
371
372             Returns an iterator pointed to inserted value, or \p end() if inserting is failed
373         */
374         template <typename K>
375         iterator insert( const K& key )
376         {
377             return node_to_iterator( insert_at( head(), key ));
378         }
379
380         /// Inserts new node with a key and a value
381         /**
382             The function creates a node with \p key and value \p val, and then inserts the node created into the list.
383
384             Preconditions:
385             - The \ref key_type should be constructible from \p key of type \p K.
386             - The \ref mapped_type should be constructible from \p val of type \p V.
387
388             Returns an iterator pointed to inserted value, or \p end() if inserting is failed
389         */
390         template <typename K, typename V>
391         iterator insert( const K& key, const V& val )
392         {
393             // We cannot use insert with functor here
394             // because we cannot lock inserted node for updating
395             // Therefore, we use separate function
396             return node_to_iterator( insert_at( head(), key, val ));
397         }
398
399         /// Inserts new node and initialize it by a functor
400         /**
401             This function inserts new node with key \p key and if inserting is successful then it calls
402             \p func functor with signature
403             \code void func( value_type& item ) ; endcode
404             or
405             \code
406             struct functor {
407                 void operator()( value_type& item );
408             };
409             \endcode
410
411             The argument \p item of user-defined functor \p func is the reference
412             to the list's item inserted. <tt>item.second</tt> is a reference to item's value that may be changed.
413             The user-defined functor is called only if the inserting is successful.
414
415             The key_type should be constructible from value of type \p K.
416
417             The function allows to split creating of new item into two part:
418             - create item from \p key;
419             - insert new item into the list;
420             - if inserting is successful, initialize the value of item by calling \p f functor
421
422             This can be useful if complete initialization of object of \p mapped_type is heavyweight and
423             it is preferable that the initialization should be completed only if inserting is successful.
424
425             Returns an iterator pointed to inserted value, or \p end() if inserting is failed
426         */
427         template <typename K, typename Func>
428         iterator insert_with( const K& key, Func func )
429         {
430             return node_to_iterator( insert_with_at( head(), key, func ));
431         }
432
433         /// Updates the item
434         /**
435             If \p key is not in the list and \p bAllowInsert is \p true,
436
437             the function inserts a new item.
438             Otherwise, the function returns an iterator pointing to the item found.
439
440             Returns <tt> std::pair<iterator, bool>  </tt> where \p first is an iterator pointing to
441             item found or inserted, \p second is true if new item has been added or \p false if the item
442             already is in the list.
443         */
444         template <typename K>
445         std::pair<iterator, bool> update( const K& key, bool bAllowInsert = true )
446         {
447             std::pair< node_type *, bool > ret = update_at( head(), key, bAllowInsert );
448             return std::make_pair( node_to_iterator( ret.first ), ret.second );
449         }
450         //@cond
451         template <typename K>
452         CDS_DEPRECATED("ensure() is deprecated, use update()")
453         std::pair<iterator, bool> ensure( const K& key )
454         {
455             return update( key, true );
456         }
457         //@endcond
458
459         /// Inserts data of type \ref mapped_type constructed with <tt>std::forward<Args>(args)...</tt>
460         /**
461             Returns an iterator pointed to inserted value, or \p end() if inserting is failed
462         */
463         template <typename... Args>
464         iterator emplace( Args&&... args )
465         {
466             return node_to_iterator( emplace_at( head(), std::forward<Args>(args)... ));
467         }
468
469         /// Checks whether the list contains \p key
470         /**
471             The function searches the item with key equal to \p key
472             and returns an iterator pointed to item found if the key is found,
473             and \ref end() otherwise
474         */
475         template <typename Q>
476         iterator contains( Q const& key )
477         {
478             return node_to_iterator( find_at( head(), key, intrusive_key_comparator()));
479         }
480         //@cond
481         template <typename Q>
482         CDS_DEPRECATED("deprecated, use contains()")
483         iterator find( Q const& key )
484         {
485             return contains( key );
486         }
487         //@endcond
488
489         /// Checks whether the map contains \p key using \p pred predicate for searching (ordered list version)
490         /**
491             The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
492             \p Less functor has the interface like \p std::less.
493             \p Less must imply the same element order as the comparator used for building the list.
494         */
495         template <typename Q, typename Less, bool Sort = c_bSort>
496         typename std::enable_if<Sort, iterator>::type contains( Q const& key, Less pred )
497         {
498             CDS_UNUSED( pred );
499             return node_to_iterator( find_at( head(), key, typename maker::template less_wrapper<Less>::type()));
500         }
501         //@cond
502         template <typename Q, typename Less, bool Sort = c_bSort>
503         CDS_DEPRECATED("deprecated, use contains()")
504         typename std::enable_if<Sort, iterator>::type find_with( Q const& key, Less pred )
505         {
506             return contains( key, pred );
507         }
508         //@endcond
509
510         /// Finds the key \p val using \p equal predicate for searching (unordered list version)
511         /**
512             The function is an analog of <tt>contains( key )</tt> but \p equal is used for key comparing.
513             \p Equal functor has the interface like \p std::equal_to.
514         */
515         template <typename Q, typename Equal, bool Sort = c_bSort>
516         typename std::enable_if<!Sort, iterator>::type contains( Q const& key, Equal equal )
517         {
518             CDS_UNUSED( equal );
519             return node_to_iterator( find_at( head(), key, typename maker::template equal_to_wrapper<Equal>::type()));
520         }
521         //@cond
522         template <typename Q, typename Equal, bool Sort = c_bSort>
523         CDS_DEPRECATED("deprecated, use contains()")
524         typename std::enable_if<!Sort, iterator>::type find_with( Q const& key, Equal equal )
525         {
526             return contains( key, equal );
527         }
528         //@endcond
529
530         /// Check if the list is empty
531         bool empty() const
532         {
533             return base_class::empty();
534         }
535
536         /// Returns list's item count
537         /**
538             The value returned depends on opt::item_counter option. For atomicity::empty_item_counter,
539             this function always returns 0.
540
541             @note Even if you use real item counter and it returns 0, this fact is not mean that the list
542             is empty. To check list emptyness use \ref empty() method.
543         */
544         size_t size() const
545         {
546             return base_class::size();
547         }
548
549         /// Returns const reference to internal statistics
550         stat const& statistics() const
551         {
552             return base_class::statistics();
553         }
554
555         /// Clears the list
556         /**
557             Post-condition: the list is empty
558         */
559         void clear()
560         {
561             base_class::clear();
562         }
563
564     protected:
565         //@cond
566         node_type * insert_node_at( head_type& refHead, node_type * pNode )
567         {
568             assert( pNode != nullptr );
569             scoped_node_ptr p( pNode );
570             if ( base_class::insert_at( &refHead, *p ))
571                 return p.release();
572
573             return nullptr;
574         }
575
576         template <typename K>
577         node_type * insert_at( head_type& refHead, const K& key )
578         {
579             return insert_node_at( refHead, alloc_node( key ));
580         }
581
582         template <typename K, typename V>
583         node_type * insert_at( head_type& refHead, const K& key, const V& val )
584         {
585             return insert_node_at( refHead, alloc_node( key, val ));
586         }
587
588         template <typename K, typename Func>
589         node_type * insert_with_at( head_type& refHead, const K& key, Func f )
590         {
591             scoped_node_ptr pNode( alloc_node( key ));
592
593             if ( base_class::insert_at( &refHead, *pNode )) {
594                 f( pNode->m_Data );
595                 return pNode.release();
596             }
597
598             return nullptr;
599         }
600
601
602         template <typename K>
603         std::pair< node_type *, bool > update_at( head_type& refHead, const K& key, bool bAllowInsert )
604         {
605             scoped_node_ptr pNode( alloc_node( key ));
606             node_type * pItemFound = nullptr;
607
608             std::pair<bool, bool> ret = base_class::update_at( &refHead, *pNode,
609                 [&pItemFound](bool, node_type& item, node_type&){ pItemFound = &item; },
610                 bAllowInsert );
611
612             if ( ret.second )
613                 pNode.release();
614
615             return std::make_pair( pItemFound, ret.second );
616         }
617
618         template <typename... Args>
619         node_type * emplace_at( head_type& refHead, Args&&... args )
620         {
621             return insert_node_at( refHead, alloc_node( std::forward<Args>(args)... ));
622         }
623
624         template <typename K, typename Compare>
625         node_type * find_at( head_type& refHead, const K& key, Compare cmp )
626         {
627             return base_class::find_at( &refHead, key, cmp );
628         }
629
630         /*
631         template <typename K, typenam Compare, typename Func>
632         bool find_at( head_type& refHead, K& key, Compare cmp, Func f )
633         {
634             return base_class::find_at( &refHead, key, cmp, [&f]( node_type& node, K const& ){ f( node.m_Data ); });
635         }
636         */
637         //@endcond
638     };
639
640 }} // namespace cds::container
641
642 #endif // #ifndef CDSLIB_CONTAINER_LAZY_KVLIST_NOGC_H