3 #ifndef __CDS_CONTAINER_LAZY_KVLIST_NOGC_H
4 #define __CDS_CONTAINER_LAZY_KVLIST_NOGC_H
7 #include <cds/container/details/lazy_list_base.h>
8 #include <cds/intrusive/lazy_list_nogc.h>
9 #include <cds/container/details/make_lazy_kvlist.h>
11 namespace cds { namespace container {
13 /// Lazy ordered list (key-value pair, template specialization for gc::nogc)
14 /** @ingroup cds_nonintrusive_list
16 This specialization is append-only list when no item
17 reclamation may be performed. The class does not support deleting of list item.
19 @copydetails cds_nonintrusive_LazyList_gc
24 #ifdef CDS_DOXYGEN_INVOKED
25 typename Traits = lazy_list::traits
30 class LazyKVList<gc::nogc, Key, Value, Traits>:
31 #ifdef CDS_DOXYGEN_INVOKED
32 protected intrusive::LazyList< gc::nogc, implementation_defined, Traits >
34 protected details::make_lazy_kvlist< cds::gc::nogc, Key, Value, Traits >::type
38 typedef details::make_lazy_kvlist< cds::gc::nogc, Key, Value, Traits > maker;
39 typedef typename maker::type base_class;
43 typedef cds::gc::nogc gc; ///< Garbage collector
44 #ifdef CDS_DOXYGEN_INVOKED
45 typedef Key key_type ; ///< Key type
46 typedef Value mapped_type ; ///< Type of value stored in the list
47 typedef std::pair<key_type const, mapped_type> value_type ; ///< key/value pair stored in the list
49 typedef typename maker::key_type key_type;
50 typedef typename maker::mapped_type mapped_type;
51 typedef typename maker::value_type value_type;
53 typedef typename base_class::back_off back_off; ///< Back-off strategy used
54 typedef typename maker::allocator_type allocator_type; ///< Allocator type used for allocate/deallocate the nodes
55 typedef typename base_class::item_counter item_counter; ///< Item counting policy used
56 typedef typename maker::key_comparator key_comparator; ///< key comparison functor
57 typedef typename base_class::memory_model memory_model; ///< Memory ordering. See cds::opt::memory_model option
61 typedef typename base_class::value_type node_type;
62 typedef typename maker::cxx_allocator cxx_allocator;
63 typedef typename maker::node_deallocator node_deallocator;
64 typedef typename maker::intrusive_traits::compare intrusive_key_comparator;
65 typedef typename base_class::node_type head_type;
71 static node_type * alloc_node(const K& key)
73 return cxx_allocator().New( key );
76 template <typename K, typename V>
77 static node_type * alloc_node( const K& key, const V& val )
79 return cxx_allocator().New( key, val );
82 template <typename... Args>
83 static node_type * alloc_node( Args&&... args )
85 return cxx_allocator().MoveNew( std::forward<Args>(args)... );
88 static void free_node( node_type * pNode )
90 cxx_allocator().Delete( pNode );
93 struct node_disposer {
94 void operator()( node_type * pNode )
99 typedef std::unique_ptr< node_type, node_disposer > scoped_node_ptr;
103 return base_class::m_Head;
106 head_type const& head() const
108 return base_class::m_Head;
113 return base_class::m_Tail;
116 head_type const& tail() const
118 return base_class::m_Tail;
124 template <bool IsConst>
125 class iterator_type: protected base_class::template iterator_type<IsConst>
127 typedef typename base_class::template iterator_type<IsConst> iterator_base;
129 iterator_type( head_type const& refNode )
130 : iterator_base( const_cast<head_type *>( &refNode ))
133 explicit iterator_type( const iterator_base& it )
134 : iterator_base( it )
137 friend class LazyKVList;
140 explicit iterator_type( node_type& pNode )
141 : iterator_base( &pNode )
145 typedef typename cds::details::make_const_type<mapped_type, IsConst>::reference value_ref;
146 typedef typename cds::details::make_const_type<mapped_type, IsConst>::pointer value_ptr;
148 typedef typename cds::details::make_const_type<value_type, IsConst>::reference pair_ref;
149 typedef typename cds::details::make_const_type<value_type, IsConst>::pointer pair_ptr;
155 iterator_type( const iterator_type& src )
156 : iterator_base( src )
159 key_type const& key() const
161 typename iterator_base::value_ptr p = iterator_base::operator ->();
162 assert( p != nullptr );
163 return p->m_Data.first;
166 value_ref val() const
168 typename iterator_base::value_ptr p = iterator_base::operator ->();
169 assert( p != nullptr );
170 return p->m_Data.second;
173 pair_ptr operator ->() const
175 typename iterator_base::value_ptr p = iterator_base::operator ->();
176 return p ? &(p->m_Data) : nullptr;
179 pair_ref operator *() const
181 typename iterator_base::value_ref p = iterator_base::operator *();
186 iterator_type& operator ++()
188 iterator_base::operator ++();
193 iterator_type operator ++(int)
195 return iterator_base::operator ++(0);
199 bool operator ==(iterator_type<C> const& i ) const
201 return iterator_base::operator ==(i);
204 bool operator !=(iterator_type<C> const& i ) const
206 return iterator_base::operator !=(i);
214 The forward iterator for lazy list based on gc::nogc has pre- and post-increment operators.
216 The iterator interface to access item data:
217 - <tt> operator -> </tt> - returns a pointer to \ref value_type for iterator
218 - <tt> operator *</tt> - returns a reference (a const reference for \p const_iterator) to \ref value_type for iterator
219 - <tt> const key_type& key() </tt> - returns a key reference for iterator
220 - <tt> mapped_type& val() </tt> - retuns a value reference for iterator (const reference for \p const_iterator)
222 For both functions the iterator should not be equal to <tt> end() </tt>
224 typedef iterator_type<false> iterator;
226 /// Const forward iterator
228 For iterator's features and requirements see \ref iterator
230 typedef iterator_type<true> const_iterator;
232 /// Returns a forward iterator addressing the first element in a list
234 For empty list \code begin() == end() \endcode
238 iterator it( head() );
239 ++it ; // skip dummy head
243 /// Returns an iterator that addresses the location succeeding the last element in a list
245 Do not use the value returned by <tt>end</tt> function to access any item.
246 Internally, <tt>end</tt> returning value equals to nullptr.
248 The returned value can be used only to control reaching the end of the list.
249 For empty list \code begin() == end() \endcode
253 return iterator( tail());
256 /// Returns a forward const iterator addressing the first element in a list
258 const_iterator begin() const
260 const_iterator it( head() );
261 ++it ; // skip dummy head
264 const_iterator cbegin()
266 const_iterator it( head() );
267 ++it ; // skip dummy head
272 /// Returns an const iterator that addresses the location succeeding the last element in a list
274 const_iterator end() const
276 return const_iterator( tail());
278 const_iterator cend()
280 return const_iterator( tail());
286 iterator node_to_iterator( node_type * pNode )
289 return iterator( *pNode );
295 /// Default constructor
299 /// Desctructor clears the list
305 /// Inserts new node with key and default value
307 The function creates a node with \p key and default value, and then inserts the node created into the list.
310 - The \ref key_type should be constructible from value of type \p K.
311 In trivial case, \p K is equal to \ref key_type.
312 - The \ref mapped_type should be default-constructible.
314 Returns an iterator pointed to inserted value, or \p end() if inserting is failed
316 template <typename K>
317 iterator insert( const K& key )
319 return node_to_iterator( insert_at( head(), key ));
322 /// Inserts new node with a key and a value
324 The function creates a node with \p key and value \p val, and then inserts the node created into the list.
327 - The \ref key_type should be constructible from \p key of type \p K.
328 - The \ref mapped_type should be constructible from \p val of type \p V.
330 Returns an iterator pointed to inserted value, or \p end() if inserting is failed
332 template <typename K, typename V>
333 iterator insert( const K& key, const V& val )
335 // We cannot use insert with functor here
336 // because we cannot lock inserted node for updating
337 // Therefore, we use separate function
338 return node_to_iterator( insert_at( head(), key, val ));
341 /// Inserts new node and initialize it by a functor
343 This function inserts new node with key \p key and if inserting is successful then it calls
344 \p func functor with signature
345 \code void func( value_type& item ) ; endcode
349 void operator()( value_type& item );
353 The argument \p item of user-defined functor \p func is the reference
354 to the list's item inserted. <tt>item.second</tt> is a reference to item's value that may be changed.
355 The user-defined functor is called only if the inserting is successful.
357 The key_type should be constructible from value of type \p K.
359 The function allows to split creating of new item into two part:
360 - create item from \p key;
361 - insert new item into the list;
362 - if inserting is successful, initialize the value of item by calling \p f functor
364 This can be useful if complete initialization of object of \p mapped_type is heavyweight and
365 it is preferable that the initialization should be completed only if inserting is successful.
367 Returns an iterator pointed to inserted value, or \p end() if inserting is failed
369 template <typename K, typename Func>
370 iterator insert_key( const K& key, Func func )
372 return node_to_iterator( insert_key_at( head(), key, func ));
375 /// Ensures that the key \p key exists in the list
377 The operation inserts new item if the key \p key is not found in the list.
378 Otherwise, the function returns an iterator that points to item found.
380 Returns <tt> std::pair<iterator, bool> </tt> where \p first is an iterator pointing to
381 item found or inserted, \p second is true if new item has been added or \p false if the item
382 already is in the list.
384 template <typename K>
385 std::pair<iterator, bool> ensure( const K& key )
387 std::pair< node_type *, bool > ret = ensure_at( head(), key );
388 return std::make_pair( node_to_iterator( ret.first ), ret.second );
391 /// Inserts data of type \ref mapped_type constructed with <tt>std::forward<Args>(args)...</tt>
393 Returns an iterator pointed to inserted value, or \p end() if inserting is failed
395 template <typename... Args>
396 iterator emplace( Args&&... args )
398 return node_to_iterator( emplace_at( head(), std::forward<Args>(args)... ));
401 /// Find the key \p key
402 /** \anchor cds_nonintrusive_LazyKVList_nogc_find
403 The function searches the item with key equal to \p key
404 and returns an iterator pointed to item found if the key is found,
405 and \ref end() otherwise
407 template <typename Q>
408 iterator find( Q const& key )
410 return node_to_iterator( find_at( head(), key, intrusive_key_comparator() ) );
413 /// Finds the key \p val using \p pred predicate for searching
415 The function is an analog of \ref cds_nonintrusive_LazyKVList_nogc_find "find(Q const&)"
416 but \p pred is used for key comparing.
417 \p Less functor has the interface like \p std::less.
418 \p pred must imply the same element order as the comparator used for building the list.
420 template <typename Q, typename Less>
421 iterator find_with( Q const& key, Less pred )
423 return node_to_iterator( find_at( head(), key, typename maker::template less_wrapper<Less>::type() ) );
426 /// Check if the list is empty
429 return base_class::empty();
432 /// Returns list's item count
434 The value returned depends on opt::item_counter option. For atomicity::empty_item_counter,
435 this function always returns 0.
437 @note Even if you use real item counter and it returns 0, this fact is not mean that the list
438 is empty. To check list emptyness use \ref empty() method.
442 return base_class::size();
447 Post-condition: the list is empty
456 node_type * insert_node_at( head_type& refHead, node_type * pNode )
458 assert( pNode != nullptr );
459 scoped_node_ptr p( pNode );
460 if ( base_class::insert_at( &refHead, *p ))
466 template <typename K>
467 node_type * insert_at( head_type& refHead, const K& key )
469 return insert_node_at( refHead, alloc_node( key ));
472 template <typename K, typename V>
473 node_type * insert_at( head_type& refHead, const K& key, const V& val )
475 return insert_node_at( refHead, alloc_node( key, val ));
478 template <typename K, typename Func>
479 node_type * insert_key_at( head_type& refHead, const K& key, Func f )
481 scoped_node_ptr pNode( alloc_node( key ));
483 if ( base_class::insert_at( &refHead, *pNode )) {
485 return pNode.release();
492 template <typename K>
493 std::pair< node_type *, bool > ensure_at( head_type& refHead, const K& key )
495 scoped_node_ptr pNode( alloc_node( key ));
496 node_type * pItemFound = nullptr;
498 std::pair<bool, bool> ret = base_class::ensure_at( &refHead, *pNode, [&pItemFound](bool, node_type& item, node_type&){ pItemFound = &item; } );
499 if ( ret.first && ret.second )
502 assert( pItemFound != nullptr );
503 return std::make_pair( pItemFound, ret.second );
506 template <typename... Args>
507 node_type * emplace_at( head_type& refHead, Args&&... args )
509 return insert_node_at( refHead, alloc_node( std::forward<Args>(args)... ));
512 template <typename K, typename Compare>
513 node_type * find_at( head_type& refHead, const K& key, Compare cmp )
515 return base_class::find_at( &refHead, key, cmp );
519 template <typename K, typenam Compare, typename Func>
520 bool find_at( head_type& refHead, K& key, Compare cmp, Func f )
522 return base_class::find_at( &refHead, key, cmp, [&f]( node_type& node, K const& ){ f( node.m_Data ); });
528 }} // namespace cds::container
530 #endif // #ifndef __CDS_CONTAINER_LAZY_KVLIST_NOGC_H