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