Minor changes related to unit test
[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         /// Count of hazard pointer required
184         static CDS_CONSTEXPR const size_t c_nHazardPtrCount = base_class::c_nHazardPtrCount;
185
186     protected:
187         //@cond
188         typedef typename maker::cxx_node_allocator    cxx_node_allocator;
189         typedef typename maker::node_type             node_type;
190         //@endcond
191
192     public:
193         /// Guarded pointer
194         typedef typename gc::template guarded_ptr< node_type, value_type, details::guarded_ptr_cast_set<node_type, value_type> > guarded_ptr;
195
196     protected:
197         //@cond
198         template <typename Q>
199         static node_type * alloc_node(Q const& v )
200         {
201             return cxx_node_allocator().New( v );
202         }
203
204         template <typename... Args>
205         static node_type * alloc_node( Args&&... args )
206         {
207             return cxx_node_allocator().MoveNew( std::forward<Args>( args )... );
208         }
209
210         static void free_node( node_type * pNode )
211         {
212             cxx_node_allocator().Delete( pNode );
213         }
214
215         template <typename Q, typename Func>
216         bool find_( Q& val, Func f )
217         {
218             return base_class::find( val, [&f]( node_type& item, Q& val ) { f(item.m_Value, val) ; } );
219         }
220
221         template <typename Q, typename Less, typename Func>
222         bool find_with_( Q& val, Less pred, Func f )
223         {
224             CDS_UNUSED( pred );
225             return base_class::find_with( val, typename maker::template predicate_wrapper<Less>::type(),
226                 [&f]( node_type& item, Q& val ) { f(item.m_Value, val) ; } );
227         }
228
229         struct node_disposer {
230             void operator()( node_type * pNode )
231             {
232                 free_node( pNode );
233             }
234         };
235         typedef std::unique_ptr< node_type, node_disposer >     scoped_node_ptr;
236
237         bool insert_node( node_type * pNode )
238         {
239             assert( pNode != nullptr );
240             scoped_node_ptr p(pNode);
241
242             if ( base_class::insert( *pNode )) {
243                 p.release();
244                 return true;
245             }
246             return false;
247         }
248
249         //@endcond
250
251     protected:
252         /// Forward iterator
253         /**
254             \p IsConst - constness boolean flag
255
256             The forward iterator for a split-list has the following features:
257             - it has no post-increment operator
258             - it depends on underlying ordered list iterator
259             - The iterator object cannot be moved across thread boundary since it contains GC's guard that is thread-private GC data.
260             - Iterator ensures thread-safety even if you delete the item that iterator points to. However, in case of concurrent
261               deleting operations it is no guarantee that you iterate all item in the split-list.
262
263             Therefore, the use of iterators in concurrent environment is not good idea. Use it for debug purpose only.
264         */
265         template <bool IsConst>
266         class iterator_type: protected base_class::template iterator_type<IsConst>
267         {
268             //@cond
269             typedef typename base_class::template iterator_type<IsConst> iterator_base_class;
270             friend class SplitListSet;
271             //@endcond
272         public:
273             /// Value pointer type (const for const iterator)
274             typedef typename cds::details::make_const_type<value_type, IsConst>::pointer   value_ptr;
275             /// Value reference type (const for const iterator)
276             typedef typename cds::details::make_const_type<value_type, IsConst>::reference value_ref;
277
278         public:
279             /// Default ctor
280             iterator_type()
281             {}
282
283             /// Copy ctor
284             iterator_type( iterator_type const& src )
285                 : iterator_base_class( src )
286             {}
287
288         protected:
289             //@cond
290             explicit iterator_type( iterator_base_class const& src )
291                 : iterator_base_class( src )
292             {}
293             //@endcond
294
295         public:
296             /// Dereference operator
297             value_ptr operator ->() const
298             {
299                 return &(iterator_base_class::operator->()->m_Value);
300             }
301
302             /// Dereference operator
303             value_ref operator *() const
304             {
305                 return iterator_base_class::operator*().m_Value;
306             }
307
308             /// Pre-increment
309             iterator_type& operator ++()
310             {
311                 iterator_base_class::operator++();
312                 return *this;
313             }
314
315             /// Assignment operator
316             iterator_type& operator = (iterator_type const& src)
317             {
318                 iterator_base_class::operator=(src);
319                 return *this;
320             }
321
322             /// Equality operator
323             template <bool C>
324             bool operator ==(iterator_type<C> const& i ) const
325             {
326                 return iterator_base_class::operator==(i);
327             }
328
329             /// Equality operator
330             template <bool C>
331             bool operator !=(iterator_type<C> const& i ) const
332             {
333                 return iterator_base_class::operator!=(i);
334             }
335         };
336
337     public:
338         /// Initializes split-ordered list of default capacity
339         /**
340             The default capacity is defined in bucket table constructor.
341             See \p intrusive::split_list::expandable_bucket_table, \p intrusive::split_list::static_bucket_table
342             which selects by \p split_list::dynamic_bucket_table option.
343         */
344         SplitListSet()
345             : base_class()
346         {}
347
348         /// Initializes split-ordered list
349         SplitListSet(
350             size_t nItemCount           ///< estimated average of item count
351             , size_t nLoadFactor = 1    ///< the load factor - average item count per bucket. Small integer up to 8, default is 1.
352             )
353             : base_class( nItemCount, nLoadFactor )
354         {}
355
356     public:
357         /// Forward iterator
358         typedef iterator_type<false>  iterator;
359
360         /// Const forward iterator
361         typedef iterator_type<true>    const_iterator;
362
363         /// Returns a forward iterator addressing the first element in a set
364         /**
365             For empty set \code begin() == end() \endcode
366         */
367         iterator begin()
368         {
369             return iterator( base_class::begin());
370         }
371
372         /// Returns an iterator that addresses the location succeeding the last element in a set
373         /**
374             Do not use the value returned by <tt>end</tt> function to access any item.
375             The returned value can be used only to control reaching the end of the set.
376             For empty set \code begin() == end() \endcode
377         */
378         iterator end()
379         {
380             return iterator( base_class::end());
381         }
382
383         /// Returns a forward const iterator addressing the first element in a set
384         const_iterator begin() const
385         {
386             return cbegin();
387         }
388         /// Returns a forward const iterator addressing the first element in a set
389         const_iterator cbegin() const
390         {
391             return const_iterator( base_class::cbegin());
392         }
393
394         /// Returns an const iterator that addresses the location succeeding the last element in a set
395         const_iterator end() const
396         {
397             return cend();
398         }
399         /// Returns an const iterator that addresses the location succeeding the last element in a set
400         const_iterator cend() const
401         {
402             return const_iterator( base_class::cend());
403         }
404
405     public:
406         /// Inserts new node
407         /**
408             The function creates a node with copy of \p val value
409             and then inserts the node created into the set.
410
411             The type \p Q should contain as minimum the complete key for the node.
412             The object of \ref value_type should be constructible from a value of type \p Q.
413             In trivial case, \p Q is equal to \ref value_type.
414
415             Returns \p true if \p val is inserted into the set, \p false otherwise.
416         */
417         template <typename Q>
418         bool insert( Q const& val )
419         {
420             return insert_node( alloc_node( val ));
421         }
422
423         /// Inserts new node
424         /**
425             The function allows to split creating of new item into two part:
426             - create item with key only
427             - insert new item into the set
428             - if inserting is success, calls  \p f functor to initialize value-field of \p val.
429
430             The functor signature is:
431             \code
432                 void func( value_type& val );
433             \endcode
434             where \p val is the item inserted.
435
436             The user-defined functor is called only if the inserting is success.
437
438             @warning For \ref cds_intrusive_MichaelList_hp "MichaelList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
439             \ref cds_intrusive_LazyList_hp "LazyList" provides exclusive access to inserted item and does not require any node-level
440             synchronization.
441         */
442         template <typename Q, typename Func>
443         bool insert( Q const& val, Func f )
444         {
445             scoped_node_ptr pNode( alloc_node( val ));
446
447             if ( base_class::insert( *pNode, [&f](node_type& node) { f( node.m_Value ) ; } )) {
448                 pNode.release();
449                 return true;
450             }
451             return false;
452         }
453
454         /// Inserts data of type \p value_type created from \p args
455         /**
456             Returns \p true if inserting successful, \p false otherwise.
457         */
458         template <typename... Args>
459         bool emplace( Args&&... args )
460         {
461             return insert_node( alloc_node( std::forward<Args>(args)...));
462         }
463
464         /// Updates the node
465         /**
466             The operation performs inserting or changing data with lock-free manner.
467
468             If \p key is not found in the set, then \p key is inserted iff \p bAllowInsert is \p true.
469             Otherwise, the functor \p func is called with item found.
470
471             The functor signature is:
472             \code
473                 struct my_functor {
474                     void operator()( bool bNew, value_type& item, const Q& val );
475                 };
476             \endcode
477             with arguments:
478             - \p bNew - \p true if the item has been inserted, \p false otherwise
479             - \p item - item of the set
480             - \p val - argument \p val passed into the \p %update() function
481
482             The functor may change non-key fields of the \p item.
483
484             Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
485             \p second is true if new item has been added or \p false if the item with \p key
486             already is in the map.
487
488             @warning For \ref cds_intrusive_MichaelList_hp "MichaelList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
489             \ref cds_intrusive_LazyList_hp "LazyList" provides exclusive access to inserted item and does not require any node-level
490             synchronization.
491         */
492         template <typename Q, typename Func>
493         std::pair<bool, bool> update( Q const& val, Func func, bool bAllowInsert = true )
494         {
495             scoped_node_ptr pNode( alloc_node( val ));
496
497             std::pair<bool, bool> bRet = base_class::update( *pNode,
498                 [&func, &val]( bool bNew, node_type& item,  node_type const& /*val*/ ) {
499                     func( bNew, item.m_Value, val );
500                 }, bAllowInsert );
501
502             if ( bRet.first && bRet.second )
503                 pNode.release();
504             return bRet;
505         }
506         //@cond
507         template <typename Q, typename Func>
508         CDS_DEPRECATED("ensure() is deprecated, use update()")
509         std::pair<bool, bool> ensure( Q const& val, Func func )
510         {
511             return update( val, func, true );
512         }
513         //@endcond
514
515         /// Deletes \p key from the set
516         /** \anchor cds_nonintrusive_SplitListSet_erase_val
517
518             The item comparator should be able to compare the values of type \p value_type
519             and the type \p Q.
520
521             Return \p true if key is found and deleted, \p false otherwise
522         */
523         template <typename Q>
524         bool erase( Q const& key )
525         {
526             return base_class::erase( key );
527         }
528
529         /// Deletes the item from the set using \p pred predicate for searching
530         /**
531             The function is an analog of \ref cds_nonintrusive_SplitListSet_erase_val "erase(Q const&)"
532             but \p pred is used for key comparing.
533             \p Less functor has the interface like \p std::less.
534             \p Less must imply the same element order as the comparator used for building the set.
535         */
536         template <typename Q, typename Less>
537         bool erase_with( Q const& key, Less pred )
538         {
539             CDS_UNUSED( pred );
540             return base_class::erase_with( key, typename maker::template predicate_wrapper<Less>::type());
541         }
542
543         /// Deletes \p key from the set
544         /** \anchor cds_nonintrusive_SplitListSet_erase_func
545
546             The function searches an item with key \p key, calls \p f functor
547             and deletes the item. If \p key is not found, the functor is not called.
548
549             The functor \p Func interface:
550             \code
551             struct extractor {
552                 void operator()(value_type const& val);
553             };
554             \endcode
555
556             Since the key of split-list \p value_type is not explicitly specified,
557             template parameter \p Q defines the key type searching in the list.
558             The list item comparator should be able to compare the values of the type \p value_type
559             and the type \p Q.
560
561             Return \p true if key is found and deleted, \p false otherwise
562         */
563         template <typename Q, typename Func>
564         bool erase( Q const& key, Func f )
565         {
566             return base_class::erase( key, [&f](node_type& node) { f( node.m_Value ); } );
567         }
568
569         /// Deletes the item from the set using \p pred predicate for searching
570         /**
571             The function is an analog of \ref cds_nonintrusive_SplitListSet_erase_func "erase(Q const&, Func)"
572             but \p pred is used for key comparing.
573             \p Less functor has the interface like \p std::less.
574             \p Less must imply the same element order as the comparator used for building the set.
575         */
576         template <typename Q, typename Less, typename Func>
577         bool erase_with( Q const& key, Less pred, Func f )
578         {
579             CDS_UNUSED( pred );
580             return base_class::erase_with( key, typename maker::template predicate_wrapper<Less>::type(),
581                 [&f](node_type& node) { f( node.m_Value ); } );
582         }
583
584         /// Extracts the item with specified \p key
585         /** \anchor cds_nonintrusive_SplitListSet_hp_extract
586             The function searches an item with key equal to \p key,
587             unlinks it from the set, and returns it as \p guarded_ptr.
588             If \p key is not found the function returns an empty guarded pointer.
589
590             Note the compare functor should accept a parameter of type \p Q that may be not the same as \p value_type.
591
592             The extracted item is freed automatically when returned \p guarded_ptr object will be destroyed or released.
593             @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
594
595             Usage:
596             \code
597             typedef cds::container::SplitListSet< your_template_args > splitlist_set;
598             splitlist_set theSet;
599             // ...
600             {
601                 splitlist_set::guarded_ptr gp(theSet.extract( 5 ));
602                 if ( gp ) {
603                     // Deal with gp
604                     // ...
605                 }
606                 // Destructor of gp releases internal HP guard
607             }
608             \endcode
609         */
610         template <typename Q>
611         guarded_ptr extract( Q const& key )
612         {
613             guarded_ptr gp;
614             extract_( gp.guard(), key );
615             return gp;
616         }
617
618         /// Extracts the item using compare functor \p pred
619         /**
620             The function is an analog of \ref cds_nonintrusive_SplitListSet_hp_extract "extract(Q const&)"
621             but \p pred predicate is used for key comparing.
622
623             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
624             in any order.
625             \p pred must imply the same element order as the comparator used for building the set.
626         */
627         template <typename Q, typename Less>
628         guarded_ptr extract_with( Q const& key, Less pred )
629         {
630             guarded_ptr gp;
631             extract_with_( gp.guard(), key, pred );
632             return gp;
633         }
634
635         /// Finds the key \p key
636         /** \anchor cds_nonintrusive_SplitListSet_find_func
637
638             The function searches the item with key equal to \p key and calls the functor \p f for item found.
639             The interface of \p Func functor is:
640             \code
641             struct functor {
642                 void operator()( value_type& item, Q& key );
643             };
644             \endcode
645             where \p item is the item found, \p key is the <tt>find</tt> function argument.
646
647             The functor may change non-key fields of \p item. Note that the functor is only guarantee
648             that \p item cannot be disposed during functor is executing.
649             The functor does not serialize simultaneous access to the set's \p item. If such access is
650             possible you must provide your own synchronization schema on item level to exclude unsafe item modifications.
651
652             The \p key argument is non-const since it can be used as \p f functor destination i.e., the functor
653             may modify both arguments.
654
655             Note the hash functor specified for class \p Traits template parameter
656             should accept a parameter of type \p Q that can be not the same as \p value_type.
657
658             The function returns \p true if \p key is found, \p false otherwise.
659         */
660         template <typename Q, typename Func>
661         bool find( Q& key, Func f )
662         {
663             return find_( key, f );
664         }
665         //@cond
666         template <typename Q, typename Func>
667         bool find( Q const& key, Func f )
668         {
669             return find_( key, f );
670         }
671         //@endcond
672
673         /// Finds the key \p key using \p pred predicate for searching
674         /**
675             The function is an analog of \ref cds_nonintrusive_SplitListSet_find_func "find(Q&, Func)"
676             but \p pred is used for key comparing.
677             \p Less functor has the interface like \p std::less.
678             \p Less must imply the same element order as the comparator used for building the set.
679         */
680         template <typename Q, typename Less, typename Func>
681         bool find_with( Q& key, Less pred, Func f )
682         {
683             return find_with_( key, pred, f );
684         }
685         //@cond
686         template <typename Q, typename Less, typename Func>
687         bool find_with( Q const& key, Less pred, Func f )
688         {
689             return find_with_( key, pred, f );
690         }
691         //@endcond
692
693         /// Checks whether the set contains \p key
694         /**
695             The function searches the item with key equal to \p key
696             and returns \p true if it is found, and \p false otherwise.
697
698             Note the hash functor specified for class \p Traits template parameter
699             should accept a parameter of type \p Q that can be not the same as \p value_type.
700             Otherwise, you may use \p contains( Q const&, Less pred ) functions with explicit predicate for key comparing.
701         */
702         template <typename Q>
703         bool contains( Q const& key )
704         {
705             return base_class::contains( key );
706         }
707         //@cond
708         template <typename Q>
709         CDS_DEPRECATED("deprecated, use contains()")
710         bool find( Q const& key )
711         {
712             return contains( key );
713         }
714         //@endcond
715
716         /// Checks whether the map contains \p key using \p pred predicate for searching
717         /**
718             The function is similar to <tt>contains( key )</tt> but \p pred is used for key comparing.
719             \p Less functor has the interface like \p std::less.
720             \p Less must imply the same element order as the comparator used for building the map.
721         */
722         template <typename Q, typename Less>
723         bool contains( Q const& key, Less pred )
724         {
725             CDS_UNUSED( pred );
726             return base_class::contains( key, typename maker::template predicate_wrapper<Less>::type());
727         }
728         //@cond
729         template <typename Q, typename Less>
730         CDS_DEPRECATED("deprecated, use contains()")
731         bool find_with( Q const& key, Less pred )
732         {
733             return contains( key, pred );
734         }
735         //@endcond
736
737         /// Finds the key \p key and return the item found
738         /** \anchor cds_nonintrusive_SplitListSet_hp_get
739             The function searches the item with key equal to \p key
740             and returns the item found as \p guarded_ptr.
741             If \p key is not found the function returns an empty guarded pointer.
742
743             @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
744
745             Usage:
746             \code
747             typedef cds::container::SplitListSet< your_template_params >  splitlist_set;
748             splitlist_set theSet;
749             // ...
750             {
751                 splitlist_set::guarded_ptr gp(theSet.get( 5 ));
752                 if ( gp ) {
753                     // Deal with gp
754                     //...
755                 }
756                 // Destructor of guarded_ptr releases internal HP guard
757             }
758             \endcode
759
760             Note the compare functor specified for split-list set
761             should accept a parameter of type \p Q that can be not the same as \p value_type.
762         */
763         template <typename Q>
764         guarded_ptr get( Q const& key )
765         {
766             guarded_ptr gp;
767             get_( gp.guard(), key );
768             return gp;
769         }
770
771         /// Finds \p key and return the item found
772         /**
773             The function is an analog of \ref cds_nonintrusive_SplitListSet_hp_get "get( Q const&)"
774             but \p pred is used for comparing the keys.
775
776             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
777             in any order.
778             \p pred must imply the same element order as the comparator used for building the set.
779         */
780         template <typename Q, typename Less>
781         guarded_ptr get_with( Q const& key, Less pred )
782         {
783             guarded_ptr gp;
784             get_with_( gp.guard(), key, pred );
785             return gp;
786         }
787
788         /// Clears the set (not atomic)
789         void clear()
790         {
791             base_class::clear();
792         }
793
794         /// Checks if the set is empty
795         /**
796             Emptiness is checked by item counting: if item count is zero then assume that the set is empty.
797             Thus, the correct item counting feature is an important part of split-list set implementation.
798         */
799         bool empty() const
800         {
801             return base_class::empty();
802         }
803
804         /// Returns item count in the set
805         size_t size() const
806         {
807             return base_class::size();
808         }
809
810         /// Returns internal statistics
811         stat const& statistics() const
812         {
813             return base_class::statistics();
814         }
815
816     protected:
817         //@cond
818         using base_class::extract_;
819         using base_class::get_;
820
821         template <typename Q, typename Less>
822         bool extract_with_( typename guarded_ptr::native_guard& guard, Q const& key, Less pred )
823         {
824             CDS_UNUSED( pred );
825             return base_class::extract_with_( guard, key, typename maker::template predicate_wrapper<Less>::type());
826         }
827
828         template <typename Q, typename Less>
829         bool get_with_( typename guarded_ptr::native_guard& guard, Q const& key, Less pred )
830         {
831             CDS_UNUSED( pred );
832             return base_class::get_with_( guard, key, typename maker::template predicate_wrapper<Less>::type());
833         }
834
835         //@endcond
836
837     };
838
839
840 }}  // namespace cds::container
841
842 #endif // #ifndef CDSLIB_CONTAINER_SPLIT_LIST_SET_H