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