5ef7d955cc03df0f4d37590cbdbdc7ce507e3e48
[libcds.git] / cds / container / split_list_set.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_SPLIT_LIST_SET_H
32 #define CDSLIB_CONTAINER_SPLIT_LIST_SET_H
33
34 #include <cds/intrusive/split_list.h>
35 #include <cds/container/details/make_split_list_set.h>
36
37 namespace cds { namespace container {
38
39     /// Split-ordered list set
40     /** @ingroup cds_nonintrusive_set
41         \anchor cds_nonintrusive_SplitListSet_hp
42
43         Hash table implementation based on split-ordered list algorithm discovered by Ori Shalev and Nir Shavit, see
44         - [2003] Ori Shalev, Nir Shavit "Split-Ordered Lists - Lock-free Resizable Hash Tables"
45         - [2008] Nir Shavit "The Art of Multiprocessor Programming"
46
47         See \p intrusive::SplitListSet for a brief description of the split-list algorithm.
48
49         Template parameters:
50         - \p GC - Garbage collector used
51         - \p T - type to be stored in the split-list.
52         - \p Traits - type traits, default is \p split_list::traits. Instead of declaring \p split_list::traits -based
53             struct you may apply option-based notation with \p split_list::make_traits metafunction.
54
55         There are the specializations:
56         - for \ref cds_urcu_desc "RCU" - declared in <tt>cd/container/split_list_set_rcu.h</tt>,
57             see \ref cds_nonintrusive_SplitListSet_rcu "SplitListSet<RCU>".
58         - for \ref cds::gc::nogc declared in <tt>cds/container/split_list_set_nogc.h</tt>,
59             see \ref cds_nonintrusive_SplitListSet_nogc "SplitListSet<gc::nogc>".
60
61         \par Usage
62
63         You should decide what garbage collector you want, and what ordered list you want to use as a base. Split-ordered list
64         is original data structure based on an ordered list.
65
66         Suppose, you want construct split-list set based on \p gc::DHP GC
67         and \p LazyList as ordered list implementation. So, you beginning your program with following include:
68         \code
69         #include <cds/container/lazy_list_dhp.h>
70         #include <cds/container/split_list_set.h>
71
72         namespace cc = cds::container;
73
74         // The data belonged to split-ordered list
75         sturuct foo {
76             int     nKey;   // key field
77             std::string strValue    ;   // value field
78         };
79         \endcode
80         The inclusion order is important: first, include header for ordered-list implementation (for this example, <tt>cds/container/lazy_list_dhp.h</tt>),
81         then the header for split-list set <tt>cds/container/split_list_set.h</tt>.
82
83         Now, you should declare traits for split-list set. The main parts of traits are a hash functor for the set and a comparing functor for ordered list.
84         Note that we define several function in <tt>foo_hash</tt> and <tt>foo_less</tt> functors for different argument types since we want call our \p %SplitListSet
85         object by the key of type <tt>int</tt> and by the value of type <tt>foo</tt>.
86
87         The second attention: instead of using \p %LazyList in \p %SplitListSet traits we use a tag \p cds::contaner::lazy_list_tag for the lazy list.
88         The split-list requires significant support from underlying ordered list class and it is not good idea to dive you
89         into deep implementation details of split-list and ordered list interrelations. The tag paradigm simplifies split-list interface.
90
91         \code
92         // foo hash functor
93         struct foo_hash {
94             size_t operator()( int key ) const { return std::hash( key ) ; }
95             size_t operator()( foo const& item ) const { return std::hash( item.nKey ) ; }
96         };
97
98         // foo comparator
99         struct foo_less {
100             bool operator()(int i, foo const& f ) const { return i < f.nKey ; }
101             bool operator()(foo const& f, int i ) const { return f.nKey < i ; }
102             bool operator()(foo const& f1, foo const& f2) const { return f1.nKey < f2.nKey; }
103         };
104
105         // SplitListSet traits
106         struct foo_set_traits: public cc::split_list::traits
107         {
108             typedef cc::lazy_list_tag   ordered_list; // what type of ordered list we want to use
109             typedef foo_hash            hash;         // hash functor for our data stored in split-list set
110
111             // Type traits for our LazyList class
112             struct ordered_list_traits: public cc::lazy_list::traits
113             {
114                 typedef foo_less less   ;   // use our foo_less as comparator to order list nodes
115             };
116         };
117         \endcode
118
119         Now you are ready to declare our set class based on \p %SplitListSet:
120         \code
121         typedef cc::SplitListSet< cds::gc::DHP, foo, foo_set_traits > foo_set;
122         \endcode
123
124         You may use the modern option-based declaration instead of classic traits-based one:
125         \code
126         typedef cc::SplitListSet<
127             cs::gc::DHP             // GC used
128             ,foo                    // type of data stored
129             ,cc::split_list::make_traits<      // metafunction to build split-list traits
130                 cc::split_list::ordered_list<cc::lazy_list_tag>  // tag for underlying ordered list implementation
131                 ,cc::opt::hash< foo_hash >               // hash functor
132                 ,cc::split_list::ordered_list_traits<    // ordered list traits desired
133                     cc::lazy_list::make_traits<          // metafunction to build lazy list traits
134                         cc::opt::less< foo_less >        // less-based compare functor
135                     >::type
136                 >
137             >::type
138         >  foo_set;
139         \endcode
140         In case of option-based declaration using split_list::make_traits metafunction
141         the struct \p foo_set_traits is not required.
142
143         Now, the set of type \p foo_set is ready to use in your program.
144
145         Note that in this example we show only mandatory \p traits parts, optional ones is the default and they are inherited
146         from \p cds::container::split_list::traits.
147         There are many other options for deep tuning the split-list and ordered-list containers.
148     */
149     template <
150         class GC,
151         class T,
152 #ifdef CDS_DOXYGEN_INVOKED
153         class Traits = split_list::traits
154 #else
155         class Traits
156 #endif
157     >
158     class SplitListSet:
159 #ifdef CDS_DOXYGEN_INVOKED
160         protected intrusive::SplitListSet<GC, typename Traits::ordered_list, Traits>
161 #else
162         protected details::make_split_list_set< GC, T, typename Traits::ordered_list, split_list::details::wrap_set_traits<T, Traits> >::type
163 #endif
164     {
165     protected:
166         //@cond
167         typedef details::make_split_list_set< GC, T, typename Traits::ordered_list, split_list::details::wrap_set_traits<T, Traits> > maker;
168         typedef typename maker::type  base_class;
169         //@endcond
170
171     public:
172         typedef GC      gc;         ///< Garbage collector
173         typedef T       value_type; ///< Type of vlue to be stored in split-list
174         typedef Traits  traits;     ///< \p Traits template argument
175         typedef typename maker::ordered_list ordered_list; ///< Underlying ordered list class
176         typedef typename base_class::key_comparator key_comparator; ///< key compare functor
177
178         /// Hash functor for \p %value_type and all its derivatives that you use
179         typedef typename base_class::hash         hash;
180         typedef typename base_class::item_counter item_counter; ///< Item counter type
181         typedef typename base_class::stat         stat; ///< Internal statistics
182
183     protected:
184         //@cond
185         typedef typename maker::cxx_node_allocator    cxx_node_allocator;
186         typedef typename maker::node_type             node_type;
187         //@endcond
188
189     public:
190         /// Guarded pointer
191         typedef typename gc::template guarded_ptr< node_type, value_type, details::guarded_ptr_cast_set<node_type, value_type> > guarded_ptr;
192
193     protected:
194         //@cond
195         template <typename Q>
196         static node_type * alloc_node(Q const& v )
197         {
198             return cxx_node_allocator().New( v );
199         }
200
201         template <typename... Args>
202         static node_type * alloc_node( Args&&... args )
203         {
204             return cxx_node_allocator().MoveNew( std::forward<Args>( args )... );
205         }
206
207         static void free_node( node_type * pNode )
208         {
209             cxx_node_allocator().Delete( pNode );
210         }
211
212         template <typename Q, typename Func>
213         bool find_( Q& val, Func f )
214         {
215             return base_class::find( val, [&f]( node_type& item, Q& val ) { f(item.m_Value, val) ; } );
216         }
217
218         template <typename Q, typename Less, typename Func>
219         bool find_with_( Q& val, Less pred, Func f )
220         {
221             CDS_UNUSED( pred );
222             return base_class::find_with( val, typename maker::template predicate_wrapper<Less>::type(),
223                 [&f]( node_type& item, Q& val ) { f(item.m_Value, val) ; } );
224         }
225
226         struct node_disposer {
227             void operator()( node_type * pNode )
228             {
229                 free_node( pNode );
230             }
231         };
232         typedef std::unique_ptr< node_type, node_disposer >     scoped_node_ptr;
233
234         bool insert_node( node_type * pNode )
235         {
236             assert( pNode != nullptr );
237             scoped_node_ptr p(pNode);
238
239             if ( base_class::insert( *pNode )) {
240                 p.release();
241                 return true;
242             }
243             return false;
244         }
245
246         //@endcond
247
248     protected:
249         /// Forward iterator
250         /**
251             \p IsConst - constness boolean flag
252
253             The forward iterator for a split-list has the following features:
254             - it has no post-increment operator
255             - it depends on underlying ordered list iterator
256             - The iterator object cannot be moved across thread boundary since it contains GC's guard that is thread-private GC data.
257             - Iterator ensures thread-safety even if you delete the item that iterator points to. However, in case of concurrent
258               deleting operations it is no guarantee that you iterate all item in the split-list.
259
260             Therefore, the use of iterators in concurrent environment is not good idea. Use it for debug purpose only.
261         */
262         template <bool IsConst>
263         class iterator_type: protected base_class::template iterator_type<IsConst>
264         {
265             //@cond
266             typedef typename base_class::template iterator_type<IsConst> iterator_base_class;
267             friend class SplitListSet;
268             //@endcond
269         public:
270             /// Value pointer type (const for const iterator)
271             typedef typename cds::details::make_const_type<value_type, IsConst>::pointer   value_ptr;
272             /// Value reference type (const for const iterator)
273             typedef typename cds::details::make_const_type<value_type, IsConst>::reference value_ref;
274
275         public:
276             /// Default ctor
277             iterator_type()
278             {}
279
280             /// Copy ctor
281             iterator_type( iterator_type const& src )
282                 : iterator_base_class( src )
283             {}
284
285         protected:
286             //@cond
287             explicit iterator_type( iterator_base_class const& src )
288                 : iterator_base_class( src )
289             {}
290             //@endcond
291
292         public:
293             /// Dereference operator
294             value_ptr operator ->() const
295             {
296                 return &(iterator_base_class::operator->()->m_Value);
297             }
298
299             /// Dereference operator
300             value_ref operator *() const
301             {
302                 return iterator_base_class::operator*().m_Value;
303             }
304
305             /// Pre-increment
306             iterator_type& operator ++()
307             {
308                 iterator_base_class::operator++();
309                 return *this;
310             }
311
312             /// Assignment operator
313             iterator_type& operator = (iterator_type const& src)
314             {
315                 iterator_base_class::operator=(src);
316                 return *this;
317             }
318
319             /// Equality operator
320             template <bool C>
321             bool operator ==(iterator_type<C> const& i ) const
322             {
323                 return iterator_base_class::operator==(i);
324             }
325
326             /// Equality operator
327             template <bool C>
328             bool operator !=(iterator_type<C> const& i ) const
329             {
330                 return iterator_base_class::operator!=(i);
331             }
332         };
333
334     public:
335         /// Initializes split-ordered list of default capacity
336         /**
337             The default capacity is defined in bucket table constructor.
338             See \p intrusive::split_list::expandable_bucket_table, \p intrusive::split_list::static_bucket_table
339             which selects by \p split_list::dynamic_bucket_table option.
340         */
341         SplitListSet()
342             : base_class()
343         {}
344
345         /// Initializes split-ordered list
346         SplitListSet(
347             size_t nItemCount           ///< estimated average of item count
348             , size_t nLoadFactor = 1    ///< the load factor - average item count per bucket. Small integer up to 8, default is 1.
349             )
350             : base_class( nItemCount, nLoadFactor )
351         {}
352
353     public:
354         /// Forward iterator
355         typedef iterator_type<false>  iterator;
356
357         /// Const forward iterator
358         typedef iterator_type<true>    const_iterator;
359
360         /// Returns a forward iterator addressing the first element in a set
361         /**
362             For empty set \code begin() == end() \endcode
363         */
364         iterator begin()
365         {
366             return iterator( base_class::begin());
367         }
368
369         /// Returns an iterator that addresses the location succeeding the last element in a set
370         /**
371             Do not use the value returned by <tt>end</tt> function to access any item.
372             The returned value can be used only to control reaching the end of the set.
373             For empty set \code begin() == end() \endcode
374         */
375         iterator end()
376         {
377             return iterator( base_class::end());
378         }
379
380         /// Returns a forward const iterator addressing the first element in a set
381         const_iterator begin() const
382         {
383             return cbegin();
384         }
385         /// Returns a forward const iterator addressing the first element in a set
386         const_iterator cbegin() const
387         {
388             return const_iterator( base_class::cbegin());
389         }
390
391         /// Returns an const iterator that addresses the location succeeding the last element in a set
392         const_iterator end() const
393         {
394             return cend();
395         }
396         /// Returns an const iterator that addresses the location succeeding the last element in a set
397         const_iterator cend() const
398         {
399             return const_iterator( base_class::cend());
400         }
401
402     public:
403         /// Inserts new node
404         /**
405             The function creates a node with copy of \p val value
406             and then inserts the node created into the set.
407
408             The type \p Q should contain as minimum the complete key for the node.
409             The object of \ref value_type should be constructible from a value of type \p Q.
410             In trivial case, \p Q is equal to \ref value_type.
411
412             Returns \p true if \p val is inserted into the set, \p false otherwise.
413         */
414         template <typename Q>
415         bool insert( Q const& val )
416         {
417             return insert_node( alloc_node( val ));
418         }
419
420         /// Inserts new node
421         /**
422             The function allows to split creating of new item into two part:
423             - create item with key only
424             - insert new item into the set
425             - if inserting is success, calls  \p f functor to initialize value-field of \p val.
426
427             The functor signature is:
428             \code
429                 void func( value_type& val );
430             \endcode
431             where \p val is the item inserted.
432
433             The user-defined functor is called only if the inserting is success.
434
435             @warning For \ref cds_intrusive_MichaelList_hp "MichaelList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
436             \ref cds_intrusive_LazyList_hp "LazyList" provides exclusive access to inserted item and does not require any node-level
437             synchronization.
438         */
439         template <typename Q, typename Func>
440         bool insert( Q const& val, Func f )
441         {
442             scoped_node_ptr pNode( alloc_node( val ));
443
444             if ( base_class::insert( *pNode, [&f](node_type& node) { f( node.m_Value ) ; } )) {
445                 pNode.release();
446                 return true;
447             }
448             return false;
449         }
450
451         /// Inserts data of type \p value_type created from \p args
452         /**
453             Returns \p true if inserting successful, \p false otherwise.
454         */
455         template <typename... Args>
456         bool emplace( Args&&... args )
457         {
458             return insert_node( alloc_node( std::forward<Args>(args)...));
459         }
460
461         /// Updates the node
462         /**
463             The operation performs inserting or changing data with lock-free manner.
464
465             If \p key is not found in the set, then \p key is inserted iff \p bAllowInsert is \p true.
466             Otherwise, the functor \p func is called with item found.
467
468             The functor signature is:
469             \code
470                 struct my_functor {
471                     void operator()( bool bNew, value_type& item, const Q& val );
472                 };
473             \endcode
474             with arguments:
475             - \p bNew - \p true if the item has been inserted, \p false otherwise
476             - \p item - item of the set
477             - \p val - argument \p val passed into the \p %update() function
478
479             The functor may change non-key fields of the \p item.
480
481             Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
482             \p second is true if new item has been added or \p false if the item with \p key
483             already is in the map.
484
485             @warning For \ref cds_intrusive_MichaelList_hp "MichaelList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
486             \ref cds_intrusive_LazyList_hp "LazyList" provides exclusive access to inserted item and does not require any node-level
487             synchronization.
488         */
489         template <typename Q, typename Func>
490         std::pair<bool, bool> update( Q const& val, Func func, bool bAllowInsert = true )
491         {
492             scoped_node_ptr pNode( alloc_node( val ));
493
494             std::pair<bool, bool> bRet = base_class::update( *pNode,
495                 [&func, &val]( bool bNew, node_type& item,  node_type const& /*val*/ ) {
496                     func( bNew, item.m_Value, val );
497                 }, bAllowInsert );
498
499             if ( bRet.first && bRet.second )
500                 pNode.release();
501             return bRet;
502         }
503         //@cond
504         template <typename Q, typename Func>
505         CDS_DEPRECATED("ensure() is deprecated, use update()")
506         std::pair<bool, bool> ensure( Q const& val, Func func )
507         {
508             return update( val, func, true );
509         }
510         //@endcond
511
512         /// Deletes \p key from the set
513         /** \anchor cds_nonintrusive_SplitListSet_erase_val
514
515             The item comparator should be able to compare the values of type \p value_type
516             and the type \p Q.
517
518             Return \p true if key is found and deleted, \p false otherwise
519         */
520         template <typename Q>
521         bool erase( Q const& key )
522         {
523             return base_class::erase( key );
524         }
525
526         /// Deletes the item from the set using \p pred predicate for searching
527         /**
528             The function is an analog of \ref cds_nonintrusive_SplitListSet_erase_val "erase(Q const&)"
529             but \p pred is used for key comparing.
530             \p Less functor has the interface like \p std::less.
531             \p Less must imply the same element order as the comparator used for building the set.
532         */
533         template <typename Q, typename Less>
534         bool erase_with( Q const& key, Less pred )
535         {
536             CDS_UNUSED( pred );
537             return base_class::erase_with( key, typename maker::template predicate_wrapper<Less>::type());
538         }
539
540         /// Deletes \p key from the set
541         /** \anchor cds_nonintrusive_SplitListSet_erase_func
542
543             The function searches an item with key \p key, calls \p f functor
544             and deletes the item. If \p key is not found, the functor is not called.
545
546             The functor \p Func interface:
547             \code
548             struct extractor {
549                 void operator()(value_type const& val);
550             };
551             \endcode
552
553             Since the key of split-list \p value_type is not explicitly specified,
554             template parameter \p Q defines the key type searching in the list.
555             The list item comparator should be able to compare the values of the type \p value_type
556             and the type \p Q.
557
558             Return \p true if key is found and deleted, \p false otherwise
559         */
560         template <typename Q, typename Func>
561         bool erase( Q const& key, Func f )
562         {
563             return base_class::erase( key, [&f](node_type& node) { f( node.m_Value ); } );
564         }
565
566         /// Deletes the item from the set using \p pred predicate for searching
567         /**
568             The function is an analog of \ref cds_nonintrusive_SplitListSet_erase_func "erase(Q const&, Func)"
569             but \p pred is used for key comparing.
570             \p Less functor has the interface like \p std::less.
571             \p Less must imply the same element order as the comparator used for building the set.
572         */
573         template <typename Q, typename Less, typename Func>
574         bool erase_with( Q const& key, Less pred, Func f )
575         {
576             CDS_UNUSED( pred );
577             return base_class::erase_with( key, typename maker::template predicate_wrapper<Less>::type(),
578                 [&f](node_type& node) { f( node.m_Value ); } );
579         }
580
581         /// Extracts the item with specified \p key
582         /** \anchor cds_nonintrusive_SplitListSet_hp_extract
583             The function searches an item with key equal to \p key,
584             unlinks it from the set, and returns it as \p guarded_ptr.
585             If \p key is not found the function returns an empty guarded pointer.
586
587             Note the compare functor should accept a parameter of type \p Q that may be not the same as \p value_type.
588
589             The extracted item is freed automatically when returned \p guarded_ptr object will be destroyed or released.
590             @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
591
592             Usage:
593             \code
594             typedef cds::container::SplitListSet< your_template_args > splitlist_set;
595             splitlist_set theSet;
596             // ...
597             {
598                 splitlist_set::guarded_ptr gp(theSet.extract( 5 ));
599                 if ( gp ) {
600                     // Deal with gp
601                     // ...
602                 }
603                 // Destructor of gp releases internal HP guard
604             }
605             \endcode
606         */
607         template <typename Q>
608         guarded_ptr extract( Q const& key )
609         {
610             guarded_ptr gp;
611             extract_( gp.guard(), key );
612             return gp;
613         }
614
615         /// Extracts the item using compare functor \p pred
616         /**
617             The function is an analog of \ref cds_nonintrusive_SplitListSet_hp_extract "extract(Q const&)"
618             but \p pred predicate is used for key comparing.
619
620             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
621             in any order.
622             \p pred must imply the same element order as the comparator used for building the set.
623         */
624         template <typename Q, typename Less>
625         guarded_ptr extract_with( Q const& key, Less pred )
626         {
627             guarded_ptr gp;
628             extract_with_( gp.guard(), key, pred );
629             return gp;
630         }
631
632         /// Finds the key \p key
633         /** \anchor cds_nonintrusive_SplitListSet_find_func
634
635             The function searches the item with key equal to \p key and calls the functor \p f for item found.
636             The interface of \p Func functor is:
637             \code
638             struct functor {
639                 void operator()( value_type& item, Q& key );
640             };
641             \endcode
642             where \p item is the item found, \p key is the <tt>find</tt> function argument.
643
644             The functor may change non-key fields of \p item. Note that the functor is only guarantee
645             that \p item cannot be disposed during functor is executing.
646             The functor does not serialize simultaneous access to the set's \p item. If such access is
647             possible you must provide your own synchronization schema on item level to exclude unsafe item modifications.
648
649             The \p key argument is non-const since it can be used as \p f functor destination i.e., the functor
650             may modify both arguments.
651
652             Note the hash functor specified for class \p Traits template parameter
653             should accept a parameter of type \p Q that can be not the same as \p value_type.
654
655             The function returns \p true if \p key is found, \p false otherwise.
656         */
657         template <typename Q, typename Func>
658         bool find( Q& key, Func f )
659         {
660             return find_( key, f );
661         }
662         //@cond
663         template <typename Q, typename Func>
664         bool find( Q const& key, Func f )
665         {
666             return find_( key, f );
667         }
668         //@endcond
669
670         /// Finds the key \p key using \p pred predicate for searching
671         /**
672             The function is an analog of \ref cds_nonintrusive_SplitListSet_find_func "find(Q&, Func)"
673             but \p pred is used for key comparing.
674             \p Less functor has the interface like \p std::less.
675             \p Less must imply the same element order as the comparator used for building the set.
676         */
677         template <typename Q, typename Less, typename Func>
678         bool find_with( Q& key, Less pred, Func f )
679         {
680             return find_with_( key, pred, f );
681         }
682         //@cond
683         template <typename Q, typename Less, typename Func>
684         bool find_with( Q const& key, Less pred, Func f )
685         {
686             return find_with_( key, pred, f );
687         }
688         //@endcond
689
690         /// Checks whether the set contains \p key
691         /**
692             The function searches the item with key equal to \p key
693             and returns \p true if it is found, and \p false otherwise.
694
695             Note the hash functor specified for class \p Traits template parameter
696             should accept a parameter of type \p Q that can be not the same as \p value_type.
697             Otherwise, you may use \p contains( Q const&, Less pred ) functions with explicit predicate for key comparing.
698         */
699         template <typename Q>
700         bool contains( Q const& key )
701         {
702             return base_class::contains( key );
703         }
704         //@cond
705         template <typename Q>
706         CDS_DEPRECATED("deprecated, use contains()")
707         bool find( Q const& key )
708         {
709             return contains( key );
710         }
711         //@endcond
712
713         /// Checks whether the map contains \p key using \p pred predicate for searching
714         /**
715             The function is similar to <tt>contains( key )</tt> but \p pred is used for key comparing.
716             \p Less functor has the interface like \p std::less.
717             \p Less must imply the same element order as the comparator used for building the map.
718         */
719         template <typename Q, typename Less>
720         bool contains( Q const& key, Less pred )
721         {
722             CDS_UNUSED( pred );
723             return base_class::contains( key, typename maker::template predicate_wrapper<Less>::type());
724         }
725         //@cond
726         template <typename Q, typename Less>
727         CDS_DEPRECATED("deprecated, use contains()")
728         bool find_with( Q const& key, Less pred )
729         {
730             return contains( key, pred );
731         }
732         //@endcond
733
734         /// Finds the key \p key and return the item found
735         /** \anchor cds_nonintrusive_SplitListSet_hp_get
736             The function searches the item with key equal to \p key
737             and returns the item found as \p guarded_ptr.
738             If \p key is not found the function returns an empty guarded pointer.
739
740             @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
741
742             Usage:
743             \code
744             typedef cds::container::SplitListSet< your_template_params >  splitlist_set;
745             splitlist_set theSet;
746             // ...
747             {
748                 splitlist_set::guarded_ptr gp(theSet.get( 5 ));
749                 if ( gp ) {
750                     // Deal with gp
751                     //...
752                 }
753                 // Destructor of guarded_ptr releases internal HP guard
754             }
755             \endcode
756
757             Note the compare functor specified for split-list set
758             should accept a parameter of type \p Q that can be not the same as \p value_type.
759         */
760         template <typename Q>
761         guarded_ptr get( Q const& key )
762         {
763             guarded_ptr gp;
764             get_( gp.guard(), key );
765             return gp;
766         }
767
768         /// Finds \p key and return the item found
769         /**
770             The function is an analog of \ref cds_nonintrusive_SplitListSet_hp_get "get( Q const&)"
771             but \p pred is used for comparing the keys.
772
773             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
774             in any order.
775             \p pred must imply the same element order as the comparator used for building the set.
776         */
777         template <typename Q, typename Less>
778         guarded_ptr get_with( Q const& key, Less pred )
779         {
780             guarded_ptr gp;
781             get_with_( gp.guard(), key, pred );
782             return gp;
783         }
784
785         /// Clears the set (not atomic)
786         void clear()
787         {
788             base_class::clear();
789         }
790
791         /// Checks if the set is empty
792         /**
793             Emptiness is checked by item counting: if item count is zero then assume that the set is empty.
794             Thus, the correct item counting feature is an important part of split-list set implementation.
795         */
796         bool empty() const
797         {
798             return base_class::empty();
799         }
800
801         /// Returns item count in the set
802         size_t size() const
803         {
804             return base_class::size();
805         }
806
807         /// Returns internal statistics
808         stat const& statistics() const
809         {
810             return base_class::statistics();
811         }
812
813     protected:
814         //@cond
815         using base_class::extract_;
816         using base_class::get_;
817
818         template <typename Q, typename Less>
819         bool extract_with_( typename guarded_ptr::native_guard& guard, Q const& key, Less pred )
820         {
821             CDS_UNUSED( pred );
822             return base_class::extract_with_( guard, key, typename maker::template predicate_wrapper<Less>::type());
823         }
824
825         template <typename Q, typename Less>
826         bool get_with_( typename guarded_ptr::native_guard& guard, Q const& key, Less pred )
827         {
828             CDS_UNUSED( pred );
829             return base_class::get_with_( guard, key, typename maker::template predicate_wrapper<Less>::type());
830         }
831
832         //@endcond
833
834     };
835
836
837 }}  // namespace cds::container
838
839 #endif // #ifndef CDSLIB_CONTAINER_SPLIT_LIST_SET_H