Merge branch 'dev' of github.com:khizmax/libcds into dev
[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     protected:
486         //@cond
487         typedef typename base_class::scoped_cell_lock   scoped_cell_lock;
488         typedef typename base_class::scoped_full_lock   scoped_full_lock;
489         typedef typename base_class::scoped_resize_lock scoped_resize_lock;
490         //@endcond
491
492     public:
493         /// Default ctor. The initial capacity is 16.
494         StripedSet()
495             : base_class()
496         {}
497
498         /// Ctor with initial capacity specified
499         StripedSet(
500             size_t nCapacity    ///< Initial size of bucket table and lock array. Must be power of two, the minimum is 16.
501         ) 
502             : base_class( nCapacity )
503         {}
504
505         /// Ctor with resizing policy (copy semantics)
506         /**
507             This constructor initializes m_ResizingPolicy member with copy of \p resizingPolicy parameter
508         */
509         StripedSet(
510             size_t nCapacity    ///< Initial size of bucket table and lock array. Must be power of two, the minimum is 16.
511             ,resizing_policy const& resizingPolicy  ///< Resizing policy
512         ) 
513             : base_class( nCapacity, resizingPolicy )
514         {}
515
516         /// Ctor with resizing policy (move semantics)
517         /**
518             This constructor initializes m_ResizingPolicy member moving \p resizingPolicy parameter
519             Move semantics is used. Available only for the compilers that supports C++11 rvalue reference.
520         */
521         StripedSet(
522             size_t nCapacity    ///< Initial size of bucket table and lock array. Must be power of two, the minimum is 16.
523             ,resizing_policy&& resizingPolicy  ///< Resizing policy
524         ) 
525             : base_class( nCapacity, std::forward<resizing_policy>(resizingPolicy) )
526         {}
527
528         /// Destructor destroys internal data
529         ~StripedSet()
530         {}
531
532     public:
533         /// Inserts new node
534         /**
535             The function creates a node with copy of \p val value
536             and then inserts the node created into the set.
537
538             The type \p Q should contain as minimum the complete key for the node.
539             The object of \p value_type should be constructible from a value of type \p Q.
540             In trivial case, \p Q is equal to \p value_type.
541
542             Returns \p true if \p val is inserted into the set, \p false otherwise.
543         */
544         template <typename Q>
545         bool insert( Q const& val )
546         {
547             return insert( val, []( value_type& ) {} );
548         }
549
550         /// Inserts new node
551         /**
552             The function allows to split creating of new item into two part:
553             - create item with key only
554             - insert new item into the set
555             - if inserting is success, calls \p f functor to initialize value-field of new item .
556
557             The functor signature is:
558             \code
559                 void func( value_type& item );
560             \endcode
561             where \p item is the item inserted.
562
563             The type \p Q can differ from \p value_type of items storing in the set.
564             Therefore, the \p value_type should be constructible from type \p Q.
565
566             The user-defined functor is called only if the inserting is success.
567         */
568         template <typename Q, typename Func>
569         bool insert( Q const& val, Func f )
570         {
571             bool bOk;
572             bool bResize;
573             size_t nHash = base_class::hashing( val );
574             bucket_type * pBucket;
575             {
576                 scoped_cell_lock sl( base_class::m_MutexPolicy, nHash );
577                 pBucket = base_class::bucket( nHash );
578                 bOk = pBucket->insert( val, f );
579                 bResize = bOk && base_class::m_ResizingPolicy( ++base_class::m_ItemCounter, *this, *pBucket );
580             }
581
582             if ( bResize )
583                 base_class::resize();
584             return bOk;
585         }
586
587         /// Inserts data of type \p %value_type constructed with <tt>std::forward<Args>(args)...</tt>
588         /**
589             Returns \p true if inserting successful, \p false otherwise.
590         */
591         template <typename... Args>
592         bool emplace( Args&&... args )
593         {
594             bool bOk;
595             bool bResize;
596             size_t nHash = base_class::hashing( value_type( std::forward<Args>(args)...));
597             bucket_type * pBucket;
598             {
599                 scoped_cell_lock sl( base_class::m_MutexPolicy, nHash );
600                 pBucket = base_class::bucket( nHash );
601
602                 bOk = pBucket->emplace( std::forward<Args>(args)...);
603                 bResize = bOk && base_class::m_ResizingPolicy( ++base_class::m_ItemCounter, *this, *pBucket );
604             }
605
606             if ( bResize )
607                 base_class::resize();
608             return bOk;
609         }
610
611         /// Updates the node
612         /**
613             The operation performs inserting or changing data with lock-free manner.
614
615             If \p key is not found in the set, then \p key is inserted iff \p bAllowInsert is \p true.
616             Otherwise, the functor \p func is called with item found.
617
618             The functor signature is:
619             \code
620                 struct my_functor {
621                     void operator()( bool bNew, value_type& item, const Q& val );
622                 };
623             \endcode
624             with arguments:
625             - \p bNew - \p true if the item has been inserted, \p false otherwise
626             - \p item - item of the set
627             - \p val - argument \p val passed into the \p %update() function
628
629             The functor may change non-key fields of the \p item.
630
631             Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
632             \p second is true if new item has been added or \p false if the item with \p key
633             already is in the map.
634         */
635         template <typename Q, typename Func>
636         std::pair<bool, bool> update( Q const& val, Func func, bool bAllowInsert = true )
637         {
638             std::pair<bool, bool> result;
639             bool bResize;
640             size_t nHash = base_class::hashing( val );
641             bucket_type * pBucket;
642             {
643                 scoped_cell_lock sl( base_class::m_MutexPolicy, nHash );
644                 pBucket = base_class::bucket( nHash );
645
646                 result = pBucket->update( val, func, bAllowInsert );
647                 bResize = result.first && result.second && base_class::m_ResizingPolicy( ++base_class::m_ItemCounter, *this, *pBucket );
648             }
649
650             if ( bResize )
651                 base_class::resize();
652             return result;
653         }
654         //@cond
655         template <typename Q, typename Func>
656         CDS_DEPRECATED("ensure() is deprecated, use update()")
657         std::pair<bool, bool> ensure( Q const& val, Func func )
658         {
659             return update( val, func, true );
660         }
661         //@endcond
662
663         /// Delete \p key from the set
664         /** \anchor cds_nonintrusive_StripedSet_erase
665
666             The set item comparator should be able to compare the type \p value_type and the type \p Q.
667             Return \p true if key is found and deleted, \p false otherwise
668         */
669         template <typename Q>
670         bool erase( Q const& key )
671         {
672             return erase( key, [](value_type const&) {} );
673         }
674
675         /// Deletes the item from the set using \p pred predicate for searching
676         /**
677             The function is an analog of \ref cds_nonintrusive_StripedSet_erase "erase(Q const&)"
678             but \p pred is used for key comparing.
679             \p Less functor has the interface like \p std::less.
680             \p pred must imply the same element order as the comparator used for building the set.
681
682             @note This function is enabled if the compiler supports C++11
683             default template arguments for function template <b>and</b> the underlying container
684             supports \p %erase_with feature.
685         */
686         template < typename Q, typename Less
687             ,typename Bucket = bucket_type, typename = typename std::enable_if< Bucket::has_erase_with >::type >
688         bool erase_with( Q const& key, Less pred )
689         {
690             return erase_with( key, pred, [](value_type const&) {} );
691         }
692
693         /// Delete \p key from the set
694         /** \anchor cds_nonintrusive_StripedSet_erase_func
695
696             The function searches an item with key \p key, calls \p f functor with item found
697             and deletes it. If \p key is not found, the functor is not called.
698
699             The functor \p Func interface is:
700             \code
701             struct functor {
702                 void operator()(value_type const& val);
703             };
704             \endcode
705
706             Return \p true if key is found and deleted, \p false otherwise
707         */
708         template <typename Q, typename Func>
709         bool erase( Q const& key, Func f )
710         {
711             bool bOk;
712             size_t nHash = base_class::hashing( key );
713             {
714                 scoped_cell_lock sl( base_class::m_MutexPolicy, nHash );
715                 bucket_type * pBucket = base_class::bucket( nHash );
716
717                 bOk = pBucket->erase( key, f );
718             }
719
720             if ( bOk )
721                 --base_class::m_ItemCounter;
722             return bOk;
723         }
724
725         /// Deletes the item from the set using \p pred predicate for searching
726         /**
727             The function is an analog of \ref cds_nonintrusive_StripedSet_erase_func "erase(Q const&, Func)"
728             but \p pred is used for key comparing.
729             \p Less functor has the interface like \p std::less.
730             \p pred must imply the same element order as the comparator used for building the set.
731
732             @note This function is enabled if the compiler supports C++11
733             default template arguments for function template <b>and</b> the underlying container
734             supports \p %erase_with feature.
735         */
736         template < typename Q, typename Less, typename Func
737             , typename Bucket = bucket_type, typename = typename std::enable_if< Bucket::has_erase_with >::type >
738         bool erase_with( Q const& key, Less pred, Func f )
739         {
740             bool bOk;
741             size_t nHash = base_class::hashing( key );
742             {
743                 scoped_cell_lock sl( base_class::m_MutexPolicy, nHash );
744                 bucket_type * pBucket = base_class::bucket( nHash );
745
746                 bOk = pBucket->erase( key, pred, f );
747             }
748
749             if ( bOk )
750                 --base_class::m_ItemCounter;
751             return bOk;
752         }
753
754         /// Find the key \p val
755         /** \anchor cds_nonintrusive_StripedSet_find_func
756
757             The function searches the item with key equal to \p val and calls the functor \p f for item found.
758             The interface of \p Func functor is:
759             \code
760             struct functor {
761                 void operator()( value_type& item, Q& val );
762             };
763             \endcode
764             where \p item is the item found, \p val is the <tt>find</tt> function argument.
765
766             The functor can change non-key fields of \p item.
767             The \p val argument is non-const since it can be used as \p f functor destination i.e., the functor
768             can modify both arguments.
769
770             The type \p Q can differ from \p value_type of items storing in the container.
771             Therefore, the \p value_type should be comparable with type \p Q.
772
773             The function returns \p true if \p val is found, \p false otherwise.
774         */
775         template <typename Q, typename Func>
776         bool find( Q& val, Func f )
777         {
778             return base_class::find( val, f );
779         }
780
781         /// Find the key \p val using \p pred predicate
782         /**
783             The function is an analog of \ref cds_nonintrusive_StripedSet_find_func "find(Q&, Func)"
784             but \p pred is used for key comparing
785             \p Less has the interface like \p std::less.
786             \p pred must imply the same element order as the comparator used for building the set.
787
788             @note This function is enabled if the compiler supports C++11
789             default template arguments for function template <b>and</b> the underlying container
790             supports \p %find_with feature.
791         */
792         template <typename Q, typename Less, typename Func
793             , typename Bucket = bucket_type, typename = typename std::enable_if< Bucket::has_find_with >::type >
794         bool find_with( Q& val, Less pred, Func f )
795         {
796             return base_class::find_with( val, pred, f );
797         }
798
799         /// Find the key \p val
800         /** \anchor cds_nonintrusive_StripedSet_find_cfunc
801
802             The function searches the item with key equal to \p val and calls the functor \p f for item found.
803             The interface of \p Func functor is:
804             \code
805             struct functor {
806                 void operator()( value_type& item, Q const& val );
807             };
808             \endcode
809             where \p item is the item found, \p val is the <tt>find</tt> function argument.
810
811             The functor can change non-key fields of \p item.
812
813             The type \p Q can differ from \p value_type of items storing in the container.
814             Therefore, the \p value_type should be comparable with type \p Q.
815
816             The function returns \p true if \p val is found, \p false otherwise.
817         */
818         template <typename Q, typename Func>
819         bool find( Q const& val, Func f )
820         {
821             return base_class::find( val, f );
822         }
823
824         /// Find the key \p val using \p pred predicate
825         /**
826             The function is an analog of \ref cds_nonintrusive_StripedSet_find_cfunc "find(Q const&, Func)"
827             but \p pred is used for key comparing
828             \p Less has the interface like \p std::less.
829             \p pred must imply the same element order as the comparator used for building the set.
830
831             @note This function is enabled if the compiler supports C++11
832             default template arguments for function template <b>and</b> the underlying container
833             supports \p %find_with feature.
834         */
835         template <typename Q, typename Less, typename Func
836             , typename Bucket = bucket_type, typename = typename std::enable_if< Bucket::has_find_with >::type >
837         bool find_with( Q const& val, Less pred, Func f )
838         {
839             return base_class::find_with( val, pred, f );
840         }
841
842         /// Checks whether the set contains \p key
843         /**
844             The function searches the item with key equal to \p key
845             and returns \p true if it is found, and \p false otherwise.
846
847             Note the hash functor specified for class \p Traits template parameter
848             should accept a parameter of type \p Q that can be not the same as \p value_type.
849             Otherwise, you may use \p contains( Q const&, Less pred ) functions with explicit predicate for key comparing.
850         */
851         template <typename Q>
852         bool contains( Q const& key )
853         {
854             return base_class::contains( key );
855         }
856         //@cond
857         template <typename Q>
858         CDS_DEPRECATED("use contains()")
859         bool find( Q const& key )
860         {
861             return contains( key );
862         }
863         //@endcond
864
865         /// Checks whether the map contains \p key using \p pred predicate for searching
866         /**
867             The function is similar to <tt>contains( key )</tt> but \p pred is used for key comparing.
868             \p Less functor has the interface like \p std::less.
869             \p Less must imply the same element order as the comparator used for building the map.
870         */
871         template <typename Q, typename Less
872             , typename Bucket = bucket_type, typename = typename std::enable_if< Bucket::has_find_with >::type >
873         bool contains( Q const& key, Less pred )
874         {
875             return base_class::contains( key, pred );
876         }
877         //@cond
878         template <typename Q, typename Less
879             , typename Bucket = bucket_type, typename = typename std::enable_if< Bucket::has_find_with >::type >
880         CDS_DEPRECATED("use contains()")
881         bool find_with( Q const& val, Less pred )
882         {
883             return contains( val, pred );
884         }
885         //@endcond
886
887         /// Clears the set
888         /**
889             The function erases all items from the set.
890         */
891         void clear()
892         {
893             return base_class::clear();
894         }
895
896         /// Checks if the set is empty
897         /**
898             Emptiness is checked by item counting: if item count is zero then the set is empty.
899         */
900         bool empty() const
901         {
902             return base_class::empty();
903         }
904
905         /// Returns item count in the set
906         size_t size() const
907         {
908             return base_class::size();
909         }
910
911         /// Returns the size of hash table
912         /**
913             The hash table size is non-constant and can be increased via resizing.
914         */
915         size_t bucket_count() const
916         {
917             return base_class::bucket_count();
918         }
919
920         /// Returns lock array size
921         size_t lock_count() const
922         {
923             return base_class::lock_count();
924         }
925
926         /// Returns resizing policy object
927         resizing_policy& get_resizing_policy()
928         {
929             return base_class::get_resizing_policy();
930         }
931
932         /// Returns resizing policy (const version)
933         resizing_policy const& get_resizing_policy() const
934         {
935             return base_class::get_resizing_policy();
936         }
937     };
938
939 }} // namespace cds::container
940
941
942 #endif // #ifndef CDSLIB_CONTAINER_STRIPED_SET_H