3 #ifndef __CDS_CONTAINER_IMPL_LAZY_KVLIST_H
4 #define __CDS_CONTAINER_IMPL_LAZY_KVLIST_H
7 #include <functional> // ref
8 #include <cds/container/details/guarded_ptr_cast.h>
10 namespace cds { namespace container {
12 /// Lazy ordered list (key-value pair)
13 /** @ingroup cds_nonintrusive_list
14 \anchor cds_nonintrusive_LazyKVList_gc
16 This is key-value variation of non-intrusive LazyList.
17 Like standard container, this implementation split a value stored into two part -
18 constant key and alterable value.
20 Usually, ordered single-linked list is used as a building block for the hash table implementation.
21 The complexity of searching is <tt>O(N)</tt>.
24 - \p GC - garbage collector used
25 - \p Key - key type of an item stored in the list. It should be copy-constructible
26 - \p Value - value type stored in the list
27 - \p Traits - type traits, default is lazy_list::type_traits
29 It is possible to declare option-based list with cds::container::lazy_list::make_traits metafunction istead of \p Traits template
30 argument. For example, the following traits-based declaration of gc::HP lazy list
32 #include <cds/container/lazy_kvlist_hp.h>
33 // Declare comparator for the item
35 int operator ()( int i1, int i2 )
41 // Declare type_traits
42 struct my_traits: public cds::container::lazy_list::type_traits
44 typedef my_compare compare;
47 // Declare traits-based list
48 typedef cds::container::LazyKVList< cds::gc::HP, int, int, my_traits > traits_based_list;
51 is equivalent for the following option-based list
53 #include <cds/container/lazy_kvlist_hp.h>
55 // my_compare is the same
57 // Declare option-based list
58 typedef cds::container::LazyKVList< cds::gc::HP, int, int,
59 typename cds::container::lazy_list::make_traits<
60 cds::container::opt::compare< my_compare > // item comparator option
65 Template argument list \p Options of cds::container::lazy_list::make_traits metafunction are:
66 - opt::compare - key comparison functor. No default functor is provided.
67 If the option is not specified, the opt::less is used.
68 - opt::less - specifies binary predicate used for key comparison. Default is \p std::less<T>.
69 - opt::back_off - back-off strategy used. If the option is not specified, the cds::backoff::empty is used.
70 - opt::item_counter - the type of item counting feature. Default is \ref atomicity::empty_item_counter that is no item counting.
71 - opt::allocator - the allocator used for creating and freeing list's item. Default is \ref CDS_DEFAULT_ALLOCATOR macro.
72 - opt::memory_model - C++ memory ordering model. Can be opt::v::relaxed_ordering (relaxed memory model, the default)
73 or opt::v::sequential_consistent (sequentially consisnent memory model).
76 There are different specializations of this template for each garbage collecting schema used.
77 You should include appropriate .h-file depending on GC you are using:
78 - for gc::HP: \code #include <cds/container/lazy_kvlist_hp.h> \endcode
79 - for gc::PTB: \code #include <cds/container/lazy_kvlist_ptb.h> \endcode
80 - for gc::HRC: \code #include <cds/container/lazy_kvlist_hrc.h> \endcode
81 - for \ref cds_urcu_desc "RCU": \code #include <cds/container/lazy_kvlist_rcu.h> \endcode
82 - for gc::nogc: \code #include <cds/container/lazy_kvlist_nogc.h> \endcode
88 #ifdef CDS_DOXYGEN_INVOKED
89 typename Traits = lazy_list::type_traits
95 #ifdef CDS_DOXYGEN_INVOKED
96 protected intrusive::LazyList< GC, implementation_defined, Traits >
98 protected details::make_lazy_kvlist< GC, Key, Value, Traits >::type
102 typedef details::make_lazy_kvlist< GC, Key, Value, Traits > options;
103 typedef typename options::type base_class;
107 #ifdef CDS_DOXYGEN_INVOKED
108 typedef Key key_type ; ///< Key type
109 typedef Value mapped_type ; ///< Type of value stored in the list
110 typedef std::pair<key_type const, mapped_type> value_type ; ///< key/value pair stored in the list
112 typedef typename options::key_type key_type;
113 typedef typename options::value_type mapped_type;
114 typedef typename options::pair_type value_type;
117 typedef typename base_class::gc gc ; ///< Garbage collector used
118 typedef typename base_class::back_off back_off ; ///< Back-off strategy used
119 typedef typename options::allocator_type allocator_type ; ///< Allocator type used for allocate/deallocate the nodes
120 typedef typename base_class::item_counter item_counter ; ///< Item counting policy used
121 typedef typename options::key_comparator key_comparator ; ///< key comparison functor
122 typedef typename base_class::memory_model memory_model ; ///< Memory ordering. See cds::opt::memory_model option
126 typedef typename base_class::value_type node_type;
127 typedef typename options::cxx_allocator cxx_allocator;
128 typedef typename options::node_deallocator node_deallocator;
129 typedef typename options::type_traits::compare intrusive_key_comparator;
131 typedef typename base_class::node_type head_type;
136 typedef cds::gc::guarded_ptr< gc, node_type, value_type, details::guarded_ptr_cast_map<node_type, value_type> > guarded_ptr;
140 template <typename K>
141 static node_type * alloc_node(const K& key)
143 return cxx_allocator().New( key );
146 template <typename K, typename V>
147 static node_type * alloc_node( const K& key, const V& val )
149 return cxx_allocator().New( key, val );
152 template <typename... Args>
153 static node_type * alloc_node( Args&&... args )
155 return cxx_allocator().MoveNew( std::forward<Args>(args)... );
158 static void free_node( node_type * pNode )
160 cxx_allocator().Delete( pNode );
163 struct node_disposer {
164 void operator()( node_type * pNode )
169 typedef std::unique_ptr< node_type, node_disposer > scoped_node_ptr;
173 return *base_class::head();
176 head_type const& head() const
178 return *base_class::head();
183 return *base_class::tail();
186 head_type const& tail() const
188 return *base_class::tail();
195 template <bool IsConst>
196 class iterator_type: protected base_class::template iterator_type<IsConst>
198 typedef typename base_class::template iterator_type<IsConst> iterator_base;
200 iterator_type( head_type const& pNode )
201 : iterator_base( const_cast<head_type *>(&pNode) )
203 iterator_type( head_type const * pNode )
204 : iterator_base( const_cast<head_type *>(pNode) )
207 friend class LazyKVList;
210 typedef typename cds::details::make_const_type<mapped_type, IsConst>::reference value_ref;
211 typedef typename cds::details::make_const_type<mapped_type, IsConst>::pointer value_ptr;
213 typedef typename cds::details::make_const_type<value_type, IsConst>::reference pair_ref;
214 typedef typename cds::details::make_const_type<value_type, IsConst>::pointer pair_ptr;
219 iterator_type( iterator_type const& src )
220 : iterator_base( src )
223 key_type const& key() const
225 typename iterator_base::value_ptr p = iterator_base::operator ->();
226 assert( p != nullptr );
227 return p->m_Data.first;
230 value_ref val() const
232 typename iterator_base::value_ptr p = iterator_base::operator ->();
233 assert( p != nullptr );
234 return p->m_Data.second;
237 pair_ptr operator ->() const
239 typename iterator_base::value_ptr p = iterator_base::operator ->();
240 return p ? &(p->m_Data) : nullptr;
243 pair_ref operator *() const
245 typename iterator_base::value_ref p = iterator_base::operator *();
250 iterator_type& operator ++()
252 iterator_base::operator ++();
257 bool operator ==(iterator_type<C> const& i ) const
259 return iterator_base::operator ==(i);
262 bool operator !=(iterator_type<C> const& i ) const
264 return iterator_base::operator !=(i);
272 The forward iterator for lazy list has some features:
273 - it has no post-increment operator
274 - to protect the value, the iterator contains a GC-specific guard + another guard is required locally for increment operator.
275 For some GC (gc::HP, gc::HRC), a guard is limited resource per thread, so an exception (or assertion) "no free guard"
276 may be thrown if a limit of guard count per thread is exceeded.
277 - The iterator cannot be moved across thread boundary since it contains GC's guard that is thread-private GC data.
278 - Iterator ensures thread-safety even if you delete the item that iterator points to. However, in case of concurrent
279 deleting operations it is no guarantee that you iterate all item in the list.
281 Therefore, the use of iterators in concurrent environment is not good idea. Use the iterator on the concurrent container
282 for debug purpose only.
284 The iterator interface to access item data:
285 - <tt> operator -> </tt> - returns a pointer to \ref value_type for iterator
286 - <tt> operator *</tt> - returns a reference (a const reference for \p const_iterator) to \ref value_type for iterator
287 - <tt> const key_type& key() </tt> - returns a key reference for iterator
288 - <tt> mapped_type& val() </tt> - retuns a value reference for iterator (const reference for \p const_iterator)
290 For both functions the iterator should not be equal to <tt> end() </tt>
292 typedef iterator_type<false> iterator;
294 /// Const forward iterator
296 For iterator's features and requirements see \ref iterator
298 typedef iterator_type<true> const_iterator;
300 /// Returns a forward iterator addressing the first element in a list
302 For empty list \code begin() == end() \endcode
306 iterator it( head() );
307 ++it ; // skip dummy head
311 /// Returns an iterator that addresses the location succeeding the last element in a list
313 Do not use the value returned by <tt>end</tt> function to access any item.
314 Internally, <tt>end</tt> returning value equals to \p nullptr.
316 The returned value can be used only to control reaching the end of the list.
317 For empty list \code begin() == end() \endcode
321 return iterator( tail() );
324 /// Returns a forward const iterator addressing the first element in a list
326 const_iterator begin() const
328 const_iterator it( head() );
329 ++it; // skip dummy head
332 const_iterator cbegin()
334 const_iterator it( head() );
335 ++it; // skip dummy head
340 /// Returns an const iterator that addresses the location succeeding the last element in a list
342 const_iterator end() const
344 return const_iterator( tail());
346 const_iterator cend()
348 return const_iterator( tail());
353 /// Default constructor
355 Initializes empty list
369 /// Inserts new node with key and default value
371 The function creates a node with \p key and default value, and then inserts the node created into the list.
374 - The \ref key_type should be constructible from value of type \p K.
375 In trivial case, \p K is equal to \ref key_type.
376 - The \ref mapped_type should be default-constructible.
378 Returns \p true if inserting successful, \p false otherwise.
380 template <typename K>
381 bool insert( const K& key )
383 return insert_at( head(), key );
386 /// Inserts new node with a key and a value
388 The function creates a node with \p key and value \p val, and then inserts the node created into the list.
391 - The \ref key_type should be constructible from \p key of type \p K.
392 - The \ref mapped_type should be constructible from \p val of type \p V.
394 Returns \p true if inserting successful, \p false otherwise.
396 template <typename K, typename V>
397 bool insert( const K& key, const V& val )
399 // We cannot use insert with functor here
400 // because we cannot lock inserted node for updating
401 // Therefore, we use separate function
402 return insert_at( head(), key, val );
405 /// Inserts new node and initializes it by a functor
407 This function inserts new node with key \p key and if inserting is successful then it calls
408 \p func functor with signature
411 void operator()( value_type& item );
415 The argument \p item of user-defined functor \p func is the reference
416 to the list's item inserted. <tt>item.second</tt> is a reference to item's value that may be changed.
417 User-defined functor \p func should guarantee that during changing item's value no any other changes
418 could be made on this list's item by concurrent threads.
419 The user-defined functor can be passed by reference using \p std::ref
420 and it is called only if inserting is successful.
422 The key_type should be constructible from value of type \p K.
424 The function allows to split creating of new item into two part:
425 - create item from \p key;
426 - insert new item into the list;
427 - if inserting is successful, initialize the value of item by calling \p func functor
429 This can be useful if complete initialization of object of \p mapped_type is heavyweight and
430 it is preferable that the initialization should be completed only if inserting is successful.
432 template <typename K, typename Func>
433 bool insert_key( const K& key, Func func )
435 return insert_key_at( head(), key, func );
438 /// Inserts data of type \ref mapped_type constructed with <tt>std::forward<Args>(args)...</tt>
440 Returns \p true if inserting successful, \p false otherwise.
442 template <typename... Args>
443 bool emplace( Args&&... args )
445 return emplace_at( head(), std::forward<Args>(args)... );
448 /// Ensures that the \p key exists in the list
450 The operation performs inserting or changing data with lock-free manner.
452 If the \p key not found in the list, then the new item created from \p key
453 is inserted into the list (note that in this case the \ref key_type should be
454 copy-constructible from type \p K).
455 Otherwise, the functor \p func is called with item found.
456 The functor \p Func may be a function with signature:
458 void func( bool bNew, value_type& item );
463 void operator()( bool bNew, value_type& item );
468 - \p bNew - \p true if the item has been inserted, \p false otherwise
469 - \p item - item of the list
471 The functor may change any fields of the \p item.second that is \ref mapped_type;
472 however, \p func must guarantee that during changing no any other modifications
473 could be made on this item by concurrent threads.
475 You may pass \p func argument by reference using \p std::ref.
477 Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
478 \p second is true if new item has been added or \p false if the item with \p key
479 already is in the list.
481 template <typename K, typename Func>
482 std::pair<bool, bool> ensure( const K& key, Func f )
484 return ensure_at( head(), key, f );
487 /// Deletes \p key from the list
488 /** \anchor cds_nonintrusive_LazyKVList_hp_erase_val
490 Returns \p true if \p key is found and has been deleted, \p false otherwise
492 template <typename K>
493 bool erase( K const& key )
495 return erase_at( head(), key, intrusive_key_comparator() );
498 /// Deletes the item from the list using \p pred predicate for searching
500 The function is an analog of \ref cds_nonintrusive_LazyKVList_hp_erase_val "erase(K const&)"
501 but \p pred is used for key comparing.
502 \p Less functor has the interface like \p std::less.
503 \p pred must imply the same element order as the comparator used for building the list.
505 template <typename K, typename Less>
506 bool erase_with( K const& key, Less pred )
508 return erase_at( head(), key, typename options::template less_wrapper<Less>::type() );
511 /// Deletes \p key from the list
512 /** \anchor cds_nonintrusive_LazyKVList_hp_erase_func
513 The function searches an item with key \p key, calls \p f functor with item found
514 and deletes it. If \p key is not found, the functor is not called.
516 The functor \p Func interface:
519 void operator()(value_type& val) { ... }
522 The functor may be passed by reference with <tt>boost:ref</tt>
524 Returns \p true if key is found and deleted, \p false otherwise
526 template <typename K, typename Func>
527 bool erase( K const& key, Func f )
529 return erase_at( head(), key, intrusive_key_comparator(), f );
532 /// Deletes the item from the list using \p pred predicate for searching
534 The function is an analog of \ref cds_nonintrusive_LazyKVList_hp_erase_func "erase(K const&, Func)"
535 but \p pred is used for key comparing.
536 \p Less functor has the interface like \p std::less.
537 \p pred must imply the same element order as the comparator used for building the list.
539 template <typename K, typename Less, typename Func>
540 bool erase_with( K const& key, Less pred, Func f )
542 return erase_at( head(), key, typename options::template less_wrapper<Less>::type(), f );
545 /// Extracts the item from the list with specified \p key
546 /** \anchor cds_nonintrusive_LazyKVList_hp_extract
547 The function searches an item with key equal to \p key,
548 unlinks it from the list, and returns it in \p dest parameter.
549 If the item with key equal to \p key is not found the function returns \p false.
551 Note the compare functor should accept a parameter of type \p K that can be not the same as \p key_type.
553 @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
557 typedef cds::container::LazyKVList< cds::gc::HP, int, foo, my_traits > ord_list;
561 ord_list::guarded_ptr gp;
562 theList.extract( gp, 5 );
566 // Destructor of gp releases internal HP guard and frees the item
570 template <typename K>
571 bool extract( guarded_ptr& dest, K const& key )
573 return extract_at( head(), dest.guard(), key, intrusive_key_comparator() );
576 /// Extracts the item from the list with comparing functor \p pred
578 The function is an analog of \ref cds_nonintrusive_LazyKVList_hp_extract "extract(guarded_ptr&, K const&)"
579 but \p pred predicate is used for key comparing.
581 \p Less functor has the semantics like \p std::less but should take arguments of type \ref key_type and \p K
583 \p pred must imply the same element order as the comparator used for building the list.
585 template <typename K, typename Less>
586 bool extract_with( guarded_ptr& dest, K const& key, Less pred )
588 return extract_at( head(), dest.guard(), key, typename options::template less_wrapper<Less>::type() );
591 /// Finds the key \p key
592 /** \anchor cds_nonintrusive_LazyKVList_hp_find_val
593 The function searches the item with key equal to \p key
594 and returns \p true if it is found, and \p false otherwise
596 template <typename Q>
597 bool find( Q const& key )
599 return find_at( head(), key, intrusive_key_comparator() );
602 /// Finds the key \p val using \p pred predicate for searching
604 The function is an analog of \ref cds_nonintrusive_LazyKVList_hp_find_val "find(Q const&)"
605 but \p pred is used for key comparing.
606 \p Less functor has the interface like \p std::less.
607 \p pred must imply the same element order as the comparator used for building the list.
609 template <typename Q, typename Less>
610 bool find_with( Q const& key, Less pred )
612 return find_at( head(), key, typename options::template less_wrapper<Less>::type() );
615 /// Finds the key \p key and performs an action with it
616 /** \anchor cds_nonintrusive_LazyKVList_hp_find_func
617 The function searches an item with key equal to \p key and calls the functor \p f for the item found.
618 The interface of \p Func functor is:
621 void operator()( value_type& item );
624 where \p item is the item found.
626 You may pass \p f argument by reference using \p std::ref.
628 The functor may change <tt>item.second</tt> that is reference to value of node.
629 Note that the function is only guarantee that \p item cannot be deleted during functor is executing.
630 The function does not serialize simultaneous access to the list \p item. If such access is
631 possible you must provide your own synchronization schema to exclude unsafe item modifications.
633 The function returns \p true if \p key is found, \p false otherwise.
635 template <typename Q, typename Func>
636 bool find( Q const& key, Func f )
638 return find_at( head(), key, intrusive_key_comparator(), f );
641 /// Finds the key \p val using \p pred predicate for searching
643 The function is an analog of \ref cds_nonintrusive_LazyKVList_hp_find_func "find(Q&, Func)"
644 but \p pred is used for key comparing.
645 \p Less functor has the interface like \p std::less.
646 \p pred must imply the same element order as the comparator used for building the list.
648 template <typename Q, typename Less, typename Func>
649 bool find_with( Q const& key, Less pred, Func f )
651 return find_at( head(), key, typename options::template less_wrapper<Less>::type(), f );
654 /// Finds \p key and return the item found
655 /** \anchor cds_nonintrusive_LazyKVList_hp_get
656 The function searches the item with key equal to \p key
657 and assigns the item found to guarded pointer \p ptr.
658 The function returns \p true if \p key is found, and \p false otherwise.
659 If \p key is not found the \p ptr parameter is not changed.
661 @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
665 typedef cds::container::LazyKVList< cds::gc::HP, int, foo, my_traits > ord_list;
669 ord_list::guarded_ptr gp;
670 if ( theList.get( gp, 5 )) {
674 // Destructor of guarded_ptr releases internal HP guard and frees the item
678 Note the compare functor specified for class \p Traits template parameter
679 should accept a parameter of type \p K that can be not the same as \p key_type.
681 template <typename K>
682 bool get( guarded_ptr& ptr, K const& key )
684 return get_at( head(), ptr.guard(), key, intrusive_key_comparator() );
687 /// Finds the key \p val and return the item found
689 The function is an analog of \ref cds_nonintrusive_LazyKVList_hp_get "get(guarded_ptr& ptr, K const&)"
690 but \p pred is used for comparing the keys.
692 \p Less functor has the semantics like \p std::less but should take arguments of type \ref key_type and \p K
694 \p pred must imply the same element order as the comparator used for building the list.
696 template <typename K, typename Less>
697 bool get_with( guarded_ptr& ptr, K const& key, Less pred )
699 return get_at( head(), ptr.guard(), key, typename options::template less_wrapper<Less>::type() );
702 /// Checks if the list is empty
705 return base_class::empty();
708 /// Returns list's item count
710 The value returned depends on opt::item_counter option. For atomicity::empty_item_counter,
711 this function always returns 0.
713 <b>Warning</b>: even if you use real item counter and it returns 0, this fact is not mean that the list
714 is empty. To check list emptyness use \ref empty() method.
718 return base_class::size();
723 Post-condition: the list is empty
732 bool insert_node_at( head_type& refHead, node_type * pNode )
734 assert( pNode != nullptr );
735 scoped_node_ptr p( pNode );
737 if ( base_class::insert_at( &refHead, *p )) {
745 template <typename K>
746 bool insert_at( head_type& refHead, const K& key )
748 return insert_node_at( refHead, alloc_node( key ));
751 template <typename K, typename V>
752 bool insert_at( head_type& refHead, const K& key, const V& val )
754 return insert_node_at( refHead, alloc_node( key, val ));
757 template <typename K, typename Func>
758 bool insert_key_at( head_type& refHead, const K& key, Func f )
760 scoped_node_ptr pNode( alloc_node( key ));
762 if ( base_class::insert_at( &refHead, *pNode, [&f](node_type& node){ f( node.m_Data ); } )) {
769 template <typename... Args>
770 bool emplace_at( head_type& refHead, Args&&... args )
772 return insert_node_at( refHead, alloc_node( std::forward<Args>(args)... ));
775 template <typename K, typename Compare>
776 bool erase_at( head_type& refHead, K const& key, Compare cmp )
778 return base_class::erase_at( &refHead, key, cmp );
781 template <typename K, typename Compare, typename Func>
782 bool erase_at( head_type& refHead, K const& key, Compare cmp, Func f )
784 return base_class::erase_at( &refHead, key, cmp, [&f](node_type const & node){f( const_cast<value_type&>(node.m_Data)); });
787 template <typename K, typename Compare>
788 bool extract_at( head_type& refHead, typename gc::Guard& dest, K const& key, Compare cmp )
790 return base_class::extract_at( &refHead, dest, key, cmp );
793 template <typename K, typename Func>
794 std::pair<bool, bool> ensure_at( head_type& refHead, const K& key, Func f )
796 scoped_node_ptr pNode( alloc_node( key ));
798 std::pair<bool, bool> ret = base_class::ensure_at( &refHead, *pNode,
799 [&f]( bool bNew, node_type& node, node_type& ){ f( bNew, node.m_Data ); });
800 if ( ret.first && ret.second )
806 template <typename K, typename Compare>
807 bool find_at( head_type& refHead, K const& key, Compare cmp )
809 return base_class::find_at( &refHead, key, cmp );
812 template <typename K, typename Compare, typename Func>
813 bool find_at( head_type& refHead, K& key, Compare cmp, Func f )
815 return base_class::find_at( &refHead, key, cmp, [&f]( node_type& node, K& ){ f( node.m_Data ); });
818 template <typename K, typename Compare>
819 bool get_at( head_type& refHead, typename gc::Guard& guard, K const& key, Compare cmp )
821 return base_class::get_at( &refHead, guard, key, cmp );
827 }} // namespace cds::container
829 #endif // #ifndef __CDS_CONTAINER_IMPL_LAZY_KVLIST_H