Add rational load factor resizing policy
[libcds.git] / cds / container / striped_set.h
1 //$$CDS-header$$
2
3 #ifndef CDSLIB_CONTAINER_STRIPED_SET_H
4 #define CDSLIB_CONTAINER_STRIPED_SET_H
5
6 #include <cds/intrusive/striped_set.h>
7 #include <cds/container/striped_set/adapter.h>
8
9 namespace cds { namespace container {
10
11     /// Striped hash set
12     /** @ingroup cds_nonintrusive_set
13
14         Source
15             - [2008] Maurice Herlihy, Nir Shavit "The Art of Multiprocessor Programming"
16
17         Lock striping is very simple technique.
18         The set consists of the bucket table and the array of locks.
19         Initially, the capacity of lock array and bucket table is the same.
20         When set is resized, bucket table capacity will be doubled but lock array will not.
21         The lock \p i protects each bucket \p j, where <tt> j = i mod L </tt>,
22         where \p L - the size of lock array.
23
24         Template arguments:
25             - \p Container - the container class that is used as bucket table entry. The \p Container class should support
26                 an uniform interface described below.
27             - \p Options - options
28
29         The \p %StripedSet class does not exactly dictate the type of container that should be used as a \p Container bucket.
30         Instead, the class supports different container type for the bucket, for exampe, \p std::list, \p std::set and others.
31
32         Remember that \p %StripedSet class algorithm ensures sequential blocking access to its bucket through the mutex type you specify
33         among \p Options template arguments.
34
35         The \p Options are:
36             - \p opt::mutex_policy - concurrent access policy.
37                 Available policies: \p intrusive::striped_set::striping, \p intrusive::striped_set::refinable.
38                 Default is \p %striped_set::striping.
39             - \p opt::hash - hash functor. Default option value see <tt>opt::v::hash_selector<opt::none> </tt>
40                 which selects default hash functor for your compiler.
41             - \p opt::compare - key comparison functor. No default functor is provided.
42                 If the option is not specified, the \p %opt::less is used.
43             - \p opt::less - specifies binary predicate used for key comparison. Default is \p std::less<T>.
44             - \p opt::item_counter - item counter type. Default is \p atomicity::item_counter since some operation on the counter is performed
45                 without locks. Note that item counting is an essential part of the set algorithm, so dummy counter
46                 like as \p atomicity::empty_item_counter is not suitable.
47             - \p opt::allocator - the allocator type using for memory allocation of bucket table and lock array. Default is \ref CDS_DEFAULT_ALLOCATOR.
48             - \p opt::resizing_policy - the resizing policy that is a functor that decides when to resize the hash set.
49                 Default option value depends on bucket container type:
50                     for sequential containers like \p std::list, \p std::vector the resizing policy is <tt>striped_set::load_factor_resizing<4> </tt>;
51                     for other type of containers like \p std::set, \p std::unordered_set the resizing policy is \p striped_set::no_resizing.
52                 See \ref cds_striped_resizing_policy "available resizing policy".
53                 Note that the choose of resizing policy depends of \p Container type:
54                 for sequential containers like \p std::list, \p std::vector and so on, right choosing of the policy can
55                 significantly improve performance.
56                 For other, non-sequential types of \p Container (like a \p std::set) the resizing policy is not so important.
57             - \p opt::copy_policy - the copy policy which is used to copy items from the old set to the new one when resizing.
58                 The policy can be optionally used in adapted bucket container for performance reasons of resizing.
59                 The detail of copy algorithm depends on type of bucket container and explains below.
60
61             \p %opt::compare or \p %opt::less options are used in some \p Container class for searching an item.
62             \p %opt::compare option has the highest priority: if \p %opt::compare is specified, \p %opt::less is not used.
63
64         You can pass other option that would be passed to <tt>adapt</tt> metafunction, see below.
65
66         <b>Internal details</b>
67
68             The \p %StripedSet class cannot utilize the \p Container container specified directly, but only its adapted variant which
69             supports an unified interface. Internally, the adaptation is made via striped_set::adapt metafunction that wraps bucket container
70             and provides the unified bucket interface suitable for \p %StripedSet. Such adaptation is completely transparent for you -
71             you don't need to call \p adapt metafunction directly, \p %StripedSet class's internal machinery itself invokes appropriate
72             \p adapt metafunction to adjust your \p Container container class to \p %StripedSet bucket's internal interface.
73             All you need is to include a right header before <tt>striped_hash_set.h</tt>.
74
75             By default, <tt>striped_set::adapt<AnyContainer, Options...> </tt> metafunction does not make any wrapping to \p AnyContainer,
76             so, the result <tt>striped_set::adapt<AnyContainer, Options...>::type </tt> is the same as \p AnyContainer.
77             However, there are a lot of specializations of <tt>striped_set::adapt</tt> for well-known containers, see table below.
78             Any of this specialization wraps corresponding container making it suitable for the set's bucket.
79             Remember, you should include the proper header file for \p adapt <b>before</b> including <tt>striped_hash_set.h</tt>.
80             <table>
81                 <tr>
82                     <th>Container</th>
83                     <th>.h-file for \p adapt</th>
84                     <th>Example</th>
85                     <th>Notes</th>
86                 </tr>
87                 <tr>
88                     <td> \p std::list</td>
89                     <td><tt><cds/container/striped_set/std_list.h></tt></td>
90                     <td>\code
91                         #include <cds/container/striped_set/std_list.h>
92                         #include <cds/container/striped_hash_set.h>
93                         typedef cds::container::StripedSet<
94                             std::list<T>,
95                             cds::opt::less< std::less<T> >
96                         > striped_set;
97                     \endcode
98                     </td>
99                     <td>
100                         The list is ordered.
101                         Template argument pack \p Options <b>must</b> contain cds::opt::less or cds::opt::compare for type \p T stored in the list
102                     </td>
103                 </tr>
104                 <tr>
105                     <td> \p std::vector</td>
106                     <td><tt><cds/container/striped_set/std_vector.h></tt></td>
107                     <td>\code
108                         #include <cds/container/striped_set/std_vector.h>
109                         #include <cds/container/striped_hash_set.h>
110                         typedef cds::container::StripedSet<
111                             std::vector<T>,
112                             cds::opt::less< std::less<T> >
113                         > striped_set;
114                     \endcode
115                     </td>
116                     <td>
117                         The vector is ordered.
118                         Template argument pack \p Options <b>must</b> contain \p cds::opt::less or \p cds::opt::compare for type \p T stored in the list
119                     </td>
120                 </tr>
121                 <tr>
122                     <td> \p std::set</td>
123                     <td><tt><cds/container/striped_set/std_set.h></tt></td>
124                     <td>\code
125                         #include <cds/container/striped_set/std_set.h>
126                         #include <cds/container/striped_hash_set.h>
127                         typedef cds::container::StripedSet<
128                             std::set< T, std::less<T> >
129                         > striped_set;
130                     \endcode
131                     </td>
132                     <td>
133                     </td>
134                 </tr>
135                 <tr>
136                     <td> \p std::unordered_set</td>
137                     <td><tt><cds/container/striped_set/std_hash_set.h></tt></td>
138                     <td>\code
139                         #include <cds/container/striped_set/std_hash_set.h>
140                         #include <cds/container/striped_hash_set.h>
141                         typedef cds::container::StripedSet<
142                             std::unordered_set<
143                                 T,
144                                 hash<T>,
145                                 equal<T>
146                             >
147                         > striped_set;
148                     \endcode
149                     </td>
150                     <td>
151                         You should provide two different hash function \p h1 and \p h2 - one for \p std::unordered_set and other for \p %StripedSet.
152                         For the best result, \p h1 and \p h2 must be orthogonal i.e. <tt> h1(X) != h2(X) </tt> for any value \p X.
153                     </td>
154                 </tr>
155                 <tr>
156                     <td> \p boost::container::slist</td>
157                     <td><tt><cds/container/striped_set/boost_slist.h></tt></td>
158                     <td>\code
159                         #include <cds/container/striped_set/boost_slist.h>
160                         #include <cds/container/striped_hash_set.h>
161                         typedef cds::container::StripedSet<
162                             boost::container::slist<T>
163                         > striped_set;
164                     \endcode
165                     </td>
166                     <td>
167                         The list is ordered.
168                         \p Options <b>must</b> contain \p cds::opt::less or \p cds::opt::compare.
169                     </td>
170                 </tr>
171                 <tr>
172                     <td> \p boost::container::list</td>
173                     <td><tt><cds/container/striped_set/boost_list.h></tt></td>
174                     <td>\code
175                         #include <cds/container/striped_set/boost_list.h>
176                         #include <cds/container/striped_hash_set.h>
177                         typedef cds::container::StripedSet<
178                             boost::container::list<T>
179                         > striped_set;
180                     \endcode
181                     </td>
182                     <td>
183                         The list is ordered.
184                         \p Options <b>must</b> contain \p cds::opt::less or \p cds::opt::compare.
185                     </td>
186                 </tr>
187                 <tr>
188                     <td> \p boost::container::vector</td>
189                     <td><tt><cds/container/striped_set/boost_vector.h></tt></td>
190                     <td>\code
191                         #include <cds/container/striped_set/boost_vector.h>
192                         #include <cds/container/striped_hash_set.h>
193                         typedef cds::container::StripedSet<
194                             boost::container::vector<T>,
195                             cds::opt::less< std::less<T> >
196                         > striped_set;
197                     \endcode
198                     </td>
199                     <td>
200                         The vector is ordered.
201                         Template argument pack \p Options <b>must</b> contain \p cds::opt::less or \p cds::opt::compare for type \p T stored in the vector
202                     </td>
203                 </tr>
204                 <tr>
205                     <td> \p boost::container::stable_vector</td>
206                     <td><tt><cds/container/striped_set/boost_stable_vector.h></tt></td>
207                     <td>\code
208                         #include <cds/container/striped_set/boost_stable_vector.h>
209                         #include <cds/container/striped_hash_set.h>
210                         typedef cds::container::StripedSet<
211                             boost::container::stable_vector<T>,
212                             cds::opt::less< std::less<T> >
213                         > striped_set;
214                     \endcode
215                     </td>
216                     <td>
217                         The vector is ordered.
218                         Template argument pack \p Options <b>must</b> contain \p cds::opt::less or \p cds::opt::compare for type \p T stored in the vector
219                     </td>
220                 </tr>
221                 <tr>
222                     <td> \p boost::container::set</td>
223                     <td><tt><cds/container/striped_set/boost_set.h></tt></td>
224                     <td>\code
225                         #include <cds/container/striped_set/boost_set.h>
226                         #include <cds/container/striped_hash_set.h>
227                         typedef cds::container::StripedSet<
228                             boost::container::set< T, std::less<T> >
229                         > striped_set;
230                     \endcode
231                     </td>
232                     <td>
233                     </td>
234                 </tr>
235                 <tr>
236                     <td> \p boost::container::flat_set</td>
237                     <td><tt><cds/container/striped_set/boost_flat_set.h></tt></td>
238                     <td>\code
239                         #include <cds/container/striped_set/boost_flat_set.h>
240                         #include <cds/container/striped_hash_set.h>
241                         typedef cds::container::StripedSet<
242                             boost::container::flat_set< T, std::less<T> >
243                         > striped_set;
244                     \endcode
245                     </td>
246                     <td>
247                     </td>
248                 </tr>
249                 <tr>
250                     <td> \p boost::unordered_set</td>
251                     <td><tt><cds/container/striped_set/boost_unordered_set.h></tt></td>
252                     <td>\code
253                         #include <cds/container/striped_set/boost_unordered_set.h>
254                         #include <cds/container/striped_hash_set.h>
255                         typedef cds::container::StripedSet<
256                             boost::unordered_set<
257                                 T,
258                                 hash<T>,
259                                 equal<T>
260                             >
261                         > striped_set;
262                     \endcode
263                     </td>
264                     <td>
265                         You should provide two different hash function \p h1 and \p h2 - one for \p boost::unordered_set and other for \p %StripedSet.
266                         For the best result, \p h1 and \p h2 must be orthogonal i.e. <tt> h1(X) != h2(X) </tt> for any value \p X.
267                     </td>
268                 </tr>
269             </table>
270
271             You can use another container type as set's bucket.
272             Suppose, you have a container class \p MyBestContainer and you want to integrate it with \p %StripedSet as bucket type.
273             There are two possibility:
274             - either your \p MyBestContainer class has native support of bucket's interface;
275                 in this case, you can use default <tt>striped_set::adapt</tt> metafunction;
276             - or your \p MyBestContainer class does not support bucket's interface, which means, that you should develop a specialization
277                 <tt>cds::container::striped_set::adapt<MyBestContainer> </tt> metafunction providing necessary interface.
278
279             The <tt>striped_set::adapt< Container, Options... ></tt> metafunction has two template argument:
280             - \p Container is the class that should be used as the bucket, for example, <tt>std::list< T ></tt>.
281             - \p Options pack is the options from \p %StripedSet declaration. The \p adapt metafunction can use
282                 any option from \p Options for its internal use. For example, a \p compare option can be passed to \p adapt
283                 metafunction via \p Options argument of \p %StripedSet declaration.
284
285             See striped_set::adapt metafunction for the description of interface that the bucket container must provide
286             to be %StripedSet compatible.
287
288         <b>Copy policy</b>
289             There are three predefined copy policy:
290             - \p cds::container::striped_set::copy_item - copy item from old bucket to new one when resizing using copy ctor. It is default policy for
291                 any compiler that do not support move semantics
292             - \p cds::container::striped_set::move_item - move item from old bucket to new one when resizing using move semantics. It is default policy for
293                 any compiler that support move semantics. If compiler does not support move semantics, the move policy is the same as \p copy_item
294             - \p cds::container::striped_set::swap_item - copy item from old bucket to new one when resizing using \p std::swap. Not all containers support
295                 this copy policy, see details in table below.
296
297             You can define your own copy policy specifically for your case.
298             Note, right copy policy can significantly improve the performance of resizing.
299
300             <table>
301                 <tr>
302                     <th>Container</th>
303                     <th>Policies</th>
304                 </tr>
305                 <tr>
306                     <td>
307                         - \p std::list
308                         - \p std::vector
309                         - \p boost::list
310                         - \p boost::vector
311                         - \p boost::stable_vector
312                     </td>
313                     <td>\code
314                         struct copy_item {
315                             void operator()( std::list<T>& list, std::list<T>::iterator itInsert, std::list<T>::iterator itWhat )
316                             {
317                                 list.insert( itInsert, *itWhat );
318                             }
319                         } \endcode
320
321                         \code
322                         // The type T stored in the list must be swappable
323                         struct swap_item {
324                             void operator()( std::list<T>& list, std::list<T>::iterator itInsert, std::list<T>::iterator itWhat )
325                             {
326                                 std::swap( *list.insert( itInsert, T() ), *itWhat );
327                             }
328                         } \endcode
329
330                         \code
331                         struct move_item {
332                             void operator()( std::list<T>& list, std::list<T>::iterator itInsert, std::list<T>::iterator itWhat )
333                             {
334                                 list.insert( itInsert, std::move( *itWhat ) );
335                             }
336                         } \endcode
337                     </td>
338                 </tr>
339                 <tr>
340                     <td>
341                         - \p std::set
342                         - \p std::unordered_set
343                     </td>
344                     <td>\code
345                         struct copy_item {
346                             void operator()( std::set<T>& set, std::set<T>::iterator itWhat )
347                             {
348                                 set.insert( *itWhat );
349                             }
350                         } \endcode
351                     \p swap_item is not applicable (same as \p copy_item)
352
353                     \code
354                         struct move_item {
355                             void operator()( std::set<T>& set, std::set<T>::iterator itWhat )
356                             {
357                                 set.insert( std::move( *itWhat ));
358                             }
359                         } \endcode
360                 </tr>
361                 <tr>
362                     <td>
363                         - \p boost::container::slist
364                     </td>
365                     <td>\code
366                         struct copy_item {
367                             void operator()( bc::slist<T>& list, bc::slist<T>::iterator itInsert, bc::slist<T>::iterator itWhat )
368                             {
369                                 list.insert_after( itInsert, *itWhat );
370                             }
371                         } \endcode
372
373                         \code
374                         // The type T stored in the list must be swappable
375                         struct swap_item {
376                             void operator()( bc::slist<T>& list, bc::slist<T>::iterator itInsert, bc::slist<T>::iterator itWhat )
377                             {
378                                 std::swap( *list.insert_after( itInsert, T() ), *itWhat );
379                             }
380                         } \endcode
381
382                         \code
383                         struct move_item {
384                             void operator()( bc::slist<T>& list, bc::slist<T>::iterator itInsert, bc::slist<T>::iterator itWhat )
385                             {
386                                 list.insert_after( itInsert, std::move( *itWhat ) );
387                             }
388                         } \endcode
389                     </td>
390                 </tr>
391             </table>
392
393         <b>Advanced functions</b>
394
395             <b>libcds</b> provides some advanced functions like \p erase_with(), \p find_with(),
396             that cannot be supported by all underlying containers.
397             The table below shows whether underlying container supports those functions
398             (the sign "+" means "container supports the function"):
399
400             <table>
401                 <tr>
402                     <th>Container</th>
403                     <th>\p find_with</th>
404                     <th>\p erse_with</th>
405                 </tr>
406                 <tr>
407                     <td> \p std::list</td>
408                     <td>+</td>
409                     <td>+</td>
410                 </tr>
411                 <tr>
412                     <td> \p std::vector</td>
413                     <td>+</td>
414                     <td>+</td>
415                 </tr>
416                 <tr>
417                     <td> \p std::set</td>
418                     <td>-</td>
419                     <td>-</td>
420                 </tr>
421                 <tr>
422                     <td> \p std::unordered_set</td>
423                     <td>-</td>
424                     <td>-</td>
425                 </tr>
426                 <tr>
427                     <td> \p boost::container::slist</td>
428                     <td>+</td>
429                     <td>+</td>
430                 </tr>
431                 <tr>
432                     <td> \p boost::container::list</td>
433                     <td>+</td>
434                     <td>+</td>
435                 </tr>
436                 <tr>
437                     <td> \p boost::container::vector</td>
438                     <td>+</td>
439                     <td>+</td>
440                 </tr>
441                 <tr>
442                     <td> \p boost::container::stable_vector</td>
443                     <td>+</td>
444                     <td>+</td>
445                 </tr>
446                 <tr>
447                     <td> \p boost::container::set</td>
448                     <td>-</td>
449                     <td>-</td>
450                 </tr>
451                 <tr>
452                     <td> \p boost::container::flat_set</td>
453                     <td>-</td>
454                     <td>-</td>
455                 </tr>
456                 <tr>
457                     <td> \p boost::unordered_set</td>
458                     <td>-</td>
459                     <td>-</td>
460                 </tr>
461             </table>
462     */
463     template <class Container, typename... Options>
464     class StripedSet: protected intrusive::StripedSet<Container, Options...>
465     {
466         //@cond
467         typedef intrusive::StripedSet<Container, Options...>  base_class;
468         //@endcond
469     public:
470         //@cond
471         typedef typename base_class::default_options    default_options;
472         typedef typename base_class::options            options;
473         //@endcond
474
475         typedef Container                           underlying_container_type   ;   ///< original intrusive container type for the bucket
476         typedef typename base_class::bucket_type    bucket_type ;   ///< container type adapted for hash set
477         typedef typename bucket_type::value_type    value_type  ;   ///< value type stored in the set
478
479         typedef typename base_class::hash               hash            ; ///< Hash functor
480         typedef typename base_class::item_counter       item_counter    ; ///< Item counter
481         typedef typename base_class::resizing_policy    resizing_policy ; ///< Resizing policy
482         typedef typename base_class::allocator_type     allocator_type  ; ///< allocator type specified in options.
483         typedef typename base_class::mutex_policy       mutex_policy    ; ///< Mutex policy
484
485         //@cond
486         typedef cds::container::striped_set::implementation_tag implementation_tag;
487         //@endcond
488
489     protected:
490         //@cond
491         typedef typename base_class::scoped_cell_lock   scoped_cell_lock;
492         typedef typename base_class::scoped_full_lock   scoped_full_lock;
493         typedef typename base_class::scoped_resize_lock scoped_resize_lock;
494         //@endcond
495
496     public:
497         /// Default ctor. The initial capacity is 16.
498         StripedSet()
499         : base_class()
500         {}
501
502         /// Ctor with initial capacity specified
503         StripedSet(
504             size_t nCapacity    ///< Initial size of bucket table and lock array. Must be power of two, the minimum is 16.
505         ) : base_class( nCapacity )
506         {}
507
508         /// Ctor with resizing policy (copy semantics)
509         /**
510             This constructor initializes m_ResizingPolicy member with copy of \p resizingPolicy parameter
511         */
512         StripedSet(
513             size_t nCapacity    ///< Initial size of bucket table and lock array. Must be power of two, the minimum is 16.
514             ,resizing_policy const& resizingPolicy  ///< Resizing policy
515         ) : base_class( nCapacity, resizingPolicy )
516         {}
517
518         /// Ctor with resizing policy (move semantics)
519         /**
520             This constructor initializes m_ResizingPolicy member moving \p resizingPolicy parameter
521             Move semantics is used. Available only for the compilers that supports C++11 rvalue reference.
522         */
523         StripedSet(
524             size_t nCapacity    ///< Initial size of bucket table and lock array. Must be power of two, the minimum is 16.
525             ,resizing_policy&& resizingPolicy  ///< Resizing policy
526             ) : base_class( nCapacity, std::forward<resizing_policy>(resizingPolicy) )
527         {}
528
529         /// Destructor destroys internal data
530         ~StripedSet()
531         {}
532
533     public:
534         /// Inserts new node
535         /**
536             The function creates a node with copy of \p val value
537             and then inserts the node created into the set.
538
539             The type \p Q should contain as minimum the complete key for the node.
540             The object of \p value_type should be constructible from a value of type \p Q.
541             In trivial case, \p Q is equal to \p value_type.
542
543             Returns \p true if \p val is inserted into the set, \p false otherwise.
544         */
545         template <typename Q>
546         bool insert( Q const& val )
547         {
548             return insert( val, []( value_type& ) {} );
549         }
550
551         /// Inserts new node
552         /**
553             The function allows to split creating of new item into two part:
554             - create item with key only
555             - insert new item into the set
556             - if inserting is success, calls \p f functor to initialize value-field of new item .
557
558             The functor signature is:
559             \code
560                 void func( value_type& item );
561             \endcode
562             where \p item is the item inserted.
563
564             The type \p Q can differ from \p value_type of items storing in the set.
565             Therefore, the \p value_type should be constructible from type \p Q.
566
567             The user-defined functor is called only if the inserting is success.
568         */
569         template <typename Q, typename Func>
570         bool insert( Q const& val, Func f )
571         {
572             bool bOk;
573             bool bResize;
574             size_t nHash = base_class::hashing( val );
575             bucket_type * pBucket;
576             {
577                 scoped_cell_lock sl( base_class::m_MutexPolicy, nHash );
578                 pBucket = base_class::bucket( nHash );
579                 bOk = pBucket->insert( val, f );
580                 bResize = bOk && base_class::m_ResizingPolicy( ++base_class::m_ItemCounter, *this, *pBucket );
581             }
582
583             if ( bResize )
584                 base_class::resize();
585             return bOk;
586         }
587
588         /// Inserts data of type \p %value_type constructed with <tt>std::forward<Args>(args)...</tt>
589         /**
590             Returns \p true if inserting successful, \p false otherwise.
591         */
592         template <typename... Args>
593         bool emplace( Args&&... args )
594         {
595             bool bOk;
596             bool bResize;
597             size_t nHash = base_class::hashing( value_type( std::forward<Args>(args)...));
598             bucket_type * pBucket;
599             {
600                 scoped_cell_lock sl( base_class::m_MutexPolicy, nHash );
601                 pBucket = base_class::bucket( nHash );
602
603                 bOk = pBucket->emplace( std::forward<Args>(args)...);
604                 bResize = bOk && base_class::m_ResizingPolicy( ++base_class::m_ItemCounter, *this, *pBucket );
605             }
606
607             if ( bResize )
608                 base_class::resize();
609             return bOk;
610         }
611
612         /// Ensures that the \p val exists in the set
613         /**
614             The operation performs inserting or changing data.
615
616             If the \p val key not found in the set, then the new item created from \p val
617             is inserted into the set. Otherwise, the functor \p func is called with the item found.
618             The functor \p Func should be a function with signature:
619             \code
620                 void func( bool bNew, value_type& item, const Q& val );
621             \endcode
622             or a functor:
623             \code
624                 struct my_functor {
625                     void operator()( bool bNew, value_type& item, const Q& val );
626                 };
627             \endcode
628
629             with arguments:
630             - \p bNew - \p true if the item has been inserted, \p false otherwise
631             - \p item - item of the list
632             - \p val - argument \p val passed into the \p ensure function
633
634             The functor can change non-key fields of the \p item.
635
636             Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
637             \p second is true if new item has been added or \p false if the item with \p val key
638             already exists.
639         */
640         template <typename Q, typename Func>
641         std::pair<bool, bool> ensure( Q const& val, Func func )
642         {
643             std::pair<bool, bool> result;
644             bool bResize;
645             size_t nHash = base_class::hashing( val );
646             bucket_type * pBucket;
647             {
648                 scoped_cell_lock sl( base_class::m_MutexPolicy, nHash );
649                 pBucket = base_class::bucket( nHash );
650
651                 result = pBucket->ensure( val, func );
652                 bResize = result.first && result.second && base_class::m_ResizingPolicy( ++base_class::m_ItemCounter, *this, *pBucket );
653             }
654
655             if ( bResize )
656                 base_class::resize();
657             return result;
658         }
659
660         /// Delete \p key from the set
661         /** \anchor cds_nonintrusive_StripedSet_erase
662
663             The set item comparator should be able to compare the type \p value_type and the type \p Q.
664             Return \p true if key is found and deleted, \p false otherwise
665         */
666         template <typename Q>
667         bool erase( Q const& key )
668         {
669             return erase( key, [](value_type const&) {} );
670         }
671
672         /// Deletes the item from the set using \p pred predicate for searching
673         /**
674             The function is an analog of \ref cds_nonintrusive_StripedSet_erase "erase(Q const&)"
675             but \p pred is used for key comparing.
676             \p Less functor has the interface like \p std::less.
677             \p pred must imply the same element order as the comparator used for building the set.
678
679             @note This function is enabled if the compiler supports C++11
680             default template arguments for function template <b>and</b> the underlying container
681             supports \p %erase_with feature.
682         */
683         template < typename Q, typename Less
684             ,typename Bucket = bucket_type, typename = typename std::enable_if< Bucket::has_erase_with >::type >
685         bool erase_with( Q const& key, Less pred )
686         {
687             return erase_with( key, pred, [](value_type const&) {} );
688         }
689
690         /// Delete \p key from the set
691         /** \anchor cds_nonintrusive_StripedSet_erase_func
692
693             The function searches an item with key \p key, calls \p f functor with item found
694             and deletes it. If \p key is not found, the functor is not called.
695
696             The functor \p Func interface is:
697             \code
698             struct functor {
699                 void operator()(value_type const& val);
700             };
701             \endcode
702
703             Return \p true if key is found and deleted, \p false otherwise
704         */
705         template <typename Q, typename Func>
706         bool erase( Q const& key, Func f )
707         {
708             bool bOk;
709             size_t nHash = base_class::hashing( key );
710             {
711                 scoped_cell_lock sl( base_class::m_MutexPolicy, nHash );
712                 bucket_type * pBucket = base_class::bucket( nHash );
713
714                 bOk = pBucket->erase( key, f );
715             }
716
717             if ( bOk )
718                 --base_class::m_ItemCounter;
719             return bOk;
720         }
721
722         /// Deletes the item from the set using \p pred predicate for searching
723         /**
724             The function is an analog of \ref cds_nonintrusive_StripedSet_erase_func "erase(Q const&, Func)"
725             but \p pred is used for key comparing.
726             \p Less functor has the interface like \p std::less.
727             \p pred must imply the same element order as the comparator used for building the set.
728
729             @note This function is enabled if the compiler supports C++11
730             default template arguments for function template <b>and</b> the underlying container
731             supports \p %erase_with feature.
732         */
733         template < typename Q, typename Less, typename Func
734             , typename Bucket = bucket_type, typename = typename std::enable_if< Bucket::has_erase_with >::type >
735         bool erase_with( Q const& key, Less pred, Func f )
736         {
737             bool bOk;
738             size_t nHash = base_class::hashing( key );
739             {
740                 scoped_cell_lock sl( base_class::m_MutexPolicy, nHash );
741                 bucket_type * pBucket = base_class::bucket( nHash );
742
743                 bOk = pBucket->erase( key, pred, f );
744             }
745
746             if ( bOk )
747                 --base_class::m_ItemCounter;
748             return bOk;
749         }
750
751         /// Find the key \p val
752         /** \anchor cds_nonintrusive_StripedSet_find_func
753
754             The function searches the item with key equal to \p val and calls the functor \p f for item found.
755             The interface of \p Func functor is:
756             \code
757             struct functor {
758                 void operator()( value_type& item, Q& val );
759             };
760             \endcode
761             where \p item is the item found, \p val is the <tt>find</tt> function argument.
762
763             The functor can change non-key fields of \p item.
764             The \p val argument is non-const since it can be used as \p f functor destination i.e., the functor
765             can modify both arguments.
766
767             The type \p Q can differ from \p value_type of items storing in the container.
768             Therefore, the \p value_type should be comparable with type \p Q.
769
770             The function returns \p true if \p val is found, \p false otherwise.
771         */
772         template <typename Q, typename Func>
773         bool find( Q& val, Func f )
774         {
775             return base_class::find( val, f );
776         }
777
778         /// Find the key \p val using \p pred predicate
779         /**
780             The function is an analog of \ref cds_nonintrusive_StripedSet_find_func "find(Q&, Func)"
781             but \p pred is used for key comparing
782             \p Less has the interface like \p std::less.
783             \p pred must imply the same element order as the comparator used for building the set.
784
785             @note This function is enabled if the compiler supports C++11
786             default template arguments for function template <b>and</b> the underlying container
787             supports \p %find_with feature.
788         */
789         template <typename Q, typename Less, typename Func
790             , typename Bucket = bucket_type, typename = typename std::enable_if< Bucket::has_find_with >::type >
791         bool find_with( Q& val, Less pred, Func f )
792         {
793             return base_class::find_with( val, pred, f );
794         }
795
796         /// Find the key \p val
797         /** \anchor cds_nonintrusive_StripedSet_find_cfunc
798
799             The function searches the item with key equal to \p val and calls the functor \p f for item found.
800             The interface of \p Func functor is:
801             \code
802             struct functor {
803                 void operator()( value_type& item, Q const& val );
804             };
805             \endcode
806             where \p item is the item found, \p val is the <tt>find</tt> function argument.
807
808             The functor can change non-key fields of \p item.
809
810             The type \p Q can differ from \p value_type of items storing in the container.
811             Therefore, the \p value_type should be comparable with type \p Q.
812
813             The function returns \p true if \p val is found, \p false otherwise.
814         */
815         template <typename Q, typename Func>
816         bool find( Q const& val, Func f )
817         {
818             return base_class::find( val, f );
819         }
820
821         /// Find the key \p val using \p pred predicate
822         /**
823             The function is an analog of \ref cds_nonintrusive_StripedSet_find_cfunc "find(Q const&, Func)"
824             but \p pred is used for key comparing
825             \p Less has the interface like \p std::less.
826             \p pred must imply the same element order as the comparator used for building the set.
827
828             @note This function is enabled if the compiler supports C++11
829             default template arguments for function template <b>and</b> the underlying container
830             supports \p %find_with feature.
831         */
832         template <typename Q, typename Less, typename Func
833             , typename Bucket = bucket_type, typename = typename std::enable_if< Bucket::has_find_with >::type >
834         bool find_with( Q const& val, Less pred, Func f )
835         {
836             return base_class::find_with( val, pred, f );
837         }
838
839         /// Find the key \p val
840         /** \anchor cds_nonintrusive_StripedSet_find_val
841
842             The function searches the item with key equal to \p val
843             and returns \p true if it is found, and \p false otherwise.
844
845             Note the hash functor specified for class \p Traits template parameter
846             should accept a parameter of type \p Q that can be not the same as \p value_type.
847         */
848         template <typename Q>
849         bool find( Q const& val )
850         {
851             return base_class::find( val );
852         }
853
854         /// Find the key \p val using \p pred predicate
855         /**
856             The function is an analog of \ref cds_nonintrusive_StripedSet_find_val "find(Q const&)"
857             but \p pred is used for key comparing
858             \p Less has the interface like \p std::less.
859             \p pred must imply the same element order as the comparator used for building the set.
860
861             @note This function is enabled if the compiler supports C++11
862             default template arguments for function template <b>and</b> the underlying container
863             supports \p %find_with feature.
864         */
865         template <typename Q, typename Less
866             , typename Bucket = bucket_type, typename = typename std::enable_if< Bucket::has_find_with >::type >
867         bool find_with( Q const& val, Less pred )
868         {
869             return base_class::find_with( val, pred );
870         }
871
872         /// Clears the set
873         /**
874             The function erases all items from the set.
875         */
876         void clear()
877         {
878             return base_class::clear();
879         }
880
881         /// Checks if the set is empty
882         /**
883             Emptiness is checked by item counting: if item count is zero then the set is empty.
884         */
885         bool empty() const
886         {
887             return base_class::empty();
888         }
889
890         /// Returns item count in the set
891         size_t size() const
892         {
893             return base_class::size();
894         }
895
896         /// Returns the size of hash table
897         /**
898             The hash table size is non-constant and can be increased via resizing.
899         */
900         size_t bucket_count() const
901         {
902             return base_class::bucket_count();
903         }
904
905         /// Returns lock array size
906         size_t lock_count() const
907         {
908             return base_class::lock_count();
909         }
910
911         /// Returns resizing policy object
912         resizing_policy& get_resizing_policy()
913         {
914             return base_class::get_resizing_policy();
915         }
916
917         /// Returns resizing policy (const version)
918         resizing_policy const& get_resizing_policy() const
919         {
920             return base_class::get_resizing_policy();
921         }
922     };
923
924 }} // namespace cds::container
925
926
927 #endif // #ifndef CDSLIB_CONTAINER_STRIPED_SET_H