6bd64468dd95c7c6441d5a3e9955048d93a1d4c4
[libcds.git] / cds / container / impl / lazy_kvlist.h
1 //$$CDS-header$$
2
3 #ifndef __CDS_CONTAINER_IMPL_LAZY_KVLIST_H
4 #define __CDS_CONTAINER_IMPL_LAZY_KVLIST_H
5
6 #include <memory>
7 #include <functional>   // ref
8 #include <cds/container/details/guarded_ptr_cast.h>
9
10 namespace cds { namespace container {
11
12     /// Lazy ordered list (key-value pair)
13     /** @ingroup cds_nonintrusive_list
14         \anchor cds_nonintrusive_LazyKVList_gc
15
16         This is key-value variation of non-intrusive LazyList.
17         Like standard container, this implementation split a value stored into two part -
18         constant key and alterable value.
19
20         Usually, ordered single-linked list is used as a building block for the hash table implementation.
21         The complexity of searching is <tt>O(N)</tt>.
22
23         Template arguments:
24         - \p GC - garbage collector used
25         - \p Key - key type of an item stored in the list. It should be copy-constructible
26         - \p Value - value type stored in the list
27         - \p Traits - type traits, default is lazy_list::type_traits
28
29         It is possible to declare option-based list with cds::container::lazy_list::make_traits metafunction istead of \p Traits template
30         argument. For example, the following traits-based declaration of gc::HP lazy list
31         \code
32         #include <cds/container/lazy_kvlist_hp.h>
33         // Declare comparator for the item
34         struct my_compare {
35             int operator ()( int i1, int i2 )
36             {
37                 return i1 - i2;
38             }
39         };
40
41         // Declare type_traits
42         struct my_traits: public cds::container::lazy_list::type_traits
43         {
44             typedef my_compare compare;
45         };
46
47         // Declare traits-based list
48         typedef cds::container::LazyKVList< cds::gc::HP, int, int, my_traits >     traits_based_list;
49         \endcode
50
51         is equivalent for the following option-based list
52         \code
53         #include <cds/container/lazy_kvlist_hp.h>
54
55         // my_compare is the same
56
57         // Declare option-based list
58         typedef cds::container::LazyKVList< cds::gc::HP, int, int,
59             typename cds::container::lazy_list::make_traits<
60                 cds::container::opt::compare< my_compare >     // item comparator option
61             >::type
62         >     option_based_list;
63         \endcode
64
65         Template argument list \p Options of cds::container::lazy_list::make_traits metafunction are:
66         - opt::compare - key comparison functor. No default functor is provided.
67             If the option is not specified, the opt::less is used.
68         - opt::less - specifies binary predicate used for key comparison. Default is \p std::less<T>.
69         - opt::back_off - back-off strategy used. If the option is not specified, the cds::backoff::empty is used.
70         - opt::item_counter - the type of item counting feature. Default is \ref atomicity::empty_item_counter that is no item counting.
71         - opt::allocator - the allocator used for creating and freeing list's item. Default is \ref CDS_DEFAULT_ALLOCATOR macro.
72         - opt::memory_model - C++ memory ordering model. Can be opt::v::relaxed_ordering (relaxed memory model, the default)
73             or opt::v::sequential_consistent (sequentially consisnent memory model).
74
75         \par Usage
76         There are different specializations of this template for each garbage collecting schema used.
77         You should include appropriate .h-file depending on GC you are using:
78         - for gc::HP: \code #include <cds/container/lazy_kvlist_hp.h> \endcode
79         - for gc::PTB: \code #include <cds/container/lazy_kvlist_ptb.h> \endcode
80         - for gc::HRC: \code #include <cds/container/lazy_kvlist_hrc.h> \endcode
81         - for \ref cds_urcu_desc "RCU": \code #include <cds/container/lazy_kvlist_rcu.h> \endcode
82         - for gc::nogc: \code #include <cds/container/lazy_kvlist_nogc.h> \endcode
83     */
84     template <
85         typename GC,
86         typename Key,
87         typename Value,
88 #ifdef CDS_DOXYGEN_INVOKED
89         typename Traits = lazy_list::type_traits
90 #else
91         typename Traits
92 #endif
93     >
94     class LazyKVList:
95 #ifdef CDS_DOXYGEN_INVOKED
96         protected intrusive::LazyList< GC, implementation_defined, Traits >
97 #else
98         protected details::make_lazy_kvlist< GC, Key, Value, Traits >::type
99 #endif
100     {
101         //@cond
102         typedef details::make_lazy_kvlist< GC, Key, Value, Traits > options;
103         typedef typename options::type  base_class;
104         //@endcond
105
106     public:
107 #ifdef CDS_DOXYGEN_INVOKED
108         typedef Key                                 key_type        ;   ///< Key type
109         typedef Value                               mapped_type     ;   ///< Type of value stored in the list
110         typedef std::pair<key_type const, mapped_type> value_type   ;   ///< key/value pair stored in the list
111 #else
112         typedef typename options::key_type          key_type;
113         typedef typename options::value_type        mapped_type;
114         typedef typename options::pair_type         value_type;
115 #endif
116
117         typedef typename base_class::gc             gc              ;   ///< Garbage collector used
118         typedef typename base_class::back_off       back_off        ;   ///< Back-off strategy used
119         typedef typename options::allocator_type    allocator_type  ;   ///< Allocator type used for allocate/deallocate the nodes
120         typedef typename base_class::item_counter   item_counter    ;   ///< Item counting policy used
121         typedef typename options::key_comparator    key_comparator  ;   ///< key comparison functor
122         typedef typename base_class::memory_model   memory_model    ;   ///< Memory ordering. See cds::opt::memory_model option
123
124     protected:
125         //@cond
126         typedef typename base_class::value_type     node_type;
127         typedef typename options::cxx_allocator     cxx_allocator;
128         typedef typename options::node_deallocator  node_deallocator;
129         typedef typename options::type_traits::compare  intrusive_key_comparator;
130
131         typedef typename base_class::node_type      head_type;
132         //@endcond
133
134     public:
135         /// Guarded pointer
136         typedef cds::gc::guarded_ptr< gc, node_type, value_type, details::guarded_ptr_cast_map<node_type, value_type> > guarded_ptr;
137
138     protected:
139         //@cond
140         template <typename K>
141         static node_type * alloc_node(const K& key)
142         {
143             return cxx_allocator().New( key );
144         }
145
146         template <typename K, typename V>
147         static node_type * alloc_node( const K& key, const V& val )
148         {
149             return cxx_allocator().New( key, val );
150         }
151
152         template <typename... Args>
153         static node_type * alloc_node( Args&&... args )
154         {
155             return cxx_allocator().MoveNew( std::forward<Args>(args)... );
156         }
157
158         static void free_node( node_type * pNode )
159         {
160             cxx_allocator().Delete( pNode );
161         }
162
163         struct node_disposer {
164             void operator()( node_type * pNode )
165             {
166                 free_node( pNode );
167             }
168         };
169         typedef std::unique_ptr< node_type, node_disposer >     scoped_node_ptr;
170
171         head_type& head()
172         {
173             return *base_class::head();
174         }
175
176         head_type const& head() const
177         {
178             return *base_class::head();
179         }
180
181         head_type& tail()
182         {
183             return *base_class::tail();
184         }
185
186         head_type const& tail() const
187         {
188             return *base_class::tail();
189         }
190
191         //@endcond
192
193     protected:
194         //@cond
195         template <bool IsConst>
196         class iterator_type: protected base_class::template iterator_type<IsConst>
197         {
198             typedef typename base_class::template iterator_type<IsConst>    iterator_base;
199
200             iterator_type( head_type const& pNode )
201                 : iterator_base( const_cast<head_type *>(&pNode) )
202             {}
203             iterator_type( head_type const * pNode )
204                 : iterator_base( const_cast<head_type *>(pNode) )
205             {}
206
207             friend class LazyKVList;
208
209         public:
210             typedef typename cds::details::make_const_type<mapped_type, IsConst>::reference  value_ref;
211             typedef typename cds::details::make_const_type<mapped_type, IsConst>::pointer    value_ptr;
212
213             typedef typename cds::details::make_const_type<value_type,  IsConst>::reference  pair_ref;
214             typedef typename cds::details::make_const_type<value_type,  IsConst>::pointer    pair_ptr;
215
216             iterator_type()
217             {}
218
219             iterator_type( iterator_type const& src )
220                 : iterator_base( src )
221             {}
222
223             key_type const& key() const
224             {
225                 typename iterator_base::value_ptr p = iterator_base::operator ->();
226                 assert( p != nullptr );
227                 return p->m_Data.first;
228             }
229
230             value_ref val() const
231             {
232                 typename iterator_base::value_ptr p = iterator_base::operator ->();
233                 assert( p != nullptr );
234                 return p->m_Data.second;
235             }
236
237             pair_ptr operator ->() const
238             {
239                 typename iterator_base::value_ptr p = iterator_base::operator ->();
240                 return p ? &(p->m_Data) : nullptr;
241             }
242
243             pair_ref operator *() const
244             {
245                 typename iterator_base::value_ref p = iterator_base::operator *();
246                 return p.m_Data;
247             }
248
249             /// Pre-increment
250             iterator_type& operator ++()
251             {
252                 iterator_base::operator ++();
253                 return *this;
254             }
255
256             template <bool C>
257             bool operator ==(iterator_type<C> const& i ) const
258             {
259                 return iterator_base::operator ==(i);
260             }
261             template <bool C>
262             bool operator !=(iterator_type<C> const& i ) const
263             {
264                 return iterator_base::operator !=(i);
265             }
266         };
267         //@endcond
268
269     public:
270         /// Forward iterator
271         /**
272             The forward iterator for lazy list has some features:
273             - it has no post-increment operator
274             - to protect the value, the iterator contains a GC-specific guard + another guard is required locally for increment operator.
275               For some GC (gc::HP, gc::HRC), a guard is limited resource per thread, so an exception (or assertion) "no free guard"
276               may be thrown if a limit of guard count per thread is exceeded.
277             - The iterator cannot be moved across thread boundary since it contains GC's guard that is thread-private GC data.
278             - Iterator ensures thread-safety even if you delete the item that iterator points to. However, in case of concurrent
279               deleting operations it is no guarantee that you iterate all item in the list.
280
281             Therefore, the use of iterators in concurrent environment is not good idea. Use the iterator on the concurrent container
282             for debug purpose only.
283
284             The iterator interface to access item data:
285             - <tt> operator -> </tt> - returns a pointer to \ref value_type for iterator
286             - <tt> operator *</tt> - returns a reference (a const reference for \p const_iterator) to \ref value_type for iterator
287             - <tt> const key_type& key() </tt> - returns a key reference for iterator
288             - <tt> mapped_type& val() </tt> - retuns a value reference for iterator (const reference for \p const_iterator)
289
290             For both functions the iterator should not be equal to <tt> end() </tt>
291         */
292         typedef iterator_type<false>    iterator;
293
294         /// Const forward iterator
295         /**
296             For iterator's features and requirements see \ref iterator
297         */
298         typedef iterator_type<true>     const_iterator;
299
300         /// Returns a forward iterator addressing the first element in a list
301         /**
302             For empty list \code begin() == end() \endcode
303         */
304         iterator begin()
305         {
306             iterator it( head() );
307             ++it ;  // skip dummy head
308             return it;
309         }
310
311         /// Returns an iterator that addresses the location succeeding the last element in a list
312         /**
313             Do not use the value returned by <tt>end</tt> function to access any item.
314             Internally, <tt>end</tt> returning value equals to \p nullptr.
315
316             The returned value can be used only to control reaching the end of the list.
317             For empty list \code begin() == end() \endcode
318         */
319         iterator end()
320         {
321             return iterator( tail() );
322         }
323
324         /// Returns a forward const iterator addressing the first element in a list
325         //@{
326         const_iterator begin() const
327         {
328             const_iterator it( head() );
329             ++it;   // skip dummy head
330             return it;
331         }
332         const_iterator cbegin()
333         {
334             const_iterator it( head() );
335             ++it;   // skip dummy head
336             return it;
337         }
338         //@}
339
340         /// Returns an const iterator that addresses the location succeeding the last element in a list
341         //@{
342         const_iterator end() const
343         {
344             return const_iterator( tail());
345         }
346         const_iterator cend()
347         {
348             return const_iterator( tail());
349         }
350         //@}
351
352     public:
353         /// Default constructor
354         /**
355             Initializes empty list
356         */
357         LazyKVList()
358         {}
359
360         /// List destructor
361         /**
362             Clears the list
363         */
364         ~LazyKVList()
365         {
366             clear();
367         }
368
369         /// Inserts new node with key and default value
370         /**
371             The function creates a node with \p key and default value, and then inserts the node created into the list.
372
373             Preconditions:
374             - The \ref key_type should be constructible from value of type \p K.
375                 In trivial case, \p K is equal to \ref key_type.
376             - The \ref mapped_type should be default-constructible.
377
378             Returns \p true if inserting successful, \p false otherwise.
379         */
380         template <typename K>
381         bool insert( const K& key )
382         {
383             return insert_at( head(), key );
384         }
385
386         /// Inserts new node with a key and a value
387         /**
388             The function creates a node with \p key and value \p val, and then inserts the node created into the list.
389
390             Preconditions:
391             - The \ref key_type should be constructible from \p key of type \p K.
392             - The \ref mapped_type should be constructible from \p val of type \p V.
393
394             Returns \p true if inserting successful, \p false otherwise.
395         */
396         template <typename K, typename V>
397         bool insert( const K& key, const V& val )
398         {
399             // We cannot use insert with functor here
400             // because we cannot lock inserted node for updating
401             // Therefore, we use separate function
402             return insert_at( head(), key, val );
403         }
404
405         /// Inserts new node and initializes it by a functor
406         /**
407             This function inserts new node with key \p key and if inserting is successful then it calls
408             \p func functor with signature
409             \code
410                 struct functor {
411                     void operator()( value_type& item );
412                 };
413             \endcode
414
415             The argument \p item of user-defined functor \p func is the reference
416             to the list's item inserted. <tt>item.second</tt> is a reference to item's value that may be changed.
417             User-defined functor \p func should guarantee that during changing item's value no any other changes
418             could be made on this list's item by concurrent threads.
419             The user-defined functor can be passed by reference using \p std::ref
420             and it is called only if inserting is successful.
421
422             The key_type should be constructible from value of type \p K.
423
424             The function allows to split creating of new item into two part:
425             - create item from \p key;
426             - insert new item into the list;
427             - if inserting is successful, initialize the value of item by calling \p func functor
428
429             This can be useful if complete initialization of object of \p mapped_type is heavyweight and
430             it is preferable that the initialization should be completed only if inserting is successful.
431         */
432         template <typename K, typename Func>
433         bool insert_key( const K& key, Func func )
434         {
435             return insert_key_at( head(), key, func );
436         }
437
438         /// Inserts data of type \ref mapped_type constructed with <tt>std::forward<Args>(args)...</tt>
439         /**
440             Returns \p true if inserting successful, \p false otherwise.
441         */
442         template <typename... Args>
443         bool emplace( Args&&... args )
444         {
445             return emplace_at( head(), std::forward<Args>(args)... );
446         }
447
448         /// Ensures that the \p key exists in the list
449         /**
450             The operation performs inserting or changing data with lock-free manner.
451
452             If the \p key not found in the list, then the new item created from \p key
453             is inserted into the list (note that in this case the \ref key_type should be
454             copy-constructible from type \p K).
455             Otherwise, the functor \p func is called with item found.
456             The functor \p Func may be a function with signature:
457             \code
458                 void func( bool bNew, value_type& item );
459             \endcode
460             or a functor:
461             \code
462                 struct my_functor {
463                     void operator()( bool bNew, value_type& item );
464                 };
465             \endcode
466
467             with arguments:
468             - \p bNew - \p true if the item has been inserted, \p false otherwise
469             - \p item - item of the list
470
471             The functor may change any fields of the \p item.second that is \ref mapped_type;
472             however, \p func must guarantee that during changing no any other modifications
473             could be made on this item by concurrent threads.
474
475             You may pass \p func argument by reference using \p std::ref.
476
477             Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
478             \p second is true if new item has been added or \p false if the item with \p key
479             already is in the list.
480         */
481         template <typename K, typename Func>
482         std::pair<bool, bool> ensure( const K& key, Func f )
483         {
484             return ensure_at( head(), key, f );
485         }
486
487         /// Deletes \p key from the list
488         /** \anchor cds_nonintrusive_LazyKVList_hp_erase_val
489
490             Returns \p true if \p key is found and has been deleted, \p false otherwise
491         */
492         template <typename K>
493         bool erase( K const& key )
494         {
495             return erase_at( head(), key, intrusive_key_comparator() );
496         }
497
498         /// Deletes the item from the list using \p pred predicate for searching
499         /**
500             The function is an analog of \ref cds_nonintrusive_LazyKVList_hp_erase_val "erase(K const&)"
501             but \p pred is used for key comparing.
502             \p Less functor has the interface like \p std::less.
503             \p pred must imply the same element order as the comparator used for building the list.
504         */
505         template <typename K, typename Less>
506         bool erase_with( K const& key, Less pred )
507         {
508             return erase_at( head(), key, typename options::template less_wrapper<Less>::type() );
509         }
510
511         /// Deletes \p key from the list
512         /** \anchor cds_nonintrusive_LazyKVList_hp_erase_func
513             The function searches an item with key \p key, calls \p f functor with item found
514             and deletes it. If \p key is not found, the functor is not called.
515
516             The functor \p Func interface:
517             \code
518             struct extractor {
519                 void operator()(value_type& val) { ... }
520             };
521             \endcode
522             The functor may be passed by reference with <tt>boost:ref</tt>
523
524             Returns \p true if key is found and deleted, \p false otherwise
525         */
526         template <typename K, typename Func>
527         bool erase( K const& key, Func f )
528         {
529             return erase_at( head(), key, intrusive_key_comparator(), f );
530         }
531
532         /// Deletes the item from the list using \p pred predicate for searching
533         /**
534             The function is an analog of \ref cds_nonintrusive_LazyKVList_hp_erase_func "erase(K const&, Func)"
535             but \p pred is used for key comparing.
536             \p Less functor has the interface like \p std::less.
537             \p pred must imply the same element order as the comparator used for building the list.
538         */
539         template <typename K, typename Less, typename Func>
540         bool erase_with( K const& key, Less pred, Func f )
541         {
542             return erase_at( head(), key, typename options::template less_wrapper<Less>::type(), f );
543         }
544
545         /// Extracts the item from the list with specified \p key
546         /** \anchor cds_nonintrusive_LazyKVList_hp_extract
547             The function searches an item with key equal to \p key,
548             unlinks it from the list, and returns it in \p dest parameter.
549             If the item with key equal to \p key is not found the function returns \p false.
550
551             Note the compare functor should accept a parameter of type \p K that can be not the same as \p key_type.
552
553             @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
554
555             Usage:
556             \code
557             typedef cds::container::LazyKVList< cds::gc::HP, int, foo, my_traits >  ord_list;
558             ord_list theList;
559             // ...
560             {
561                 ord_list::guarded_ptr gp;
562                 theList.extract( gp, 5 );
563                 // Deal with gp
564                 // ...
565
566                 // Destructor of gp releases internal HP guard and frees the item
567             }
568             \endcode
569         */
570         template <typename K>
571         bool extract( guarded_ptr& dest, K const& key )
572         {
573             return extract_at( head(), dest.guard(), key, intrusive_key_comparator() );
574         }
575
576         /// Extracts the item from the list with comparing functor \p pred
577         /**
578             The function is an analog of \ref cds_nonintrusive_LazyKVList_hp_extract "extract(guarded_ptr&, K const&)"
579             but \p pred predicate is used for key comparing.
580
581             \p Less functor has the semantics like \p std::less but should take arguments of type \ref key_type and \p K
582             in any order.
583             \p pred must imply the same element order as the comparator used for building the list.
584         */
585         template <typename K, typename Less>
586         bool extract_with( guarded_ptr& dest, K const& key, Less pred )
587         {
588             return extract_at( head(), dest.guard(), key, typename options::template less_wrapper<Less>::type() );
589         }
590
591         /// Finds the key \p key
592         /** \anchor cds_nonintrusive_LazyKVList_hp_find_val
593             The function searches the item with key equal to \p key
594             and returns \p true if it is found, and \p false otherwise
595         */
596         template <typename Q>
597         bool find( Q const& key )
598         {
599             return find_at( head(), key, intrusive_key_comparator() );
600         }
601
602         /// Finds the key \p val using \p pred predicate for searching
603         /**
604             The function is an analog of \ref cds_nonintrusive_LazyKVList_hp_find_val "find(Q const&)"
605             but \p pred is used for key comparing.
606             \p Less functor has the interface like \p std::less.
607             \p pred must imply the same element order as the comparator used for building the list.
608         */
609         template <typename Q, typename Less>
610         bool find_with( Q const& key, Less pred )
611         {
612             return find_at( head(), key, typename options::template less_wrapper<Less>::type() );
613         }
614
615         /// Finds the key \p key and performs an action with it
616         /** \anchor cds_nonintrusive_LazyKVList_hp_find_func
617             The function searches an item with key equal to \p key and calls the functor \p f for the item found.
618             The interface of \p Func functor is:
619             \code
620             struct functor {
621                 void operator()( value_type& item );
622             };
623             \endcode
624             where \p item is the item found.
625
626             You may pass \p f argument by reference using \p std::ref.
627
628             The functor may change <tt>item.second</tt> that is reference to value of node.
629             Note that the function is only guarantee that \p item cannot be deleted during functor is executing.
630             The function does not serialize simultaneous access to the list \p item. If such access is
631             possible you must provide your own synchronization schema to exclude unsafe item modifications.
632
633             The function returns \p true if \p key is found, \p false otherwise.
634         */
635         template <typename Q, typename Func>
636         bool find( Q const& key, Func f )
637         {
638             return find_at( head(), key, intrusive_key_comparator(), f );
639         }
640
641         /// Finds the key \p val using \p pred predicate for searching
642         /**
643             The function is an analog of \ref cds_nonintrusive_LazyKVList_hp_find_func "find(Q&, Func)"
644             but \p pred is used for key comparing.
645             \p Less functor has the interface like \p std::less.
646             \p pred must imply the same element order as the comparator used for building the list.
647         */
648         template <typename Q, typename Less, typename Func>
649         bool find_with( Q const& key, Less pred, Func f )
650         {
651             return find_at( head(), key, typename options::template less_wrapper<Less>::type(), f );
652         }
653
654         /// Finds \p key and return the item found
655         /** \anchor cds_nonintrusive_LazyKVList_hp_get
656             The function searches the item with key equal to \p key
657             and assigns the item found to guarded pointer \p ptr.
658             The function returns \p true if \p key is found, and \p false otherwise.
659             If \p key is not found the \p ptr parameter is not changed.
660
661             @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
662
663             Usage:
664             \code
665             typedef cds::container::LazyKVList< cds::gc::HP, int, foo, my_traits >  ord_list;
666             ord_list theList;
667             // ...
668             {
669                 ord_list::guarded_ptr gp;
670                 if ( theList.get( gp, 5 )) {
671                     // Deal with gp
672                     //...
673                 }
674                 // Destructor of guarded_ptr releases internal HP guard and frees the item
675             }
676             \endcode
677
678             Note the compare functor specified for class \p Traits template parameter
679             should accept a parameter of type \p K that can be not the same as \p key_type.
680         */
681         template <typename K>
682         bool get( guarded_ptr& ptr, K const& key )
683         {
684             return get_at( head(), ptr.guard(), key, intrusive_key_comparator() );
685         }
686
687         /// Finds the key \p val and return the item found
688         /**
689             The function is an analog of \ref cds_nonintrusive_LazyKVList_hp_get "get(guarded_ptr& ptr, K const&)"
690             but \p pred is used for comparing the keys.
691
692             \p Less functor has the semantics like \p std::less but should take arguments of type \ref key_type and \p K
693             in any order.
694             \p pred must imply the same element order as the comparator used for building the list.
695         */
696         template <typename K, typename Less>
697         bool get_with( guarded_ptr& ptr, K const& key, Less pred )
698         {
699             return get_at( head(), ptr.guard(), key, typename options::template less_wrapper<Less>::type() );
700         }
701
702         /// Checks if the list is empty
703         bool empty() const
704         {
705             return base_class::empty();
706         }
707
708         /// Returns list's item count
709         /**
710             The value returned depends on opt::item_counter option. For atomicity::empty_item_counter,
711             this function always returns 0.
712
713             <b>Warning</b>: even if you use real item counter and it returns 0, this fact is not mean that the list
714             is empty. To check list emptyness use \ref empty() method.
715         */
716         size_t size() const
717         {
718             return base_class::size();
719         }
720
721         /// Clears the list
722         /**
723             Post-condition: the list is empty
724         */
725         void clear()
726         {
727             base_class::clear();
728         }
729
730     protected:
731         //@cond
732         bool insert_node_at( head_type& refHead, node_type * pNode )
733         {
734             assert( pNode != nullptr );
735             scoped_node_ptr p( pNode );
736
737             if ( base_class::insert_at( &refHead, *p )) {
738                 p.release();
739                 return true;
740             }
741
742             return false;
743         }
744
745         template <typename K>
746         bool insert_at( head_type& refHead, const K& key )
747         {
748             return insert_node_at( refHead, alloc_node( key ));
749         }
750
751         template <typename K, typename V>
752         bool insert_at( head_type& refHead, const K& key, const V& val )
753         {
754             return insert_node_at( refHead, alloc_node( key, val ));
755         }
756
757         template <typename K, typename Func>
758         bool insert_key_at( head_type& refHead, const K& key, Func f )
759         {
760             scoped_node_ptr pNode( alloc_node( key ));
761
762             if ( base_class::insert_at( &refHead, *pNode, [&f](node_type& node){ f( node.m_Data ); } )) {
763                 pNode.release();
764                 return true;
765             }
766             return false;
767         }
768
769         template <typename... Args>
770         bool emplace_at( head_type& refHead, Args&&... args )
771         {
772             return insert_node_at( refHead, alloc_node( std::forward<Args>(args)... ));
773         }
774
775         template <typename K, typename Compare>
776         bool erase_at( head_type& refHead, K const& key, Compare cmp )
777         {
778             return base_class::erase_at( &refHead, key, cmp );
779         }
780
781         template <typename K, typename Compare, typename Func>
782         bool erase_at( head_type& refHead, K const& key, Compare cmp, Func f )
783         {
784             return base_class::erase_at( &refHead, key, cmp, [&f](node_type const & node){f( const_cast<value_type&>(node.m_Data)); });
785         }
786
787         template <typename K, typename Compare>
788         bool extract_at( head_type& refHead, typename gc::Guard& dest, K const& key, Compare cmp )
789         {
790             return base_class::extract_at( &refHead, dest, key, cmp );
791         }
792
793         template <typename K, typename Func>
794         std::pair<bool, bool> ensure_at( head_type& refHead, const K& key, Func f )
795         {
796             scoped_node_ptr pNode( alloc_node( key ));
797
798             std::pair<bool, bool> ret = base_class::ensure_at( &refHead, *pNode,
799                 [&f]( bool bNew, node_type& node, node_type& ){ f( bNew, node.m_Data ); });
800             if ( ret.first && ret.second )
801                 pNode.release();
802
803             return ret;
804         }
805
806         template <typename K, typename Compare>
807         bool find_at( head_type& refHead, K const& key, Compare cmp )
808         {
809             return base_class::find_at( &refHead, key, cmp );
810         }
811
812         template <typename K, typename Compare, typename Func>
813         bool find_at( head_type& refHead, K& key, Compare cmp, Func f )
814         {
815             return base_class::find_at( &refHead, key, cmp, [&f]( node_type& node, K& ){ f( node.m_Data ); });
816         }
817
818         template <typename K, typename Compare>
819         bool get_at( head_type& refHead, typename gc::Guard& guard, K const& key, Compare cmp )
820         {
821             return base_class::get_at( &refHead, guard, key, cmp );
822         }
823
824         //@endcond
825     };
826
827 }}  // namespace cds::container
828
829 #endif  // #ifndef __CDS_CONTAINER_IMPL_LAZY_KVLIST_H