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