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 {
16 template <typename K, typename T, class Traits>
17 struct make_lazy_kvlist_nogc: public make_lazy_kvlist<gc::nogc, K, T, Traits>
19 typedef make_lazy_kvlist<cds::gc::nogc, K, T, Traits> base_maker;
20 typedef typename base_maker::node_type node_type;
22 struct type_traits: public base_maker::type_traits
24 typedef typename base_maker::node_deallocator disposer;
27 typedef intrusive::LazyList<cds::gc::nogc, node_type, type_traits> type;
30 } // namespace details
33 /// Lazy ordered list (key-value pair, template specialization for gc::nogc)
34 /** @ingroup cds_nonintrusive_list
36 This specialization is intended for so-called persistent usage when no item
37 reclamation may be performed. The class does not support deleting of list item.
39 Usually, ordered single-linked list is used as a building block for the hash table implementation.
40 The complexity of searching is <tt>O(N)</tt>.
42 See \ref cds_nonintrusive_LazyList_gc "LazyList" for description of template parameters.
44 The interface of the specialization is a little different.
49 #ifdef CDS_DOXYGEN_INVOKED
50 typename Traits = lazy_list::type_traits
55 class LazyKVList<gc::nogc, Key, Value, Traits>:
56 #ifdef CDS_DOXYGEN_INVOKED
57 protected intrusive::LazyList< gc::nogc, implementation_defined, Traits >
59 protected details::make_lazy_kvlist_nogc< Key, Value, Traits >::type
63 typedef details::make_lazy_kvlist_nogc< Key, Value, Traits > options;
64 typedef typename options::type base_class;
68 #ifdef CDS_DOXYGEN_INVOKED
69 typedef Key key_type ; ///< Key type
70 typedef Value mapped_type ; ///< Type of value stored in the list
71 typedef std::pair<key_type const, mapped_type> value_type ; ///< key/value pair stored in the list
73 typedef typename options::key_type key_type;
74 typedef typename options::value_type mapped_type;
75 typedef typename options::pair_type value_type;
77 typedef typename base_class::gc gc ; ///< Garbage collector used
78 typedef typename base_class::back_off back_off ; ///< Back-off strategy used
79 typedef typename options::allocator_type allocator_type ; ///< Allocator type used for allocate/deallocate the nodes
80 typedef typename base_class::item_counter item_counter ; ///< Item counting policy used
81 typedef typename options::key_comparator key_comparator ; ///< key comparison functor
82 typedef typename base_class::memory_model memory_model ; ///< Memory ordering. See cds::opt::memory_model option
86 typedef typename base_class::value_type node_type;
87 typedef typename options::cxx_allocator cxx_allocator;
88 typedef typename options::node_deallocator node_deallocator;
89 typedef typename options::type_traits::compare intrusive_key_comparator;
91 typedef typename base_class::node_type head_type;
97 static node_type * alloc_node(const K& key)
99 return cxx_allocator().New( key );
102 template <typename K, typename V>
103 static node_type * alloc_node( const K& key, const V& val )
105 return cxx_allocator().New( key, val );
108 template <typename... Args>
109 static node_type * alloc_node( Args&&... args )
111 return cxx_allocator().MoveNew( std::forward<Args>(args)... );
114 static void free_node( node_type * pNode )
116 cxx_allocator().Delete( pNode );
119 struct node_disposer {
120 void operator()( node_type * pNode )
125 typedef std::unique_ptr< node_type, node_disposer > scoped_node_ptr;
129 return base_class::m_Head;
132 head_type const& head() const
134 return base_class::m_Head;
139 return base_class::m_Tail;
142 head_type const& tail() const
144 return base_class::m_Tail;
150 template <bool IsConst>
151 class iterator_type: protected base_class::template iterator_type<IsConst>
153 typedef typename base_class::template iterator_type<IsConst> iterator_base;
155 iterator_type( head_type const& refNode )
156 : iterator_base( const_cast<head_type *>( &refNode ))
159 explicit iterator_type( const iterator_base& it )
160 : iterator_base( it )
163 friend class LazyKVList;
166 explicit iterator_type( node_type& pNode )
167 : iterator_base( &pNode )
171 typedef typename cds::details::make_const_type<mapped_type, IsConst>::reference value_ref;
172 typedef typename cds::details::make_const_type<mapped_type, IsConst>::pointer value_ptr;
174 typedef typename cds::details::make_const_type<value_type, IsConst>::reference pair_ref;
175 typedef typename cds::details::make_const_type<value_type, IsConst>::pointer pair_ptr;
181 iterator_type( const iterator_type& src )
182 : iterator_base( src )
185 key_type const& key() const
187 typename iterator_base::value_ptr p = iterator_base::operator ->();
188 assert( p != nullptr );
189 return p->m_Data.first;
192 value_ref val() const
194 typename iterator_base::value_ptr p = iterator_base::operator ->();
195 assert( p != nullptr );
196 return p->m_Data.second;
199 pair_ptr operator ->() const
201 typename iterator_base::value_ptr p = iterator_base::operator ->();
202 return p ? &(p->m_Data) : nullptr;
205 pair_ref operator *() const
207 typename iterator_base::value_ref p = iterator_base::operator *();
212 iterator_type& operator ++()
214 iterator_base::operator ++();
219 iterator_type operator ++(int)
221 return iterator_base::operator ++(0);
225 bool operator ==(iterator_type<C> const& i ) const
227 return iterator_base::operator ==(i);
230 bool operator !=(iterator_type<C> const& i ) const
232 return iterator_base::operator !=(i);
240 The forward iterator for lazy list based on gc::nogc has pre- and post-increment operators.
242 The iterator interface to access item data:
243 - <tt> operator -> </tt> - returns a pointer to \ref value_type for iterator
244 - <tt> operator *</tt> - returns a reference (a const reference for \p const_iterator) to \ref value_type for iterator
245 - <tt> const key_type& key() </tt> - returns a key reference for iterator
246 - <tt> mapped_type& val() </tt> - retuns a value reference for iterator (const reference for \p const_iterator)
248 For both functions the iterator should not be equal to <tt> end() </tt>
250 typedef iterator_type<false> iterator;
252 /// Const forward iterator
254 For iterator's features and requirements see \ref iterator
256 typedef iterator_type<true> const_iterator;
258 /// Returns a forward iterator addressing the first element in a list
260 For empty list \code begin() == end() \endcode
264 iterator it( head() );
265 ++it ; // skip dummy head
269 /// Returns an iterator that addresses the location succeeding the last element in a list
271 Do not use the value returned by <tt>end</tt> function to access any item.
272 Internally, <tt>end</tt> returning value equals to nullptr.
274 The returned value can be used only to control reaching the end of the list.
275 For empty list \code begin() == end() \endcode
279 return iterator( tail());
282 /// Returns a forward const iterator addressing the first element in a list
284 const_iterator begin() const
286 const_iterator it( head() );
287 ++it ; // skip dummy head
290 const_iterator cbegin()
292 const_iterator it( head() );
293 ++it ; // skip dummy head
298 /// Returns an const iterator that addresses the location succeeding the last element in a list
300 const_iterator end() const
302 return const_iterator( tail());
304 const_iterator cend()
306 return const_iterator( tail());
312 iterator node_to_iterator( node_type * pNode )
315 return iterator( *pNode );
321 /// Default constructor
323 Initialize empty list
337 /// Inserts new node with key and default value
339 The function creates a node with \p key and default value, and then inserts the node created into the list.
342 - The \ref key_type should be constructible from value of type \p K.
343 In trivial case, \p K is equal to \ref key_type.
344 - The \ref mapped_type should be default-constructible.
346 Returns an iterator pointed to inserted value, or \p end() if inserting is failed
348 template <typename K>
349 iterator insert( const K& key )
351 return node_to_iterator( insert_at( head(), key ));
354 /// Inserts new node with a key and a value
356 The function creates a node with \p key and value \p val, and then inserts the node created into the list.
359 - The \ref key_type should be constructible from \p key of type \p K.
360 - The \ref mapped_type should be constructible from \p val of type \p V.
362 Returns an iterator pointed to inserted value, or \p end() if inserting is failed
364 template <typename K, typename V>
365 iterator insert( const K& key, const V& val )
367 // We cannot use insert with functor here
368 // because we cannot lock inserted node for updating
369 // Therefore, we use separate function
370 return node_to_iterator( insert_at( head(), key, val ));
373 /// Inserts new node and initialize it by a functor
375 This function inserts new node with key \p key and if inserting is successful then it calls
376 \p func functor with signature
377 \code void func( value_type& item ) ; endcode
381 void operator()( value_type& item );
385 The argument \p item of user-defined functor \p func is the reference
386 to the list's item inserted. <tt>item.second</tt> is a reference to item's value that may be changed.
387 User-defined functor \p func should guarantee that during changing item's value no any other changes
388 could be made on this list's item by concurrent threads.
389 The user-defined functor can be passed by reference using \p std::ref
390 and it is called only if the inserting is successful.
392 The key_type should be constructible from value of type \p K.
394 The function allows to split creating of new item into two part:
395 - create item from \p key;
396 - insert new item into the list;
397 - if inserting is successful, initialize the value of item by calling \p f functor
399 This can be useful if complete initialization of object of \p mapped_type is heavyweight and
400 it is preferable that the initialization should be completed only if inserting is successful.
402 Returns an iterator pointed to inserted value, or \p end() if inserting is failed
404 template <typename K, typename Func>
405 iterator insert_key( const K& key, Func func )
407 return node_to_iterator( insert_key_at( head(), key, func ));
410 /// Ensures that the key \p key exists in the list
412 The operation inserts new item if the key \p key is not found in the list.
413 Otherwise, the function returns an iterator that points to item found.
415 Returns <tt> std::pair<iterator, bool> </tt> where \p first is an iterator pointing to
416 item found or inserted, \p second is true if new item has been added or \p false if the item
417 already is in the list.
419 template <typename K>
420 std::pair<iterator, bool> ensure( const K& key )
422 std::pair< node_type *, bool > ret = ensure_at( head(), key );
423 return std::make_pair( node_to_iterator( ret.first ), ret.second );
426 /// Inserts data of type \ref mapped_type constructed with <tt>std::forward<Args>(args)...</tt>
428 Returns an iterator pointed to inserted value, or \p end() if inserting is failed
430 template <typename... Args>
431 iterator emplace( Args&&... args )
433 return node_to_iterator( emplace_at( head(), std::forward<Args>(args)... ));
436 /// Find the key \p key
437 /** \anchor cds_nonintrusive_LazyKVList_nogc_find
438 The function searches the item with key equal to \p key
439 and returns an iterator pointed to item found if the key is found,
440 and \ref end() otherwise
442 template <typename Q>
443 iterator find( Q const& key )
445 return node_to_iterator( find_at( head(), key, intrusive_key_comparator() ) );
448 /// Finds the key \p val using \p pred predicate for searching
450 The function is an analog of \ref cds_nonintrusive_LazyKVList_nogc_find "find(Q const&)"
451 but \p pred is used for key comparing.
452 \p Less functor has the interface like \p std::less.
453 \p pred must imply the same element order as the comparator used for building the list.
455 template <typename Q, typename Less>
456 iterator find_with( Q const& key, Less pred )
458 return node_to_iterator( find_at( head(), key, typename options::template less_wrapper<Less>::type() ) );
461 /// Check if the list is empty
464 return base_class::empty();
467 /// Returns list's item count
469 The value returned depends on opt::item_counter option. For atomicity::empty_item_counter,
470 this function always returns 0.
472 <b>Warning</b>: even if you use real item counter and it returns 0, this fact is not mean that the list
473 is empty. To check list emptyness use \ref empty() method.
477 return base_class::size();
482 Post-condition: the list is empty
491 node_type * insert_node_at( head_type& refHead, node_type * pNode )
493 assert( pNode != nullptr );
494 scoped_node_ptr p( pNode );
495 if ( base_class::insert_at( &refHead, *p ))
501 template <typename K>
502 node_type * insert_at( head_type& refHead, const K& key )
504 return insert_node_at( refHead, alloc_node( key ));
507 template <typename K, typename V>
508 node_type * insert_at( head_type& refHead, const K& key, const V& val )
510 return insert_node_at( refHead, alloc_node( key, val ));
513 template <typename K, typename Func>
514 node_type * insert_key_at( head_type& refHead, const K& key, Func f )
516 scoped_node_ptr pNode( alloc_node( key ));
518 if ( base_class::insert_at( &refHead, *pNode )) {
520 return pNode.release();
527 template <typename K>
528 std::pair< node_type *, bool > ensure_at( head_type& refHead, const K& key )
530 scoped_node_ptr pNode( alloc_node( key ));
531 node_type * pItemFound = nullptr;
533 std::pair<bool, bool> ret = base_class::ensure_at( &refHead, *pNode, [&pItemFound](bool, node_type& item, node_type&){ pItemFound = &item; } );
534 if ( ret.first && ret.second )
537 assert( pItemFound != nullptr );
538 return std::make_pair( pItemFound, ret.second );
541 template <typename... Args>
542 node_type * emplace_at( head_type& refHead, Args&&... args )
544 return insert_node_at( refHead, alloc_node( std::forward<Args>(args)... ));
547 template <typename K, typename Compare>
548 node_type * find_at( head_type& refHead, const K& key, Compare cmp )
550 return base_class::find_at( &refHead, key, cmp );
554 template <typename K, typenam Compare, typename Func>
555 bool find_at( head_type& refHead, K& key, Compare cmp, Func f )
557 return base_class::find_at( &refHead, key, cmp, [&f]( node_type& node, K const& ){ f( node.m_Data ); });
563 }} // namespace cds::container
565 #endif // #ifndef __CDS_CONTAINER_LAZY_KVLIST_NOGC_H