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