49e07c06eba2f4d6290bca0a7cfb44c8402ae43e
[libcds.git] / cds / container / split_list_set_nogc.h
1 //$$CDS-header$$
2
3 #ifndef __CDS_CONTAINER_SPLIT_LIST_SET_NOGC_H
4 #define __CDS_CONTAINER_SPLIT_LIST_SET_NOGC_H
5
6 #include <cds/intrusive/split_list_nogc.h>
7 #include <cds/container/details/split_list_base.h>
8 #include <cds/gc/nogc.h>
9 #include <cds/container/details/make_split_list_set.h>
10
11 namespace cds { namespace container {
12
13     /// Split-ordered list set (template specialization for \p gc::nogc)
14     /** @ingroup cds_nonintrusive_set
15         \anchor cds_nonintrusive_SplitListSet_nogc
16
17         This specialization is so-called append-only container when no item
18         reclamation may be performed. The class does not support deleting of list item.
19
20         See \ref cds_nonintrusive_SplitListSet_hp "SplitListSet" for description of template parameters.
21
22         @warning Many member functions return an iterator pointing to an item.
23         The iterator can be used to set up field of the item,
24         but you should provide an exclusive access to it, 
25         see \ref cds_intrusive_item_creating "insert item troubleshooting".
26     */
27     template <
28         class T,
29 #ifdef CDS_DOXYGEN_INVOKED
30         class Traits = split_list::traits
31 #else
32         class Traits
33 #endif
34     >
35     class SplitListSet< cds::gc::nogc, T, Traits>
36 #ifdef CDS_DOXYGEN_INVOKED
37         :protected intrusive::SplitListSet<cds::gc::nogc, typename Traits::ordered_list, Traits>
38 #else
39         :protected details::make_split_list_set< cds::gc::nogc, T, typename Traits::ordered_list, split_list::details::wrap_set_traits<T, Traits> >::type
40 #endif
41     {
42     protected:
43         //@cond
44         typedef details::make_split_list_set< cds::gc::nogc, T, typename Traits::ordered_list, split_list::details::wrap_set_traits<T, Traits> > maker;
45         typedef typename maker::type  base_class;
46         //@endcond
47
48     public:
49         typedef cds::gc::nogc  gc;         ///< Garbage collector
50         typedef T              value_type; ///< type of value to be stored in the list
51         typedef Traits         traits;     ///< List traits
52
53         typedef typename maker::ordered_list      ordered_list;     ///< Underlying ordered list class
54         typedef typename base_class::key_comparator key_comparator; ///< key comparison functor
55
56         /// Hash functor for \ref value_type and all its derivatives that you use
57         typedef typename base_class::hash           hash;
58         typedef typename base_class::item_counter   item_counter; ///< Item counter type
59         typedef typename base_class::stat           stat; ///< Internal statistics
60
61     protected:
62         //@cond
63         typedef typename maker::cxx_node_allocator    cxx_node_allocator;
64         typedef typename maker::node_type             node_type;
65
66         template <typename Q>
67         static node_type * alloc_node(Q const& v )
68         {
69             return cxx_node_allocator().New( v );
70         }
71
72         template <typename... Args>
73         static node_type * alloc_node( Args&&... args )
74         {
75             return cxx_node_allocator().MoveNew( std::forward<Args>(args)...);
76         }
77
78         static void free_node( node_type * pNode )
79         {
80             cxx_node_allocator().Delete( pNode );
81         }
82
83         struct node_disposer {
84             void operator()( node_type * pNode )
85             {
86                 free_node( pNode );
87             }
88         };
89         typedef std::unique_ptr< node_type, node_disposer >     scoped_node_ptr;
90         //@endcond
91
92     public:
93         /// Initialize split-ordered list of default capacity
94         /**
95             The default capacity is defined in bucket table constructor.
96             See \p intrusive::split_list::expandable_bucket_table, \p intrusive::split_list::static_bucket_table
97             which selects by \p split_list::dynamic_bucket_table option.
98         */
99         SplitListSet()
100             : base_class()
101         {}
102
103         /// Initialize split-ordered list
104         SplitListSet(
105             size_t nItemCount           ///< estimated average of item count
106             , size_t nLoadFactor = 1    ///< load factor - average item count per bucket. Small integer up to 10, default is 1.
107             )
108             : base_class( nItemCount, nLoadFactor )
109         {}
110
111     protected:
112         /// Forward iterator
113         /**
114             \p IsConst - constness boolean flag
115
116             The forward iterator has the following features:
117             - it has no post-increment operator
118             - it depends on underlying ordered list iterator
119         */
120         template <bool IsConst>
121         class iterator_type: protected base_class::template iterator_type<IsConst>
122         {
123             //@cond
124             typedef typename base_class::template iterator_type<IsConst> iterator_base_class;
125             friend class SplitListSet;
126             //@endcond
127         public:
128             /// Value pointer type (const for const iterator)
129             typedef typename cds::details::make_const_type<value_type, IsConst>::pointer   value_ptr;
130             /// Value reference type (const for const iterator)
131             typedef typename cds::details::make_const_type<value_type, IsConst>::reference value_ref;
132
133         public:
134             /// Default ctor
135             iterator_type()
136             {}
137
138             /// Copy ctor
139             iterator_type( iterator_type const& src )
140                 : iterator_base_class( src )
141             {}
142
143         protected:
144             //@cond
145             explicit iterator_type( iterator_base_class const& src )
146                 : iterator_base_class( src )
147             {}
148             //@endcond
149
150         public:
151             /// Dereference operator
152             value_ptr operator ->() const
153             {
154                 return &(iterator_base_class::operator->()->m_Value);
155             }
156
157             /// Dereference operator
158             value_ref operator *() const
159             {
160                 return iterator_base_class::operator*().m_Value;
161             }
162
163             /// Pre-increment
164             iterator_type& operator ++()
165             {
166                 iterator_base_class::operator++();
167                 return *this;
168             }
169
170             /// Assignment operator
171             iterator_type& operator = (iterator_type const& src)
172             {
173                 iterator_base_class::operator=(src);
174                 return *this;
175             }
176
177             /// Equality operator
178             template <bool C>
179             bool operator ==(iterator_type<C> const& i ) const
180             {
181                 return iterator_base_class::operator==(i);
182             }
183
184             /// Equality operator
185             template <bool C>
186             bool operator !=(iterator_type<C> const& i ) const
187             {
188                 return iterator_base_class::operator!=(i);
189             }
190         };
191
192     public:
193         /// Forward iterator
194         typedef iterator_type<false>  iterator;
195
196         /// Const forward iterator
197         typedef iterator_type<true>    const_iterator;
198
199         /// Returns a forward iterator addressing the first element in a set
200         /**
201             For empty set \code begin() == end() \endcode
202         */
203         iterator begin()
204         {
205             return iterator( base_class::begin() );
206         }
207
208         /// Returns an iterator that addresses the location succeeding the last element in a set
209         /**
210             Do not use the value returned by <tt>end</tt> function to access any item.
211             The returned value can be used only to control reaching the end of the set.
212             For empty set \code begin() == end() \endcode
213         */
214         iterator end()
215         {
216             return iterator( base_class::end() );
217         }
218
219         /// Returns a forward const iterator addressing the first element in a set
220         const_iterator begin() const
221         {
222             return const_iterator( base_class::begin() );
223         }
224
225         /// Returns an const iterator that addresses the location succeeding the last element in a set
226         const_iterator end() const
227         {
228             return const_iterator( base_class::end() );
229         }
230
231     protected:
232         //@cond
233         iterator insert_node( node_type * pNode )
234         {
235             assert( pNode != nullptr );
236             scoped_node_ptr p(pNode);
237
238             iterator it( base_class::insert_( *pNode ));
239             if ( it != end() ) {
240                 p.release();
241                 return it;
242             }
243
244             return end();
245         }
246         //@endcond
247
248     public:
249         /// Inserts new node
250         /**
251             The function inserts \p val in the set if it does not contain
252             an item with key equal to \p val.
253             The \p value_type should be constructible from a value of type \p Q.
254
255             Return an iterator pointing to inserted item if success \p end() otherwise
256         */
257         template <typename Q>
258         iterator insert( const Q& val )
259         {
260             return insert_node( alloc_node( val ) );
261         }
262
263         /// Inserts data of type \p value_type created from \p args
264         /**
265             Return an iterator pointing to inserted item if success \p end() otherwise
266         */
267         template <typename... Args>
268         iterator emplace( Args&&... args )
269         {
270             return insert_node( alloc_node( std::forward<Args>(args)... ) );
271         }
272
273         /// Ensures that the item \p val exists in the set
274         /**
275             The operation inserts new item created from \p val if the key \p val is not found in the set.
276             Otherwise, the function returns an iterator that points to item found.
277             The \p value_type should be constructible from a value of type \p Q.
278
279             Returns <tt> std::pair<iterator, bool> </tt> where \p first is an iterator pointing to
280             item found or inserted, \p second is true if new item has been added or \p false if the item
281             already is in the set.
282         */
283         template <typename Q>
284         std::pair<iterator, bool> ensure( const Q& val )
285         {
286             scoped_node_ptr pNode( alloc_node( val ));
287
288             std::pair<typename base_class::iterator, bool> ret = base_class::ensure_( *pNode, [](bool /*bNew*/, node_type& /*item*/, node_type& /*val*/){} );
289             if ( ret.first != base_class::end() && ret.second ) {
290                 pNode.release();
291                 return std::make_pair( iterator(ret.first), ret.second );
292             }
293
294             return std::make_pair( iterator(ret.first), ret.second );
295         }
296
297         /// Find the key \p key
298         /** \anchor cds_nonintrusive_SplitListSet_nogc_find
299
300             The function searches the item with key equal to \p key
301             and returns an iterator pointed to item found if the key is found,
302             and \ref end() otherwise.
303         */
304         template <typename Q>
305         iterator find( Q const& key )
306         {
307             return iterator( base_class::find_( key ));
308         }
309
310         /// Finds the key \p key using \p pred predicate for searching
311         /**
312             The function is an analog of \ref cds_nonintrusive_SplitListSet_nogc_find "find(Q const&)"
313             but \p pred is used for key comparing.
314             \p Less functor has the interface like \p std::less.
315             \p Less must imply the same element order as the comparator used for building the set.
316         */
317         template <typename Q, typename Less>
318         iterator find_with( Q const& key, Less pred )
319         {
320             return iterator( base_class::find_with_( key, typename maker::template predicate_wrapper<Less>::type() ));
321         }
322
323         /// Checks if the set is empty
324         /**
325             Emptiness is checked by item counting: if item count is zero then the set is empty.
326             Thus, the correct item counting feature is an important part of split-list set implementation.
327         */
328         bool empty() const
329         {
330             return base_class::empty();
331         }
332
333         /// Returns item count in the set
334         size_t size() const
335         {
336             return base_class::size();
337         }
338
339         /// Returns internal statistics
340         stat const& statistics() const
341         {
342             return base_class::statistics();
343         }
344     };
345
346 }}  // namespace cds::container
347
348 #endif // #ifndef __CDS_CONTAINER_SPLIT_LIST_SET_NOGC_H