#define CDS_DATA_ALIGNMENT(n) __attribute__ ((aligned (n)))
+// likely/unlikely
+
+#define cds_likely( expr ) __builtin_expect( !!( expr ), 1 )
+#define cds_unlikely( expr ) __builtin_expect( !!( expr ), 0 )
+
#include <cds/compiler/gcc/compiler_barriers.h>
#endif // #ifndef CDSLIB_COMPILER_GCC_DEFS_H
# define CDS_EXPORT_API
#endif
+#ifndef cds_likely
+# define cds_likely( expr ) expr
+# define cds_unlikely( expr ) expr
+#endif
+
// Features
#include <cds/compiler/feature_tsan.h>
# define CDS_DEPRECATED( reason ) __attribute__((deprecated( reason )))
#endif
+// likely/unlikely
+
+#define cds_likely( expr ) __builtin_expect( !!( expr ), 1 )
+#define cds_unlikely( expr ) __builtin_expect( !!( expr ), 0 )
+
#include <cds/compiler/gcc/compiler_barriers.h>
#endif // #ifndef CDSLIB_COMPILER_GCC_DEFS_H
RCU \p synchronize() method can be called. RCU should not be locked.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
\p second is \p true if new item has been added or \p false if the item with \p key
already exists.
*/
- \p bNew - \p true if the item has been inserted, \p false otherwise
- \p item - an item of the map for \p key
- Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+ Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
i.e. the node has been inserted or updated,
\p second is \p true if new item has been added or \p false if the item with \p key
already exists.
If new item has been inserted (i.e. \p bNew is \p true) then \p item and \p val arguments
refer to the same thing.
- Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+ Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
i.e. the node has been inserted or updated,
\p second is \p true if new item has been added or \p false if the item with \p key
already exists.
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSLIB_CONTAINER_DETAILS_ITERABLE_LIST_BASE_H
+#define CDSLIB_CONTAINER_DETAILS_ITERABLE_LIST_BASE_H
+
+#include <cds/container/details/base.h>
+#include <cds/intrusive/details/iterable_list_base.h>
+#include <cds/urcu/options.h>
+
+namespace cds { namespace container {
+
+ /// \p IterableList ordered list related definitions
+ /** @ingroup cds_nonintrusive_helper
+ */
+ namespace iterable_list {
+
+ /// \p IterableList internal statistics, see \p cds::intrusive::iterable_list::stat
+ template <typename EventCounter = cds::intrusive::iterable_list::stat<>::event_counter >
+ using stat = cds::intrusive::iterable_list::stat< EventCounter >;
+
+ /// \p IterableList empty internal statistics, see \p cds::intrusive::iterable_list::empty_stat
+ typedef cds::intrusive::iterable_list::empty_stat empty_stat;
+
+ //@cond
+ template <typename Stat = cds::intrusive::iterable_list::wrapped_stat<>::stat_type >
+ using wrapped_stat = cds::intrusive::iterable_list::wrapped_stat< Stat >;
+ //@endif
+
+ /// \p IterableList traits
+ struct traits
+ {
+ /// Allocator used to allocate new data
+ typedef CDS_DEFAULT_ALLOCATOR allocator;
+
+ /// Node allocator
+ typedef intrusive::iterable_list::traits::node_allocator node_allocator;
+
+ /// Key comparison functor
+ /**
+ No default functor is provided. If the option is not specified, the \p less is used.
+ */
+ typedef opt::none compare;
+
+ /// Specifies binary predicate used for key comparison.
+ /**
+ Default is \p std::less<T>.
+ */
+ typedef opt::none less;
+
+ /// Back-off strategy
+ typedef intrusive::iterable_list::traits::back_off back_off;
+
+ /// Item counting feature; by default, disabled. Use \p cds::atomicity::item_counter to enable item counting
+ typedef intrusive::iterable_list::traits::item_counter item_counter;
+
+ /// Internal statistics
+ /**
+ By default, internal statistics is disabled (\p iterable_list::empty_stat).
+ Use \p iterable_list::stat to enable it.
+ */
+ typedef intrusive::iterable_list::traits::stat stat;
+
+ /// C++ memory ordering model
+ /**
+ Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
+ or \p opt::v::sequential_consistent (sequentially consisnent memory model).
+ */
+ typedef opt::v::relaxed_ordering memory_model;
+
+ /// RCU deadlock checking policy (only for \ref cds_intrusive_MichaelList_rcu "RCU-based MichaelList")
+ /**
+ List of available options see opt::rcu_check_deadlock
+ */
+ typedef opt::v::rcu_throw_deadlock rcu_check_deadlock;
+
+ //@cond
+ // IterableKVList: supporting for split-ordered list
+ // key accessor (opt::none = internal key type is equal to user key type)
+ typedef opt::none key_accessor;
+ //@endcond
+ };
+
+ /// Metafunction converting option list to \p iterable_list::traits
+ /**
+ Supported \p Options are:
+ - \p opt::compare - key comparison functor. No default functor is provided.
+ If the option is not specified, the \p opt::less is used.
+ - \p opt::less - specifies binary predicate used for key comparison. Default is \p std::less<T>.
+ - \p opt::allocator - an allocator for data, default is \p CDS_DEFAULT_ALLOCATOR
+ - \p opt::node_allocator - node allocator, default is \p std::allocator.
+ - \p opt::back_off - back-off strategy used. If the option is not specified, the \p cds::backoff::Default is used.
+ - \p opt::item_counter - the type of item counting feature. Default is disabled (\p atomicity::empty_item_counter).
+ To enable item counting use \p atomicity::item_counter.
+ - \p opt::stat - internal statistics. By default, it is disabled (\p iterable_list::empty_stat).
+ To enable it use \p iterable_list::stat
+ - \p opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
+ or \p opt::v::sequential_consistent (sequentially consistent memory model).
+ - \p opt::rcu_check_deadlock - a deadlock checking policy for \ref cds_intrusive_IterableList_rcu "RCU-based IterableList"
+ Default is \p opt::v::rcu_throw_deadlock
+ */
+ template <typename... Options>
+ struct make_traits {
+# ifdef CDS_DOXYGEN_INVOKED
+ typedef implementation_defined type ; ///< Metafunction result
+# else
+ typedef typename cds::opt::make_options<
+ typename cds::opt::find_type_traits< traits, Options... >::type
+ ,Options...
+ >::type type;
+#endif
+ };
+
+
+ } // namespace iterable_list
+
+ // Forward declarations
+ template <typename GC, typename T, typename Traits=iterable_list::traits>
+ class IterableList;
+
+ template <typename GC, typename Key, typename Value, typename Traits=iterable_list::traits>
+ class IterableKVList;
+
+ // Tag for selecting iterable list implementation
+ /**
+ This struct is empty and it is used only as a tag for selecting \p IterableList
+ as ordered list implementation in declaration of some classes.
+
+ See split_list::traits::ordered_list as an example.
+ */
+ struct iterable_list_tag
+ {};
+
+ //@cond
+ template <typename List>
+ struct is_iterable_list {
+ enum {
+ value = false
+ };
+ };
+
+ template <typename GC, typename T, typename Traits>
+ struct is_iterable_list< IterableList<GC, T, Traits >>
+ {
+ enum {
+ value = true
+ };
+ };
+
+ template <typename GC, typename T, typename Traits>
+ struct is_iterable_list< IterableKVList<GC, T, Traits >>
+ {
+ enum {
+ value = true
+ };
+ };
+ //@endcond
+
+}} // namespace cds::container
+
+
+#endif // #ifndef CDSLIB_CONTAINER_DETAILS_ITERABLE_LIST_BASE_H
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_CONTAINER_DETAILS_LAZY_LIST_BASE_H
namespace cds { namespace container {
- /// LazyList ordered list related definitions
+ /// \p LazyList ordered list related definitions
/** @ingroup cds_nonintrusive_helper
*/
namespace lazy_list {
+
+ /// \p LazyList internal statistics, see \p cds::intrusive::lazy_list::stat
+ template <typename EventCounter = cds::intrusive::lazy_list::stat<>::event_counter>
+ using stat = cds::intrusive::lazy_list::stat< EventCounter >;
+
+ /// \p LazyList empty internal statistics, see \p cds::intrusive::lazy_list::empty_stat
+ typedef cds::intrusive::lazy_list::empty_stat empty_stat;
+
+ //@cond
+ template <typename Stat = cds::intrusive::lazy_list::wrapped_stat<>::stat_type>
+ using wrapped_stat = cds::intrusive::lazy_list::wrapped_stat< Stat >;
+ //@endif
+
/// LazyList traits
/**
Either \p compare or \p less or both must be specified.
/// Item counting feature; by default, disabled. Use \p cds::atomicity::item_counter to enable item counting
typedef atomicity::empty_item_counter item_counter;
+ /// Internal statistics
+ /**
+ By default, internal statistics is disabled (\p lazy_list::empty_stat).
+ Use \p lazy_list::stat to enable it.
+ */
+ typedef empty_stat stat;
+
/// C++ memory ordering model
/**
Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
- or \p opt::v::sequential_consistent (sequentially consisnent memory model).
+ or \p opt::v::sequential_consistent (sequentially consistent memory model).
*/
typedef opt::v::relaxed_ordering memory_model;
- \p opt::back_off - back-off strategy used. If the option is not specified, \p cds::backoff::Default is used.
- \p opt::item_counter - the type of item counting feature. Default is disabled (\p atomicity::empty_item_counter).
To enable item counting use \p atomicity::item_counter.
+ - \p opt::stat - internal statistics. By default, it is disabled (\p lazy_list::empty_stat).
+ To enable it use \p lazy_list::stat
- \p opt::allocator - the allocator used for creating and freeing list's item. Default is \ref CDS_DEFAULT_ALLOCATOR macro.
- \p opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
- or \p opt::v::sequential_consistent (sequentially consisnent memory model).
+ or \p opt::v::sequential_consistent (sequentially consistent memory model).
*/
template <typename... Options>
struct make_traits {
// Tag for selecting lazy list implementation
/**
- This struct is empty and it is used only as a tag for selecting LazyList
+ This empty struct is used only as a tag for selecting \p LazyList
as ordered list implementation in declaration of some classes.
See \p split_list::traits::ordered_list as an example.
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSLIB_CONTAINER_DETAILS_MAKE_ITERABLE_KVLIST_H
+#define CDSLIB_CONTAINER_DETAILS_MAKE_ITERABLE_KVLIST_H
+
+#include <cds/details/binary_functor_wrapper.h>
+#include <cds/opt/compare.h>
+
+namespace cds { namespace container {
+
+ //@cond
+ namespace details {
+
+ template <class GC, typename K, typename T, class Traits>
+ struct make_iterable_kvlist
+ {
+ typedef Traits original_type_traits;
+
+ typedef GC gc;
+ typedef K key_type;
+ typedef T mapped_type;
+ typedef std::pair<key_type const, mapped_type> value_type;
+
+ typedef typename original_type_traits::allocator::template rebind<value_type>::other data_allocator_type;
+ typedef cds::details::Allocator< value_type, data_allocator_type > cxx_data_allocator;
+
+ typedef typename original_type_traits::memory_model memory_model;
+
+ struct data_disposer
+ {
+ void operator ()( value_type * pData )
+ {
+ cxx_data_allocator().Delete( pData );
+ }
+ };
+
+ struct key_field_accessor {
+ key_type const& operator()( value_type const& data )
+ {
+ return data.first;
+ }
+ };
+
+ template <typename Less>
+ struct less_wrapper
+ {
+ template <typename Q>
+ bool operator()( value_type const& lhs, Q const& rhs ) const
+ {
+ return Less()( lhs.first, rhs );
+ }
+
+ template <typename Q>
+ bool operator()( Q const& lhs, value_type const& rhs ) const
+ {
+ return Less()( lhs, rhs.first );
+ }
+ };
+
+ typedef typename opt::details::make_comparator< key_type, original_type_traits >::type key_comparator;
+
+ struct base_traits: public original_type_traits
+ {
+ typedef data_disposer disposer;
+ typedef cds::details::compare_wrapper< value_type, key_comparator, key_field_accessor > compare;
+ };
+
+ typedef container::IterableList<gc, value_type, base_traits> type;
+ };
+ } // namespace details
+ //@endcond
+
+}} // namespace cds::container
+
+#endif // #ifndef CDSLIB_CONTAINER_DETAILS_MAKE_ITERABLE_KVLIST_H
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSLIB_CONTAINER_DETAILS_MAKE_ITERABLE_LIST_H
+#define CDSLIB_CONTAINER_DETAILS_MAKE_ITERABLE_LIST_H
+
+#include <cds/intrusive/details/iterable_list_base.h>
+#include <cds/details/binary_functor_wrapper.h>
+
+namespace cds { namespace container {
+
+ //@cond
+ namespace details {
+
+ template <class GC, typename T, class Traits>
+ struct make_iterable_list
+ {
+ typedef GC gc;
+ typedef T value_type;
+
+ typedef Traits original_traits;
+
+ typedef typename original_traits::allocator::template rebind<value_type>::other data_allocator_type;
+ typedef cds::details::Allocator< value_type, data_allocator_type > cxx_data_allocator;
+
+ typedef typename original_traits::memory_model memory_model;
+
+ struct data_disposer
+ {
+ void operator ()( value_type* data )
+ {
+ cxx_data_allocator().Delete( data );
+ }
+ };
+
+ template <typename Less>
+ struct less_wrapper {
+ typedef cds::opt::details::make_comparator_from_less<Less> type;
+ };
+
+ struct intrusive_traits: public original_traits
+ {
+ typedef data_disposer disposer;
+ };
+
+ typedef intrusive::IterableList<gc, value_type, intrusive_traits> type;
+
+ typedef typename type::key_comparator key_comparator;
+ };
+ } // namespace details
+ //@endcond
+
+}} // namespace cds::container
+
+#endif // #ifndef CDSLIB_CONTAINER_DETAILS_MAKE_ITERABLE_LIST_H
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_CONTAINER_DETAILS_MAKE_MICHAEL_KVLIST_H
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_CONTAINER_DETAILS_MAKE_MICHAEL_LIST_H
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_CONTAINER_DETAILS_MICHAEL_LIST_BASE_H
/** @ingroup cds_nonintrusive_helper
*/
namespace michael_list {
+
+ /// \p MichaelList internal statistics, see \p cds::intrusive::michael_list::stat
+ template <typename EventCounter = cds::intrusive::michael_list::stat<>::event_counter >
+ using stat = cds::intrusive::michael_list::stat< EventCounter >;
+
+ /// \p MichaelList empty internal statistics, see \p cds::intrusive::michael_list::empty_stat
+ typedef cds::intrusive::michael_list::empty_stat empty_stat;
+
+ //@cond
+ template <typename Stat = cds::intrusive::michael_list::wrapped_stat<>::stat_type>
+ using wrapped_stat = cds::intrusive::michael_list::wrapped_stat< Stat >;
+ //@endif
+
/// MichaelList traits
struct traits
{
- typedef CDS_DEFAULT_ALLOCATOR allocator ; ///< allocator used to allocate new node
+ typedef CDS_DEFAULT_ALLOCATOR allocator; ///< allocator used to allocate new node
/// Key comparison functor
/**
/// Item counting feature; by default, disabled. Use \p cds::atomicity::item_counter to enable item counting
typedef atomicity::empty_item_counter item_counter;
+ /// Internal statistics
+ /**
+ By default, internal statistics is disabled (\p michael_list::empty_stat).
+ Use \p michael_list::stat to enable it.
+ */
+ typedef empty_stat stat;
+
/// C++ memory ordering model
/**
Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
/// Metafunction converting option list to \p michael_list::traits
/**
+ Supported \p Options are:
+ - \p opt::compare - key comparison functor. No default functor is provided.
+ If the option is not specified, the \p opt::less is used.
+ - \p opt::less - specifies binary predicate used for key comparison. Default is \p std::less<T>.
+ - \p opt::allocator - an allocator, default is \p CDS_DEFAULT_ALLOCATOR
+ - \p opt::back_off - back-off strategy used. If the option is not specified, the \p cds::backoff::Default is used.
+ - \p opt::item_counter - the type of item counting feature. Default is disabled (\p atomicity::empty_item_counter).
+ To enable item counting use \p atomicity::item_counter.
+ - \p opt::stat - internal statistics. By default, it is disabled (\p michael_list::empty_stat).
+ To enable it use \p michael_list::stat
+ - \p opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
+ or \p opt::v::sequential_consistent (sequentially consistent memory model).
+ - \p opt::rcu_check_deadlock - a deadlock checking policy for \ref cds_intrusive_MichaelList_rcu "RCU-based MichaelList"
+ Default is \p opt::v::rcu_throw_deadlock
*/
template <typename... Options>
struct make_traits {
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_CONTAINER_DETAILS_MICHAEL_SET_BASE_H
RCU \p synchronize() method can be called. RCU should not be locked.
- Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+ Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
i.e. the node has been inserted or updated,
\p second is \p true if new item has been added or \p false if the item with \p key
already exists.
RCU \p synchronize method can be called. RCU should not be locked.
- Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+ Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
i.e. the node has been inserted or updated,
\p second is \p true if new item has been added or \p false if the item with \p key
already exists.
The functor may change any fields of the \p item.second.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
\p second is \p true if new item has been added or \p false if \p key already exists.
The function locks RCU internally.
The functor may change non-key fields of the \p item; however, \p func must guarantee
that during changing no any other modifications could be made on this item by concurrent threads.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
i.e. the item has been inserted or updated,
\p second is \p true if the new item has been added or \p false if the item with key equal to \p val
already exists.
RCU \p synchronize() method can be called. RCU should not be locked.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
\p second is \p true if new node has been added or \p false if the node with \p key
already exists.
*/
however, \p func must guarantee that during changing no any other modifications
could be made on this item by concurrent threads.
- Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+ Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
i.e. the node has been inserted or updated,
\p second is \p true if new item has been added or \p false if the item with \p key
already exists.
The functor can change non-key fields of the \p item; however, \p func must guarantee
that during changing no any other modifications could be made on this item by concurrent threads.
- Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+ Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
i.e. the node has been inserted or updated,
\p second is \p true if new item has been added or \p false if the item with \p key
already exists.
The functor may change any fields of the \p item.second.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
\p second is \p true if new item has been added or \p false if \p key already exists.
@warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
The functor may change non-key fields of the \p item; however, \p func must guarantee
that during changing no any other modifications could be made on this item by concurrent threads.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
i.e. the item has been inserted or updated,
\p second is \p true if the new item has been added or \p false if the item with key equal to \p val
already exists.
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSLIB_CONTAINER_IMPL_ITERABLE_KVLIST_H
+#define CDSLIB_CONTAINER_IMPL_ITERABLE_KVLIST_H
+
+#include <memory>
+#include <cds/container/details/guarded_ptr_cast.h>
+
+namespace cds { namespace container {
+
+ /// Iterable ordered list for key-value pair
+ /** @ingroup cds_nonintrusive_list
+ \anchor cds_nonintrusive_IterableKVList_gc
+
+ This is key-value variation of non-intrusive \p IterableList.
+ Like standard container, this implementation split a value stored into two part -
+ constant key and alterable value.
+
+ Usually, ordered single-linked list is used as a building block for the hash table implementation.
+ Iterable list is suitable for almost append-only hash table because the list doesn't delete
+ its internal node when erasing a key but it is marked them as empty to be reused in the future.
+ However, plenty of empty nodes degrades performance.
+
+ The complexity of searching is <tt>O(N)</tt>.
+
+ Template arguments:
+ - \p GC - garbage collector used
+ - \p Key - key type of an item stored in the list. It should be copy-constructible
+ - \p Value - value type stored in a list
+ - \p Traits - type traits, default is \p iterable_list::traits
+
+ It is possible to declare option-based list with \p cds::container::iterable_list::make_traits metafunction instead of \p Traits template
+ argument. For example, the following traits-based declaration of \p gc::HP iterable list
+ \code
+ #include <cds/container/iterable_kvlist_hp.h>
+ // Declare comparator for the item
+ struct my_compare {
+ int operator ()( int i1, int i2 )
+ {
+ return i1 - i2;
+ }
+ };
+
+ // Declare traits
+ struct my_traits: public cds::container::iterable_list::traits
+ {
+ typedef my_compare compare;
+ };
+
+ // Declare traits-based list
+ typedef cds::container::IterableKVList< cds::gc::HP, int, int, my_traits > traits_based_list;
+ \endcode
+ is equivalent for the following option-based list
+ \code
+ #include <cds/container/iterable_kvlist_hp.h>
+
+ // my_compare is the same
+
+ // Declare option-based list
+ typedef cds::container::IterableKVList< cds::gc::HP, int, int,
+ typename cds::container::iterable_list::make_traits<
+ cds::container::opt::compare< my_compare > // item comparator option
+ >::type
+ > option_based_list;
+ \endcode
+
+ \par Usage
+ There are different specializations of this template for each garbage collecting schema used.
+ You should include appropriate .h-file depending on GC you are using:
+ - for gc::HP: \code #include <cds/container/iterable_kvlist_hp.h> \endcode
+ - for gc::DHP: \code #include <cds/container/iterable_kvlist_dhp.h> \endcode
+ - for \ref cds_urcu_desc "RCU": \code #include <cds/container/iterable_kvlist_rcu.h> \endcode
+ */
+ template <
+ typename GC,
+ typename Key,
+ typename Value,
+#ifdef CDS_DOXYGEN_INVOKED
+ typename Traits = iterable_list::traits
+#else
+ typename Traits
+#endif
+ >
+ class IterableKVList:
+#ifdef CDS_DOXYGEN_INVOKED
+ protected container::IterableList< GC, std::pair<Key, Value>, Traits >
+#else
+ protected details::make_iterable_kvlist< GC, Key, Value, Traits >::type
+#endif
+ {
+ //@cond
+ typedef details::make_iterable_kvlist< GC, Key, Value, Traits > maker;
+ typedef typename maker::type base_class;
+ //@endcond
+
+ public:
+#ifdef CDS_DOXYGEN_INVOKED
+ typedef Key key_type; ///< Key type
+ typedef Value mapped_type; ///< Type of value stored in the list
+ typedef std::pair<key_type const, mapped_type> value_type; ///< key/value pair stored in the list
+#else
+ typedef typename maker::key_type key_type;
+ typedef typename maker::mapped_type mapped_type;
+ typedef typename maker::value_type value_type;
+#endif
+
+ typedef typename base_class::gc gc; ///< Garbage collector used
+ typedef typename base_class::back_off back_off; ///< Back-off strategy used
+ typedef typename maker::data_allocator_type allocator_type; ///< Allocator type used for allocate/deallocate data
+ typedef typename base_class::item_counter item_counter; ///< Item counting policy used
+ typedef typename maker::key_comparator key_comparator; ///< key comparison functor
+ typedef typename base_class::memory_model memory_model; ///< Memory ordering. See cds::opt::memory_model option
+ typedef typename base_class::stat stat; ///< Internal statistics
+
+ static CDS_CONSTEXPR const size_t c_nHazardPtrCount = base_class::c_nHazardPtrCount; ///< Count of hazard pointer required for the algorithm
+
+ /// Guarded pointer
+ typedef typename base_class::guarded_ptr guarded_ptr;
+
+ protected:
+ //@cond
+ typedef typename base_class::head_type head_type;
+ typedef typename maker::cxx_data_allocator cxx_data_allocator;
+
+ template <typename Less>
+ using less_wrapper = typename maker::template less_wrapper< Less >;
+
+ template <bool IsConst>
+ using iterator_type = typename base_class::template iterator_type<IsConst>;
+ //@endcond
+
+ public:
+ /// Forward iterator
+ /**
+ The forward iterator for iterable list has some features:
+ - it has no post-increment operator
+ - to protect the value, the iterator contains a GC-specific guard.
+ For some GC (like as \p gc::HP), a guard is a limited resource per thread, so an exception (or assertion) "no free guard"
+ may be thrown if the limit of guard count per thread is exceeded.
+ - The iterator cannot be moved across thread boundary since it contains thread-private GC's guard.
+ - Iterator is thread-safe: even if an element the iterator points to is removed, the iterator stays valid because
+ it contains the guard keeping the value from to be recycled.
+
+ The iterator interface:
+ \code
+ class iterator {
+ public:
+ // Default constructor
+ iterator();
+
+ // Copy constructor
+ iterator( iterator const& src );
+
+ // Dereference operator
+ value_type * operator ->() const;
+
+ // Dereference operator
+ value_type& operator *() const;
+
+ // Preincrement operator
+ iterator& operator ++();
+
+ // Assignment operator
+ iterator& operator = (iterator const& src);
+
+ // Equality operators
+ bool operator ==(iterator const& i ) const;
+ bool operator !=(iterator const& i ) const;
+ };
+ \endcode
+
+ @note For two iterators pointed to the same element the value can be different;
+ this code
+ \code
+ if ( it1 == it2 )
+ assert( &(*it1) == &(*it2) );
+ \endcode
+ can throw assertion. The point is that the iterator stores the value of element which can be modified later by other thread.
+ The guard inside the iterator prevents recycling that value so the iterator's value remains valid even after such changing.
+ Other iterator can observe modified value of the element.
+ */
+ using typename base_class::iterator;
+ using typename base_class::const_iterator;
+ using base_class::begin;
+ using base_class::end;
+ using base_class::cbegin;
+ using base_class::cend;
+
+ public:
+ /// Default constructor
+ /**
+ Initializes empty list
+ */
+ IterableKVList()
+ {}
+
+ //@cond
+ template <typename Stat, typename = std::enable_if<std::is_same<stat, iterable_list::wrapped_stat<Stat>>::value >>
+ explicit IterableKVList( Stat& st )
+ : base_class( st )
+ {}
+ //@endcond
+
+ /// List destructor
+ /**
+ Clears the list
+ */
+ ~IterableKVList()
+ {}
+
+ /// Inserts new node with key and default value
+ /**
+ The function creates a node with \p key and default value, and then inserts the node created into the list.
+
+ Preconditions:
+ - The \p key_type should be constructible from value of type \p K. In trivial case, \p K is equal to \p key_type.
+ - The \p mapped_type should be default-constructible.
+
+ Returns \p true if inserting successful, \p false otherwise.
+
+ @note The function is supported only if \ref mapped_type is default constructible
+ */
+ template <typename K>
+ bool insert( K&& key )
+ {
+ return base_class::emplace( key_type( std::forward<K>( key )), mapped_type());
+ }
+
+ /// Inserts new node with a key and a value
+ /**
+ The function creates a node with \p key and value \p val, and then inserts the node created into the list.
+
+ Preconditions:
+ - The \p key_type should be constructible from \p key of type \p K.
+ - The \p mapped_type should be constructible from \p val of type \p V.
+
+ Returns \p true if inserting successful, \p false otherwise.
+ */
+ template <typename K, typename V>
+ bool insert( K&& key, V&& val )
+ {
+ return base_class::emplace( key_type( std::forward<K>( key )), mapped_type( std::forward<V>( val )));
+ }
+
+ /// Inserts new node and initialize it by a functor
+ /**
+ This function inserts new node with key \p key and if inserting is successful then it calls
+ \p func functor with signature
+ \code
+ struct functor {
+ void operator()( value_type& item );
+ };
+ \endcode
+
+ The argument \p item of user-defined functor \p func is the reference
+ to the item inserted. <tt>item.second</tt> is a reference to item's value that may be changed.
+ User-defined functor \p func should guarantee that during changing item's value no any other changes
+ could be made on this list's item by concurrent threads.
+ The user-defined functor is called only if inserting is successful.
+
+ The \p key_type should be constructible from value of type \p K.
+
+ The function allows to split creating of new item into two part:
+ - create a new item from \p key;
+ - insert the new item into the list;
+ - if inserting is successful, initialize the value of item by calling \p func functor
+
+ This can be useful if complete initialization of object of \p mapped_type is heavyweight and
+ it is preferable that the initialization should be completed only if inserting is successful.
+
+ @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
+
+ @note The function is supported only if \ref mapped_type is default constructible
+ */
+ template <typename K, typename Func>
+ bool insert_with( K&& key, Func func )
+ {
+ return base_class::insert( value_type( key_type( std::forward<K>( key )), mapped_type()), func );
+ }
+
+ /// Updates data by \p key
+ /**
+ The operation performs inserting or replacing the element with lock-free manner.
+
+ If the \p key not found in the list, then the new item created from \p key
+ will be inserted iff \p bAllowInsert is \p true.
+ (note that in this case the \ref key_type should be constructible from type \p K).
+ Otherwise, if \p key is found, the functor \p func is called with item found.
+
+ The functor \p func is called after inserting or replacing, it signature is:
+ \code
+ void func( value_type& val, value_type* old );
+ \endcode
+ where
+ - \p val - a new data constructed from \p key
+ - \p old - old value that will be retired. If new item has been inserted then \p old is \p nullptr.
+
+ The functor may change non-key fields of \p val; however, \p func must guarantee
+ that during changing no any other modifications could be made on this item by concurrent threads.
+
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
+ \p second is true if new item has been added or \p false if the item with such \p key
+ already exists.
+
+ @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
+
+ @note The function is supported only if \ref mapped_type is default constructible
+ */
+ template <typename K, typename Func>
+ std::pair<bool, bool> update( K&& key, Func f, bool bAllowInsert = true )
+ {
+ return base_class::update( value_type( key_type( std::forward<K>( key )), mapped_type()), f, bAllowInsert );
+ }
+
+ /// Insert or update
+ /**
+ The operation performs inserting or updating data with lock-free manner.
+
+ If the item \p key is not found in the list, then \p key is inserted
+ iff \p bInsert is \p true.
+ Otherwise, the current element is changed to <tt> value_type( key, val )</tt>,
+ the old element will be retired later.
+
+ Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
+ \p second is \p true if \p key has been added or \p false if the item with that key
+ already in the list.
+ */
+ template <typename Q, typename V >
+ std::pair<bool, bool> upsert( Q&& key, V&& val, bool bInsert = true )
+ {
+ return base_class::upsert( value_type( key_type( std::forward<Q>( key )), mapped_type( std::forward<V>( val ))), bInsert );
+ }
+
+ /// Inserts a new node using move semantics
+ /**
+ \p key_type field of new item is constructed from \p key argument,
+ \p mapped_type field is done from \p args.
+
+ Returns \p true if inserting successful, \p false otherwise.
+ */
+ template <typename K, typename... Args>
+ bool emplace( K&& key, Args&&... args )
+ {
+ return base_class::emplace( key_type( std::forward<K>( key )), mapped_type( std::forward<Args>( args )... ));
+ }
+
+ /// Deletes \p key from the list
+ /**
+
+ Returns \p true if \p key is found and has been deleted, \p false otherwise
+ */
+ template <typename K>
+ bool erase( K const& key )
+ {
+ return base_class::erase( key );
+ }
+
+ /// Deletes the item from the list using \p pred predicate for searching
+ /**
+ The function is an analog of \p erase(K const&) but \p pred is used for key comparing.
+ \p Less functor has the interface like \p std::less.
+ \p pred must imply the same element order as the comparator used for building the list.
+ */
+ template <typename K, typename Less>
+ bool erase_with( K const& key, Less pred )
+ {
+ CDS_UNUSED( pred );
+ return base_class::erase_with( key, less_wrapper<Less>() );
+ }
+
+ /// Deletes \p key from the list
+ /**
+ The function searches an item with key \p key, calls \p f functor
+ and deletes the item. If \p key is not found, the functor is not called.
+
+ The functor \p Func interface:
+ \code
+ struct extractor {
+ void operator()(value_type& val) { ... }
+ };
+ \endcode
+
+ Return \p true if key is found and deleted, \p false otherwise
+ */
+ template <typename K, typename Func>
+ bool erase( K const& key, Func f )
+ {
+ return base_class::erase( key, f );
+ }
+
+ /// Deletes the item from the list using \p pred predicate for searching
+ /**
+ The function is an analog of \p erase(K const&, Func) but \p pred is used for key comparing.
+ \p Less functor has the interface like \p std::less.
+ \p pred must imply the same element order as the comparator used for building the list.
+ */
+ template <typename K, typename Less, typename Func>
+ bool erase_with( K const& key, Less pred, Func f )
+ {
+ CDS_UNUSED( pred );
+ return base_class::erase_with( key, less_wrapper<Less>(), f );
+ }
+
+ /// Extracts the item from the list with specified \p key
+ /**
+ The function searches an item with key equal to \p key,
+ unlinks it from the list, and returns it as \p guarded_ptr.
+ If \p key is not found the function returns an empty guarded pointer.
+
+ Note the compare functor should accept a parameter of type \p K that can be not the same as \p key_type.
+
+ The \p disposer specified in \p Traits class template parameter is called automatically
+ by garbage collector \p GC specified in class' template parameters when returned \p guarded_ptr object
+ will be destroyed or released.
+ @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
+
+ Usage:
+ \code
+ typedef cds::container::IterableKVList< cds::gc::HP, int, foo, my_traits > ord_list;
+ ord_list theList;
+ // ...
+ {
+ ord_list::guarded_ptr gp(theList.extract( 5 ));
+ if ( gp ) {
+ // Deal with gp
+ // ...
+ }
+ // Destructor of gp releases internal HP guard
+ }
+ \endcode
+ */
+ template <typename K>
+ guarded_ptr extract( K const& key )
+ {
+ return base_class::extract( key );
+ }
+
+ /// Extracts the item from the list with comparing functor \p pred
+ /**
+ The function is an analog of \p extract(K const&) but \p pred predicate is used for key comparing.
+
+ \p Less functor has the semantics like \p std::less but should take arguments of type \ref key_type and \p K
+ in any order.
+ \p pred must imply the same element order as the comparator used for building the list.
+ */
+ template <typename K, typename Less>
+ guarded_ptr extract_with( K const& key, Less pred )
+ {
+ CDS_UNUSED( pred );
+ return base_class::extract_with( key, less_wrapper<Less>() );
+ }
+
+ /// Checks whether the list contains \p key
+ /**
+ The function searches the item with key equal to \p key
+ and returns \p true if it is found, and \p false otherwise.
+ */
+ template <typename Q>
+ bool contains( Q const& key ) const
+ {
+ return base_class::contains( key );
+ }
+
+ /// Checks whether the map contains \p key using \p pred predicate for searching
+ /**
+ The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
+ \p Less functor has the interface like \p std::less.
+ \p Less must imply the same element order as the comparator used for building the list.
+ */
+ template <typename Q, typename Less>
+ bool contains( Q const& key, Less pred ) const
+ {
+ CDS_UNUSED( pred );
+ return base_class::contains( key, less_wrapper<Less>() );
+ }
+
+ /// Finds the key \p key and performs an action with it
+ /**
+ The function searches an item with key equal to \p key and calls the functor \p f for the item found.
+ The interface of \p Func functor is:
+ \code
+ struct functor {
+ void operator()( value_type& item );
+ };
+ \endcode
+ where \p item is the item found.
+
+ The functor may change <tt>item.second</tt> that is reference to value of node.
+ Note that the function is only guarantee that \p item cannot be deleted during functor is executing.
+ The function does not serialize simultaneous access to the list \p item. If such access is
+ possible you must provide your own synchronization schema to exclude unsafe item modifications.
+
+ The function returns \p true if \p key is found, \p false otherwise.
+ */
+ template <typename Q, typename Func>
+ bool find( Q const& key, Func f ) const
+ {
+ return base_class::find( key, [&f]( value_type& v, Q const& ) { f( v ); } );
+ }
+
+ /// Finds \p key in the list and returns iterator pointed to the item found
+ /**
+ If \p key is not found the function returns \p end().
+ */
+ template <typename Q>
+ iterator find( Q const& key ) const
+ {
+ return base_class::find( key );
+ }
+
+ /// Finds the key \p val using \p pred predicate for searching
+ /**
+ The function is an analog of \p find(Q&, Func) but \p pred is used for key comparing.
+ \p Less functor has the interface like \p std::less.
+ \p pred must imply the same element order as the comparator used for building the list.
+ */
+ template <typename Q, typename Less, typename Func>
+ bool find_with( Q const& key, Less pred, Func f ) const
+ {
+ CDS_UNUSED( pred );
+ return base_class::find_with( key, less_wrapper<Less>(), [&f]( value_type& v, Q const& ) { f( v ); } );
+ }
+
+ /// Finds \p key in the list using \p pred predicate for searching and returns iterator pointed to the item found
+ /**
+ The function is an analog of \p find(Q&) but \p pred is used for key comparing.
+ \p Less functor has the interface like \p std::less.
+ \p pred must imply the same element order as the comparator used for building the list.
+
+ If \p key is not found the function returns \p end().
+ */
+ template <typename Q, typename Less>
+ iterator find_with( Q const& key, Less pred ) const
+ {
+ CDS_UNUSED( pred );
+ return base_class::find_with( key, less_wrapper<Less>());
+ }
+
+ /// Finds the \p key and return the item found
+ /**
+ The function searches the item with key equal to \p key
+ and returns it as \p guarded_ptr.
+ If \p key is not found the function returns an empty guarded pointer.
+
+ @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
+
+ Usage:
+ \code
+ typedef cds::container::IterableKVList< cds::gc::HP, int, foo, my_traits > ord_list;
+ ord_list theList;
+ // ...
+ {
+ ord_list::guarded_ptr gp(theList.get( 5 ));
+ if ( gp ) {
+ // Deal with gp
+ //...
+ }
+ // Destructor of guarded_ptr releases internal HP guard
+ }
+ \endcode
+
+ Note the compare functor specified for class \p Traits template parameter
+ should accept a parameter of type \p K that can be not the same as \p key_type.
+ */
+ template <typename K>
+ guarded_ptr get( K const& key ) const
+ {
+ return base_class::get( key );
+ }
+
+ /// Finds the \p key and return the item found
+ /**
+ The function is an analog of \p get( guarded_ptr& ptr, K const&)
+ but \p pred is used for comparing the keys.
+
+ \p Less functor has the semantics like \p std::less but should take arguments of type \ref key_type and \p K
+ in any order.
+ \p pred must imply the same element order as the comparator used for building the list.
+ */
+ template <typename K, typename Less>
+ guarded_ptr get_with( K const& key, Less pred ) const
+ {
+ CDS_UNUSED( pred );
+ return base_class::get_with( key, less_wrapper<Less>() );
+ }
+
+ /// Checks if the list is empty
+ /**
+ Emptiness is checked by item counting: if item count is zero then the set is empty.
+ Thus, if you need to use \p %empty() you should provide appropriate (non-empty) \p iterable_list::traits::item_counter
+ feature.
+ */
+ bool empty() const
+ {
+ return base_class::empty();
+ }
+
+ /// Returns list's item count
+ /**
+ The value returned depends on item counter provided by \p Traits. For \p atomicity::empty_item_counter,
+ this function always returns 0.
+ */
+ size_t size() const
+ {
+ return base_class::size();
+ }
+
+ /// Clears the list
+ void clear()
+ {
+ base_class::clear();
+ }
+
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return base_class::statistics();
+ }
+
+ protected:
+ //@cond
+ // Split-list support
+
+ template <typename K>
+ bool insert_at( head_type& refHead, K const& key )
+ {
+ return base_class::insert_at( refHead, value_type( key_type( key ), mapped_type() ));
+ }
+
+ template <typename K, typename V>
+ bool insert_at( head_type& refHead, const K& key, V const& val )
+ {
+ return base_class::insert_at( refHead, value_type( key_type( key ), val ));
+ }
+
+ template <typename K, typename Func>
+ bool insert_with_at( head_type& refHead, K const& key, Func f )
+ {
+ return base_class::insert_at( refHead, value_type( key_type( key ), mapped_type()), f );
+ }
+
+ template <typename K, typename... Args>
+ bool emplace_at( head_type& refHead, K&& key, Args&&... args )
+ {
+ return base_class::emplace_at( refHead, std::forward<K>(key), std::forward<Args>(args)... );
+ }
+
+ template <typename K, typename Func>
+ std::pair<bool, bool> update_at( head_type& refHead, const K& key, Func f, bool bAllowInsert )
+ {
+ return base_class::update_at( refHead, value_type( key_type( key ), mapped_type()), f, bAllowInsert );
+ }
+
+ template <typename K, typename Compare>
+ bool erase_at( head_type& refHead, K const& key, Compare cmp )
+ {
+ return base_class::erase_at( refHead, key, cmp );
+ }
+
+ template <typename K, typename Compare, typename Func>
+ bool erase_at( head_type& refHead, K const& key, Compare cmp, Func f )
+ {
+ return base_class::erase_at( refHead, key, cmp, f );
+ }
+ template <typename K, typename Compare>
+ bool extract_at( head_type& refHead, typename guarded_ptr::native_guard& guard, K const& key, Compare cmp )
+ {
+ return base_class::extract_at( refHead, guard, key, cmp );
+ }
+
+ template <typename K, typename Compare>
+ bool find_at( head_type& refHead, K const& key, Compare cmp )
+ {
+ return base_class::find_at( refHead, key, cmp );
+ }
+
+ template <typename K, typename Compare, typename Func>
+ bool find_at( head_type& refHead, K& key, Compare cmp, Func f )
+ {
+ return base_class::find_at( refHead, key, cmp, f );
+ }
+
+ template <typename K, typename Compare>
+ bool get_at( head_type& refHead, typename guarded_ptr::native_guard& guard, K const& key, Compare cmp )
+ {
+ return base_class::get_at( refHead, guard, key, cmp );
+ }
+
+ //@endcond
+ };
+
+}} // namespace cds::container
+
+#endif // #ifndef CDSLIB_CONTAINER_IMPL_ITERABLE_KVLIST_H
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSLIB_CONTAINER_IMPL_ITERABLE_LIST_H
+#define CDSLIB_CONTAINER_IMPL_ITERABLE_LIST_H
+
+#include <cds/container/details/make_iterable_list.h>
+#include <memory>
+
+namespace cds { namespace container {
+
+ /// Iterable ordered list
+ /** @ingroup cds_nonintrusive_list
+ \anchor cds_nonintrusive_IterableList_gc
+
+ This lock-free list implementation supports thread-safe iterators.
+
+ Usually, ordered single-linked list is used as a building block for the hash table implementation.
+ Iterable list is suitable for almost append-only hash table because the list doesn't delete
+ its internal node when erasing a key but it is marked them as empty to be reused in the future.
+ However, plenty of empty nodes degrades performance.
+
+ The complexity of searching is <tt>O(N)</tt>.
+
+ Template arguments:
+ - \p GC - Garbage collector used.
+ - \p T - type to be stored in the list.
+ - \p Traits - type traits, default is \p iterable_list::traits.
+
+ Unlike standard container, this implementation does not divide type \p T into key and value part and
+ may be used as a main building block for hash set algorithms.
+ The key is a function (or a part) of type \p T, and this function is specified by <tt>Traits::compare</tt> functor
+ or <tt>Traits::less</tt> predicate.
+
+ \p IterableKVList is a key-value version of iterable non-intrusive list that is closer to the C++ std library approach.
+
+ It is possible to declare option-based list with cds::container::iterable_list::make_traits metafunction istead of \p Traits template
+ argument. For example, the following traits-based declaration of gc::HP iterable list
+ \code
+ #include <cds/container/iterable_list_hp.h>
+ // Declare comparator for the item
+ struct my_compare {
+ int operator ()( int i1, int i2 )
+ {
+ return i1 - i2;
+ }
+ };
+
+ // Declare traits
+ struct my_traits: public cds::container::iterable_list::traits
+ {
+ typedef my_compare compare;
+ };
+
+ // Declare traits-based list
+ typedef cds::container::IterableList< cds::gc::HP, int, my_traits > traits_based_list;
+ \endcode
+
+ is equivalent for the following option-based list
+ \code
+ #include <cds/container/iterable_list_hp.h>
+
+ // my_compare is the same
+
+ // Declare option-based list
+ typedef cds::container::IterableList< cds::gc::HP, int,
+ typename cds::container::iterable_list::make_traits<
+ cds::container::opt::compare< my_compare > // item comparator option
+ >::type
+ > option_based_list;
+ \endcode
+
+ \par Usage
+ There are different specializations of this template for each garbage collecting schema used.
+ You should include appropriate .h-file depending on GC you are using:
+ - for gc::HP: \code #include <cds/container/iterable_list_hp.h> \endcode
+ - for gc::DHP: \code #include <cds/container/iterable_list_dhp.h> \endcode
+ - for \ref cds_urcu_desc "RCU": \code #include <cds/container/iterable_list_rcu.h> \endcode
+ */
+ template <
+ typename GC,
+ typename T,
+#ifdef CDS_DOXYGEN_INVOKED
+ typename Traits = iterable_list::traits
+#else
+ typename Traits
+#endif
+ >
+ class IterableList:
+#ifdef CDS_DOXYGEN_INVOKED
+ protected intrusive::IterableList< GC, T, Traits >
+#else
+ protected details::make_iterable_list< GC, T, Traits >::type
+#endif
+ {
+ //@cond
+ typedef details::make_iterable_list< GC, T, Traits > maker;
+ typedef typename maker::type base_class;
+ //@endcond
+
+ public:
+ typedef T value_type; ///< Type of value stored in the list
+ typedef Traits traits; ///< List traits
+
+ typedef typename base_class::gc gc; ///< Garbage collector used
+ typedef typename base_class::back_off back_off; ///< Back-off strategy used
+ typedef typename maker::data_allocator_type allocator_type; ///< Allocator type used for allocate/deallocate data
+ typedef typename base_class::item_counter item_counter; ///< Item counting policy used
+ typedef typename maker::key_comparator key_comparator; ///< key comparison functor
+ typedef typename base_class::memory_model memory_model; ///< Memory ordering. See \p cds::opt::memory_model option
+ typedef typename base_class::stat stat; ///< Internal statistics
+
+ static CDS_CONSTEXPR const size_t c_nHazardPtrCount = base_class::c_nHazardPtrCount; ///< Count of hazard pointer required for the algorithm
+
+ //@cond
+ // Rebind traits (split-list support)
+ template <typename... Options>
+ struct rebind_traits {
+ typedef IterableList<
+ gc
+ , value_type
+ , typename cds::opt::make_options< traits, Options...>::type
+ > type;
+ };
+
+ // Stat selector
+ template <typename Stat>
+ using select_stat_wrapper = typename base_class::template select_stat_wrapper< Stat >;
+ //@endcond
+
+ protected:
+ //@cond
+ typedef typename maker::cxx_data_allocator cxx_data_allocator;
+ typedef typename maker::data_disposer data_disposer;
+ typedef typename base_class::atomic_node_ptr head_type;
+ //@endcond
+
+ public:
+ /// Guarded pointer
+ typedef typename base_class::guarded_ptr guarded_ptr;
+
+ protected:
+ //@cond
+ template <bool IsConst>
+ class iterator_type: protected base_class::template iterator_type<IsConst>
+ {
+ typedef typename base_class::template iterator_type<IsConst> iterator_base;
+ friend class IterableList;
+
+ iterator_type( head_type const& pNode )
+ : iterator_base( pNode )
+ {}
+
+ iterator_type( iterator_base it )
+ : iterator_base( it )
+ {}
+
+ public:
+ typedef typename iterator_base::value_ptr value_ptr;
+ typedef typename iterator_base::value_ref value_ref;
+
+ iterator_type()
+ {}
+
+ iterator_type( iterator_type const& src )
+ : iterator_base( src )
+ {}
+
+ value_ptr operator ->() const
+ {
+ return iterator_base::operator ->();
+ }
+
+ value_ref operator *() const
+ {
+ return iterator_base::operator *();
+ }
+
+ /// Pre-increment
+ iterator_type& operator ++()
+ {
+ iterator_base::operator ++();
+ return *this;
+ }
+
+ template <bool C>
+ bool operator ==(iterator_type<C> const& i ) const
+ {
+ return iterator_base::operator ==(i);
+ }
+ template <bool C>
+ bool operator !=(iterator_type<C> const& i ) const
+ {
+ return iterator_base::operator !=(i);
+ }
+ };
+ //@endcond
+
+ public:
+ ///@name Thread-safe forward iterators
+ //@{
+ /// Forward iterator
+ /**
+ The forward iterator for iterable list has some features:
+ - it has no post-increment operator
+ - to protect the value, the iterator contains a GC-specific guard.
+ For some GC (like as \p gc::HP), a guard is a limited resource per thread, so an exception (or assertion) "no free guard"
+ may be thrown if the limit of guard count per thread is exceeded.
+ - The iterator cannot be moved across thread boundary since it contains thread-private GC's guard.
+ - Iterator is thread-safe: even if an element the iterator points to is removed, the iterator stays valid because
+ it contains the guard keeping the value from to be recycled.
+
+ The iterator interface:
+ \code
+ class iterator {
+ public:
+ // Default constructor
+ iterator();
+
+ // Copy constructor
+ iterator( iterator const& src );
+
+ // Dereference operator
+ value_type * operator ->() const;
+
+ // Dereference operator
+ value_type& operator *() const;
+
+ // Preincrement operator
+ iterator& operator ++();
+
+ // Assignment operator
+ iterator& operator = (iterator const& src);
+
+ // Equality operators
+ bool operator ==(iterator const& i ) const;
+ bool operator !=(iterator const& i ) const;
+ };
+ \endcode
+
+ @note For two iterators pointed to the same element the value can be different;
+ this code
+ \code
+ if ( it1 == it2 )
+ assert( &(*it1) == &(*it2) );
+ \endcode
+ can throw assertion. The point is that the iterator stores the value of element which can be modified later by other thread.
+ The guard inside the iterator prevents recycling that value so the iterator's value remains valid even after such changing.
+ Other iterator can observe modified value of the element.
+ */
+ typedef iterator_type<false> iterator;
+
+ /// Const forward iterator
+ /**
+ For iterator's features and requirements see \ref iterator
+ */
+ typedef iterator_type<true> const_iterator;
+
+ /// Returns a forward iterator addressing the first element in a list
+ /**
+ For empty list \code begin() == end() \endcode
+ */
+ iterator begin()
+ {
+ return iterator( head() );
+ }
+
+ /// Returns an iterator that addresses the location succeeding the last element in a list
+ /**
+ Do not use the value returned by <tt>end</tt> function to access any item.
+ Internally, <tt>end</tt> returning value equals to \p nullptr.
+
+ The returned value can be used only to control reaching the end of the list.
+ For empty list \code begin() == end() \endcode
+ */
+ iterator end()
+ {
+ return iterator();
+ }
+
+ /// Returns a forward const iterator addressing the first element in a list
+ const_iterator begin() const
+ {
+ return const_iterator( head() );
+ }
+
+ /// Returns a forward const iterator addressing the first element in a list
+ const_iterator cbegin() const
+ {
+ return const_iterator( head() );
+ }
+
+ /// Returns an const iterator that addresses the location succeeding the last element in a list
+ const_iterator end() const
+ {
+ return const_iterator();
+ }
+
+ /// Returns an const iterator that addresses the location succeeding the last element in a list
+ const_iterator cend() const
+ {
+ return const_iterator();
+ }
+ //@}
+
+ public:
+ /// Default constructor
+ /**
+ Initialize empty list
+ */
+ IterableList()
+ {}
+
+ //@cond
+ template <typename Stat, typename = std::enable_if<std::is_same<stat, iterable_list::wrapped_stat<Stat>>::value >>
+ explicit IterableList( Stat& st )
+ : base_class( st )
+ {}
+ //@endcond
+
+ /// List destructor
+ /**
+ Clears the list
+ */
+ ~IterableList()
+ {}
+
+ /// Inserts new node
+ /**
+ The function creates a node with copy of \p val value
+ and then inserts the node created into the list.
+
+ The type \p Q should contain least the complete key of the node.
+ The object of \ref value_type should be constructible from \p val of type \p Q.
+ In trivial case, \p Q is equal to \ref value_type.
+
+ Returns \p true if inserting successful, \p false otherwise.
+ */
+ template <typename Q>
+ bool insert( Q&& val )
+ {
+ return insert_at( head(), std::forward<Q>( val ));
+ }
+
+ /// Inserts new node
+ /**
+ This function inserts new node with default-constructed value and then it calls
+ \p func functor with signature
+ \code
+ void func( value_type& data );
+ \endcode
+
+ The argument \p data of user-defined functor \p func is the reference
+ to the list's item inserted. User-defined functor \p func should guarantee that during changing
+ item's value no any other changes could be made on this list's item by concurrent threads.
+ The user-defined functor is called only if inserting is success.
+
+ The type \p Q should contain the complete key of the node.
+ The object of \p value_type should be constructible from \p key of type \p Q.
+
+ The function allows to split creating of new item into two part:
+ - create item from \p key with initializing key-fields only;
+ - insert new item into the list;
+ - if inserting is successful, initialize non-key fields of item by calling \p func functor
+
+ The method can be useful if complete initialization of object of \p value_type is heavyweight and
+ it is preferable that the initialization should be completed only if inserting is successful.
+
+ @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
+ */
+ template <typename Q, typename Func>
+ bool insert( Q&& key, Func func )
+ {
+ return insert_at( head(), std::forward<Q>( key ), func );
+ }
+
+ /// Updates data by \p key
+ /**
+ The operation performs inserting or replacing the element with lock-free manner.
+
+ If the \p key not found in the list, then the new item created from \p key
+ will be inserted iff \p bAllowInsert is \p true.
+ Otherwise, if \p key is found, the functor \p func is called with item found.
+
+ The functor \p func is called after inserting or replacing, it signature is:
+ \code
+ void func( value_type& val, value_type * old );
+ \endcode
+ where
+ - \p val - a new data constructed from \p key
+ - \p old - old value that will be retired. If new item has been inserted then \p old is \p nullptr.
+
+ The functor may change non-key fields of \p val; however, \p func must guarantee
+ that during changing no any other modifications could be made on this item by concurrent threads.
+
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
+ \p second is true if new item has been added or \p false if the item with such \p key
+ already exists.
+
+ @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
+ */
+ template <typename Q, typename Func>
+ std::pair<bool, bool> update( Q&& key, Func func, bool bAllowInsert = true )
+ {
+ return update_at( head(), std::forward<Q>( key ), func, bAllowInsert );
+ }
+
+ /// Insert or update
+ /**
+ The operation performs inserting or updating data with lock-free manner.
+
+ If the item \p key is not found in the list, then \p key is inserted
+ iff \p bInsert is \p true.
+ Otherwise, the current element is changed to \p key, the old element will be retired later.
+
+ \p value_type should be constructible from \p key.
+
+ Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
+ \p second is \p true if \p key has been added or \p false if the item with that key
+ already in the list.
+ */
+ template <typename Q>
+ std::pair<bool, bool> upsert( Q&& key, bool bInsert = true )
+ {
+ return update_at( head(), std::forward<Q>( key ), []( value_type&, value_type* ) {}, bInsert );
+ }
+
+ /// Inserts data of type \p value_type constructed with <tt>std::forward<Args>(args)...</tt>
+ /**
+ Returns \p true if inserting successful, \p false otherwise.
+ */
+ template <typename... Args>
+ bool emplace( Args&&... args )
+ {
+ return emplace_at( head(), std::forward<Args>(args)... );
+ }
+
+ /// Delete \p key from the list
+ /**
+ Since the key of IterableList's item type \p value_type is not explicitly specified,
+ template parameter \p Q sould contain the complete key to search in the list.
+ The list item comparator should be able to compare the type \p value_type
+ and the type \p Q.
+
+ Return \p true if key is found and deleted, \p false otherwise
+ */
+ template <typename Q>
+ bool erase( Q const& key )
+ {
+ return erase_at( head(), key, key_comparator(), [](value_type const&){} );
+ }
+
+ /// Deletes the item from the list using \p pred predicate for searching
+ /**
+ The function is an analog of \p erase(Q const&) but \p pred is used for key comparing.
+ \p Less functor has the interface like \p std::less.
+ \p pred must imply the same element order as the comparator used for building the list.
+ */
+ template <typename Q, typename Less>
+ bool erase_with( Q const& key, Less pred )
+ {
+ CDS_UNUSED( pred );
+ return erase_at( head(), key, typename maker::template less_wrapper<Less>::type(), [](value_type const&){} );
+ }
+
+ /// Deletes \p key from the list
+ /**
+ The function searches an item with key \p key, calls \p f functor with item found
+ and deletes it. If \p key is not found, the functor is not called.
+
+ The functor \p Func interface:
+ \code
+ struct extractor {
+ void operator()(const value_type& val) { ... }
+ };
+ \endcode
+
+ Since the key of IterableList's item type \p value_type is not explicitly specified,
+ template parameter \p Q should contain the complete key to search in the list.
+ The list item comparator should be able to compare the type \p value_type of list item
+ and the type \p Q.
+
+ Return \p true if key is found and deleted, \p false otherwise
+ */
+ template <typename Q, typename Func>
+ bool erase( Q const& key, Func f )
+ {
+ return erase_at( head(), key, key_comparator(), f );
+ }
+
+ /// Deletes the item from the list using \p pred predicate for searching
+ /**
+ The function is an analog of \p erase(Q const&, Func) but \p pred is used for key comparing.
+ \p Less functor has the interface like \p std::less.
+ \p pred must imply the same element order as the comparator used for building the list.
+ */
+ template <typename Q, typename Less, typename Func>
+ bool erase_with( Q const& key, Less pred, Func f )
+ {
+ CDS_UNUSED( pred );
+ return erase_at( head(), key, typename maker::template less_wrapper<Less>::type(), f );
+ }
+
+ /// Extracts the item from the list with specified \p key
+ /**
+ The function searches an item with key equal to \p key,
+ unlinks it from the list, and returns it as \p guarded_ptr.
+ If \p key is not found the function returns an empty guarded pointer.
+
+ Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
+
+ @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
+
+ Usage:
+ \code
+ typedef cds::container::IterableList< cds::gc::HP, foo, my_traits > ord_list;
+ ord_list theList;
+ // ...
+ {
+ ord_list::guarded_ptr gp(theList.extract( 5 ));
+ if ( gp ) {
+ // Deal with gp
+ // ...
+ }
+ // Destructor of gp releases internal HP guard and frees the item
+ }
+ \endcode
+ */
+ template <typename Q>
+ guarded_ptr extract( Q const& key )
+ {
+ guarded_ptr gp;
+ extract_at( head(), gp.guard(), key, key_comparator() );
+ return gp;
+ }
+
+ /// Extracts the item from the list with comparing functor \p pred
+ /**
+ The function is an analog of \p extract(Q const&) but \p pred predicate is used for key comparing.
+
+ \p Less functor has the semantics like \p std::less but it should accept arguments
+ of type \p value_type and \p Q in any order.
+ \p pred must imply the same element order as the comparator used for building the list.
+ */
+ template <typename Q, typename Less>
+ guarded_ptr extract_with( Q const& key, Less pred )
+ {
+ CDS_UNUSED( pred );
+ guarded_ptr gp;
+ extract_at( head(), gp.guard(), key, typename maker::template less_wrapper<Less>::type() );
+ return gp;
+ }
+
+ /// Checks whether the list contains \p key
+ /**
+ The function searches the item with key equal to \p key
+ and returns \p true if it is found, and \p false otherwise.
+ */
+ template <typename Q>
+ bool contains( Q const& key ) const
+ {
+ return find_at( head(), key, key_comparator() );
+ }
+
+ /// Checks whether the list contains \p key using \p pred predicate for searching
+ /**
+ The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
+ \p Less functor has the interface like \p std::less.
+ \p pred must imply the same element order as the comparator used for building the list.
+ */
+ template <typename Q, typename Less>
+ bool contains( Q const& key, Less pred ) const
+ {
+ CDS_UNUSED( pred );
+ return find_at( head(), key, typename maker::template less_wrapper<Less>::type() );
+ }
+
+ /// Finds \p key and perform an action with it
+ /**
+ The function searches an item with key equal to \p key and calls the functor \p f for the item found.
+ The interface of \p Func functor is:
+ \code
+ struct functor {
+ void operator()( value_type& item, Q& key );
+ };
+ \endcode
+ where \p item is the item found, \p key is the <tt>find</tt> function argument.
+
+ The functor may change non-key fields of \p item. Note that the function is only guarantee
+ that \p item cannot be deleted during functor is executing.
+ The function does not serialize simultaneous access to the list \p item. If such access is
+ possible you must provide your own synchronization schema to exclude unsafe item modifications.
+
+ The function returns \p true if \p key is found, \p false otherwise.
+ */
+ template <typename Q, typename Func>
+ bool find( Q& key, Func f ) const
+ {
+ return find_at( head(), key, key_comparator(), f );
+ }
+ //@cond
+ template <typename Q, typename Func>
+ bool find( Q const& key, Func f ) const
+ {
+ return find_at( head(), key, key_comparator(), f );
+ }
+ //@endcond
+
+ /// Finds \p key in the list and returns iterator pointed to the item found
+ /**
+ If \p key is not found the function returns \p end().
+ */
+ template <typename Q>
+ iterator find( Q const& key ) const
+ {
+ return find_iterator_at( head(), key, key_comparator());
+ }
+
+ /// Finds \p key using \p pred predicate for searching
+ /**
+ The function is an analog of \p find(Q&, Func) but \p pred is used for key comparing.
+ \p Less functor has the interface like \p std::less.
+ \p pred must imply the same element order as the comparator used for building the list.
+ */
+ template <typename Q, typename Less, typename Func>
+ bool find_with( Q& key, Less pred, Func f ) const
+ {
+ CDS_UNUSED( pred );
+ return find_at( head(), key, typename maker::template less_wrapper<Less>::type(), f );
+ }
+ //@cond
+ template <typename Q, typename Less, typename Func>
+ bool find_with( Q const& key, Less pred, Func f ) const
+ {
+ CDS_UNUSED( pred );
+ return find_at( head(), key, typename maker::template less_wrapper<Less>::type(), f );
+ }
+ //@endcond
+
+ /// Finds \p key in the list using \p pred predicate for searching and returns iterator pointed to the item found
+ /**
+ The function is an analog of \p find(Q&) but \p pred is used for key comparing.
+ \p Less functor has the interface like \p std::less.
+ \p pred must imply the same element order as the comparator used for building the list.
+
+ If \p key is not found the function returns \p end().
+ */
+ template <typename Q, typename Less>
+ iterator find_with( Q const& key, Less pred ) const
+ {
+ CDS_UNUSED( pred );
+ return find_iterator_at( head(), key, cds::opt::details::make_comparator_from_less<Less>());
+ }
+
+ /// Finds \p key and return the item found
+ /** \anchor cds_nonintrusive_MichaelList_hp_get
+ The function searches the item with key equal to \p key
+ and returns it as \p guarded_ptr.
+ If \p key is not found the function returns an empty guarded pointer.
+
+ @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
+
+ Usage:
+ \code
+ typedef cds::container::MichaelList< cds::gc::HP, foo, my_traits > ord_list;
+ ord_list theList;
+ // ...
+ {
+ ord_list::guarded_ptr gp(theList.get( 5 ));
+ if ( gp ) {
+ // Deal with gp
+ //...
+ }
+ // Destructor of guarded_ptr releases internal HP guard and frees the item
+ }
+ \endcode
+
+ Note the compare functor specified for class \p Traits template parameter
+ should accept a parameter of type \p Q that can be not the same as \p value_type.
+ */
+ template <typename Q>
+ guarded_ptr get( Q const& key ) const
+ {
+ guarded_ptr gp;
+ get_at( head(), gp.guard(), key, key_comparator() );
+ return gp;
+ }
+
+ /// Finds \p key and return the item found
+ /**
+ The function is an analog of \ref cds_nonintrusive_MichaelList_hp_get "get( Q const&)"
+ but \p pred is used for comparing the keys.
+
+ \p Less functor has the semantics like \p std::less but should accept arguments of type \p value_type and \p Q
+ in any order.
+ \p pred must imply the same element order as the comparator used for building the list.
+ */
+ template <typename Q, typename Less>
+ guarded_ptr get_with( Q const& key, Less pred ) const
+ {
+ CDS_UNUSED( pred );
+ guarded_ptr gp;
+ get_at( head(), gp.guard(), key, typename maker::template less_wrapper<Less>::type() );
+ return gp;
+ }
+
+ /// Checks if the list is empty
+ /**
+ Emptiness is checked by item counting: if item count is zero then the set is empty.
+ Thus, if you need to use \p %empty() you should provide appropriate (non-empty) \p iterable_list::traits::item_counter
+ feature.
+ */
+ bool empty() const
+ {
+ return base_class::empty();
+ }
+
+ /// Returns list's item count
+ /**
+ The value returned depends on item counter provided by \p Traits. For \p atomicity::empty_item_counter,
+ this function always returns 0.
+ */
+ size_t size() const
+ {
+ return base_class::size();
+ }
+
+ /// Clears the list (thread safe, not atomic)
+ void clear()
+ {
+ base_class::clear();
+ }
+
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return base_class::statistics();
+ }
+
+ protected:
+ //@cond
+ template <typename... Args>
+ static value_type* alloc_data( Args&&... args )
+ {
+ return cxx_data_allocator().MoveNew( std::forward<Args>(args)... );
+ }
+
+ static void free_data( value_type* pData )
+ {
+ cxx_data_allocator().Delete( pData );
+ }
+
+ typedef std::unique_ptr< value_type, data_disposer > scoped_data_ptr;
+
+ head_type& head()
+ {
+ return base_class::m_pHead;
+ }
+
+ head_type const& head() const
+ {
+ return base_class::m_pHead;
+ }
+ //@endcond
+
+ protected:
+ //@cond
+ bool insert_node( value_type* pData )
+ {
+ return insert_node_at( head(), pData );
+ }
+
+ bool insert_node_at( head_type& refHead, value_type* pData )
+ {
+ assert( pData );
+ scoped_data_ptr p( pData );
+ if ( base_class::insert_at( refHead, *pData )) {
+ p.release();
+ return true;
+ }
+
+ return false;
+ }
+
+ template <typename Q>
+ bool insert_at( head_type& refHead, Q&& val )
+ {
+ return insert_node_at( refHead, alloc_data( std::forward<Q>( val )));
+ }
+
+ template <typename Q, typename Func>
+ bool insert_at( head_type& refHead, Q&& key, Func f )
+ {
+ scoped_data_ptr pNode( alloc_data( std::forward<Q>( key )));
+
+ if ( base_class::insert_at( refHead, *pNode, f )) {
+ pNode.release();
+ return true;
+ }
+ return false;
+ }
+
+ template <typename... Args>
+ bool emplace_at( head_type& refHead, Args&&... args )
+ {
+ return insert_node_at( refHead, alloc_data( std::forward<Args>(args)... ));
+ }
+
+ template <typename Q, typename Func>
+ std::pair<bool, bool> update_at( head_type& refHead, Q&& key, Func f, bool bAllowInsert )
+ {
+ scoped_data_ptr pData( alloc_data( std::forward<Q>( key )));
+
+ std::pair<bool, bool> ret = base_class::update_at( refHead, *pData, f, bAllowInsert );
+ if ( ret.first )
+ pData.release();
+
+ return ret;
+ }
+
+ template <typename Q, typename Compare, typename Func>
+ bool erase_at( head_type& refHead, Q const& key, Compare cmp, Func f )
+ {
+ return base_class::erase_at( refHead, key, cmp, f );
+ }
+
+ template <typename Q, typename Compare>
+ bool extract_at( head_type& refHead, typename guarded_ptr::native_guard& guard, Q const& key, Compare cmp )
+ {
+ return base_class::extract_at( refHead, guard, key, cmp );
+ }
+
+ template <typename Q, typename Compare>
+ bool find_at( head_type const& refHead, Q const& key, Compare cmp ) const
+ {
+ return base_class::find_at( refHead, key, cmp );
+ }
+
+ template <typename Q, typename Compare, typename Func>
+ bool find_at( head_type const& refHead, Q& val, Compare cmp, Func f ) const
+ {
+ return base_class::find_at( refHead, val, cmp, f );
+ }
+
+ template <typename Q, typename Compare>
+ iterator find_iterator_at( head_type const& refHead, Q const& key, Compare cmp ) const
+ {
+ return iterator( base_class::find_iterator_at( refHead, key, cmp ));
+ }
+
+ template <typename Q, typename Compare>
+ bool get_at( head_type const& refHead, typename guarded_ptr::native_guard& guard, Q const& key, Compare cmp ) const
+ {
+ return base_class::get_at( refHead, guard, key, cmp );
+ }
+
+ //@endcond
+ };
+
+}} // namespace cds::container
+
+#endif // #ifndef CDSLIB_CONTAINER_IMPL_ITERABLE_LIST_H
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_CONTAINER_IMPL_LAZY_KVLIST_H
typedef typename base_class::item_counter item_counter; ///< Item counter type
typedef typename maker::key_comparator key_comparator; ///< key comparing functor
typedef typename base_class::memory_model memory_model; ///< Memory ordering. See \p cds::opt::memory_model
+ typedef typename base_class::stat stat; ///< Internal statistics
static CDS_CONSTEXPR const size_t c_nHazardPtrCount = base_class::c_nHazardPtrCount; ///< Count of hazard pointer required for the algorithm
LazyKVList()
{}
+ //@cond
+ template <typename Stat, typename = std::enable_if<std::is_same<stat, lazy_list::wrapped_stat<Stat>>::value >>
+ explicit LazyKVList( Stat& st )
+ : base_class( st )
+ {}
+ //@endcond
+
/// Destructor clears the list
~LazyKVList()
{
during \p func call \p item is locked so it is safe to modify the item in
multi-threaded environment.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
\p second is true if new item has been added or \p false if the item with \p key
already exists.
*/
return base_class::size();
}
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return base_class::statistics();
+ }
+
/// Clears the list
void clear()
{
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_CONTAINER_IMPL_LAZY_LIST_H
typedef typename base_class::item_counter item_counter; ///< Item counting policy used
typedef typename maker::key_comparator key_comparator; ///< key comparison functor
typedef typename base_class::memory_model memory_model; ///< Memory ordering. See cds::opt::memory_model option
+ typedef typename base_class::stat stat; ///< Internal statistics
static CDS_CONSTEXPR const size_t c_nHazardPtrCount = base_class::c_nHazardPtrCount; ///< Count of hazard pointer required for the algorithm
+ //@cond
+ // Rebind traits (split-list support)
+ template <typename... Options>
+ struct rebind_traits {
+ typedef LazyList<
+ gc
+ , value_type
+ , typename cds::opt::make_options< traits, Options...>::type
+ > type;
+ };
+
+ // Stat selector
+ template <typename Stat>
+ using select_stat_wrapper = typename base_class::template select_stat_wrapper< Stat >;
+ //@endcond
+
protected:
//@cond
typedef typename base_class::value_type node_type;
typedef typename maker::intrusive_traits::compare intrusive_key_comparator;
typedef typename base_class::node_type head_type;
- //@endcond
-
- public:
- /// Guarded pointer
- typedef typename gc::template guarded_ptr< node_type, value_type, details::guarded_ptr_cast_set<node_type, value_type> > guarded_ptr;
-
- protected:
- //@cond
- static value_type& node_to_value( node_type& n )
- {
- return n.m_Value;
- }
-
- static value_type const& node_to_value( node_type const& n )
- {
- return n.m_Value;
- }
-
- template <typename Q>
- static node_type * alloc_node( Q const& v )
- {
- return cxx_allocator().New( v );
- }
-
- template <typename... Args>
- static node_type * alloc_node( Args&&... args )
- {
- return cxx_allocator().MoveNew( std::forward<Args>(args)... );
- }
-
- static void free_node( node_type * pNode )
- {
- cxx_allocator().Delete( pNode );
- }
struct node_disposer {
void operator()( node_type * pNode )
free_node( pNode );
}
};
- typedef std::unique_ptr< node_type, node_disposer > scoped_node_ptr;
+ typedef std::unique_ptr< node_type, node_disposer > scoped_node_ptr;
- head_type& head()
- {
- return base_class::m_Head;
- }
-
- head_type const& head() const
- {
- return base_class::m_Head;
- }
-
- head_type& tail()
- {
- return base_class::m_Tail;
- }
-
- head_type const& tail() const
- {
- return base_class::m_Tail;
- }
//@endcond
+ public:
+ /// Guarded pointer
+ typedef typename gc::template guarded_ptr< node_type, value_type, details::guarded_ptr_cast_set<node_type, value_type> > guarded_ptr;
+
protected:
- //@cond
+ //@cond
template <bool IsConst>
class iterator_type: protected base_class::template iterator_type<IsConst>
{
- typedef typename base_class::template iterator_type<IsConst> iterator_base;
+ typedef typename base_class::template iterator_type<IsConst> iterator_base;
iterator_type( head_type const& pNode )
: iterator_base( const_cast<head_type *>( &pNode ))
iterator_type()
{}
- iterator_type( const iterator_type& src )
+ iterator_type( iterator_type const& src )
: iterator_base( src )
{}
LazyList()
{}
+ //@cond
+ template <typename Stat, typename = std::enable_if<std::is_same<stat, lazy_list::wrapped_stat<Stat>>::value >>
+ explicit LazyList( Stat& st )
+ : base_class( st )
+ {}
+ //@endcond
+
/// Destructor clears the list
~LazyList()
{
Returns \p true if inserting successful, \p false otherwise.
*/
template <typename Q>
- bool insert( Q const& val )
+ bool insert( Q&& val )
{
- return insert_at( head(), val );
+ return insert_at( head(), std::forward<Q>( val ));
}
/// Inserts new node
it is preferable that the initialization should be completed only if inserting is successful.
*/
template <typename Q, typename Func>
- bool insert( Q const& key, Func func )
+ bool insert( Q&& key, Func func )
{
- return insert_at( head(), key, func );
+ return insert_at( head(), std::forward<Q>( key ), func );
}
/// Inserts data of type \p value_type constructed from \p args
The functor \p Func signature is:
\code
struct my_functor {
- void operator()( bool bNew, value_type& item, Q const& val );
+ void operator()( bool bNew, value_type& item, Q const& key );
};
\endcode
with arguments:
- \p bNew - \p true if the item has been inserted, \p false otherwise
- \p item - item of the list
- - \p val - argument \p key passed into the \p %update() function
+ - \p key - argument \p key passed into the \p %update() function
The functor may change non-key fields of the \p item;
during \p func call \p item is locked so it is safe to modify the item in
multi-threaded environment.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
\p second is true if new item has been added or \p false if the item with \p key
already exists.
*/
return base_class::size();
}
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return base_class::statistics();
+ }
+
/// Clears the list
void clear()
{
protected:
//@cond
+ static value_type& node_to_value( node_type& n )
+ {
+ return n.m_Value;
+ }
+
+ static value_type const& node_to_value( node_type const& n )
+ {
+ return n.m_Value;
+ }
+
+ template <typename Q>
+ static node_type * alloc_node( Q const& v )
+ {
+ return cxx_allocator().New( v );
+ }
+
+ template <typename... Args>
+ static node_type * alloc_node( Args&&... args )
+ {
+ return cxx_allocator().MoveNew( std::forward<Args>( args )... );
+ }
+
+ static void free_node( node_type * pNode )
+ {
+ cxx_allocator().Delete( pNode );
+ }
+
+ head_type& head()
+ {
+ return base_class::m_Head;
+ }
+
+ head_type const& head() const
+ {
+ return base_class::m_Head;
+ }
+
+ head_type& tail()
+ {
+ return base_class::m_Tail;
+ }
+
+ head_type const& tail() const
+ {
+ return base_class::m_Tail;
+ }
+
bool insert_node( node_type * pNode )
{
return insert_node_at( head(), pNode );
}
template <typename Q>
- bool insert_at( head_type& refHead, const Q& val )
+ bool insert_at( head_type& refHead, Q&& val )
{
- return insert_node_at( refHead, alloc_node( val ));
+ return insert_node_at( refHead, alloc_node( std::forward<Q>( val )));
}
template <typename... Args>
}
template <typename Q, typename Func>
- bool insert_at( head_type& refHead, const Q& key, Func f )
+ bool insert_at( head_type& refHead, Q&& key, Func f )
{
- scoped_node_ptr pNode( alloc_node( key ));
+ scoped_node_ptr pNode( alloc_node( std::forward<Q>( key )));
if ( base_class::insert_at( &refHead, *pNode, [&f](node_type& node){ f( node_to_value(node) ); } )) {
pNode.release();
}
template <typename Q, typename Compare, typename Func>
- bool erase_at( head_type& refHead, const Q& key, Compare cmp, Func f )
+ bool erase_at( head_type& refHead, Q const& key, Compare cmp, Func f )
{
return base_class::erase_at( &refHead, key, cmp, [&f](node_type const& node){ f( node_to_value(node) ); } );
}
}
template <typename Q, typename Func>
- std::pair<bool, bool> update_at( head_type& refHead, const Q& key, Func f, bool bAllowInsert )
+ std::pair<bool, bool> update_at( head_type& refHead, Q const& key, Func f, bool bAllowInsert )
{
scoped_node_ptr pNode( alloc_node( key ));
std::pair<bool, bool> ret = base_class::update_at( &refHead, *pNode,
- [&f, &key](bool bNew, node_type& node, node_type&){f( bNew, node_to_value(node), key );},
+ [&f, &key](bool bNew, node_type& node, node_type&) { f( bNew, node_to_value(node), key );},
bAllowInsert );
if ( ret.first && ret.second )
pNode.release();
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_CONTAINER_IMPL_MICHAEL_KVLIST_H
- \p Value - value type stored in a list
- \p Traits - type traits, default is \p michael_list::traits
- It is possible to declare option-based list with \p cds::container::michael_list::make_traits metafunction istead of \p Traits template
+ It is possible to declare option-based list with \p cds::container::michael_list::make_traits metafunction instead of \p Traits template
argument. For example, the following traits-based declaration of \p gc::HP Michael's list
\code
#include <cds/container/michael_kvlist_hp.h>
typedef typename base_class::item_counter item_counter; ///< Item counting policy used
typedef typename maker::key_comparator key_comparator; ///< key comparison functor
typedef typename base_class::memory_model memory_model; ///< Memory ordering. See cds::opt::memory_model option
+ typedef typename base_class::stat stat; ///< Internal statistics
static CDS_CONSTEXPR const size_t c_nHazardPtrCount = base_class::c_nHazardPtrCount; ///< Count of hazard pointer required for the algorithm
MichaelKVList()
{}
- /// List desctructor
+ //@cond
+ template <typename Stat, typename = std::enable_if<std::is_same<stat, michael_list::wrapped_stat<Stat>>::value >>
+ explicit MichaelKVList( Stat& st )
+ : base_class( st )
+ {}
+ //@endcond
+
+ /// List destructor
/**
Clears the list
*/
however, \p func must guarantee that during changing no any other modifications
could be made on this item by concurrent threads.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
\p second is true if new item has been added or \p false if the item with \p key
already exists.
and returns it as \p guarded_ptr.
If \p key is not found the function returns an empty guarded pointer.
- The \p disposer specified in \p Traits class template parameter is called
- by garbage collector \p GC automatically when returned \p guarded_ptr object
- will be destroyed or released.
@note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
Usage:
base_class::clear();
}
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return base_class::statistics();
+ }
+
protected:
//@cond
bool insert_node_at( head_type& refHead, node_type * pNode )
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_CONTAINER_IMPL_MICHAEL_LIST_H
typedef typename base_class::item_counter item_counter; ///< Item counting policy used
typedef typename maker::key_comparator key_comparator; ///< key comparison functor
typedef typename base_class::memory_model memory_model; ///< Memory ordering. See \p cds::opt::memory_model option
+ typedef typename base_class::stat stat; ///< Internal statistics
static CDS_CONSTEXPR const size_t c_nHazardPtrCount = base_class::c_nHazardPtrCount; ///< Count of hazard pointer required for the algorithm
+ //@cond
+ // Rebind traits (split-list support)
+ template <typename... Options>
+ struct rebind_traits {
+ typedef MichaelList<
+ gc
+ , value_type
+ , typename cds::opt::make_options< traits, Options...>::type
+ > type;
+ };
+
+ // Stat selector
+ template <typename Stat>
+ using select_stat_wrapper = typename base_class::template select_stat_wrapper< Stat >;
+ //@endcond
+
protected:
//@cond
typedef typename base_class::value_type node_type;
typedef typename maker::intrusive_traits::compare intrusive_key_comparator;
typedef typename base_class::atomic_node_ptr head_type;
- //@endcond
-
- public:
- /// Guarded pointer
- typedef typename gc::template guarded_ptr< node_type, value_type, details::guarded_ptr_cast_set<node_type, value_type> > guarded_ptr;
-
- protected:
- //@cond
- static value_type& node_to_value( node_type& n )
- {
- return n.m_Value;
- }
- static value_type const& node_to_value( node_type const& n )
- {
- return n.m_Value;
- }
-
- template <typename Q>
- static node_type * alloc_node( Q const& v )
- {
- return cxx_allocator().New( v );
- }
-
- template <typename... Args>
- static node_type * alloc_node( Args&&... args )
- {
- return cxx_allocator().MoveNew( std::forward<Args>(args)... );
- }
-
- static void free_node( node_type * pNode )
- {
- cxx_allocator().Delete( pNode );
- }
struct node_disposer {
void operator()( node_type * pNode )
}
};
typedef std::unique_ptr< node_type, node_disposer > scoped_node_ptr;
-
- head_type& head()
- {
- return base_class::m_pHead;
- }
-
- head_type const& head() const
- {
- return base_class::m_pHead;
- }
//@endcond
+ public:
+ /// Guarded pointer
+ typedef typename gc::template guarded_ptr< node_type, value_type, details::guarded_ptr_cast_set<node_type, value_type> > guarded_ptr;
+
protected:
//@cond
template <bool IsConst>
MichaelList()
{}
+ //@cond
+ template <typename Stat, typename = std::enable_if<std::is_same<stat, michael_list::wrapped_stat<Stat>>::value >>
+ explicit MichaelList( Stat& st )
+ : base_class( st )
+ {}
+ //@endcond
+
/// List destructor
/**
Clears the list
Returns \p true if inserting successful, \p false otherwise.
*/
template <typename Q>
- bool insert( Q const& val )
+ bool insert( Q&& val )
{
- return insert_at( head(), val );
+ return insert_at( head(), std::forward<Q>( val ));
}
/// Inserts new node
@warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
*/
template <typename Q, typename Func>
- bool insert( Q const& key, Func func )
+ bool insert( Q&& key, Func func )
{
- return insert_at( head(), key, func );
+ return insert_at( head(), std::forward<Q>(key), func );
}
/// Updates data by \p key
The functor \p Func signature is:
\code
struct my_functor {
- void operator()( bool bNew, value_type& item, Q const& val );
+ void operator()( bool bNew, value_type& item, Q const& key );
};
\endcode
with arguments:
- \p bNew - \p true if the item has been inserted, \p false otherwise
- \p item - item of the list
- - \p val - argument \p key passed into the \p %update() function
+ - \p key - argument \p key passed into the \p %update() function
The functor may change non-key fields of the \p item; however, \p func must guarantee
that during changing no any other modifications could be made on this item by concurrent threads.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
\p second is true if new item has been added or \p false if the item with \p key
already exists.
//@endcond
/// Finds \p key and return the item found
- /** \anchor cds_nonintrusive_MichaelList_hp_get
+ /**
The function searches the item with key equal to \p key
and returns it as \p guarded_ptr.
If \p key is not found the function returns an empty guarded pointer.
/// Finds \p key and return the item found
/**
- The function is an analog of \ref cds_nonintrusive_MichaelList_hp_get "get( Q const&)"
+ The function is an analog of \p get( Q const&)
but \p pred is used for comparing the keys.
\p Less functor has the semantics like \p std::less but should accept arguments of type \p value_type and \p Q
base_class::clear();
}
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return base_class::statistics();
+ }
+
protected:
//@cond
+ static value_type& node_to_value( node_type& n )
+ {
+ return n.m_Value;
+ }
+ static value_type const& node_to_value( node_type const& n )
+ {
+ return n.m_Value;
+ }
+
+ template <typename Q>
+ static node_type * alloc_node( Q const& v )
+ {
+ return cxx_allocator().New( v );
+ }
+
+ template <typename... Args>
+ static node_type * alloc_node( Args&&... args )
+ {
+ return cxx_allocator().MoveNew( std::forward<Args>( args )... );
+ }
+
+ static void free_node( node_type * pNode )
+ {
+ cxx_allocator().Delete( pNode );
+ }
+
+ head_type& head()
+ {
+ return base_class::m_pHead;
+ }
+
+ head_type const& head() const
+ {
+ return base_class::m_pHead;
+ }
+
bool insert_node( node_type * pNode )
{
return insert_node_at( head(), pNode );
}
template <typename Q>
- bool insert_at( head_type& refHead, Q const& val )
+ bool insert_at( head_type& refHead, Q&& val )
{
- return insert_node_at( refHead, alloc_node( val ));
+ return insert_node_at( refHead, alloc_node( std::forward<Q>(val)));
}
template <typename Q, typename Func>
- bool insert_at( head_type& refHead, Q const& key, Func f )
+ bool insert_at( head_type& refHead, Q&& key, Func f )
{
- scoped_node_ptr pNode( alloc_node( key ));
+ scoped_node_ptr pNode( alloc_node( std::forward<Q>( key )));
if ( base_class::insert_at( refHead, *pNode, [&f]( node_type& node ) { f( node_to_value(node) ); } )) {
pNode.release();
The functor may change any fields of the \p item.second that is \ref value_type.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
\p second is \p true if new item has been added or \p false if \p key already exists.
@warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
The functor may change non-key fields of the \p item; however, \p func must guarantee
that during changing no any other modifications could be made on this item by concurrent threads.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
i.e. the item has been inserted or updated,
\p second is \p true if new item has been added or \p false if the item with key equal to \p val
already exists.
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSLIB_CONTAINER_ITERABLE_KVLIST_DHP_H
+#define CDSLIB_CONTAINER_ITERABLE_KVLIST_DHP_H
+
+#include <cds/container/details/iterable_list_base.h>
+#include <cds/container/iterable_list_dhp.h>
+#include <cds/container/details/make_iterable_kvlist.h>
+#include <cds/container/impl/iterable_kvlist.h>
+
+#endif // #ifndef CDSLIB_CONTAINER_ITERABLE_KVLIST_DHP_H
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSLIB_CONTAINER_ITERABLE_KVLIST_HP_H
+#define CDSLIB_CONTAINER_ITERABLE_KVLIST_HP_H
+
+#include <cds/container/details/iterable_list_base.h>
+#include <cds/container/iterable_list_hp.h>
+#include <cds/container/details/make_iterable_kvlist.h>
+#include <cds/container/impl/iterable_kvlist.h>
+
+#endif // #ifndef CDSLIB_CONTAINER_ITERABLE_KVLIST_HP_H
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSLIB_CONTAINER_ITERABLE_LIST_DHP_H
+#define CDSLIB_CONTAINER_ITERABLE_LIST_DHP_H
+
+#include <cds/container/details/iterable_list_base.h>
+#include <cds/intrusive/iterable_list_dhp.h>
+#include <cds/container/details/make_iterable_list.h>
+#include <cds/container/impl/iterable_list.h>
+
+#endif // #ifndef CDSLIB_CONTAINER_ITERABLE_LIST_DHP_H
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSLIB_CONTAINER_ITERABLE_LIST_HP_H
+#define CDSLIB_CONTAINER_ITERABLE_LIST_HP_H
+
+#include <cds/container/details/iterable_list_base.h>
+#include <cds/intrusive/iterable_list_hp.h>
+#include <cds/container/details/make_iterable_list.h>
+#include <cds/container/impl/iterable_list.h>
+
+#endif // #ifndef CDSLIB_CONTAINER_ITERABLE_LIST_HP_H
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_CONTAINER_LAZY_KVLIST_NOGC_H
typedef typename base_class::item_counter item_counter; ///< Item counting policy used
typedef typename maker::key_comparator key_comparator; ///< key comparison functor
typedef typename base_class::memory_model memory_model; ///< Memory ordering. See cds::opt::memory_model option
+ typedef typename base_class::stat stat; ///< Internal statistics
static CDS_CONSTEXPR bool const c_bSort = base_class::c_bSort; ///< List type: ordered (\p true) or unordered (\p false)
protected:
LazyKVList()
{}
+ //@cond
+ template <typename Stat, typename = std::enable_if<std::is_same<stat, lazy_list::wrapped_stat<Stat>>::value >>
+ explicit LazyKVList( Stat& st )
+ : base_class( st )
+ {}
+ //@endcond
+
/// Desctructor clears the list
~LazyKVList()
{
return base_class::size();
}
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return base_class::statistics();
+ }
+
/// Clears the list
/**
Post-condition: the list is empty
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_CONTAINER_LAZY_KVLIST_RCU_H
typedef typename base_class::item_counter item_counter; ///< Item counting policy used
typedef typename maker::key_comparator key_comparator; ///< key comparison functor
typedef typename base_class::memory_model memory_model; ///< Memory ordering. See cds::opt::memory_model option
+ typedef typename base_class::stat stat; ///< Internal statistics
typedef typename base_class::rcu_check_deadlock rcu_check_deadlock ; ///< RCU deadlock checking policy
typedef typename gc::scoped_lock rcu_lock ; ///< RCU scoped lock
LazyKVList()
{}
+ //@cond
+ template <typename Stat, typename = std::enable_if<std::is_same<stat, lazy_list::wrapped_stat<Stat>>::value >>
+ explicit LazyKVList( Stat& st )
+ : base_class( st )
+ {}
+ //@endcond
+
/// Destructor clears the list
~LazyKVList()
{
The function applies RCU lock internally.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
\p second is true if new item has been added or \p false if the item with \p key
already exists.
*/
return base_class::size();
}
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return base_class::statistics();
+ }
+
/// Clears the list
void clear()
{
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_CONTAINER_LAZY_LIST_NOGC_H
typedef T value_type; ///< Type of value stored in the list
typedef Traits traits; ///< List traits
- typedef typename base_class::back_off back_off; ///< Back-off strategy used
- typedef typename maker::allocator_type allocator_type; ///< Allocator type used for allocate/deallocate the nodes
- typedef typename base_class::item_counter item_counter; ///< Item counting policy used
- typedef typename maker::key_comparator key_comparator; ///< key comparing functor
- typedef typename base_class::memory_model memory_model; ///< Memory ordering. See cds::opt::memory_model option
+ typedef typename base_class::back_off back_off; ///< Back-off strategy used
+ typedef typename maker::allocator_type allocator_type; ///< Allocator type used for allocate/deallocate the nodes
+ typedef typename base_class::item_counter item_counter; ///< Item counting policy used
+ typedef typename maker::key_comparator key_comparator; ///< key comparing functor
+ typedef typename base_class::memory_model memory_model; ///< Memory ordering. See cds::opt::memory_model option
+ typedef typename base_class::stat stat; ///< Internal statistics
+
static CDS_CONSTEXPR bool const c_bSort = base_class::c_bSort; ///< List type: ordered (\p true) or unordered (\p false)
+ //@cond
+ // Rebind traits (split-list support)
+ template <typename... Options>
+ struct rebind_traits {
+ typedef LazyList<
+ gc
+ , value_type
+ , typename cds::opt::make_options< traits, Options...>::type
+ > type;
+ };
+
+ // Stat selector
+ template <typename Stat>
+ using select_stat_wrapper = typename base_class::template select_stat_wrapper< Stat >;
+ //@endcond
+
protected:
//@cond
typedef typename base_class::value_type node_type;
typedef typename base_class::key_comparator intrusive_key_comparator;
typedef typename base_class::node_type head_type;
- //@endcond
-
- protected:
- //@cond
- static value_type& node_to_value( node_type& n )
- {
- return n.m_Value;
- }
-
- static node_type * alloc_node()
- {
- return cxx_allocator().New();
- }
-
- static node_type * alloc_node( value_type const& v )
- {
- return cxx_allocator().New( v );
- }
-
- template <typename... Args>
- static node_type * alloc_node( Args&&... args )
- {
- return cxx_allocator().MoveNew( std::forward<Args>(args)... );
- }
-
- static void free_node( node_type * pNode )
- {
- cxx_allocator().Delete( pNode );
- }
struct node_disposer {
void operator()( node_type * pNode )
}
};
typedef std::unique_ptr< node_type, node_disposer > scoped_node_ptr;
-
- head_type& head()
- {
- return base_class::m_Head;
- }
-
- head_type const& head() const
- {
- return base_class::m_Head;
- }
-
- head_type& tail()
- {
- return base_class::m_Tail;
- }
-
- head_type const& tail() const
- {
- return base_class::m_Tail;
- }
//@endcond
protected:
}
//@}
- protected:
- //@cond
- iterator node_to_iterator( node_type * pNode )
- {
- if ( pNode )
- return iterator( *pNode );
- return end();
- }
- //@endcond
-
public:
/// Default constructor
LazyList()
{}
+ //@cond
+ template <typename Stat, typename = std::enable_if<std::is_same<stat, lazy_list::wrapped_stat<Stat>>::value >>
+ explicit LazyList( Stat& st )
+ : base_class( st )
+ {}
+ //@endcond
+
/// Desctructor clears the list
~LazyList()
{
Return an iterator pointing to inserted item if success \ref end() otherwise
*/
template <typename Q>
- iterator insert( Q const& val )
+ iterator insert( Q&& val )
{
- return node_to_iterator( insert_at( head(), val ) );
+ return node_to_iterator( insert_at( head(), std::forward<Q>( val )) );
}
/// Inserts data of type \p value_type created from \p args
/// Updates the item
/**
If \p key is not in the list and \p bAllowInsert is \p true,
-
the function inserts a new item.
Otherwise, the function returns an iterator pointing to the item found.
already is in the list.
*/
template <typename Q>
- std::pair<iterator, bool> update( Q const& val, bool bAllowInsert = true )
+ std::pair<iterator, bool> update( Q&& val, bool bAllowInsert = true )
{
- std::pair< node_type *, bool > ret = update_at( head(), val, bAllowInsert );
+ std::pair< node_type *, bool > ret = update_at( head(), std::forward<Q>( val ), bAllowInsert );
return std::make_pair( node_to_iterator( ret.first ), ret.second );
}
//@cond
return base_class::size();
}
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return base_class::statistics();
+ }
+
/// Clears the list
void clear()
{
protected:
//@cond
+ static value_type& node_to_value( node_type& n )
+ {
+ return n.m_Value;
+ }
+
+ static node_type * alloc_node()
+ {
+ return cxx_allocator().New();
+ }
+
+ static node_type * alloc_node( value_type const& v )
+ {
+ return cxx_allocator().New( v );
+ }
+
+ template <typename... Args>
+ static node_type * alloc_node( Args&&... args )
+ {
+ return cxx_allocator().MoveNew( std::forward<Args>( args )... );
+ }
+
+ static void free_node( node_type * pNode )
+ {
+ cxx_allocator().Delete( pNode );
+ }
+
+ head_type& head()
+ {
+ return base_class::m_Head;
+ }
+
+ head_type const& head() const
+ {
+ return base_class::m_Head;
+ }
+
+ head_type& tail()
+ {
+ return base_class::m_Tail;
+ }
+
+ head_type const& tail() const
+ {
+ return base_class::m_Tail;
+ }
+
+ iterator node_to_iterator( node_type * pNode )
+ {
+ if ( pNode )
+ return iterator( *pNode );
+ return end();
+ }
+
iterator insert_node( node_type * pNode )
{
return node_to_iterator( insert_node_at( head(), pNode ));
}
template <typename Q>
- node_type * insert_at( head_type& refHead, Q const& val )
+ node_type * insert_at( head_type& refHead, Q&& val )
{
- return insert_node_at( refHead, alloc_node( val ));
+ return insert_node_at( refHead, alloc_node( std::forward<Q>( val )));
}
template <typename... Args>
}
template <typename Q>
- std::pair< node_type *, bool > update_at( head_type& refHead, Q const& val, bool bAllowInsert )
+ std::pair< node_type *, bool > update_at( head_type& refHead, Q&& val, bool bAllowInsert )
{
- scoped_node_ptr pNode( alloc_node( val ));
+ scoped_node_ptr pNode( alloc_node( std::forward<Q>( val )));
node_type * pItemFound = nullptr;
std::pair<bool, bool> ret = base_class::update_at( &refHead, *pNode,
- [&pItemFound](bool, node_type& item, node_type&){ pItemFound = &item; },
+ [&pItemFound](bool, node_type& item, node_type&) { pItemFound = &item; },
bAllowInsert );
if ( ret.second )
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_CONTAINER_LAZY_LIST_RCU_H
typedef T value_type; ///< Type of value stored in the list
typedef Traits traits; ///< List traits
- typedef typename base_class::back_off back_off; ///< Back-off strategy
- typedef typename maker::allocator_type allocator_type; ///< Allocator type used for allocate/deallocate the nodes
- typedef typename base_class::item_counter item_counter; ///< Item counting policy used
- typedef typename maker::key_comparator key_comparator; ///< key compare functor
- typedef typename base_class::memory_model memory_model; ///< Memory ordering. See cds::opt::memory_model option
+ typedef typename base_class::back_off back_off; ///< Back-off strategy
+ typedef typename maker::allocator_type allocator_type; ///< Allocator type used for allocate/deallocate the nodes
+ typedef typename base_class::item_counter item_counter; ///< Item counting policy used
+ typedef typename maker::key_comparator key_comparator; ///< key compare functor
+ typedef typename base_class::memory_model memory_model; ///< Memory ordering. See cds::opt::memory_model option
+ typedef typename base_class::stat stat; ///< Internal statistics
typedef typename base_class::rcu_check_deadlock rcu_check_deadlock; ///< Deadlock checking policy
typedef typename gc::scoped_lock rcu_lock ; ///< RCU scoped lock
static CDS_CONSTEXPR const bool c_bExtractLockExternal = base_class::c_bExtractLockExternal; ///< Group of \p extract_xxx functions require external locking
+ //@cond
+ // Rebind traits (split-list support)
+ template <typename... Options>
+ struct rebind_traits {
+ typedef LazyList<
+ gc
+ , value_type
+ , typename cds::opt::make_options< traits, Options...>::type
+ > type;
+ };
+
+ // Stat selector
+ template <typename Stat>
+ using select_stat_wrapper = typename base_class::template select_stat_wrapper< Stat >;
+ //@endcond
+
protected:
//@cond
typedef typename base_class::value_type node_type;
typedef typename maker::intrusive_traits::compare intrusive_key_comparator;
typedef typename base_class::node_type head_type;
- //@endcond
-
- public:
- using exempt_ptr = cds::urcu::exempt_ptr< gc, node_type, value_type, typename maker::intrusive_traits::disposer >; ///< pointer to extracted node
- /// Type of \p get() member function return value
- typedef value_type * raw_ptr;
-
- protected:
- //@cond
- static value_type& node_to_value( node_type& n )
- {
- return n.m_Value;
- }
-
- static value_type const& node_to_value( node_type const& n )
- {
- return n.m_Value;
- }
-
- template <typename Q>
- static node_type * alloc_node( Q const& v )
- {
- return cxx_allocator().New( v );
- }
-
- template <typename... Args>
- static node_type * alloc_node( Args&&... args )
- {
- return cxx_allocator().MoveNew( std::forward<Args>(args)... );
- }
-
- static void free_node( node_type * pNode )
- {
- cxx_allocator().Delete( pNode );
- }
struct node_disposer {
void operator()( node_type * pNode )
}
};
typedef std::unique_ptr< node_type, node_disposer > scoped_node_ptr;
-
- head_type& head()
- {
- return base_class::m_Head;
- }
-
- head_type& head() const
- {
- return const_cast<head_type&>( base_class::m_Head );
- }
-
- head_type& tail()
- {
- return base_class::m_Tail;
- }
-
- head_type const& tail() const
- {
- return base_class::m_Tail;
- }
//@endcond
+ public:
+ using exempt_ptr = cds::urcu::exempt_ptr< gc, node_type, value_type, typename maker::intrusive_traits::disposer >; ///< pointer to extracted node
+ /// Type of \p get() member function return value
+ typedef value_type * raw_ptr;
+
protected:
- //@cond
+ //@cond
template <bool IsConst>
class iterator_type: protected base_class::template iterator_type<IsConst>
{
LazyList()
{}
+ //@cond
+ template <typename Stat, typename = std::enable_if<std::is_same<stat, lazy_list::wrapped_stat<Stat>>::value >>
+ explicit LazyList( Stat& st )
+ : base_class( st )
+ {}
+ //@endcond
+
/// Desctructor clears the list
~LazyList()
{
Returns \p true if inserting successful, \p false otherwise.
*/
template <typename Q>
- bool insert( Q const& val )
+ bool insert( Q&& val )
{
- return insert_at( head(), val );
+ return insert_at( head(), std::forward<Q>( val ));
}
/// Inserts new node
The function makes RCU lock internally.
*/
template <typename Q, typename Func>
- bool insert( Q const& key, Func func )
+ bool insert( Q&& key, Func func )
{
- return insert_at( head(), key, func );
+ return insert_at( head(), std::forward<Q>( key ), func );
}
/// Inserts data of type \p value_type constructed from \p args
The function applies RCU lock internally.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
\p second is true if new item has been added or \p false if the item with \p key
already exists.
*/
return base_class::size();
}
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return base_class::statistics();
+ }
+
/// Clears the list
void clear()
{
}
template <typename Q>
- bool insert_at( head_type& refHead, Q const& val )
+ bool insert_at( head_type& refHead, Q&& val )
{
- return insert_node_at( refHead, alloc_node( val ));
+ return insert_node_at( refHead, alloc_node( std::forward<Q>( val )));
}
template <typename... Args>
}
template <typename Q, typename Func>
- bool insert_at( head_type& refHead, Q const& key, Func f )
+ bool insert_at( head_type& refHead, Q&& key, Func f )
{
- scoped_node_ptr pNode( alloc_node( key ));
+ scoped_node_ptr pNode( alloc_node( std::forward<Q>( key )));
if ( base_class::insert_at( &refHead, *pNode, [&f](node_type& node){ f( node_to_value(node) ); } )) {
pNode.release();
return pNode ? &pNode->m_Value : nullptr;
}
+ static value_type& node_to_value( node_type& n )
+ {
+ return n.m_Value;
+ }
+
+ static value_type const& node_to_value( node_type const& n )
+ {
+ return n.m_Value;
+ }
+
+ template <typename Q>
+ static node_type * alloc_node( Q&& v )
+ {
+ return cxx_allocator().New( std::forward<Q>( v ));
+ }
+
+ template <typename... Args>
+ static node_type * alloc_node( Args&&... args )
+ {
+ return cxx_allocator().MoveNew( std::forward<Args>( args )... );
+ }
+
+ static void free_node( node_type * pNode )
+ {
+ cxx_allocator().Delete( pNode );
+ }
+
+ head_type& head()
+ {
+ return base_class::m_Head;
+ }
+
+ head_type& head() const
+ {
+ return const_cast<head_type&>(base_class::m_Head);
+ }
+
+ head_type& tail()
+ {
+ return base_class::m_Tail;
+ }
+
+ head_type const& tail() const
+ {
+ return base_class::m_Tail;
+ }
//@endcond
};
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_CONTAINER_MICHAEL_KVLIST_NOGC_H
typedef typename base_class::item_counter item_counter; ///< Item counting policy used
typedef typename maker::key_comparator key_comparator; ///< key comparison functor
typedef typename base_class::memory_model memory_model; ///< Memory ordering. See cds::opt::memory_model option
+ typedef typename base_class::stat stat; ///< Internal statistics
protected:
//@cond
MichaelKVList()
{}
- /// List desctructor
+ //@cond
+ template <typename Stat, typename = std::enable_if<std::is_same<stat, michael_list::wrapped_stat<Stat>>::value >>
+ explicit MichaelKVList( Stat& st )
+ : base_class( st )
+ {}
+ //@endcond
+
+ /// List destructor
/**
Clears the list
*/
return base_class::size();
}
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return base_class::statistics();
+ }
+
/// Clears the list
void clear()
{
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_CONTAINER_MICHAEL_KVLIST_RCU_H
typedef typename base_class::item_counter item_counter; ///< Item counting policy
typedef typename maker::key_comparator key_comparator; ///< key comparison functor
typedef typename base_class::memory_model memory_model; ///< Memory ordering. See \p michael_list::traits::memory_model
+ typedef typename base_class::stat stat; ///< Internal statistics
typedef typename base_class::rcu_check_deadlock rcu_check_deadlock ; ///< RCU deadlock checking policy
typedef typename gc::scoped_lock rcu_lock ; ///< RCU scoped lock
MichaelKVList()
{}
- /// List desctructor
+ //@cond
+ template <typename Stat, typename = std::enable_if<std::is_same<stat, michael_list::wrapped_stat<Stat>>::value >>
+ explicit MichaelKVList( Stat& st )
+ : base_class( st )
+ {}
+ //@endcond
+
+ /// List destructor
/**
Clears the list
*/
The function applies RCU lock internally.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
\p second is true if new item has been added or \p false if the item with \p key
already is in the list.
The function applies RCU lock internally.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
\p second is true if new item has been added or \p false if the item with \p key
already exists.
return base_class::size();
}
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return base_class::statistics();
+ }
+
/// Clears the list
/**
Post-condition: the list is empty
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_CONTAINER_MICHAEL_LIST_NOGC_H
typedef typename base_class::item_counter item_counter; ///< Item counting policy used
typedef typename maker::key_comparator key_comparator; ///< key comparison functor
typedef typename base_class::memory_model memory_model; ///< Memory ordering. See cds::opt::memory_model option
+ typedef typename base_class::stat stat; ///< Internal statistics
+
+ //@cond
+ // Rebind traits (split-list support)
+ template <typename... Options>
+ struct rebind_traits {
+ typedef MichaelList<
+ gc
+ , value_type
+ , typename cds::opt::make_options< traits, Options...>::type
+ > type;
+ };
+
+ // Stat selector
+ template <typename Stat>
+ using select_stat_wrapper = typename base_class::template select_stat_wrapper< Stat >;
+ //@endcond
protected:
//@cond
typedef typename maker::intrusive_traits::compare intrusive_key_comparator;
typedef typename base_class::atomic_node_ptr head_type;
- //@endcond
-
- protected:
- //@cond
- static node_type * alloc_node()
- {
- return cxx_allocator().New();
- }
-
- static node_type * alloc_node( value_type const& v )
- {
- return cxx_allocator().New( v );
- }
-
- template <typename... Args>
- static node_type * alloc_node( Args&&... args )
- {
- return cxx_allocator().MoveNew( std::forward<Args>(args)... );
- }
-
- static void free_node( node_type * pNode )
- {
- cxx_allocator().Delete( pNode );
- }
struct node_disposer {
void operator()( node_type * pNode )
free_node( pNode );
}
};
- typedef std::unique_ptr< node_type, node_disposer > scoped_node_ptr;
-
- head_type& head()
- {
- return base_class::m_pHead;
- }
- head_type const& head() const
- {
- return base_class::m_pHead;
- }
+ typedef std::unique_ptr< node_type, node_disposer > scoped_node_ptr;
//@endcond
protected:
}
//@}
- protected:
- //@cond
- iterator node_to_iterator( node_type * pNode )
- {
- if ( pNode )
- return iterator( *pNode );
- return end();
- }
- //@endcond
-
public:
/// Default constructor
/**
MichaelList()
{}
- /// List desctructor
+ //@cond
+ template <typename Stat, typename = std::enable_if<std::is_same<stat, michael_list::wrapped_stat<Stat>>::value >>
+ explicit MichaelList( Stat& st )
+ : base_class( st )
+ {}
+ //@endcond
+
+ /// List destructor
/**
Clears the list
*/
Return an iterator pointing to inserted item if success \ref end() otherwise
*/
template <typename Q>
- iterator insert( const Q& val )
+ iterator insert( Q&& val )
{
- return node_to_iterator( insert_at( head(), val ) );
+ return node_to_iterator( insert_at( head(), std::forward<Q>( val )) );
}
/// Updates the item
already is in the list.
*/
template <typename Q>
- std::pair<iterator, bool> update( const Q& key, bool bAllowInsert = true )
+ std::pair<iterator, bool> update( Q&& key, bool bAllowInsert = true )
{
- std::pair< node_type *, bool > ret = update_at( head(), key, bAllowInsert );
+ std::pair< node_type *, bool > ret = update_at( head(), std::forward<Q>( key ), bAllowInsert );
return std::make_pair( node_to_iterator( ret.first ), ret.second );
}
//@cond
return base_class::size();
}
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return base_class::statistics();
+ }
+
/// Clears the list
void clear()
{
return n.m_Value;
}
+ static node_type * alloc_node()
+ {
+ return cxx_allocator().New();
+ }
+
+ static node_type * alloc_node( value_type const& v )
+ {
+ return cxx_allocator().New( v );
+ }
+
+ template <typename... Args>
+ static node_type * alloc_node( Args&&... args )
+ {
+ return cxx_allocator().MoveNew( std::forward<Args>( args )... );
+ }
+
+ static void free_node( node_type * pNode )
+ {
+ cxx_allocator().Delete( pNode );
+ }
+
+ head_type& head()
+ {
+ return base_class::m_pHead;
+ }
+
+ head_type const& head() const
+ {
+ return base_class::m_pHead;
+ }
+
+ iterator node_to_iterator( node_type * pNode )
+ {
+ if ( pNode )
+ return iterator( *pNode );
+ return end();
+ }
+
iterator insert_node( node_type * pNode )
{
return node_to_iterator( insert_node_at( head(), pNode ));
}
template <typename Q>
- node_type * insert_at( head_type& refHead, const Q& val )
+ node_type * insert_at( head_type& refHead, Q&& val )
{
- return insert_node_at( refHead, alloc_node( val ));
+ return insert_node_at( refHead, alloc_node( std::forward<Q>( val )));
}
template <typename Q>
- std::pair< node_type *, bool > update_at( head_type& refHead, const Q& val, bool bAllowInsert )
+ std::pair< node_type *, bool > update_at( head_type& refHead, Q&& val, bool bAllowInsert )
{
- scoped_node_ptr pNode( alloc_node( val ));
+ scoped_node_ptr pNode( alloc_node( std::forward<Q>( val )));
node_type * pItemFound = nullptr;
std::pair<bool, bool> ret = base_class::update_at( refHead, *pNode,
{
return base_class::find_at( refHead, key, cmp );
}
-
//@endcond
};
}} // namespace cds::container
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_CONTAINER_MICHAEL_LIST_RCU_H
typedef typename base_class::item_counter item_counter; ///< Item counting policy used
typedef typename maker::key_comparator key_comparator; ///< key comparison functor
typedef typename base_class::memory_model memory_model; ///< Memory ordering. See cds::opt::memory_model option
+ typedef typename base_class::stat stat; ///< Internal statistics
typedef typename base_class::rcu_check_deadlock rcu_check_deadlock ; ///< RCU deadlock checking policy
typedef typename gc::scoped_lock rcu_lock ; ///< RCU scoped lock
static CDS_CONSTEXPR const bool c_bExtractLockExternal = base_class::c_bExtractLockExternal; ///< Group of \p extract_xxx functions do not require external locking
+ //@cond
+ // Rebind traits (split-list support)
+ template <typename... Options>
+ struct rebind_traits {
+ typedef MichaelList<
+ gc
+ , value_type
+ , typename cds::opt::make_options< traits, Options...>::type
+ > type;
+ };
+
+ // Stat selector
+ template <typename Stat>
+ using select_stat_wrapper = typename base_class::template select_stat_wrapper< Stat >;
+ //@endcond
+
protected:
//@cond
typedef typename base_class::value_type node_type;
typedef typename maker::intrusive_traits::compare intrusive_key_comparator;
typedef typename base_class::atomic_node_ptr head_type;
- //@endcond
- public:
- using exempt_ptr = cds::urcu::exempt_ptr< gc, node_type, value_type, typename maker::intrusive_traits::disposer >; ///< pointer to extracted node
+ struct node_disposer {
+ void operator()( node_type * pNode )
+ {
+ free_node( pNode );
+ }
+ };
+ typedef std::unique_ptr< node_type, node_disposer > scoped_node_ptr;
+ //@endcond
private:
//@cond
//@endcond
public:
+ ///< pointer to extracted node
+ using exempt_ptr = cds::urcu::exempt_ptr< gc, node_type, value_type, typename maker::intrusive_traits::disposer >;
+
/// Result of \p get(), \p get_with() functions - pointer to the node found
typedef cds::urcu::raw_ptr_adaptor< value_type, typename base_class::raw_ptr, raw_ptr_converter > raw_ptr;
protected:
//@cond
- static value_type& node_to_value( node_type& n )
- {
- return n.m_Value;
- }
- static value_type const& node_to_value( node_type const& n )
- {
- return n.m_Value;
- }
-
- template <typename Q>
- static node_type * alloc_node( Q const& v )
- {
- return cxx_allocator().New( v );
- }
-
- template <typename... Args>
- static node_type * alloc_node( Args&&... args )
- {
- return cxx_allocator().MoveNew( std::forward<Args>(args)... );
- }
-
- static void free_node( node_type * pNode )
- {
- cxx_allocator().Delete( pNode );
- }
-
- struct node_disposer {
- void operator()( node_type * pNode )
- {
- free_node( pNode );
- }
- };
- typedef std::unique_ptr< node_type, node_disposer > scoped_node_ptr;
-
- head_type& head()
- {
- return base_class::m_pHead;
- }
-
- head_type& head() const
- {
- return const_cast<head_type&>( base_class::m_pHead );
- }
- //@endcond
-
- protected:
- //@cond
template <bool IsConst>
class iterator_type: protected base_class::template iterator_type<IsConst>
{
MichaelList()
{}
+ //@cond
+ template <typename Stat, typename = std::enable_if<std::is_same<stat, michael_list::wrapped_stat<Stat>>::value >>
+ explicit MichaelList( Stat& st )
+ : base_class( st )
+ {}
+ //@endcond
+
/// List destructor
/**
Clears the list
Returns \p true if inserting successful, \p false otherwise.
*/
template <typename Q>
- bool insert( Q const& val )
+ bool insert( Q&& val )
{
- return insert_at( head(), val );
+ return insert_at( head(), std::forward<Q>( val ));
}
/// Inserts new node
@warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
*/
template <typename Q, typename Func>
- bool insert( Q const& key, Func func )
+ bool insert( Q&& key, Func func )
{
- return insert_at( head(), key, func );
+ return insert_at( head(), std::forward<Q>( key ), func );
}
/// Updates data by \p key
The function applies RCU lock internally.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
\p second is true if new item has been added or \p false if the item with \p key
already exists.
return base_class::size();
}
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return base_class::statistics();
+ }
+
/// Clears the list
void clear()
{
}
template <typename Q>
- bool insert_at( head_type& refHead, Q const& val )
+ bool insert_at( head_type& refHead, Q&& val )
{
- return insert_node_at( refHead, alloc_node( val ));
+ return insert_node_at( refHead, alloc_node( std::forward<Q>( val )));
}
template <typename Q, typename Func>
- bool insert_at( head_type& refHead, Q const& key, Func f )
+ bool insert_at( head_type& refHead, Q&& key, Func f )
{
- scoped_node_ptr pNode( alloc_node( key ));
+ scoped_node_ptr pNode( alloc_node( std::forward<Q>( key )));
if ( base_class::insert_at( refHead, *pNode, [&f]( node_type& node ) { f( node_to_value(node) ); } )) {
pNode.release();
return raw_ptr( base_class::get_at( refHead, val, cmp ));
}
+ static value_type& node_to_value( node_type& n )
+ {
+ return n.m_Value;
+ }
+ static value_type const& node_to_value( node_type const& n )
+ {
+ return n.m_Value;
+ }
+
+ template <typename Q>
+ static node_type * alloc_node( Q&& v )
+ {
+ return cxx_allocator().New( std::forward<Q>( v ));
+ }
+
+ template <typename... Args>
+ static node_type * alloc_node( Args&&... args )
+ {
+ return cxx_allocator().MoveNew( std::forward<Args>( args )... );
+ }
+
+ static void free_node( node_type * pNode )
+ {
+ cxx_allocator().Delete( pNode );
+ }
+
+ head_type& head()
+ {
+ return base_class::m_pHead;
+ }
+
+ head_type& head() const
+ {
+ return const_cast<head_type&>(base_class::m_pHead);
+ }
//@endcond
};
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_CONTAINER_MICHAEL_MAP_H
};
\endcode
- Note, the iterator object returned by \p end(), \p cend() member functions points to \p nullptr and should not be dereferenced.
+ @note The iterator object returned by \p end(), \p cend() member functions points to \p nullptr and should not be dereferenced.
*/
typedef iterator_type< false > iterator;
The functor may change any fields of the \p item.second that is \p mapped_type.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
\p second is true if new item has been added or \p false if the item with \p key
already exists.
The function applies RCU lock internally.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
\p second is true if new item has been added or \p false if the item with \p key
already exists.
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_CONTAINER_MICHAEL_SET_H
#define CDSLIB_CONTAINER_MICHAEL_SET_H
#include <cds/container/details/michael_set_base.h>
+#include <cds/container/details/iterable_list_base.h>
#include <cds/details/allocator.h>
namespace cds { namespace container {
- \p GC - Garbage collector used. You may use any \ref cds_garbage_collector "Garbage collector"
from the \p libcds library.
Note the \p GC must be the same as the \p GC used for \p OrderedList
- - \p OrderedList - ordered list implementation used as bucket for hash set, for example, \p MichaelList.
+ - \p OrderedList - ordered list implementation used as bucket for hash set, possible implementations:
+ \p MichaelList, \p LazyList, \p IterableList.
The ordered list implementation specifies the type \p T to be stored in the hash-set,
the comparing functor for the type \p T and other features specific for the ordered list.
- \p Traits - set traits, default is \p michael_set::traits.
\code
// Our node type
struct Foo {
- std::string key_ ; // key field
+ std::string key_; // key field
// ... other fields
};
Suppose, we have the following type \p Foo that we want to store in our \p %MichaelHashSet:
\code
struct Foo {
- int nKey ; // key field
- int nVal ; // value field
+ int nKey; // key field
+ int nVal; // value field
};
\endcode
class MichaelHashSet
{
public:
- typedef GC gc; ///< Garbage collector
- typedef OrderedList bucket_type; ///< type of ordered list used as a bucket implementation
- typedef Traits traits; ///< Set traits
+ typedef GC gc; ///< Garbage collector
+ typedef OrderedList ordered_list; ///< type of ordered list used as a bucket implementation
+ typedef Traits traits; ///< Set traits
- typedef typename bucket_type::value_type value_type; ///< type of value to be stored in the list
- typedef typename bucket_type::key_comparator key_comparator; ///< key comparison functor
+ typedef typename ordered_list::value_type value_type; ///< type of value to be stored in the list
+ typedef typename ordered_list::key_comparator key_comparator; ///< key comparison functor
+ typedef typename ordered_list::stat stat; ///< Internal statistics
/// Hash functor for \ref value_type and all its derivatives that you use
typedef typename cds::opt::v::hash_selector< typename traits::hash >::type hash;
typedef typename traits::item_counter item_counter; ///< Item counter type
+ typedef typename traits::allocator allocator; ///< Bucket table allocator
- typedef typename bucket_type::guarded_ptr guarded_ptr; ///< Guarded pointer
- static CDS_CONSTEXPR const size_t c_nHazardPtrCount = bucket_type::c_nHazardPtrCount; ///< Count of hazard pointer required
+ static CDS_CONSTEXPR const size_t c_nHazardPtrCount = ordered_list::c_nHazardPtrCount; ///< Count of hazard pointer required
- protected:
- //@cond
- class internal_bucket_type: public bucket_type
- {
- typedef bucket_type base_class;
- public:
- using base_class::node_type;
- using base_class::alloc_node;
- using base_class::insert_node;
- using base_class::node_to_value;
- };
+ // GC and OrderedList::gc must be the same
+ static_assert( std::is_same<gc, typename ordered_list::gc>::value, "GC and OrderedList::gc must be the same");
- /// Bucket table allocator
- typedef cds::details::Allocator< internal_bucket_type, typename traits::allocator > bucket_table_allocator;
- //@endcond
+ // atomicity::empty_item_counter is not allowed as a item counter
+ static_assert( !std::is_same<item_counter, atomicity::empty_item_counter>::value,
+ "cds::atomicity::empty_item_counter is not allowed as a item counter");
- protected:
- //@cond
- item_counter m_ItemCounter; ///< Item counter
- hash m_HashFunctor; ///< Hash functor
- internal_bucket_type * m_Buckets; ///< bucket table
- //@endcond
+#ifdef CDS_DOXYGEN_INVOKED
+ /// Wrapped internal statistics for \p ordered_list
+ typedef implementatin_specific bucket_stat;
+#else
+ typedef typename ordered_list::template select_stat_wrapper< typename ordered_list::stat > bucket_stat;
+#endif
+
+#ifdef CDS_DOXYGEN_INVOKED
+ /// Internal bucket type - rebind \p ordered_list with empty item counter and wrapped internal statistics
+ typedef modified_ordered_list internal_bucket_type;
+#else
+ typedef typename ordered_list::template rebind_traits<
+ cds::opt::item_counter< cds::atomicity::empty_item_counter >
+ , cds::opt::stat< typename bucket_stat::wrapped_stat >
+ >::type internal_bucket_type;
+#endif
+
+ /// Guarded pointer - a result of \p get() and \p extract() functions
+ typedef typename internal_bucket_type::guarded_ptr guarded_ptr;
- private:
//@cond
- const size_t m_nHashBitmask;
+ /// Bucket table allocator
+ typedef typename allocator::template rebind< internal_bucket_type >::other bucket_table_allocator;
//@endcond
protected:
//@cond
- /// Calculates hash value of \p key
- template <typename Q>
- size_t hash_value( Q const& key ) const
- {
- return m_HashFunctor( key ) & m_nHashBitmask;
- }
-
- /// Returns the bucket (ordered list) for \p key
- template <typename Q>
- internal_bucket_type& bucket( Q const& key )
- {
- return m_Buckets[ hash_value( key ) ];
- }
+ size_t const m_nHashBitmask;
+ internal_bucket_type * m_Buckets; ///< bucket table
+ item_counter m_ItemCounter; ///< Item counter
+ hash m_HashFunctor; ///< Hash functor
+ typename bucket_stat::stat m_Stat; ///< Internal statistics
//@endcond
public:
- ///@name Forward iterators (only for debugging purpose)
+ ///@name Forward iterators
//@{
/// Forward iterator
/**
For some GC (like as \p gc::HP), a guard is a limited resource per thread, so an exception (or assertion) "no free guard"
may be thrown if the limit of guard count per thread is exceeded.
- The iterator cannot be moved across thread boundary because it contains thread-private GC's guard.
- - Iterator ensures thread-safety even if you delete the item the iterator points to. However, in case of concurrent
- deleting operations there is no guarantee that you iterate all item in the set.
- Moreover, a crash is possible when you try to iterate the next element that has been deleted by concurrent thread.
- @warning Use this iterator on the concurrent container for debugging purpose only.
+ Iterator thread safety depends on type of \p OrderedList:
+ - for \p MichaelList and \p LazyList: iterator guarantees safety even if you delete the item that iterator points to
+ because that item is guarded by hazard pointer.
+ However, in case of concurrent deleting operations it is no guarantee that you iterate all item in the set.
+ Moreover, a crash is possible when you try to iterate the next element that has been deleted by concurrent thread.
+ Use this iterator on the concurrent container for debugging purpose only.
+ - for \p IterableList: iterator is thread-safe. You may use it freely in concurrent environment.
The iterator interface:
\code
*/
/// Forward iterator
- typedef michael_set::details::iterator< bucket_type, false > iterator;
+ typedef michael_set::details::iterator< internal_bucket_type, false > iterator;
/// Const forward iterator
- typedef michael_set::details::iterator< bucket_type, true > const_iterator;
+ typedef michael_set::details::iterator< internal_bucket_type, true > const_iterator;
/// Returns a forward iterator addressing the first element in a set
/**
*/
iterator begin()
{
- return iterator( m_Buckets[0].begin(), m_Buckets, m_Buckets + bucket_count() );
+ return iterator( bucket_begin()->begin(), bucket_begin(), bucket_end());
}
/// Returns an iterator that addresses the location succeeding the last element in a set
*/
iterator end()
{
- return iterator( m_Buckets[bucket_count() - 1].end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
+ return iterator( bucket_end()[-1].end(), bucket_end() - 1, bucket_end());
}
/// Returns a forward const iterator addressing the first element in a set
}
//@}
- private:
- //@cond
- const_iterator get_const_begin() const
- {
- return const_iterator( const_cast<internal_bucket_type const&>(m_Buckets[0]).begin(), m_Buckets, m_Buckets + bucket_count() );
- }
- const_iterator get_const_end() const
- {
- return const_iterator( const_cast<internal_bucket_type const&>(m_Buckets[bucket_count() - 1]).end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
- }
- //@endcond
-
public:
/// Initialize hash set
- /** @anchor cds_nonintrusive_MichaelHashSet_hp_ctor
+ /**
The Michael's hash set is non-expandable container. You should point the average count of items \p nMaxItemCount
when you create an object.
\p nLoadFactor parameter defines average count of items per bucket and it should be small number between 1 and 10.
size_t nMaxItemCount, ///< estimation of max item count in the hash set
size_t nLoadFactor ///< load factor: estimation of max number of items in the bucket
) : m_nHashBitmask( michael_set::details::init_hash_bitmask( nMaxItemCount, nLoadFactor ))
+ , m_Buckets( bucket_table_allocator().allocate( bucket_count() ) )
{
- // GC and OrderedList::gc must be the same
- static_assert( std::is_same<gc, typename bucket_type::gc>::value, "GC and OrderedList::gc must be the same");
-
- // atomicity::empty_item_counter is not allowed as a item counter
- static_assert( !std::is_same<item_counter, atomicity::empty_item_counter>::value,
- "cds::atomicity::empty_item_counter is not allowed as a item counter");
-
- m_Buckets = bucket_table_allocator().NewArray( bucket_count() );
+ for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
+ construct_bucket<bucket_stat>( it );
}
/// Clears hash set and destroys it
~MichaelHashSet()
{
clear();
- bucket_table_allocator().Delete( m_Buckets, bucket_count() );
+
+ for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
+ it->~internal_bucket_type();
+ bucket_table_allocator().deallocate( m_Buckets, bucket_count() );
}
/// Inserts new node
Returns \p true if \p val is inserted into the set, \p false otherwise.
*/
template <typename Q>
- bool insert( Q const& val )
+ bool insert( Q&& val )
{
- const bool bRet = bucket( val ).insert( val );
+ const bool bRet = bucket( val ).insert( std::forward<Q>( val ));
if ( bRet )
++m_ItemCounter;
return bRet;
where \p val is the item inserted.
The user-defined functor is called only if the inserting is success.
- @warning For \ref cds_nonintrusive_MichaelList_gc "MichaelList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
+ @warning For \ref cds_nonintrusive_MichaelList_gc "MichaelList" and \ref cds_nonintrusive_IterableList_gc "IterableList"
+ as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
@ref cds_nonintrusive_LazyList_gc "LazyList" provides exclusive access to inserted item and does not require any node-level
synchronization.
*/
template <typename Q, typename Func>
- bool insert( Q const& val, Func f )
+ bool insert( Q&& val, Func f )
{
- const bool bRet = bucket( val ).insert( val, f );
+ const bool bRet = bucket( val ).insert( std::forward<Q>( val ), f );
if ( bRet )
++m_ItemCounter;
return bRet;
If the item \p val not found in the set, then \p val is inserted iff \p bAllowInsert is \p true.
Otherwise, the functor \p func is called with item found.
- The functor signature is:
+
+ The functor \p func signature depends of \p OrderedList:
+
+ <b>for \p MichaelList, \p LazyList</b>
\code
struct functor {
void operator()( bool bNew, value_type& item, Q const& val );
The functor may change non-key fields of the \p item.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+ <b>for \p IterableList</b>
+ \code
+ void func( value_type& val, value_type * old );
+ \endcode
+ where
+ - \p val - a new data constructed from \p key
+ - \p old - old value that will be retired. If new item has been inserted then \p old is \p nullptr.
+
+ @return <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
\p second is \p true if new item has been added or \p false if the item with \p key
already is in the set.
- @warning For \ref cds_intrusive_MichaelList_hp "MichaelList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
+ @warning For \ref cds_intrusive_MichaelList_hp "MichaelList" and \ref cds_nonintrusive_IterableList_gc "IterableList"
+ as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
\ref cds_intrusive_LazyList_hp "LazyList" provides exclusive access to inserted item and does not require any node-level
synchronization.
*/
template <typename Q, typename Func>
- std::pair<bool, bool> update( const Q& val, Func func, bool bAllowUpdate = true )
+ std::pair<bool, bool> update( Q&& val, Func func, bool bAllowUpdate = true )
{
- std::pair<bool, bool> bRet = bucket( val ).update( val, func, bAllowUpdate );
+ std::pair<bool, bool> bRet = bucket( val ).update( std::forward<Q>( val ), func, bAllowUpdate );
if ( bRet.second )
++m_ItemCounter;
return bRet;
}
//@endcond
+ /// Inserts or updates the node (only for \p IterableList)
+ /**
+ The operation performs inserting or changing data with lock-free manner.
+
+ If the item \p val is not found in the set, then \p val is inserted iff \p bAllowInsert is \p true.
+ Otherwise, the current element is changed to \p val, the old element will be retired later
+ by call \p Traits::disposer.
+
+ Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
+ \p second is \p true if \p val has been added or \p false if the item with that key
+ already in the set.
+ */
+ template <typename Q>
+#ifdef CDS_DOXYGEN_INVOKED
+ std::pair<bool, bool>
+#else
+ typename std::enable_if<
+ std::is_same< Q, Q>::value && is_iterable_list< ordered_list >::value,
+ std::pair<bool, bool>
+ >::type
+#endif
+ upsert( Q&& val, bool bAllowInsert = true )
+ {
+ std::pair<bool, bool> bRet = bucket( val ).upsert( std::forward<Q>( val ), bAllowInsert );
+ if ( bRet.second )
+ ++m_ItemCounter;
+ return bRet;
+ }
+
/// Inserts data of type \p value_type constructed from \p args
/**
Returns \p true if inserting successful, \p false otherwise.
template <typename... Args>
bool emplace( Args&&... args )
{
- typename internal_bucket_type::node_type * pNode = internal_bucket_type::alloc_node( std::forward<Args>( args )... );
- bool bRet = bucket( internal_bucket_type::node_to_value( *pNode )).insert_node( pNode );
+ bool bRet = bucket_emplace<internal_bucket_type>( std::forward<Args>(args)... );
if ( bRet )
++m_ItemCounter;
return bRet;
}
/// Deletes \p key from the set
- /** \anchor cds_nonintrusive_MichaelSet_erase_val
-
- Since the key of MichaelHashSet's item type \ref value_type is not explicitly specified,
+ /**
+ Since the key of MichaelHashSet's item type \p value_type is not explicitly specified,
template parameter \p Q defines the key type searching in the list.
The set item comparator should be able to compare the type \p value_type
and the type \p Q.
- Return \p true if key is found and deleted, \p false otherwise
+ Return \p true if key is found and deleted, \p false otherwise.
*/
template <typename Q>
bool erase( Q const& key )
/// Deletes the item from the set using \p pred predicate for searching
/**
- The function is an analog of \ref cds_nonintrusive_MichaelSet_erase_val "erase(Q const&)"
- but \p pred is used for key comparing.
+ The function is an analog of \p erase(Q const&) but \p pred is used for key comparing.
\p Less functor has the interface like \p std::less.
\p Less must imply the same element order as the comparator used for building the set.
*/
}
/// Deletes \p key from the set
- /** \anchor cds_nonintrusive_MichaelSet_erase_func
-
+ /**
The function searches an item with key \p key, calls \p f functor
and deletes the item. If \p key is not found, the functor is not called.
/// Deletes the item from the set using \p pred predicate for searching
/**
- The function is an analog of \ref cds_nonintrusive_MichaelSet_erase_func "erase(Q const&, Func)"
- but \p pred is used for key comparing.
+ The function is an analog of \p erase(Q const&, Func) but \p pred is used for key comparing.
\p Less functor has the interface like \p std::less.
\p Less must imply the same element order as the comparator used for building the set.
*/
michael_set theSet;
// ...
{
- michael_set::guarded_ptr gp( theSet.extract( 5 ));
+ typename michael_set::guarded_ptr gp( theSet.extract( 5 ));
if ( gp ) {
// Deal with gp
// ...
/// Extracts the item using compare functor \p pred
/**
- The function is an analog of \ref cds_nonintrusive_MichaelHashSet_hp_extract "extract(Q const&)"
+ The function is an analog of \p extract(Q const&)
but \p pred predicate is used for key comparing.
- \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
- in any order.
+ \p Less functor has the semantics like \p std::less but should take arguments
+ of type \p value_type and \p Q in any order.
\p pred must imply the same element order as the comparator used for building the set.
*/
template <typename Q, typename Less>
}
/// Finds the key \p key
- /** \anchor cds_nonintrusive_MichaelSet_find_func
-
+ /**
The function searches the item with key equal to \p key and calls the functor \p f for item found.
The interface of \p Func functor is:
\code
}
//@endcond
+ /// Finds \p key and returns iterator pointed to the item found (only for \p IterableList)
+ /**
+ If \p key is not found the function returns \p end().
+
+ @note This function is supported only for the set based on \p IterableList
+ */
+ template <typename Q>
+#ifdef CDS_DOXYGEN_INVOKED
+ iterator
+#else
+ typename std::enable_if< std::is_same<Q,Q>::value && is_iterable_list< ordered_list >::value, iterator >::type
+#endif
+ find( Q& key )
+ {
+ internal_bucket_type& b = bucket( key );
+ typename internal_bucket_type::iterator it = b.find( key );
+ if ( it == b.end() )
+ return end();
+ return iterator( it, &b, bucket_end());
+ }
+ //@cond
+ template <typename Q>
+ typename std::enable_if< std::is_same<Q, Q>::value && is_iterable_list< ordered_list >::value, iterator >::type
+ find( Q const& key )
+ {
+ internal_bucket_type& b = bucket( key );
+ typename internal_bucket_type::iterator it = b.find( key );
+ if ( it == b.end() )
+ return end();
+ return iterator( it, &b, bucket_end() );
+ }
+ //@endcond
+
/// Finds the key \p key using \p pred predicate for searching
/**
- The function is an analog of \ref cds_nonintrusive_MichaelSet_find_func "find(Q&, Func)"
- but \p pred is used for key comparing.
+ The function is an analog of \p find(Q&, Func) but \p pred is used for key comparing.
\p Less functor has the interface like \p std::less.
\p Less must imply the same element order as the comparator used for building the set.
*/
}
//@endcond
- /// Checks whether the set contains \p key
+ /// Finds \p key using \p pred predicate and returns iterator pointed to the item found (only for \p IterableList)
/**
+ The function is an analog of \p find(Q&) but \p pred is used for key comparing.
+ \p Less functor has the interface like \p std::less.
+ \p pred must imply the same element order as the comparator used for building the set.
+
+ If \p key is not found the function returns \p end().
+ @note This function is supported only for the set based on \p IterableList
+ */
+ template <typename Q, typename Less>
+#ifdef CDS_DOXYGEN_INVOKED
+ iterator
+#else
+ typename std::enable_if< std::is_same<Q, Q>::value && is_iterable_list< ordered_list >::value, iterator >::type
+#endif
+ find_with( Q& key, Less pred )
+ {
+ internal_bucket_type& b = bucket( key );
+ typename internal_bucket_type::iterator it = b.find_with( key, pred );
+ if ( it == b.end() )
+ return end();
+ return iterator( it, &b, bucket_end() );
+ }
+ //@cond
+ template <typename Q, typename Less>
+ typename std::enable_if< std::is_same<Q, Q>::value && is_iterable_list< ordered_list >::value, iterator >::type
+ find_with( Q const& key, Less pred )
+ {
+ internal_bucket_type& b = bucket( key );
+ typename internal_bucket_type::iterator it = b.find_with( key, pred );
+ if ( it == b.end() )
+ return end();
+ return iterator( it, &b, bucket_end() );
+ }
+ //@endcond
+
+ /// Checks whether the set contains \p key
+ /**
The function searches the item with key equal to \p key
and returns \p true if the key is found, and \p false otherwise.
{
return bucket( key ).contains( key );
}
- //@cond
- template <typename Q>
- CDS_DEPRECATED("use contains()")
- bool find( Q const& key )
- {
- return contains( key );
- }
- //@endcond
/// Checks whether the set contains \p key using \p pred predicate for searching
/**
{
return bucket( key ).contains( key, pred );
}
- //@cond
- template <typename Q, typename Less>
- CDS_DEPRECATED("use contains()")
- bool find_with( Q const& key, Less pred )
- {
- return contains( key, pred );
- }
- //@endcond
/// Finds the key \p key and return the item found
/** \anchor cds_nonintrusive_MichaelHashSet_hp_get
michael_set theSet;
// ...
{
- michael_set::guarded_ptr gp( theSet.get( 5 ));
+ typename michael_set::guarded_ptr gp( theSet.get( 5 ));
if ( gp ) {
// Deal with gp
//...
return m_ItemCounter;
}
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return m_Stat;
+ }
+
/// Returns the size of hash table
/**
Since MichaelHashSet cannot dynamically extend the hash table size,
{
return m_nHashBitmask + 1;
}
+
+ protected:
+ //@cond
+ /// Calculates hash value of \p key
+ template <typename Q>
+ size_t hash_value( Q const& key ) const
+ {
+ return m_HashFunctor( key ) & m_nHashBitmask;
+ }
+
+ /// Returns the bucket (ordered list) for \p key
+ template <typename Q>
+ internal_bucket_type& bucket( Q const& key )
+ {
+ return m_Buckets[ hash_value( key ) ];
+ }
+ template <typename Q>
+ internal_bucket_type const& bucket( Q const& key ) const
+ {
+ return m_Buckets[hash_value( key )];
+ }
+ //@endcond
+
+ private:
+ //@cond
+ internal_bucket_type* bucket_begin() const
+ {
+ return m_Buckets;
+ }
+
+ internal_bucket_type* bucket_end() const
+ {
+ return m_Buckets + bucket_count();
+ }
+
+ const_iterator get_const_begin() const
+ {
+ return const_iterator( bucket_begin()->cbegin(), bucket_begin(), bucket_end() );
+ }
+ const_iterator get_const_end() const
+ {
+ return const_iterator(( bucket_end() -1 )->cend(), bucket_end() - 1, bucket_end() );
+ }
+
+ template <typename Stat>
+ typename std::enable_if< Stat::empty >::type construct_bucket( internal_bucket_type* bucket )
+ {
+ new (bucket) internal_bucket_type;
+ }
+
+ template <typename Stat>
+ typename std::enable_if< !Stat::empty >::type construct_bucket( internal_bucket_type* bucket )
+ {
+ new (bucket) internal_bucket_type( m_Stat );
+ }
+
+ template <typename List, typename... Args>
+ typename std::enable_if< !is_iterable_list<List>::value, bool>::type
+ bucket_emplace( Args&&... args )
+ {
+ class list_accessor: public List
+ {
+ public:
+ using List::alloc_node;
+ using List::node_to_value;
+ using List::insert_node;
+ };
+
+ auto pNode = list_accessor::alloc_node( std::forward<Args>( args )... );
+ assert( pNode != nullptr );
+ return static_cast<list_accessor&>( bucket( list_accessor::node_to_value( *pNode ))).insert_node( pNode );
+ }
+
+ template <typename List, typename... Args>
+ typename std::enable_if< is_iterable_list<List>::value, bool>::type
+ bucket_emplace( Args&&... args )
+ {
+ class list_accessor: public List
+ {
+ public:
+ using List::alloc_data;
+ using List::insert_node;
+ };
+
+ auto pData = list_accessor::alloc_data( std::forward<Args>( args )... );
+ assert( pData != nullptr );
+ return static_cast<list_accessor&>( bucket( *pData )).insert_node( pData );
+ }
+ //@endcond
};
}} // namespace cds::container
#include <cds/container/details/michael_set_base.h>
#include <cds/gc/nogc.h>
-#include <cds/details/allocator.h>
namespace cds { namespace container {
class MichaelHashSet< cds::gc::nogc, OrderedList, Traits >
{
public:
- typedef cds::gc::nogc gc; ///< Garbage collector
- typedef OrderedList bucket_type; ///< type of ordered list to be used as a bucket implementation
- typedef Traits traits; ///< Set traits
+ typedef cds::gc::nogc gc; ///< Garbage collector
+ typedef OrderedList ordered_list; ///< type of ordered list to be used as a bucket implementation
+ typedef Traits traits; ///< Set traits
- typedef typename bucket_type::value_type value_type; ///< type of value stored in the list
- typedef typename bucket_type::key_comparator key_comparator; ///< key comparison functor
+ typedef typename ordered_list::value_type value_type; ///< type of value stored in the list
+ typedef typename ordered_list::key_comparator key_comparator; ///< key comparison functor
+ typedef typename ordered_list::stat stat; ///< Internal statistics
/// Hash functor for \ref value_type and all its derivatives that you use
typedef typename cds::opt::v::hash_selector< typename traits::hash >::type hash;
- typedef typename traits::item_counter item_counter; ///< Item counter type
+ typedef typename traits::item_counter item_counter; ///< Item counter type
+ typedef typename traits::allocator allocator; ///< Bucket table allocator
+
+ // GC and OrderedList::gc must be the same
+ static_assert(std::is_same<gc, typename ordered_list::gc>::value, "GC and OrderedList::gc must be the same");
+
+ // atomicity::empty_item_counter is not allowed as a item counter
+ static_assert(!std::is_same<item_counter, atomicity::empty_item_counter>::value,
+ "cds::atomicity::empty_item_counter is not allowed as a item counter");
protected:
//@cond
- class internal_bucket_type: public bucket_type
+ typedef typename ordered_list::template select_stat_wrapper< typename ordered_list::stat > bucket_stat;
+
+ typedef typename ordered_list::template rebind_traits<
+ cds::opt::item_counter< cds::atomicity::empty_item_counter >
+ , cds::opt::stat< typename bucket_stat::wrapped_stat >
+ >::type internal_bucket_type_;
+
+ class internal_bucket_type: public internal_bucket_type_
{
- typedef bucket_type base_class;
+ typedef internal_bucket_type_ base_class;
public:
+ using base_class::base_class;
using base_class::node_type;
using base_class::alloc_node;
using base_class::insert_node;
};
/// Bucket table allocator
- typedef cds::details::Allocator< internal_bucket_type, typename traits::allocator > bucket_table_allocator;
+ typedef typename allocator::template rebind< internal_bucket_type >::other bucket_table_allocator;
- typedef typename bucket_type::iterator bucket_iterator;
- typedef typename bucket_type::const_iterator bucket_const_iterator;
+ typedef typename internal_bucket_type::iterator bucket_iterator;
+ typedef typename internal_bucket_type::const_iterator bucket_const_iterator;
//@endcond
protected:
- //@cond
- item_counter m_ItemCounter; ///< Item counter
- hash m_HashFunctor; ///< Hash functor
- internal_bucket_type * m_Buckets; ///< bucket table
- //@endcond
-
- private:
//@cond
const size_t m_nHashBitmask;
- //@endcond
-
- protected:
- //@cond
- /// Calculates hash value of \p key
- template <typename Q>
- size_t hash_value( const Q& key ) const
- {
- return m_HashFunctor( key ) & m_nHashBitmask;
- }
-
- /// Returns the bucket (ordered list) for \p key
- template <typename Q>
- internal_bucket_type& bucket( const Q& key )
- {
- return m_Buckets[ hash_value( key ) ];
- }
+ item_counter m_ItemCounter; ///< Item counter
+ hash m_HashFunctor; ///< Hash functor
+ internal_bucket_type* m_Buckets; ///< bucket table
+ typename bucket_stat::stat m_Stat; ///< Internal statistics
//@endcond
public:
};
\endcode
*/
- typedef michael_set::details::iterator< bucket_type, false > iterator;
+ typedef michael_set::details::iterator< internal_bucket_type, false > iterator;
/// Const forward iterator
/**
For iterator's features and requirements see \ref iterator
*/
- typedef michael_set::details::iterator< bucket_type, true > const_iterator;
+ typedef michael_set::details::iterator< internal_bucket_type, true > const_iterator;
/// Returns a forward iterator addressing the first element in a set
/**
}
//@}
- private:
- //@cond
- const_iterator get_const_begin() const
- {
- return const_iterator( const_cast<internal_bucket_type const&>(m_Buckets[0]).begin(), m_Buckets, m_Buckets + bucket_count() );
- }
- const_iterator get_const_end() const
- {
- return const_iterator( const_cast<internal_bucket_type const&>(m_Buckets[bucket_count() - 1]).end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
- }
- //@endcond
-
public:
/// Initialize hash set
/**
size_t nMaxItemCount, ///< estimation of max item count in the hash set
size_t nLoadFactor ///< load factor: estimation of max number of items in the bucket
) : m_nHashBitmask( michael_set::details::init_hash_bitmask( nMaxItemCount, nLoadFactor ))
+ , m_Buckets( bucket_table_allocator().allocate( bucket_count() ) )
{
- // GC and OrderedList::gc must be the same
- static_assert( std::is_same<gc, typename bucket_type::gc>::value, "GC and OrderedList::gc must be the same");
-
- // atomicity::empty_item_counter is not allowed as a item counter
- static_assert( !std::is_same<item_counter, atomicity::empty_item_counter>::value,
- "cds::atomicity::empty_item_counter is not allowed as a item counter");
-
- m_Buckets = bucket_table_allocator().NewArray( bucket_count() );
+ for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
+ construct_bucket<bucket_stat>( it );
}
/// Clears hash set and destroys it
~MichaelHashSet()
{
clear();
- bucket_table_allocator().Delete( m_Buckets, bucket_count() );
+ for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
+ it->~internal_bucket_type();
+ bucket_table_allocator().deallocate( m_Buckets, bucket_count() );
}
/// Inserts new node
return m_ItemCounter;
}
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return m_Stat;
+ }
+
/// Returns the size of hash table
/**
Since \p %MichaelHashSet cannot dynamically extend the hash table size,
{
return m_nHashBitmask + 1;
}
+
+ protected:
+ //@cond
+ /// Calculates hash value of \p key
+ template <typename Q>
+ size_t hash_value( const Q& key ) const
+ {
+ return m_HashFunctor( key ) & m_nHashBitmask;
+ }
+
+ /// Returns the bucket (ordered list) for \p key
+ template <typename Q>
+ internal_bucket_type& bucket( const Q& key )
+ {
+ return m_Buckets[hash_value( key )];
+ }
+ //@endcond
+
+ private:
+ //@cond
+ template <typename Stat>
+ typename std::enable_if< Stat::empty >::type construct_bucket( internal_bucket_type* bucket )
+ {
+ new (bucket) internal_bucket_type;
+ }
+
+ template <typename Stat>
+ typename std::enable_if< !Stat::empty >::type construct_bucket( internal_bucket_type* bucket )
+ {
+ new (bucket) internal_bucket_type( m_Stat );
+ }
+
+ const_iterator get_const_begin() const
+ {
+ return const_iterator( const_cast<internal_bucket_type const&>(m_Buckets[0]).begin(), m_Buckets, m_Buckets + bucket_count() );
+ }
+ const_iterator get_const_end() const
+ {
+ return const_iterator( const_cast<internal_bucket_type const&>(m_Buckets[bucket_count() - 1]).end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
+ }
+ //@endcond
};
}} // cds::container
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_CONTAINER_MICHAEL_SET_RCU_H
{
public:
typedef cds::urcu::gc< RCU > gc; ///< RCU used as garbage collector
- typedef OrderedList bucket_type; ///< type of ordered list to be used as a bucket implementation
+ typedef OrderedList ordered_list; ///< type of ordered list to be used as a bucket implementation
typedef Traits traits; ///< Set traits
- typedef typename bucket_type::value_type value_type; ///< type of value to be stored in the list
- typedef typename bucket_type::key_comparator key_comparator; ///< key comparing functor
+ typedef typename ordered_list::value_type value_type; ///< type of value to be stored in the list
+ typedef typename ordered_list::key_comparator key_comparator; ///< key comparing functor
+ typedef typename ordered_list::stat stat; ///< Internal statistics
/// Hash functor for \ref value_type and all its derivatives that you use
typedef typename cds::opt::v::hash_selector< typename traits::hash >::type hash;
- typedef typename traits::item_counter item_counter; ///< Item counter type
+ typedef typename traits::item_counter item_counter; ///< Item counter type
+ typedef typename traits::allocator allocator; ///< Bucket table allocator
- typedef typename bucket_type::rcu_lock rcu_lock; ///< RCU scoped lock
- typedef typename bucket_type::exempt_ptr exempt_ptr; ///< pointer to extracted node
- typedef typename bucket_type::raw_ptr raw_ptr; ///< Return type of \p get() member function and its derivatives
+ typedef typename ordered_list::rcu_lock rcu_lock; ///< RCU scoped lock
/// Group of \p extract_xxx functions require external locking if underlying ordered list requires that
- static CDS_CONSTEXPR const bool c_bExtractLockExternal = bucket_type::c_bExtractLockExternal;
+ static CDS_CONSTEXPR const bool c_bExtractLockExternal = ordered_list::c_bExtractLockExternal;
- protected:
- //@cond
- class internal_bucket_type: public bucket_type
+ // GC and OrderedList::gc must be the same
+ static_assert(std::is_same<gc, typename ordered_list::gc>::value, "GC and OrderedList::gc must be the same");
+
+ static_assert(!std::is_same<item_counter, atomicity::empty_item_counter>::value,
+ "atomicity::empty_item_counter is not allowed as a item counter");
+
+#ifdef CDS_DOXYGEN_INVOKED
+ /// Wrapped internal statistics for \p ordered_list
+ typedef implementatin_specific bucket_stat;
+
+ /// Internal bucket type - rebind \p ordered_list with empty item counter and wrapped internal statistics
+ typedef modified_ordered_list internal_bucket_type;
+#else
+ typedef typename ordered_list::template select_stat_wrapper< typename ordered_list::stat > bucket_stat;
+
+ typedef typename ordered_list::template rebind_traits<
+ cds::opt::item_counter< cds::atomicity::empty_item_counter >
+ , cds::opt::stat< typename bucket_stat::wrapped_stat >
+ >::type internal_bucket_type_;
+
+ class internal_bucket_type: public internal_bucket_type_
{
- typedef bucket_type base_class;
+ typedef internal_bucket_type_ base_class;
public:
+ using base_class::base_class;
using base_class::node_type;
using base_class::alloc_node;
using base_class::insert_node;
using base_class::node_to_value;
};
+#endif
- /// Bucket table allocator
- typedef cds::details::Allocator< internal_bucket_type, typename traits::allocator > bucket_table_allocator;
-
- //@endcond
-
- protected:
- item_counter m_ItemCounter; ///< Item counter
- hash m_HashFunctor; ///< Hash functor
- internal_bucket_type * m_Buckets; ///< bucket table
-
- private:
- //@cond
- const size_t m_nHashBitmask;
- //@endcond
+ typedef typename internal_bucket_type::exempt_ptr exempt_ptr; ///< pointer to extracted node
+ typedef typename internal_bucket_type::raw_ptr raw_ptr; ///< Return type of \p get() member function and its derivatives
protected:
//@cond
- /// Calculates hash value of \p key
- template <typename Q>
- size_t hash_value( Q const& key ) const
- {
- return m_HashFunctor( key ) & m_nHashBitmask;
- }
+ /// Bucket table allocator
+ typedef typename allocator::template rebind< internal_bucket_type >::other bucket_table_allocator;
- /// Returns the bucket (ordered list) for \p key
- template <typename Q>
- internal_bucket_type& bucket( Q const& key )
- {
- return m_Buckets[ hash_value( key ) ];
- }
- template <typename Q>
- internal_bucket_type const& bucket( Q const& key ) const
- {
- return m_Buckets[ hash_value( key ) ];
- }
+ const size_t m_nHashBitmask;
+ item_counter m_ItemCounter; ///< Item counter
+ hash m_HashFunctor; ///< Hash functor
+ internal_bucket_type* m_Buckets; ///< bucket table
+ typename bucket_stat::stat m_Stat; ///< Internal statistics
//@endcond
+
public:
///@name Forward iterators (thread-safe under RCU lock)
//@{
};
\endcode
*/
- typedef michael_set::details::iterator< bucket_type, false > iterator;
+ typedef michael_set::details::iterator< internal_bucket_type, false > iterator;
/// Const forward iterator
- typedef michael_set::details::iterator< bucket_type, true > const_iterator;
+ typedef michael_set::details::iterator< internal_bucket_type, true > const_iterator;
/// Returns a forward iterator addressing the first element in a set
/**
}
//@}
- private:
- //@cond
- const_iterator get_const_begin() const
- {
- return const_iterator( const_cast<internal_bucket_type const&>(m_Buckets[0]).begin(), m_Buckets, m_Buckets + bucket_count() );
- }
- const_iterator get_const_end() const
- {
- return const_iterator( const_cast<internal_bucket_type const&>(m_Buckets[bucket_count() - 1]).end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
- }
- //@endcond
-
public:
/// Initialize hash set
/**
size_t nMaxItemCount, ///< estimation of max item count in the hash set
size_t nLoadFactor ///< load factor: estimation of max number of items in the bucket
) : m_nHashBitmask( michael_set::details::init_hash_bitmask( nMaxItemCount, nLoadFactor ))
+ , m_Buckets( bucket_table_allocator().allocate( bucket_count() ) )
{
- // GC and OrderedList::gc must be the same
- static_assert( std::is_same<gc, typename bucket_type::gc>::value, "GC and OrderedList::gc must be the same");
-
- static_assert( !std::is_same<item_counter, atomicity::empty_item_counter>::value,
- "atomicity::empty_item_counter is not allowed as a item counter");
-
- m_Buckets = bucket_table_allocator().NewArray( bucket_count() );
+ for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
+ construct_bucket<bucket_stat>( it );
}
/// Clears hash set and destroys it
~MichaelHashSet()
{
clear();
- bucket_table_allocator().Delete( m_Buckets, bucket_count() );
+
+ for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
+ it->~internal_bucket_type();
+ bucket_table_allocator().deallocate( m_Buckets, bucket_count() );
+
}
/// Inserts new node
Returns \p true if \p val is inserted into the set, \p false otherwise.
*/
template <typename Q>
- bool insert( Q const& val )
+ bool insert( Q&& val )
{
- const bool bRet = bucket( val ).insert( val );
+ const bool bRet = bucket( val ).insert( std::forward<Q>( val ));
if ( bRet )
++m_ItemCounter;
return bRet;
synchronization.
*/
template <typename Q, typename Func>
- bool insert( Q const& val, Func f )
+ bool insert( Q&& val, Func f )
{
- const bool bRet = bucket( val ).insert( val, f );
+ const bool bRet = bucket( val ).insert( std::forward<Q>( val ), f );
if ( bRet )
++m_ItemCounter;
return bRet;
}
-
/// Updates the element
/**
The operation performs inserting or changing data with lock-free manner.
The function applies RCU lock internally.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
\p second is \p true if new item has been added or \p false if the item with \p key
already is in the set.
synchronization.
*/
template <typename Q, typename Func>
- std::pair<bool, bool> update( const Q& val, Func func, bool bAllowInsert = true )
+ std::pair<bool, bool> update( Q const& val, Func func, bool bAllowInsert = true )
{
std::pair<bool, bool> bRet = bucket( val ).update( val, func, bAllowInsert );
if ( bRet.second )
If the item with the key equal to \p key is not found the function return an empty \p exempt_ptr.
The function just excludes the item from the set and returns a pointer to item found.
- Depends on \p bucket_type you should or should not lock RCU before calling of this function:
+ Depends on \p ordered_list you should or should not lock RCU before calling of this function:
- for the set based on \ref cds_nonintrusive_MichaelList_rcu "MichaelList" RCU should not be locked
- for the set based on \ref cds_nonintrusive_LazyList_rcu "LazyList" RCU should be locked
See ordered list implementation for details.
/** \anchor cds_nonintrusive_MichaelHashSet_rcu_get
The function searches the item with key equal to \p key and returns the pointer to item found.
If \p key is not found it returns \p nullptr.
- Note the type of returned value depends on underlying \p bucket_type.
+ Note the type of returned value depends on underlying \p ordered_list.
For details, see documentation of ordered list you use.
Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
return m_ItemCounter;
}
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return m_Stat;
+ }
+
/// Returns the size of hash table
/**
Since \p %MichaelHashSet cannot dynamically extend the hash table size,
{
return m_nHashBitmask + 1;
}
+
+ protected:
+ //@cond
+ /// Calculates hash value of \p key
+ template <typename Q>
+ size_t hash_value( Q const& key ) const
+ {
+ return m_HashFunctor( key ) & m_nHashBitmask;
+ }
+
+ /// Returns the bucket (ordered list) for \p key
+ template <typename Q>
+ internal_bucket_type& bucket( Q const& key )
+ {
+ return m_Buckets[hash_value( key )];
+ }
+ template <typename Q>
+ internal_bucket_type const& bucket( Q const& key ) const
+ {
+ return m_Buckets[hash_value( key )];
+ }
+
+ template <typename Stat>
+ typename std::enable_if< Stat::empty >::type construct_bucket( internal_bucket_type* bucket )
+ {
+ new (bucket) internal_bucket_type;
+ }
+
+ template <typename Stat>
+ typename std::enable_if< !Stat::empty >::type construct_bucket( internal_bucket_type* bucket )
+ {
+ new (bucket) internal_bucket_type( m_Stat );
+ }
+
+ const_iterator get_const_begin() const
+ {
+ return const_iterator( const_cast<internal_bucket_type const&>(m_Buckets[0]).begin(), m_Buckets, m_Buckets + bucket_count() );
+ }
+ const_iterator get_const_end() const
+ {
+ return const_iterator( const_cast<internal_bucket_type const&>(m_Buckets[bucket_count() - 1]).end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
+ }
+ //@endcond
};
}} // namespace cds::container
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_CONTAINER_MSPRIORITY_QUEUE_H
namespace mspriority_queue {
#ifdef CDS_DOXYGEN_INVOKED
- /// Synonym for cds::intrusive::mspriority_queue::stat
+ /// Synonym for \p cds::intrusive::mspriority_queue::stat
typedef cds::intrusive::mspriority_queue::stat<> stat;
- /// Synonym for cds::intrusive::mspriority_queue::empty_stat
+ /// Synonym for \p cds::intrusive::mspriority_queue::empty_stat
typedef cds::intrusive::mspriority_queue::empty_stat empty_stat;
#else
using cds::intrusive::mspriority_queue::stat;
If the compiler supports move semantics it would be better to specify the move policy
based on the move semantics for type \p T.
- \p opt::stat - internal statistics. Available types: \p mspriority_queue::stat, \p mspriority_queue::empty_stat (the default, no overhead)
- */
+ */
template <typename... Options>
struct make_traits {
# ifdef CDS_DOXYGEN_INVOKED
typedef Traits traits ; ///< Traits template parameter
typedef typename base_class::key_comparator key_comparator; ///< priority comparing functor based on opt::compare and opt::less option setter.
- typedef typename base_class::lock_type lock_type; ///< heap's size lock type
- typedef typename base_class::back_off back_off ; ///< Back-off strategy
- typedef typename base_class::stat stat ; ///< internal statistics type
+ typedef typename base_class::lock_type lock_type; ///< heap's size lock type
+ typedef typename base_class::back_off back_off ; ///< Back-off strategy
+ typedef typename traits::stat stat; ///< internal statistics type, see \p intrusive::mspriority_queue::traits::stat
+ typedef typename base_class::item_counter item_counter;///< Item counter type
typedef typename traits::allocator::template rebind<value_type>::other allocator_type; ///< Value allocator
- typedef typename traits::move_policy move_policy; ///< Move policy for type \p T
+ typedef typename traits::move_policy move_policy; ///< Move policy for type \p T
protected:
//@cond
RCU \p synchronize() method can be called. RCU should not be locked.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
\p second is \p true if new item has been added or \p false if the item with \p key
already exists.
RCU \p synchronize method can be called. RCU should not be locked.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
\p second is true if new item has been added or \p false if the item with \p key
already exists.
*/
- \p bNew - \p true if the item has been inserted, \p false otherwise
- \p item - item of the map
- Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
\p second is true if new item has been added or \p false if the item with \p key
already is in the map.
The function applies RCU lock internally.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
\p second is true if new item has been added or \p false if the item with \p key
already exists.
The functor may change non-key fields of the \p item.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
\p second is true if new item has been added or \p false if the item with \p key
already is in the map.
The function applies RCU lock internally.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
\p second is true if new item has been added or \p false if the item with \p key
already is in the set.
*/
The function applies RCU lock internally.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
\p second is true if new item has been added or \p false if the item with \p key
already is in the map.
- \p bNew - \p true if the item has been inserted, \p false otherwise
- \p item - item of the map
- Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
\p second is true if new item has been added or \p false if the item with \p key
already is in the map.
*/
The functor may change non-key fields of the \p item.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
\p second is true if new item has been added or \p false if the item with \p key
already is in the map.
*/
The type \p Q can differ from \ref value_type of items storing in the container.
Therefore, the \p value_type should be comparable with type \p Q and constructible from type \p Q,
- Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
\p second is true if new item has been added or \p false if the item with \p val key
already exists.
<hr>
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_DETAILS_ALLOCATOR_H
counter_type dec()
{
+ counter_type ret = m_nReversed;
--m_nCounter;
int nBit;
for ( nBit = m_nHighBit - 1; nBit >= 0; --nBit ) {
m_nReversed = m_nCounter;
--m_nHighBit;
}
- return m_nReversed;
+ return ret;
}
counter_type value() const
{
return m_nReversed;
}
+
+ int high_bit() const
+ {
+ return m_nHighBit;
+ }
};
}} // namespace cds::bitop
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_DETAILS_BITOP_GENERIC_H
r -= 2;
}
if (!(x & 0x80000000u)) {
- x <<= 1;
+ //x <<= 1;
r -= 1;
}
return r;
r += 2;
}
if (!(x & 1)) {
- x >>= 1;
+ //x >>= 1;
r += 1;
}
return r;
counter_type m_nRelocateCallCount ; ///< Count of \p relocate() function call
counter_type m_nRelocateRoundCount ; ///< Count of attempts to relocate items
counter_type m_nFalseRelocateCount ; ///< Count of unneeded attempts of \p relocate call
- counter_type m_nSuccessRelocateCount ; ///< Count of successfull item relocating
+ counter_type m_nSuccessRelocateCount ; ///< Count of successful item relocating
counter_type m_nRelocateAboveThresholdCount; ///< Count of item relocating above probeset threshold
counter_type m_nFailedRelocateCount ; ///< Count of failed relocation attemp (when all probeset is full)
counter_type m_nResizeCallCount ; ///< Count of \p resize() function call
counter_type m_nFalseResizeCount ; ///< Count of false \p resize() function call (when other thread has been resized the set)
- counter_type m_nResizeSuccessNodeMove; ///< Count of successfull node moving when resizing
+ counter_type m_nResizeSuccessNodeMove; ///< Count of successful node moving when resizing
counter_type m_nResizeRelocateCall ; ///< Count of \p relocate() function call from \p resize function
- counter_type m_nInsertSuccess ; ///< Count of successfull \p insert() function call
+ counter_type m_nInsertSuccess ; ///< Count of successful \p insert() function call
counter_type m_nInsertFailed ; ///< Count of failed \p insert() function call
counter_type m_nInsertResizeCount ; ///< Count of \p resize() function call from \p insert()
counter_type m_nInsertRelocateCount ; ///< Count of \p relocate() function call from \p insert()
counter_type m_nInsertRelocateFault ; ///< Count of failed \p relocate() function call from \p insert()
counter_type m_nUpdateExistCount ; ///< Count of call \p update() function for existing node
- counter_type m_nUpdateSuccessCount ; ///< Count of successfull \p insert() function call for new node
+ counter_type m_nUpdateSuccessCount ; ///< Count of successful \p insert() function call for new node
counter_type m_nUpdateResizeCount ; ///< Count of \p resize() function call from \p update()
counter_type m_nUpdateRelocateCount ; ///< Count of \p relocate() function call from \p update()
counter_type m_nUpdateRelocateFault ; ///< Count of failed \p relocate() function call from \p update()
The functor may change non-key fields of the \p item.
- Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+ Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
i.e. the node has been inserted or updated,
\p second is \p true if new item has been added or \p false if the item with \p key
already exists.
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSLIB_INTRUSIVE_DETAILS_ITERABLE_LIST_BASE_H
+#define CDSLIB_INTRUSIVE_DETAILS_ITERABLE_LIST_BASE_H
+
+#include <type_traits>
+#include <cds/intrusive/details/base.h>
+#include <cds/opt/compare.h>
+#include <cds/algo/atomic.h>
+#include <cds/details/marked_ptr.h>
+#include <cds/urcu/options.h>
+
+namespace cds { namespace intrusive {
+
+ /// \p IterableList ordered list related definitions
+ /** @ingroup cds_intrusive_helper
+ */
+ namespace iterable_list {
+
+ /// Node type
+ template <typename T>
+ struct node
+ {
+ typedef T value_type; ///< Value type
+
+ atomics::atomic< node* > next; ///< pointer to next node in the list
+ atomics::atomic< value_type* > data; ///< pointer to user data, \p nullptr if the node is free
+
+ //@cond
+ node()
+ : next( nullptr )
+ , data( nullptr )
+ {}
+
+ node( value_type * pVal )
+ : next( nullptr )
+ , data( pVal )
+ {}
+ //@endcond
+ };
+
+ /// \p IterableList internal statistics
+ template <typename EventCounter = cds::atomicity::event_counter>
+ struct stat {
+ typedef EventCounter event_counter; ///< Event counter type
+
+ event_counter m_nInsertSuccess; ///< Number of success \p insert() operations
+ event_counter m_nInsertFailed; ///< Number of failed \p insert() operations
+ event_counter m_nInsertRetry; ///< Number of attempts to insert new item
+ event_counter m_nUpdateNew; ///< Number of new item inserted for \p update()
+ event_counter m_nUpdateExisting; ///< Number of existing item updates
+ event_counter m_nUpdateFailed; ///< Number of failed \p update() call
+ event_counter m_nUpdateRetry; ///< Number of attempts to update the item
+ event_counter m_nEraseSuccess; ///< Number of successful \p erase(), \p unlink(), \p extract() operations
+ event_counter m_nEraseFailed; ///< Number of failed \p erase(), \p unlink(), \p extract() operations
+ event_counter m_nEraseRetry; ///< Number of attempts to \p erase() an item
+ event_counter m_nFindSuccess; ///< Number of successful \p find() and \p get() operations
+ event_counter m_nFindFailed; ///< Number of failed \p find() and \p get() operations
+
+ event_counter m_nNodeCreated; ///< Number of created internal nodes
+ event_counter m_nNodeRemoved; ///< Number of removed internal nodes
+
+ //@cond
+ void onInsertSuccess() { ++m_nInsertSuccess; }
+ void onInsertFailed() { ++m_nInsertFailed; }
+ void onInsertRetry() { ++m_nInsertRetry; }
+ void onUpdateNew() { ++m_nUpdateNew; }
+ void onUpdateExisting() { ++m_nUpdateExisting; }
+ void onUpdateFailed() { ++m_nUpdateFailed; }
+ void onUpdateRetry() { ++m_nUpdateRetry; }
+ void onEraseSuccess() { ++m_nEraseSuccess; }
+ void onEraseFailed() { ++m_nEraseFailed; }
+ void onEraseRetry() { ++m_nEraseRetry; }
+ void onFindSuccess() { ++m_nFindSuccess; }
+ void onFindFailed() { ++m_nFindFailed; }
+
+ void onNodeCreated() { ++m_nNodeCreated; }
+ void onNodeRemoved() { ++m_nNodeRemoved; }
+ //@endcond
+ };
+
+ /// \p IterableList empty internal statistics
+ struct empty_stat {
+ //@cond
+ void onInsertSuccess() const {}
+ void onInsertFailed() const {}
+ void onInsertRetry() const {}
+ void onUpdateNew() const {}
+ void onUpdateExisting() const {}
+ void onUpdateFailed() const {}
+ void onUpdateRetry() const {}
+ void onEraseSuccess() const {}
+ void onEraseFailed() const {}
+ void onEraseRetry() const {}
+ void onFindSuccess() const {}
+ void onFindFailed() const {}
+
+ void onNodeCreated() const {}
+ void onNodeRemoved() const {}
+ //@endcond
+ };
+
+ //@cond
+ template <typename Stat = iterable_list::stat<>>
+ struct wrapped_stat {
+ typedef Stat stat_type;
+
+ wrapped_stat( stat_type& st )
+ : m_stat( st )
+ {}
+
+ void onInsertSuccess() { m_stat.onInsertSuccess(); }
+ void onInsertFailed() { m_stat.onInsertFailed(); }
+ void onInsertRetry() { m_stat.onInsertRetry(); }
+ void onUpdateNew() { m_stat.onUpdateNew(); }
+ void onUpdateExisting() { m_stat.onUpdateExisting();}
+ void onUpdateFailed() { m_stat.onUpdateFailed(); }
+ void onUpdateRetry() { m_stat.onUpdateRetry(); }
+ void onEraseSuccess() { m_stat.onEraseSuccess(); }
+ void onEraseFailed() { m_stat.onEraseFailed(); }
+ void onEraseRetry() { m_stat.onEraseRetry(); }
+ void onFindSuccess() { m_stat.onFindSuccess(); }
+ void onFindFailed() { m_stat.onFindFailed(); }
+
+ void onNodeCreated() { m_stat.onNodeCreated(); }
+ void onNodeRemoved() { m_stat.onNodeRemoved(); }
+
+ stat_type& m_stat;
+ };
+ //@endcond
+
+
+ /// \p IterableList traits
+ struct traits
+ {
+ /// Key comparison functor
+ /**
+ No default functor is provided. If the option is not specified, the \p less is used.
+ */
+ typedef opt::none compare;
+
+ /// Specifies binary predicate used for key compare.
+ /**
+ Default is \p std::less<T>
+ */
+ typedef opt::none less;
+
+ /// Node allocator
+ typedef CDS_DEFAULT_ALLOCATOR node_allocator;
+
+ /// Back-off strategy
+ typedef cds::backoff::Default back_off;
+
+ /// Disposer for removing items
+ typedef opt::v::empty_disposer disposer;
+
+ /// Internal statistics
+ /**
+ By default, internal statistics is disabled (\p iterable_list::empty_stat).
+ Use \p iterable_list::stat to enable it.
+ */
+ typedef empty_stat stat;
+
+ /// Item counting feature; by default, disabled. Use \p cds::atomicity::item_counter to enable item counting
+ typedef atomicity::empty_item_counter item_counter;
+
+ /// C++ memory ordering model
+ /**
+ Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
+ or \p opt::v::sequential_consistent (sequentially consisnent memory model).
+ */
+ typedef opt::v::relaxed_ordering memory_model;
+
+ /// RCU deadlock checking policy (only for \ref cds_intrusive_IterableList_rcu "RCU-based IterableList")
+ /**
+ List of available policy see \p opt::rcu_check_deadlock
+ */
+ typedef opt::v::rcu_throw_deadlock rcu_check_deadlock;
+ };
+
+ /// Metafunction converting option list to \p iterable_list::traits
+ /**
+ Supported \p Options are:
+ - \p opt::compare - key comparison functor. No default functor is provided.
+ If the option is not specified, the \p opt::less is used.
+ - \p opt::less - specifies binary predicate used for key comparison. Default is \p std::less<T>.
+ - \p opt::node_allocator - node allocator, default is \p std::allocator.
+ - \p opt::back_off - back-off strategy used. If the option is not specified, the \p cds::backoff::Default is used.
+ - \p opt::disposer - the functor used for disposing removed items. Default is \p opt::v::empty_disposer. Due the nature
+ of GC schema the disposer may be called asynchronously.
+ - \p opt::item_counter - the type of item counting feature. Default is disabled (\p atomicity::empty_item_counter).
+ To enable item counting use \p atomicity::item_counter.
+ - \p opt::stat - internal statistics. By default, it is disabled (\p iterable_list::empty_stat).
+ To enable it use \p iterable_list::stat
+ - \p opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
+ or \p opt::v::sequential_consistent (sequentially consistent memory model).
+ - \p opt::rcu_check_deadlock - a deadlock checking policy for \ref cds_intrusive_IterableList_rcu "RCU-based IterableList"
+ Default is \p opt::v::rcu_throw_deadlock
+ */
+ template <typename... Options>
+ struct make_traits {
+# ifdef CDS_DOXYGEN_INVOKED
+ typedef implementation_defined type ; ///< Metafunction result
+# else
+ typedef typename cds::opt::make_options<
+ typename cds::opt::find_type_traits< traits, Options... >::type
+ ,Options...
+ >::type type;
+# endif
+ };
+
+
+ //@cond
+ template <typename Stat>
+ struct select_stat_wrapper
+ {
+ typedef Stat stat;
+ typedef iterable_list::wrapped_stat<Stat> wrapped_stat;
+ enum {
+ empty = false
+ };
+ };
+
+ template <>
+ struct select_stat_wrapper< empty_stat >
+ {
+ typedef empty_stat stat;
+ typedef empty_stat wrapped_stat;
+ enum {
+ empty = true
+ };
+ };
+
+ template <typename Stat>
+ struct select_stat_wrapper< iterable_list::wrapped_stat<Stat>>: public select_stat_wrapper<Stat>
+ {};
+ //@endcond
+
+ } // namespace iterable_list
+
+ //@cond
+ // Forward declaration
+ template < class GC, typename T, class Traits = iterable_list::traits >
+ class IterableList;
+ //@endcond
+
+ //@cond
+ template <typename List>
+ struct is_iterable_list {
+ enum {
+ value = false
+ };
+ };
+
+ template <typename GC, typename T, typename Traits>
+ struct is_iterable_list< IterableList< GC, T, Traits >> {
+ enum {
+ value = true
+ };
+ };
+ //@endcond
+
+}} // namespace cds::intrusive
+
+#endif // #ifndef CDSLIB_INTRUSIVE_DETAILS_ITERABLE_LIST_BASE_H
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_INTRUSIVE_DETAILS_LAZY_LIST_BASE_H
//@endcond
};
+ /// \p LazyList internal statistics
+ template <typename EventCounter = cds::atomicity::event_counter>
+ struct stat {
+ typedef EventCounter event_counter; ///< Event counter type
+
+ event_counter m_nInsertSuccess; ///< Number of success \p insert() operations
+ event_counter m_nInsertFailed; ///< Number of failed \p insert() operations
+ event_counter m_nInsertRetry; ///< Number of attempts to insert new item
+ event_counter m_nUpdateNew; ///< Number of new item inserted for \p update()
+ event_counter m_nUpdateExisting; ///< Number of existing item updates
+ event_counter m_nUpdateFailed; ///< Number of failed \p update() call
+ event_counter m_nUpdateRetry; ///< Number of attempts to \p update() the item
+ event_counter m_nUpdateMarked; ///< Number of attempts to \p update() logically deleted (marked) items
+ event_counter m_nEraseSuccess; ///< Number of successful \p erase(), \p unlink(), \p extract() operations
+ event_counter m_nEraseFailed; ///< Number of failed \p erase(), \p unlink(), \p extract() operations
+ event_counter m_nEraseRetry; ///< Number of attempts to \p erase() an item
+ event_counter m_nFindSuccess; ///< Number of successful \p find() and \p get() operations
+ event_counter m_nFindFailed; ///< Number of failed \p find() and \p get() operations
+
+ event_counter m_nValidationSuccess; ///< Number of successful validating of search result
+ event_counter m_nValidationFailed; ///< Number of failed validating of search result
+
+ //@cond
+ void onInsertSuccess() { ++m_nInsertSuccess; }
+ void onInsertFailed() { ++m_nInsertFailed; }
+ void onInsertRetry() { ++m_nInsertRetry; }
+ void onUpdateNew() { ++m_nUpdateNew; }
+ void onUpdateExisting() { ++m_nUpdateExisting; }
+ void onUpdateFailed() { ++m_nUpdateFailed; }
+ void onUpdateRetry() { ++m_nUpdateRetry; }
+ void onUpdateMarked() { ++m_nUpdateMarked; }
+ void onEraseSuccess() { ++m_nEraseSuccess; }
+ void onEraseFailed() { ++m_nEraseFailed; }
+ void onEraseRetry() { ++m_nEraseRetry; }
+ void onFindSuccess() { ++m_nFindSuccess; }
+ void onFindFailed() { ++m_nFindFailed; }
+
+ void onValidationSuccess() { ++m_nValidationSuccess; }
+ void onValidationFailed() { ++m_nValidationFailed; }
+ //@endcond
+ };
+
+ /// \p LazyList empty internal statistics
+ struct empty_stat {
+ //@cond
+ void onInsertSuccess() const {}
+ void onInsertFailed() const {}
+ void onInsertRetry() const {}
+ void onUpdateNew() const {}
+ void onUpdateExisting() const {}
+ void onUpdateFailed() const {}
+ void onUpdateRetry() const {}
+ void onUpdateMarked() const {}
+ void onEraseSuccess() const {}
+ void onEraseFailed() const {}
+ void onEraseRetry() const {}
+ void onFindSuccess() const {}
+ void onFindFailed() const {}
+
+ void onValidationSuccess() const {}
+ void onValidationFailed() const {}
+ //@endcond
+ };
+
+ //@cond
+ template <typename Stat = lazy_list::stat<>>
+ struct wrapped_stat {
+ typedef Stat stat_type;
+
+ wrapped_stat( stat_type& st )
+ : m_stat( st )
+ {}
+
+ void onInsertSuccess() { m_stat.onInsertSuccess(); }
+ void onInsertFailed() { m_stat.onInsertFailed(); }
+ void onInsertRetry() { m_stat.onInsertRetry(); }
+ void onUpdateNew() { m_stat.onUpdateNew(); }
+ void onUpdateExisting() { m_stat.onUpdateExisting(); }
+ void onUpdateFailed() { m_stat.onUpdateFailed(); }
+ void onUpdateRetry() { m_stat.onUpdateRetry(); }
+ void onUpdateMarked() { m_stat.onUpdateMarked(); }
+ void onEraseSuccess() { m_stat.onEraseSuccess(); }
+ void onEraseFailed() { m_stat.onEraseFailed(); }
+ void onEraseRetry() { m_stat.onEraseRetry(); }
+ void onFindSuccess() { m_stat.onFindSuccess(); }
+ void onFindFailed() { m_stat.onFindFailed(); }
+
+ void onValidationSuccess() { m_stat.onValidationSuccess(); }
+ void onValidationFailed() { m_stat.onValidationFailed(); }
+
+ stat_type& m_stat;
+ };
+ //@endcond
+
+
/// LazyList traits
struct traits
{
/// Item counting feature; by default, disabled. Use \p cds::atomicity::item_counter to enable item counting
typedef atomicity::empty_item_counter item_counter;
+ /// Internal statistics
+ /**
+ By default, internal statistics is disabled (\p lazy_list::empty_stat).
+ Use \p lazy_list::stat to enable it.
+ */
+ typedef empty_stat stat;
+
/// Link fields checking feature
/**
Default is \p opt::debug_check_link
- \p opt::link_checker - the type of node's link fields checking. Default is \p opt::debug_check_link
- \p opt::item_counter - the type of item counting feature. Default is disabled (\p atomicity::empty_item_counter).
To enable item counting use \p atomicity::item_counter.
+ - \p opt::stat - internal statistics. By default, it is disabled (\p lazy_list::empty_stat).
+ To enable it use \p lazy_list::stat
- \p opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
or \p opt::v::sequential_consistent (sequentially consisnent memory model).
- \p opt::rcu_check_deadlock - a deadlock checking policy for \ref cds_intrusive_MichaelList_rcu "RCU-based MichaelList"
# endif
};
+ //@cond
+ template <typename Stat>
+ struct select_stat_wrapper
+ {
+ typedef Stat stat;
+ typedef lazy_list::wrapped_stat<Stat> wrapped_stat;
+ enum {
+ empty = false
+ };
+ };
+
+ template <>
+ struct select_stat_wrapper< empty_stat >
+ {
+ typedef empty_stat stat;
+ typedef empty_stat wrapped_stat;
+ enum {
+ empty = true
+ };
+ };
+
+ template <typename Stat>
+ struct select_stat_wrapper< lazy_list::wrapped_stat<Stat>>: public select_stat_wrapper< Stat >
+ {};
+ //@endcond
+
} // namespace lazy_list
//@cond
class LazyList;
//@endcond
+ //@cond
+ template <typename List>
+ struct is_lazy_list {
+ enum {
+ value = false
+ };
+ };
+
+ template <typename GC, typename T, typename Traits>
+ struct is_lazy_list< LazyList< GC, T, Traits >> {
+ enum {
+ value = true
+ };
+ };
+ //@endcond
+
}} // namespace cds::intrusive
#endif // #ifndef CDSLIB_INTRUSIVE_DETAILS_LAZY_LIST_BASE_H
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_INTRUSIVE_DETAILS_MICHAEL_LIST_BASE_H
//@endcond
};
+
+ /// \p MichaelList internal statistics
+ template <typename EventCounter = cds::atomicity::event_counter>
+ struct stat {
+ typedef EventCounter event_counter; ///< Event counter type
+
+ event_counter m_nInsertSuccess; ///< Number of success \p insert() operations
+ event_counter m_nInsertFailed; ///< Number of failed \p insert() operations
+ event_counter m_nInsertRetry; ///< Number of attempts to insert new item
+ event_counter m_nUpdateNew; ///< Number of new item inserted for \p update()
+ event_counter m_nUpdateExisting; ///< Number of existing item updates
+ event_counter m_nUpdateFailed; ///< Number of failed \p update() call
+ event_counter m_nUpdateRetry; ///< Number of attempts to \p update() the item
+ event_counter m_nUpdateMarked; ///< Number of attempts to \p update() logically deleted (marked) items
+ event_counter m_nEraseSuccess; ///< Number of successful \p erase(), \p unlink(), \p extract() operations
+ event_counter m_nEraseFailed; ///< Number of failed \p erase(), \p unlink(), \p extract() operations
+ event_counter m_nEraseRetry; ///< Number of attempts to \p erase() an item
+ event_counter m_nFindSuccess; ///< Number of successful \p find() and \p get() operations
+ event_counter m_nFindFailed; ///< Number of failed \p find() and \p get() operations
+
+ event_counter m_nHelpingSuccess; ///< Number of successful help attempts to remove marked item during searching
+ event_counter m_nHelpingFailed; ///< Number if failed help attempts to remove marked item during searching
+
+ //@cond
+ void onInsertSuccess() { ++m_nInsertSuccess; }
+ void onInsertFailed() { ++m_nInsertFailed; }
+ void onInsertRetry() { ++m_nInsertRetry; }
+ void onUpdateNew() { ++m_nUpdateNew; }
+ void onUpdateExisting() { ++m_nUpdateExisting; }
+ void onUpdateFailed() { ++m_nUpdateFailed; }
+ void onUpdateRetry() { ++m_nUpdateRetry; }
+ void onUpdateMarked() { ++m_nUpdateMarked; }
+ void onEraseSuccess() { ++m_nEraseSuccess; }
+ void onEraseFailed() { ++m_nEraseFailed; }
+ void onEraseRetry() { ++m_nEraseRetry; }
+ void onFindSuccess() { ++m_nFindSuccess; }
+ void onFindFailed() { ++m_nFindFailed; }
+
+ void onHelpingSuccess() { ++m_nHelpingSuccess; }
+ void onHelpingFailed() { ++m_nHelpingFailed; }
+ //@endcond
+ };
+
+ /// \p MichaelList empty internal statistics
+ struct empty_stat {
+ //@cond
+ void onInsertSuccess() const {}
+ void onInsertFailed() const {}
+ void onInsertRetry() const {}
+ void onUpdateNew() const {}
+ void onUpdateExisting() const {}
+ void onUpdateFailed() const {}
+ void onUpdateRetry() const {}
+ void onUpdateMarked() const {}
+ void onEraseSuccess() const {}
+ void onEraseFailed() const {}
+ void onEraseRetry() const {}
+ void onFindSuccess() const {}
+ void onFindFailed() const {}
+
+ void onHelpingSuccess() const {}
+ void onHelpingFailed() const {}
+ //@endcond
+ };
+
+ //@cond
+ template <typename Stat = michael_list::stat<>>
+ struct wrapped_stat {
+ typedef Stat stat_type;
+
+ wrapped_stat( stat_type& st )
+ : m_stat( st )
+ {}
+
+ void onInsertSuccess() { m_stat.onInsertSuccess(); }
+ void onInsertFailed() { m_stat.onInsertFailed(); }
+ void onInsertRetry() { m_stat.onInsertRetry(); }
+ void onUpdateNew() { m_stat.onUpdateNew(); }
+ void onUpdateExisting() { m_stat.onUpdateExisting(); }
+ void onUpdateFailed() { m_stat.onUpdateFailed(); }
+ void onUpdateRetry() { m_stat.onUpdateRetry(); }
+ void onUpdateMarked() { m_stat.onUpdateMarked(); }
+ void onEraseSuccess() { m_stat.onEraseSuccess(); }
+ void onEraseFailed() { m_stat.onEraseFailed(); }
+ void onEraseRetry() { m_stat.onEraseRetry(); }
+ void onFindSuccess() { m_stat.onFindSuccess(); }
+ void onFindFailed() { m_stat.onFindFailed(); }
+
+ void onHelpingSuccess() { m_stat.onHelpingSuccess(); }
+ void onHelpingFailed() { m_stat.onHelpingFailed(); }
+
+ stat_type& m_stat;
+ };
+ //@endcond
+
/// MichaelList traits
struct traits
{
typedef opt::v::empty_disposer disposer;
/// Item counting feature; by default, disabled. Use \p cds::atomicity::item_counter to enable item counting
- typedef atomicity::empty_item_counter item_counter;
+ typedef atomicity::empty_item_counter item_counter;
+
+ /// Internal statistics
+ /**
+ By default, internal statistics is disabled (\p michael_list::empty_stat).
+ Use \p michael_list::stat to enable it.
+ */
+ typedef empty_stat stat;
/// Link fields checking feature
/**
- \p opt::link_checker - the type of node's link fields checking. Default is \p opt::debug_check_link
- \p opt::item_counter - the type of item counting feature. Default is disabled (\p atomicity::empty_item_counter).
To enable item counting use \p atomicity::item_counter.
+ - \p opt::stat - internal statistics. By default, it is disabled (\p michael_list::empty_stat).
+ To enable it use \p michael_list::stat
- \p opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
- or \p opt::v::sequential_consistent (sequentially consisnent memory model).
+ or \p opt::v::sequential_consistent (sequentially consistent memory model).
- \p opt::rcu_check_deadlock - a deadlock checking policy for \ref cds_intrusive_MichaelList_rcu "RCU-based MichaelList"
Default is \p opt::v::rcu_throw_deadlock
*/
# endif
};
+
+ //@cond
+ template <typename Stat>
+ struct select_stat_wrapper
+ {
+ typedef Stat stat;
+ typedef michael_list::wrapped_stat<Stat> wrapped_stat;
+ enum {
+ empty = false
+ };
+ };
+
+ template <>
+ struct select_stat_wrapper< empty_stat >
+ {
+ typedef empty_stat stat;
+ typedef empty_stat wrapped_stat;
+ enum {
+ empty = true
+ };
+ };
+
+ template <typename Stat>
+ struct select_stat_wrapper< michael_list::wrapped_stat<Stat>>: public select_stat_wrapper< Stat >
+ {};
+
+ //@endcond
+
} // namespace michael_list
//@cond
//@endcond
- /// Tag for selecting Michael list
- //class michael_list_tag;
+ //@cond
+ template <typename List>
+ struct is_michael_list {
+ enum {
+ value = false
+ };
+ };
+
+ template <typename GC, typename T, typename Traits>
+ struct is_michael_list< MichaelList< GC, T, Traits >> {
+ enum {
+ value = true
+ };
+ };
+ //@endcond
}} // namespace cds::intrusive
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_INTRUSIVE_DETAILS_MICHAEL_SET_BASE_H
template <typename OrderedList, bool IsConst>
class iterator
{
- friend class iterator < OrderedList, !IsConst >;
+ friend class iterator< OrderedList, !IsConst >;
+
protected:
typedef OrderedList bucket_type;
typedef typename list_iterator_selector< bucket_type, IsConst>::bucket_ptr bucket_ptr;
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_INTRUSIVE_DETAILS_SPLIT_LIST_BASE_H
/// Split-ordered list node
/**
Template parameter:
- - OrderedListNode - node type for underlying ordered list
+ - \p OrderedListNode - node type for underlying ordered list
*/
template <typename OrderedListNode>
struct node: public OrderedListNode
}
};
- /// SplitListSet internal statistics. May be used for debugging or profiling
+ /// \p SplitListSet internal statistics. May be used for debugging or profiling
/**
- Template argument \p Counter defines type of counter.
- Default is \p cds::atomicity::event_counter, that is weak, i.e. it is not guaranteed
- strict event counting.
- You may use stronger type of counter like as \p cds::atomicity::item_counter,
- or even integral type, for example, \p int.
+ Template argument \p Counter defines type of counter, default is \p cds::atomicity::event_counter.
*/
template <typename Counter = cds::atomicity::event_counter >
struct stat
for default type.
- \p opt::memory_model - C++ memory model for atomic operations.
Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
- or \p opt::v::sequential_consistent (sequentially consisnent memory model).
+ or \p opt::v::sequential_consistent (sequentially consistent memory model).
- \p opt::allocator - optional, bucket table allocator. Default is \ref CDS_DEFAULT_ALLOCATOR.
- \p split_list::dynamic_bucket_table - use dynamic or static bucket table implementation.
Dynamic bucket table expands its size up to maximum bucket count when necessary
- - \p opt::back_off - back-off strategy used for spinning, defult is \p cds::backoff::Default.
+ - \p opt::back_off - back-off strategy used for spinning, default is \p cds::backoff::Default.
- \p opt::stat - internal statistics, default is \p split_list::empty_stat (disabled).
To enable internal statistics use \p split_list::stat.
*/
return static_cast<node_type const *>( base_class::to_node_ptr( v ) );
}
- /// Convert node refernce to value pointer
+ /// Convert node reference to value pointer
static value_type * to_value_ptr( node_type& n )
{
return base_class::to_value_ptr( static_cast<base_node_type &>( n ) );
RCU \p synchronize method can be called. RCU should not be locked.
- Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+ Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
i.e. the node has been inserted or updated,
\p second is \p true if new item has been added or \p false if the item with \p key
already exists.
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_INTRUSIVE_FELDMAN_HASHSET_RCU_H
- If hash value is not found and \p bInsert is \p false then the set is unchanged,
the function returns <tt> std::pair<false, false> </tt>
- Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful
(i.e. the item has been inserted or updated),
\p second is \p true if new item has been added or \p false if the set contains that hash.
/** @anchor cds_intrusive_FeldmanHashSet_rcu_iterators
The set supports thread-safe iterators: you may iterate over the set in multi-threaded environment
under explicit RCU lock.
- RCU lock requirement means that inserting or searching is allowed but you must not erase the items from the set
- because erasing under RCU lock can lead to a deadlock. However, another thread can call \p erase() safely
- while your thread is iterating.
+
+ RCU lock requirement means that inserting or searching is allowed for iterating thread
+ but you must not erase the items from the set because erasing under RCU lock can lead
+ to a deadlock. However, another thread can call \p erase() safely while your thread is iterating.
A typical example is:
\code
/** @ingroup cds_intrusive_helper
Free list is a helper class intended for reusing objects instead of freeing them completely;
- this avoids the overhead of \p malloc(), and also avoids its worst-case behaviour of taking an operating system lock.
+ this avoids the overhead of \p malloc(), and also avoids its worst-case behavior of taking an operating system lock.
So, the free list can be considered as a specialized allocator for objects of some type.
The algorithm is taken from <a href="http://moodycamel.com/blog/2014/solving-the-aba-problem-for-lock-free-free-lists">this article</a>.
while ( head != nullptr ) {
auto prevHead = head;
auto refs = head->m_freeListRefs.load( atomics::memory_order_relaxed );
- if ( (refs & c_RefsMask) == 0 || !head->m_freeListRefs.compare_exchange_strong( refs, refs + 1,
- atomics::memory_order_acquire, atomics::memory_order_relaxed ))
+
+ if ( cds_unlikely( (refs & c_RefsMask) == 0 || !head->m_freeListRefs.compare_exchange_strong( refs, refs + 1,
+ atomics::memory_order_acquire, atomics::memory_order_relaxed )))
{
head = m_Head.load( atomics::memory_order_acquire );
continue;
// we can read the next and not worry about it changing between now and the time
// we do the CAS
node * next = head->m_freeListNext.load( atomics::memory_order_relaxed );
- if ( m_Head.compare_exchange_strong( head, next, atomics::memory_order_acquire, atomics::memory_order_relaxed )) {
+ if ( cds_likely( m_Head.compare_exchange_strong( head, next, atomics::memory_order_acquire, atomics::memory_order_relaxed ))) {
// Yay, got the node. This means it was on the list, which means
// shouldBeOnFreeList must be false no matter the refcount (because
// nobody else knows it's been taken off yet, it can't have been put back on).
while ( true ) {
pNode->m_freeListNext.store( head, atomics::memory_order_relaxed );
pNode->m_freeListRefs.store( 1, atomics::memory_order_release );
- if ( !m_Head.compare_exchange_strong( head, pNode, atomics::memory_order_release, atomics::memory_order_relaxed )) {
+ if ( cds_unlikely( !m_Head.compare_exchange_strong( head, pNode, atomics::memory_order_release, atomics::memory_order_relaxed ))) {
// Hmm, the add failed, but we can only try again when the refcount goes back to zero
if ( pNode->m_freeListRefs.fetch_add( c_ShouldBeOnFreeList - 1, atomics::memory_order_release ) == 1 )
continue;
do {
newHead.tag = currentHead.tag + 1;
pNode->m_freeListNext.store( currentHead.ptr, atomics::memory_order_relaxed );
- } while ( !m_Head.compare_exchange_weak( currentHead, newHead, atomics::memory_order_release, atomics::memory_order_relaxed ));
+ } while ( cds_unlikely( !m_Head.compare_exchange_weak( currentHead, newHead, atomics::memory_order_release, atomics::memory_order_relaxed )));
}
/// Gets a node from the free list. If the list is empty, returns \p nullptr
while ( currentHead.ptr != nullptr ) {
newHead.ptr = currentHead.ptr->m_freeListNext.load( atomics::memory_order_relaxed );
newHead.tag = currentHead.tag + 1;
- if ( m_Head.compare_exchange_weak( currentHead, newHead, atomics::memory_order_release, atomics::memory_order_acquire ) )
+ if ( cds_likely( m_Head.compare_exchange_weak( currentHead, newHead, atomics::memory_order_release, atomics::memory_order_acquire )))
break;
}
return currentHead.ptr;
The functor can change non-key fields of the \p item; however, \p func must guarantee
that during changing no any other modifications could be made on this item by concurrent threads.
- Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+ Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
i.e. the node has been inserted or updated,
\p second is \p true if new item has been added or \p false if the item with \p key
already exists.
// slot value has been changed - retry
stats().onSlotChanged();
}
-
- if ( slot.ptr()) {
+ else if ( slot.ptr()) {
if ( cmp( hash, hash_accessor()( *slot.ptr())) == 0 ) {
// the item with that hash value already exists
stats().onInsertFailed();
- If hash value is not found and \p bInsert is \p false then the set is unchanged,
the function returns <tt> std::pair<false, false> </tt>
- Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful
(i.e. the item has been inserted or updated),
\p second is \p true if new item has been added or \p false if the set contains that hash.
*/
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSLIB_INTRUSIVE_IMPL_ITERABLE_LIST_H
+#define CDSLIB_INTRUSIVE_IMPL_ITERABLE_LIST_H
+
+#include <cds/intrusive/details/iterable_list_base.h>
+#include <cds/details/make_const_type.h>
+
+namespace cds { namespace intrusive {
+
+ /// Iterable lock-free ordered single-linked list
+ /** @ingroup cds_intrusive_list
+ \anchor cds_intrusive_IterableList_hp
+
+ This lock-free list implementation supports thread-safe iterators.
+ Unlike \p cds::intrusive::MichaelList the iterable list does not require
+ any hook in \p T to be stored in the list.
+
+ Usually, ordered single-linked list is used as a building block for the hash table implementation.
+ Iterable list is suitable for almost append-only hash table because the list doesn't delete
+ its internal node when erasing a key but it is marked them as empty to be reused in the future.
+ However, plenty of empty nodes degrades performance.
+ Separation of internal nodes and user data implies the need for an allocator for internal node
+ so the iterable list is not fully intrusive. Nevertheless, if you need thread-safe iterator,
+ the iterable list is good choice.
+
+ The complexity of searching is <tt>O(N)</tt>.
+
+ Template arguments:
+ - \p GC - Garbage collector used.
+ - \p T - type to be stored in the list.
+ - \p Traits - type traits, default is \p iterable_list::traits. It is possible to declare option-based
+ list with \p cds::intrusive::iterable_list::make_traits metafunction:
+ For example, the following traits-based declaration of \p gc::HP iterable list
+ \code
+ #include <cds/intrusive/iterable_list_hp.h>
+ // Declare item stored in your list
+ struct foo
+ {
+ int nKey;
+ // .... other data
+ };
+
+ // Declare comparator for the item
+ struct my_compare {
+ int operator()( foo const& i1, foo const& i2 ) const
+ {
+ return i1.nKey - i2.nKey;
+ }
+ };
+
+ // Declare traits
+ struct my_traits: public cds::intrusive::iterable_list::traits
+ {
+ typedef my_compare compare;
+ };
+
+ // Declare list
+ typedef cds::intrusive::IterableList< cds::gc::HP, foo, my_traits > list_type;
+ \endcode
+ is equivalent for the following option-based list
+ \code
+ #include <cds/intrusive/iterable_list_hp.h>
+
+ // foo struct and my_compare are the same
+
+ // Declare option-based list
+ typedef cds::intrusive::IterableList< cds::gc::HP, foo,
+ typename cds::intrusive::iterable_list::make_traits<
+ cds::intrusive::opt::compare< my_compare > // item comparator option
+ >::type
+ > option_list_type;
+ \endcode
+
+ \par Usage
+ There are different specializations of this template for each garbage collecting schema.
+ You should select GC you want and include appropriate .h-file:
+ - for \p gc::HP: <tt> <cds/intrusive/iterable_list_hp.h> </tt>
+ - for \p gc::DHP: <tt> <cds/intrusive/iterable_list_dhp.h> </tt>
+ - for \ref cds_urcu_gc "RCU type" - see \ref cds_intrusive_IterableList_rcu "RCU-based IterableList"
+ */
+ template <
+ class GC
+ ,typename T
+#ifdef CDS_DOXYGEN_INVOKED
+ ,class Traits = iterable_list::traits
+#else
+ ,class Traits
+#endif
+ >
+ class IterableList
+ {
+ public:
+ typedef T value_type; ///< type of value stored in the list
+ typedef Traits traits; ///< Traits template parameter
+
+ typedef iterable_list::node< value_type > node_type; ///< node type
+
+# ifdef CDS_DOXYGEN_INVOKED
+ typedef implementation_defined key_comparator ; ///< key comparison functor based on opt::compare and opt::less option setter.
+# else
+ typedef typename opt::details::make_comparator< value_type, traits >::type key_comparator;
+# endif
+
+ typedef typename traits::disposer disposer; ///< disposer for \p value_type
+
+ typedef GC gc; ///< Garbage collector
+ typedef typename traits::back_off back_off; ///< back-off strategy
+ typedef typename traits::item_counter item_counter; ///< Item counting policy used
+ typedef typename traits::memory_model memory_model; ///< Memory ordering. See \p cds::opt::memory_model option
+ typedef typename traits::node_allocator node_allocator; ///< Node allocator
+ typedef typename traits::stat stat; ///< Internal statistics
+
+ typedef typename gc::template guarded_ptr< value_type > guarded_ptr; ///< Guarded pointer
+
+ static CDS_CONSTEXPR const size_t c_nHazardPtrCount = 2; ///< Count of hazard pointer required for the algorithm
+
+ //@cond
+ // Rebind traits (split-list support)
+ template <typename... Options>
+ struct rebind_traits {
+ typedef IterableList<
+ gc
+ , value_type
+ , typename cds::opt::make_options< traits, Options...>::type
+ > type;
+ };
+
+ // Stat selector
+ template <typename Stat>
+ using select_stat_wrapper = iterable_list::select_stat_wrapper< Stat >;
+ //@endcond
+
+ protected:
+ typedef atomics::atomic< node_type* > atomic_node_ptr; ///< Atomic node pointer
+ typedef atomic_node_ptr auxiliary_head; ///< Auxiliary head type (for split-list support)
+
+ atomic_node_ptr m_pHead; ///< Head pointer
+ item_counter m_ItemCounter; ///< Item counter
+ mutable stat m_Stat; ///< Internal statistics
+
+ //@cond
+ typedef cds::details::Allocator< node_type, node_allocator > cxx_node_allocator;
+
+ /// Position pointer for item search
+ struct position {
+ atomic_node_ptr * pHead; ///< Previous node (pointer to pPrev->next or to m_pHead)
+ node_type * pPrev; ///< Previous node
+ node_type * pCur; ///< Current node
+
+ value_type * pFound; ///< Value of \p pCur->data, valid only if data found
+ typename gc::Guard guard; ///< guard for \p pFound
+ };
+ //@endcond
+
+ protected:
+ //@cond
+ template <bool IsConst>
+ class iterator_type
+ {
+ friend class IterableList;
+
+ protected:
+ node_type* m_pNode;
+ typename gc::Guard m_Guard; // data guard
+
+ void next()
+ {
+ while ( m_pNode ) {
+ m_pNode = m_pNode->next.load( memory_model::memory_order_acquire );
+ if ( !m_pNode ) {
+ m_Guard.clear();
+ break;
+ }
+ if ( m_Guard.protect( m_pNode->data ))
+ break;
+ }
+ }
+
+ explicit iterator_type( atomic_node_ptr const& pNode )
+ : m_pNode( pNode.load( memory_model::memory_order_acquire ))
+ {
+ if ( m_pNode ) {
+ if ( !m_Guard.protect( m_pNode->data ))
+ next();
+ }
+ }
+
+ iterator_type( node_type* pNode, value_type* pVal )
+ : m_pNode( pNode )
+ {
+ if ( m_pNode ) {
+ assert( pVal != nullptr );
+ m_Guard.assign( pVal );
+ }
+ }
+
+ public:
+ typedef typename cds::details::make_const_type<value_type, IsConst>::pointer value_ptr;
+ typedef typename cds::details::make_const_type<value_type, IsConst>::reference value_ref;
+
+ iterator_type()
+ : m_pNode( nullptr )
+ {}
+
+ iterator_type( iterator_type const& src )
+ : m_pNode( src.m_pNode )
+ {
+ m_Guard.copy( src.m_Guard );
+ }
+
+ value_ptr operator ->() const
+ {
+ return m_Guard.get<value_type>();
+ }
+
+ value_ref operator *() const
+ {
+ assert( m_Guard.get_native() != nullptr );
+ return *m_Guard.get<value_type>();
+ }
+
+ /// Pre-increment
+ iterator_type& operator ++()
+ {
+ next();
+ return *this;
+ }
+
+ iterator_type& operator = (iterator_type const& src)
+ {
+ m_pNode = src.m_pNode;
+ m_Guard.copy( src.m_Guard );
+ return *this;
+ }
+
+ template <bool C>
+ bool operator ==(iterator_type<C> const& i ) const
+ {
+ return m_pNode == i.m_pNode;
+ }
+ template <bool C>
+ bool operator !=(iterator_type<C> const& i ) const
+ {
+ return !( *this == i );
+ }
+ };
+ //@endcond
+
+ public:
+ ///@name Thread-safe forward iterators
+ //@{
+ /// Forward iterator
+ /**
+ The forward iterator for iterable list has some features:
+ - it has no post-increment operator
+ - to protect the value, the iterator contains a GC-specific guard.
+ For some GC (like as \p gc::HP), a guard is a limited resource per thread, so an exception (or assertion) "no free guard"
+ may be thrown if the limit of guard count per thread is exceeded.
+ - The iterator cannot be moved across thread boundary since it contains thread-private GC's guard.
+ - Iterator is thread-safe: even if the element the iterator points to is removed, the iterator stays valid because
+ it contains the guard keeping the value from to be recycled.
+
+ The iterator interface:
+ \code
+ class iterator {
+ public:
+ // Default constructor
+ iterator();
+
+ // Copy construtor
+ iterator( iterator const& src );
+
+ // Dereference operator
+ value_type * operator ->() const;
+
+ // Dereference operator
+ value_type& operator *() const;
+
+ // Preincrement operator
+ iterator& operator ++();
+
+ // Assignment operator
+ iterator& operator = (iterator const& src);
+
+ // Equality operators
+ bool operator ==(iterator const& i ) const;
+ bool operator !=(iterator const& i ) const;
+ };
+ \endcode
+
+ @note For two iterators pointed to the same element the value can be different;
+ this code
+ \code
+ if ( it1 == it2 )
+ assert( &(*it1) == &(*it2) );
+ \endcode
+ can throw assertion. The point is that the iterator stores the value of element which can be modified later by other thread.
+ The guard inside the iterator prevents recycling that value so the iterator's value remains valid even after such changing.
+ Other iterator can observe modified value of the element.
+ */
+ typedef iterator_type<false> iterator;
+ /// Const forward iterator
+ /**
+ For iterator's features and requirements see \ref iterator
+ */
+ typedef iterator_type<true> const_iterator;
+
+ /// Returns a forward iterator addressing the first element in a list
+ /**
+ For empty list \code begin() == end() \endcode
+ */
+ iterator begin()
+ {
+ return iterator( m_pHead );
+ }
+
+ /// Returns an iterator that addresses the location succeeding the last element in a list
+ /**
+ Do not use the value returned by <tt>end</tt> function to access any item.
+ Internally, <tt>end</tt> returning value equals to \p nullptr.
+
+ The returned value can be used only to control reaching the end of the list.
+ For empty list <tt>begin() == end()</tt>
+ */
+ iterator end()
+ {
+ return iterator();
+ }
+
+ /// Returns a forward const iterator addressing the first element in a list
+ const_iterator cbegin() const
+ {
+ return const_iterator( m_pHead );
+ }
+
+ /// Returns a forward const iterator addressing the first element in a list
+ const_iterator begin() const
+ {
+ return const_iterator( m_pHead );
+ }
+
+ /// Returns an const iterator that addresses the location succeeding the last element in a list
+ const_iterator end() const
+ {
+ return const_iterator();
+ }
+
+ /// Returns an const iterator that addresses the location succeeding the last element in a list
+ const_iterator cend() const
+ {
+ return const_iterator();
+ }
+ //@}
+
+ public:
+ /// Default constructor initializes empty list
+ IterableList()
+ : m_pHead( nullptr )
+ {}
+
+ //@cond
+ template <typename Stat, typename = std::enable_if<std::is_same<stat, iterable_list::wrapped_stat<Stat>>::value >>
+ explicit IterableList( Stat& st )
+ : m_pHead( nullptr )
+ , m_Stat( st )
+ {}
+ //@endcond
+
+ /// Destroys the list object
+ ~IterableList()
+ {
+ destroy();
+ }
+
+ /// Inserts new node
+ /**
+ The function inserts \p val into the list if the list does not contain
+ an item with key equal to \p val.
+
+ Returns \p true if \p val has been linked to the list, \p false otherwise.
+ */
+ bool insert( value_type& val )
+ {
+ return insert_at( m_pHead, val );
+ }
+
+ /// Inserts new node
+ /**
+ This function is intended for derived non-intrusive containers.
+
+ The function allows to split new item creating into two part:
+ - create item with key only
+ - insert new item into the list
+ - if inserting is success, calls \p f functor to initialize value-field of \p val.
+
+ The functor signature is:
+ \code
+ void func( value_type& val );
+ \endcode
+ where \p val is the item inserted. User-defined functor \p f should guarantee that during changing
+ \p val no any other changes could be made on this list's item by concurrent threads.
+ The user-defined functor is called only if the inserting is success.
+
+ @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
+ */
+ template <typename Func>
+ bool insert( value_type& val, Func f )
+ {
+ return insert_at( m_pHead, val, f );
+ }
+
+ /// Updates the node
+ /**
+ The operation performs inserting or changing data with lock-free manner.
+
+ If the item \p val is not found in the list, then \p val is inserted
+ iff \p bInsert is \p true.
+ Otherwise, the current element is changed to \p val, the element will be retired later
+ by call \p Traits::disposer.
+ The functor \p func is called after inserting or replacing, it signature is:
+ \code
+ void func( value_type& val, value_type * old );
+ \endcode
+ where
+ - \p val - argument \p val passed into the \p %update() function
+ - \p old - old value that will be retired. If new item has been inserted then \p old is \p nullptr.
+
+ Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
+ \p second is \p true if \p val has been added or \p false if the item with that key
+ already in the list.
+ */
+ template <typename Func>
+ std::pair<bool, bool> update( value_type& val, Func func, bool bInsert = true )
+ {
+ return update_at( m_pHead, val, func, bInsert );
+ }
+
+ /// Insert or update
+ /**
+ The operation performs inserting or updating data with lock-free manner.
+
+ If the item \p val is not found in the list, then \p val is inserted
+ iff \p bInsert is \p true.
+ Otherwise, the current element is changed to \p val, the old element will be retired later
+ by call \p Traits::disposer.
+
+ Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
+ \p second is \p true if \p val has been added or \p false if the item with that key
+ already in the list.
+ */
+ std::pair<bool, bool> upsert( value_type& val, bool bInsert = true )
+ {
+ return update_at( m_pHead, val, []( value_type&, value_type* ) {}, bInsert );
+ }
+
+ /// Unlinks the item \p val from the list
+ /**
+ The function searches the item \p val in the list and unlinks it from the list
+ if it is found and it is equal to \p val.
+
+ Difference between \p erase() and \p %unlink(): \p %erase() finds <i>a key</i>
+ and deletes the item found. \p %unlink() finds an item by key and deletes it
+ only if \p val is an item of the list, i.e. the pointer to item found
+ is equal to <tt> &val </tt>.
+
+ \p disposer specified in \p Traits is called for deleted item.
+
+ The function returns \p true if success and \p false otherwise.
+ */
+ bool unlink( value_type& val )
+ {
+ return unlink_at( m_pHead, val );
+ }
+
+ /// Deletes the item from the list
+ /** \anchor cds_intrusive_IterableList_hp_erase_val
+ The function searches an item with key equal to \p key in the list,
+ unlinks it from the list, and returns \p true.
+ If \p key is not found the function return \p false.
+
+ \p disposer specified in \p Traits is called for deleted item.
+ */
+ template <typename Q>
+ bool erase( Q const& key )
+ {
+ return erase_at( m_pHead, key, key_comparator());
+ }
+
+ /// Deletes the item from the list using \p pred predicate for searching
+ /**
+ The function is an analog of \ref cds_intrusive_IterableList_hp_erase_val "erase(Q const&)"
+ but \p pred is used for key comparing.
+ \p Less functor has the interface like \p std::less.
+ \p pred must imply the same element order as the comparator used for building the list.
+
+ \p disposer specified in \p Traits is called for deleted item.
+ */
+ template <typename Q, typename Less>
+ bool erase_with( Q const& key, Less pred )
+ {
+ CDS_UNUSED( pred );
+ return erase_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>());
+ }
+
+ /// Deletes the item from the list
+ /** \anchor cds_intrusive_IterableList_hp_erase_func
+ The function searches an item with key equal to \p key in the list,
+ call \p func functor with item found, unlinks it from the list, and returns \p true.
+ The \p Func interface is
+ \code
+ struct functor {
+ void operator()( value_type const& item );
+ };
+ \endcode
+ If \p key is not found the function return \p false, \p func is not called.
+
+ \p disposer specified in \p Traits is called for deleted item.
+ */
+ template <typename Q, typename Func>
+ bool erase( Q const& key, Func func )
+ {
+ return erase_at( m_pHead, key, key_comparator(), func );
+ }
+
+ /// Deletes the item from the list using \p pred predicate for searching
+ /**
+ The function is an analog of \ref cds_intrusive_IterableList_hp_erase_func "erase(Q const&, Func)"
+ but \p pred is used for key comparing.
+ \p Less functor has the interface like \p std::less.
+ \p pred must imply the same element order as the comparator used for building the list.
+
+ \p disposer specified in \p Traits is called for deleted item.
+ */
+ template <typename Q, typename Less, typename Func>
+ bool erase_with( Q const& key, Less pred, Func f )
+ {
+ CDS_UNUSED( pred );
+ return erase_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>(), f );
+ }
+
+ /// Extracts the item from the list with specified \p key
+ /** \anchor cds_intrusive_IterableList_hp_extract
+ The function searches an item with key equal to \p key,
+ unlinks it from the list, and returns it as \p guarded_ptr.
+ If \p key is not found returns an empty guarded pointer.
+
+ Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
+
+ The \ref disposer specified in \p Traits class template parameter is called automatically
+ by garbage collector \p GC when returned \ref guarded_ptr object will be destroyed or released.
+ @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
+
+ Usage:
+ \code
+ typedef cds::intrusive::IterableList< cds::gc::HP, foo, my_traits > ord_list;
+ ord_list theList;
+ // ...
+ {
+ ord_list::guarded_ptr gp(theList.extract( 5 ));
+ if ( gp ) {
+ // Deal with gp
+ // ...
+ }
+ // Destructor of gp releases internal HP guard
+ }
+ \endcode
+ */
+ template <typename Q>
+ guarded_ptr extract( Q const& key )
+ {
+ guarded_ptr gp;
+ extract_at( m_pHead, gp.guard(), key, key_comparator());
+ return gp;
+ }
+
+ /// Extracts the item using compare functor \p pred
+ /**
+ The function is an analog of \ref cds_intrusive_IterableList_hp_extract "extract(Q const&)"
+ but \p pred predicate is used for key comparing.
+
+ \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
+ in any order.
+ \p pred must imply the same element order as the comparator used for building the list.
+ */
+ template <typename Q, typename Less>
+ guarded_ptr extract_with( Q const& key, Less pred )
+ {
+ CDS_UNUSED( pred );
+ guarded_ptr gp;
+ extract_at( m_pHead, gp.guard(), key, cds::opt::details::make_comparator_from_less<Less>());
+ return gp;
+ }
+
+ /// Finds \p key in the list
+ /** \anchor cds_intrusive_IterableList_hp_find_func
+ The function searches the item with key equal to \p key and calls the functor \p f for item found.
+ The interface of \p Func functor is:
+ \code
+ struct functor {
+ void operator()( value_type& item, Q& key );
+ };
+ \endcode
+ where \p item is the item found, \p key is the \p %find() function argument.
+
+ The functor may change non-key fields of \p item. Note that the function is only guarantee
+ that \p item cannot be disposed during functor is executing.
+ The function does not serialize simultaneous access to the \p item. If such access is
+ possible you must provide your own synchronization schema to keep out unsafe item modifications.
+
+ The function returns \p true if \p val is found, \p false otherwise.
+ */
+ template <typename Q, typename Func>
+ bool find( Q& key, Func f ) const
+ {
+ return find_at( m_pHead, key, key_comparator(), f );
+ }
+ //@cond
+ template <typename Q, typename Func>
+ bool find( Q const& key, Func f ) const
+ {
+ return find_at( m_pHead, key, key_comparator(), f );
+ }
+ //@endcond
+
+ /// Finds \p key in the list and returns iterator pointed to the item found
+ /**
+ If \p key is not found the function returns \p end().
+ */
+ template <typename Q>
+ iterator find( Q const& key ) const
+ {
+ return find_iterator_at( m_pHead, key, key_comparator());
+ }
+
+ /// Finds the \p key using \p pred predicate for searching
+ /**
+ The function is an analog of \ref cds_intrusive_IterableList_hp_find_func "find(Q&, Func)"
+ but \p pred is used for key comparing.
+ \p Less functor has the interface like \p std::less.
+ \p pred must imply the same element order as the comparator used for building the list.
+ */
+ template <typename Q, typename Less, typename Func>
+ bool find_with( Q& key, Less pred, Func f ) const
+ {
+ CDS_UNUSED( pred );
+ return find_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>(), f );
+ }
+ //@cond
+ template <typename Q, typename Less, typename Func>
+ bool find_with( Q const& key, Less pred, Func f ) const
+ {
+ CDS_UNUSED( pred );
+ return find_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>(), f );
+ }
+ //@endcond
+
+ /// Finds \p key in the list using \p pred predicate for searching and returns iterator pointed to the item found
+ /**
+ The function is an analog of \p find(Q&) but \p pred is used for key comparing.
+ \p Less functor has the interface like \p std::less.
+ \p pred must imply the same element order as the comparator used for building the list.
+
+ If \p key is not found the function returns \p end().
+ */
+ template <typename Q, typename Less>
+ iterator find_with( Q const& key, Less pred ) const
+ {
+ CDS_UNUSED( pred );
+ return find_iterator_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>());
+ }
+
+ /// Checks whether the list contains \p key
+ /**
+ The function searches the item with key equal to \p key
+ and returns \p true if it is found, and \p false otherwise.
+ */
+ template <typename Q>
+ bool contains( Q const& key ) const
+ {
+ return find_at( m_pHead, key, key_comparator());
+ }
+
+ /// Checks whether the list contains \p key using \p pred predicate for searching
+ /**
+ The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
+ \p Less functor has the interface like \p std::less.
+ \p Less must imply the same element order as the comparator used for building the list.
+ */
+ template <typename Q, typename Less>
+ bool contains( Q const& key, Less pred ) const
+ {
+ CDS_UNUSED( pred );
+ return find_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>());
+ }
+
+ /// Finds the \p key and return the item found
+ /** \anchor cds_intrusive_IterableList_hp_get
+ The function searches the item with key equal to \p key
+ and returns it as \p guarded_ptr.
+ If \p key is not found the function returns an empty guarded pointer.
+
+ The \ref disposer specified in \p Traits class template parameter is called
+ by garbage collector \p GC automatically when returned \ref guarded_ptr object
+ will be destroyed or released.
+ @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
+
+ Usage:
+ \code
+ typedef cds::intrusive::IterableList< cds::gc::HP, foo, my_traits > ord_list;
+ ord_list theList;
+ // ...
+ {
+ ord_list::guarded_ptr gp(theList.get( 5 ));
+ if ( gp ) {
+ // Deal with gp
+ //...
+ }
+ // Destructor of guarded_ptr releases internal HP guard
+ }
+ \endcode
+
+ Note the compare functor specified for \p Traits template parameter
+ should accept a parameter of type \p Q that can be not the same as \p value_type.
+ */
+ template <typename Q>
+ guarded_ptr get( Q const& key ) const
+ {
+ guarded_ptr gp;
+ get_at( m_pHead, gp.guard(), key, key_comparator());
+ return gp;
+ }
+
+ /// Finds the \p key and return the item found
+ /**
+ The function is an analog of \ref cds_intrusive_IterableList_hp_get "get( Q const&)"
+ but \p pred is used for comparing the keys.
+
+ \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
+ in any order.
+ \p pred must imply the same element order as the comparator used for building the list.
+ */
+ template <typename Q, typename Less>
+ guarded_ptr get_with( Q const& key, Less pred ) const
+ {
+ CDS_UNUSED( pred );
+ guarded_ptr gp;
+ get_at( m_pHead, gp.guard(), key, cds::opt::details::make_comparator_from_less<Less>());
+ return gp;
+ }
+
+ /// Clears the list (thread safe, not atomic)
+ void clear()
+ {
+ position pos;
+ for ( pos.pCur = m_pHead.load( memory_model::memory_order_relaxed ); pos.pCur; pos.pCur = pos.pCur->next.load( memory_model::memory_order_relaxed )) {
+ while ( true ) {
+ pos.pFound = pos.guard.protect( pos.pCur->data );
+ if ( !pos.pFound )
+ break;
+ if ( cds_likely( unlink_node( pos ))) {
+ --m_ItemCounter;
+ break;
+ }
+ }
+ }
+ }
+
+ /// Checks if the list is empty
+ /**
+ Emptiness is checked by item counting: if item count is zero then the set is empty.
+ Thus, if you need to use \p %empty() you should provide appropriate (non-empty) \p iterable_list::traits::item_counter
+ feature.
+ */
+ bool empty() const
+ {
+ return size() == 0;
+ }
+
+ /// Returns list's item count
+ /**
+ The value returned depends on item counter provided by \p iterable_list::traits::item_counter. For \p atomicity::empty_item_counter,
+ this function always returns 0.
+ */
+ size_t size() const
+ {
+ return m_ItemCounter.value();
+ }
+
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return m_Stat;
+ }
+
+ protected:
+ //@cond
+#if 0
+ // split-list support
+ bool insert_aux_node( node_type * pNode )
+ {
+ return insert_aux_node( m_pHead, pNode );
+ }
+
+ // split-list support
+ bool insert_aux_node( atomic_node_ptr& refHead, node_type * pNode )
+ {
+ assert( pNode != nullptr );
+
+ // Hack: convert node_type to value_type.
+ // In principle, auxiliary node can be non-reducible to value_type
+ // We assume that comparator can correctly distinguish aux and regular node.
+ return insert_at( refHead, *node_traits::to_value_ptr( pNode ) );
+ }
+#endif
+
+ bool insert_at( atomic_node_ptr& refHead, value_type& val )
+ {
+ position pos;
+
+ while ( true ) {
+ if ( search( refHead, val, pos, key_comparator() )) {
+ m_Stat.onInsertFailed();
+ return false;
+ }
+
+ if ( link_node( &val, pos ) ) {
+ ++m_ItemCounter;
+ m_Stat.onInsertSuccess();
+ return true;
+ }
+
+ m_Stat.onInsertRetry();
+ }
+ }
+
+ template <typename Func>
+ bool insert_at( atomic_node_ptr& refHead, value_type& val, Func f )
+ {
+ position pos;
+
+ typename gc::Guard guard;
+ guard.assign( &val );
+
+ while ( true ) {
+ if ( search( refHead, val, pos, key_comparator() ) ) {
+ m_Stat.onInsertFailed();
+ return false;
+ }
+
+ if ( link_node( &val, pos ) ) {
+ f( val );
+ ++m_ItemCounter;
+ m_Stat.onInsertSuccess();
+ return true;
+ }
+
+ m_Stat.onInsertRetry();
+ }
+ }
+
+ template <typename Func>
+ std::pair<bool, bool> update_at( atomic_node_ptr& refHead, value_type& val, Func func, bool bInsert )
+ {
+ position pos;
+
+ typename gc::Guard guard;
+ guard.assign( &val );
+
+ while ( true ) {
+ if ( search( refHead, val, pos, key_comparator() ) ) {
+ // try to replace pCur->data with val
+ assert( pos.pFound != nullptr );
+ assert( key_comparator()(*pos.pFound, val) == 0 );
+
+ if ( cds_likely( pos.pCur->data.compare_exchange_strong( pos.pFound, &val, memory_model::memory_order_release, atomics::memory_order_relaxed ))) {
+ if ( pos.pFound != &val ) {
+ retire_data( pos.pFound );
+ func( val, pos.pFound );
+ }
+ m_Stat.onUpdateExisting();
+ return std::make_pair( true, false );
+ }
+ }
+ else {
+ if ( !bInsert ) {
+ m_Stat.onUpdateFailed();
+ return std::make_pair( false, false );
+ }
+
+ if ( link_node( &val, pos )) {
+ func( val, static_cast<value_type*>( nullptr ));
+ ++m_ItemCounter;
+ m_Stat.onUpdateNew();
+ return std::make_pair( true, true );
+ }
+ }
+
+ m_Stat.onUpdateRetry();
+ }
+ }
+
+ bool unlink_at( atomic_node_ptr& refHead, value_type& val )
+ {
+ position pos;
+
+ back_off bkoff;
+ while ( search( refHead, val, pos, key_comparator())) {
+ if ( pos.pFound == &val ) {
+ if ( unlink_node( pos )) {
+ --m_ItemCounter;
+ m_Stat.onEraseSuccess();
+ return true;
+ }
+ else
+ bkoff();
+ }
+ else
+ break;
+
+ m_Stat.onEraseRetry();
+ }
+
+ m_Stat.onEraseFailed();
+ return false;
+ }
+
+ template <typename Q, typename Compare, typename Func>
+ bool erase_at( atomic_node_ptr& refHead, const Q& val, Compare cmp, Func f, position& pos )
+ {
+ back_off bkoff;
+ while ( search( refHead, val, pos, cmp )) {
+ if ( unlink_node( pos )) {
+ f( *pos.pFound );
+ --m_ItemCounter;
+ m_Stat.onEraseSuccess();
+ return true;
+ }
+ else
+ bkoff();
+
+ m_Stat.onEraseRetry();
+ }
+
+ m_Stat.onEraseFailed();
+ return false;
+ }
+
+ template <typename Q, typename Compare, typename Func>
+ bool erase_at( atomic_node_ptr& refHead, const Q& val, Compare cmp, Func f )
+ {
+ position pos;
+ return erase_at( refHead, val, cmp, f, pos );
+ }
+
+ template <typename Q, typename Compare>
+ bool erase_at( atomic_node_ptr& refHead, Q const& val, Compare cmp )
+ {
+ position pos;
+ return erase_at( refHead, val, cmp, [](value_type const&){}, pos );
+ }
+
+ template <typename Q, typename Compare>
+ bool extract_at( atomic_node_ptr& refHead, typename guarded_ptr::native_guard& dest, Q const& val, Compare cmp )
+ {
+ position pos;
+ back_off bkoff;
+ while ( search( refHead, val, pos, cmp )) {
+ if ( unlink_node( pos )) {
+ dest.set( pos.pFound );
+ --m_ItemCounter;
+ m_Stat.onEraseSuccess();
+ return true;
+ }
+ else
+ bkoff();
+
+ m_Stat.onEraseRetry();
+ }
+
+ m_Stat.onEraseFailed();
+ return false;
+ }
+
+ template <typename Q, typename Compare>
+ bool find_at( atomic_node_ptr const& refHead, Q const& val, Compare cmp ) const
+ {
+ position pos;
+ if ( search( refHead, val, pos, cmp ) ) {
+ m_Stat.onFindSuccess();
+ return true;
+ }
+
+ m_Stat.onFindFailed();
+ return false;
+ }
+
+ template <typename Q, typename Compare, typename Func>
+ bool find_at( atomic_node_ptr const& refHead, Q& val, Compare cmp, Func f ) const
+ {
+ position pos;
+ if ( search( refHead, val, pos, cmp )) {
+ assert( pos.pFound != nullptr );
+ f( *pos.pFound, val );
+ m_Stat.onFindSuccess();
+ return true;
+ }
+
+ m_Stat.onFindFailed();
+ return false;
+ }
+
+ template <typename Q, typename Compare>
+ iterator find_iterator_at( atomic_node_ptr const& refHead, Q const& val, Compare cmp ) const
+ {
+ position pos;
+ if ( search( refHead, val, pos, cmp )) {
+ assert( pos.pCur != nullptr );
+ assert( pos.pFound != nullptr );
+ m_Stat.onFindSuccess();
+ return iterator( pos.pCur, pos.pFound );
+ }
+
+ m_Stat.onFindFailed();
+ return iterator{};
+ }
+
+ template <typename Q, typename Compare>
+ bool get_at( atomic_node_ptr const& refHead, typename guarded_ptr::native_guard& guard, Q const& val, Compare cmp ) const
+ {
+ position pos;
+ if ( search( refHead, val, pos, cmp )) {
+ guard.set( pos.pFound );
+ m_Stat.onFindSuccess();
+ return true;
+ }
+
+ m_Stat.onFindFailed();
+ return false;
+ }
+ //@endcond
+
+ protected:
+
+ //@cond
+ template <typename Q, typename Compare >
+ bool search( atomic_node_ptr const& refHead, const Q& val, position& pos, Compare cmp ) const
+ {
+ atomic_node_ptr* pHead = const_cast<atomic_node_ptr*>( &refHead );
+ node_type * pPrev = nullptr;
+
+ while ( true ) {
+ node_type * pCur = pHead->load( memory_model::memory_order_relaxed );
+
+ if ( pCur == nullptr ) {
+ // end-of-list
+ pos.pHead = pHead;
+ pos.pPrev = pPrev;
+ pos.pCur = nullptr;
+ pos.pFound = nullptr;
+ return false;
+ }
+
+ value_type * pVal = pos.guard.protect( pCur->data );
+
+ if ( pVal ) {
+ int nCmp = cmp( *pVal, val );
+ if ( nCmp >= 0 ) {
+ pos.pHead = pHead;
+ pos.pPrev = pPrev;
+ pos.pCur = pCur;
+ pos.pFound = pVal;
+ return nCmp == 0;
+ }
+ }
+
+ pPrev = pCur;
+ pHead = &( pCur->next );
+ }
+ }
+ //@endcond
+
+ private:
+ //@cond
+ node_type * alloc_node( value_type * pVal )
+ {
+ m_Stat.onNodeCreated();
+ return cxx_node_allocator().New( pVal );
+ }
+
+ void delete_node( node_type * pNode )
+ {
+ m_Stat.onNodeRemoved();
+ cxx_node_allocator().Delete( pNode );
+ }
+
+ static void retire_data( value_type * pVal )
+ {
+ assert( pVal != nullptr );
+ gc::template retire<disposer>( pVal );
+ }
+
+ void destroy()
+ {
+ node_type * pNode = m_pHead.load( memory_model::memory_order_relaxed );
+ while ( pNode ) {
+ value_type * pVal = pNode->data.load( memory_model::memory_order_relaxed );
+ if ( pVal )
+ retire_data( pVal );
+ node_type * pNext = pNode->next.load( memory_model::memory_order_relaxed );
+ delete_node( pNode );
+ pNode = pNext;
+ }
+ }
+
+ bool link_node( value_type * pVal, position& pos )
+ {
+ if ( pos.pPrev ) {
+ if ( pos.pPrev->data.load( memory_model::memory_order_relaxed ) == nullptr ) {
+ // reuse pPrev
+ value_type * p = nullptr;
+ return pos.pPrev->data.compare_exchange_strong( p, pVal, memory_model::memory_order_release, atomics::memory_order_relaxed );
+ }
+ else {
+ // insert new node between pos.pPrev and pos.pCur
+ node_type * pNode = alloc_node( pVal );
+ pNode->next.store( pos.pCur, memory_model::memory_order_relaxed );
+
+ if ( cds_likely( pos.pPrev->next.compare_exchange_strong( pos.pCur, pNode, memory_model::memory_order_release, atomics::memory_order_relaxed )))
+ return true;
+
+ delete_node( pNode );
+ }
+ }
+ else {
+ node_type * pNode = alloc_node( pVal );
+ pNode->next.store( pos.pCur, memory_model::memory_order_relaxed );
+ if ( cds_likely( pos.pHead->compare_exchange_strong( pos.pCur, pNode, memory_model::memory_order_release, atomics::memory_order_relaxed ) ) )
+ return true;
+
+ delete_node( pNode );
+ }
+ return false;
+ }
+
+ static bool unlink_node( position& pos )
+ {
+ assert( pos.pCur != nullptr );
+ assert( pos.pFound != nullptr );
+
+ if ( pos.pCur->data.compare_exchange_strong( pos.pFound, nullptr, memory_model::memory_order_acquire, atomics::memory_order_relaxed ) ) {
+ retire_data( pos.pFound );
+ return true;
+ }
+ return false;
+ }
+
+ //@endcond
+ };
+}} // namespace cds::intrusive
+
+#endif // #ifndef CDSLIB_INTRUSIVE_IMPL_ITERABLE_LIST_H
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_INTRUSIVE_IMPL_LAZY_LIST_H
- \p T - type to be stored in the list. The type must be based on lazy_list::node (for lazy_list::base_hook)
or it must have a member of type lazy_list::node (for lazy_list::member_hook).
- \p Traits - type traits. See lazy_list::traits for explanation.
- It is possible to declare option-based list with cds::intrusive::lazy_list::make_traits metafunction istead of \p Traits template
+ It is possible to declare option-based list with cds::intrusive::lazy_list::make_traits metafunction instead of \p Traits template
argument. For example, the following traits-based declaration of \p gc::HP lazy list
\code
#include <cds/intrusive/lazy_list_hp.h>
typedef typename get_node_traits< value_type, node_type, hook>::type node_traits; ///< node traits
typedef typename lazy_list::get_link_checker< node_type, traits::link_checker >::type link_checker; ///< link checker
- typedef typename traits::back_off back_off; ///< back-off strategy
+ typedef typename traits::back_off back_off; ///< back-off strategy
typedef typename traits::item_counter item_counter; ///< Item counting policy used
- typedef typename traits::memory_model memory_model; ///< C++ memory ordering (see \p lazy_list::traits::memory_model)
+ typedef typename traits::memory_model memory_model; ///< C++ memory ordering (see \p lazy_list::traits::memory_model)
+ typedef typename traits::stat stat; ///< Internal statistics
+
+ static_assert((std::is_same< gc, typename node_type::gc >::value), "GC and node_type::gc must be the same type");
typedef typename gc::template guarded_ptr< value_type > guarded_ptr; ///< Guarded pointer
, typename cds::opt::make_options< traits, Options...>::type
> type;
};
+
+ // Stat selector
+ template <typename Stat>
+ using select_stat_wrapper = lazy_list::select_stat_wrapper< Stat >;
//@endcond
protected:
node_type m_Tail;
item_counter m_ItemCounter;
+ stat m_Stat; ///< Internal statistics
- //@cond
struct clean_disposer {
void operator()( value_type * p )
{
/// Default constructor initializes empty list
LazyList()
{
- static_assert( (std::is_same< gc, typename node_type::gc >::value), "GC and node_type::gc must be the same type" );
m_Head.m_pNext.store( marked_node_ptr( &m_Tail ), memory_model::memory_order_relaxed );
}
+ //@cond
+ template <typename Stat, typename = std::enable_if<std::is_same<stat, lazy_list::wrapped_stat<Stat>>::value >>
+ explicit LazyList( Stat& st )
+ : m_Stat( st )
+ {
+ m_Head.m_pNext.store( marked_node_ptr( &m_Tail ), memory_model::memory_order_relaxed );
+ }
+ //@endcond
+
/// Destroys the list object
~LazyList()
{
While the functor \p f is working the item \p item is locked,
so \p func has exclusive access to the item.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
\p second is \p true if new item has been added or \p false if the item with \p key
already is in the list.
this function always returns 0.
@note Even if you use real item counter and it returns 0, this fact does not mean that the list
- is empty. To check list emptyness use \p empty() method.
+ is empty. To check list emptiness use \p empty() method.
*/
size_t size() const
{
return m_ItemCounter.value();
}
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return m_Stat;
+ }
+
protected:
//@cond
// split-list support
if ( validate( pos.pPred, pos.pCur )) {
if ( pos.pCur != &m_Tail && cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 ) {
// failed: key already in list
+ m_Stat.onInsertFailed();
return false;
}
else {
link_node( node_traits::to_node_ptr( val ), pos.pPred, pos.pCur );
- ++m_ItemCounter;
- return true;
+ break;
}
}
}
+
+ m_Stat.onInsertRetry();
}
+
+ ++m_ItemCounter;
+ m_Stat.onInsertSuccess();
+ return true;
}
template <typename Func>
if ( validate( pos.pPred, pos.pCur )) {
if ( pos.pCur != &m_Tail && cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 ) {
// failed: key already in list
+ m_Stat.onInsertFailed();
return false;
}
else {
link_node( node_traits::to_node_ptr( val ), pos.pPred, pos.pCur );
f( val );
- ++m_ItemCounter;
- return true;
+ break;
}
}
}
+
+ m_Stat.onInsertRetry();
}
+
+ ++m_ItemCounter;
+ m_Stat.onInsertSuccess();
+ return true;
}
template <typename Func>
// key already in the list
func( false, *node_traits::to_value_ptr( *pos.pCur ) , val );
+ m_Stat.onUpdateExisting();
return std::make_pair( true, false );
}
else {
// new key
- if ( !bAllowInsert )
+ if ( !bAllowInsert ) {
+ m_Stat.onUpdateFailed();
return std::make_pair( false, false );
+ }
link_node( node_traits::to_node_ptr( val ), pos.pPred, pos.pCur );
func( true, val, val );
- ++m_ItemCounter;
- return std::make_pair( true, true );
+ break;
}
}
}
+
+ m_Stat.onUpdateRetry();
}
+
+ ++m_ItemCounter;
+ m_Stat.onUpdateNew();
+ return std::make_pair( true, true );
}
bool unlink_at( node_type * pHead, value_type& val )
{
// item found
unlink_node( pos.pPred, pos.pCur, pHead );
- --m_ItemCounter;
nResult = 1;
}
else
nResult = -1;
}
}
+
if ( nResult ) {
if ( nResult > 0 ) {
+ --m_ItemCounter;
retire_node( pos.pCur );
+ m_Stat.onEraseSuccess();
return true;
}
+
+ m_Stat.onEraseFailed();
return false;
}
}
+
+ m_Stat.onEraseRetry();
}
}
// key found
unlink_node( pos.pPred, pos.pCur, pHead );
f( *node_traits::to_value_ptr( *pos.pCur ));
- --m_ItemCounter;
nResult = 1;
}
else {
}
if ( nResult ) {
if ( nResult > 0 ) {
+ --m_ItemCounter;
retire_node( pos.pCur );
+ m_Stat.onEraseSuccess();
return true;
}
+
+ m_Stat.onEraseFailed();
return false;
}
}
+
+ m_Stat.onEraseRetry();
}
}
&& cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 )
{
f( *node_traits::to_value_ptr( *pos.pCur ), val );
+ m_Stat.onFindSuccess();
return true;
}
}
+
+ m_Stat.onFindFailed();
return false;
}
position pos;
search( pHead, val, pos, cmp );
- return pos.pCur != &m_Tail
- && !pos.pCur->is_marked()
- && cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0;
+ if ( pos.pCur != &m_Tail && !pos.pCur->is_marked() && cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 ) {
+ m_Stat.onFindSuccess();
+ return true;
+ }
+
+ m_Stat.onFindFailed();
+ return false;
}
template <typename Q, typename Compare>
&& cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 )
{
gp.set( pos.guards.template get<value_type>( position::guard_current_item ));
+ m_Stat.onFindSuccess();
return true;
}
+
+ m_Stat.onFindFailed();
return false;
}
pos.pPred = pPrev.ptr();
}
- static bool validate( node_type * pPred, node_type * pCur )
+ bool validate( node_type * pPred, node_type * pCur ) CDS_NOEXCEPT
+ {
+ if ( validate_link( pPred, pCur )) {
+ m_Stat.onValidationSuccess();
+ return true;
+ }
+
+ m_Stat.onValidationFailed();
+ return false;
+ }
+
+ static bool validate_link( node_type * pPred, node_type * pCur ) CDS_NOEXCEPT
{
return !pPred->is_marked()
&& !pCur->is_marked()
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_INTRUSIVE_IMPL_MICHAEL_LIST_H
# endif
typedef typename traits::disposer disposer; ///< disposer used
+ typedef typename traits::stat stat; ///< Internal statistics
typedef typename get_node_traits< value_type, node_type, hook>::type node_traits ; ///< node traits
typedef typename michael_list::get_link_checker< node_type, traits::link_checker >::type link_checker; ///< link checker
, typename cds::opt::make_options< traits, Options...>::type
> type;
};
+
+ // Stat selector
+ template <typename Stat>
+ using select_stat_wrapper = michael_list::select_stat_wrapper< Stat >;
//@endcond
protected:
typedef atomic_node_ptr auxiliary_head; ///< Auxiliary head type (for split-list support)
- atomic_node_ptr m_pHead; ///< Head pointer
- item_counter m_ItemCounter; ///< Item counter
+ atomic_node_ptr m_pHead; ///< Head pointer
+ item_counter m_ItemCounter; ///< Item counter
+ stat m_Stat; ///< Internal statistics
//@cond
/// Position pointer for item search
marked_node_ptr cur(pos.pCur);
pNode->m_pNext.store( cur, memory_model::memory_order_release );
- if ( pos.pPrev->compare_exchange_strong( cur, marked_node_ptr(pNode), memory_model::memory_order_release, atomics::memory_order_relaxed ))
+ if ( cds_likely( pos.pPrev->compare_exchange_strong( cur, marked_node_ptr(pNode), memory_model::memory_order_release, atomics::memory_order_relaxed )))
return true;
pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
// Mark the node (logical deleting)
marked_node_ptr next(pos.pNext, 0);
- if ( pos.pCur->m_pNext.compare_exchange_strong( next, marked_node_ptr(pos.pNext, 1), memory_model::memory_order_release, atomics::memory_order_relaxed )) {
+ if ( cds_likely( pos.pCur->m_pNext.compare_exchange_strong( next, marked_node_ptr(pos.pNext, 1), memory_model::memory_order_release, atomics::memory_order_relaxed ))) {
// physical deletion may be performed by search function if it detects that a node is logically deleted (marked)
// CAS may be successful here or in other thread that searching something
marked_node_ptr cur(pos.pCur);
- if ( pos.pPrev->compare_exchange_strong( cur, marked_node_ptr( pos.pNext ), memory_model::memory_order_acquire, atomics::memory_order_relaxed ))
+ if ( cds_likely( pos.pPrev->compare_exchange_strong( cur, marked_node_ptr( pos.pNext ), memory_model::memory_order_acquire, atomics::memory_order_relaxed )))
retire_node( pos.pCur );
return true;
}
do {
pNext = pCur->m_pNext.load(memory_model::memory_order_relaxed);
g.assign( node_traits::to_value_ptr( pNext.ptr()));
- } while ( pNext != pCur->m_pNext.load(memory_model::memory_order_acquire));
+ } while ( cds_unlikely( pNext != pCur->m_pNext.load(memory_model::memory_order_acquire)));
if ( pNext.ptr())
m_pNode = m_Guard.assign( g.template get<value_type>());
m_pNode = nullptr;
m_Guard.clear();
}
- if ( p == pNode.load(memory_model::memory_order_acquire))
+ if ( cds_likely( p == pNode.load(memory_model::memory_order_acquire)))
break;
}
}
static_assert( (std::is_same< gc, typename node_type::gc >::value), "GC and node_type::gc must be the same type" );
}
+ //@cond
+ template <typename Stat, typename = std::enable_if<std::is_same<stat, michael_list::wrapped_stat<Stat>>::value >>
+ explicit MichaelList( Stat& st )
+ : m_pHead( nullptr )
+ , m_Stat( st )
+ {}
+ //@endcond
+
/// Destroys the list object
~MichaelList()
{
The functor may change non-key fields of the \p item; however, \p func must guarantee
that during changing no any other modifications could be made on this item by concurrent threads.
- Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
- \p second is \p true if new item has been added or \p false if the item with \p key
- already is in the list.
+ Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
+ \p second is \p true if new item has been added or \p false if the item with that key
+ already in the list.
@warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
*/
head = m_pHead.load(memory_model::memory_order_relaxed);
if ( head.ptr())
guard.assign( node_traits::to_value_ptr( *head.ptr()));
- if ( m_pHead.load(memory_model::memory_order_acquire) == head ) {
+ if ( cds_likely( m_pHead.load(memory_model::memory_order_acquire) == head )) {
if ( head.ptr() == nullptr )
break;
value_type& val = *node_traits::to_value_ptr( *head.ptr());
this function always returns 0.
@note Even if you use real item counter and it returns 0, this fact does not mean that the list
- is empty. To check list emptyness use \p empty() method.
+ is empty. To check list emptiness use \p empty() method.
*/
size_t size() const
{
return m_ItemCounter.value();
}
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return m_Stat;
+ }
+
protected:
//@cond
// split-list support
position pos;
while ( true ) {
- if ( search( refHead, val, pos, key_comparator()))
+ if ( search( refHead, val, pos, key_comparator())) {
+ m_Stat.onInsertFailed();
return false;
+ }
if ( link_node( pNode, pos )) {
++m_ItemCounter;
+ m_Stat.onInsertSuccess();
return true;
}
- // clear next field
- pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
+ m_Stat.onInsertRetry();
}
}
position pos;
while ( true ) {
- if ( search( refHead, val, pos, key_comparator()))
+ if ( search( refHead, val, pos, key_comparator())) {
+ m_Stat.onInsertFailed();
return false;
+ }
typename gc::Guard guard;
guard.assign( &val );
if ( link_node( pNode, pos )) {
f( val );
++m_ItemCounter;
+ m_Stat.onInsertSuccess();
return true;
}
- // clear next field
- pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
+ m_Stat.onInsertRetry();
}
}
node_type * pNode = node_traits::to_node_ptr( val );
while ( true ) {
if ( search( refHead, val, pos, key_comparator())) {
- if ( pos.pCur->m_pNext.load(memory_model::memory_order_acquire).bits()) {
+ if ( cds_unlikely( pos.pCur->m_pNext.load(memory_model::memory_order_acquire).bits())) {
back_off()();
+ m_Stat.onUpdateMarked();
continue; // the node found is marked as deleted
}
assert( key_comparator()( val, *node_traits::to_value_ptr( *pos.pCur )) == 0 );
func( false, *node_traits::to_value_ptr( *pos.pCur ) , val );
+ m_Stat.onUpdateExisting();
return std::make_pair( true, false );
}
else {
- if ( !bInsert )
+ if ( !bInsert ) {
+ m_Stat.onUpdateFailed();
return std::make_pair( false, false );
+ }
typename gc::Guard guard;
guard.assign( &val );
if ( link_node( pNode, pos )) {
++m_ItemCounter;
func( true, val, val );
+ m_Stat.onUpdateNew();
return std::make_pair( true, true );
}
- // clear next field
- pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
}
+
+ m_Stat.onUpdateRetry();
}
}
if ( node_traits::to_value_ptr( *pos.pCur ) == &val ) {
if ( unlink_node( pos )) {
--m_ItemCounter;
+ m_Stat.onEraseSuccess();
return true;
}
else
bkoff();
}
- else
+ else {
+ m_Stat.onUpdateFailed();
break;
+ }
+
+ m_Stat.onEraseRetry();
}
+
+ m_Stat.onEraseFailed();
return false;
}
if ( unlink_node( pos )) {
f( *node_traits::to_value_ptr( *pos.pCur ));
--m_ItemCounter;
+ m_Stat.onEraseSuccess();
return true;
}
else
bkoff();
+
+ m_Stat.onEraseRetry();
}
+
+ m_Stat.onEraseFailed();
return false;
}
if ( unlink_node( pos )) {
dest.set( pos.guards.template get<value_type>( position::guard_current_item ));
--m_ItemCounter;
+ m_Stat.onEraseSuccess();
return true;
}
else
bkoff();
+ m_Stat.onEraseRetry();
}
+
+ m_Stat.onEraseFailed();
return false;
}
bool find_at( atomic_node_ptr& refHead, Q const& val, Compare cmp )
{
position pos;
- return search( refHead, val, pos, cmp );
+ if ( search( refHead, val, pos, cmp ) ) {
+ m_Stat.onFindSuccess();
+ return true;
+ }
+
+ m_Stat.onFindFailed();
+ return false;
}
template <typename Q, typename Compare, typename Func>
position pos;
if ( search( refHead, val, pos, cmp )) {
f( *node_traits::to_value_ptr( *pos.pCur ), val );
+ m_Stat.onFindSuccess();
return true;
}
+
+ m_Stat.onFindFailed();
return false;
}
position pos;
if ( search( refHead, val, pos, cmp )) {
guard.set( pos.guards.template get<value_type>( position::guard_current_item ));
+ m_Stat.onFindSuccess();
return true;
}
+
+ m_Stat.onFindFailed();
return false;
}
{
return node_traits::to_value_ptr( p.ptr());
});
- if ( pPrev->load(memory_model::memory_order_acquire).all() != pCur.ptr()) {
+ if ( cds_unlikely( pPrev->load(memory_model::memory_order_acquire).all() != pCur.ptr())) {
bkoff();
goto try_again;
}
if ( pNext.bits() == 1 ) {
// pCur marked i.e. logically deleted. Help the erase/unlink function to unlink pCur node
marked_node_ptr cur( pCur.ptr());
- if ( pPrev->compare_exchange_strong( cur, marked_node_ptr( pNext.ptr()), memory_model::memory_order_acquire, atomics::memory_order_relaxed )) {
+ if ( cds_unlikely( pPrev->compare_exchange_strong( cur, marked_node_ptr( pNext.ptr()), memory_model::memory_order_acquire, atomics::memory_order_relaxed ))) {
retire_node( pCur.ptr());
+ m_Stat.onHelpingSuccess();
}
else {
bkoff();
+ m_Stat.onHelpingFailed();
goto try_again;
}
}
If new item has been inserted (i.e. \p bNew is \p true) then \p item and \p val arguments
refer to the same thing.
- Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+ Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
i.e. the node has been inserted or updated,
\p second is \p true if new item has been added or \p false if the item with \p key
already exists.
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSLIB_INTRUSIVE_ITERABLE_LIST_DHP_H
+#define CDSLIB_INTRUSIVE_ITERABLE_LIST_DHP_H
+
+#include <cds/intrusive/impl/iterable_list.h>
+#include <cds/gc/dhp.h>
+
+#endif // #ifndef CDSLIB_INTRUSIVE_ITERABLE_LIST_DHP_H
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSLIB_INTRUSIVE_ITERABLE_LIST_HP_H
+#define CDSLIB_INTRUSIVE_ITERABLE_LIST_HP_H
+
+#include <cds/gc/hp.h>
+#include <cds/intrusive/impl/iterable_list.h>
+
+#endif // #ifndef CDSLIB_INTRUSIVE_ITERABLE_LIST_HP_H
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_INTRUSIVE_LAZY_LIST_NOGC_H
typedef typename get_node_traits< value_type, node_type, hook>::type node_traits; ///< node traits
typedef typename lazy_list::get_link_checker< node_type, traits::link_checker >::type link_checker; ///< link checker
- typedef typename traits::item_counter item_counter; ///< Item counting policy used
- typedef typename traits::memory_model memory_model; ///< C++ memory ordering (see lazy_list::traits::memory_model)
+ typedef typename traits::item_counter item_counter; ///< Item counting policy used
+ typedef typename traits::memory_model memory_model; ///< C++ memory ordering (see \p lazy_list::traits::memory_model)
+ typedef typename traits::stat stat; ///< Internal statistics
//@cond
+ static_assert((std::is_same< gc, typename node_type::gc >::value), "GC and node_type::gc must be the same type");
+
// Rebind traits (split-list support)
template <typename... Options>
struct rebind_traits {
, typename cds::opt::make_options< traits, Options...>::type
> type;
};
+
+ // Stat selector
+ template <typename Stat>
+ using select_stat_wrapper = lazy_list::select_stat_wrapper< Stat >;
//@endcond
protected:
node_type m_Head; ///< List head (dummy node)
node_type m_Tail; ///< List tail (dummy node)
item_counter m_ItemCounter; ///< Item counter
+ mutable stat m_Stat; ///< Internal statistics
//@cond
/// Default constructor initializes empty list
LazyList()
{
- static_assert( (std::is_same< gc, typename node_type::gc >::value), "GC and node_type::gc must be the same type" );
m_Head.m_pNext.store( &m_Tail, memory_model::memory_order_relaxed );
}
+ //@cond
+ template <typename Stat, typename = std::enable_if<std::is_same<stat, lazy_list::wrapped_stat<Stat>>::value >>
+ explicit LazyList( Stat& st )
+ : m_Stat( st )
+ {
+ m_Head.m_pNext.store( &m_Tail, memory_model::memory_order_relaxed );
+ }
+ //@endcond
+
/// Destroys the list object
~LazyList()
{
The functor may change non-key fields of the \p item.
While the functor \p f is calling the item \p item is locked.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
\p second is \p true if new item has been added or \p false if the item with \p key
already is in the list.
*/
return m_ItemCounter.value();
}
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return m_Stat;
+ }
+
protected:
//@cond
// split-list support
if ( validate( pos.pPred, pos.pCur )) {
if ( pos.pCur != &m_Tail && equal( *node_traits::to_value_ptr( *pos.pCur ), val, pred ) ) {
// failed: key already in list
+ m_Stat.onInsertFailed();
return false;
}
else {
link_node( node_traits::to_node_ptr( val ), pos.pPred, pos.pCur );
- ++m_ItemCounter;
- return true;
+ break;
}
}
}
+
+ m_Stat.onInsertRetry();
}
+
+ ++m_ItemCounter;
+ m_Stat.onInsertSuccess();
+ return true;
}
iterator insert_at_( node_type * pHead, value_type& val )
// key already in the list
func( false, *node_traits::to_value_ptr( *pos.pCur ) , val );
+ m_Stat.onUpdateExisting();
return std::make_pair( iterator( pos.pCur ), false );
}
else {
// new key
- if ( !bAllowInsert )
+ if ( !bAllowInsert ) {
+ m_Stat.onUpdateFailed();
return std::make_pair( end(), false );
+ }
link_node( node_traits::to_node_ptr( val ), pos.pPred, pos.pCur );
func( true, val, val );
- ++m_ItemCounter;
- return std::make_pair( iterator( node_traits::to_node_ptr( val )), true );
+ break;
}
}
+
+ m_Stat.onUpdateRetry();
}
}
+
+ ++m_ItemCounter;
+ m_Stat.onUpdateNew();
+ return std::make_pair( iterator( node_traits::to_node_ptr( val ) ), true );
}
template <typename Func>
if ( equal( *node_traits::to_value_ptr( *pos.pCur ), val, pred ) )
{
f( *node_traits::to_value_ptr( *pos.pCur ), val );
+ m_Stat.onFindSuccess();
return true;
}
}
+
+ m_Stat.onFindFailed();
return false;
}
search( pHead, val, pos, pred );
if ( pos.pCur != &m_Tail ) {
- if ( equal( *node_traits::to_value_ptr( *pos.pCur ), val, pred ))
+ if ( equal( *node_traits::to_value_ptr( *pos.pCur ), val, pred )) {
+ m_Stat.onFindSuccess();
return iterator( pos.pCur );
+ }
}
+
+ m_Stat.onFindFailed();
return end();
}
return cmp(l, r) == 0;
}
- static bool validate( node_type * pPred, node_type * pCur )
+ bool validate( node_type * pPred, node_type * pCur )
{
- return pPred->m_pNext.load(memory_model::memory_order_acquire) == pCur;
+ if ( pPred->m_pNext.load(memory_model::memory_order_acquire) == pCur ) {
+ m_Stat.onValidationSuccess();
+ return true;
+ }
+
+ m_Stat.onValidationFailed();
+ return false;
}
// for split-list
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_INTRUSIVE_LAZY_LIST_RCU_H
#define CDSLIB_INTRUSIVE_LAZY_LIST_RCU_H
-#include <mutex> // unique_lock
+#include <mutex> // unique_lock
#include <cds/intrusive/details/lazy_list_base.h>
#include <cds/urcu/details/check_deadlock.h>
#include <cds/details/binary_functor_wrapper.h>
- \p RCU - one of \ref cds_urcu_gc "RCU type"
- \p T - type to be stored in the list
- \p Traits - type traits. See \p lazy_list::traits for explanation.
-
- It is possible to declare option-based list with \p %cds::intrusive::lazy_list::make_traits metafunction istead of \p Traits template
- argument. Template argument list \p Options of cds::intrusive::lazy_list::make_traits metafunction are:
- - opt::hook - hook used. Possible values are: lazy_list::base_hook, lazy_list::member_hook, lazy_list::traits_hook.
- If the option is not specified, <tt>lazy_list::base_hook<></tt> is used.
- - opt::compare - key comparison functor. No default functor is provided.
- If the option is not specified, the opt::less is used.
- - opt::less - specifies binary predicate used for key comparison. Default is \p std::less<T>.
- - opt::back_off - back-off strategy used. If the option is not specified, the cds::backoff::empty is used.
- - opt::disposer - the functor used for dispose removed items. Default is opt::v::empty_disposer
- - opt::rcu_check_deadlock - a deadlock checking policy. Default is opt::v::rcu_throw_deadlock
- - opt::item_counter - the type of item counting feature. Default is \ref atomicity::empty_item_counter
- - opt::memory_model - C++ memory ordering model. Can be opt::v::relaxed_ordering (relaxed memory model, the default)
- or opt::v::sequential_consistent (sequentially consisnent memory model).
+ It is possible to declare option-based list with \p %cds::intrusive::lazy_list::make_traits metafunction instead of \p Traits template
+ argument.
\par Usage
Before including <tt><cds/intrusive/lazy_list_rcu.h></tt> you should include appropriate RCU header file,
typedef typename get_node_traits< value_type, node_type, hook>::type node_traits; ///< node traits
typedef typename lazy_list::get_link_checker< node_type, traits::link_checker >::type link_checker; ///< link checker
- typedef typename traits::back_off back_off; ///< back-off strategy (not used)
- typedef typename traits::item_counter item_counter; ///< Item counting policy used
- typedef typename traits::memory_model memory_model; ///< C++ memory ordering (see \p lazy_list::traits::memory_model)
- typedef typename traits::rcu_check_deadlock rcu_check_deadlock; ///< Deadlock checking policy
+ typedef typename traits::back_off back_off; ///< back-off strategy (not used)
+ typedef typename traits::item_counter item_counter; ///< Item counting policy used
+ typedef typename traits::memory_model memory_model; ///< C++ memory ordering (see \p lazy_list::traits::memory_model)
+ typedef typename traits::stat stat; ///< Internal statistics
+ typedef typename traits::rcu_check_deadlock rcu_check_deadlock; ///< Deadlock checking policy
typedef typename gc::scoped_lock rcu_lock ; ///< RCU scoped lock
static CDS_CONSTEXPR const bool c_bExtractLockExternal = true; ///< Group of \p extract_xxx functions require external locking
+ static_assert((std::is_same< gc, typename node_type::gc >::value), "GC and node_type::gc must be the same type");
+
//@cond
// Rebind traits (split-list support)
template <typename... Options>
, typename cds::opt::make_options< traits, Options...>::type
> type;
};
- //@endcond
- protected:
- typedef typename node_type::marked_ptr marked_node_ptr; ///< Node marked pointer
- typedef node_type * auxiliary_head; ///< Auxiliary head type (for split-list support)
+ // Stat selector
+ template <typename Stat>
+ using select_stat_wrapper = lazy_list::select_stat_wrapper< Stat >;
+ //@endcond
protected:
node_type m_Head; ///< List head (dummy node)
node_type m_Tail; ///< List tail (dummy node)
item_counter m_ItemCounter; ///< Item counter
+ mutable stat m_Stat; ///< Internal statistics
//@cond
+ typedef typename node_type::marked_ptr marked_node_ptr; ///< Node marked pointer
+ typedef node_type * auxiliary_head; ///< Auxiliary head type (for split-list support)
/// Position pointer for item search
struct position {
typedef std::unique_lock< position > scoped_position_lock;
typedef cds::urcu::details::check_deadlock_policy< gc, rcu_check_deadlock> deadlock_policy;
- //@endcond
-
- protected:
- //@cond
- static void clear_links( node_type * pNode )
- {
- pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
- }
struct clear_and_dispose {
void operator()( value_type * p )
disposer()( p );
}
};
-
- static void dispose_node( node_type * pNode )
- {
- assert( pNode );
- assert( !gc::is_locked());
-
- gc::template retire_ptr<clear_and_dispose>( node_traits::to_value_ptr( *pNode ));
- }
-
- static void link_node( node_type * pNode, node_type * pPred, node_type * pCur )
- {
- assert( pPred->m_pNext.load(memory_model::memory_order_relaxed).ptr() == pCur );
- link_checker::is_empty( pNode );
-
- pNode->m_pNext.store( marked_node_ptr(pCur), memory_model::memory_order_relaxed );
- pPred->m_pNext.store( marked_node_ptr(pNode), memory_model::memory_order_release );
- }
-
- void unlink_node( node_type * pPred, node_type * pCur, node_type * pHead )
- {
- assert( pPred->m_pNext.load(memory_model::memory_order_relaxed).ptr() == pCur );
- assert( pCur != &m_Tail );
-
- node_type * pNext = pCur->m_pNext.load(memory_model::memory_order_relaxed).ptr();
- pCur->m_pNext.store( marked_node_ptr( pHead, 1 ), memory_model::memory_order_relaxed ); // logical deletion + back-link for search
- pPred->m_pNext.store( marked_node_ptr( pNext ), memory_model::memory_order_release); // physically deleting
- }
-
//@endcond
public:
}
//@}
- private:
- //@cond
- const_iterator get_const_begin() const
- {
- const_iterator it( const_cast<node_type *>( &m_Head ));
- ++it ; // skip dummy head
- return it;
- }
- const_iterator get_const_end() const
- {
- return const_iterator( const_cast<node_type *>( &m_Tail ));
- }
- //@endcond
-
public:
/// Default constructor initializes empty list
LazyList()
{
- static_assert( (std::is_same< gc, typename node_type::gc >::value), "GC and node_type::gc must be the same type" );
m_Head.m_pNext.store( marked_node_ptr( &m_Tail ), memory_model::memory_order_relaxed );
}
+ //@cond
+ template <typename Stat, typename = std::enable_if<std::is_same<stat, lazy_list::wrapped_stat<Stat>>::value >>
+ explicit LazyList( Stat& st )
+ : m_Stat( st )
+ {
+ m_Head.m_pNext.store( marked_node_ptr( &m_Tail ), memory_model::memory_order_relaxed );
+ }
+ //@endcond
+
/// Destroys the list object
~LazyList()
{
The functor may change non-key fields of the \p item.
While the functor \p f is calling the item \p item is locked.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
\p second is \p true if new item has been added or \p false if the item with \p key
already is in the list.
this function always returns 0.
<b>Warning</b>: even if you use real item counter and it returns 0, this fact is not mean that the list
- is empty. To check list emptyness use \ref empty() method.
+ is empty. To check list emptiness use \ref empty() method.
*/
size_t size() const
{
return m_ItemCounter.value();
}
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return m_Stat;
+ }
+
protected:
//@cond
+ static void clear_links( node_type * pNode )
+ {
+ pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
+ }
+
+ static void dispose_node( node_type * pNode )
+ {
+ assert( pNode );
+ assert( !gc::is_locked() );
+
+ gc::template retire_ptr<clear_and_dispose>( node_traits::to_value_ptr( *pNode ) );
+ }
+
+ static void link_node( node_type * pNode, node_type * pPred, node_type * pCur )
+ {
+ assert( pPred->m_pNext.load( memory_model::memory_order_relaxed ).ptr() == pCur );
+ link_checker::is_empty( pNode );
+
+ pNode->m_pNext.store( marked_node_ptr( pCur ), memory_model::memory_order_relaxed );
+ pPred->m_pNext.store( marked_node_ptr( pNode ), memory_model::memory_order_release );
+ }
+
+ void unlink_node( node_type * pPred, node_type * pCur, node_type * pHead )
+ {
+ assert( pPred->m_pNext.load( memory_model::memory_order_relaxed ).ptr() == pCur );
+ assert( pCur != &m_Tail );
+
+ node_type * pNext = pCur->m_pNext.load( memory_model::memory_order_relaxed ).ptr();
+ pCur->m_pNext.store( marked_node_ptr( pHead, 1 ), memory_model::memory_order_relaxed ); // logical deletion + back-link for search
+ pPred->m_pNext.store( marked_node_ptr( pNext ), memory_model::memory_order_release ); // physically deleting
+ }
+
// split-list support
bool insert_aux_node( node_type * pNode )
{
if ( validate( pos.pPred, pos.pCur )) {
if ( pos.pCur != &m_Tail && cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 ) {
// failed: key already in list
+ m_Stat.onInsertFailed();
return false;
}
f( val );
link_node( node_traits::to_node_ptr( val ), pos.pPred, pos.pCur );
- ++m_ItemCounter;
- return true;
+ break;
}
}
+
+ m_Stat.onInsertRetry();
}
+
+ ++m_ItemCounter;
+ m_Stat.onInsertSuccess();
+ return true;
}
iterator insert_at_( node_type * pHead, value_type& val )
{
// item found
unlink_node( pos.pPred, pos.pCur, pHead );
- --m_ItemCounter;
nResult = 1;
}
else
if ( nResult ) {
if ( nResult > 0 ) {
+ --m_ItemCounter;
dispose_node( pos.pCur );
+ m_Stat.onEraseSuccess();
return true;
}
+
+ m_Stat.onEraseFailed();
return false;
}
+
+ m_Stat.onEraseRetry();
}
}
// key found
unlink_node( pos.pPred, pos.pCur, pHead );
f( *node_traits::to_value_ptr( *pos.pCur ));
- --m_ItemCounter;
nResult = 1;
}
else
if ( nResult ) {
if ( nResult > 0 ) {
+ --m_ItemCounter;
dispose_node( pos.pCur );
+ m_Stat.onEraseSuccess();
return true;
}
+
+ m_Stat.onEraseFailed();
return false;
}
+
+ m_Stat.onEraseRetry();
}
}
if ( pos.pCur != &m_Tail && cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 ) {
// key found
unlink_node( pos.pPred, pos.pCur, pHead );
- --m_ItemCounter;
nResult = 1;
}
else {
}
if ( nResult ) {
- if ( nResult > 0 )
+ if ( nResult > 0 ) {
+ --m_ItemCounter;
+ m_Stat.onEraseSuccess();
return node_traits::to_value_ptr( pos.pCur );
+ }
+
+ m_Stat.onEraseFailed();
return nullptr;
}
+
+ m_Stat.onEraseRetry();
}
}
search( pHead, val, pos, cmp );
if ( pos.pCur != &m_Tail ) {
std::unique_lock< typename node_type::lock_type> al( pos.pCur->m_Lock );
- if ( cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 )
- {
+ if ( cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 ) {
f( *node_traits::to_value_ptr( *pos.pCur ), val );
+ m_Stat.onFindSuccess();
return true;
}
}
+
+ m_Stat.onFindFailed();
return false;
}
search( pHead, val, pos, cmp );
if ( pos.pCur != &m_Tail ) {
- if ( cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 )
+ if ( cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 ) {
+ m_Stat.onFindSuccess();
return const_iterator( pos.pCur );
+ }
}
+
+ m_Stat.onFindFailed();
return end();
}
pos.pPred = pPrev.ptr();
}
- static bool validate( node_type * pPred, node_type * pCur ) CDS_NOEXCEPT
+ bool validate( node_type * pPred, node_type * pCur ) CDS_NOEXCEPT
+ {
+ if ( validate_link( pPred, pCur ) ) {
+ m_Stat.onValidationSuccess();
+ return true;
+ }
+
+ m_Stat.onValidationFailed();
+ return false;
+ }
+
+ static bool validate_link( node_type * pPred, node_type * pCur ) CDS_NOEXCEPT
{
// RCU lock should be locked
assert( gc::is_locked());
if ( validate( pos.pPred, pos.pCur )) {
if ( pos.pCur != &m_Tail && cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 ) {
// failed: key already in list
+ m_Stat.onInsertFailed();
return false;
}
link_node( node_traits::to_node_ptr( val ), pos.pPred, pos.pCur );
- ++m_ItemCounter;
- return true;
+ break;
}
}
+
+ m_Stat.onInsertRetry();
}
+
+ ++m_ItemCounter;
+ m_Stat.onInsertSuccess();
+ return true;
+
}
template <typename Func>
// key already in the list
func( false, *node_traits::to_value_ptr( *pos.pCur ), val );
+ m_Stat.onUpdateExisting();
return std::make_pair( iterator( pos.pCur ), false );
}
else {
// new key
- if ( !bAllowInsert )
+ if ( !bAllowInsert ) {
+ m_Stat.onUpdateFailed();
return std::make_pair( end(), false );
+ }
func( true, val, val );
link_node( node_traits::to_node_ptr( val ), pos.pPred, pos.pCur );
- ++m_ItemCounter;
- return std::make_pair( iterator( node_traits::to_node_ptr( val )), true );
+ break;
}
}
}
+
+ m_Stat.onUpdateRetry();
}
+
+ ++m_ItemCounter;
+ m_Stat.onUpdateNew();
+ return std::make_pair( iterator( node_traits::to_node_ptr( val )), true );
+ }
+ //@endcond
+
+ private:
+ //@cond
+ const_iterator get_const_begin() const
+ {
+ const_iterator it( const_cast<node_type *>(&m_Head) );
+ ++it; // skip dummy head
+ return it;
+ }
+ const_iterator get_const_end() const
+ {
+ return const_iterator( const_cast<node_type *>(&m_Tail) );
}
//@endcond
};
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_INTRUSIVE_MICHAEL_LIST_NOGC_H
#include <cds/gc/nogc.h>
#include <cds/details/make_const_type.h>
-
namespace cds { namespace intrusive {
namespace michael_list {
typedef typename get_node_traits< value_type, node_type, hook>::type node_traits ; ///< node traits
typedef typename michael_list::get_link_checker< node_type, traits::link_checker >::type link_checker; ///< link checker
- typedef typename traits::back_off back_off; ///< back-off strategy
- typedef typename traits::item_counter item_counter; ///< Item counting policy used
- typedef typename traits::memory_model memory_model; ///< Memory ordering. See cds::opt::memory_model option
+ typedef typename traits::back_off back_off; ///< back-off strategy
+ typedef typename traits::item_counter item_counter; ///< Item counting policy used
+ typedef typename traits::memory_model memory_model; ///< Memory ordering. See cds::opt::memory_model option
+ typedef typename traits::stat stat; ///< Internal statistics
//@cond
+ static_assert((std::is_same< gc, typename node_type::gc >::value), "GC and node_type::gc must be the same type");
+
// Rebind traits (split-list support)
template <typename... Options>
struct rebind_traits {
, typename cds::opt::make_options< traits, Options...>::type
> type;
};
+
+ // Stat selector
+ template <typename Stat>
+ using select_stat_wrapper = michael_list::select_stat_wrapper< Stat >;
//@endcond
protected:
atomic_node_ptr m_pHead; ///< Head pointer
item_counter m_ItemCounter; ///< Item counter
+ stat m_Stat; ///< Internal statistics
//@cond
/// Position pointer for item search
link_checker::is_empty( pNode );
pNode->m_pNext.store( pos.pCur, memory_model::memory_order_relaxed );
- if ( pos.pPrev->compare_exchange_strong( pos.pCur, pNode, memory_model::memory_order_release, atomics::memory_order_relaxed ))
+ if ( cds_likely( pos.pPrev->compare_exchange_strong( pos.pCur, pNode, memory_model::memory_order_release, atomics::memory_order_relaxed )))
return true;
pNode->m_pNext.store( nullptr, memory_model::memory_order_relaxed );
/// Default constructor initializes empty list
MichaelList()
: m_pHead( nullptr )
- {
- static_assert( (std::is_same< gc, typename node_type::gc >::value), "GC and node_type::gc must be the same type" );
- }
+ {}
+
+ //@cond
+ template <typename Stat, typename = std::enable_if<std::is_same<stat, michael_list::wrapped_stat<Stat>>::value >>
+ explicit MichaelList( Stat& st )
+ : m_pHead( nullptr )
+ , m_Stat( st )
+ {}
+ //@endcond
/// Destroys the list objects
~MichaelList()
The functor may change non-key fields of the \p item; however, \p func must guarantee
that during changing no any other modifications could be made on this item by concurrent threads.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
\p second is \p true if new item has been added or \p false if the item with \p key
already is in the list.
*/
void clear( Disposer disp )
{
node_type * pHead = m_pHead.load(memory_model::memory_order_relaxed);
- do {} while ( !m_pHead.compare_exchange_weak( pHead, nullptr, memory_model::memory_order_relaxed ) );
+ do {} while ( cds_unlikely( !m_pHead.compare_exchange_weak( pHead, nullptr, memory_model::memory_order_relaxed )));
while ( pHead ) {
node_type * p = pHead->m_pNext.load(memory_model::memory_order_relaxed);
return m_ItemCounter.value();
}
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return m_Stat;
+ }
+
protected:
//@cond
// split-list support
position pos;
while ( true ) {
- if ( search( refHead, val, key_comparator(), pos ) )
+ if ( search( refHead, val, key_comparator(), pos )) {
+ m_Stat.onInsertFailed();
return false;
+ }
if ( link_node( node_traits::to_node_ptr( val ), pos ) ) {
++m_ItemCounter;
+ m_Stat.onInsertSuccess();
return true;
}
+
+ m_Stat.onInsertRetry();
}
}
assert( key_comparator()( val, *node_traits::to_value_ptr( *pos.pCur ) ) == 0 );
func( false, *node_traits::to_value_ptr( *pos.pCur ) , val );
+ m_Stat.onUpdateExisting();
return std::make_pair( iterator( pos.pCur ), false );
}
else {
- if ( !bAllowInsert )
+ if ( !bAllowInsert ) {
+ m_Stat.onUpdateFailed();
return std::make_pair( end(), false );
+ }
if ( link_node( node_traits::to_node_ptr( val ), pos ) ) {
++m_ItemCounter;
func( true, val , val );
+ m_Stat.onUpdateNew();
return std::make_pair( iterator( node_traits::to_node_ptr( val )), true );
}
}
+
+ m_Stat.onUpdateRetry();
}
}
if ( search( refHead, val, cmp, pos ) ) {
assert( pos.pCur != nullptr );
f( *node_traits::to_value_ptr( *pos.pCur ), val );
+ m_Stat.onFindSuccess();
return true;
}
+
+ m_Stat.onFindFailed();
return false;
}
value_type * find_at( atomic_node_ptr& refHead, Q const& val, Compare cmp )
{
iterator it = find_at_( refHead, val, cmp );
- if ( it != end() )
+ if ( it != end() ) {
+ m_Stat.onFindSuccess();
return &*it;
+ }
+
+ m_Stat.onFindFailed();
return nullptr;
}
if ( search( refHead, val, cmp, pos ) ) {
assert( pos.pCur != nullptr );
+ m_Stat.onFindSuccess();
return iterator( pos.pCur );
}
+
+ m_Stat.onFindFailed();
return end();
}
}
pNext = pCur->m_pNext.load(memory_model::memory_order_relaxed);
- if ( pCur->m_pNext.load(memory_model::memory_order_acquire) != pNext ) {
+ if ( cds_unlikely( pCur->m_pNext.load(memory_model::memory_order_acquire) != pNext )) {
bkoff();
goto try_again;
}
- if ( pPrev->load(memory_model::memory_order_acquire) != pCur ) {
+ if ( cds_unlikely( pPrev->load(memory_model::memory_order_acquire) != pCur )) {
bkoff();
goto try_again;
}
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_INTRUSIVE_MICHAEL_LIST_RCU_H
typedef typename get_node_traits< value_type, node_type, hook>::type node_traits ; ///< node traits
typedef typename michael_list::get_link_checker< node_type, traits::link_checker >::type link_checker; ///< link checker
- typedef cds::urcu::gc<RCU> gc; ///< RCU schema
- typedef typename traits::back_off back_off; ///< back-off strategy
- typedef typename traits::item_counter item_counter; ///< Item counting policy used
- typedef typename traits::memory_model memory_model; ///< Memory ordering. See cds::opt::memory_model option
- typedef typename traits::rcu_check_deadlock rcu_check_deadlock; ///< Deadlock checking policy
+ typedef cds::urcu::gc<RCU> gc; ///< RCU schema
+ typedef typename traits::back_off back_off; ///< back-off strategy
+ typedef typename traits::item_counter item_counter; ///< Item counting policy used
+ typedef typename traits::memory_model memory_model; ///< Memory ordering. See cds::opt::memory_model option
+ typedef typename traits::rcu_check_deadlock rcu_check_deadlock; ///< Deadlock checking policy
+ typedef typename traits::stat stat; ///< Internal statistics
typedef typename gc::scoped_lock rcu_lock ; ///< RCU scoped lock
static CDS_CONSTEXPR const bool c_bExtractLockExternal = false; ///< Group of \p extract_xxx functions do not require external locking
, typename cds::opt::make_options< traits, Options...>::type
> type;
};
+
+ // Stat selector
+ template <typename Stat>
+ using select_stat_wrapper = michael_list::select_stat_wrapper< Stat >;
//@endcond
protected:
- typedef typename node_type::marked_ptr marked_node_ptr ; ///< Marked node pointer
- typedef typename node_type::atomic_marked_ptr atomic_node_ptr ; ///< Atomic node pointer
- typedef atomic_node_ptr auxiliary_head ; ///< Auxiliary head type (for split-list support)
+ typedef typename node_type::marked_ptr marked_node_ptr; ///< Marked node pointer
+ typedef typename node_type::atomic_marked_ptr atomic_node_ptr; ///< Atomic node pointer
+ typedef atomic_node_ptr auxiliary_head; ///< Auxiliary head type (for split-list support)
- atomic_node_ptr m_pHead ; ///< Head pointer
- item_counter m_ItemCounter ; ///< Item counter
+ atomic_node_ptr m_pHead; ///< Head pointer
+ item_counter m_ItemCounter; ///< Item counter
+ stat m_Stat; ///< Internal statistics
protected:
//@cond
typedef cds::urcu::details::check_deadlock_policy< gc, rcu_check_deadlock> check_deadlock_policy;
- static void clear_links( node_type * pNode )
- {
- pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_release );
- pNode->m_pDelChain = nullptr;
- }
-
struct clear_and_dispose {
void operator()( value_type * p )
{
}
};
- static void dispose_node( node_type * pNode )
- {
- assert( pNode );
- assert( !gc::is_locked() );
-
- gc::template retire_ptr<clear_and_dispose>( node_traits::to_value_ptr( *pNode ) );
- }
-
- static void dispose_chain( node_type * pChain )
- {
- if ( pChain ) {
- assert( !gc::is_locked() );
-
- auto f = [&pChain]() -> cds::urcu::retired_ptr {
- node_type * p = pChain;
- if ( p ) {
- pChain = p->m_pDelChain;
- return cds::urcu::make_retired_ptr<clear_and_dispose>( node_traits::to_value_ptr( p ));
- }
- return cds::urcu::make_retired_ptr<clear_and_dispose>( static_cast<value_type *>(nullptr));
- };
- gc::batch_retire(std::ref(f));
- }
- }
-
/// Position pointer for item search
struct position {
atomic_node_ptr * pPrev ; ///< Previous node
dispose_chain( pDelChain );
}
};
-
//@endcond
public:
/// Result of \p get(), \p get_with() functions - pointer to the node found
typedef cds::urcu::raw_ptr< gc, value_type, raw_ptr_disposer > raw_ptr;
- protected:
- //@cond
-
- bool link_node( node_type * pNode, position& pos )
- {
- assert( pNode != nullptr );
- link_checker::is_empty( pNode );
-
- marked_node_ptr p( pos.pCur );
- pNode->m_pNext.store( p, memory_model::memory_order_release );
- if ( pos.pPrev->compare_exchange_strong( p, marked_node_ptr(pNode), memory_model::memory_order_release, atomics::memory_order_relaxed ))
- return true;
-
- pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
- return false;
- }
-
- static void link_to_remove_chain( position& pos, node_type * pDel )
- {
- assert( pDel->m_pDelChain == nullptr );
-
- pDel->m_pDelChain = pos.pDelChain;
- pos.pDelChain = pDel;
- }
-
- bool unlink_node( position& pos, erase_node_mask nMask )
- {
- assert(gc::is_locked() );
-
- // Mark the node (logical deletion)
- marked_node_ptr next(pos.pNext, 0);
-
- if ( pos.pCur->m_pNext.compare_exchange_strong( next, next | nMask, memory_model::memory_order_release, atomics::memory_order_relaxed )) {
-
- // Try physical removal - fast path
- marked_node_ptr cur(pos.pCur);
- if ( pos.pPrev->compare_exchange_strong(cur, marked_node_ptr(pos.pNext), memory_model::memory_order_acquire, atomics::memory_order_relaxed )) {
- if ( nMask == erase_mask )
- link_to_remove_chain( pos, pos.pCur );
- }
- else {
- // Slow path
- search( pos.refHead, *node_traits::to_value_ptr( pos.pCur ), pos, key_comparator() );
- }
- return true;
- }
- return false;
- }
- //@endcond
-
protected:
//@cond
template <bool IsConst>
static_assert( (std::is_same< gc, typename node_type::gc >::value), "GC and node_type::gc must be the same type" );
}
+ //@cond
+ template <typename Stat, typename = std::enable_if<std::is_same<stat, michael_list::wrapped_stat<Stat>>::value >>
+ explicit MichaelList( Stat& st )
+ : m_pHead( nullptr )
+ , m_Stat( st )
+ {}
+ //@endcond
+
/// Destroy list
~MichaelList()
{
The functor may change non-key fields of the \p item; however, \p func must guarantee
that during changing no any other modifications could be made on this item by concurrent threads.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
\p second is \p true if new item has been added or \p false if the item with \p key
already is in the list.
RCU \p synchronize method can be called.
Note that depending on RCU type used the \ref disposer invocation can be deferred.
- The function can throw \p cds::urcu::rcu_deadlock exception if an deadlock is encountered and
+ The function can throw \p cds::urcu::rcu_deadlock exception if a deadlock is encountered and
deadlock checking policy is \p opt::v::rcu_throw_deadlock.
*/
void clear()
if ( !pHead.ptr() )
break;
marked_node_ptr pNext( pHead->m_pNext.load(memory_model::memory_order_relaxed) );
- if ( !pHead->m_pNext.compare_exchange_weak( pNext, pNext | 1, memory_model::memory_order_acquire, memory_model::memory_order_relaxed ))
+ if ( cds_unlikely( !pHead->m_pNext.compare_exchange_weak( pNext, pNext | 1, memory_model::memory_order_acquire, memory_model::memory_order_relaxed )))
continue;
- if ( !m_pHead.compare_exchange_weak( pHead, marked_node_ptr(pNext.ptr()), memory_model::memory_order_release, memory_model::memory_order_relaxed ))
+ if ( cds_unlikely( !m_pHead.compare_exchange_weak( pHead, marked_node_ptr(pNext.ptr()), memory_model::memory_order_release, memory_model::memory_order_relaxed )))
continue;
}
return m_ItemCounter.value();
}
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return m_Stat;
+ }
+
protected:
//@cond
+ static void clear_links( node_type * pNode )
+ {
+ pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_release );
+ pNode->m_pDelChain = nullptr;
+ }
+
+ static void dispose_node( node_type * pNode )
+ {
+ assert( pNode );
+ assert( !gc::is_locked() );
+
+ gc::template retire_ptr<clear_and_dispose>( node_traits::to_value_ptr( *pNode ) );
+ }
+
+ static void dispose_chain( node_type * pChain )
+ {
+ if ( pChain ) {
+ assert( !gc::is_locked() );
+
+ auto f = [&pChain]() -> cds::urcu::retired_ptr {
+ node_type * p = pChain;
+ if ( p ) {
+ pChain = p->m_pDelChain;
+ return cds::urcu::make_retired_ptr<clear_and_dispose>( node_traits::to_value_ptr( p ) );
+ }
+ return cds::urcu::make_retired_ptr<clear_and_dispose>( static_cast<value_type *>(nullptr) );
+ };
+ gc::batch_retire( std::ref( f ) );
+ }
+ }
+
+ bool link_node( node_type * pNode, position& pos )
+ {
+ assert( pNode != nullptr );
+ link_checker::is_empty( pNode );
+
+ marked_node_ptr p( pos.pCur );
+ pNode->m_pNext.store( p, memory_model::memory_order_release );
+ if ( cds_likely( pos.pPrev->compare_exchange_strong( p, marked_node_ptr( pNode ), memory_model::memory_order_release, atomics::memory_order_relaxed ) ) )
+ return true;
+
+ pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
+ return false;
+ }
+
+ static void link_to_remove_chain( position& pos, node_type * pDel )
+ {
+ assert( pDel->m_pDelChain == nullptr );
+
+ pDel->m_pDelChain = pos.pDelChain;
+ pos.pDelChain = pDel;
+ }
+
+ bool unlink_node( position& pos, erase_node_mask nMask )
+ {
+ assert( gc::is_locked() );
+
+ // Mark the node (logical deletion)
+ marked_node_ptr next( pos.pNext, 0 );
+
+ if ( cds_likely( pos.pCur->m_pNext.compare_exchange_strong( next, next | nMask, memory_model::memory_order_release, atomics::memory_order_relaxed ) ) ) {
+
+ // Try physical removal - fast path
+ marked_node_ptr cur( pos.pCur );
+ if ( cds_likely( pos.pPrev->compare_exchange_strong( cur, marked_node_ptr( pos.pNext ), memory_model::memory_order_acquire, atomics::memory_order_relaxed ) ) ) {
+ if ( nMask == erase_mask )
+ link_to_remove_chain( pos, pos.pCur );
+ }
+ else {
+ // Slow path
+ search( pos.refHead, *node_traits::to_value_ptr( pos.pCur ), pos, key_comparator() );
+ }
+ return true;
+ }
+ return false;
+ }
+
// split-list support
bool insert_aux_node( node_type * pNode )
{
{
rcu_lock l;
while ( true ) {
- if ( search( refHead, val, pos, key_comparator()))
+ if ( search( refHead, val, pos, key_comparator())) {
+ m_Stat.onInsertFailed();
return false;
+ }
if ( link_node( node_traits::to_node_ptr( val ), pos ) ) {
f( val );
++m_ItemCounter;
+ m_Stat.onInsertSuccess();
return true;
}
// clear next field
node_traits::to_node_ptr( val )->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
+ m_Stat.onInsertRetry();
}
}
for (;;) {
{
rcu_lock l;
- if ( !search( refHead, val, pos, key_comparator() ) || node_traits::to_value_ptr( *pos.pCur ) != &val )
+ if ( !search( refHead, val, pos, key_comparator() ) || node_traits::to_value_ptr( *pos.pCur ) != &val ) {
+ m_Stat.onEraseFailed();
return false;
+ }
if ( !unlink_node( pos, erase_mask )) {
bkoff();
+ m_Stat.onEraseRetry();
continue;
}
}
--m_ItemCounter;
+ m_Stat.onEraseSuccess();
return true;
}
}
for (;;) {
{
rcu_lock l;
- if ( !search( pos.refHead, val, pos, cmp ) )
+ if ( !search( pos.refHead, val, pos, cmp ) ) {
+ m_Stat.onEraseFailed();
return false;
+ }
+
// store pCur since it may be changed by unlink_node() slow path
pDel = pos.pCur;
if ( !unlink_node( pos, erase_mask )) {
bkoff();
+ m_Stat.onEraseRetry();
continue;
}
}
assert( pDel );
f( *node_traits::to_value_ptr( pDel ) );
--m_ItemCounter;
+ m_Stat.onEraseSuccess();
return true;
}
}
{
rcu_lock l;
for (;;) {
- if ( !search( refHead, val, pos, cmp ) )
+ if ( !search( refHead, val, pos, cmp )) {
+ m_Stat.onEraseFailed();
return nullptr;
+ }
+
// store pCur since it may be changed by unlink_node() slow path
pExtracted = pos.pCur;
if ( !unlink_node( pos, extract_mask )) {
bkoff();
+ m_Stat.onEraseRetry();
continue;
}
--m_ItemCounter;
value_type * pRet = node_traits::to_value_ptr( pExtracted );
assert( pExtracted->m_pDelChain == nullptr );
+ m_Stat.onEraseSuccess();
return pRet;
}
}
if ( search( refHead, val, pos, cmp ) ) {
assert( pos.pCur != nullptr );
f( *node_traits::to_value_ptr( *pos.pCur ), val );
+ m_Stat.onFindSuccess();
return true;
}
- return false;
- }
+ }
+
+ m_Stat.onFindFailed();
+ return false;
}
template <typename Q, typename Compare>
position pos( refHead );
- if ( search( refHead, val, pos, cmp ))
+ if ( search( refHead, val, pos, cmp )) {
+ m_Stat.onFindSuccess();
return raw_ptr( node_traits::to_value_ptr( pos.pCur ), raw_ptr_disposer( pos ));
+ }
+
+ m_Stat.onFindFailed();
return raw_ptr( raw_ptr_disposer( pos ));
}
//@endcond
pNext = pCur->m_pNext.load(memory_model::memory_order_acquire);
- if ( pPrev->load(memory_model::memory_order_acquire) != pCur
- || pNext != pCur->m_pNext.load(memory_model::memory_order_acquire))
+ if ( cds_unlikely( pPrev->load(memory_model::memory_order_acquire) != pCur
+ || pNext != pCur->m_pNext.load(memory_model::memory_order_acquire )))
{
bkoff();
goto try_again;
if ( pNext.bits() ) {
// pCur is marked as deleted. Try to unlink it from the list
- if ( pPrev->compare_exchange_weak( pCur, marked_node_ptr( pNext.ptr() ), memory_model::memory_order_acquire, atomics::memory_order_relaxed ) ) {
+ if ( cds_likely( pPrev->compare_exchange_weak( pCur, marked_node_ptr( pNext.ptr() ), memory_model::memory_order_acquire, atomics::memory_order_relaxed ))) {
if ( pNext.bits() == erase_mask )
link_to_remove_chain( pos, pCur.ptr() );
+ m_Stat.onHelpingSuccess();
}
+ m_Stat.onHelpingFailed();
goto try_again;
}
assert( gc::is_locked() );
while ( true ) {
- if ( search( pos.refHead, val, pos, key_comparator() ) )
+ if ( search( pos.refHead, val, pos, key_comparator() )) {
+ m_Stat.onInsertFailed();
return false;
+ }
if ( link_node( node_traits::to_node_ptr( val ), pos ) ) {
++m_ItemCounter;
+ m_Stat.onInsertSuccess();
return true;
}
// clear next field
node_traits::to_node_ptr( val )->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
+ m_Stat.onInsertRetry();
}
}
assert( key_comparator()( val, *node_traits::to_value_ptr( *pos.pCur ) ) == 0 );
func( false, *node_traits::to_value_ptr( *pos.pCur ), val );
+ m_Stat.onUpdateExisting();
return std::make_pair( iterator( pos.pCur ), false );
}
else {
- if ( !bInsert )
+ if ( !bInsert ) {
+ m_Stat.onUpdateFailed();
return std::make_pair( end(), false );
+ }
if ( link_node( node_traits::to_node_ptr( val ), pos ) ) {
++m_ItemCounter;
func( true, val , val );
+ m_Stat.onUpdateNew();
return std::make_pair( iterator( node_traits::to_node_ptr( val )), true );
}
// clear the next field
node_traits::to_node_ptr( val )->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
+ m_Stat.onUpdateRetry();
}
}
}
if ( search( pos.refHead, val, pos, cmp ) ) {
assert( pos.pCur != nullptr );
+ m_Stat.onFindSuccess();
return const_iterator( pos.pCur );
}
+
+ m_Stat.onFindFailed();
return cend();
}
//@endcond
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_INTRUSIVE_MICHAEL_SET_H
#define CDSLIB_INTRUSIVE_MICHAEL_SET_H
#include <cds/intrusive/details/michael_set_base.h>
-#include <cds/details/allocator.h>
+#include <cds/intrusive/details/iterable_list_base.h>
namespace cds { namespace intrusive {
Template parameters are:
- \p GC - Garbage collector used. Note the \p GC must be the same as the GC used for \p OrderedList
- - \p OrderedList - ordered list implementation used as bucket for hash set, for example, \p MichaelList, \p LazyList.
+ - \p OrderedList - ordered list implementation used as bucket for hash set, possible implementations:
+ \p MichaelList, \p LazyList, \p IterableList.
The intrusive ordered list implementation specifies the type \p T stored in the hash-set, the reclamation
schema \p GC used by hash-set, the comparison functor for the type \p T and other features specific for
the ordered list.
\code
// Our node type
struct Foo {
- std::string key_; // key field
+ std::string key_; // key field
// ... other fields
};
public:
typedef GC gc; ///< Garbage collector
typedef OrderedList ordered_list; ///< type of ordered list used as a bucket implementation
- typedef ordered_list bucket_type; ///< bucket type
- typedef Traits traits; ///< Set traits
+ typedef Traits traits; ///< Set traits
- typedef typename ordered_list::value_type value_type ; ///< type of value to be stored in the set
- typedef typename ordered_list::key_comparator key_comparator ; ///< key comparing functor
- typedef typename ordered_list::disposer disposer ; ///< Node disposer functor
+ typedef typename ordered_list::value_type value_type ; ///< type of value to be stored in the set
+ typedef typename ordered_list::key_comparator key_comparator ; ///< key comparing functor
+ typedef typename ordered_list::disposer disposer ; ///< Node disposer functor
+ typedef typename ordered_list::stat stat ; ///< Internal statistics
/// Hash functor for \p value_type and all its derivatives that you use
typedef typename cds::opt::v::hash_selector< typename traits::hash >::type hash;
typedef typename traits::item_counter item_counter; ///< Item counter type
+ typedef typename traits::allocator allocator; ///< Bucket table allocator
typedef typename ordered_list::guarded_ptr guarded_ptr; ///< Guarded pointer
- /// Bucket table allocator
- typedef cds::details::Allocator< bucket_type, typename traits::allocator > bucket_table_allocator;
-
/// Count of hazard pointer required for the algorithm
static CDS_CONSTEXPR const size_t c_nHazardPtrCount = ordered_list::c_nHazardPtrCount;
- protected:
- item_counter m_ItemCounter; ///< Item counter
- hash m_HashFunctor; ///< Hash functor
- bucket_type * m_Buckets; ///< bucket table
+ // GC and OrderedList::gc must be the same
+ static_assert(std::is_same<gc, typename ordered_list::gc>::value, "GC and OrderedList::gc must be the same");
- private:
- //@cond
- const size_t m_nHashBitmask;
- //@endcond
+ // atomicity::empty_item_counter is not allowed as a item counter
+ static_assert(!std::is_same<item_counter, atomicity::empty_item_counter>::value,
+ "cds::atomicity::empty_item_counter is not allowed as a item counter");
protected:
//@cond
- /// Calculates hash value of \p key
- template <typename Q>
- size_t hash_value( const Q& key ) const
- {
- return m_HashFunctor( key ) & m_nHashBitmask;
- }
+ typedef typename ordered_list::template select_stat_wrapper< typename ordered_list::stat > bucket_stat;
- /// Returns the bucket (ordered list) for \p key
- template <typename Q>
- bucket_type& bucket( const Q& key )
- {
- return m_Buckets[ hash_value( key ) ];
- }
+ typedef typename ordered_list::template rebind_traits<
+ cds::opt::item_counter< cds::atomicity::empty_item_counter >
+ , cds::opt::stat< typename bucket_stat::wrapped_stat >
+ >::type internal_bucket_type;
+
+ typedef typename allocator::template rebind< internal_bucket_type >::other bucket_table_allocator;
+
+ hash m_HashFunctor; ///< Hash functor
+ size_t const m_nHashBitmask;
+ internal_bucket_type* m_Buckets; ///< bucket table
+ item_counter m_ItemCounter; ///< Item counter
+ typename bucket_stat::stat m_Stat; ///< Internal statistics
//@endcond
public:
- ///@name Forward iterators (only for debugging purpose)
+ ///@name Forward iterators
//@{
/// Forward iterator
/**
- it has no post-increment operator
- it iterates items in unordered fashion
- The iterator cannot be moved across thread boundary because it may contain GC's guard that is thread-private GC data.
- - Iterator ensures thread-safety even if you delete the item that iterator points to. However, in case of concurrent
- deleting operations it is no guarantee that you iterate all item in the set.
- Moreover, a crash is possible when you try to iterate the next element that has been deleted by concurrent thread.
- @warning Use this iterator on the concurrent container for debugging purpose only.
+ Iterator thread safety depends on type of \p OrderedList:
+ - for \p MichaelList and \p LazyList: iterator guarantees safety even if you delete the item that iterator points to
+ because that item is guarded by hazard pointer.
+ However, in case of concurrent deleting operations it is no guarantee that you iterate all item in the set.
+ Moreover, a crash is possible when you try to iterate the next element that has been deleted by concurrent thread.
+ Use this iterator on the concurrent container for debugging purpose only.
+ - for \p IterableList: iterator is thread-safe. You may use it freely in concurrent environment.
+
*/
- typedef michael_set::details::iterator< bucket_type, false > iterator;
+ typedef michael_set::details::iterator< internal_bucket_type, false > iterator;
/// Const forward iterator
/**
For iterator's features and requirements see \ref iterator
*/
- typedef michael_set::details::iterator< bucket_type, true > const_iterator;
+ typedef michael_set::details::iterator< internal_bucket_type, true > const_iterator;
/// Returns a forward iterator addressing the first element in a set
/**
*/
iterator begin()
{
- return iterator( m_Buckets[0].begin(), m_Buckets, m_Buckets + bucket_count() );
+ return iterator( m_Buckets[0].begin(), bucket_begin(), bucket_end() );
}
/// Returns an iterator that addresses the location succeeding the last element in a set
*/
iterator end()
{
- return iterator( m_Buckets[bucket_count() - 1].end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
+ return iterator( bucket_end()[-1].end(), bucket_end() - 1, bucket_end() );
}
/// Returns a forward const iterator addressing the first element in a set
}
//@}
- private:
- //@cond
- const_iterator get_const_begin() const
- {
- return const_iterator( m_Buckets[0].cbegin(), m_Buckets, m_Buckets + bucket_count() );
- }
- const_iterator get_const_end() const
- {
- return const_iterator( m_Buckets[bucket_count() - 1].cend(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
- }
- //@endcond
-
public:
/// Initializes hash set
- /** @anchor cds_intrusive_MichaelHashSet_hp_ctor
+ /**
The Michael's hash set is an unbounded container, but its hash table is non-expandable.
At construction time you should pass estimated maximum item count and a load factor.
The load factor is average size of one bucket - a small number between 1 and 10.
size_t nMaxItemCount, ///< estimation of max item count in the hash set
size_t nLoadFactor ///< load factor: estimation of max number of items in the bucket. Small integer up to 10.
) : m_nHashBitmask( michael_set::details::init_hash_bitmask( nMaxItemCount, nLoadFactor ))
+ , m_Buckets( bucket_table_allocator().allocate( bucket_count()))
{
- // GC and OrderedList::gc must be the same
- static_assert( std::is_same<gc, typename bucket_type::gc>::value, "GC and OrderedList::gc must be the same");
-
- // atomicity::empty_item_counter is not allowed as a item counter
- static_assert( !std::is_same<item_counter, atomicity::empty_item_counter>::value,
- "cds::atomicity::empty_item_counter is not allowed as a item counter");
-
- m_Buckets = bucket_table_allocator().NewArray( bucket_count() );
+ for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
+ construct_bucket<bucket_stat>( it );
}
/// Clears hash set object and destroys it
~MichaelHashSet()
{
clear();
- bucket_table_allocator().Delete( m_Buckets, bucket_count() );
+
+ for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
+ it->~internal_bucket_type();
+ bucket_table_allocator().deallocate( m_Buckets, bucket_count() );
}
/// Inserts new node
If the item \p val not found in the set, then \p val is inserted iff \p bAllowInsert is \p true.
Otherwise, the functor \p func is called with item found.
- The functor signature is:
- \code
- struct functor {
- void operator()( bool bNew, value_type& item, value_type& val );
- };
- \endcode
- with arguments:
- - \p bNew - \p true if the item has been inserted, \p false otherwise
- - \p item - item of the set
- - \p val - argument \p val passed into the \p %update() function
- If new item has been inserted (i.e. \p bNew is \p true) then \p item and \p val arguments
- refers to the same thing.
-
- The functor may change non-key fields of the \p item.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+ The functor signature depends of the type of \p OrderedList:
+
+ <b>for \p MichaelList, \p LazyList</b>
+ \code
+ struct functor {
+ void operator()( bool bNew, value_type& item, value_type& val );
+ };
+ \endcode
+ with arguments:
+ - \p bNew - \p true if the item has been inserted, \p false otherwise
+ - \p item - item of the set
+ - \p val - argument \p val passed into the \p %update() function
+ If new item has been inserted (i.e. \p bNew is \p true) then \p item and \p val arguments
+ refers to the same thing.
+
+ The functor may change non-key fields of the \p item.
+ @warning For \ref cds_intrusive_MichaelList_hp "MichaelList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
+ \ref cds_intrusive_LazyList_hp "LazyList" provides exclusive access to inserted item and does not require any node-level
+ synchronization.
+
+ <b>for \p IterableList</b>
+ \code
+ void func( value_type& val, value_type * old );
+ \endcode
+ where
+ - \p val - argument \p val passed into the \p %update() function
+ - \p old - old value that will be retired. If new item has been inserted then \p old is \p nullptr.
+
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
\p second is \p true if new item has been added or \p false if the item with \p key
already is in the set.
-
- @warning For \ref cds_intrusive_MichaelList_hp "MichaelList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
- \ref cds_intrusive_LazyList_hp "LazyList" provides exclusive access to inserted item and does not require any node-level
- synchronization.
*/
template <typename Func>
std::pair<bool, bool> update( value_type& val, Func func, bool bAllowInsert = true )
}
//@endcond
+ /// Inserts or updates the node (only for \p IterableList)
+ /**
+ The operation performs inserting or changing data with lock-free manner.
+
+ If the item \p val is not found in the set, then \p val is inserted iff \p bAllowInsert is \p true.
+ Otherwise, the current element is changed to \p val, the old element will be retired later
+ by call \p Traits::disposer.
+
+ Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
+ \p second is \p true if \p val has been added or \p false if the item with that key
+ already in the set.
+ */
+#ifdef CDS_DOXYGEN_INVOKED
+ std::pair<bool, bool> upsert( value_type& val, bool bAllowInsert = true )
+#else
+ template <typename Q>
+ typename std::enable_if<
+ std::is_same< Q, value_type>::value && is_iterable_list< ordered_list >::value,
+ std::pair<bool, bool>
+ >::type
+ upsert( Q& val, bool bAllowInsert = true )
+#endif
+ {
+ std::pair<bool, bool> bRet = bucket( val ).upsert( val, bAllowInsert );
+ if ( bRet.second )
+ ++m_ItemCounter;
+ return bRet;
+ }
+
/// Unlinks the item \p val from the set
/**
The function searches the item \p val in the set and unlink it
}
//@endcond
+ /// Finds \p key and returns iterator pointed to the item found (only for \p IterableList)
+ /**
+ If \p key is not found the function returns \p end().
+
+ @note This function is supported only for the set based on \p IterableList
+ */
+ template <typename Q>
+#ifdef CDS_DOXYGEN_INVOKED
+ iterator
+#else
+ typename std::enable_if< std::is_same<Q,Q>::value && is_iterable_list< ordered_list >::value, iterator >::type
+#endif
+ find( Q& key )
+ {
+ internal_bucket_type& b = bucket( key );
+ typename internal_bucket_type::iterator it = b.find( key );
+ if ( it == b.end() )
+ return end();
+ return iterator( it, &b, bucket_end());
+ }
+ //@cond
+ template <typename Q>
+ typename std::enable_if< std::is_same<Q, Q>::value && is_iterable_list< ordered_list >::value, iterator >::type
+ find( Q const& key )
+ {
+ internal_bucket_type& b = bucket( key );
+ typename internal_bucket_type::iterator it = b.find( key );
+ if ( it == b.end() )
+ return end();
+ return iterator( it, &b, bucket_end() );
+ }
+ //@endcond
+
+
/// Finds the key \p key using \p pred predicate for searching
/**
The function is an analog of \ref cds_intrusive_MichaelHashSet_hp_find_func "find(Q&, Func)"
}
//@endcond
+ /// Finds \p key using \p pred predicate and returns iterator pointed to the item found (only for \p IterableList)
+ /**
+ The function is an analog of \p find(Q&) but \p pred is used for key comparing.
+ \p Less functor has the interface like \p std::less.
+ \p pred must imply the same element order as the comparator used for building the set.
+
+ If \p key is not found the function returns \p end().
+
+ @note This function is supported only for the set based on \p IterableList
+ */
+ template <typename Q, typename Less>
+#ifdef CDS_DOXYGEN_INVOKED
+ iterator
+#else
+ typename std::enable_if< std::is_same<Q, Q>::value && is_iterable_list< ordered_list >::value, iterator >::type
+#endif
+ find_with( Q& key, Less pred )
+ {
+ internal_bucket_type& b = bucket( key );
+ typename internal_bucket_type::iterator it = b.find_with( key, pred );
+ if ( it == b.end() )
+ return end();
+ return iterator( it, &b, bucket_end() );
+ }
+ //@cond
+ template <typename Q, typename Less>
+ typename std::enable_if< std::is_same<Q, Q>::value && is_iterable_list< ordered_list >::value, iterator >::type
+ find_with( Q const& key, Less pred )
+ {
+ internal_bucket_type& b = bucket( key );
+ typename internal_bucket_type::iterator it = b.find_with( key, pred );
+ if ( it == b.end() )
+ return end();
+ return iterator( it, &b, bucket_end() );
+ }
+ //@endcond
+
/// Checks whether the set contains \p key
/**
{
return bucket( key ).contains( key );
}
- //@cond
- template <typename Q>
- CDS_DEPRECATED("use contains()")
- bool find( Q const& key )
- {
- return contains( key );
- }
- //@endcond
/// Checks whether the set contains \p key using \p pred predicate for searching
/**
{
return bucket( key ).contains( key, pred );
}
- //@cond
- template <typename Q, typename Less>
- CDS_DEPRECATED("use contains()")
- bool find_with( Q const& key, Less pred )
- {
- return contains( key, pred );
- }
- //@endcond
/// Finds the key \p key and return the item found
/** \anchor cds_intrusive_MichaelHashSet_hp_get
return m_ItemCounter;
}
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return m_Stat;
+ }
+
/// Returns the size of hash table
/**
Since \p %MichaelHashSet cannot dynamically extend the hash table size,
{
return m_nHashBitmask + 1;
}
+
+ private:
+ //@cond
+ internal_bucket_type * bucket_begin() const
+ {
+ return m_Buckets;
+ }
+
+ internal_bucket_type * bucket_end() const
+ {
+ return m_Buckets + bucket_count();
+ }
+
+ const_iterator get_const_begin() const
+ {
+ return const_iterator( m_Buckets[0].cbegin(), bucket_begin(), bucket_end() );
+ }
+ const_iterator get_const_end() const
+ {
+ return const_iterator( bucket_end()[-1].cend(), bucket_end() - 1, bucket_end() );
+ }
+
+ template <typename Stat>
+ typename std::enable_if< Stat::empty >::type construct_bucket( internal_bucket_type * bucket )
+ {
+ new (bucket) internal_bucket_type;
+ }
+
+ template <typename Stat>
+ typename std::enable_if< !Stat::empty >::type construct_bucket( internal_bucket_type * bucket )
+ {
+ new (bucket) internal_bucket_type( m_Stat );
+ }
+
+ /// Calculates hash value of \p key
+ template <typename Q>
+ size_t hash_value( const Q& key ) const
+ {
+ return m_HashFunctor( key ) & m_nHashBitmask;
+ }
+
+ /// Returns the bucket (ordered list) for \p key
+ template <typename Q>
+ internal_bucket_type& bucket( const Q& key )
+ {
+ return m_Buckets[hash_value( key )];
+ }
+ //@endcond
};
}} // namespace cds::intrusive
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_INTRUSIVE_MICHAEL_SET_NOGC_H
#include <cds/intrusive/details/michael_set_base.h>
#include <cds/gc/nogc.h>
-#include <cds/details/allocator.h>
namespace cds { namespace intrusive {
class MichaelHashSet< cds::gc::nogc, OrderedList, Traits >
{
public:
- typedef cds::gc::nogc gc; ///< Garbage collector
- typedef OrderedList bucket_type; ///< Type of ordered list to be used as buckets
- typedef Traits traits; ///< Set traits
+ typedef cds::gc::nogc gc; ///< Garbage collector
+ typedef OrderedList ordered_list; ///< type of ordered list used as a bucket implementation
+ typedef Traits traits; ///< Set traits
- typedef typename bucket_type::value_type value_type; ///< type of value to be stored in the set
- typedef typename bucket_type::key_comparator key_comparator; ///< key comparing functor
- typedef typename bucket_type::disposer disposer; ///< Node disposer functor
+ typedef typename ordered_list::value_type value_type; ///< type of value to be stored in the set
+ typedef typename ordered_list::key_comparator key_comparator; ///< key comparing functor
+ typedef typename ordered_list::disposer disposer; ///< Node disposer functor
+ typedef typename ordered_list::stat stat; ///< Internal statistics
/// Hash functor for \p value_type and all its derivatives that you use
typedef typename cds::opt::v::hash_selector< typename traits::hash >::type hash;
typedef typename traits::item_counter item_counter; ///< Item counter type
+ typedef typename traits::allocator allocator; ///< Bucket table allocator
- /// Bucket table allocator
- typedef cds::details::Allocator< bucket_type, typename traits::allocator > bucket_table_allocator;
+ // GC and OrderedList::gc must be the same
+ static_assert(std::is_same<gc, typename ordered_list::gc>::value, "GC and OrderedList::gc must be the same");
- protected:
- item_counter m_ItemCounter; ///< Item counter
- hash m_HashFunctor; ///< Hash functor
- bucket_type * m_Buckets; ///< bucket table
+ // atomicity::empty_item_counter is not allowed as a item counter
+ static_assert(!std::is_same<item_counter, atomicity::empty_item_counter>::value,
+ "atomicity::empty_item_counter is not allowed as a item counter");
- private:
+ protected:
//@cond
- const size_t m_nHashBitmask;
+ typedef typename ordered_list::template select_stat_wrapper< typename ordered_list::stat > bucket_stat;
+
+ typedef typename ordered_list::template rebind_traits<
+ cds::opt::item_counter< cds::atomicity::empty_item_counter >
+ , cds::opt::stat< typename bucket_stat::wrapped_stat >
+ >::type internal_bucket_type;
+
+ typedef typename allocator::template rebind< internal_bucket_type >::other bucket_table_allocator;
+
+ hash m_HashFunctor; ///< Hash functor
+ const size_t m_nHashBitmask;
+ internal_bucket_type * m_Buckets; ///< bucket table
+ item_counter m_ItemCounter; ///< Item counter
+ typename bucket_stat::stat m_Stat; ///< Internal statistics
//@endcond
protected:
/// Returns the bucket (ordered list) for \p key
template <typename Q>
- bucket_type& bucket( Q const & key )
+ internal_bucket_type& bucket( Q const & key )
{
return m_Buckets[ hash_value( key ) ];
}
};
\endcode
*/
- typedef michael_set::details::iterator< bucket_type, false > iterator;
+ typedef michael_set::details::iterator< internal_bucket_type, false > iterator;
/// Const forward iterator
/**
For iterator's features and requirements see \ref iterator
*/
- typedef michael_set::details::iterator< bucket_type, true > const_iterator;
+ typedef michael_set::details::iterator< internal_bucket_type, true > const_iterator;
/// Returns a forward iterator addressing the first element in a set
/**
size_t nMaxItemCount, ///< estimation of max item count in the hash set
size_t nLoadFactor ///< load factor: estimation of max number of items in the bucket
) : m_nHashBitmask( michael_set::details::init_hash_bitmask( nMaxItemCount, nLoadFactor ))
+ , m_Buckets( bucket_table_allocator().allocate( bucket_count() ) )
{
- // GC and OrderedList::gc must be the same
- static_assert( std::is_same<gc, typename bucket_type::gc>::value, "GC and OrderedList::gc must be the same");
-
- // atomicity::empty_item_counter is not allowed as a item counter
- static_assert( !std::is_same<item_counter, atomicity::empty_item_counter>::value,
- "atomicity::empty_item_counter is not allowed as a item counter");
-
- m_Buckets = bucket_table_allocator().NewArray( bucket_count() );
+ for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
+ construct_bucket<bucket_stat>( it );
}
/// Clears hash set object and destroys it
~MichaelHashSet()
{
clear();
- bucket_table_allocator().Delete( m_Buckets, bucket_count() );
+
+ for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
+ it->~internal_bucket_type();
+ bucket_table_allocator().deallocate( m_Buckets, bucket_count() );
}
/// Inserts new node
The functor may change non-key fields of the \p item.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
\p second is \p true if new item has been added or \p false if the item with \p key
already is in the set.
return m_nHashBitmask + 1;
}
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return m_Stat;
+ }
+
+ private:
+ //@cond
+ template <typename Stat>
+ typename std::enable_if< Stat::empty >::type construct_bucket( internal_bucket_type * bucket )
+ {
+ new (bucket) internal_bucket_type;
+ }
+
+ template <typename Stat>
+ typename std::enable_if< !Stat::empty >::type construct_bucket( internal_bucket_type * bucket )
+ {
+ new (bucket) internal_bucket_type( m_Stat );
+ }
+ //@endcond
};
}} // namespace cds::intrusive
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_INTRUSIVE_MICHAEL_SET_RCU_H
#define CDSLIB_INTRUSIVE_MICHAEL_SET_RCU_H
#include <cds/intrusive/details/michael_set_base.h>
-#include <cds/details/allocator.h>
namespace cds { namespace intrusive {
class MichaelHashSet< cds::urcu::gc< RCU >, OrderedList, Traits >
{
public:
- typedef cds::urcu::gc< RCU > gc; ///< RCU schema
- typedef OrderedList bucket_type; ///< type of ordered list used as a bucket implementation
- typedef Traits traits; ///< Set traits
+ typedef cds::urcu::gc< RCU > gc; ///< RCU schema
+ typedef OrderedList ordered_list; ///< type of ordered list used as a bucket implementation
+ typedef Traits traits; ///< Set traits
- typedef typename bucket_type::value_type value_type ; ///< type of value stored in the list
- typedef typename bucket_type::key_comparator key_comparator ; ///< key comparing functor
- typedef typename bucket_type::disposer disposer ; ///< Node disposer functor
+ typedef typename ordered_list::value_type value_type; ///< type of value stored in the list
+ typedef typename ordered_list::key_comparator key_comparator; ///< key comparing functor
+ typedef typename ordered_list::disposer disposer; ///< Node disposer functor
+ typedef typename ordered_list::stat stat; ///< Internal statistics
/// Hash functor for \ref value_type and all its derivatives that you use
typedef typename cds::opt::v::hash_selector< typename traits::hash >::type hash;
typedef typename traits::item_counter item_counter; ///< Item counter type
+ typedef typename traits::allocator allocator; ///< Bucket table allocator
- /// Bucket table allocator
- typedef cds::details::Allocator< bucket_type, typename traits::allocator > bucket_table_allocator;
-
- typedef typename bucket_type::rcu_lock rcu_lock; ///< RCU scoped lock
- typedef typename bucket_type::exempt_ptr exempt_ptr; ///< pointer to extracted node
- typedef typename bucket_type::raw_ptr raw_ptr; ///< Return type of \p get() member function and its derivatives
+ typedef typename ordered_list::rcu_lock rcu_lock; ///< RCU scoped lock
/// Group of \p extract_xxx functions require external locking if underlying ordered list requires that
- static CDS_CONSTEXPR const bool c_bExtractLockExternal = bucket_type::c_bExtractLockExternal;
+ static CDS_CONSTEXPR const bool c_bExtractLockExternal = ordered_list::c_bExtractLockExternal;
- protected:
- item_counter m_ItemCounter; ///< Item counter
- hash m_HashFunctor; ///< Hash functor
- bucket_type * m_Buckets; ///< bucket table
+ // GC and OrderedList::gc must be the same
+ static_assert(std::is_same<gc, typename ordered_list::gc>::value, "GC and OrderedList::gc must be the same");
- private:
- //@cond
- const size_t m_nHashBitmask;
- //@endcond
+ // atomicity::empty_item_counter is not allowed as a item counter
+ static_assert(!std::is_same<item_counter, atomicity::empty_item_counter>::value,
+ "atomicity::empty_item_counter is not allowed as a item counter");
protected:
//@cond
- /// Calculates hash value of \p key
- template <typename Q>
- size_t hash_value( Q const& key ) const
- {
- return m_HashFunctor( key ) & m_nHashBitmask;
- }
+ typedef typename ordered_list::template select_stat_wrapper< typename ordered_list::stat > bucket_stat;
- /// Returns the bucket (ordered list) for \p key
- template <typename Q>
- bucket_type& bucket( Q const& key )
- {
- return m_Buckets[ hash_value( key ) ];
- }
- template <typename Q>
- bucket_type const& bucket( Q const& key ) const
- {
- return m_Buckets[ hash_value( key ) ];
- }
+ typedef typename ordered_list::template rebind_traits<
+ cds::opt::item_counter< cds::atomicity::empty_item_counter >
+ , cds::opt::stat< typename bucket_stat::wrapped_stat >
+ >::type internal_bucket_type;
+
+ typedef typename allocator::template rebind< internal_bucket_type >::other bucket_table_allocator;
+ //@endcond
+
+ public:
+ typedef typename internal_bucket_type::exempt_ptr exempt_ptr; ///< pointer to extracted node
+ typedef typename internal_bucket_type::raw_ptr raw_ptr; ///< Return type of \p get() member function and its derivatives
+
+ private:
+ //@cond
+ hash m_HashFunctor; ///< Hash functor
+ size_t const m_nHashBitmask;
+ internal_bucket_type* m_Buckets; ///< bucket table
+ item_counter m_ItemCounter; ///< Item counter
+ typename bucket_stat::stat m_Stat; ///< Internal statistics
//@endcond
public:
};
\endcode
*/
- typedef michael_set::details::iterator< bucket_type, false > iterator;
+ typedef michael_set::details::iterator< internal_bucket_type, false > iterator;
/// Const forward iterator
/**
For iterator's features and requirements see \ref iterator
*/
- typedef michael_set::details::iterator< bucket_type, true > const_iterator;
+ typedef michael_set::details::iterator< internal_bucket_type, true > const_iterator;
/// Returns a forward iterator addressing the first element in a set
/**
size_t nMaxItemCount, ///< estimation of max item count in the hash set
size_t nLoadFactor ///< load factor: average size of the bucket
) : m_nHashBitmask( michael_set::details::init_hash_bitmask( nMaxItemCount, nLoadFactor ))
+ , m_Buckets( bucket_table_allocator().allocate( bucket_count() ) )
{
- // GC and OrderedList::gc must be the same
- static_assert( std::is_same<gc, typename bucket_type::gc>::value, "GC and OrderedList::gc must be the same");
-
- // atomicity::empty_item_counter is not allowed as a item counter
- static_assert( !std::is_same<item_counter, atomicity::empty_item_counter>::value,
- "atomicity::empty_item_counter is not allowed as a item counter");
-
- m_Buckets = bucket_table_allocator().NewArray( bucket_count() );
+ for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
+ construct_bucket<bucket_stat>( it );
}
/// Clear hash set and destroy it
~MichaelHashSet()
{
clear();
- bucket_table_allocator().Delete( m_Buckets, bucket_count() );
+
+ for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
+ it->~internal_bucket_type();
+ bucket_table_allocator().deallocate( m_Buckets, bucket_count() );
}
/// Inserts new node
The functor may change non-key fields of the \p item.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
\p second is \p true if new item has been added or \p false if the item with \p key
already is in the set.
unlinks it from the set, and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the item found.
If the item with the key equal to \p key is not found the function returns an empty \p exempt_ptr.
- Depends on \p bucket_type you should or should not lock RCU before calling of this function:
+ Depends on \p ordered_list you should or should not lock RCU before calling of this function:
- for the set based on \ref cds_intrusive_MichaelList_rcu "MichaelList" RCU should not be locked
- for the set based on \ref cds_intrusive_LazyList_rcu "LazyList" RCU should be locked
/** \anchor cds_intrusive_MichaelHashSet_rcu_get
The function searches the item with key equal to \p key and returns the pointer to item found.
If \p key is not found it returns \p nullptr.
- Note the type of returned value depends on underlying \p bucket_type.
+ Note the type of returned value depends on underlying \p ordered_list.
For details, see documentation of ordered list you use.
Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
return m_nHashBitmask + 1;
}
+ /// Returns const reference to internal statistics
+ stat const& statistics() const
+ {
+ return m_Stat;
+ }
+
+ private:
+ //@cond
+ template <typename Stat>
+ typename std::enable_if< Stat::empty >::type construct_bucket( internal_bucket_type * bucket )
+ {
+ new (bucket) internal_bucket_type;
+ }
+
+ template <typename Stat>
+ typename std::enable_if< !Stat::empty >::type construct_bucket( internal_bucket_type * bucket )
+ {
+ new (bucket) internal_bucket_type( m_Stat );
+ }
+
+ /// Calculates hash value of \p key
+ template <typename Q>
+ size_t hash_value( Q const& key ) const
+ {
+ return m_HashFunctor( key ) & m_nHashBitmask;
+ }
+
+ /// Returns the bucket (ordered list) for \p key
+ template <typename Q>
+ internal_bucket_type& bucket( Q const& key )
+ {
+ return m_Buckets[hash_value( key )];
+ }
+ template <typename Q>
+ internal_bucket_type const& bucket( Q const& key ) const
+ {
+ return m_Buckets[hash_value( key )];
+ }
+ //@endcond
};
}} // namespace cds::intrusive
#endif // #ifndef CDSLIB_INTRUSIVE_MICHAEL_SET_NOGC_H
-
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_INTRUSIVE_MSPRIORITY_QUEUE_H
struct stat {
typedef Counter event_counter ; ///< Event counter type
- event_counter m_nPushCount ; ///< Count of success push operation
- event_counter m_nPopCount ; ///< Count of success pop operation
- event_counter m_nPushFailCount ; ///< Count of failed ("the queue is full") push operation
- event_counter m_nPopFailCount ; ///< Count of failed ("the queue is empty") pop operation
- event_counter m_nPushHeapifySwapCount ; ///< Count of item swapping when heapifying in push
- event_counter m_nPopHeapifySwapCount ; ///< Count of item swapping when heapifying in pop
+ event_counter m_nPushCount; ///< Count of success push operation
+ event_counter m_nPopCount; ///< Count of success pop operation
+ event_counter m_nPushFailCount; ///< Count of failed ("the queue is full") push operation
+ event_counter m_nPopFailCount; ///< Count of failed ("the queue is empty") pop operation
+ event_counter m_nPushHeapifySwapCount; ///< Count of item swapping when heapifying in push
+ event_counter m_nPopHeapifySwapCount; ///< Count of item swapping when heapifying in pop
+ event_counter m_nItemMovedTop; ///< Count of events when \p push() encountered that inserted item was moved to top by a concurrent \p pop()
+ event_counter m_nItemMovedUp; ///< Count of events when \p push() encountered that inserted item was moved upwards by a concurrent \p pop()
+ event_counter m_nPushEmptyPass; ///< Count of empty pass during heapify via concurrent operations
//@cond
void onPushSuccess() { ++m_nPushCount ;}
void onPopFailed() { ++m_nPopFailCount ;}
void onPushHeapifySwap() { ++m_nPushHeapifySwapCount ;}
void onPopHeapifySwap() { ++m_nPopHeapifySwapCount ;}
+
+ void onItemMovedTop() { ++m_nItemMovedTop ;}
+ void onItemMovedUp() { ++m_nItemMovedUp ;}
+ void onPushEmptyPass() { ++m_nPushEmptyPass ;}
//@endcond
};
/// MSPriorityQueue empty statistics
struct empty_stat {
//@cond
- void onPushSuccess() {}
- void onPopSuccess() {}
- void onPushFailed() {}
- void onPopFailed() {}
- void onPushHeapifySwap() {}
- void onPopHeapifySwap() {}
+ void onPushSuccess() const {}
+ void onPopSuccess() const {}
+ void onPushFailed() const {}
+ void onPopFailed() const {}
+ void onPushHeapifySwap() const {}
+ void onPopHeapifySwap() const {}
+
+ void onItemMovedTop() const {}
+ void onItemMovedUp() const {}
+ void onPushEmptyPass() const {}
//@endcond
};
*/
typedef opt::none less;
- /// Type of mutual-exclusion lock
+ /// Type of mutual-exclusion lock. The lock is not need to be recursive.
typedef cds::sync::spin lock_type;
/// Back-off strategy
typedef typename opt::details::make_comparator< value_type, traits >::type key_comparator;
# endif
- typedef typename traits::lock_type lock_type; ///< heap's size lock type
- typedef typename traits::back_off back_off; ///< Back-off strategy
- typedef typename traits::stat stat; ///< internal statistics type
+ typedef typename traits::lock_type lock_type; ///< heap's size lock type
+ typedef typename traits::back_off back_off; ///< Back-off strategy
+ typedef typename traits::stat stat; ///< internal statistics type, see \p mspriority_queue::traits::stat
+ typedef typename cds::bitop::bit_reverse_counter<> item_counter;///< Item counter type
protected:
//@cond
typedef typename traits::buffer::template rebind<node>::other buffer_type ; ///< Heap array buffer type
//@cond
- typedef cds::bitop::bit_reverse_counter<> item_counter_type;
- typedef typename item_counter_type::counter_type counter_type;
+ typedef typename item_counter::counter_type counter_type;
//@endcond
protected:
- item_counter_type m_ItemCounter ; ///< Item counter
+ item_counter m_ItemCounter ; ///< Item counter
mutable lock_type m_Lock ; ///< Heap's size lock
buffer_type m_Heap ; ///< Heap array
stat m_Stat ; ///< internal statistics accumulator
node& refNode = m_Heap[i];
refNode.lock();
m_Lock.unlock();
+ assert( refNode.m_nTag == tag_type( Empty ));
+ assert( refNode.m_pVal == nullptr );
refNode.m_pVal = &val;
refNode.m_nTag = curId;
refNode.unlock();
- // Move item towards top of the heap while it has higher priority than parent
+ // Move item towards top of heap while it has a higher priority than its parent
heapify_after_push( i, curId );
m_Stat.onPushSuccess();
*/
value_type * pop()
{
+ node& refTop = m_Heap[1];
+
m_Lock.lock();
if ( m_ItemCounter.value() == 0 ) {
// the heap is empty
m_Stat.onPopFailed();
return nullptr;
}
- counter_type nBottom = m_ItemCounter.reversed_value();
- m_ItemCounter.dec();
- // Since m_Heap[0] is not used, capacity() returns m_Heap.capacity() - 1
- // Consequently, "<=" is here
- assert( nBottom <= capacity() );
+ counter_type nBottom = m_ItemCounter.dec();
+ assert( nBottom < m_Heap.capacity() );
assert( nBottom > 0 );
- node& refBottom = m_Heap[ nBottom ];
+ refTop.lock();
+ if ( nBottom == 1 ) {
+ refTop.m_nTag = tag_type( Empty );
+ value_type * pVal = refTop.m_pVal;
+ refTop.m_pVal = nullptr;
+ refTop.unlock();
+ m_Lock.unlock();
+ m_Stat.onPopSuccess();
+ return pVal;
+ }
+
+ node& refBottom = m_Heap[nBottom];
refBottom.lock();
m_Lock.unlock();
refBottom.m_nTag = tag_type(Empty);
refBottom.m_pVal = nullptr;
refBottom.unlock();
- node& refTop = m_Heap[ 1 ];
- refTop.lock();
if ( refTop.m_nTag == tag_type(Empty) ) {
// nBottom == nTop
refTop.unlock();
refTop.m_nTag = tag_type( Available );
// refTop will be unlocked inside heapify_after_pop
- heapify_after_pop( 1, &refTop );
+ heapify_after_pop( &refTop );
m_Stat.onPopSuccess();
return pVal;
template <typename Func>
void clear_with( Func f )
{
- while ( !empty() ) {
- value_type * pVal = pop();
- if ( pVal )
- f( *pVal );
- }
+ value_type * pVal;
+ while (( pVal = pop()) != nullptr )
+ f( *pVal );
}
/// Checks is the priority queue is empty
size_t size() const
{
std::unique_lock<lock_type> l( m_Lock );
- size_t nSize = (size_t) m_ItemCounter.value();
- return nSize;
+ return static_cast<size_t>( m_ItemCounter.value());
}
/// Return capacity of the priority queue
i = 0;
}
}
- else if ( refParent.m_nTag == tag_type(Empty) )
+ else if ( refParent.m_nTag == tag_type( Empty ) ) {
+ m_Stat.onItemMovedTop();
i = 0;
- else if ( refItem.m_nTag != curId )
+ }
+ else if ( refItem.m_nTag != curId ) {
+ m_Stat.onItemMovedUp();
i = nParent;
- else
+ }
+ else {
+ m_Stat.onPushEmptyPass();
bProgress = false;
+ }
refItem.unlock();
refParent.unlock();
}
}
- void heapify_after_pop( counter_type nParent, node * pParent )
+ void heapify_after_pop( node * pParent )
{
key_comparator cmp;
+ counter_type const nCapacity = m_Heap.capacity();
+
+ counter_type nParent = 1;
+ for ( counter_type nChild = nParent * 2; nChild < nCapacity; nChild *= 2 ) {
+ node* pChild = &m_Heap[ nChild ];
+ pChild->lock();
- while ( nParent < m_Heap.capacity() / 2 ) {
- counter_type nLeft = nParent * 2;
- counter_type nRight = nLeft + 1;
- node& refLeft = m_Heap[nLeft];
- node& refRight = m_Heap[nRight];
- refLeft.lock();
- refRight.lock();
-
- counter_type nChild;
- node * pChild;
- if ( refLeft.m_nTag == tag_type(Empty) ) {
- refRight.unlock();
- refLeft.unlock();
+ if ( pChild->m_nTag == tag_type( Empty )) {
+ pChild->unlock();
break;
}
- else if ( refRight.m_nTag == tag_type(Empty) || cmp( *refLeft.m_pVal, *refRight.m_pVal ) > 0 ) {
- refRight.unlock();
- nChild = nLeft;
- pChild = &refLeft;
- }
- else {
- refLeft.unlock();
- nChild = nRight;
- pChild = &refRight;
+
+ counter_type const nRight = nChild + 1;
+ if ( nRight < nCapacity ) {
+ node& refRight = m_Heap[nRight];
+ refRight.lock();
+
+ if ( refRight.m_nTag != tag_type( Empty ) && cmp( *refRight.m_pVal, *pChild->m_pVal ) > 0 ) {
+ // get right child
+ pChild->unlock();
+ nChild = nRight;
+ pChild = &refRight;
+ }
+ else
+ refRight.unlock();
}
- // If child has higher priority that parent then swap
+ // If child has higher priority than parent then swap
// Otherwise stop
if ( cmp( *pChild->m_pVal, *pParent->m_pVal ) > 0 ) {
std::swap( pParent->m_nTag, pChild->m_nTag );
The functor can change non-key fields of the \p item; however, \p func must guarantee
that during changing no any other modifications could be made on this item by concurrent threads.
- Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+ Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
\p second is \p true if new item has been added or \p false if the item with \p key
already is in the set.
RCU \p synchronize method can be called. RCU should not be locked.
- Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+ Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
i.e. the node has been inserted or updated,
\p second is \p true if new item has been added or \p false if the item with \p key
already exists.
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_INTRUSIVE_SPLIT_LIST_H
The functor may change non-key fields of the \p item.
- Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+ Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
\p second is \p true if new item has been added or \p false if the item with \p val
already is in the list.
The functor may change non-key fields of the \p item.
- Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+ Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
\p second is \p true if new item has been added or \p false if the item with \p key
already is in the list.
The function applies RCU lock internally.
- Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+ Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
\p second is \p true if new item has been added or \p false if the item with \p key
already is in the list.
The functor may change non-key fields of the \p item.
- Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+ Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
\p second is \p true if new item has been added or \p false if the item with \p val
already is in the set.
*/
The functor can change non-key fields of the \p item.
- Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+ Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
\p second is true if new item has been added or \p false if the item with \p val key
already exists.
<hr>
class uninitialized_dynamic_buffer
{
public:
- typedef T value_type; ///< Value type
+ typedef T value_type; ///< Value type
+ typedef Alloc allocator; ///< Allocator type;
static CDS_CONSTEXPR const bool c_bExp2 = Exp2; ///< \p Exp2 flag
/// Rebind buffer for other template parameters
- template <typename Q, typename Alloc2=Alloc, bool Exp22 = c_bExp2>
+ template <typename Q, typename Alloc2= allocator, bool Exp22 = c_bExp2>
struct rebind {
typedef uninitialized_dynamic_buffer<Q, Alloc2, Exp22> other; ///< Rebinding result type
};
//@cond
- typedef typename Alloc::template rebind<value_type>::other allocator_type;
+ typedef typename allocator::template rebind<value_type>::other allocator_type;
//@endcond
private:
class initialized_dynamic_buffer
{
public:
- typedef T value_type; ///< Value type
+ typedef T value_type; ///< Value type
+ typedef Alloc allocator; ///< Allocator type
static CDS_CONSTEXPR const bool c_bExp2 = Exp2; ///< \p Exp2 flag
/// Rebind buffer for other template parameters
- template <typename Q, typename Alloc2=Alloc, bool Exp22 = c_bExp2>
+ template <typename Q, typename Alloc2= allocator, bool Exp22 = c_bExp2>
struct rebind {
typedef initialized_dynamic_buffer<Q, Alloc2, Exp22> other; ///< Rebinding result type
};
//@cond
- typedef cds::details::Allocator<value_type, Alloc> allocator_type;
+ typedef cds::details::Allocator<value_type, allocator> allocator_type;
//@endcond
private:
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_OPT_OPTIONS_H
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSLIB_SYNC_SPINLOCK_H
[1984] L. Rudolph, Z. Segall. Dynamic Decentralized Cache Schemes for MIMD Parallel Processors.
No serialization performed - any of waiting threads may owns the spin-lock.
- This spin-lock is NOT recursive: the thread owned the lock cannot call lock() method withod deadlock.
- The method unlock() can call any thread
+ This spin-lock is NOT recursive: the thread owned the lock cannot call \p lock() method without deadlock.
+ The method \p unlock() can call any thread
DEBUG version: The spinlock stores owner thead id. Assertion is raised when:
- double lock attempt encountered by same thread (deadlock)
- unlock by another thread
- If spin-lock is locked the Backoff algorithm is called. Predefined backoff::LockDefault class yields current
+ If spin-lock is locked the \p Backoff algorithm is called. Predefined \p backoff::LockDefault class yields current
thread and repeats lock attempts later
Template parameters:
- - @p Backoff backoff strategy. Used when spin lock is locked
+ - \p Backoff - backoff strategy. Used when spin lock is locked
*/
template <typename Backoff >
class spin_lock
return !bCurrent;
}
- /// Try to lock the object, repeat @p nTryCount times if failed
+ /// Try to lock the object, repeat \p nTryCount times if failed
/**
Returns \p true if locking is succeeded
otherwise (if the spin is already locked) returns \p false
Allows recursive calls: the owner thread may recursive enter to critical section guarded by the spin-lock.
Template parameters:
- - @p Integral one of integral atomic type: <tt>unsigned int</tt>, <tt>int</tt>, and others
- - @p Backoff backoff strategy. Used when spin lock is locked
+ - \p Integral one of integral atomic type: <tt>unsigned int</tt>, \p int, and others
+ - \p Backoff backoff strategy. Used when spin lock is locked
*/
template <typename Integral, class Backoff>
class reentrant_spin_lock
private:
atomics::atomic<integral_type> m_spin ; ///< spin-lock atomic
- thread_id m_OwnerId ; ///< Owner thread id. If spin-lock is not locked it usually equals to OS::c_NullThreadId
+ thread_id m_OwnerId ; ///< Owner thread id. If spin-lock is not locked it usually equals to \p OS::c_NullThreadId
private:
//@cond
return !( m_spin.load( atomics::memory_order_relaxed ) == 0 || is_taken( cds::OS::get_current_thread_id() ));
}
- /// Try to lock the spin-lock (synonym for \ref try_lock)
+ /// Try to lock the spin-lock (synonym for \p try_lock())
bool try_lock() CDS_NOEXCEPT
{
thread_id tid = OS::get_current_thread_id();
}
}
- /// Unlock the spin-lock. Return @p true if the current thread is owner of spin-lock @p false otherwise
+ /// Unlock the spin-lock. Return \p true if the current thread is owner of spin-lock \p false otherwise
bool unlock() CDS_NOEXCEPT
{
if ( is_taken( OS::get_current_thread_id() ) ) {
are removed.
- Fixed: use-after-free bug in VyukovMPMCCycleQueue internal buffer.
To prevent this bug the queue uses an uninitialized buffer now.
+ - Fixed: rare priority inversion bug in MSPriorityQueue
- Added: for minimizing runtime of stress test the detail level for some test is added.
Command line argument --detail-level=N specifies what test should be ran: each
test with level not great than N will be ran. Instead of command line arg
Microsoft Visual Studio Solution File, Format Version 12.00\r
# Visual Studio 14\r
-VisualStudioVersion = 14.0.25123.0\r
+VisualStudioVersion = 14.0.25420.1\r
MinimumVisualStudioVersion = 10.0.40219.1\r
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cds", "cds.vcxproj", "{408FE9BC-44F0-4E6A-89FA-D6F952584239}"\r
EndProject\r
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "cds_test", "cds_test", "{3A510E45-180B-4ADC-AFCD-D75774B68580}"\r
ProjectSection(SolutionItems) = preProject\r
..\..\..\test\include\cds_test\check_size.h = ..\..\..\test\include\cds_test\check_size.h\r
+ ..\..\..\test\include\cds_test\city.h = ..\..\..\test\include\cds_test\city.h\r
..\..\..\test\include\cds_test\fixture.h = ..\..\..\test\include\cds_test\fixture.h\r
..\..\..\test\include\cds_test\hash_func.h = ..\..\..\test\include\cds_test\hash_func.h\r
..\..\..\test\include\cds_test\stat_bronson_avltree_out.h = ..\..\..\test\include\cds_test\stat_bronson_avltree_out.h\r
..\..\..\test\include\cds_test\stat_ellenbintree_out.h = ..\..\..\test\include\cds_test\stat_ellenbintree_out.h\r
..\..\..\test\include\cds_test\stat_feldman_hashset_out.h = ..\..\..\test\include\cds_test\stat_feldman_hashset_out.h\r
..\..\..\test\include\cds_test\stat_flat_combining_out.h = ..\..\..\test\include\cds_test\stat_flat_combining_out.h\r
+ ..\..\..\test\include\cds_test\stat_iterable_list_out.h = ..\..\..\test\include\cds_test\stat_iterable_list_out.h\r
+ ..\..\..\test\include\cds_test\stat_lazy_list_out.h = ..\..\..\test\include\cds_test\stat_lazy_list_out.h\r
+ ..\..\..\test\include\cds_test\stat_michael_list_out.h = ..\..\..\test\include\cds_test\stat_michael_list_out.h\r
..\..\..\test\include\cds_test\stat_skiplist_out.h = ..\..\..\test\include\cds_test\stat_skiplist_out.h\r
..\..\..\test\include\cds_test\stat_splitlist_out.h = ..\..\..\test\include\cds_test\stat_splitlist_out.h\r
..\..\..\test\include\cds_test\stat_sync_monitor_out.h = ..\..\..\test\include\cds_test\stat_sync_monitor_out.h\r
..\..\..\test\stress\set\set_type_cuckoo.h = ..\..\..\test\stress\set\set_type_cuckoo.h\r
..\..\..\test\stress\set\set_type_ellen_bintree.h = ..\..\..\test\stress\set\set_type_ellen_bintree.h\r
..\..\..\test\stress\set\set_type_feldman_hashset.h = ..\..\..\test\stress\set\set_type_feldman_hashset.h\r
+ ..\..\..\test\stress\set\set_type_iterable_list.h = ..\..\..\test\stress\set\set_type_iterable_list.h\r
..\..\..\test\stress\set\set_type_lazy_list.h = ..\..\..\test\stress\set\set_type_lazy_list.h\r
..\..\..\test\stress\set\set_type_michael.h = ..\..\..\test\stress\set\set_type_michael.h\r
..\..\..\test\stress\set\set_type_michael_list.h = ..\..\..\test\stress\set\set_type_michael_list.h\r
{408FE9BC-44F0-4E6A-89FA-D6F952584239} = {408FE9BC-44F0-4E6A-89FA-D6F952584239}\r
EndProjectSection\r
EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stress-set-iteration", "stress-set-iteration.vcxproj", "{31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE}"\r
+EndProject\r
Global\r
GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
Debug|Win32 = Debug|Win32\r
{24DF3B87-387E-4EFC-BDE0-8DAD279FE19A}.Release|Win32.Build.0 = Release|Win32\r
{24DF3B87-387E-4EFC-BDE0-8DAD279FE19A}.Release|x64.ActiveCfg = Release|x64\r
{24DF3B87-387E-4EFC-BDE0-8DAD279FE19A}.Release|x64.Build.0 = Release|x64\r
+ {31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE}.Debug|Win32.ActiveCfg = Debug|Win32\r
+ {31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE}.Debug|Win32.Build.0 = Debug|Win32\r
+ {31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE}.Debug|x64.ActiveCfg = Debug|x64\r
+ {31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE}.Debug|x64.Build.0 = Debug|x64\r
+ {31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE}.DebugVLD|Win32.ActiveCfg = DebugVLD|Win32\r
+ {31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE}.DebugVLD|Win32.Build.0 = DebugVLD|Win32\r
+ {31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE}.DebugVLD|x64.ActiveCfg = DebugVLD|x64\r
+ {31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE}.DebugVLD|x64.Build.0 = DebugVLD|x64\r
+ {31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE}.Release|Win32.ActiveCfg = Release|Win32\r
+ {31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE}.Release|Win32.Build.0 = Release|Win32\r
+ {31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE}.Release|x64.ActiveCfg = Release|x64\r
+ {31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE}.Release|x64.Build.0 = Release|x64\r
EndGlobalSection\r
GlobalSection(SolutionProperties) = preSolution\r
HideSolutionNode = FALSE\r
{50387CA5-F5B2-4C40-ACFD-FC3C9EE2CD6B} = {7D3EE35B-185D-40B5-88C2-7F9933426978}\r
{1BB746AC-7856-4E59-9430-51177621DC35} = {7D3EE35B-185D-40B5-88C2-7F9933426978}\r
{24DF3B87-387E-4EFC-BDE0-8DAD279FE19A} = {7D3EE35B-185D-40B5-88C2-7F9933426978}\r
+ {31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE} = {0D83E8C7-97D1-4BA1-928A-6846E7089652}\r
EndGlobalSection\r
GlobalSection(DPCodeReviewSolutionGUID) = preSolution\r
DPCodeReviewSolutionGUID = {00000000-0000-0000-0000-000000000000}\r
<ClInclude Include="..\..\..\cds\container\details\cuckoo_base.h" />\r
<ClInclude Include="..\..\..\cds\container\details\ellen_bintree_base.h" />\r
<ClInclude Include="..\..\..\cds\container\details\guarded_ptr_cast.h" />\r
+ <ClInclude Include="..\..\..\cds\container\details\iterable_list_base.h" />\r
<ClInclude Include="..\..\..\cds\container\details\lazy_list_base.h" />\r
+ <ClInclude Include="..\..\..\cds\container\details\make_iterable_kvlist.h" />\r
+ <ClInclude Include="..\..\..\cds\container\details\make_iterable_list.h" />\r
<ClInclude Include="..\..\..\cds\container\details\make_skip_list_map.h" />\r
<ClInclude Include="..\..\..\cds\container\details\make_skip_list_set.h" />\r
<ClInclude Include="..\..\..\cds\container\details\make_split_list_set.h" />\r
<ClInclude Include="..\..\..\cds\container\impl\bronson_avltree_map_rcu.h" />\r
<ClInclude Include="..\..\..\cds\container\impl\ellen_bintree_map.h" />\r
<ClInclude Include="..\..\..\cds\container\impl\ellen_bintree_set.h" />\r
+ <ClInclude Include="..\..\..\cds\container\impl\iterable_kvlist.h" />\r
+ <ClInclude Include="..\..\..\cds\container\impl\iterable_list.h" />\r
<ClInclude Include="..\..\..\cds\container\impl\lazy_kvlist.h" />\r
<ClInclude Include="..\..\..\cds\container\impl\lazy_list.h" />\r
<ClInclude Include="..\..\..\cds\container\impl\michael_kvlist.h" />\r
<ClInclude Include="..\..\..\cds\container\impl\feldman_hashset.h" />\r
<ClInclude Include="..\..\..\cds\container\impl\skip_list_map.h" />\r
<ClInclude Include="..\..\..\cds\container\impl\skip_list_set.h" />\r
+ <ClInclude Include="..\..\..\cds\container\iterable_kvlist_dhp.h" />\r
+ <ClInclude Include="..\..\..\cds\container\iterable_kvlist_hp.h" />\r
+ <ClInclude Include="..\..\..\cds\container\iterable_list_dhp.h" />\r
+ <ClInclude Include="..\..\..\cds\container\iterable_list_hp.h" />\r
<ClInclude Include="..\..\..\cds\container\lazy_kvlist_dhp.h" />\r
<ClInclude Include="..\..\..\cds\container\lazy_kvlist_rcu.h" />\r
<ClInclude Include="..\..\..\cds\container\lazy_list_dhp.h" />\r
<ClInclude Include="..\..\..\cds\intrusive\cuckoo_set.h" />\r
<ClInclude Include="..\..\..\cds\intrusive\details\base.h" />\r
<ClInclude Include="..\..\..\cds\intrusive\details\ellen_bintree_base.h" />\r
+ <ClInclude Include="..\..\..\cds\intrusive\details\iterable_list_base.h" />\r
<ClInclude Include="..\..\..\cds\intrusive\details\lazy_list_base.h" />\r
<ClInclude Include="..\..\..\cds\intrusive\details\michael_list_base.h" />\r
<ClInclude Include="..\..\..\cds\intrusive\details\michael_set_base.h" />\r
<ClInclude Include="..\..\..\cds\intrusive\free_list.h" />\r
<ClInclude Include="..\..\..\cds\intrusive\free_list_tagged.h" />\r
<ClInclude Include="..\..\..\cds\intrusive\impl\ellen_bintree.h" />\r
+ <ClInclude Include="..\..\..\cds\intrusive\impl\iterable_list.h" />\r
<ClInclude Include="..\..\..\cds\intrusive\impl\lazy_list.h" />\r
<ClInclude Include="..\..\..\cds\intrusive\impl\michael_list.h" />\r
<ClInclude Include="..\..\..\cds\intrusive\impl\feldman_hashset.h" />\r
<ClInclude Include="..\..\..\cds\intrusive\impl\skip_list.h" />\r
+ <ClInclude Include="..\..\..\cds\intrusive\iterable_list_dhp.h" />\r
+ <ClInclude Include="..\..\..\cds\intrusive\iterable_list_hp.h" />\r
<ClInclude Include="..\..\..\cds\intrusive\lazy_list_dhp.h" />\r
<ClInclude Include="..\..\..\cds\intrusive\lazy_list_rcu.h" />\r
<ClInclude Include="..\..\..\cds\intrusive\michael_list_dhp.h" />\r
<Filter Include="Header Files\cds\intrusive">\r
<UniqueIdentifier>{7226715d-6777-4c01-8e66-83b3885c00c1}</UniqueIdentifier>\r
</Filter>\r
- <Filter Include="Header Files\cds\container">\r
- <UniqueIdentifier>{84ca9e83-f6c9-4503-a45f-14f08317fd70}</UniqueIdentifier>\r
- </Filter>\r
- <Filter Include="Header Files\cds\container\details">\r
- <UniqueIdentifier>{4b79fe31-4f6c-4e05-8910-1151a26d51f3}</UniqueIdentifier>\r
- </Filter>\r
<Filter Include="Resource Files">\r
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx</Extensions>\r
<Filter Include="Header Files\cds\intrusive\striped_set">\r
<UniqueIdentifier>{560b4d4c-71e1-443c-942e-dcc5a275c7c2}</UniqueIdentifier>\r
</Filter>\r
- <Filter Include="Header Files\cds\container\striped_map">\r
- <UniqueIdentifier>{6530b757-5bb7-4de0-b1c9-019acc8183ba}</UniqueIdentifier>\r
- </Filter>\r
- <Filter Include="Header Files\cds\container\striped_set">\r
- <UniqueIdentifier>{d3f68c37-8c36-448e-9d4c-cd89a940d275}</UniqueIdentifier>\r
- </Filter>\r
<Filter Include="Header Files\cds\urcu">\r
<UniqueIdentifier>{32754dfc-727a-42ff-b243-9a8510bf5c4e}</UniqueIdentifier>\r
</Filter>\r
<Filter Include="Header Files\cds\intrusive\impl">\r
<UniqueIdentifier>{00a14aa8-3035-4b56-bc86-442ca9bf8f44}</UniqueIdentifier>\r
</Filter>\r
- <Filter Include="Header Files\cds\container\impl">\r
- <UniqueIdentifier>{0a2328b4-ff6f-4afb-8de0-9884ae172fa9}</UniqueIdentifier>\r
- </Filter>\r
<Filter Include="Header Files\cds\gc\impl">\r
<UniqueIdentifier>{3195cce2-1710-4b79-a1cf-6c7cea085fa3}</UniqueIdentifier>\r
</Filter>\r
<Filter Include="Header Files\cds\algo\flat_combining">\r
<UniqueIdentifier>{fe703227-44ad-4ad6-bae4-b6c9f5c65355}</UniqueIdentifier>\r
</Filter>\r
+ <Filter Include="Header Files\cds\container">\r
+ <UniqueIdentifier>{84ca9e83-f6c9-4503-a45f-14f08317fd70}</UniqueIdentifier>\r
+ </Filter>\r
+ <Filter Include="Header Files\cds\container\details">\r
+ <UniqueIdentifier>{4b79fe31-4f6c-4e05-8910-1151a26d51f3}</UniqueIdentifier>\r
+ </Filter>\r
+ <Filter Include="Header Files\cds\container\striped_map">\r
+ <UniqueIdentifier>{6530b757-5bb7-4de0-b1c9-019acc8183ba}</UniqueIdentifier>\r
+ </Filter>\r
+ <Filter Include="Header Files\cds\container\striped_set">\r
+ <UniqueIdentifier>{d3f68c37-8c36-448e-9d4c-cd89a940d275}</UniqueIdentifier>\r
+ </Filter>\r
+ <Filter Include="Header Files\cds\container\impl">\r
+ <UniqueIdentifier>{0a2328b4-ff6f-4afb-8de0-9884ae172fa9}</UniqueIdentifier>\r
+ </Filter>\r
</ItemGroup>\r
<ItemGroup>\r
<ClCompile Include="..\..\..\src\dllmain.cpp">\r
<ClInclude Include="..\..\..\cds\algo\flat_combining\kernel.h">\r
<Filter>Header Files\cds\algo\flat_combining</Filter>\r
</ClInclude>\r
+ <ClInclude Include="..\..\..\cds\intrusive\details\iterable_list_base.h">\r
+ <Filter>Header Files\cds\intrusive\details</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\cds\intrusive\impl\iterable_list.h">\r
+ <Filter>Header Files\cds\intrusive\impl</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\cds\intrusive\iterable_list_dhp.h">\r
+ <Filter>Header Files\cds\intrusive</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\cds\intrusive\iterable_list_hp.h">\r
+ <Filter>Header Files\cds\intrusive</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\cds\container\details\iterable_list_base.h">\r
+ <Filter>Header Files\cds\container\details</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\cds\container\details\make_iterable_list.h">\r
+ <Filter>Header Files\cds\container\details</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\cds\container\details\make_iterable_kvlist.h">\r
+ <Filter>Header Files\cds\container\details</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\cds\container\impl\iterable_list.h">\r
+ <Filter>Header Files\cds\container\impl</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\cds\container\iterable_list_dhp.h">\r
+ <Filter>Header Files\cds\container</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\cds\container\iterable_list_hp.h">\r
+ <Filter>Header Files\cds\container</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\cds\container\impl\iterable_kvlist.h">\r
+ <Filter>Header Files\cds\container\impl</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\cds\container\iterable_kvlist_dhp.h">\r
+ <Filter>Header Files\cds\container</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\cds\container\iterable_kvlist_hp.h">\r
+ <Filter>Header Files\cds\container</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
</Project>
\ No newline at end of file
</ProjectConfiguration>\r
</ItemGroup>\r
<ItemGroup>\r
+ <ClCompile Include="..\..\..\test\unit\intrusive-set\intrusive_michael_iterable_dhp.cpp" />\r
+ <ClCompile Include="..\..\..\test\unit\intrusive-set\intrusive_michael_iterable_hp.cpp" />\r
<ClCompile Include="..\..\..\test\unit\main.cpp" />\r
<ClCompile Include="..\..\..\test\unit\intrusive-set\intrusive_feldman_hashset_dhp.cpp" />\r
<ClCompile Include="..\..\..\test\unit\intrusive-set\intrusive_feldman_hashset_hp.cpp" />\r
<ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_feldman_hashset.h" />\r
<ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_feldman_hashset_hp.h" />\r
<ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_feldman_hashset_rcu.h" />\r
+ <ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_michael_iterable.h" />\r
+ <ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_michael_iterable_hp.h" />\r
<ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_michael_lazy_rcu.h" />\r
<ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_michael_michael_rcu.h" />\r
<ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_set.h" />\r
<Optimization>Disabled</Optimization>\r
<PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
<AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+ <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r
+ <DisableSpecificWarnings>4503</DisableSpecificWarnings>\r
</ClCompile>\r
<Link>\r
<SubSystem>Console</SubSystem>\r
<Optimization>Disabled</Optimization>\r
<PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
<AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+ <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r
+ <DisableSpecificWarnings>4503</DisableSpecificWarnings>\r
</ClCompile>\r
<Link>\r
<SubSystem>Console</SubSystem>\r
<Optimization>Disabled</Optimization>\r
<PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
<AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+ <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r
+ <DisableSpecificWarnings>4503</DisableSpecificWarnings>\r
</ClCompile>\r
<Link>\r
<SubSystem>Console</SubSystem>\r
<Optimization>Disabled</Optimization>\r
<PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
<AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+ <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r
+ <DisableSpecificWarnings>4503</DisableSpecificWarnings>\r
</ClCompile>\r
<Link>\r
<SubSystem>Console</SubSystem>\r
<IntrinsicFunctions>true</IntrinsicFunctions>\r
<PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
<AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+ <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r
+ <DisableSpecificWarnings>4503</DisableSpecificWarnings>\r
</ClCompile>\r
<Link>\r
<SubSystem>Console</SubSystem>\r
<IntrinsicFunctions>true</IntrinsicFunctions>\r
<PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
<AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+ <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r
+ <DisableSpecificWarnings>4503</DisableSpecificWarnings>\r
</ClCompile>\r
<Link>\r
<SubSystem>Console</SubSystem>\r
<ClCompile Include="..\..\..\test\unit\intrusive-set\intrusive_feldman_hashset_rcu_sht.cpp">\r
<Filter>Source Files\FeldmanHashSet</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\test\unit\intrusive-set\intrusive_michael_iterable_hp.cpp">\r
+ <Filter>Source Files\MichaelSet</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\test\unit\intrusive-set\intrusive_michael_iterable_dhp.cpp">\r
+ <Filter>Source Files\MichaelSet</Filter>\r
+ </ClCompile>\r
</ItemGroup>\r
<ItemGroup>\r
<ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_set.h">\r
<ClInclude Include="..\..\..\test\unit\intrusive-set\test_michael_michael_rcu.h">\r
<Filter>Header Files</Filter>\r
</ClInclude>\r
+ <ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_michael_iterable.h">\r
+ <Filter>Header Files</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_michael_iterable_hp.h">\r
+ <Filter>Header Files</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
</Project>
\ No newline at end of file
</ProjectConfiguration>\r
</ItemGroup>\r
<ItemGroup>\r
+ <ClInclude Include="..\..\..\test\unit\list\test_intrusive_iterable_list.h" />\r
+ <ClInclude Include="..\..\..\test\unit\list\test_intrusive_iterable_list_hp.h" />\r
<ClInclude Include="..\..\..\test\unit\list\test_intrusive_lazy_rcu.h" />\r
<ClInclude Include="..\..\..\test\unit\list\test_intrusive_list.h" />\r
<ClInclude Include="..\..\..\test\unit\list\test_intrusive_list_hp.h" />\r
<ClInclude Include="..\..\..\test\unit\list\test_intrusive_list_nogc.h" />\r
<ClInclude Include="..\..\..\test\unit\list\test_intrusive_list_rcu.h" />\r
<ClInclude Include="..\..\..\test\unit\list\test_intrusive_michael_rcu.h" />\r
+ <ClInclude Include="..\..\..\test\unit\list\test_iterable_list.h" />\r
+ <ClInclude Include="..\..\..\test\unit\list\test_iterable_list_hp.h" />\r
+ <ClInclude Include="..\..\..\test\unit\list\test_kv_iterable_list.h" />\r
+ <ClInclude Include="..\..\..\test\unit\list\test_kv_iterable_list_hp.h" />\r
<ClInclude Include="..\..\..\test\unit\list\test_kv_lazy_rcu.h" />\r
<ClInclude Include="..\..\..\test\unit\list\test_kv_list.h" />\r
<ClInclude Include="..\..\..\test\unit\list\test_kv_list_hp.h" />\r
<ClInclude Include="..\..\..\test\unit\list\test_michael_rcu.h" />\r
</ItemGroup>\r
<ItemGroup>\r
+ <ClCompile Include="..\..\..\test\unit\list\intrusive_iterable_dhp.cpp" />\r
+ <ClCompile Include="..\..\..\test\unit\list\intrusive_iterable_hp.cpp" />\r
<ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_dhp.cpp" />\r
<ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_hp.cpp" />\r
<ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_nogc.cpp" />\r
<ClCompile Include="..\..\..\test\unit\list\intrusive_michael_rcu_shb.cpp" />\r
<ClCompile Include="..\..\..\test\unit\list\intrusive_michael_rcu_sht.cpp" />\r
<ClCompile Include="..\..\..\test\unit\list\intrusive_michael_nogc.cpp" />\r
+ <ClCompile Include="..\..\..\test\unit\list\iterable_dhp.cpp" />\r
+ <ClCompile Include="..\..\..\test\unit\list\iterable_hp.cpp" />\r
+ <ClCompile Include="..\..\..\test\unit\list\kv_iterable_dhp.cpp" />\r
+ <ClCompile Include="..\..\..\test\unit\list\kv_iterable_hp.cpp" />\r
<ClCompile Include="..\..\..\test\unit\list\kv_lazy_dhp.cpp" />\r
<ClCompile Include="..\..\..\test\unit\list\kv_lazy_hp.cpp" />\r
<ClCompile Include="..\..\..\test\unit\list\kv_lazy_nogc.cpp" />\r
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\r
</Filter>\r
+ <Filter Include="Source Files\iterable_list">\r
+ <UniqueIdentifier>{f6bc2494-0971-483b-98b2-7675d2aee7c9}</UniqueIdentifier>\r
+ </Filter>\r
+ <Filter Include="Source Files\lazy_list">\r
+ <UniqueIdentifier>{b975977c-e055-46d0-95ea-bc94c66c6d50}</UniqueIdentifier>\r
+ </Filter>\r
+ <Filter Include="Source Files\michael_list">\r
+ <UniqueIdentifier>{edd852ff-4431-4c46-9592-dbbba4d9846e}</UniqueIdentifier>\r
+ </Filter>\r
</ItemGroup>\r
<ItemGroup>\r
<ClInclude Include="..\..\..\test\unit\list\test_intrusive_list.h">\r
<ClInclude Include="..\..\..\test\unit\list\test_kv_lazy_rcu.h">\r
<Filter>Header Files</Filter>\r
</ClInclude>\r
+ <ClInclude Include="..\..\..\test\unit\list\test_intrusive_iterable_list_hp.h">\r
+ <Filter>Header Files</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\test\unit\list\test_intrusive_iterable_list.h">\r
+ <Filter>Header Files</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\test\unit\list\test_iterable_list.h">\r
+ <Filter>Header Files</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\test\unit\list\test_iterable_list_hp.h">\r
+ <Filter>Header Files</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\test\unit\list\test_kv_iterable_list.h">\r
+ <Filter>Header Files</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\test\unit\list\test_kv_iterable_list_hp.h">\r
+ <Filter>Header Files</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
<ItemGroup>\r
- <ClCompile Include="..\..\..\test\unit\list\intrusive_michael_hp.cpp">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
<ClCompile Include="..\..\..\test\unit\main.cpp">\r
<Filter>Source Files</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\intrusive_michael_dhp.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\intrusive_iterable_dhp.cpp">\r
+ <Filter>Source Files\iterable_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_hp.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\intrusive_iterable_hp.cpp">\r
+ <Filter>Source Files\iterable_list</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_dhp.cpp">\r
- <Filter>Source Files</Filter>\r
+ <Filter>Source Files\lazy_list</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_hp.cpp">\r
+ <Filter>Source Files\lazy_list</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_nogc.cpp">\r
- <Filter>Source Files</Filter>\r
+ <Filter>Source Files\lazy_list</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_rcu_gpb.cpp">\r
+ <Filter>Source Files\lazy_list</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_rcu_gpi.cpp">\r
+ <Filter>Source Files\lazy_list</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_rcu_gpt.cpp">\r
+ <Filter>Source Files\lazy_list</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_rcu_shb.cpp">\r
+ <Filter>Source Files\lazy_list</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_rcu_sht.cpp">\r
+ <Filter>Source Files\lazy_list</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\test\unit\list\intrusive_michael_dhp.cpp">\r
+ <Filter>Source Files\michael_list</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\test\unit\list\intrusive_michael_hp.cpp">\r
+ <Filter>Source Files\michael_list</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\test\unit\list\intrusive_michael_nogc.cpp">\r
- <Filter>Source Files</Filter>\r
+ <Filter>Source Files\michael_list</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\test\unit\list\intrusive_michael_rcu_gpb.cpp">\r
- <Filter>Source Files</Filter>\r
+ <Filter>Source Files\michael_list</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\test\unit\list\intrusive_michael_rcu_gpi.cpp">\r
- <Filter>Source Files</Filter>\r
+ <Filter>Source Files\michael_list</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\test\unit\list\intrusive_michael_rcu_gpt.cpp">\r
- <Filter>Source Files</Filter>\r
+ <Filter>Source Files\michael_list</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\test\unit\list\intrusive_michael_rcu_shb.cpp">\r
- <Filter>Source Files</Filter>\r
+ <Filter>Source Files\michael_list</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\test\unit\list\intrusive_michael_rcu_sht.cpp">\r
- <Filter>Source Files</Filter>\r
+ <Filter>Source Files\michael_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_rcu_gpb.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\kv_lazy_dhp.cpp">\r
+ <Filter>Source Files\lazy_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_rcu_gpi.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\kv_lazy_hp.cpp">\r
+ <Filter>Source Files\lazy_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_rcu_gpt.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\kv_lazy_nogc.cpp">\r
+ <Filter>Source Files\lazy_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_rcu_shb.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\kv_lazy_rcu_gpb.cpp">\r
+ <Filter>Source Files\lazy_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_rcu_sht.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\kv_lazy_rcu_gpi.cpp">\r
+ <Filter>Source Files\lazy_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\michael_hp.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\kv_lazy_rcu_gpt.cpp">\r
+ <Filter>Source Files\lazy_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\michael_dhp.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\kv_lazy_rcu_shb.cpp">\r
+ <Filter>Source Files\lazy_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\lazy_hp.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\kv_lazy_rcu_sht.cpp">\r
+ <Filter>Source Files\lazy_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\lazy_dhp.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\kv_michael_dhp.cpp">\r
+ <Filter>Source Files\michael_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\michael_nogc.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\kv_michael_hp.cpp">\r
+ <Filter>Source Files\michael_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\lazy_nogc.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\kv_michael_nogc.cpp">\r
+ <Filter>Source Files\michael_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\michael_rcu_gpb.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\kv_michael_rcu_gpb.cpp">\r
+ <Filter>Source Files\michael_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\michael_rcu_gpi.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\kv_michael_rcu_gpi.cpp">\r
+ <Filter>Source Files\michael_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\michael_rcu_gpt.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\kv_michael_rcu_gpt.cpp">\r
+ <Filter>Source Files\michael_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\michael_rcu_shb.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\kv_michael_rcu_shb.cpp">\r
+ <Filter>Source Files\michael_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\michael_rcu_sht.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\kv_michael_rcu_sht.cpp">\r
+ <Filter>Source Files\michael_list</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\test\unit\list\lazy_dhp.cpp">\r
+ <Filter>Source Files\lazy_list</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\test\unit\list\lazy_hp.cpp">\r
+ <Filter>Source Files\lazy_list</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\test\unit\list\lazy_nogc.cpp">\r
+ <Filter>Source Files\lazy_list</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\test\unit\list\lazy_rcu_gpb.cpp">\r
- <Filter>Source Files</Filter>\r
+ <Filter>Source Files\lazy_list</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\test\unit\list\lazy_rcu_gpi.cpp">\r
- <Filter>Source Files</Filter>\r
+ <Filter>Source Files\lazy_list</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\test\unit\list\lazy_rcu_gpt.cpp">\r
- <Filter>Source Files</Filter>\r
+ <Filter>Source Files\lazy_list</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\test\unit\list\lazy_rcu_shb.cpp">\r
- <Filter>Source Files</Filter>\r
+ <Filter>Source Files\lazy_list</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\..\test\unit\list\lazy_rcu_sht.cpp">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\kv_michael_hp.cpp">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\kv_michael_dhp.cpp">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\kv_lazy_hp.cpp">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\kv_lazy_dhp.cpp">\r
- <Filter>Source Files</Filter>\r
+ <Filter>Source Files\lazy_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\kv_michael_nogc.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\michael_dhp.cpp">\r
+ <Filter>Source Files\michael_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\kv_lazy_nogc.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\michael_hp.cpp">\r
+ <Filter>Source Files\michael_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\kv_michael_rcu_gpb.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\michael_nogc.cpp">\r
+ <Filter>Source Files\michael_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\kv_michael_rcu_gpi.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\michael_rcu_gpb.cpp">\r
+ <Filter>Source Files\michael_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\kv_michael_rcu_gpt.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\michael_rcu_gpi.cpp">\r
+ <Filter>Source Files\michael_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\kv_michael_rcu_shb.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\michael_rcu_gpt.cpp">\r
+ <Filter>Source Files\michael_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\kv_michael_rcu_sht.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\michael_rcu_shb.cpp">\r
+ <Filter>Source Files\michael_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\kv_lazy_rcu_gpb.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\michael_rcu_sht.cpp">\r
+ <Filter>Source Files\michael_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\kv_lazy_rcu_gpi.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\iterable_hp.cpp">\r
+ <Filter>Source Files\iterable_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\kv_lazy_rcu_gpt.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\iterable_dhp.cpp">\r
+ <Filter>Source Files\iterable_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\kv_lazy_rcu_shb.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\kv_iterable_hp.cpp">\r
+ <Filter>Source Files\iterable_list</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\..\test\unit\list\kv_lazy_rcu_sht.cpp">\r
- <Filter>Source Files</Filter>\r
+ <ClCompile Include="..\..\..\test\unit\list\kv_iterable_dhp.cpp">\r
+ <Filter>Source Files\iterable_list</Filter>\r
</ClCompile>\r
</ItemGroup>\r
</Project>
\ No newline at end of file
<ClCompile Include="..\..\..\test\unit\set\feldman_hashset_rcu_gpt.cpp" />\r
<ClCompile Include="..\..\..\test\unit\set\feldman_hashset_rcu_shb.cpp" />\r
<ClCompile Include="..\..\..\test\unit\set\feldman_hashset_rcu_sht.cpp" />\r
+ <ClCompile Include="..\..\..\test\unit\set\michael_iterable_dhp.cpp" />\r
+ <ClCompile Include="..\..\..\test\unit\set\michael_iterable_hp.cpp" />\r
<ClCompile Include="..\..\..\test\unit\set\michael_lazy_dhp.cpp">\r
<DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">4503</DisableSpecificWarnings>\r
<DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='DebugVLD|Win32'">4503</DisableSpecificWarnings>\r
<ClInclude Include="..\..\..\test\unit\set\test_feldman_hashset.h" />\r
<ClInclude Include="..\..\..\test\unit\set\test_feldman_hashset_hp.h" />\r
<ClInclude Include="..\..\..\test\unit\set\test_feldman_hashset_rcu.h" />\r
+ <ClInclude Include="..\..\..\test\unit\set\test_michael_iterable.h" />\r
+ <ClInclude Include="..\..\..\test\unit\set\test_michael_iterable_hp.h" />\r
<ClInclude Include="..\..\..\test\unit\set\test_michael_lazy_rcu.h" />\r
<ClInclude Include="..\..\..\test\unit\set\test_michael_michael_rcu.h" />\r
<ClInclude Include="..\..\..\test\unit\set\test_ordered_set_hp.h" />\r
<ClInclude Include="..\..\..\test\unit\set\test_set.h" />\r
+ <ClInclude Include="..\..\..\test\unit\set\test_set_data.h" />\r
<ClInclude Include="..\..\..\test\unit\set\test_set_hp.h" />\r
<ClInclude Include="..\..\..\test\unit\set\test_set_nogc.h" />\r
<ClInclude Include="..\..\..\test\unit\set\test_set_rcu.h" />\r
<PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
<AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r
+ <DisableSpecificWarnings>4503</DisableSpecificWarnings>\r
</ClCompile>\r
<Link>\r
<SubSystem>Console</SubSystem>\r
<PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
<AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r
+ <DisableSpecificWarnings>4503</DisableSpecificWarnings>\r
</ClCompile>\r
<Link>\r
<SubSystem>Console</SubSystem>\r
<PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
<AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r
+ <DisableSpecificWarnings>4503</DisableSpecificWarnings>\r
</ClCompile>\r
<Link>\r
<SubSystem>Console</SubSystem>\r
<PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
<AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r
+ <DisableSpecificWarnings>4503</DisableSpecificWarnings>\r
</ClCompile>\r
<Link>\r
<SubSystem>Console</SubSystem>\r
<PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
<AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r
+ <DisableSpecificWarnings>4503</DisableSpecificWarnings>\r
</ClCompile>\r
<Link>\r
<SubSystem>Console</SubSystem>\r
<PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
<AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r
+ <DisableSpecificWarnings>4503</DisableSpecificWarnings>\r
</ClCompile>\r
<Link>\r
<SubSystem>Console</SubSystem>\r
<ClCompile Include="..\..\..\test\unit\set\feldman_hashset_rcu_sht.cpp">\r
<Filter>Source Files\FeldmanHashSet</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\..\..\test\unit\set\michael_iterable_hp.cpp">\r
+ <Filter>Source Files\MichaelSet</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\test\unit\set\michael_iterable_dhp.cpp">\r
+ <Filter>Source Files\MichaelSet</Filter>\r
+ </ClCompile>\r
</ItemGroup>\r
<ItemGroup>\r
<ClInclude Include="..\..\..\test\unit\set\test_set.h">\r
<ClInclude Include="..\..\..\test\unit\set\test_ordered_set_hp.h">\r
<Filter>Header Files</Filter>\r
</ClInclude>\r
+ <ClInclude Include="..\..\..\test\unit\set\test_michael_iterable.h">\r
+ <Filter>Header Files</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\test\unit\set\test_michael_iterable_hp.h">\r
+ <Filter>Header Files</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\test\unit\set\test_set_data.h">\r
+ <Filter>Header Files</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
</Project>
\ No newline at end of file
</ItemGroup>\r
<ItemGroup>\r
<ClInclude Include="..\..\..\test\include\cds_test\stress_test.h" />\r
+ <ClInclude Include="..\..\..\test\stress\framework\city.h" />\r
<ClInclude Include="..\..\..\test\stress\framework\ellen_bintree_update_desc_pool.h" />\r
<ClInclude Include="..\..\..\test\stress\framework\michael_alloc.h" />\r
</ItemGroup>\r
<ClInclude Include="..\..\..\test\stress\framework\ellen_bintree_update_desc_pool.h">\r
<Filter>Header Files</Filter>\r
</ClInclude>\r
+ <ClInclude Include="..\..\..\test\stress\framework\city.h">\r
+ <Filter>Header Files</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
<ItemGroup>\r
<ClCompile Include="..\..\..\test\stress\framework\config.cpp">\r
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="DebugVLD|Win32">
+ <Configuration>DebugVLD</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="DebugVLD|x64">
+ <Configuration>DebugVLD</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\..\test\stress\main.cpp" />
+ <ClCompile Include="..\..\..\test\stress\set\iteration\set_iteration.cpp" />
+ <ClCompile Include="..\..\..\test\stress\set\iteration\set_iteration_feldman_hashset.cpp" />
+ <ClCompile Include="..\..\..\test\stress\set\iteration\set_iteration_michael.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\..\test\stress\set\iteration\set_iteration.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <Text Include="..\..\..\test\stress\set\iteration\CMakeLists.txt" />
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>stress_set_iteration</RootNamespace>
+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
+ <ProjectName>stress-set-iteration</ProjectName>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v140</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugVLD|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v140</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v140</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v140</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugVLD|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v140</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v140</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="Shared">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugVLD|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugVLD|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>$(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)\</OutDir>
+ <IntDir>$(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
+ <TargetName>$(ProjectName)_d</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugVLD|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>$(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)\</OutDir>
+ <IntDir>$(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
+ <TargetName>$(ProjectName)_d</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>$(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)\</OutDir>
+ <IntDir>$(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
+ <TargetName>$(ProjectName)_d</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugVLD|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>$(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)\</OutDir>
+ <IntDir>$(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
+ <TargetName>$(ProjectName)_d</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)-release\</OutDir>
+ <IntDir>$(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)-release\</OutDir>
+ <IntDir>$(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;CDSUNIT_USE_URCU;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(SolutionDir)..\..\..\test\stress\set;$(SolutionDir)..\..\..\test\stress\;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalLibraryDirectories>$(GTEST_LIB32);$(GTEST_ROOT)/lib/x86;$(BOOST_PATH)/stage32/lib;$(BOOST_PATH)/stage/lib;$(BOOST_PATH)/bin;%(AdditionalLibraryDirectories);$(OutDir)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>gtestd.lib;stress-framework_d.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugVLD|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;CDSUNIT_USE_URCU;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(SolutionDir)..\..\..\test\stress\set;$(SolutionDir)..\..\..\test\stress\;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalLibraryDirectories>$(GTEST_LIB32);$(GTEST_ROOT)/lib/x86;$(BOOST_PATH)/stage32/lib;$(BOOST_PATH)/stage/lib;$(BOOST_PATH)/bin;%(AdditionalLibraryDirectories);$(OutDir)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>gtestd.lib;stress-framework_d.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;CDSUNIT_USE_URCU;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(SolutionDir)..\..\..\test\stress\set;$(SolutionDir)..\..\..\test\stress\;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalLibraryDirectories>$(GTEST_LIB64);$(GTEST_ROOT)/lib/x64;$(BOOST_PATH)/stage64/lib;$(BOOST_PATH)/bin;%(AdditionalLibraryDirectories);$(OutDir)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>gtestd.lib;stress-framework_d.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugVLD|x64'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;CDSUNIT_USE_URCU;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(SolutionDir)..\..\..\test\stress\set;$(SolutionDir)..\..\..\test\stress\;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalLibraryDirectories>$(GTEST_LIB64);$(GTEST_ROOT)/lib/x64;$(BOOST_PATH)/stage64/lib;$(BOOST_PATH)/bin;%(AdditionalLibraryDirectories);$(OutDir)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>gtestd.lib;stress-framework_d.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;CDSUNIT_USE_URCU;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(SolutionDir)..\..\..\test\stress\set;$(SolutionDir)..\..\..\test\stress\;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalLibraryDirectories>$(GTEST_LIB32);$(GTEST_ROOT)/lib/x86;$(BOOST_PATH)/stage32/lib;$(BOOST_PATH)/stage/lib;$(BOOST_PATH)/bin;%(AdditionalLibraryDirectories);$(OutDir)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>gtest.lib;stress-framework.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;CDSUNIT_USE_URCU;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(SolutionDir)..\..\..\test\stress\set;$(SolutionDir)..\..\..\test\stress\;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalLibraryDirectories>$(GTEST_LIB64);$(GTEST_ROOT)/lib/x64;$(BOOST_PATH)/stage64/lib;$(BOOST_PATH)/bin;%(AdditionalLibraryDirectories);$(OutDir)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>gtest.lib;stress-framework.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\..\test\stress\main.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\test\stress\set\iteration\set_iteration.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\test\stress\set\iteration\set_iteration_feldman_hashset.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\test\stress\set\iteration\set_iteration_michael.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\..\test\stress\set\iteration\set_iteration.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <Text Include="..\..\..\test\stress\set\iteration\CMakeLists.txt" />
+ </ItemGroup>
+</Project>
\ No newline at end of file
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSTEST_STAT_ITERABLE_LIST_OUT_H
+#define CDSTEST_STAT_ITERABLE_LIST_OUT_H
+
+#include <cds/intrusive/details/iterable_list_base.h>
+
+namespace cds_test {
+
+ static inline property_stream& operator <<( property_stream& o, cds::intrusive::iterable_list::empty_stat const& /*s*/ )
+ {
+ return o;
+ }
+
+ static inline property_stream& operator <<( property_stream& o, cds::intrusive::iterable_list::stat<> const& s )
+ {
+ return o
+ << CDSSTRESS_STAT_OUT( s, m_nInsertSuccess )
+ << CDSSTRESS_STAT_OUT( s, m_nInsertFailed )
+ << CDSSTRESS_STAT_OUT( s, m_nInsertRetry )
+ << CDSSTRESS_STAT_OUT( s, m_nUpdateNew )
+ << CDSSTRESS_STAT_OUT( s, m_nUpdateExisting )
+ << CDSSTRESS_STAT_OUT( s, m_nUpdateFailed )
+ << CDSSTRESS_STAT_OUT( s, m_nUpdateRetry )
+ << CDSSTRESS_STAT_OUT( s, m_nEraseSuccess )
+ << CDSSTRESS_STAT_OUT( s, m_nEraseFailed )
+ << CDSSTRESS_STAT_OUT( s, m_nEraseRetry )
+ << CDSSTRESS_STAT_OUT( s, m_nFindSuccess )
+ << CDSSTRESS_STAT_OUT( s, m_nFindFailed )
+ << CDSSTRESS_STAT_OUT( s, m_nNodeCreated )
+ << CDSSTRESS_STAT_OUT( s, m_nNodeRemoved );
+ }
+
+ template <typename Stat>
+ static inline property_stream& operator <<( property_stream& o, cds::intrusive::iterable_list::wrapped_stat<Stat> const& s )
+ {
+ return o << s.m_stat;
+ }
+
+} // namespace cds_test
+
+#endif // #ifndef CDSTEST_STAT_ITERABLE_LIST_OUT_H
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSTEST_STAT_LAZY_LIST_OUT_H
+#define CDSTEST_STAT_LAZY_LIST_OUT_H
+
+#include <cds/intrusive/details/lazy_list_base.h>
+
+namespace cds_test {
+
+ static inline property_stream& operator <<( property_stream& o, cds::intrusive::lazy_list::empty_stat const& /*s*/ )
+ {
+ return o;
+ }
+
+ static inline property_stream& operator <<( property_stream& o, cds::intrusive::lazy_list::stat<> const& s )
+ {
+ return o
+ << CDSSTRESS_STAT_OUT( s, m_nInsertSuccess )
+ << CDSSTRESS_STAT_OUT( s, m_nInsertFailed )
+ << CDSSTRESS_STAT_OUT( s, m_nInsertRetry )
+ << CDSSTRESS_STAT_OUT( s, m_nUpdateNew )
+ << CDSSTRESS_STAT_OUT( s, m_nUpdateExisting )
+ << CDSSTRESS_STAT_OUT( s, m_nUpdateFailed )
+ << CDSSTRESS_STAT_OUT( s, m_nUpdateRetry )
+ << CDSSTRESS_STAT_OUT( s, m_nUpdateMarked )
+ << CDSSTRESS_STAT_OUT( s, m_nEraseSuccess )
+ << CDSSTRESS_STAT_OUT( s, m_nEraseFailed )
+ << CDSSTRESS_STAT_OUT( s, m_nEraseRetry )
+ << CDSSTRESS_STAT_OUT( s, m_nFindSuccess )
+ << CDSSTRESS_STAT_OUT( s, m_nFindFailed )
+ << CDSSTRESS_STAT_OUT( s, m_nValidationSuccess )
+ << CDSSTRESS_STAT_OUT( s, m_nValidationFailed );
+ }
+
+ template <typename Stat>
+ static inline property_stream& operator <<( property_stream& o, cds::intrusive::lazy_list::wrapped_stat<Stat> const& s )
+ {
+ return o << s.m_stat;
+ }
+
+} // namespace cds_test
+
+#endif // #ifndef CDSTEST_STAT_LAZY_LIST_OUT_H
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSTEST_STAT_MICHAEL_LIST_OUT_H
+#define CDSTEST_STAT_MICHAEL_LIST_OUT_H
+
+#include <cds/intrusive/details/michael_list_base.h>
+
+namespace cds_test {
+
+ static inline property_stream& operator <<( property_stream& o, cds::intrusive::michael_list::empty_stat const& /*s*/ )
+ {
+ return o;
+ }
+
+ static inline property_stream& operator <<( property_stream& o, cds::intrusive::michael_list::stat<> const& s )
+ {
+ return o
+ << CDSSTRESS_STAT_OUT( s, m_nInsertSuccess )
+ << CDSSTRESS_STAT_OUT( s, m_nInsertFailed )
+ << CDSSTRESS_STAT_OUT( s, m_nInsertRetry )
+ << CDSSTRESS_STAT_OUT( s, m_nUpdateNew )
+ << CDSSTRESS_STAT_OUT( s, m_nUpdateExisting )
+ << CDSSTRESS_STAT_OUT( s, m_nUpdateFailed )
+ << CDSSTRESS_STAT_OUT( s, m_nUpdateRetry )
+ << CDSSTRESS_STAT_OUT( s, m_nUpdateMarked )
+ << CDSSTRESS_STAT_OUT( s, m_nEraseSuccess )
+ << CDSSTRESS_STAT_OUT( s, m_nEraseFailed )
+ << CDSSTRESS_STAT_OUT( s, m_nEraseRetry )
+ << CDSSTRESS_STAT_OUT( s, m_nFindSuccess )
+ << CDSSTRESS_STAT_OUT( s, m_nFindFailed )
+ << CDSSTRESS_STAT_OUT( s, m_nHelpingSuccess )
+ << CDSSTRESS_STAT_OUT( s, m_nHelpingFailed );
+ }
+
+ template <typename Stat>
+ static inline property_stream& operator <<( property_stream& o, cds::intrusive::michael_list::wrapped_stat<Stat> const& s )
+ {
+ return o << s.m_stat;
+ }
+
+} // namespace cds_test
+
+#endif // #ifndef CDSTEST_STAT_MICHAEL_LIST_OUT_H
\r
[queue_push]\r
ThreadCount=8\r
-QueueSize=500000\r
+QueueSize=3000000\r
# SegmentedQueue parameters:\r
# SegmentedQueue_Iterate: \r
# 1 - run test iteratively for segment size from 4 up to SegmentedQueue_SegmentSize\r
\r
[queue_pop]\r
ThreadCount=8\r
-QueueSize=500000\r
+QueueSize=3000000\r
# SegmentedQueue parameters:\r
# SegmentedQueue_Iterate: \r
# 1 - run test iteratively for segment size from 4 up to SegmentedQueue_SegmentSize\r
[queue_push_pop]\r
ConsumerCount=4\r
ProducerCount=4\r
-QueueSize=500000\r
+QueueSize=3000000\r
# SegmentedQueue parameters:\r
# SegmentedQueue_Iterate: \r
# 1 - run test iteratively for segment size from 4 up to SegmentedQueue_SegmentSize\r
\r
[queue_random]\r
ThreadCount=8\r
-QueueSize=500000\r
+QueueSize=3000000\r
# SegmentedQueue parameters:\r
# SegmentedQueue_Iterate: \r
# 1 - run test iteratively for segment size from 4 up to SegmentedQueue_SegmentSize\r
[intrusive_queue_push_pop]\r
ReaderCount=4\r
WriterCount=4\r
-QueueSize=500000\r
+QueueSize=3000000\r
# Flat combining queue parameters\r
FCCompactFactor=64\r
FCPassCount=8\r
}
if (len > 0) {
s = s + len - 40;
+ // cppcheck-suppress uselessAssignmentPtrArg
CHUNK(33);
e ^= Rotate(a, 43);
h += Rotate(b, 42);
{}
// boost::container::flat_map requires operator =
+ // cppcheck-suppress operatorEqVarError
value_type& operator=( value_type const& v )
{
nKey = v.nKey;
typedef cds_test::stress_fixture base_class;
protected:
- template <class PQueue>
- class Producer: public cds_test::thread
- {
- typedef cds_test::thread base_class;
-
- public:
- Producer( cds_test::thread_pool& pool, PQueue& queue )
- : base_class( pool )
- , m_Queue( queue )
- {}
-
- Producer( Producer& src )
- : base_class( src )
- , m_Queue( src.m_Queue )
- {}
-
- virtual thread * clone()
- {
- return new Producer( *this );
- }
-
- virtual void test()
- {
- typedef typename PQueue::value_type value_type;
- for ( array_type::const_iterator it = m_arr.begin(); it != m_arr.end(); ++it ) {
- if ( !m_Queue.push( value_type( *it ) ))
- ++m_nPushError;
- }
- }
-
- void prepare( size_t nStart, size_t nEnd )
- {
- m_arr.reserve( nEnd - nStart );
- for ( size_t i = nStart; i < nEnd; ++i )
- m_arr.push_back( i );
- shuffle( m_arr.begin(), m_arr.end() );
- }
-
- public:
- PQueue& m_Queue;
- size_t m_nPushError = 0;
-
- typedef std::vector<size_t> array_type;
- array_type m_arr;
- };
-
template <class PQueue>
class Consumer: public cds_test::thread
{
++m_nPopSuccess;
nPrevKey = val.key;
- while ( !m_Queue.empty() ) {
- if ( m_Queue.pop( val )) {
- ++m_nPopSuccess;
- if ( val.key > nPrevKey )
- ++m_nPopError;
- else if ( val.key == nPrevKey )
- ++m_nPopErrorEq;
- nPrevKey = val.key;
+ bool prevPopFailed = false;
+ while ( m_Queue.pop( val )) {
+ ++m_nPopSuccess;
+ if ( val.key > nPrevKey ) {
+ ++m_nPopError;
+ m_arrFailedPops.emplace_back( failed_pops{ nPrevKey, val.key, static_cast<size_t>(-1) } );
+ prevPopFailed = true;
+ }
+ else if ( val.key == nPrevKey ) {
+ ++m_nPopErrorEq;
+ m_arrFailedPops.emplace_back( failed_pops{ nPrevKey, val.key, static_cast<size_t>(-1) } );
}
- else
- ++m_nPopFailed;
+ else {
+ if ( prevPopFailed )
+ m_arrFailedPops.back().next_key = val.key;
+ prevPopFailed = false;
+ }
+ if ( nPrevKey > val.key )
+ nPrevKey = val.key;
}
+
}
else
++m_nPopFailed;
size_t m_nPopErrorEq = 0;
size_t m_nPopSuccess = 0;
size_t m_nPopFailed = 0;
+
+ struct failed_pops {
+ size_t prev_key;
+ size_t popped_key;
+ size_t next_key;
+ };
+ std::vector< failed_pops > m_arrFailedPops;
};
protected:
template <class PQueue>
void test( PQueue& q )
{
- size_t const nThreadItemCount = s_nQueueSize / s_nThreadCount;
- s_nQueueSize = nThreadItemCount * s_nThreadCount;
-
cds_test::thread_pool& pool = get_pool();
- propout() << std::make_pair( "thread_count", s_nThreadCount )
- << std::make_pair( "push_count", s_nQueueSize );
-
// push
{
- pool.add( new Producer<PQueue>( pool, q ), s_nThreadCount );
+ std::vector< size_t > arr;
+ arr.reserve( s_nQueueSize );
+ for ( size_t i = 0; i < s_nQueueSize; ++i )
+ arr.push_back( i );
+ shuffle( arr.begin(), arr.end() );
- size_t nStart = 0;
- for ( size_t i = 0; i < pool.size(); ++i ) {
- static_cast<Producer<PQueue>&>( pool.get(i) ).prepare( nStart, nStart + nThreadItemCount );
- nStart += nThreadItemCount;
+ size_t nPushError = 0;
+ typedef typename PQueue::value_type value_type;
+ for ( auto it = arr.begin(); it != arr.end(); ++it ) {
+ if ( !q.push( value_type( *it ) ))
+ ++nPushError;
}
-
- std::chrono::milliseconds duration = pool.run();
- propout() << std::make_pair( "producer_duration", duration );
+ s_nQueueSize -= nPushError;
}
+ propout() << std::make_pair( "thread_count", s_nThreadCount )
+ << std::make_pair( "push_count", s_nQueueSize );
+
// pop
{
- pool.clear();
pool.add( new Consumer<PQueue>( pool, q ), s_nThreadCount );
std::chrono::milliseconds duration = pool.run();
nTotalError += cons.m_nPopError;
nTotalErrorEq += cons.m_nPopErrorEq;
nTotalFailed += cons.m_nPopFailed;
+
+ if ( !cons.m_arrFailedPops.empty() ) {
+ std::cerr << "Priority violations, thread " << i;
+ for ( size_t k = 0; k < cons.m_arrFailedPops.size(); ++k ) {
+ std::cerr << "\n " << "prev_key=" << cons.m_arrFailedPops[k].prev_key << " popped_key=" << cons.m_arrFailedPops[k].popped_key;
+ if ( cons.m_arrFailedPops[k].next_key != static_cast<size_t>(-1) )
+ std::cerr << " next_key=" << cons.m_arrFailedPops[k].next_key;
+ else
+ std::cerr << " next_key unspecified";
+ }
+ std::cerr << std::endl;
+ }
}
propout()
<< std::make_pair( "error_priority_violation", nTotalError );
EXPECT_EQ( nTotalPopped, s_nQueueSize );
- EXPECT_EQ( nTotalError, 0 );
- EXPECT_EQ( nTotalErrorEq, 0 );
+ EXPECT_EQ( nTotalError, 0 ) << "priority violations";
+ EXPECT_EQ( nTotalErrorEq, 0 ) << "double key";
}
propout() << q.statistics();
TEST_F( fixture_t, pqueue_t ) \
{ \
typedef pqueue::Types<pqueue::simple_value>::pqueue_t pqueue_type; \
- pqueue_type pq( s_nQueueSize ); \
+ pqueue_type pq( s_nQueueSize + 1 ); \
test( pq ); \
}
CDSSTRESS_MSPriorityQueue( pqueue_pop, MSPriorityQueue_dyn_less )
//CDSSTRESS_MSPriorityQueue( pqueue_pop, MSPriorityQueue_static_less )
//CDSSTRESS_MSPriorityQueue( pqueue_pop, MSPriorityQueue_static_less_stat )
//CDSSTRESS_MSPriorityQueue( pqueue_pop, MSPriorityQueue_static_cmp )
- //CDSSTRESS_MSPriorityQueue( pqueue_pop, 1MSPriorityQueue_static_mutex )
+ //CDSSTRESS_MSPriorityQueue( pqueue_pop, MSPriorityQueue_static_mutex )
#define CDSSTRESS_PriorityQueue( fixture_t, pqueue_t ) \
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSSTRESS_PQUEUE_TYPES_H
{};
typedef cc::MSPriorityQueue< Value, traits_MSPriorityQueue_static_mutex > MSPriorityQueue_static_mutex;
- struct traits_MSPriorityQueue_dyn_less : public
- cc::mspriority_queue::make_traits<
- co::buffer< co::v::initialized_dynamic_buffer< char > >
- >::type
- {};
- typedef cc::MSPriorityQueue< Value, traits_MSPriorityQueue_dyn_less > MSPriorityQueue_dyn_less;
+ struct traits_MSPriorityQueue_dyn: public cc::mspriority_queue::traits
+ {
+ typedef co::v::initialized_dynamic_buffer< char > buffer;
+ };
+ typedef cc::MSPriorityQueue< Value, traits_MSPriorityQueue_dyn > MSPriorityQueue_dyn_less;
- struct traits_MSPriorityQueue_dyn_less_stat : public
- cc::mspriority_queue::make_traits <
- co::buffer< co::v::initialized_dynamic_buffer< char > >
- , co::stat < cc::mspriority_queue::stat<> >
- > ::type
- {};
+ struct traits_MSPriorityQueue_dyn_less_stat: public traits_MSPriorityQueue_dyn
+ {
+ typedef cc::mspriority_queue::stat<> stat;
+ };
typedef cc::MSPriorityQueue< Value, traits_MSPriorityQueue_dyn_less_stat > MSPriorityQueue_dyn_less_stat;
+
struct traits_MSPriorityQueue_dyn_cmp : public
cc::mspriority_queue::make_traits <
co::buffer< co::v::initialized_dynamic_buffer< char > >
<< CDSSTRESS_STAT_OUT( s, m_nPushFailCount )
<< CDSSTRESS_STAT_OUT( s, m_nPopFailCount )
<< CDSSTRESS_STAT_OUT( s, m_nPushHeapifySwapCount )
- << CDSSTRESS_STAT_OUT( s, m_nPopHeapifySwapCount );
+ << CDSSTRESS_STAT_OUT( s, m_nPopHeapifySwapCount )
+ << CDSSTRESS_STAT_OUT( s, m_nItemMovedTop )
+ << CDSSTRESS_STAT_OUT( s, m_nItemMovedUp )
+ << CDSSTRESS_STAT_OUT( s, m_nPushEmptyPass );
}
} // namespace cds_test
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "pqueue_type.h"
//CDSSTRESS_MSPriorityQueue( pqueue_push, MSPriorityQueue_static_less )
//CDSSTRESS_MSPriorityQueue( pqueue_push, MSPriorityQueue_static_less_stat )
//CDSSTRESS_MSPriorityQueue( pqueue_push, MSPriorityQueue_static_cmp )
- //CDSSTRESS_MSPriorityQueue( pqueue_push, 1MSPriorityQueue_static_mutex )
+ //CDSSTRESS_MSPriorityQueue( pqueue_push, MSPriorityQueue_static_mutex )
#define CDSSTRESS_PriorityQueue( fixture_t, pqueue_t ) \
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "pqueue_type.h"
CDSSTRESS_MSPriorityQueue( pqueue_push_pop, MSPriorityQueue_dyn_less )
CDSSTRESS_MSPriorityQueue( pqueue_push_pop, MSPriorityQueue_dyn_less_stat )
CDSSTRESS_MSPriorityQueue( pqueue_push_pop, MSPriorityQueue_dyn_cmp )
- //CDSSTRESS_MSPriorityQueue( pqueue_push_pop, MSPriorityQueue_dyn_mutex ) too slow
+ //CDSSTRESS_MSPriorityQueue( pqueue_push_pop, MSPriorityQueue_dyn_mutex ) // too slow
#define CDSSTRESS_MSPriorityQueue_static( fixture_t, pqueue_t ) \
TEST_F( fixture_t, pqueue_t ) \
//CDSSTRESS_MSPriorityQueue( pqueue_push_pop, MSPriorityQueue_static_less )
//CDSSTRESS_MSPriorityQueue( pqueue_push_pop, MSPriorityQueue_static_less_stat )
//CDSSTRESS_MSPriorityQueue( pqueue_push_pop, MSPriorityQueue_static_cmp )
- //CDSSTRESS_MSPriorityQueue( pqueue_push_pop, 1MSPriorityQueue_static_mutex )
+ //CDSSTRESS_MSPriorityQueue( pqueue_push_pop, MSPriorityQueue_static_mutex )
#define CDSSTRESS_PriorityQueue( fixture_t, pqueue_t ) \
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/insdel_find)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/insdel_func)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/insdel_string)
+add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/iteration)
add_custom_target( stress-set
DEPENDS
stress-set-insdelfind
stress-set-insdel-func
stress-set-insdel-string
+ stress-set-iteration
)
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "set_delodd.h"
namespace set {
CDSSTRESS_MichaelSet( Set_DelOdd_LF, run_test_extract, key_thread, size_t )
+ CDSSTRESS_MichaelIterableSet( Set_DelOdd_LF, run_test_extract, key_thread, size_t )
} // namespace set
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "set_insdelfind.h"
namespace set {
CDSSTRESS_MichaelSet( Set_InsDelFind_LF, run_test, size_t, size_t )
+ CDSSTRESS_MichaelIterableSet( Set_InsDelFind_LF, run_test, size_t, size_t )
} // namespace set
{}
// boost::container::flat_map requires operator =
+ // cppcheck-suppress operatorEqVarError
value& operator=( value const& v )
{
nKey = v.nKey;
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "set_insdel_func.h"
namespace set {
CDSSTRESS_MichaelSet( Set_InsDel_func_LF, run_test, size_t, value )
+ CDSSTRESS_MichaelIterableSet( Set_InsDel_func_LF, run_test, size_t, value )
} // namespace set
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "set_insdel_string.h"
void Set_InsDel_string::SetUpTestCase()
{
- cds_test::config const& cfg = get_config( "map_insdel_func" );
+ cds_test::config const& cfg = get_config( "map_insdel_string" );
s_nSetSize = cfg.get_size_t( "MapSize", s_nSetSize );
if ( s_nSetSize < 1000 )
std::vector<size_t> Set_InsDel_string_LF::get_load_factors()
{
- cds_test::config const& cfg = get_config( "map_insdel_func" );
+ cds_test::config const& cfg = get_config( "map_insdel_string" );
s_nMaxLoadFactor = cfg.get_size_t( "MaxLoadFactor", s_nMaxLoadFactor );
if ( s_nMaxLoadFactor == 0 )
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "set_insdel_string.h"
namespace set {
CDSSTRESS_MichaelSet( Set_InsDel_string_LF, run_test_extract, std::string, size_t )
+ CDSSTRESS_MichaelIterableSet( Set_InsDel_string_LF, run_test_extract, std::string, size_t )
} // namespace set
--- /dev/null
+set(PACKAGE_NAME stress-set-iteration)
+
+set(CDSSTRESS_SET_ITERATION_SOURCES
+ ../../main.cpp
+ set_iteration.cpp
+ set_iteration_feldman_hashset.cpp
+ set_iteration_michael.cpp
+)
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/..
+)
+
+add_executable(${PACKAGE_NAME} ${CDSSTRESS_SET_ITERATION_SOURCES} $<TARGET_OBJECTS:${CDSSTRESS_FRAMEWORK_LIBRARY}>)
+target_link_libraries(${PACKAGE_NAME}
+ ${CDS_SHARED_LIBRARY}
+ ${GTEST_LIBRARY}
+ ${Boost_THREAD_LIBRARY}
+ ${Boost_SYSTEM_LIBRARY}
+ ${CMAKE_THREAD_LIBS_INIT}
+)
+
+add_test(NAME ${PACKAGE_NAME} COMMAND ${PACKAGE_NAME} WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH})
\ No newline at end of file
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "set_iteration.h"
+
+namespace set {
+
+ size_t Set_Iteration::s_nSetSize = 1000000; // set size
+ size_t Set_Iteration::s_nInsertThreadCount = 4; // count of insertion thread
+ size_t Set_Iteration::s_nDeleteThreadCount = 4; // count of deletion thread
+ size_t Set_Iteration::s_nThreadPassCount = 4; // pass count for each thread
+ size_t Set_Iteration::s_nMaxLoadFactor = 8; // maximum load factor
+
+ size_t Set_Iteration::s_nCuckooInitialSize = 1024;// initial size for CuckooSet
+ size_t Set_Iteration::s_nCuckooProbesetSize = 16; // CuckooSet probeset size (only for list-based probeset)
+ size_t Set_Iteration::s_nCuckooProbesetThreshold = 0; // CUckooSet probeset threshold (0 - use default)
+
+ size_t Set_Iteration::s_nFeldmanSet_HeadBits = 10;
+ size_t Set_Iteration::s_nFeldmanSet_ArrayBits = 4;
+
+ size_t Set_Iteration::s_nLoadFactor = 1;
+ std::vector<std::string> Set_Iteration::m_arrString;
+
+ void Set_Iteration::SetUpTestCase()
+ {
+ cds_test::config const& cfg = get_config( "map_insdel_string" );
+
+ s_nSetSize = cfg.get_size_t( "MapSize", s_nSetSize );
+ if ( s_nSetSize < 1000 )
+ s_nSetSize = 1000;
+
+ s_nInsertThreadCount = cfg.get_size_t( "InsertThreadCount", s_nInsertThreadCount );
+ if ( s_nInsertThreadCount == 0 )
+ s_nInsertThreadCount = 2;
+
+ s_nDeleteThreadCount = cfg.get_size_t( "DeleteThreadCount", s_nDeleteThreadCount );
+ if ( s_nDeleteThreadCount == 0 )
+ s_nDeleteThreadCount = 2;
+
+ s_nThreadPassCount = cfg.get_size_t( "ThreadPassCount", s_nThreadPassCount );
+ if ( s_nThreadPassCount == 0 )
+ s_nThreadPassCount = 4;
+
+ s_nMaxLoadFactor = cfg.get_size_t( "MaxLoadFactor", s_nMaxLoadFactor );
+ if ( s_nMaxLoadFactor == 0 )
+ s_nMaxLoadFactor = 1;
+
+ s_nCuckooInitialSize = cfg.get_size_t( "CuckooInitialSize", s_nCuckooInitialSize );
+ if ( s_nCuckooInitialSize < 256 )
+ s_nCuckooInitialSize = 256;
+
+ s_nCuckooProbesetSize = cfg.get_size_t( "CuckooProbesetSize", s_nCuckooProbesetSize );
+ if ( s_nCuckooProbesetSize < 8 )
+ s_nCuckooProbesetSize = 8;
+
+ s_nCuckooProbesetThreshold = cfg.get_size_t( "CuckooProbesetThreshold", s_nCuckooProbesetThreshold );
+
+ s_nFeldmanSet_HeadBits = cfg.get_size_t( "FeldmanMapHeadBits", s_nFeldmanSet_HeadBits );
+ if ( s_nFeldmanSet_HeadBits == 0 )
+ s_nFeldmanSet_HeadBits = 2;
+
+ s_nFeldmanSet_ArrayBits = cfg.get_size_t( "FeldmanMapArrayBits", s_nFeldmanSet_ArrayBits );
+ if ( s_nFeldmanSet_ArrayBits == 0 )
+ s_nFeldmanSet_ArrayBits = 2;
+
+ // Load string dictionary
+ m_arrString = load_dictionary();
+ }
+
+ void Set_Iteration::TearDownTestCase()
+ {
+ m_arrString.clear();
+ }
+
+ std::vector<size_t> Set_Iteration_LF::get_load_factors()
+ {
+ cds_test::config const& cfg = get_config( "map_insdel_string" );
+
+ s_nMaxLoadFactor = cfg.get_size_t( "MaxLoadFactor", s_nMaxLoadFactor );
+ if ( s_nMaxLoadFactor == 0 )
+ s_nMaxLoadFactor = 1;
+
+ std::vector<size_t> lf;
+ for ( size_t n = 1; n <= s_nMaxLoadFactor; n *= 2 )
+ lf.push_back( n );
+
+ return lf;
+ }
+
+ INSTANTIATE_TEST_CASE_P( a, Set_Iteration_LF, ::testing::ValuesIn( Set_Iteration_LF::get_load_factors()));
+} // namespace set
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "set_type.h"
+#include <cds_test/city.h>
+
+namespace set {
+
+// Test for set's thread-safe iterator:
+// Several thread inserts/erases elemets from the set.
+// Dedicated Iterator thread iterates over the set, calculates CityHash for each element
+// and stores it in the element.
+// Test goal: no crash
+
+#define TEST_CASE(TAG, X) void X();
+
+ class Set_Iteration: public cds_test::stress_fixture
+ {
+ public:
+ static size_t s_nSetSize; // set size
+ static size_t s_nInsertThreadCount; // count of insertion thread
+ static size_t s_nDeleteThreadCount; // count of deletion thread
+ static size_t s_nThreadPassCount; // pass count for each thread
+ static size_t s_nMaxLoadFactor; // maximum load factor
+
+ static size_t s_nCuckooInitialSize; // initial size for CuckooSet
+ static size_t s_nCuckooProbesetSize; // CuckooSet probeset size (only for list-based probeset)
+ static size_t s_nCuckooProbesetThreshold; // CUckooSet probeset threshold (0 - use default)
+
+ static size_t s_nFeldmanSet_HeadBits;
+ static size_t s_nFeldmanSet_ArrayBits;
+
+ static size_t s_nLoadFactor;
+ static std::vector<std::string> m_arrString;
+
+ static void SetUpTestCase();
+ static void TearDownTestCase();
+
+ void on_modifier_done()
+ {
+ m_nModifierCount.fetch_sub( 1, atomics::memory_order_relaxed );
+ }
+
+ bool all_modifiers_done() const
+ {
+ return m_nModifierCount.load( atomics::memory_order_relaxed ) == 0;
+ }
+
+ typedef std::string key_type;
+
+ struct value_type
+ {
+ size_t val;
+ uint64_t hash;
+
+ explicit value_type( size_t v )
+ : val(v)
+ , hash(0)
+ {}
+ };
+
+ private:
+ enum {
+ insert_thread,
+ delete_thread,
+ extract_thread,
+ iterator_thread
+ };
+
+ atomics::atomic<size_t> m_nModifierCount;
+
+ template <class Set>
+ class Inserter: public cds_test::thread
+ {
+ typedef cds_test::thread base_class;
+
+ Set& m_Set;
+ typedef typename Set::value_type keyval_type;
+
+ public:
+ size_t m_nInsertSuccess = 0;
+ size_t m_nInsertFailed = 0;
+
+ public:
+ Inserter( cds_test::thread_pool& pool, Set& set )
+ : base_class( pool, insert_thread )
+ , m_Set( set )
+ {}
+
+ Inserter( Inserter& src )
+ : base_class( src )
+ , m_Set( src.m_Set )
+ {}
+
+ virtual thread * clone()
+ {
+ return new Inserter( *this );
+ }
+
+ virtual void test()
+ {
+ Set& rSet = m_Set;
+
+ Set_Iteration& fixture = pool().template fixture<Set_Iteration>();
+ size_t nArrSize = m_arrString.size();
+ size_t const nSetSize = fixture.s_nSetSize;
+ size_t const nPassCount = fixture.s_nThreadPassCount;
+
+ if ( id() & 1 ) {
+ for ( size_t nPass = 0; nPass < nPassCount; ++nPass ) {
+ for ( size_t nItem = 0; nItem < nSetSize; ++nItem ) {
+ if ( rSet.insert( keyval_type( m_arrString[nItem % nArrSize], nItem * 8 )))
+ ++m_nInsertSuccess;
+ else
+ ++m_nInsertFailed;
+ }
+ }
+ }
+ else {
+ for ( size_t nPass = 0; nPass < nPassCount; ++nPass ) {
+ for ( size_t nItem = nSetSize; nItem > 0; --nItem ) {
+ if ( rSet.insert( keyval_type( m_arrString[nItem % nArrSize], nItem * 8 )))
+ ++m_nInsertSuccess;
+ else
+ ++m_nInsertFailed;
+ }
+ }
+ }
+
+ fixture.on_modifier_done();
+ }
+ };
+
+ template <class Set>
+ class Deleter: public cds_test::thread
+ {
+ typedef cds_test::thread base_class;
+
+ Set& m_Set;
+ public:
+ size_t m_nDeleteSuccess = 0;
+ size_t m_nDeleteFailed = 0;
+
+ public:
+ Deleter( cds_test::thread_pool& pool, Set& set )
+ : base_class( pool, delete_thread )
+ , m_Set( set )
+ {}
+
+ Deleter( Deleter& src )
+ : base_class( src )
+ , m_Set( src.m_Set )
+ {}
+
+ virtual thread * clone()
+ {
+ return new Deleter( *this );
+ }
+
+ virtual void test()
+ {
+ Set& rSet = m_Set;
+
+ Set_Iteration& fixture = pool().template fixture<Set_Iteration>();
+ size_t nArrSize = m_arrString.size();
+ size_t const nSetSize = fixture.s_nSetSize;
+ size_t const nPassCount = fixture.s_nThreadPassCount;
+
+ if ( id() & 1 ) {
+ for ( size_t nPass = 0; nPass < nPassCount; ++nPass ) {
+ for ( size_t nItem = 0; nItem < nSetSize; ++nItem ) {
+ if ( rSet.erase( m_arrString[nItem % nArrSize] ))
+ ++m_nDeleteSuccess;
+ else
+ ++m_nDeleteFailed;
+ }
+ }
+ }
+ else {
+ for ( size_t nPass = 0; nPass < nPassCount; ++nPass ) {
+ for ( size_t nItem = nSetSize; nItem > 0; --nItem ) {
+ if ( rSet.erase( m_arrString[nItem % nArrSize] ))
+ ++m_nDeleteSuccess;
+ else
+ ++m_nDeleteFailed;
+ }
+ }
+ }
+
+ fixture.on_modifier_done();
+ }
+ };
+
+ template <typename GC, class Set>
+ class Extractor: public cds_test::thread
+ {
+ typedef cds_test::thread base_class;
+ Set& m_Set;
+
+ public:
+ size_t m_nDeleteSuccess = 0;
+ size_t m_nDeleteFailed = 0;
+
+ public:
+ Extractor( cds_test::thread_pool& pool, Set& set )
+ : base_class( pool, extract_thread )
+ , m_Set( set )
+ {}
+
+ Extractor( Extractor& src )
+ : base_class( src )
+ , m_Set( src.m_Set )
+ {}
+
+ virtual thread * clone()
+ {
+ return new Extractor( *this );
+ }
+
+ virtual void test()
+ {
+ Set& rSet = m_Set;
+
+ typename Set::guarded_ptr gp;
+
+ Set_Iteration& fixture = pool().template fixture<Set_Iteration>();
+ size_t nArrSize = m_arrString.size();
+ size_t const nSetSize = fixture.s_nSetSize;
+ size_t const nPassCount = fixture.s_nThreadPassCount;
+
+ if ( id() & 1 ) {
+ for ( size_t nPass = 0; nPass < nPassCount; ++nPass ) {
+ for ( size_t nItem = 0; nItem < nSetSize; ++nItem ) {
+ gp = rSet.extract( m_arrString[nItem % nArrSize] );
+ if ( gp )
+ ++m_nDeleteSuccess;
+ else
+ ++m_nDeleteFailed;
+ gp.release();
+ }
+ }
+ }
+ else {
+ for ( size_t nPass = 0; nPass < nPassCount; ++nPass ) {
+ for ( size_t nItem = nSetSize; nItem > 0; --nItem ) {
+ gp = rSet.extract( m_arrString[nItem % nArrSize] );
+ if ( gp )
+ ++m_nDeleteSuccess;
+ else
+ ++m_nDeleteFailed;
+ gp.release();
+ }
+ }
+ }
+
+ fixture.on_modifier_done();
+ }
+ };
+
+ template <typename RCU, class Set>
+ class Extractor<cds::urcu::gc<RCU>, Set >: public cds_test::thread
+ {
+ typedef cds_test::thread base_class;
+ Set& m_Set;
+
+ public:
+ size_t m_nDeleteSuccess = 0;
+ size_t m_nDeleteFailed = 0;
+
+ public:
+ Extractor( cds_test::thread_pool& pool, Set& set )
+ : base_class( pool, extract_thread )
+ , m_Set( set )
+ {}
+
+ Extractor( Extractor& src )
+ : base_class( src )
+ , m_Set( src.m_Set )
+ {}
+
+ virtual thread * clone()
+ {
+ return new Extractor( *this );
+ }
+
+ virtual void test()
+ {
+ Set& rSet = m_Set;
+
+ typename Set::exempt_ptr xp;
+
+ Set_Iteration& fixture = pool().template fixture<Set_Iteration>();
+ size_t nArrSize = m_arrString.size();
+ size_t const nSetSize = fixture.s_nSetSize;
+ size_t const nPassCount = fixture.s_nThreadPassCount;
+
+ if ( id() & 1 ) {
+ for ( size_t nPass = 0; nPass < nPassCount; ++nPass ) {
+ for ( size_t nItem = 0; nItem < nSetSize; ++nItem ) {
+ if ( Set::c_bExtractLockExternal ) {
+ typename Set::rcu_lock l;
+ xp = rSet.extract( m_arrString[nItem % nArrSize] );
+ if ( xp )
+ ++m_nDeleteSuccess;
+ else
+ ++m_nDeleteFailed;
+ }
+ else {
+ xp = rSet.extract( m_arrString[nItem % nArrSize] );
+ if ( xp )
+ ++m_nDeleteSuccess;
+ else
+ ++m_nDeleteFailed;
+ }
+ xp.release();
+ }
+ }
+ }
+ else {
+ for ( size_t nPass = 0; nPass < nPassCount; ++nPass ) {
+ for ( size_t nItem = nSetSize; nItem > 0; --nItem ) {
+ if ( Set::c_bExtractLockExternal ) {
+ typename Set::rcu_lock l;
+ xp = rSet.extract( m_arrString[nItem % nArrSize] );
+ if ( xp )
+ ++m_nDeleteSuccess;
+ else
+ ++m_nDeleteFailed;
+ }
+ else {
+ xp = rSet.extract( m_arrString[nItem % nArrSize] );
+ if ( xp )
+ ++m_nDeleteSuccess;
+ else
+ ++m_nDeleteFailed;
+ }
+ xp.release();
+ }
+ }
+ }
+
+ fixture.on_modifier_done();
+ }
+ };
+
+ template <typename GC, class Set>
+ class Iterator: public cds_test::thread
+ {
+ typedef cds_test::thread base_class;
+
+ Set& m_Set;
+ typedef typename Set::value_type keyval_type;
+
+ public:
+ size_t m_nPassCount = 0;
+ size_t m_nVisitCount = 0; // how many items the iterator visited
+
+ public:
+ Iterator( cds_test::thread_pool& pool, Set& set )
+ : base_class( pool, iterator_thread )
+ , m_Set( set )
+ {}
+
+ Iterator( Iterator& src )
+ : base_class( src )
+ , m_Set( src.m_Set )
+ {}
+
+ virtual thread * clone()
+ {
+ return new Iterator( *this );
+ }
+
+ virtual void test()
+ {
+ Set& rSet = m_Set;
+
+ Set_Iteration& fixture = pool().template fixture<Set_Iteration>();
+ while ( !fixture.all_modifiers_done() ) {
+ ++m_nPassCount;
+ typename Set::iterator it;
+ typename Set::iterator itEnd;
+ itEnd = rSet.end();
+ for ( it = rSet.begin(); it != itEnd; ++it ) {
+ it->val.hash = CityHash64( it->key.c_str(), it->key.length());
+ ++m_nVisitCount;
+ }
+ }
+ }
+ };
+
+ template <typename RCU, class Set>
+ class Iterator<cds::urcu::gc<RCU>, Set>: public cds_test::thread
+ {
+ typedef cds_test::thread base_class;
+
+ Set& m_Set;
+ typedef typename Set::value_type keyval_type;
+
+ public:
+ size_t m_nPassCount = 0;
+ size_t m_nVisitCount = 0; // how many items the iterator visited
+
+ public:
+ Iterator( cds_test::thread_pool& pool, Set& set )
+ : base_class( pool, iterator_thread )
+ , m_Set( set )
+ {}
+
+ Iterator( Iterator& src )
+ : base_class( src )
+ , m_Set( src.m_Set )
+ {}
+
+ virtual thread * clone()
+ {
+ return new Iterator( *this );
+ }
+
+ virtual void test()
+ {
+ Set& rSet = m_Set;
+
+ Set_Iteration& fixture = pool().template fixture<Set_Iteration>();
+ while ( !fixture.all_modifiers_done() ) {
+ ++m_nPassCount;
+ typename Set::rcu_lock l;
+ for ( auto it = rSet.begin(); it != rSet.end(); ++it ) {
+ it->val.hash = CityHash64( it->key.c_str(), it->key.length() );
+ ++m_nVisitCount;
+ }
+ }
+ }
+ };
+
+ protected:
+ template <class Set>
+ void do_test( Set& testSet )
+ {
+ typedef Inserter<Set> InserterThread;
+ typedef Deleter<Set> DeleterThread;
+ typedef Iterator<typename Set::gc, Set> IteratorThread;
+
+ cds_test::thread_pool& pool = get_pool();
+ pool.add( new InserterThread( pool, testSet ), s_nInsertThreadCount );
+ pool.add( new DeleterThread( pool, testSet ), s_nDeleteThreadCount );
+
+ m_nModifierCount.store( pool.size(), atomics::memory_order_relaxed );
+ pool.add( new IteratorThread( pool, testSet ), 1 );
+
+ propout() << std::make_pair( "insert_thread_count", s_nInsertThreadCount )
+ << std::make_pair( "delete_thread_count", s_nDeleteThreadCount )
+ << std::make_pair( "thread_pass_count", s_nThreadPassCount )
+ << std::make_pair( "set_size", s_nSetSize );
+
+ std::chrono::milliseconds duration = pool.run();
+
+ propout() << std::make_pair( "duration", duration );
+
+ size_t nInsertSuccess = 0;
+ size_t nInsertFailed = 0;
+ size_t nDeleteSuccess = 0;
+ size_t nDeleteFailed = 0;
+ size_t nIteratorPassCount = 0;
+ size_t nIteratorVisitCount = 0;
+ for ( size_t i = 0; i < pool.size(); ++i ) {
+ cds_test::thread& thr = pool.get( i );
+ switch ( thr.type() ) {
+ case insert_thread:
+ {
+ InserterThread& inserter = static_cast<InserterThread&>( thr );
+ nInsertSuccess += inserter.m_nInsertSuccess;
+ nInsertFailed += inserter.m_nInsertFailed;
+ }
+ break;
+ case delete_thread:
+ {
+ DeleterThread& deleter = static_cast<DeleterThread&>(thr);
+ nDeleteSuccess += deleter.m_nDeleteSuccess;
+ nDeleteFailed += deleter.m_nDeleteFailed;
+ }
+ break;
+ case iterator_thread:
+ {
+ IteratorThread& iter = static_cast<IteratorThread&>(thr);
+ nIteratorPassCount += iter.m_nPassCount;
+ nIteratorVisitCount += iter.m_nVisitCount;
+ }
+ break;
+ default:
+ assert( false ); // Forgot anything?..
+ }
+ }
+
+ propout()
+ << std::make_pair( "insert_success", nInsertSuccess )
+ << std::make_pair( "delete_success", nDeleteSuccess )
+ << std::make_pair( "insert_failed", nInsertFailed )
+ << std::make_pair( "delete_failed", nDeleteFailed )
+ << std::make_pair( "iterator_pass_count", nIteratorPassCount )
+ << std::make_pair( "iterator_visit_count", nIteratorVisitCount )
+ << std::make_pair( "final_set_size", testSet.size() );
+
+ testSet.clear();
+ EXPECT_TRUE( testSet.empty() );
+
+ additional_check( testSet );
+ print_stat( propout(), testSet );
+ additional_cleanup( testSet );
+ }
+
+ template <class Set>
+ void do_test_extract( Set& testSet )
+ {
+ typedef Inserter<Set> InserterThread;
+ typedef Deleter<Set> DeleterThread;
+ typedef Extractor<typename Set::gc, Set> ExtractThread;
+ typedef Iterator<typename Set::gc, Set> IteratorThread;
+
+ size_t const nDelThreadCount = s_nDeleteThreadCount / 2;
+ size_t const nExtractThreadCount = s_nDeleteThreadCount - nDelThreadCount;
+
+ cds_test::thread_pool& pool = get_pool();
+ pool.add( new InserterThread( pool, testSet ), s_nInsertThreadCount );
+ pool.add( new DeleterThread( pool, testSet ), nDelThreadCount );
+ pool.add( new ExtractThread( pool, testSet ), nExtractThreadCount );
+
+ m_nModifierCount.store( pool.size(), atomics::memory_order_relaxed );
+ pool.add( new IteratorThread( pool, testSet ), 1 );
+
+ propout() << std::make_pair( "insert_thread_count", s_nInsertThreadCount )
+ << std::make_pair( "delete_thread_count", nDelThreadCount )
+ << std::make_pair( "extract_thread_count", nExtractThreadCount )
+ << std::make_pair( "thread_pass_count", s_nThreadPassCount )
+ << std::make_pair( "set_size", s_nSetSize );
+
+ std::chrono::milliseconds duration = pool.run();
+
+ propout() << std::make_pair( "duration", duration );
+
+ size_t nInsertSuccess = 0;
+ size_t nInsertFailed = 0;
+ size_t nDeleteSuccess = 0;
+ size_t nDeleteFailed = 0;
+ size_t nExtractSuccess = 0;
+ size_t nExtractFailed = 0;
+ size_t nIteratorPassCount = 0;
+ size_t nIteratorVisitCount = 0;
+ for ( size_t i = 0; i < pool.size(); ++i ) {
+ cds_test::thread& thr = pool.get( i );
+ switch ( thr.type() ) {
+ case insert_thread:
+ {
+ InserterThread& inserter = static_cast<InserterThread&>(thr);
+ nInsertSuccess += inserter.m_nInsertSuccess;
+ nInsertFailed += inserter.m_nInsertFailed;
+ }
+ break;
+ case delete_thread:
+ {
+ DeleterThread& deleter = static_cast<DeleterThread&>(thr);
+ nDeleteSuccess += deleter.m_nDeleteSuccess;
+ nDeleteFailed += deleter.m_nDeleteFailed;
+ }
+ break;
+ case extract_thread:
+ {
+ ExtractThread& extractor = static_cast<ExtractThread&>(thr);
+ nExtractSuccess += extractor.m_nDeleteSuccess;
+ nExtractFailed += extractor.m_nDeleteFailed;
+ }
+ break;
+ case iterator_thread:
+ {
+ IteratorThread& iter = static_cast<IteratorThread&>(thr);
+ nIteratorPassCount += iter.m_nPassCount;
+ nIteratorVisitCount += iter.m_nVisitCount;
+ }
+ break;
+ default:
+ assert( false ); // Forgot anything?..
+ }
+ }
+
+ propout()
+ << std::make_pair( "insert_success", nInsertSuccess )
+ << std::make_pair( "delete_success", nDeleteSuccess )
+ << std::make_pair( "extract_success", nExtractSuccess )
+ << std::make_pair( "insert_failed", nInsertFailed )
+ << std::make_pair( "delete_failed", nDeleteFailed )
+ << std::make_pair( "extract_failed", nExtractFailed )
+ << std::make_pair( "iterator_pass_count", nIteratorPassCount )
+ << std::make_pair( "iterator_visit_count", nIteratorVisitCount )
+ << std::make_pair( "final_set_size", testSet.size() );
+
+ testSet.clear();
+ EXPECT_TRUE( testSet.empty() );
+
+ additional_check( testSet );
+ print_stat( propout(), testSet );
+ additional_cleanup( testSet );
+ }
+
+ template <class Set>
+ void run_test()
+ {
+ ASSERT_TRUE( m_arrString.size() > 0 );
+
+ Set s( *this );
+ do_test( s );
+ }
+
+ template <class Set>
+ void run_test_extract()
+ {
+ ASSERT_TRUE( m_arrString.size() > 0 );
+
+ Set s( *this );
+ do_test_extract( s );
+ }
+ };
+
+ class Set_Iteration_LF: public Set_Iteration
+ , public ::testing::WithParamInterface<size_t>
+ {
+ public:
+ template <class Set>
+ void run_test()
+ {
+ s_nLoadFactor = GetParam();
+ propout() << std::make_pair( "load_factor", s_nLoadFactor );
+ Set_Iteration::run_test<Set>();
+ }
+
+ template <class Set>
+ void run_test_extract()
+ {
+ s_nLoadFactor = GetParam();
+ propout() << std::make_pair( "load_factor", s_nLoadFactor );
+ Set_Iteration::run_test_extract<Set>();
+ }
+
+ static std::vector<size_t> get_load_factors();
+ };
+
+} // namespace set
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "set_iteration.h"
+#include "set_type_feldman_hashset.h"
+
+namespace set {
+
+ CDSSTRESS_FeldmanHashSet_stdhash_quick( Set_Iteration, run_test_extract, std::string, Set_Iteration::value_type )
+ CDSSTRESS_FeldmanHashSet_city_quick( Set_Iteration, run_test_extract, std::string, Set_Iteration::value_type )
+
+} // namespace set
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "set_iteration.h"
+#include "set_type_michael.h"
+
+namespace set {
+
+ CDSSTRESS_MichaelIterableSet( Set_Iteration_LF, run_test_extract, std::string, Set_Iteration::value_type )
+
+} // namespace set
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSUNIT_SET_TYPE_FELDMAN_HASHSET_H
CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpt_fixed_stat, key_type, value_type ) \
CDSSTRESS_FeldmanHashSet_fixed_SHRCU( fixture, test_case, key_type, value_type )
-#define CDSSTRESS_FeldmanHashSet_stdhash( fixture, test_case, key_type, value_type ) \
+#define CDSSTRESS_FeldmanHashSet_stdhash_rcu_gpi( fixture, test_case, key_type, value_type ) \
+ CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpi_stdhash, key_type, value_type ) \
+ CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpi_stdhash_stat, key_type, value_type ) \
+
+#define CDSSTRESS_FeldmanHashSet_stdhash_quick( fixture, test_case, key_type, value_type ) \
CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_hp_stdhash, key_type, value_type ) \
CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_dhp_stdhash, key_type, value_type ) \
- CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpi_stdhash, key_type, value_type ) \
CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpb_stdhash, key_type, value_type ) \
CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpt_stdhash, key_type, value_type ) \
CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_hp_stdhash_stat, key_type, value_type ) \
CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_dhp_stdhash_stat, key_type, value_type ) \
- CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpi_stdhash_stat, key_type, value_type ) \
CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpb_stdhash_stat, key_type, value_type ) \
CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpt_stdhash_stat, key_type, value_type ) \
CDSSTRESS_FeldmanHashSet_stdhash_SHRCU( fixture, test_case, key_type, value_type )
+#define CDSSTRESS_FeldmanHashSet_stdhash( fixture, test_case, key_type, value_type ) \
+ CDSSTRESS_FeldmanHashSet_stdhash_quick( fixture, test_case, key_type, value_type ) \
+ CDSSTRESS_FeldmanHashSet_stdhash_rcu_gpi( fixture, test_case, key_type, value_type ) \
+
#if CDS_BUILD_BITS == 64
-# define CDSSTRESS_FeldmanHashSet_city( fixture, test_case, key_type, value_type ) \
+# define CDSSTRESS_FeldmanHashSet_city_rcu_gpi( fixture, test_case, key_type, value_type ) \
+ CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpi_city64, key_type, value_type ) \
+ CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpi_city64_stat, key_type, value_type ) \
+ CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpi_city128, key_type, value_type ) \
+ CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpi_city128_stat, key_type, value_type ) \
+
+# define CDSSTRESS_FeldmanHashSet_city_quick( fixture, test_case, key_type, value_type ) \
CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_hp_city64, key_type, value_type ) \
CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_dhp_city64, key_type, value_type ) \
- CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpi_city64, key_type, value_type ) \
CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpb_city64, key_type, value_type ) \
CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpt_city64, key_type, value_type ) \
CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_hp_city64_stat, key_type, value_type ) \
CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_dhp_city64_stat, key_type, value_type ) \
- CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpi_city64_stat, key_type, value_type ) \
CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpb_city64_stat, key_type, value_type ) \
CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpt_city64_stat, key_type, value_type ) \
CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_hp_city128, key_type, value_type ) \
CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_dhp_city128, key_type, value_type ) \
- CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpi_city128, key_type, value_type ) \
CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpb_city128, key_type, value_type ) \
CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpt_city128, key_type, value_type ) \
CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_hp_city128_stat, key_type, value_type ) \
CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_dhp_city128_stat, key_type, value_type ) \
- CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpi_city128_stat, key_type, value_type ) \
CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpb_city128_stat, key_type, value_type ) \
CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpt_city128_stat, key_type, value_type ) \
CDSSTRESS_FeldmanHashSet_city_SHRCU( fixture, test_case, key_type, value_type )
+
+# define CDSSTRESS_FeldmanHashSet_city( fixture, test_case, key_type, value_type ) \
+ CDSSTRESS_FeldmanHashSet_city_quick( fixture, test_case, key_type, value_type ) \
+ CDSSTRESS_FeldmanHashSet_city_rcu_gpi( fixture, test_case, key_type, value_type ) \
+
+
#else
+# define CDSSTRESS_FeldmanHashSet_city_rcu_gpi( fixture, test_case, key_type, value_type )
+# define CDSSTRESS_FeldmanHashSet_city_quick( fixture, test_case, key_type, value_type )
# define CDSSTRESS_FeldmanHashSet_city( fixture, test_case, key_type, value_type )
#endif
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSUNIT_SET_TYPE_ITRERABLE_LIST_H
+#define CDSUNIT_SET_TYPE_ITRERABLE_LIST_H
+
+#include "set_type.h"
+
+#include <cds/container/iterable_list_hp.h>
+#include <cds/container/iterable_list_dhp.h>
+//#include <cds/container/michael_list_rcu.h>
+
+namespace set {
+
+ template <typename Key, typename Val>
+ struct iterable_list_type
+ {
+ typedef typename set_type_base< Key, Val >::key_val key_val;
+ typedef typename set_type_base< Key, Val >::compare compare;
+ typedef typename set_type_base< Key, Val >::less less;
+
+ struct traits_IterableList_cmp_stdAlloc:
+ public cc::iterable_list::make_traits<
+ co::compare< compare >
+ >::type
+ {};
+ typedef cc::IterableList< cds::gc::HP, key_val, traits_IterableList_cmp_stdAlloc > IterableList_HP_cmp_stdAlloc;
+ typedef cc::IterableList< cds::gc::DHP, key_val, traits_IterableList_cmp_stdAlloc > IterableList_DHP_cmp_stdAlloc;
+ //typedef cc::IterableList< rcu_gpi, key_val, traits_IterableList_cmp_stdAlloc > IterableList_RCU_GPI_cmp_stdAlloc;
+ //typedef cc::IterableList< rcu_gpb, key_val, traits_IterableList_cmp_stdAlloc > IterableList_RCU_GPB_cmp_stdAlloc;
+ //typedef cc::IterableList< rcu_gpt, key_val, traits_IterableList_cmp_stdAlloc > IterableList_RCU_GPT_cmp_stdAlloc;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+ //typedef cc::IterableList< rcu_shb, key_val, traits_IterableList_cmp_stdAlloc > IterableList_RCU_SHB_cmp_stdAlloc;
+ //typedef cc::IterableList< rcu_sht, key_val, traits_IterableList_cmp_stdAlloc > IterableList_RCU_SHT_cmp_stdAlloc;
+#endif
+
+ struct traits_IterableList_cmp_stdAlloc_stat: public traits_IterableList_cmp_stdAlloc
+ {
+ typedef cc::iterable_list::stat<> stat;
+ };
+ typedef cc::IterableList< cds::gc::HP, key_val, traits_IterableList_cmp_stdAlloc_stat > IterableList_HP_cmp_stdAlloc_stat;
+ typedef cc::IterableList< cds::gc::DHP, key_val, traits_IterableList_cmp_stdAlloc_stat > IterableList_DHP_cmp_stdAlloc_stat;
+ //typedef cc::IterableList< rcu_gpi, key_val, traits_IterableList_cmp_stdAlloc_stat > IterableList_RCU_GPI_cmp_stdAlloc_stat;
+ //typedef cc::IterableList< rcu_gpb, key_val, traits_IterableList_cmp_stdAlloc_stat > IterableList_RCU_GPB_cmp_stdAlloc_stat;
+ //typedef cc::IterableList< rcu_gpt, key_val, traits_IterableList_cmp_stdAlloc_stat > IterableList_RCU_GPT_cmp_stdAlloc_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+ //typedef cc::IterableList< rcu_shb, key_val, traits_IterableList_cmp_stdAlloc_stat > IterableList_RCU_SHB_cmp_stdAlloc_stat;
+ //typedef cc::IterableList< rcu_sht, key_val, traits_IterableList_cmp_stdAlloc_stat > IterableList_RCU_SHT_cmp_stdAlloc_stat;
+#endif
+
+ struct traits_IterableList_cmp_stdAlloc_seqcst : public traits_IterableList_cmp_stdAlloc
+ {
+ typedef co::v::sequential_consistent memory_model;
+ };
+ typedef cc::IterableList< cds::gc::HP, key_val, traits_IterableList_cmp_stdAlloc_seqcst > IterableList_HP_cmp_stdAlloc_seqcst;
+ typedef cc::IterableList< cds::gc::DHP, key_val, traits_IterableList_cmp_stdAlloc_seqcst > IterableList_DHP_cmp_stdAlloc_seqcst;
+ //typedef cc::IterableList< rcu_gpi, key_val, traits_IterableList_cmp_stdAlloc_seqcst > IterableList_RCU_GPI_cmp_stdAlloc_seqcst;
+ //typedef cc::IterableList< rcu_gpb, key_val, traits_IterableList_cmp_stdAlloc_seqcst > IterableList_RCU_GPB_cmp_stdAlloc_seqcst;
+ //typedef cc::IterableList< rcu_gpt, key_val, traits_IterableList_cmp_stdAlloc_seqcst > IterableList_RCU_GPT_cmp_stdAlloc_seqcst;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+ //typedef cc::IterableList< rcu_shb, key_val, traits_IterableList_cmp_stdAlloc_seqcst > IterableList_RCU_SHB_cmp_stdAlloc_seqcst;
+ //typedef cc::IterableList< rcu_sht, key_val, traits_IterableList_cmp_stdAlloc_seqcst > IterableList_RCU_SHT_cmp_stdAlloc_seqcst;
+#endif
+
+ struct traits_IterableList_less_stdAlloc :
+ public cc::iterable_list::make_traits<
+ co::less< less >
+ >::type
+ {};
+ typedef cc::IterableList< cds::gc::HP, key_val, traits_IterableList_less_stdAlloc > IterableList_HP_less_stdAlloc;
+ typedef cc::IterableList< cds::gc::DHP, key_val, traits_IterableList_less_stdAlloc > IterableList_DHP_less_stdAlloc;
+ //typedef cc::IterableList< rcu_gpi, key_val, traits_IterableList_less_stdAlloc > IterableList_RCU_GPI_less_stdAlloc;
+ //typedef cc::IterableList< rcu_gpb, key_val, traits_IterableList_less_stdAlloc > IterableList_RCU_GPB_less_stdAlloc;
+ //typedef cc::IterableList< rcu_gpt, key_val, traits_IterableList_less_stdAlloc > IterableList_RCU_GPT_less_stdAlloc;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+ //typedef cc::IterableList< rcu_shb, key_val, traits_IterableList_less_stdAlloc > IterableList_RCU_SHB_less_stdAlloc;
+ //typedef cc::IterableList< rcu_sht, key_val, traits_IterableList_less_stdAlloc > IterableList_RCU_SHT_less_stdAlloc;
+#endif
+
+ struct traits_IterableList_less_stdAlloc_stat : public traits_IterableList_less_stdAlloc
+ {
+ typedef cc::iterable_list::stat<> stat;
+ };
+ typedef cc::IterableList< cds::gc::HP, key_val, traits_IterableList_less_stdAlloc_stat > IterableList_HP_less_stdAlloc_stat;
+ typedef cc::IterableList< cds::gc::DHP, key_val, traits_IterableList_less_stdAlloc_stat > IterableList_DHP_less_stdAlloc_stat;
+ //typedef cc::IterableList< rcu_gpi, key_val, traits_IterableList_less_stdAlloc_stat > IterableList_RCU_GPI_less_stdAlloc_stat;
+ //typedef cc::IterableList< rcu_gpb, key_val, traits_IterableList_less_stdAlloc_stat > IterableList_RCU_GPB_less_stdAlloc_stat;
+ //typedef cc::IterableList< rcu_gpt, key_val, traits_IterableList_less_stdAlloc_stat > IterableList_RCU_GPT_less_stdAlloc_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+ //typedef cc::IterableList< rcu_shb, key_val, traits_IterableList_less_stdAlloc_stat > IterableList_RCU_SHB_less_stdAlloc_stat;
+ //typedef cc::IterableList< rcu_sht, key_val, traits_IterableList_less_stdAlloc_stat > IterableList_RCU_SHT_less_stdAlloc_stat;
+#endif
+
+ struct traits_IterableList_less_stdAlloc_seqcst :
+ public cc::iterable_list::make_traits<
+ co::less< less >
+ ,co::memory_model< co::v::sequential_consistent >
+ >::type
+ {};
+ typedef cc::IterableList< cds::gc::HP, key_val, traits_IterableList_less_stdAlloc_seqcst > IterableList_HP_less_stdAlloc_seqcst;
+ typedef cc::IterableList< cds::gc::DHP, key_val, traits_IterableList_less_stdAlloc_seqcst > IterableList_DHP_less_stdAlloc_seqcst;
+ //typedef cc::IterableList< rcu_gpi, key_val, traits_IterableList_less_stdAlloc_seqcst > IterableList_RCU_GPI_less_stdAlloc_seqcst;
+ //typedef cc::IterableList< rcu_gpb, key_val, traits_IterableList_less_stdAlloc_seqcst > IterableList_RCU_GPB_less_stdAlloc_seqcst;
+ //typedef cc::IterableList< rcu_gpt, key_val, traits_IterableList_less_stdAlloc_seqcst > IterableList_RCU_GPT_less_stdAlloc_seqcst;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+ //typedef cc::IterableList< rcu_shb, key_val, traits_IterableList_less_stdAlloc_seqcst > IterableList_RCU_SHB_less_stdAlloc_seqcst;
+ //typedef cc::IterableList< rcu_sht, key_val, traits_IterableList_less_stdAlloc_seqcst > IterableList_RCU_SHT_less_stdAlloc_seqcst;
+#endif
+
+ };
+
+} // namespace set
+
+#endif // #ifndef CDSUNIT_SET_TYPE_ITRERABLE_LIST_H
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSUNIT_SET_TYPE_LAZY_LIST_H
typedef typename set_type_base< Key, Val >::compare compare;
typedef typename set_type_base< Key, Val >::less less;
- struct traits_LazyList_cmp_stdAlloc :
+ struct traits_LazyList_cmp_stdAlloc :
public cc::lazy_list::make_traits<
co::compare< compare >
>::type
typedef cc::LazyList< rcu_shb, key_val, traits_LazyList_cmp_stdAlloc > LazyList_RCU_SHB_cmp_stdAlloc;
typedef cc::LazyList< rcu_sht, key_val, traits_LazyList_cmp_stdAlloc > LazyList_RCU_SHT_cmp_stdAlloc;
#endif
+
+ struct traits_LazyList_cmp_stdAlloc_stat : public traits_LazyList_cmp_stdAlloc
+ {
+ typedef cc::lazy_list::stat<> stat;
+ };
+ typedef cc::LazyList< cds::gc::HP, key_val, traits_LazyList_cmp_stdAlloc_stat > LazyList_HP_cmp_stdAlloc_stat;
+ typedef cc::LazyList< cds::gc::DHP, key_val, traits_LazyList_cmp_stdAlloc_stat > LazyList_DHP_cmp_stdAlloc_stat;
+ typedef cc::LazyList< rcu_gpi, key_val, traits_LazyList_cmp_stdAlloc_stat > LazyList_RCU_GPI_cmp_stdAlloc_stat;
+ typedef cc::LazyList< rcu_gpb, key_val, traits_LazyList_cmp_stdAlloc_stat > LazyList_RCU_GPB_cmp_stdAlloc_stat;
+ typedef cc::LazyList< rcu_gpt, key_val, traits_LazyList_cmp_stdAlloc_stat > LazyList_RCU_GPT_cmp_stdAlloc_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+ typedef cc::LazyList< rcu_shb, key_val, traits_LazyList_cmp_stdAlloc_stat > LazyList_RCU_SHB_cmp_stdAlloc_stat;
+ typedef cc::LazyList< rcu_sht, key_val, traits_LazyList_cmp_stdAlloc_stat > LazyList_RCU_SHT_cmp_stdAlloc_stat;
+#endif
+
struct traits_LazyList_cmp_stdAlloc_seqcst :
public cc::lazy_list::make_traits<
co::compare< compare >
typedef cc::LazyList< rcu_sht, key_val, traits_LazyList_less_stdAlloc > LazyList_RCU_SHT_less_stdAlloc;
#endif
+ struct traits_LazyList_less_stdAlloc_stat: public traits_LazyList_less_stdAlloc
+ {
+ typedef cc::lazy_list::stat<> stat;
+ };
+ typedef cc::LazyList< cds::gc::HP, key_val, traits_LazyList_less_stdAlloc_stat > LazyList_HP_less_stdAlloc_stat;
+ typedef cc::LazyList< cds::gc::DHP, key_val, traits_LazyList_less_stdAlloc_stat > LazyList_DHP_less_stdAlloc_stat;
+ typedef cc::LazyList< rcu_gpi, key_val, traits_LazyList_less_stdAlloc_stat > LazyList_RCU_GPI_less_stdAlloc_stat;
+ typedef cc::LazyList< rcu_gpb, key_val, traits_LazyList_less_stdAlloc_stat > LazyList_RCU_GPB_less_stdAlloc_stat;
+ typedef cc::LazyList< rcu_gpt, key_val, traits_LazyList_less_stdAlloc_stat > LazyList_RCU_GPT_less_stdAlloc_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+ typedef cc::LazyList< rcu_shb, key_val, traits_LazyList_less_stdAlloc_stat > LazyList_RCU_SHB_less_stdAlloc_stat;
+ typedef cc::LazyList< rcu_sht, key_val, traits_LazyList_less_stdAlloc_stat > LazyList_RCU_SHT_less_stdAlloc_stat;
+#endif
+
struct traits_LazyList_less_stdAlloc_seqcst :
public cc::lazy_list::make_traits<
co::less< less >
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSUNIT_SET_TYPE_MICHAEL_H
#include "set_type_michael_list.h"
#include "set_type_lazy_list.h"
+#include "set_type_iterable_list.h"
#include <cds/container/michael_set.h>
#include <cds/container/michael_set_rcu.h>
+#include <cds_test/stat_michael_list_out.h>
+#include <cds_test/stat_lazy_list_out.h>
+#include <cds_test/stat_iterable_list_out.h>
+
#include <framework/michael_alloc.h>
namespace set {
typedef MichaelHashSet< rcu_sht, typename ml::MichaelList_RCU_SHT_cmp_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_RCU_SHT_cmp_stdAlloc;
#endif
+ typedef MichaelHashSet< cds::gc::HP, typename ml::MichaelList_HP_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_HP_cmp_stdAlloc_stat;
+ typedef MichaelHashSet< cds::gc::DHP, typename ml::MichaelList_DHP_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_DHP_cmp_stdAlloc_stat;
+ typedef MichaelHashSet< rcu_gpi, typename ml::MichaelList_RCU_GPI_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_RCU_GPI_cmp_stdAlloc_stat;
+ typedef MichaelHashSet< rcu_gpb, typename ml::MichaelList_RCU_GPB_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_RCU_GPB_cmp_stdAlloc_stat;
+ typedef MichaelHashSet< rcu_gpt, typename ml::MichaelList_RCU_GPT_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_RCU_GPT_cmp_stdAlloc_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+ typedef MichaelHashSet< rcu_shb, typename ml::MichaelList_RCU_SHB_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_RCU_SHB_cmp_stdAlloc_stat;
+ typedef MichaelHashSet< rcu_sht, typename ml::MichaelList_RCU_SHT_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_RCU_SHT_cmp_stdAlloc_stat;
+#endif
+
typedef MichaelHashSet< cds::gc::HP, typename ml::MichaelList_HP_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_HP_less_stdAlloc;
typedef MichaelHashSet< cds::gc::DHP, typename ml::MichaelList_DHP_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_DHP_less_stdAlloc;
typedef MichaelHashSet< rcu_gpi, typename ml::MichaelList_RCU_GPI_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_RCU_GPI_less_stdAlloc;
typedef MichaelHashSet< rcu_sht, typename ml::MichaelList_RCU_SHT_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_RCU_SHT_less_stdAlloc;
#endif
+ typedef MichaelHashSet< cds::gc::HP, typename ml::MichaelList_HP_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_HP_less_stdAlloc_stat;
+ typedef MichaelHashSet< cds::gc::DHP, typename ml::MichaelList_DHP_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_DHP_less_stdAlloc_stat;
+ typedef MichaelHashSet< rcu_gpi, typename ml::MichaelList_RCU_GPI_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_RCU_GPI_less_stdAlloc_stat;
+ typedef MichaelHashSet< rcu_gpb, typename ml::MichaelList_RCU_GPB_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_RCU_GPB_less_stdAlloc_stat;
+ typedef MichaelHashSet< rcu_gpt, typename ml::MichaelList_RCU_GPT_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_RCU_GPT_less_stdAlloc_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+ typedef MichaelHashSet< rcu_shb, typename ml::MichaelList_RCU_SHB_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_RCU_SHB_less_stdAlloc_stat;
+ typedef MichaelHashSet< rcu_sht, typename ml::MichaelList_RCU_SHT_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_RCU_SHT_less_stdAlloc_stat;
+#endif
+
typedef MichaelHashSet< cds::gc::HP, typename ml::MichaelList_HP_less_stdAlloc_seqcst, traits_MichaelSet_stdAlloc > MichaelSet_HP_less_stdAlloc_seqcst;
typedef MichaelHashSet< cds::gc::DHP, typename ml::MichaelList_DHP_less_stdAlloc_seqcst, traits_MichaelSet_stdAlloc > MichaelSet_DHP_less_stdAlloc_seqcst;
typedef MichaelHashSet< rcu_gpi, typename ml::MichaelList_RCU_GPI_less_stdAlloc_seqcst, traits_MichaelSet_stdAlloc > MichaelSet_RCU_GPI_less_stdAlloc_seqcst;
typedef MichaelHashSet< rcu_sht, typename ll::LazyList_RCU_SHT_cmp_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_RCU_SHT_cmp_stdAlloc;
#endif
+ typedef MichaelHashSet< cds::gc::HP, typename ll::LazyList_HP_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_HP_cmp_stdAlloc_stat;
+ typedef MichaelHashSet< cds::gc::DHP, typename ll::LazyList_DHP_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_DHP_cmp_stdAlloc_stat;
+ typedef MichaelHashSet< rcu_gpi, typename ll::LazyList_RCU_GPI_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_RCU_GPI_cmp_stdAlloc_stat;
+ typedef MichaelHashSet< rcu_gpb, typename ll::LazyList_RCU_GPB_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_RCU_GPB_cmp_stdAlloc_stat;
+ typedef MichaelHashSet< rcu_gpt, typename ll::LazyList_RCU_GPT_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_RCU_GPT_cmp_stdAlloc_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+ typedef MichaelHashSet< rcu_shb, typename ll::LazyList_RCU_SHB_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_RCU_SHB_cmp_stdAlloc_stat;
+ typedef MichaelHashSet< rcu_sht, typename ll::LazyList_RCU_SHT_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_RCU_SHT_cmp_stdAlloc_stat;
+#endif
+
typedef MichaelHashSet< cds::gc::HP, typename ll::LazyList_HP_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_HP_less_stdAlloc;
typedef MichaelHashSet< cds::gc::DHP, typename ll::LazyList_DHP_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_DHP_less_stdAlloc;
typedef MichaelHashSet< rcu_gpi, typename ll::LazyList_RCU_GPI_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_RCU_GPI_less_stdAlloc;
typedef MichaelHashSet< rcu_sht, typename ll::LazyList_RCU_SHT_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_RCU_SHT_less_stdAlloc;
#endif
+ typedef MichaelHashSet< cds::gc::HP, typename ll::LazyList_HP_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_HP_less_stdAlloc_stat;
+ typedef MichaelHashSet< cds::gc::DHP, typename ll::LazyList_DHP_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_DHP_less_stdAlloc_stat;
+ typedef MichaelHashSet< rcu_gpi, typename ll::LazyList_RCU_GPI_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_RCU_GPI_less_stdAlloc_stat;
+ typedef MichaelHashSet< rcu_gpb, typename ll::LazyList_RCU_GPB_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_RCU_GPB_less_stdAlloc_stat;
+ typedef MichaelHashSet< rcu_gpt, typename ll::LazyList_RCU_GPT_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_RCU_GPT_less_stdAlloc_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+ typedef MichaelHashSet< rcu_shb, typename ll::LazyList_RCU_SHB_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_RCU_SHB_less_stdAlloc_stat;
+ typedef MichaelHashSet< rcu_sht, typename ll::LazyList_RCU_SHT_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_RCU_SHT_less_stdAlloc_stat;
+#endif
+
typedef MichaelHashSet< cds::gc::HP, typename ll::LazyList_HP_less_stdAlloc_seqcst, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_HP_less_stdAlloc_seqcst;
typedef MichaelHashSet< cds::gc::DHP, typename ll::LazyList_DHP_less_stdAlloc_seqcst, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_DHP_less_stdAlloc_seqcst;
typedef MichaelHashSet< rcu_gpi, typename ll::LazyList_RCU_GPI_less_stdAlloc_seqcst, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_RCU_GPI_less_stdAlloc_seqcst;
typedef MichaelHashSet< rcu_shb, typename ll::LazyList_RCU_SHB_less_michaelAlloc, traits_MichaelSet_michaelAlloc > MichaelSet_Lazy_RCU_SHB_less_michaelAlloc;
typedef MichaelHashSet< rcu_sht, typename ll::LazyList_RCU_SHT_less_michaelAlloc, traits_MichaelSet_michaelAlloc > MichaelSet_Lazy_RCU_SHT_less_michaelAlloc;
#endif
+
+
+ // ***************************************************************************
+ // MichaelHashSet based on IterableList
+
+ typedef iterable_list_type< Key, Val > il;
+
+ typedef MichaelHashSet< cds::gc::HP, typename il::IterableList_HP_cmp_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_HP_cmp_stdAlloc;
+ typedef MichaelHashSet< cds::gc::DHP, typename il::IterableList_DHP_cmp_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_DHP_cmp_stdAlloc;
+ //typedef MichaelHashSet< rcu_gpi, typename il::IterableList_RCU_GPI_cmp_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPI_cmp_stdAlloc;
+ //typedef MichaelHashSet< rcu_gpb, typename il::IterableList_RCU_GPB_cmp_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPB_cmp_stdAlloc;
+ //typedef MichaelHashSet< rcu_gpt, typename il::IterableList_RCU_GPT_cmp_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPT_cmp_stdAlloc;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+ //typedef MichaelHashSet< rcu_shb, typename il::IterableList_RCU_SHB_cmp_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_SHB_cmp_stdAlloc;
+ //typedef MichaelHashSet< rcu_sht, typename il::IterableList_RCU_SHT_cmp_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_SHT_cmp_stdAlloc;
+#endif
+
+ typedef MichaelHashSet< cds::gc::HP, typename il::IterableList_HP_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_HP_cmp_stdAlloc_stat;
+ typedef MichaelHashSet< cds::gc::DHP, typename il::IterableList_DHP_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_DHP_cmp_stdAlloc_stat;
+ //typedef MichaelHashSet< rcu_gpi, typename il::IterableList_RCU_GPI_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPI_cmp_stdAlloc_stat;
+ //typedef MichaelHashSet< rcu_gpb, typename il::IterableList_RCU_GPB_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPB_cmp_stdAlloc_stat;
+ //typedef MichaelHashSet< rcu_gpt, typename il::IterableList_RCU_GPT_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPT_cmp_stdAlloc_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+ //typedef MichaelHashSet< rcu_shb, typename il::IterableList_RCU_SHB_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_SHB_cmp_stdAlloc_stat;
+ //typedef MichaelHashSet< rcu_sht, typename il::IterableList_RCU_SHT_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_SHT_cmp_stdAlloc_stat;
+#endif
+
+ typedef MichaelHashSet< cds::gc::HP, typename il::IterableList_HP_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_HP_less_stdAlloc;
+ typedef MichaelHashSet< cds::gc::DHP, typename il::IterableList_DHP_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_DHP_less_stdAlloc;
+ //typedef MichaelHashSet< rcu_gpi, typename il::IterableList_RCU_GPI_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPI_less_stdAlloc;
+ //typedef MichaelHashSet< rcu_gpb, typename il::IterableList_RCU_GPB_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPB_less_stdAlloc;
+ //typedef MichaelHashSet< rcu_gpt, typename il::IterableList_RCU_GPT_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPT_less_stdAlloc;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+ //typedef MichaelHashSet< rcu_shb, typename il::IterableList_RCU_SHB_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_SHB_less_stdAlloc;
+ //typedef MichaelHashSet< rcu_sht, typename il::IterableList_RCU_SHT_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_SHT_less_stdAlloc;
+#endif
+
+ typedef MichaelHashSet< cds::gc::HP, typename il::IterableList_HP_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_HP_less_stdAlloc_stat;
+ typedef MichaelHashSet< cds::gc::DHP, typename il::IterableList_DHP_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_DHP_less_stdAlloc_stat;
+ //typedef MichaelHashSet< rcu_gpi, typename il::IterableList_RCU_GPI_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPI_less_stdAlloc_stat;
+ //typedef MichaelHashSet< rcu_gpb, typename il::IterableList_RCU_GPB_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPB_less_stdAlloc_stat;
+ //typedef MichaelHashSet< rcu_gpt, typename il::IterableList_RCU_GPT_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPT_less_stdAlloc_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+ //typedef MichaelHashSet< rcu_shb, typename il::IterableList_RCU_SHB_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_SHB_less_stdAlloc_stat;
+ //typedef MichaelHashSet< rcu_sht, typename il::IterableList_RCU_SHT_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_SHT_less_stdAlloc_stat;
+#endif
+
+ typedef MichaelHashSet< cds::gc::HP, typename il::IterableList_HP_less_stdAlloc_seqcst, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_HP_less_stdAlloc_seqcst;
+ typedef MichaelHashSet< cds::gc::DHP, typename il::IterableList_DHP_less_stdAlloc_seqcst, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_DHP_less_stdAlloc_seqcst;
+ //typedef MichaelHashSet< rcu_gpi, typename il::IterableList_RCU_GPI_less_stdAlloc_seqcst, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPI_less_stdAlloc_seqcst;
+ //typedef MichaelHashSet< rcu_gpb, typename il::IterableList_RCU_GPB_less_stdAlloc_seqcst, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPB_less_stdAlloc_seqcst;
+ //typedef MichaelHashSet< rcu_gpt, typename il::IterableList_RCU_GPT_less_stdAlloc_seqcst, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPT_less_stdAlloc_seqcst;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+ //typedef MichaelHashSet< rcu_shb, typename il::IterableList_RCU_SHB_less_stdAlloc_seqcst, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_SHB_less_stdAlloc_seqcst;
+ //typedef MichaelHashSet< rcu_sht, typename il::IterableList_RCU_SHT_less_stdAlloc_seqcst, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_SHT_less_stdAlloc_seqcst;
+#endif
+
};
+ template <typename GC, typename T, typename Traits>
+ static inline void print_stat( cds_test::property_stream& o, MichaelHashSet<GC, T, Traits> const& s )
+ {
+ o << s.statistics();
+ }
+
} // namespace set
# define CDSSTRESS_MichaelSet_SHRCU( fixture, test_case, key_type, value_type ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_SHB_cmp_stdAlloc, key_type, value_type, 0 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_SHT_cmp_stdAlloc, key_type, value_type, 1 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_SHB_cmp_stdAlloc_stat, key_type, value_type, 1 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_SHT_cmp_stdAlloc_stat, key_type, value_type, 0 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_SHB_less_stdAlloc, key_type, value_type, 1 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_SHT_less_stdAlloc, key_type, value_type, 0 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_SHB_less_stdAlloc_stat, key_type, value_type, 0 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_SHT_less_stdAlloc_stat, key_type, value_type, 1 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_SHB_cmp_michaelAlloc, key_type, value_type, 0 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_SHT_cmp_michaelAlloc, key_type, value_type, 1 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_SHB_less_michaelAlloc, key_type, value_type, 1 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_SHT_less_michaelAlloc, key_type, value_type, 0 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_SHB_cmp_stdAlloc, key_type, value_type, 0 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_SHT_cmp_stdAlloc, key_type, value_type, 1 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_SHB_cmp_stdAlloc_stat, key_type, value_type, 1 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_SHT_cmp_stdAlloc_stat, key_type, value_type, 0 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_SHB_less_stdAlloc, key_type, value_type, 1 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_SHT_less_stdAlloc, key_type, value_type, 0 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_SHB_less_stdAlloc_stat, key_type, value_type, 0 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_SHT_less_stdAlloc_stat, key_type, value_type, 1 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_SHB_cmp_michaelAlloc, key_type, value_type, 0 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_SHT_cmp_michaelAlloc, key_type, value_type, 1 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_SHB_less_michaelAlloc, key_type, value_type, 1 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_SHT_less_michaelAlloc, key_type, value_type, 0 )
+
+# define CDSSTRESS_MichaelIterableSet_SHRCU( fixture, test_case, key_type, value_type ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_SHB_cmp_stdAlloc, key_type, value_type, 0 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_SHT_cmp_stdAlloc, key_type, value_type, 1 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_SHB_cmp_stdAlloc_stat, key_type, value_type, 1 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_SHT_cmp_stdAlloc_stat, key_type, value_type, 0 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_SHB_less_stdAlloc, key_type, value_type, 1 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_SHT_less_stdAlloc, key_type, value_type, 0 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_SHB_less_stdAlloc_stat, key_type, value_type, 0 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_SHT_less_stdAlloc_stat, key_type, value_type, 1 ) \
+
#else
# define CDSSTRESS_MichaelSet_SHRCU( fixture, test_case, key_type, value_type )
+# define CDSSTRESS_MichaelIterableSet_SHRCU( fixture, test_case, key_type, value_type )
#endif
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_GPI_cmp_stdAlloc, key_type, value_type, 0 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_GPB_cmp_stdAlloc, key_type, value_type, 1 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_GPT_cmp_stdAlloc, key_type, value_type, 0 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_HP_cmp_stdAlloc_stat, key_type, value_type, 1 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_DHP_cmp_stdAlloc_stat, key_type, value_type, 0 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_GPI_cmp_stdAlloc_stat, key_type, value_type, 1 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_GPB_cmp_stdAlloc_stat, key_type, value_type, 0 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_GPT_cmp_stdAlloc_stat, key_type, value_type, 1 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_HP_less_stdAlloc, key_type, value_type, 1 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_DHP_less_stdAlloc, key_type, value_type, 0 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_GPI_less_stdAlloc, key_type, value_type, 1 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_GPB_less_stdAlloc, key_type, value_type, 0 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_GPT_less_stdAlloc, key_type, value_type, 1 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_HP_less_stdAlloc_stat, key_type, value_type, 0 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_DHP_less_stdAlloc_stat, key_type, value_type, 1 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_GPI_less_stdAlloc_stat, key_type, value_type, 0 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_GPB_less_stdAlloc_stat, key_type, value_type, 1 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_GPT_less_stdAlloc_stat, key_type, value_type, 0 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_HP_cmp_michaelAlloc, key_type, value_type, 0 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_DHP_cmp_michaelAlloc, key_type, value_type, 1 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_GPI_cmp_michaelAlloc, key_type, value_type, 0 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_GPI_cmp_stdAlloc, key_type, value_type, 0 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_GPB_cmp_stdAlloc, key_type, value_type, 1 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_GPT_cmp_stdAlloc, key_type, value_type, 0 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_HP_cmp_stdAlloc_stat, key_type, value_type, 1 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_DHP_cmp_stdAlloc_stat, key_type, value_type, 0 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_GPI_cmp_stdAlloc_stat, key_type, value_type, 1 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_GPB_cmp_stdAlloc_stat, key_type, value_type, 0 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_GPT_cmp_stdAlloc_stat, key_type, value_type, 1 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_HP_less_stdAlloc, key_type, value_type, 1 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_DHP_less_stdAlloc, key_type, value_type, 0 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_GPI_less_stdAlloc, key_type, value_type, 1 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_GPB_less_stdAlloc, key_type, value_type, 0 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_GPT_less_stdAlloc, key_type, value_type, 1 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_HP_less_stdAlloc_stat, key_type, value_type, 0 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_DHP_less_stdAlloc_stat, key_type, value_type, 1 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_GPI_less_stdAlloc_stat, key_type, value_type, 0 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_GPB_less_stdAlloc_stat, key_type, value_type, 1 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_GPT_less_stdAlloc_stat, key_type, value_type, 0 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_HP_cmp_michaelAlloc, key_type, value_type, 0 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_DHP_cmp_michaelAlloc, key_type, value_type, 1 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_GPI_cmp_michaelAlloc, key_type, value_type, 0 ) \
CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_GPT_less_michaelAlloc, key_type, value_type, 1 ) \
CDSSTRESS_MichaelSet_SHRCU( fixture, test_case, key_type, value_type )
+#define CDSSTRESS_MichaelIterableSet( fixture, test_case, key_type, value_type ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_HP_cmp_stdAlloc, key_type, value_type, 0 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_DHP_cmp_stdAlloc, key_type, value_type, 1 ) \
+ /*CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_GPI_cmp_stdAlloc, key_type, value_type, 0 )*/ \
+ /*CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_GPB_cmp_stdAlloc, key_type, value_type, 1 )*/ \
+ /*CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_GPT_cmp_stdAlloc, key_type, value_type, 0 )*/ \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_HP_cmp_stdAlloc_stat, key_type, value_type, 1 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_DHP_cmp_stdAlloc_stat, key_type, value_type, 0 ) \
+ /*CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_GPI_cmp_stdAlloc_stat, key_type, value_type, 1 )*/ \
+ /*CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_GPB_cmp_stdAlloc_stat, key_type, value_type, 0 )*/ \
+ /*CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_GPT_cmp_stdAlloc_stat, key_type, value_type, 1 )*/ \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_HP_less_stdAlloc, key_type, value_type, 1 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_DHP_less_stdAlloc, key_type, value_type, 0 ) \
+ /*CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_GPI_less_stdAlloc, key_type, value_type, 1 )*/ \
+ /*CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_GPB_less_stdAlloc, key_type, value_type, 0 )*/ \
+ /*CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_GPT_less_stdAlloc, key_type, value_type, 1 )*/ \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_HP_less_stdAlloc_stat, key_type, value_type, 0 ) \
+ CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_DHP_less_stdAlloc_stat, key_type, value_type, 1 ) \
+ /*CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_GPI_less_stdAlloc_stat, key_type, value_type, 0 )*/ \
+ /*CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_GPB_less_stdAlloc_stat, key_type, value_type, 1 )*/ \
+ /*CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_GPT_less_stdAlloc_stat, key_type, value_type, 0 )*/ \
+ /*CDSSTRESS_MichaelIterableSet_SHRCU( fixture, test_case, key_type, value_type )*/
+
#endif // #ifndef CDSUNIT_SET_TYPE_MICHAEL_H
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSUNIT_SET_TYPE_MICHAEL_LIST_H
typedef cc::MichaelList< rcu_sht, key_val, traits_MichaelList_cmp_stdAlloc > MichaelList_RCU_SHT_cmp_stdAlloc;
#endif
+ struct traits_MichaelList_cmp_stdAlloc_stat: public traits_MichaelList_cmp_stdAlloc
+ {
+ typedef cc::michael_list::stat<> stat;
+ };
+ typedef cc::MichaelList< cds::gc::HP, key_val, traits_MichaelList_cmp_stdAlloc_stat > MichaelList_HP_cmp_stdAlloc_stat;
+ typedef cc::MichaelList< cds::gc::DHP, key_val, traits_MichaelList_cmp_stdAlloc_stat > MichaelList_DHP_cmp_stdAlloc_stat;
+ typedef cc::MichaelList< rcu_gpi, key_val, traits_MichaelList_cmp_stdAlloc_stat > MichaelList_RCU_GPI_cmp_stdAlloc_stat;
+ typedef cc::MichaelList< rcu_gpb, key_val, traits_MichaelList_cmp_stdAlloc_stat > MichaelList_RCU_GPB_cmp_stdAlloc_stat;
+ typedef cc::MichaelList< rcu_gpt, key_val, traits_MichaelList_cmp_stdAlloc_stat > MichaelList_RCU_GPT_cmp_stdAlloc_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+ typedef cc::MichaelList< rcu_shb, key_val, traits_MichaelList_cmp_stdAlloc_stat > MichaelList_RCU_SHB_cmp_stdAlloc_stat;
+ typedef cc::MichaelList< rcu_sht, key_val, traits_MichaelList_cmp_stdAlloc_stat > MichaelList_RCU_SHT_cmp_stdAlloc_stat;
+#endif
+
struct traits_MichaelList_cmp_stdAlloc_seqcst : public traits_MichaelList_cmp_stdAlloc
{
typedef co::v::sequential_consistent memory_model;
typedef cc::MichaelList< rcu_sht, key_val, traits_MichaelList_less_stdAlloc > MichaelList_RCU_SHT_less_stdAlloc;
#endif
+ struct traits_MichaelList_less_stdAlloc_stat : public traits_MichaelList_less_stdAlloc
+ {
+ typedef cc::michael_list::stat<> stat;
+ };
+ typedef cc::MichaelList< cds::gc::HP, key_val, traits_MichaelList_less_stdAlloc_stat > MichaelList_HP_less_stdAlloc_stat;
+ typedef cc::MichaelList< cds::gc::DHP, key_val, traits_MichaelList_less_stdAlloc_stat > MichaelList_DHP_less_stdAlloc_stat;
+ typedef cc::MichaelList< rcu_gpi, key_val, traits_MichaelList_less_stdAlloc_stat > MichaelList_RCU_GPI_less_stdAlloc_stat;
+ typedef cc::MichaelList< rcu_gpb, key_val, traits_MichaelList_less_stdAlloc_stat > MichaelList_RCU_GPB_less_stdAlloc_stat;
+ typedef cc::MichaelList< rcu_gpt, key_val, traits_MichaelList_less_stdAlloc_stat > MichaelList_RCU_GPT_less_stdAlloc_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+ typedef cc::MichaelList< rcu_shb, key_val, traits_MichaelList_less_stdAlloc_stat > MichaelList_RCU_SHB_less_stdAlloc_stat;
+ typedef cc::MichaelList< rcu_sht, key_val, traits_MichaelList_less_stdAlloc_stat > MichaelList_RCU_SHT_less_stdAlloc_stat;
+#endif
+
struct traits_MichaelList_less_stdAlloc_seqcst :
public cc::michael_list::make_traits<
co::less< less >
intrusive_feldman_hashset_rcu_gpt.cpp
intrusive_feldman_hashset_rcu_shb.cpp
intrusive_feldman_hashset_rcu_sht.cpp
+ intrusive_michael_iterable_dhp.cpp
+ intrusive_michael_iterable_hp.cpp
intrusive_michael_lazy_hp.cpp
intrusive_michael_lazy_dhp.cpp
intrusive_michael_lazy_nogc.cpp
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "test_intrusive_michael_iterable_hp.h"
+
+#include <cds/intrusive/iterable_list_dhp.h>
+#include <cds/intrusive/michael_set.h>
+
+namespace {
+ namespace ci = cds::intrusive;
+ typedef cds::gc::DHP gc_type;
+
+ class IntrusiveMichaelIterableSet_DHP : public cds_test::intrusive_set_hp
+ {
+ protected:
+ typedef cds_test::intrusive_set_hp base_class;
+
+ protected:
+ void SetUp()
+ {
+ struct list_traits : public ci::iterable_list::traits
+ {};
+ typedef ci::IterableList< gc_type, item_type, list_traits > list_type;
+ typedef ci::MichaelHashSet< gc_type, list_type > set_type;
+
+ cds::gc::dhp::GarbageCollector::Construct( 16, set_type::c_nHazardPtrCount );
+ cds::threading::Manager::attachThread();
+ }
+
+ void TearDown()
+ {
+ cds::threading::Manager::detachThread();
+ cds::gc::dhp::GarbageCollector::Destruct();
+ }
+ };
+
+
+ TEST_F( IntrusiveMichaelIterableSet_DHP, cmp )
+ {
+ typedef ci::IterableList< gc_type
+ , item_type
+ ,ci::iterable_list::make_traits<
+ ci::opt::compare< cmp<item_type> >
+ ,ci::opt::disposer< mock_disposer >
+ >::type
+ > bucket_type;
+
+ typedef ci::MichaelHashSet< gc_type, bucket_type,
+ ci::michael_set::make_traits<
+ ci::opt::hash< hash_int >
+ >::type
+ > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
+ TEST_F( IntrusiveMichaelIterableSet_DHP, less )
+ {
+ typedef ci::IterableList< gc_type
+ , item_type
+ ,ci::iterable_list::make_traits<
+ ci::opt::less< less<item_type> >
+ ,ci::opt::disposer< mock_disposer >
+ >::type
+ > bucket_type;
+
+ typedef ci::MichaelHashSet< gc_type, bucket_type,
+ ci::michael_set::make_traits<
+ ci::opt::hash< hash_int >
+ >::type
+ > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
+ TEST_F( IntrusiveMichaelIterableSet_DHP, cmpmix )
+ {
+ struct list_traits : public ci::iterable_list::traits
+ {
+ typedef base_class::less<item_type> less;
+ typedef cmp<item_type> compare;
+ typedef mock_disposer disposer;
+ };
+ typedef ci::IterableList< gc_type, item_type, list_traits > bucket_type;
+
+ struct set_traits : public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
+ TEST_F( IntrusiveMichaelIterableSet_DHP, stat )
+ {
+ struct list_traits: public ci::iterable_list::traits
+ {
+ typedef base_class::less<item_type> less;
+ typedef mock_disposer disposer;
+ typedef ci::iterable_list::stat<> stat;
+ };
+ typedef ci::IterableList< gc_type, item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
+ TEST_F( IntrusiveMichaelIterableSet_DHP, wrapped_stat )
+ {
+ struct list_traits: public ci::iterable_list::traits
+ {
+ typedef base_class::less<item_type> less;
+ typedef mock_disposer disposer;
+ typedef ci::iterable_list::wrapped_stat<> stat;
+ };
+ typedef ci::IterableList< gc_type, item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
+} // namespace
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "test_intrusive_michael_iterable_hp.h"
+
+#include <cds/intrusive/iterable_list_hp.h>
+#include <cds/intrusive/michael_set.h>
+
+namespace {
+ namespace ci = cds::intrusive;
+ typedef cds::gc::HP gc_type;
+
+ class IntrusiveMichaelIterableSet_HP : public cds_test::intrusive_set_hp
+ {
+ protected:
+ typedef cds_test::intrusive_set_hp base_class;
+
+ protected:
+ void SetUp()
+ {
+ struct list_traits : public ci::iterable_list::traits
+ {};
+ typedef ci::IterableList< gc_type, item_type, list_traits > list_type;
+ typedef ci::MichaelHashSet< gc_type, list_type > set_type;
+
+ // +3 - for iterators
+ cds::gc::hp::GarbageCollector::Construct( set_type::c_nHazardPtrCount + 3, 1, 16 );
+ cds::threading::Manager::attachThread();
+ }
+
+ void TearDown()
+ {
+ cds::threading::Manager::detachThread();
+ cds::gc::hp::GarbageCollector::Destruct( true );
+ }
+ };
+
+
+ TEST_F( IntrusiveMichaelIterableSet_HP, cmp )
+ {
+ typedef ci::IterableList< gc_type
+ , item_type
+ ,ci::iterable_list::make_traits<
+ ci::opt::compare< cmp<item_type> >
+ ,ci::opt::disposer< mock_disposer >
+ >::type
+ > bucket_type;
+
+ typedef ci::MichaelHashSet< gc_type, bucket_type,
+ ci::michael_set::make_traits<
+ ci::opt::hash< hash_int >
+ >::type
+ > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
+ TEST_F( IntrusiveMichaelIterableSet_HP, less )
+ {
+ typedef ci::IterableList< gc_type
+ , item_type
+ ,ci::iterable_list::make_traits<
+ ci::opt::less< less<item_type> >
+ ,ci::opt::disposer< mock_disposer >
+ >::type
+ > bucket_type;
+
+ typedef ci::MichaelHashSet< gc_type, bucket_type,
+ ci::michael_set::make_traits<
+ ci::opt::hash< hash_int >
+ >::type
+ > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
+ TEST_F( IntrusiveMichaelIterableSet_HP, cmpmix )
+ {
+ struct list_traits : public ci::iterable_list::traits
+ {
+ typedef base_class::less<item_type> less;
+ typedef cmp<item_type> compare;
+ typedef mock_disposer disposer;
+ };
+ typedef ci::IterableList< gc_type, item_type, list_traits > bucket_type;
+
+ struct set_traits : public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
+ TEST_F( IntrusiveMichaelIterableSet_HP, stat )
+ {
+ struct list_traits: public ci::iterable_list::traits
+ {
+ typedef base_class::less<item_type> less;
+ typedef cmp<item_type> compare;
+ typedef mock_disposer disposer;
+ typedef ci::iterable_list::stat<> stat;
+ };
+ typedef ci::IterableList< gc_type, item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
+ TEST_F( IntrusiveMichaelIterableSet_HP, wrapped_stat )
+ {
+ struct list_traits: public ci::iterable_list::traits
+ {
+ typedef base_class::less<item_type> less;
+ typedef cmp<item_type> compare;
+ typedef mock_disposer disposer;
+ typedef ci::iterable_list::wrapped_stat<> stat;
+ };
+ typedef ci::IterableList< gc_type, item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
+} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_intrusive_set_hp.h"
test( s );
}
+ TEST_F( IntrusiveMichaelLazySet_DHP, base_stat )
+ {
+ struct list_traits: public ci::lazy_list::traits
+ {
+ typedef ci::lazy_list::base_hook< ci::opt::gc<gc_type>> hook;
+ typedef base_class::less<base_item_type> less;
+ typedef mock_disposer disposer;
+ typedef ci::lazy_list::stat<> stat;
+ };
+ typedef ci::LazyList< gc_type, base_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
+ TEST_F( IntrusiveMichaelLazySet_DHP, base_wrapped_stat )
+ {
+ struct list_traits: public ci::lazy_list::traits
+ {
+ typedef ci::lazy_list::base_hook< ci::opt::gc<gc_type>> hook;
+ typedef base_class::less<base_item_type> less;
+ typedef mock_disposer disposer;
+ typedef ci::lazy_list::wrapped_stat<> stat;
+ };
+ typedef ci::LazyList< gc_type, base_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
TEST_F( IntrusiveMichaelLazySet_DHP, member_cmp )
{
test( s );
}
+ TEST_F( IntrusiveMichaelLazySet_DHP, member_stat )
+ {
+ struct list_traits: public ci::lazy_list::traits
+ {
+ typedef ci::lazy_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<gc_type>> hook;
+ typedef cmp<member_item_type> compare;
+ typedef mock_disposer disposer;
+ typedef ci::lazy_list::stat<> stat;
+ };
+ typedef ci::LazyList< gc_type, member_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
+ TEST_F( IntrusiveMichaelLazySet_DHP, member_wrapped_stat )
+ {
+ struct list_traits: public ci::lazy_list::traits
+ {
+ typedef ci::lazy_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<gc_type>> hook;
+ typedef cmp<member_item_type> compare;
+ typedef mock_disposer disposer;
+ typedef ci::lazy_list::wrapped_stat<> stat;
+ };
+ typedef ci::LazyList< gc_type, member_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_intrusive_set_hp.h"
test( s );
}
+ TEST_F( IntrusiveMichaelLazySet_HP, base_stat )
+ {
+ struct list_traits: public ci::lazy_list::traits
+ {
+ typedef ci::lazy_list::base_hook< ci::opt::gc<gc_type>, ci::opt::lock_type<std::mutex>> hook;
+ typedef cmp<base_mutex_item_type> compare;
+ typedef mock_disposer disposer;
+ typedef ci::lazy_list::stat<> stat;
+ };
+ typedef ci::LazyList< gc_type, base_mutex_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
+ TEST_F( IntrusiveMichaelLazySet_HP, base_wrapped_stat )
+ {
+ struct list_traits: public ci::lazy_list::traits
+ {
+ typedef ci::lazy_list::base_hook< ci::opt::gc<gc_type>> hook;
+ typedef cmp<base_item_type> compare;
+ typedef mock_disposer disposer;
+ typedef ci::lazy_list::wrapped_stat<> stat;
+ };
+ typedef ci::LazyList< gc_type, base_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
TEST_F( IntrusiveMichaelLazySet_HP, member_cmp )
{
test( s );
}
+ TEST_F( IntrusiveMichaelLazySet_HP, member_stat )
+ {
+ struct list_traits: public ci::lazy_list::traits
+ {
+ typedef ci::lazy_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<gc_type>> hook;
+ typedef base_class::less<member_item_type> less;
+ typedef mock_disposer disposer;
+ typedef ci::lazy_list::stat<> stat;
+ };
+ typedef ci::LazyList< gc_type, member_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
+ TEST_F( IntrusiveMichaelLazySet_HP, member_wrapped_stat )
+ {
+ struct list_traits: public ci::lazy_list::traits
+ {
+ typedef ci::lazy_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<gc_type>> hook;
+ typedef base_class::less<member_item_type> less;
+ typedef mock_disposer disposer;
+ typedef ci::lazy_list::wrapped_stat<> stat;
+ };
+ typedef ci::LazyList< gc_type, member_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_intrusive_set_nogc.h"
test( s );
}
+ TEST_F( IntrusiveMichaelLazySet_NoGC, base_stat )
+ {
+ struct list_traits: public ci::lazy_list::traits
+ {
+ typedef ci::lazy_list::base_hook< ci::opt::gc<gc_type>> hook;
+ typedef base_class::less<base_item_type> less;
+ typedef mock_disposer disposer;
+ typedef ci::lazy_list::stat<> stat;
+ };
+ typedef ci::LazyList< gc_type, base_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
+ TEST_F( IntrusiveMichaelLazySet_NoGC, base_wrapped_stat )
+ {
+ struct list_traits: public ci::lazy_list::traits
+ {
+ typedef ci::lazy_list::base_hook< ci::opt::gc<gc_type>> hook;
+ typedef base_class::less<base_item_type> less;
+ typedef mock_disposer disposer;
+ typedef ci::lazy_list::wrapped_stat<> stat;
+ };
+ typedef ci::LazyList< gc_type, base_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
TEST_F( IntrusiveMichaelLazySet_NoGC, member_cmp )
{
test( s );
}
+ TEST_F( IntrusiveMichaelLazySet_NoGC, member_stat )
+ {
+ struct list_traits: public ci::lazy_list::traits
+ {
+ typedef ci::lazy_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<gc_type>> hook;
+ typedef cmp<member_item_type> compare;
+ typedef mock_disposer disposer;
+ typedef ci::lazy_list::stat<> stat;
+ };
+ typedef ci::LazyList< gc_type, member_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
+ TEST_F( IntrusiveMichaelLazySet_NoGC, member_wrapped_stat )
+ {
+ struct list_traits: public ci::lazy_list::traits
+ {
+ typedef ci::lazy_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<gc_type>> hook;
+ typedef cmp<member_item_type> compare;
+ typedef mock_disposer disposer;
+ typedef ci::lazy_list::wrapped_stat<> stat;
+ };
+ typedef ci::LazyList< gc_type, member_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_intrusive_set_hp.h"
test( s );
}
+ TEST_F( IntrusiveMichaelSet_DHP, base_stat )
+ {
+ struct list_traits: public ci::michael_list::traits
+ {
+ typedef ci::michael_list::base_hook< ci::opt::gc<gc_type>> hook;
+ typedef base_class::less<base_item_type> less;
+ typedef cmp<base_item_type> compare;
+ typedef mock_disposer disposer;
+ typedef ci::michael_list::stat<> stat;
+ };
+ typedef ci::MichaelList< gc_type, base_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
+ TEST_F( IntrusiveMichaelSet_DHP, base_wrapped_stat )
+ {
+ struct list_traits: public ci::michael_list::traits
+ {
+ typedef ci::michael_list::base_hook< ci::opt::gc<gc_type>> hook;
+ typedef base_class::less<base_item_type> less;
+ typedef cmp<base_item_type> compare;
+ typedef mock_disposer disposer;
+ typedef ci::michael_list::wrapped_stat<> stat;
+ };
+ typedef ci::MichaelList< gc_type, base_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
TEST_F( IntrusiveMichaelSet_DHP, member_cmp )
{
test( s );
}
+ TEST_F( IntrusiveMichaelSet_DHP, member_stat )
+ {
+ struct list_traits: public ci::michael_list::traits
+ {
+ typedef ci::michael_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<gc_type>> hook;
+ typedef base_class::less<member_item_type> less;
+ typedef cmp<member_item_type> compare;
+ typedef mock_disposer disposer;
+ typedef ci::michael_list::stat<> stat;
+ };
+ typedef ci::MichaelList< gc_type, member_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
+ TEST_F( IntrusiveMichaelSet_DHP, member_wrapped_stat )
+ {
+ struct list_traits: public ci::michael_list::traits
+ {
+ typedef ci::michael_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<gc_type>> hook;
+ typedef base_class::less<member_item_type> less;
+ typedef cmp<member_item_type> compare;
+ typedef mock_disposer disposer;
+ typedef ci::michael_list::wrapped_stat<> stat;
+ };
+ typedef ci::MichaelList< gc_type, member_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_intrusive_set_hp.h"
}
+ TEST_F( IntrusiveMichaelSet_HP, base_stat )
+ {
+ struct list_traits: public ci::michael_list::traits
+ {
+ typedef ci::michael_list::base_hook< ci::opt::gc<gc_type>> hook;
+ typedef cmp<base_item_type> compare;
+ typedef mock_disposer disposer;
+ typedef ci::michael_list::stat<> stat;
+ };
+ typedef ci::MichaelList< gc_type, base_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
+ TEST_F( IntrusiveMichaelSet_HP, base_wrapped_stat )
+ {
+ struct list_traits: public ci::michael_list::traits
+ {
+ typedef ci::michael_list::base_hook< ci::opt::gc<gc_type>> hook;
+ typedef base_class::less<base_item_type> less;
+ typedef mock_disposer disposer;
+ typedef ci::michael_list::wrapped_stat<> stat;
+ };
+ typedef ci::MichaelList< gc_type, base_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
TEST_F( IntrusiveMichaelSet_HP, member_cmp )
{
typedef ci::MichaelList< gc_type
test( s );
}
+ TEST_F( IntrusiveMichaelSet_HP, member_stat )
+ {
+ struct list_traits: public ci::michael_list::traits
+ {
+ typedef ci::michael_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<gc_type>> hook;
+ typedef base_class::less<member_item_type> less;
+ typedef cmp<member_item_type> compare;
+ typedef mock_disposer disposer;
+ typedef ci::michael_list::stat<> stat;
+ };
+ typedef ci::MichaelList< gc_type, member_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
+ TEST_F( IntrusiveMichaelSet_HP, member_wrapped_stat )
+ {
+ struct list_traits: public ci::michael_list::traits
+ {
+ typedef ci::michael_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<gc_type>> hook;
+ typedef base_class::less<member_item_type> less;
+ typedef cmp<member_item_type> compare;
+ typedef mock_disposer disposer;
+ typedef ci::michael_list::wrapped_stat<> stat;
+ };
+ typedef ci::MichaelList< gc_type, member_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_intrusive_set_nogc.h"
test( s );
}
+ TEST_F( IntrusiveMichaelSet_NoGC, base_stat )
+ {
+ struct list_traits: public ci::michael_list::traits
+ {
+ typedef ci::michael_list::base_hook< ci::opt::gc<gc_type>> hook;
+ typedef base_class::less<base_item_type> less;
+ typedef mock_disposer disposer;
+ typedef ci::michael_list::stat<> stat;
+ };
+ typedef ci::MichaelList< gc_type, base_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
+ TEST_F( IntrusiveMichaelSet_NoGC, base_wrapped_stat )
+ {
+ struct list_traits: public ci::michael_list::traits
+ {
+ typedef ci::michael_list::base_hook< ci::opt::gc<gc_type>> hook;
+ typedef base_class::less<base_item_type> less;
+ typedef mock_disposer disposer;
+ typedef ci::michael_list::wrapped_stat<> stat;
+ };
+ typedef ci::MichaelList< gc_type, base_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
TEST_F( IntrusiveMichaelSet_NoGC, member_cmp )
{
test( s );
}
+ TEST_F( IntrusiveMichaelSet_NoGC, member_stat )
+ {
+ struct list_traits: public ci::michael_list::traits
+ {
+ typedef ci::michael_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<gc_type>> hook;
+ typedef cmp<member_item_type> compare;
+ typedef mock_disposer disposer;
+ typedef ci::michael_list::stat<> stat;
+ };
+ typedef ci::MichaelList< gc_type, member_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
+ TEST_F( IntrusiveMichaelSet_NoGC, member_wrapped_stat )
+ {
+ struct list_traits: public ci::michael_list::traits
+ {
+ typedef ci::michael_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<gc_type>> hook;
+ typedef cmp<member_item_type> compare;
+ typedef mock_disposer disposer;
+ typedef ci::michael_list::wrapped_stat<> stat;
+ };
+ typedef ci::MichaelList< gc_type, member_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
} // namespace
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSUNIT_SET_TEST_INTRUSIVE_MICHAEL_ITERABLE_H
+#define CDSUNIT_SET_TEST_INTRUSIVE_MICHAEL_ITERABLE_H
+
+#include <cds_test/check_size.h>
+#include <cds_test/fixture.h>
+
+#include <cds/opt/hash.h>
+#include <functional> // ref
+
+// forward declaration
+namespace cds { namespace intrusive {}}
+
+namespace cds_test {
+
+ namespace ci = cds::intrusive;
+ namespace co = cds::opt;
+
+ class intrusive_set: public fixture
+ {
+ public:
+ static size_t const kSize = 100;
+
+ struct stat
+ {
+ unsigned int nDisposeCount ; // count of disposer calling
+ unsigned int nFindCount ; // count of find-functor calling
+ unsigned int nUpdateNewCount;
+ unsigned int nUpdateCount;
+ mutable unsigned int nEraseCount;
+
+ stat()
+ {
+ clear_stat();
+ }
+
+ void clear_stat()
+ {
+ memset( this, 0, sizeof( *this ) );
+ }
+ };
+
+ struct item_type: public stat
+ {
+ int nKey;
+ int nVal;
+
+ item_type( int k )
+ : nKey(k)
+ , nVal(0)
+ {}
+
+ int key() const
+ {
+ return nKey;
+ }
+ };
+
+ struct hash_int {
+ size_t operator()( int i ) const
+ {
+ return co::v::hash<int>()( i );
+ }
+ template <typename Q>
+ size_t operator()( Q const& i ) const
+ {
+ return (*this)( i.key());
+ }
+ };
+
+ struct simple_item_counter {
+ size_t m_nCount;
+
+ simple_item_counter()
+ : m_nCount(0)
+ {}
+
+ size_t operator ++()
+ {
+ return ++m_nCount;
+ }
+
+ size_t operator --()
+ {
+ return --m_nCount;
+ }
+
+ void reset()
+ {
+ m_nCount = 0;
+ }
+
+ operator size_t() const
+ {
+ return m_nCount;
+ }
+
+ };
+
+
+ template <typename T>
+ struct less
+ {
+ bool operator ()(const T& v1, const T& v2 ) const
+ {
+ return v1.key() < v2.key();
+ }
+
+ template <typename Q>
+ bool operator ()(const T& v1, const Q& v2 ) const
+ {
+ return v1.key() < v2;
+ }
+
+ template <typename Q>
+ bool operator ()(const Q& v1, const T& v2 ) const
+ {
+ return v1 < v2.key();
+ }
+ };
+
+ template <typename T>
+ struct cmp {
+ int operator ()(const T& v1, const T& v2 ) const
+ {
+ if ( v1.key() < v2.key() )
+ return -1;
+ return v1.key() > v2.key() ? 1 : 0;
+ }
+
+ template <typename Q>
+ int operator ()(const T& v1, const Q& v2 ) const
+ {
+ if ( v1.key() < v2 )
+ return -1;
+ return v1.key() > v2 ? 1 : 0;
+ }
+
+ template <typename Q>
+ int operator ()(const Q& v1, const T& v2 ) const
+ {
+ if ( v1 < v2.key() )
+ return -1;
+ return v1 > v2.key() ? 1 : 0;
+ }
+ };
+
+ struct other_item {
+ int nKey;
+
+ explicit other_item( int k )
+ : nKey( k )
+ {}
+
+ int key() const
+ {
+ return nKey;
+ }
+ };
+
+ struct other_less {
+ template <typename Q, typename T>
+ bool operator()( Q const& lhs, T const& rhs ) const
+ {
+ return lhs.key() < rhs.key();
+ }
+ };
+
+ struct mock_disposer
+ {
+ template <typename T>
+ void operator ()( T * p )
+ {
+ ++p->nDisposeCount;
+ }
+ };
+
+ protected:
+ template <class Set>
+ void test( Set& s )
+ {
+ // Precondition: set is empty
+ // Postcondition: set is empty
+
+ ASSERT_TRUE( s.empty() );
+ ASSERT_CONTAINER_SIZE( s, 0 );
+ size_t const nSetSize = kSize;
+
+ typedef typename Set::value_type value_type;
+
+ std::vector< value_type > data;
+ std::vector< size_t> indices;
+ data.reserve( kSize );
+ indices.reserve( kSize );
+ for ( size_t key = 0; key < kSize; ++key ) {
+ data.push_back( value_type( static_cast<int>( key )));
+ indices.push_back( key );
+ }
+ shuffle( indices.begin(), indices.end() );
+
+ // insert/find
+ for ( auto idx : indices ) {
+ auto& i = data[ idx ];
+
+ ASSERT_FALSE( s.contains( i.nKey ));
+ ASSERT_FALSE( s.contains( i ));
+ ASSERT_FALSE( s.contains( other_item( i.key()), other_less()));
+ ASSERT_FALSE( s.find( i.nKey, []( value_type&, int ) {} ));
+ ASSERT_FALSE( s.find_with( other_item( i.key()), other_less(), []( value_type&, other_item const& ) {} ));
+ ASSERT_TRUE( s.find( i.nKey ) == s.end());
+ ASSERT_TRUE( s.find_with( other_item( i.key() ), other_less()) == s.end());
+
+ std::pair<bool, bool> updResult;
+
+ updResult = s.update( i, []( value_type&, value_type* )
+ {
+ ASSERT_TRUE( false );
+ }, false );
+ EXPECT_FALSE( updResult.first );
+ EXPECT_FALSE( updResult.second );
+
+ updResult = s.upsert( i, false );
+ EXPECT_FALSE( updResult.first );
+ EXPECT_FALSE( updResult.second );
+
+ switch ( i.key() % 4 ) {
+ case 0:
+ ASSERT_TRUE( s.insert( i ));
+ ASSERT_FALSE( s.insert( i ));
+ updResult = s.update( i, []( value_type& val, value_type* arg)
+ {
+ ASSERT_TRUE( arg != nullptr );
+ EXPECT_EQ( val.key(), arg->key() );
+ }, false );
+ EXPECT_TRUE( updResult.first );
+ EXPECT_FALSE( updResult.second );
+ break;
+ case 1:
+ EXPECT_EQ( i.nUpdateNewCount, 0 );
+ ASSERT_TRUE( s.insert( i, []( value_type& v ) { ++v.nUpdateNewCount;} ));
+ EXPECT_EQ( i.nUpdateNewCount, 1 );
+ ASSERT_FALSE( s.insert( i, []( value_type& v ) { ++v.nUpdateNewCount;} ) );
+ EXPECT_EQ( i.nUpdateNewCount, 1 );
+ i.nUpdateNewCount = 0;
+ break;
+ case 2:
+ updResult = s.update( i, []( value_type& /*val*/, value_type* arg )
+ {
+ EXPECT_TRUE( arg == nullptr );
+ });
+ EXPECT_TRUE( updResult.first );
+ EXPECT_TRUE( updResult.second );
+ break;
+ case 3:
+ updResult = s.upsert( i );
+ EXPECT_TRUE( updResult.first );
+ EXPECT_TRUE( updResult.second );
+ break;
+ }
+
+ ASSERT_TRUE( s.contains( i.nKey ) );
+ ASSERT_TRUE( s.contains( i ) );
+ ASSERT_TRUE( s.contains( other_item( i.key() ), other_less()));
+ EXPECT_EQ( i.nFindCount, 0 );
+ ASSERT_TRUE( s.find( i.nKey, []( value_type& v, int ) { ++v.nFindCount; } ));
+ EXPECT_EQ( i.nFindCount, 1 );
+ ASSERT_TRUE( s.find_with( other_item( i.key() ), other_less(), []( value_type& v, other_item const& ) { ++v.nFindCount; } ));
+ EXPECT_EQ( i.nFindCount, 2 );
+ ASSERT_TRUE( s.find( i.nKey ) != s.end() );
+ ASSERT_TRUE( s.find_with( other_item( i.key() ), other_less() ) != s.end() );
+ EXPECT_EQ( s.find( i.nKey )->nKey, i.key() );
+ EXPECT_EQ( s.find_with( other_item( i.key() ), other_less())->nKey, i.key() );
+ }
+ ASSERT_FALSE( s.empty() );
+ ASSERT_CONTAINER_SIZE( s, nSetSize );
+
+ std::for_each( data.begin(), data.end(), []( value_type& v ) { v.clear_stat(); });
+
+ // erase
+ shuffle( indices.begin(), indices.end() );
+ for ( auto idx : indices ) {
+ auto& i = data[ idx ];
+
+ ASSERT_TRUE( s.contains( i.nKey ) );
+ ASSERT_TRUE( s.contains( i ) );
+ ASSERT_TRUE( s.contains( other_item( i.key() ), other_less() ) );
+ EXPECT_EQ( i.nFindCount, 0 );
+ ASSERT_TRUE( s.find( i.nKey, []( value_type& v, int ) { ++v.nFindCount; } ) );
+ EXPECT_EQ( i.nFindCount, 1 );
+ ASSERT_TRUE( s.find_with( other_item( i.key() ), other_less(), []( value_type& v, other_item const& ) { ++v.nFindCount; } ) );
+ EXPECT_EQ( i.nFindCount, 2 );
+ ASSERT_TRUE( s.find( i.nKey ) != s.end() );
+ ASSERT_TRUE( s.find_with( other_item( i.key() ), other_less()) != s.end() );
+ EXPECT_EQ( s.find( i.nKey )->nKey, i.key() );
+ EXPECT_EQ( s.find_with( other_item( i.key() ), other_less())->nKey, i.key() );
+
+
+ value_type v( i );
+ switch ( i.key() % 6 ) {
+ case 0:
+ ASSERT_FALSE( s.unlink( v ));
+ ASSERT_TRUE( s.unlink( i ));
+ ASSERT_FALSE( s.unlink( i ) );
+ break;
+ case 1:
+ ASSERT_TRUE( s.erase( i.key()));
+ ASSERT_FALSE( s.erase( i.key() ) );
+ break;
+ case 2:
+ ASSERT_TRUE( s.erase( v ));
+ ASSERT_FALSE( s.erase( v ) );
+ break;
+ case 3:
+ ASSERT_TRUE( s.erase_with( other_item( i.key()), other_less()));
+ ASSERT_FALSE( s.erase_with( other_item( i.key() ), other_less() ) );
+ break;
+ case 4:
+ EXPECT_EQ( i.nEraseCount, 0 );
+ ASSERT_TRUE( s.erase( v, []( value_type& val ) { ++val.nEraseCount; } ));
+ EXPECT_EQ( i.nEraseCount, 1 );
+ ASSERT_FALSE( s.erase( v, []( value_type& val ) { ++val.nEraseCount; } ));
+ EXPECT_EQ( i.nEraseCount, 1 );
+ break;
+ case 5:
+ EXPECT_EQ( i.nEraseCount, 0 );
+ ASSERT_TRUE( s.erase_with( other_item( i.key() ), other_less(), []( value_type& val ) { ++val.nEraseCount; } ));
+ EXPECT_EQ( i.nEraseCount, 1 );
+ ASSERT_FALSE( s.erase_with( other_item( i.key() ), other_less(), []( value_type& val ) { ++val.nEraseCount; } ));
+ EXPECT_EQ( i.nEraseCount, 1 );
+ break;
+ }
+
+ ASSERT_FALSE( s.contains( i.nKey ));
+ ASSERT_FALSE( s.contains( i ));
+ ASSERT_FALSE( s.contains( other_item( i.key()), other_less()));
+ ASSERT_FALSE( s.find( i.nKey, []( value_type&, int ) {} ));
+ ASSERT_FALSE( s.find_with( other_item( i.key()), other_less(), []( value_type&, other_item const& ) {} ));
+ ASSERT_TRUE( s.find( i.nKey ) == s.end() );
+ ASSERT_TRUE( s.find_with( other_item( i.key() ), other_less() ) == s.end() );
+ }
+ ASSERT_TRUE( s.empty() );
+ ASSERT_CONTAINER_SIZE( s, 0 );
+
+ // Force retiring cycle
+ Set::gc::force_dispose();
+ for ( auto& i : data ) {
+ EXPECT_EQ( i.nDisposeCount, 1 );
+ }
+
+ // clear
+ for ( auto& i : data ) {
+ i.clear_stat();
+ ASSERT_TRUE( s.insert( i ));
+ }
+ ASSERT_FALSE( s.empty() );
+ ASSERT_CONTAINER_SIZE( s, nSetSize );
+
+ // Iterator test
+ for ( auto it = s.begin(); it != s.end(); ++it ) {
+ ++it->nFindCount;
+ }
+ for ( auto it = s.cbegin(); it != s.cend(); ++it ) {
+ EXPECT_EQ( it->nFindCount, 1 );
+ }
+ for ( auto& i : data ) {
+ EXPECT_EQ( i.nFindCount, 1 );
+ }
+
+ // clear test
+ s.clear();
+
+ ASSERT_TRUE( s.empty());
+ ASSERT_CONTAINER_SIZE( s, 0 );
+ ASSERT_TRUE( s.begin() == s.end() );
+ ASSERT_TRUE( s.cbegin() == s.cend() );
+
+ // Force retiring cycle
+ Set::gc::force_dispose();
+ for ( auto& i : data ) {
+ EXPECT_EQ( i.nDisposeCount, 1 );
+ }
+
+ }
+ };
+
+} // namespace cds_test
+
+#endif // #ifndef CDSUNIT_SET_TEST_INTRUSIVE_MICHAEL_ITERABLE_H
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSUNIT_SET_TEST_INTRUSIVE_MICHAEL_ITERABLE_HP_H
+#define CDSUNIT_SET_TEST_INTRUSIVE_MICHAEL_ITERABLE_HP_H
+
+#include "test_intrusive_michael_iterable.h"
+
+// forward declaration
+namespace cds { namespace intrusive {}}
+
+namespace cds_test {
+
+ namespace ci = cds::intrusive;
+ namespace co = cds::opt;
+
+ class intrusive_set_hp: public intrusive_set
+ {
+ typedef intrusive_set base_class;
+
+ protected:
+
+ template <class Set>
+ void test( Set& s )
+ {
+ // Precondition: set is empty
+ // Postcondition: set is empty
+
+ base_class::test( s );
+
+ ASSERT_TRUE( s.empty() );
+ ASSERT_CONTAINER_SIZE( s, 0 );
+
+ typedef typename Set::value_type value_type;
+
+ std::vector< value_type > data;
+ std::vector< size_t> indices;
+ data.reserve( kSize );
+ indices.reserve( kSize );
+ for ( size_t key = 0; key < kSize; ++key ) {
+ data.push_back( value_type( static_cast<int>(key) ) );
+ indices.push_back( key );
+ }
+ shuffle( indices.begin(), indices.end() );
+
+ typename Set::guarded_ptr gp;
+
+ // get/extract from empty set
+ for ( auto idx : indices ) {
+ auto& i = data[idx];
+
+ gp = s.get( i );
+ ASSERT_TRUE( !gp );
+ gp = s.get( i.key() );
+ ASSERT_TRUE( !gp );
+ gp = s.get_with( other_item( i.key()), other_less());
+ ASSERT_TRUE( !gp );
+
+ gp = s.extract( i );
+ ASSERT_TRUE( !gp );
+ gp = s.extract( i.key());
+ ASSERT_TRUE( !gp );
+ gp = s.extract_with( other_item( i.key()), other_less());
+ ASSERT_TRUE( !gp );
+ }
+
+ // fill set
+ for ( auto& i : data ) {
+ i.nDisposeCount = 0;
+ ASSERT_TRUE( s.insert( i ) );
+ }
+
+ // get/extract
+ for ( auto idx : indices ) {
+ auto& i = data[idx];
+
+ EXPECT_EQ( i.nFindCount, 0 );
+ gp = s.get( i );
+ ASSERT_FALSE( !gp );
+ ++gp->nFindCount;
+ EXPECT_EQ( i.nFindCount, 1 );
+
+ gp = s.get( i.key() );
+ ASSERT_FALSE( !gp );
+ ++gp->nFindCount;
+ EXPECT_EQ( i.nFindCount, 2 );
+
+ gp = s.get_with( other_item( i.key()), other_less());
+ ASSERT_FALSE( !gp );
+ ++gp->nFindCount;
+ EXPECT_EQ( i.nFindCount, 3 );
+
+ EXPECT_EQ( i.nEraseCount, 0 );
+ switch ( i.key() % 3 ) {
+ case 0:
+ gp = s.extract( i.key());
+ break;
+ case 1:
+ gp = s.extract( i );
+ break;
+ case 2:
+ gp = s.extract_with( other_item( i.key() ), other_less() );
+ break;
+ }
+ ASSERT_FALSE( !gp );
+ ++gp->nEraseCount;
+ EXPECT_EQ( i.nEraseCount, 1 );
+
+ gp = s.extract( i );
+ ASSERT_TRUE( !gp );
+ gp = s.extract( i.key() );
+ ASSERT_TRUE( !gp );
+ gp = s.extract_with( other_item( i.key() ), other_less() );
+ ASSERT_TRUE( !gp );
+ }
+
+ gp.release();
+
+ ASSERT_TRUE( s.empty() );
+ ASSERT_CONTAINER_SIZE( s, 0 );
+
+ // Force retiring cycle
+ Set::gc::force_dispose();
+ for ( auto& i : data ) {
+ EXPECT_EQ( i.nDisposeCount, 1 );
+ }
+
+ }
+ };
+
+} // namespace cds_test
+
+#endif // #ifndef CDSUNIT_SET_TEST_INTRUSIVE_MICHAEL_ITERABLE_HP_H
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSUNIT_SET_TEST_INTRUSIVE_MICHAEL_LAZY_RCU_H
#define CDSUNIT_SET_TEST_INTRUSIVE_MICHAEL_LAZY_RCU_H
this->test( s );
}
+TYPED_TEST_P( IntrusiveMichaelLazySet, base_stat )
+{
+ typedef typename TestFixture::rcu_type rcu_type;
+ typedef typename TestFixture::base_item_type base_item_type;
+ typedef typename TestFixture::mock_disposer mock_disposer;
+ typedef typename TestFixture::hash_int hash_int;
+
+ struct list_traits: public ci::lazy_list::traits
+ {
+ typedef ci::lazy_list::base_hook< ci::opt::gc<rcu_type>> hook;
+ typedef typename TestFixture::template less<base_item_type> less;
+ typedef mock_disposer disposer;
+ typedef ci::lazy_list::stat<> stat;
+ };
+ typedef ci::LazyList< rcu_type, base_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef typename TestFixture::simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< rcu_type, bucket_type, set_traits > set_type;
+
+ set_type s( TestFixture::kSize, 2 );
+ this->test( s );
+}
+
+TYPED_TEST_P( IntrusiveMichaelLazySet, base_wrapped_stat )
+{
+ typedef typename TestFixture::rcu_type rcu_type;
+ typedef typename TestFixture::base_item_type base_item_type;
+ typedef typename TestFixture::mock_disposer mock_disposer;
+ typedef typename TestFixture::hash_int hash_int;
+
+ struct list_traits: public ci::lazy_list::traits
+ {
+ typedef ci::lazy_list::base_hook< ci::opt::gc<rcu_type>> hook;
+ typedef typename TestFixture::template less<base_item_type> less;
+ typedef mock_disposer disposer;
+ typedef ci::lazy_list::wrapped_stat<> stat;
+ };
+ typedef ci::LazyList< rcu_type, base_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef typename TestFixture::simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< rcu_type, bucket_type, set_traits > set_type;
+
+ set_type s( TestFixture::kSize, 2 );
+ this->test( s );
+}
TYPED_TEST_P( IntrusiveMichaelLazySet, member_cmp )
{
this->test( s );
}
+TYPED_TEST_P( IntrusiveMichaelLazySet, member_stat )
+{
+ typedef typename TestFixture::rcu_type rcu_type;
+ typedef typename TestFixture::member_item_type member_item_type;
+ typedef typename TestFixture::mock_disposer mock_disposer;
+ typedef typename TestFixture::hash_int hash_int;
+
+ struct list_traits: public ci::lazy_list::traits
+ {
+ typedef ci::lazy_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<rcu_type>> hook;
+ typedef typename TestFixture::template cmp<member_item_type> compare;
+ typedef mock_disposer disposer;
+ typedef ci::lazy_list::stat<> stat;
+ };
+ typedef ci::LazyList< rcu_type, member_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef typename TestFixture::simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< rcu_type, bucket_type, set_traits > set_type;
+
+ set_type s( TestFixture::kSize, 2 );
+ this->test( s );
+}
+
+TYPED_TEST_P( IntrusiveMichaelLazySet, member_wrapped_stat )
+{
+ typedef typename TestFixture::rcu_type rcu_type;
+ typedef typename TestFixture::member_item_type member_item_type;
+ typedef typename TestFixture::mock_disposer mock_disposer;
+ typedef typename TestFixture::hash_int hash_int;
+
+ struct list_traits: public ci::lazy_list::traits
+ {
+ typedef ci::lazy_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<rcu_type>> hook;
+ typedef typename TestFixture::template cmp<member_item_type> compare;
+ typedef mock_disposer disposer;
+ typedef ci::lazy_list::wrapped_stat<> stat;
+ };
+ typedef ci::LazyList< rcu_type, member_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef typename TestFixture::simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< rcu_type, bucket_type, set_traits > set_type;
+
+ set_type s( TestFixture::kSize, 2 );
+ this->test( s );
+}
// GCC 5: All test names should be written on single line, otherwise a runtime error will be encountered like as
// "No test named <test_name> can be found in this test case"
REGISTER_TYPED_TEST_CASE_P( IntrusiveMichaelLazySet,
- base_cmp, base_less, base_cmpmix, base_mutex, member_cmp, member_less, member_cmpmix, member_mutex
+ base_cmp, base_less, base_cmpmix, base_mutex, base_stat, base_wrapped_stat, member_cmp, member_less, member_cmpmix, member_mutex, member_stat, member_wrapped_stat
);
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSUNIT_SET_TEST_INTRUSIVE_MICHAEL_MICHAEL_RCU_H
#define CDSUNIT_SET_TEST_INTRUSIVE_MICHAEL_MICHAEL_RCU_H
this->test( s );
}
+TYPED_TEST_P( IntrusiveMichaelSet, base_stat )
+{
+ typedef typename TestFixture::rcu_type rcu_type;
+ typedef typename TestFixture::base_item_type base_item_type;
+ typedef typename TestFixture::mock_disposer mock_disposer;
+ typedef typename TestFixture::hash_int hash_int;
+
+ struct list_traits: public ci::michael_list::traits
+ {
+ typedef ci::michael_list::base_hook< ci::opt::gc<rcu_type>> hook;
+ typedef typename TestFixture::template less<base_item_type> less;
+ typedef typename TestFixture::template cmp<base_item_type> compare;
+ typedef mock_disposer disposer;
+ typedef ci::michael_list::stat<> stat;
+ };
+ typedef ci::MichaelList< rcu_type, base_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef typename TestFixture::simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< rcu_type, bucket_type, set_traits > set_type;
+
+ set_type s( TestFixture::kSize, 2 );
+ this->test( s );
+}
+
+TYPED_TEST_P( IntrusiveMichaelSet, base_wrapped_stat )
+{
+ typedef typename TestFixture::rcu_type rcu_type;
+ typedef typename TestFixture::base_item_type base_item_type;
+ typedef typename TestFixture::mock_disposer mock_disposer;
+ typedef typename TestFixture::hash_int hash_int;
+
+ struct list_traits: public ci::michael_list::traits
+ {
+ typedef ci::michael_list::base_hook< ci::opt::gc<rcu_type>> hook;
+ typedef typename TestFixture::template less<base_item_type> less;
+ typedef typename TestFixture::template cmp<base_item_type> compare;
+ typedef mock_disposer disposer;
+ typedef ci::michael_list::wrapped_stat<> stat;
+ };
+ typedef ci::MichaelList< rcu_type, base_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef typename TestFixture::simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< rcu_type, bucket_type, set_traits > set_type;
+
+ set_type s( TestFixture::kSize, 2 );
+ this->test( s );
+}
TYPED_TEST_P( IntrusiveMichaelSet, member_cmp )
{
this->test( s );
}
+TYPED_TEST_P( IntrusiveMichaelSet, member_stat )
+{
+ typedef typename TestFixture::rcu_type rcu_type;
+ typedef typename TestFixture::member_item_type member_item_type;
+ typedef typename TestFixture::mock_disposer mock_disposer;
+ typedef typename TestFixture::hash_int hash_int;
+
+ struct list_traits: public ci::michael_list::traits
+ {
+ typedef ci::michael_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<rcu_type>> hook;
+ typedef typename TestFixture::template cmp<member_item_type> compare;
+ typedef mock_disposer disposer;
+ typedef ci::michael_list::stat<> stat;
+ };
+ typedef ci::MichaelList< rcu_type, member_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef typename TestFixture::simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< rcu_type, bucket_type, set_traits > set_type;
+
+ set_type s( TestFixture::kSize, 2 );
+ this->test( s );
+}
+TYPED_TEST_P( IntrusiveMichaelSet, member_wrapped_stat )
+{
+ typedef typename TestFixture::rcu_type rcu_type;
+ typedef typename TestFixture::member_item_type member_item_type;
+ typedef typename TestFixture::mock_disposer mock_disposer;
+ typedef typename TestFixture::hash_int hash_int;
+
+ struct list_traits: public ci::michael_list::traits
+ {
+ typedef ci::michael_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<rcu_type>> hook;
+ typedef typename TestFixture::template cmp<member_item_type> compare;
+ typedef mock_disposer disposer;
+ typedef ci::michael_list::wrapped_stat<> stat;
+ };
+ typedef ci::MichaelList< rcu_type, member_item_type, list_traits > bucket_type;
+
+ struct set_traits: public ci::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef typename TestFixture::simple_item_counter item_counter;
+ };
+ typedef ci::MichaelHashSet< rcu_type, bucket_type, set_traits > set_type;
+
+ set_type s( TestFixture::kSize, 2 );
+ this->test( s );
+}
// GCC 5: All test names should be written on single line, otherwise a runtime error will be encountered like as
// "No test named <test_name> can be found in this test case"
REGISTER_TYPED_TEST_CASE_P( IntrusiveMichaelSet,
- base_cmp, base_less, base_cmpmix, member_cmp, member_less, member_cmpmix
+ base_cmp, base_less, base_cmpmix, base_stat, base_wrapped_stat, member_cmp, member_less, member_cmpmix, member_stat, member_wrapped_stat
);
set(CDSGTEST_LIST_SOURCES
../main.cpp
+ intrusive_iterable_dhp.cpp
+ intrusive_iterable_hp.cpp
intrusive_lazy_hp.cpp
intrusive_lazy_dhp.cpp
intrusive_lazy_nogc.cpp
intrusive_michael_rcu_gpt.cpp
intrusive_michael_rcu_shb.cpp
intrusive_michael_rcu_sht.cpp
+ iterable_hp.cpp
+ iterable_dhp.cpp
+ kv_iterable_hp.cpp
+ kv_iterable_dhp.cpp
kv_lazy_hp.cpp
kv_lazy_dhp.cpp
kv_lazy_nogc.cpp
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "test_intrusive_iterable_list_hp.h"
+#include <cds/intrusive/iterable_list_dhp.h>
+
+namespace {
+ namespace ci = cds::intrusive;
+ typedef cds::gc::DHP gc_type;
+
+ class IntrusiveIterableList_DHP : public cds_test::intrusive_iterable_list_hp
+ {
+ protected:
+ void SetUp()
+ {
+ typedef ci::IterableList< gc_type, item_type > list_type;
+
+ // +1 - for guarded_ptr
+ // +3 - for iterator test
+ cds::gc::dhp::GarbageCollector::Construct( 16, list_type::c_nHazardPtrCount );
+ cds::threading::Manager::attachThread();
+ }
+
+ void TearDown()
+ {
+ cds::threading::Manager::detachThread();
+ cds::gc::dhp::GarbageCollector::Destruct();
+ }
+ };
+
+ TEST_F( IntrusiveIterableList_DHP, less )
+ {
+ typedef ci::IterableList< gc_type, item_type,
+ typename ci::iterable_list::make_traits<
+ ci::opt::disposer< mock_disposer >
+ ,cds::opt::less< less< item_type >>
+ , cds::opt::item_counter< cds::atomicity::item_counter >
+ >::type
+ > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IntrusiveIterableList_DHP, compare )
+ {
+ typedef ci::IterableList< gc_type, item_type,
+ typename ci::iterable_list::make_traits<
+ ci::opt::disposer< mock_disposer >
+ , cds::opt::compare< cmp< item_type >>
+ , cds::opt::item_counter< cds::atomicity::item_counter >
+ >::type
+ > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IntrusiveIterableList_DHP, item_counting )
+ {
+ struct traits : public ci::iterable_list::traits {
+ typedef mock_disposer disposer;
+ typedef cmp< item_type > compare;
+ typedef intrusive_iterable_list::less< item_type > less;
+ typedef cds::atomicity::item_counter item_counter;
+ };
+ typedef ci::IterableList< gc_type, item_type, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IntrusiveIterableList_DHP, backoff )
+ {
+ struct traits : public ci::iterable_list::traits {
+ typedef mock_disposer disposer;
+ typedef cmp< item_type > compare;
+ typedef intrusive_iterable_list::less< item_type > less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::backoff::pause back_off;
+ };
+ typedef ci::IterableList< gc_type, item_type, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IntrusiveIterableList_DHP, seqcst )
+ {
+ struct traits : public ci::iterable_list::traits {
+ typedef mock_disposer disposer;
+ typedef intrusive_iterable_list::less< item_type > less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::opt::v::sequential_consistent memory_model;
+ };
+ typedef ci::IterableList< gc_type, item_type, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IntrusiveIterableList_DHP, stat )
+ {
+ struct traits: public ci::iterable_list::traits {
+ typedef mock_disposer disposer;
+ typedef intrusive_iterable_list::less< item_type > less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::intrusive::iterable_list::stat<> stat;
+ };
+ typedef ci::IterableList< gc_type, item_type, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IntrusiveIterableList_DHP, wrapped_stat )
+ {
+ struct traits: public ci::iterable_list::traits {
+ typedef mock_disposer disposer;
+ typedef intrusive_iterable_list::less< item_type > less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::intrusive::iterable_list::wrapped_stat<> stat;
+ };
+ typedef ci::IterableList< gc_type, item_type, traits > list_type;
+
+ traits::stat::stat_type st;
+ list_type l( st );
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+} // namespace
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "test_intrusive_iterable_list_hp.h"
+#include <cds/intrusive/iterable_list_hp.h>
+
+namespace {
+ namespace ci = cds::intrusive;
+ typedef cds::gc::HP gc_type;
+
+ class IntrusiveIterableList_HP : public cds_test::intrusive_iterable_list_hp
+ {
+ protected:
+ void SetUp()
+ {
+ typedef ci::IterableList< gc_type, item_type > list_type;
+
+ // +1 - for guarded_ptr
+ // +3 - for iterator test
+ cds::gc::hp::GarbageCollector::Construct( list_type::c_nHazardPtrCount + 3, 1, 16 );
+ cds::threading::Manager::attachThread();
+ }
+
+ void TearDown()
+ {
+ cds::threading::Manager::detachThread();
+ cds::gc::hp::GarbageCollector::Destruct( true );
+ }
+ };
+
+ TEST_F( IntrusiveIterableList_HP, less )
+ {
+ typedef ci::IterableList< gc_type, item_type,
+ typename ci::iterable_list::make_traits<
+ ci::opt::disposer< mock_disposer >
+ ,cds::opt::less< less< item_type >>
+ ,cds::opt::item_counter< cds::atomicity::item_counter >
+
+ >::type
+ > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IntrusiveIterableList_HP, compare )
+ {
+ typedef ci::IterableList< gc_type, item_type,
+ typename ci::iterable_list::make_traits<
+ ci::opt::disposer< mock_disposer >
+ , cds::opt::compare< cmp< item_type >>
+ , cds::opt::item_counter< cds::atomicity::item_counter >
+ >::type
+ > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IntrusiveIterableList_HP, item_counting )
+ {
+ struct traits : public ci::iterable_list::traits {
+ typedef mock_disposer disposer;
+ typedef cmp< item_type > compare;
+ typedef intrusive_iterable_list::less< item_type > less;
+ typedef cds::atomicity::item_counter item_counter;
+ };
+ typedef ci::IterableList< gc_type, item_type, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IntrusiveIterableList_HP, backoff )
+ {
+ struct traits : public ci::iterable_list::traits {
+ typedef mock_disposer disposer;
+ typedef cmp< item_type > compare;
+ typedef intrusive_iterable_list::less< item_type > less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::backoff::pause back_off;
+ };
+ typedef ci::IterableList< gc_type, item_type, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IntrusiveIterableList_HP, seqcst )
+ {
+ struct traits : public ci::iterable_list::traits {
+ typedef mock_disposer disposer;
+ typedef intrusive_iterable_list::less< item_type > less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::opt::v::sequential_consistent memory_model;
+ };
+ typedef ci::IterableList< gc_type, item_type, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IntrusiveIterableList_HP, stat )
+ {
+ struct traits: public ci::iterable_list::traits {
+ typedef mock_disposer disposer;
+ typedef intrusive_iterable_list::less< item_type > less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::intrusive::iterable_list::stat<> stat;
+ };
+ typedef ci::IterableList< gc_type, item_type, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IntrusiveIterableList_HP, wrapped_stat )
+ {
+ struct traits: public ci::iterable_list::traits {
+ typedef mock_disposer disposer;
+ typedef intrusive_iterable_list::less< item_type > less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::intrusive::iterable_list::wrapped_stat<> stat;
+ };
+ typedef ci::IterableList< gc_type, item_type, traits > list_type;
+
+ traits::stat::stat_type st;
+
+ list_type l( st );
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_intrusive_list_hp.h"
void TearDown()
{
cds::threading::Manager::detachThread();
- cds::gc::hp::GarbageCollector::Destruct();
+ cds::gc::dhp::GarbageCollector::Destruct();
}
};
test_hp( l );
}
+ TEST_F( IntrusiveLazyList_DHP, base_hook_stat )
+ {
+ struct traits: public ci::lazy_list::traits {
+ typedef ci::lazy_list::base_hook< cds::opt::gc< gc_type >> hook;
+ typedef mock_disposer disposer;
+ typedef cmp< base_item > compare;
+ typedef intrusive_list_common::less< base_item > less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::intrusive::lazy_list::stat<> stat;
+ };
+ typedef ci::LazyList< gc_type, base_item, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IntrusiveLazyList_DHP, base_hook_wrapped_stat )
+ {
+ struct traits: public ci::lazy_list::traits {
+ typedef ci::lazy_list::base_hook< cds::opt::gc< gc_type >> hook;
+ typedef mock_disposer disposer;
+ typedef intrusive_list_common::less< base_item > less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::intrusive::lazy_list::wrapped_stat<> stat;
+ };
+ typedef ci::LazyList< gc_type, base_item, traits > list_type;
+
+ cds::intrusive::lazy_list::stat<> st;
+ list_type l( st );
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
TEST_F( IntrusiveLazyList_DHP, member_hook )
{
typedef ci::LazyList< gc_type, member_item,
test_hp( l );
}
+ TEST_F( IntrusiveLazyList_DHP, member_hook_stat )
+ {
+ struct traits: public ci::lazy_list::traits {
+ typedef ci::lazy_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >> hook;
+ typedef mock_disposer disposer;
+ typedef cmp< member_item > compare;
+ typedef intrusive_list_common::less< member_item > less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::intrusive::lazy_list::stat<> stat;
+ };
+ typedef ci::LazyList< gc_type, member_item, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IntrusiveLazyList_DHP, member_hook_wrapped_stat )
+ {
+ struct traits: public ci::lazy_list::traits {
+ typedef ci::lazy_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >> hook;
+ typedef mock_disposer disposer;
+ typedef cmp< member_item > compare;
+ typedef intrusive_list_common::less< member_item > less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::intrusive::lazy_list::wrapped_stat<> stat;
+ };
+ typedef ci::LazyList< gc_type, member_item, traits > list_type;
+
+ cds::intrusive::lazy_list::stat<> st;
+ list_type l( st );
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_intrusive_list_hp.h"
test_hp( l );
}
+ TEST_F( IntrusiveLazyList_HP, base_hook_stat )
+ {
+ struct traits: public ci::lazy_list::traits {
+ typedef ci::lazy_list::base_hook< cds::opt::gc< gc_type >> hook;
+ typedef mock_disposer disposer;
+ typedef cmp< base_item > compare;
+ typedef intrusive_list_common::less< base_item > less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::intrusive::lazy_list::stat<> stat;
+ };
+ typedef ci::LazyList< gc_type, base_item, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IntrusiveLazyList_HP, base_hook_wrapped_stat )
+ {
+ struct traits: public ci::lazy_list::traits {
+ typedef ci::lazy_list::base_hook< cds::opt::gc< gc_type >> hook;
+ typedef mock_disposer disposer;
+ typedef cmp< base_item > compare;
+ typedef cds::intrusive::lazy_list::wrapped_stat<> stat;
+ };
+ typedef ci::LazyList< gc_type, base_item, traits > list_type;
+
+ cds::intrusive::lazy_list::stat<> st;
+ list_type l( st );
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
TEST_F( IntrusiveLazyList_HP, member_hook )
{
typedef ci::LazyList< gc_type, member_item,
test_hp( l );
}
+ TEST_F( IntrusiveLazyList_HP, member_hook_stat )
+ {
+ struct traits: public ci::lazy_list::traits {
+ typedef ci::lazy_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >> hook;
+ typedef mock_disposer disposer;
+ typedef cmp< member_item > compare;
+ typedef intrusive_list_common::less< member_item > less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::intrusive::lazy_list::stat<> stat;
+ };
+ typedef ci::LazyList< gc_type, member_item, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IntrusiveLazyList_HP, member_hook_wrapped_stat )
+ {
+ struct traits: public ci::lazy_list::traits {
+ typedef ci::lazy_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >> hook;
+ typedef mock_disposer disposer;
+ typedef cmp< member_item > compare;
+ typedef cds::intrusive::lazy_list::wrapped_stat<> stat;
+ };
+ typedef ci::LazyList< gc_type, member_item, traits > list_type;
+
+ cds::intrusive::lazy_list::stat<> st;
+ list_type l( st );
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_intrusive_list_nogc.h"
test_ordered_iterator( l );
}
+ TEST_F( IntrusiveLazyList_NOGC, base_hook_stat )
+ {
+ struct traits: public ci::lazy_list::traits {
+ typedef ci::lazy_list::base_hook< cds::opt::gc< gc_type >> hook;
+ typedef mock_disposer disposer;
+ typedef cmp< base_item > compare;
+ typedef intrusive_list_nogc::less< base_item > less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::intrusive::lazy_list::stat<> stat;
+ };
+ typedef ci::LazyList< gc_type, base_item, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ }
+
+ TEST_F( IntrusiveLazyList_NOGC, base_hook_wrapped_stat )
+ {
+ struct traits: public ci::lazy_list::traits {
+ typedef ci::lazy_list::base_hook< cds::opt::gc< gc_type >> hook;
+ typedef mock_disposer disposer;
+ typedef cmp< base_item > compare;
+ typedef intrusive_list_nogc::less< base_item > less;
+ typedef cds::intrusive::lazy_list::wrapped_stat<> stat;
+ };
+ typedef ci::LazyList< gc_type, base_item, traits > list_type;
+
+ cds::intrusive::lazy_list::stat<> st;
+ list_type l( st );
+ test_common( l );
+ test_ordered_iterator( l );
+ }
+
TEST_F( IntrusiveLazyList_NOGC, member_hook )
{
typedef ci::LazyList< gc_type, member_item,
test_ordered_iterator( l );
}
+ TEST_F( IntrusiveLazyList_NOGC, member_hook_stat )
+ {
+ struct traits: public ci::lazy_list::traits {
+ typedef ci::lazy_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >> hook;
+ typedef mock_disposer disposer;
+ typedef cmp< member_item > compare;
+ typedef intrusive_list_nogc::less< member_item > less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::intrusive::lazy_list::stat<> stat;
+ };
+ typedef ci::LazyList< gc_type, member_item, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ }
+
+ TEST_F( IntrusiveLazyList_NOGC, member_hook_wrapped_stat )
+ {
+ struct traits: public ci::lazy_list::traits {
+ typedef ci::lazy_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >> hook;
+ typedef mock_disposer disposer;
+ typedef cmp< member_item > compare;
+ typedef intrusive_list_nogc::less< member_item > less;
+ typedef cds::intrusive::lazy_list::wrapped_stat<> stat;
+ };
+ typedef ci::LazyList< gc_type, member_item, traits > list_type;
+
+ cds::intrusive::lazy_list::stat<> st;
+ list_type l( st );
+ test_common( l );
+ test_ordered_iterator( l );
+ }
+
} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_intrusive_list_hp.h"
void TearDown()
{
cds::threading::Manager::detachThread();
- cds::gc::hp::GarbageCollector::Destruct();
+ cds::gc::dhp::GarbageCollector::Destruct();
}
};
test_ordered_iterator( l );
test_hp( l );
}
+ TEST_F( IntrusiveMichaelList_DHP, base_hook_stat )
+ {
+ struct traits: public ci::michael_list::traits {
+ typedef ci::michael_list::base_hook< cds::opt::gc< gc_type >> hook;
+ typedef mock_disposer disposer;
+ typedef cmp< base_item > compare;
+ typedef intrusive_list_common::less< base_item > less;
+ typedef cds::intrusive::michael_list::stat<> stat;
+ };
+ typedef ci::MichaelList< gc_type, base_item, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IntrusiveMichaelList_DHP, base_hook_wrapped_stat )
+ {
+ struct traits: public ci::michael_list::traits {
+ typedef ci::michael_list::base_hook< cds::opt::gc< gc_type >> hook;
+ typedef mock_disposer disposer;
+ typedef cmp< base_item > compare;
+ typedef cds::intrusive::michael_list::wrapped_stat<> stat;
+ };
+ typedef ci::MichaelList< gc_type, base_item, traits > list_type;
+
+ cds::intrusive::michael_list::stat<> st;
+ list_type l( st );
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
TEST_F( IntrusiveMichaelList_DHP, member_hook )
{
test_hp( l );
}
+ TEST_F( IntrusiveMichaelList_DHP, member_hook_stat )
+ {
+ struct traits: public ci::michael_list::traits {
+ typedef ci::michael_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >> hook;
+ typedef mock_disposer disposer;
+ typedef cmp< member_item > compare;
+ typedef intrusive_list_common::less< member_item > less;
+ typedef cds::intrusive::michael_list::stat<> stat;
+ };
+ typedef ci::MichaelList< gc_type, member_item, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IntrusiveMichaelList_DHP, member_hook_wrapped_stat )
+ {
+ struct traits: public ci::michael_list::traits {
+ typedef ci::michael_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >> hook;
+ typedef mock_disposer disposer;
+ typedef cmp< member_item > compare;
+ typedef cds::intrusive::michael_list::wrapped_stat<> stat;
+ };
+ typedef ci::MichaelList< gc_type, member_item, traits > list_type;
+
+ cds::intrusive::michael_list::stat<> st;
+ list_type l( st );
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_intrusive_list_hp.h"
test_hp( l );
}
+ TEST_F( IntrusiveMichaelList_HP, base_hook_stat )
+ {
+ struct traits: public ci::michael_list::traits {
+ typedef ci::michael_list::base_hook< cds::opt::gc< gc_type >> hook;
+ typedef mock_disposer disposer;
+ typedef cmp< base_item > compare;
+ typedef intrusive_list_common::less< base_item > less;
+ typedef cds::intrusive::michael_list::stat<> stat;
+ };
+ typedef ci::MichaelList< gc_type, base_item, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IntrusiveMichaelList_HP, base_hook_wrapped_stat )
+ {
+ struct traits: public ci::michael_list::traits {
+ typedef ci::michael_list::base_hook< cds::opt::gc< gc_type >> hook;
+ typedef mock_disposer disposer;
+ typedef cmp< base_item > compare;
+ typedef cds::intrusive::michael_list::wrapped_stat<> stat;
+ };
+ typedef ci::MichaelList< gc_type, base_item, traits > list_type;
+
+ cds::intrusive::michael_list::stat<> st;
+ list_type l( st );
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
TEST_F( IntrusiveMichaelList_HP, member_hook )
{
typedef ci::MichaelList< gc_type, member_item,
test_hp( l );
}
+ TEST_F( IntrusiveMichaelList_HP, member_hook_stat )
+ {
+ struct traits: public ci::michael_list::traits {
+ typedef ci::michael_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >> hook;
+ typedef mock_disposer disposer;
+ typedef cmp< member_item > compare;
+ typedef intrusive_list_common::less< member_item > less;
+ typedef cds::intrusive::michael_list::stat<> stat;
+ };
+ typedef ci::MichaelList< gc_type, member_item, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IntrusiveMichaelList_HP, member_hook_wrapped_stat )
+ {
+ struct traits: public ci::michael_list::traits {
+ typedef ci::michael_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >> hook;
+ typedef mock_disposer disposer;
+ typedef cmp< member_item > compare;
+ typedef cds::intrusive::michael_list::wrapped_stat<> stat;
+ };
+ typedef ci::MichaelList< gc_type, member_item, traits > list_type;
+
+ cds::intrusive::michael_list::stat<> st;
+ list_type l( st );
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
} // namespace
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "test_iterable_list_hp.h"
+#include <cds/container/iterable_list_dhp.h>
+
+namespace {
+ namespace cc = cds::container;
+ typedef cds::gc::DHP gc_type;
+
+ class IterableList_DHP : public cds_test::iterable_list_hp
+ {
+ protected:
+ void SetUp()
+ {
+ typedef cc::IterableList< gc_type, item > list_type;
+
+ // +3 - for guarded_ptr, iterators
+ cds::gc::dhp::GarbageCollector::Construct( 16, list_type::c_nHazardPtrCount );
+ cds::threading::Manager::attachThread();
+ }
+
+ void TearDown()
+ {
+ cds::threading::Manager::detachThread();
+ cds::gc::dhp::GarbageCollector::Destruct();
+ }
+ };
+
+ TEST_F( IterableList_DHP, less_ordered )
+ {
+ typedef cc::IterableList< gc_type, item,
+ typename cc::iterable_list::make_traits<
+ cds::opt::less< lt<item> >
+ ,cds::opt::item_counter< cds::atomicity::item_counter >
+ >::type
+ > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IterableList_DHP, compare_ordered )
+ {
+ typedef cc::IterableList< gc_type, item,
+ typename cc::iterable_list::make_traits<
+ cds::opt::compare< cmp<item> >
+ , cds::opt::item_counter< cds::atomicity::item_counter >
+ >::type
+ > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IterableList_DHP, mix_ordered )
+ {
+ typedef cc::IterableList< gc_type, item,
+ typename cc::iterable_list::make_traits<
+ cds::opt::compare< cmp<item> >
+ ,cds::opt::less< lt<item> >
+ , cds::opt::item_counter< cds::atomicity::item_counter >
+ >::type
+ > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IterableList_DHP, backoff )
+ {
+ struct traits : public cc::iterable_list::traits
+ {
+ typedef lt<item> less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::backoff::empty back_off;
+ };
+ typedef cc::IterableList<gc_type, item, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IterableList_DHP, seq_cst )
+ {
+ struct traits : public cc::iterable_list::traits
+ {
+ typedef lt<item> less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::opt::v::sequential_consistent memory_model;
+ };
+ typedef cc::IterableList<gc_type, item, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IterableList_DHP, stat )
+ {
+ struct traits: public cc::iterable_list::traits
+ {
+ typedef lt<item> less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::iterable_list::stat<> stat;
+
+ };
+ typedef cc::IterableList<gc_type, item, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IterableList_DHP, wrapped_stat )
+ {
+ struct traits: public cc::iterable_list::traits
+ {
+ typedef lt<item> less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::iterable_list::wrapped_stat<> stat;
+
+ };
+ typedef cc::IterableList<gc_type, item, traits > list_type;
+
+ cds::container::iterable_list::stat<> st;
+ list_type l( st );
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+} // namespace
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "test_iterable_list_hp.h"
+#include <cds/container/iterable_list_hp.h>
+
+namespace {
+ namespace cc = cds::container;
+ typedef cds::gc::HP gc_type;
+
+ class IterableList_HP : public cds_test::iterable_list_hp
+ {
+ protected:
+ void SetUp()
+ {
+ typedef cc::IterableList< gc_type, item > list_type;
+
+ // +3 - for guarded_ptr, iterators
+ cds::gc::hp::GarbageCollector::Construct( list_type::c_nHazardPtrCount + 3, 1, 16 );
+ cds::threading::Manager::attachThread();
+ }
+
+ void TearDown()
+ {
+ cds::threading::Manager::detachThread();
+ cds::gc::hp::GarbageCollector::Destruct( true );
+ }
+ };
+
+ TEST_F( IterableList_HP, less_ordered )
+ {
+ typedef cc::IterableList< gc_type, item,
+ typename cc::iterable_list::make_traits<
+ cds::opt::less< lt<item> >
+ ,cds::opt::item_counter< cds::atomicity::item_counter >
+ >::type
+ > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IterableList_HP, compare_ordered )
+ {
+ typedef cc::IterableList< gc_type, item,
+ typename cc::iterable_list::make_traits<
+ cds::opt::compare< cmp<item> >
+ , cds::opt::item_counter< cds::atomicity::item_counter >
+ >::type
+ > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IterableList_HP, mix_ordered )
+ {
+ typedef cc::IterableList< gc_type, item,
+ typename cc::iterable_list::make_traits<
+ cds::opt::compare< cmp<item> >
+ ,cds::opt::less< lt<item> >
+ , cds::opt::item_counter< cds::atomicity::item_counter >
+ >::type
+ > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IterableList_HP, backoff )
+ {
+ struct traits : public cc::iterable_list::traits
+ {
+ typedef lt<item> less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::backoff::empty back_off;
+ };
+ typedef cc::IterableList<gc_type, item, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IterableList_HP, seq_cst )
+ {
+ struct traits : public cc::iterable_list::traits
+ {
+ typedef lt<item> less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::opt::v::sequential_consistent memory_model;
+ };
+ typedef cc::IterableList<gc_type, item, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IterableList_HP, stat )
+ {
+ struct traits: public cc::iterable_list::traits
+ {
+ typedef lt<item> less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::iterable_list::stat<> stat;
+
+ };
+ typedef cc::IterableList<gc_type, item, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IterableList_HP, wrapped_stat )
+ {
+ struct traits: public cc::iterable_list::traits
+ {
+ typedef lt<item> less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::iterable_list::wrapped_stat<> stat;
+
+ };
+ typedef cc::IterableList<gc_type, item, traits > list_type;
+
+ cds::container::iterable_list::stat<> st;
+ list_type l( st );
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+} // namespace
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "test_kv_iterable_list_hp.h"
+#include <cds/container/iterable_kvlist_dhp.h>
+
+namespace {
+ namespace cc = cds::container;
+ typedef cds::gc::DHP gc_type;
+
+ class IterableKVList_DHP : public cds_test::kv_iterable_list_hp
+ {
+ protected:
+ void SetUp()
+ {
+ typedef cc::IterableKVList< gc_type, key_type, value_type > list_type;
+
+ cds::gc::dhp::GarbageCollector::Construct( 16, list_type::c_nHazardPtrCount );
+ cds::threading::Manager::attachThread();
+ }
+
+ void TearDown()
+ {
+ cds::threading::Manager::detachThread();
+ cds::gc::dhp::GarbageCollector::Destruct();
+ }
+ };
+
+ TEST_F( IterableKVList_DHP, less_ordered )
+ {
+ typedef cc::IterableKVList< gc_type, key_type, value_type,
+ typename cc::iterable_list::make_traits<
+ cds::opt::less< lt >
+ ,cds::opt::item_counter< cds::atomicity::item_counter >
+ >::type
+ > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IterableKVList_DHP, compare_ordered )
+ {
+ typedef cc::IterableKVList< gc_type, key_type, value_type,
+ typename cc::iterable_list::make_traits<
+ cds::opt::compare< cmp >
+ , cds::opt::item_counter< cds::atomicity::item_counter >
+ >::type
+ > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IterableKVList_DHP, mix_ordered )
+ {
+ typedef cc::IterableKVList< gc_type, key_type, value_type,
+ typename cc::iterable_list::make_traits<
+ cds::opt::compare< cmp >
+ ,cds::opt::less< lt >
+ , cds::opt::item_counter< cds::atomicity::item_counter >
+ >::type
+ > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IterableKVList_DHP, backoff )
+ {
+ struct traits : public cc::iterable_list::traits
+ {
+ typedef lt less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::backoff::empty back_off;
+ };
+ typedef cc::IterableKVList<gc_type, key_type, value_type, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IterableKVList_DHP, seq_cst )
+ {
+ struct traits : public cc::iterable_list::traits
+ {
+ typedef lt less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::opt::v::sequential_consistent memory_model;
+ };
+ typedef cc::IterableKVList<gc_type, key_type, value_type, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IterableKVList_DHP, stat )
+ {
+ struct traits: public cc::iterable_list::traits
+ {
+ typedef lt less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::iterable_list::stat<> stat;
+ };
+ typedef cc::IterableKVList<gc_type, key_type, value_type, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IterableKVList_DHP, wrapped_stat )
+ {
+ struct traits: public cc::iterable_list::traits
+ {
+ typedef lt less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::iterable_list::wrapped_stat<> stat;
+ };
+ typedef cc::IterableKVList<gc_type, key_type, value_type, traits > list_type;
+
+ cds::container::iterable_list::stat<> st;
+ list_type l( st );
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+} // namespace
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "test_kv_iterable_list_hp.h"
+#include <cds/container/iterable_kvlist_hp.h>
+
+namespace {
+ namespace cc = cds::container;
+ typedef cds::gc::HP gc_type;
+
+ class IterableKVList_HP : public cds_test::kv_iterable_list_hp
+ {
+ protected:
+ void SetUp()
+ {
+ typedef cc::IterableKVList< gc_type, key_type, value_type > list_type;
+
+ // +3 - for guarded_ptr, iterators
+ cds::gc::hp::GarbageCollector::Construct( list_type::c_nHazardPtrCount + 3, 1, 16 );
+ cds::threading::Manager::attachThread();
+ }
+
+ void TearDown()
+ {
+ cds::threading::Manager::detachThread();
+ cds::gc::hp::GarbageCollector::Destruct( true );
+ }
+ };
+
+ TEST_F( IterableKVList_HP, less_ordered )
+ {
+ typedef cc::IterableKVList< gc_type, key_type, value_type,
+ typename cc::iterable_list::make_traits<
+ cds::opt::less< lt >
+ ,cds::opt::item_counter< cds::atomicity::item_counter >
+ >::type
+ > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IterableKVList_HP, compare_ordered )
+ {
+ typedef cc::IterableKVList< gc_type, key_type, value_type,
+ typename cc::iterable_list::make_traits<
+ cds::opt::compare< cmp >
+ , cds::opt::item_counter< cds::atomicity::item_counter >
+ >::type
+ > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IterableKVList_HP, mix_ordered )
+ {
+ typedef cc::IterableKVList< gc_type, key_type, value_type,
+ typename cc::iterable_list::make_traits<
+ cds::opt::compare< cmp >
+ ,cds::opt::less< lt >
+ , cds::opt::item_counter< cds::atomicity::item_counter >
+ >::type
+ > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IterableKVList_HP, backoff )
+ {
+ struct traits : public cc::iterable_list::traits
+ {
+ typedef lt less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::backoff::empty back_off;
+ };
+ typedef cc::IterableKVList<gc_type, key_type, value_type, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IterableKVList_HP, seq_cst )
+ {
+ struct traits : public cc::iterable_list::traits
+ {
+ typedef lt less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::opt::v::sequential_consistent memory_model;
+ };
+ typedef cc::IterableKVList<gc_type, key_type, value_type, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IterableKVList_HP, stat )
+ {
+ struct traits: public cc::iterable_list::traits
+ {
+ typedef lt less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::iterable_list::stat<> stat;
+ };
+ typedef cc::IterableKVList<gc_type, key_type, value_type, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( IterableKVList_HP, wrapped_stat )
+ {
+ struct traits: public cc::iterable_list::traits
+ {
+ typedef lt less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::iterable_list::wrapped_stat<> stat;
+ };
+ typedef cc::IterableKVList<gc_type, key_type, value_type, traits > list_type;
+
+ cds::container::iterable_list::stat<> st;
+ list_type l( st );
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_kv_list_hp.h"
void TearDown()
{
cds::threading::Manager::detachThread();
- cds::gc::hp::GarbageCollector::Destruct();
+ cds::gc::dhp::GarbageCollector::Destruct();
}
};
test_hp( l );
}
+ TEST_F( LazyKVList_DHP, stat )
+ {
+ struct traits: public cc::lazy_list::traits
+ {
+ typedef lt less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::lazy_list::stat<> stat;
+ };
+ typedef cc::LazyKVList<gc_type, key_type, value_type, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( LazyKVList_DHP, wrapped_stat )
+ {
+ struct traits: public cc::lazy_list::traits
+ {
+ typedef lt less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::lazy_list::wrapped_stat<> stat;
+ };
+ typedef cc::LazyKVList<gc_type, key_type, value_type, traits > list_type;
+
+ cds::container::lazy_list::stat<> st;
+ list_type l( st );
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_kv_list_hp.h"
test_hp( l );
}
+ TEST_F( LazyKVList_HP, stat )
+ {
+ struct traits: public cc::lazy_list::traits
+ {
+ typedef lt less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::lazy_list::stat<> stat;
+ };
+ typedef cc::LazyKVList<gc_type, key_type, value_type, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( LazyKVList_HP, wrapped_stat )
+ {
+ struct traits: public cc::lazy_list::traits
+ {
+ typedef lt less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::lazy_list::wrapped_stat<> stat;
+ };
+ typedef cc::LazyKVList<gc_type, key_type, value_type, traits > list_type;
+
+ cds::container::lazy_list::stat<> st;
+ list_type l( st );
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_kv_list_nogc.h"
test_ordered_iterator( l );
}
+ TEST_F( LazyKVList_NOGC, stat )
+ {
+ struct traits: public cc::lazy_list::traits
+ {
+ typedef lt less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::lazy_list::stat<> stat;
+ };
+ typedef cc::LazyKVList<gc_type, key_type, value_type, traits > list_type;
+
+ list_type l;
+ test( l );
+ test_ordered_iterator( l );
+ }
+
+ TEST_F( LazyKVList_NOGC, wrapped_stat )
+ {
+ struct traits: public cc::lazy_list::traits
+ {
+ typedef lt less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::lazy_list::wrapped_stat<> stat;
+ };
+ typedef cc::LazyKVList<gc_type, key_type, value_type, traits > list_type;
+
+ cds::container::lazy_list::stat<> st;
+ list_type l( st );
+ test( l );
+ test_ordered_iterator( l );
+ }
+
} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_kv_list_hp.h"
void TearDown()
{
cds::threading::Manager::detachThread();
- cds::gc::hp::GarbageCollector::Destruct();
+ cds::gc::dhp::GarbageCollector::Destruct();
}
};
test_hp( l );
}
+ TEST_F( MichaelKVList_DHP, stat )
+ {
+ struct traits: public cc::michael_list::traits
+ {
+ typedef lt less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::michael_list::stat<> stat;
+ };
+ typedef cc::MichaelKVList<gc_type, key_type, value_type, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( MichaelKVList_DHP, wrapped_stat )
+ {
+ struct traits: public cc::michael_list::traits
+ {
+ typedef lt less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::michael_list::wrapped_stat<> stat;
+ };
+ typedef cc::MichaelKVList<gc_type, key_type, value_type, traits > list_type;
+
+ cds::container::michael_list::stat<> st;
+ list_type l( st );
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_kv_list_hp.h"
test_hp( l );
}
+ TEST_F( MichaelKVList_HP, stat )
+ {
+ struct traits: public cc::michael_list::traits
+ {
+ typedef lt less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::michael_list::stat<> stat;
+ };
+ typedef cc::MichaelKVList<gc_type, key_type, value_type, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( MichaelKVList_HP, wrapped_stat )
+ {
+ struct traits: public cc::michael_list::traits
+ {
+ typedef lt less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::michael_list::wrapped_stat<> stat;
+ };
+ typedef cc::MichaelKVList<gc_type, key_type, value_type, traits > list_type;
+
+ cds::container::michael_list::stat<> st;
+ list_type l( st );
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_kv_list_nogc.h"
test_ordered_iterator( l );
}
+ TEST_F( MichaelKVList_NOGC, stat )
+ {
+ struct traits: public cc::michael_list::traits
+ {
+ typedef lt less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::michael_list::stat<> stat;
+ };
+ typedef cc::MichaelKVList<gc_type, key_type, value_type, traits > list_type;
+
+ list_type l;
+ test( l );
+ test_ordered_iterator( l );
+ }
+
+ TEST_F( MichaelKVList_NOGC, wrapped_stat )
+ {
+ struct traits: public cc::michael_list::traits
+ {
+ typedef lt less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::michael_list::wrapped_stat<> stat;
+ };
+ typedef cc::MichaelKVList<gc_type, key_type, value_type, traits > list_type;
+
+ cds::container::michael_list::stat<> st;
+ list_type l( st );
+ test( l );
+ test_ordered_iterator( l );
+ }
+
} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_list_hp.h"
void TearDown()
{
cds::threading::Manager::detachThread();
- cds::gc::hp::GarbageCollector::Destruct();
+ cds::gc::dhp::GarbageCollector::Destruct();
}
};
test_hp( l );
}
+ TEST_F( LazyList_DHP, stat )
+ {
+ struct traits: public cc::lazy_list::traits
+ {
+ typedef lt<item> less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::lazy_list::stat<> stat;
+ };
+ typedef cc::LazyList<gc_type, item, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( LazyList_DHP, wrapped_stat )
+ {
+ struct traits: public cc::lazy_list::traits
+ {
+ typedef lt<item> less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::lazy_list::wrapped_stat<> stat;
+ };
+ typedef cc::LazyList<gc_type, item, traits > list_type;
+
+ cds::container::lazy_list::stat<> st;
+ list_type l( st );
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+
} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_list_hp.h"
test_hp( l );
}
+ TEST_F( LazyList_HP, stat )
+ {
+ struct traits: public cc::lazy_list::traits
+ {
+ typedef lt<item> less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::lazy_list::stat<> stat;
+ };
+ typedef cc::LazyList<gc_type, item, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( LazyList_HP, wrapped_stat )
+ {
+ struct traits: public cc::lazy_list::traits
+ {
+ typedef lt<item> less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::lazy_list::wrapped_stat<> stat;
+ };
+ typedef cc::LazyList<gc_type, item, traits > list_type;
+
+ cds::container::lazy_list::stat<> st;
+ list_type l( st );
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_list_nogc.h"
test_ordered_iterator( l );
}
+ TEST_F( LazyList_NOGC, stat )
+ {
+ struct traits: public cc::lazy_list::traits
+ {
+ typedef lt<item> less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::lazy_list::stat<> stat;
+ };
+ typedef cc::LazyList<gc_type, item, traits > list_type;
+
+ list_type l;
+ test( l );
+ test_ordered_iterator( l );
+ }
+
+ TEST_F( LazyList_NOGC, wrapped_stat )
+ {
+ struct traits: public cc::lazy_list::traits
+ {
+ typedef lt<item> less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::lazy_list::wrapped_stat<> stat;
+ };
+ typedef cc::LazyList<gc_type, item, traits > list_type;
+
+ cds::container::lazy_list::stat<> st;
+ list_type l( st );
+ test( l );
+ test_ordered_iterator( l );
+ }
+
} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_list_hp.h"
void TearDown()
{
cds::threading::Manager::detachThread();
- cds::gc::hp::GarbageCollector::Destruct();
+ cds::gc::dhp::GarbageCollector::Destruct();
}
};
test_hp( l );
}
+ TEST_F( MichaelList_DHP, stat )
+ {
+ struct traits: public cc::michael_list::traits
+ {
+ typedef lt<item> less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::michael_list::stat<> stat;
+
+ };
+ typedef cc::MichaelList<gc_type, item, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( MichaelList_DHP, wrapped_stat )
+ {
+ struct traits: public cc::michael_list::traits
+ {
+ typedef lt<item> less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::michael_list::wrapped_stat<> stat;
+
+ };
+ typedef cc::MichaelList<gc_type, item, traits > list_type;
+
+ cds::container::michael_list::stat<> st;
+ list_type l( st );
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_list_hp.h"
test_hp( l );
}
+ TEST_F( MichaelList_HP, stat )
+ {
+ struct traits: public cc::michael_list::traits
+ {
+ typedef lt<item> less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::michael_list::stat<> stat;
+
+ };
+ typedef cc::MichaelList<gc_type, item, traits > list_type;
+
+ list_type l;
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
+ TEST_F( MichaelList_HP, wrapped_stat )
+ {
+ struct traits: public cc::michael_list::traits
+ {
+ typedef lt<item> less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::michael_list::wrapped_stat<> stat;
+
+ };
+ typedef cc::MichaelList<gc_type, item, traits > list_type;
+
+ cds::container::michael_list::stat<> st;
+ list_type l( st );
+ test_common( l );
+ test_ordered_iterator( l );
+ test_hp( l );
+ }
+
} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_list_nogc.h"
test_ordered_iterator( l );
}
+ TEST_F( MichaelList_NOGC, stat )
+ {
+ struct traits: public cc::michael_list::traits
+ {
+ typedef lt<item> less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::michael_list::stat<> stat;
+ };
+ typedef cc::MichaelList<gc_type, item, traits > list_type;
+
+ list_type l;
+ test( l );
+ test_ordered_iterator( l );
+ }
+
+ TEST_F( MichaelList_NOGC, wrapped_stat )
+ {
+ struct traits: public cc::michael_list::traits
+ {
+ typedef lt<item> less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::michael_list::wrapped_stat<> stat;
+ };
+ typedef cc::MichaelList<gc_type, item, traits > list_type;
+
+ cds::container::michael_list::stat<> st;
+ list_type l{ st };
+ test( l );
+ test_ordered_iterator( l );
+ }
+
} // namespace
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CDSUNIT_LIST_TEST_INTRUSIVE_ITERABLE_LIST_H
+#define CDSUNIT_LIST_TEST_INTRUSIVE_ITERABLE_LIST_H
+
+#include <cds_test/check_size.h>
+#include <cds_test/fixture.h>
+
+namespace cds_test {
+
+ class intrusive_iterable_list : public fixture
+ {
+ public:
+ struct stat {
+ int nDisposeCount;
+ int nUpdateExistsCall;
+ int nUpdateNewCall;
+ int nFindCall;
+ int nEraseCall;
+ int nInsertCall;
+
+ stat()
+ : nDisposeCount( 0 )
+ , nUpdateExistsCall( 0 )
+ , nUpdateNewCall( 0 )
+ , nFindCall( 0 )
+ , nEraseCall( 0 )
+ , nInsertCall( 0 )
+ {}
+
+ stat( const stat& s )
+ {
+ *this = s;
+ }
+
+ stat& operator =( const stat& s )
+ {
+ memcpy( this, &s, sizeof( s ) );
+ return *this;
+ }
+ };
+
+ struct item_type
+ {
+ int nKey;
+ int nVal;
+
+ mutable stat s;
+
+ item_type()
+ {}
+
+ item_type( int key, int val )
+ : nKey( key )
+ , nVal( val )
+ , s()
+ {}
+
+ item_type( const item_type& v )
+ : nKey( v.nKey )
+ , nVal( v.nVal )
+ , s()
+ {}
+
+ const int& key() const
+ {
+ return nKey;
+ }
+
+ item_type& operator=( item_type const& src )
+ {
+ nKey = src.nKey;
+ nVal = src.nVal;
+ return *this;
+ }
+
+ item_type& operator=( item_type&& src )
+ {
+ nKey = src.nKey;
+ nVal = src.nVal;
+ return *this;
+ }
+ };
+
+ template <typename T>
+ struct less
+ {
+ bool operator ()( const T& v1, const T& v2 ) const
+ {
+ return v1.key() < v2.key();
+ }
+
+ template <typename Q>
+ bool operator ()( const T& v1, const Q& v2 ) const
+ {
+ return v1.key() < v2;
+ }
+
+ template <typename Q>
+ bool operator ()( const Q& v1, const T& v2 ) const
+ {
+ return v1 < v2.key();
+ }
+ };
+
+ struct other_item {
+ int nKey;
+
+ other_item( int n )
+ : nKey( n )
+ {}
+ };
+
+ struct other_less {
+ template <typename T, typename Q>
+ bool operator()( T const& i1, Q const& i2 ) const
+ {
+ return i1.nKey < i2.nKey;
+ }
+ };
+
+ template <typename T>
+ struct cmp {
+ int operator ()( const T& v1, const T& v2 ) const
+ {
+ if ( v1.key() < v2.key() )
+ return -1;
+ return v1.key() > v2.key() ? 1 : 0;
+ }
+
+ template <typename Q>
+ int operator ()( const T& v1, const Q& v2 ) const
+ {
+ if ( v1.key() < v2 )
+ return -1;
+ return v1.key() > v2 ? 1 : 0;
+ }
+
+ template <typename Q>
+ int operator ()( const Q& v1, const T& v2 ) const
+ {
+ if ( v1 < v2.key() )
+ return -1;
+ return v1 > v2.key() ? 1 : 0;
+ }
+ };
+
+ struct mock_disposer
+ {
+ template <typename T>
+ void operator ()( T * p )
+ {
+ ++p->s.nDisposeCount;
+ }
+ };
+
+ struct update_functor
+ {
+ template <typename T>
+ void operator()( T& item, T * old )
+ {
+ if ( !old )
+ ++item.s.nUpdateNewCall;
+ else
+ ++item.s.nUpdateExistsCall;
+ }
+ };
+
+ struct find_functor
+ {
+ template <typename T, typename Q>
+ void operator ()( T& item, Q& /*val*/ )
+ {
+ ++item.s.nFindCall;
+ }
+ };
+
+ struct erase_functor
+ {
+ template <typename T>
+ void operator()( T const& item )
+ {
+ item.s.nEraseCall++;
+ }
+ };
+
+ protected:
+ template <typename List>
+ void test_common( List& l )
+ {
+ // Precondition: list is empty
+ // Postcondition: list is empty
+
+ static const size_t nSize = 20;
+ typedef typename List::value_type value_type;
+ value_type arr[ nSize ];
+ value_type arr2[ nSize ];
+
+ for ( size_t i = 0; i < nSize; ++i ) {
+ arr[i].nKey = static_cast<int>( i );
+ arr[i].nVal = arr[i].nKey * 10;
+
+ arr2[i] = arr[i];
+ }
+ shuffle( arr, arr + nSize );
+ shuffle( arr2, arr2 + nSize );
+
+ ASSERT_TRUE( l.empty() );
+ ASSERT_CONTAINER_SIZE( l, 0 );
+
+ typedef typename List::iterator iterator;
+
+ // insert / find
+ for ( auto& i : arr ) {
+ EXPECT_FALSE( l.contains( i.nKey ));
+ EXPECT_FALSE( l.contains( other_item( i.nKey ), other_less()));
+ EXPECT_FALSE( l.find( i.nKey, []( value_type& item, int ) { ++item.s.nFindCall; } ));
+ EXPECT_EQ( i.s.nFindCall, 0 );
+ EXPECT_FALSE( l.find_with( other_item( i.nKey ), other_less(), []( value_type& item, other_item const& ) { ++item.s.nFindCall; } ));
+ EXPECT_EQ( i.s.nFindCall, 0 );
+
+ switch ( i.nKey % 4 ) {
+ case 0:
+ EXPECT_TRUE( l.insert( i ));
+ break;
+ case 1:
+ EXPECT_EQ( i.s.nInsertCall, 0 );
+ EXPECT_TRUE( l.insert( i, []( value_type& i ) { ++i.s.nInsertCall; } ));
+ EXPECT_EQ( i.s.nInsertCall, 1 );
+ break;
+ case 2:
+ {
+ std::pair<bool, bool> ret = l.update( i, []( value_type& i, value_type * old ) {
+ EXPECT_TRUE( old == nullptr );
+ EXPECT_EQ( i.s.nUpdateNewCall, 0 );
+ ++i.s.nUpdateNewCall;
+ }, false );
+ EXPECT_EQ( i.s.nUpdateNewCall, 0 );
+ EXPECT_EQ( ret.first, false );
+ EXPECT_EQ( ret.second, false );
+
+ ret = l.update( i, []( value_type& i, value_type * old ) {
+ EXPECT_TRUE( old == nullptr );
+ EXPECT_EQ( i.s.nUpdateNewCall, 0 );
+ ++i.s.nUpdateNewCall;
+ }, true );
+ EXPECT_EQ( i.s.nUpdateNewCall, 1 );
+ EXPECT_EQ( ret.first, true );
+ EXPECT_EQ( ret.second, true );
+ }
+ break;
+ case 3:
+ {
+ std::pair<bool, bool> ret = l.upsert( i, false );
+ EXPECT_EQ( ret.first, false );
+ EXPECT_EQ( ret.second, false );
+
+ ret = l.upsert( i );
+ EXPECT_EQ( ret.first, true );
+ EXPECT_EQ( ret.second, true );
+ }
+ break;
+ }
+
+ EXPECT_TRUE( l.contains( i.nKey ));
+ EXPECT_TRUE( l.contains( i ));
+ EXPECT_TRUE( l.contains( other_item( i.nKey ), other_less()));
+ EXPECT_TRUE( l.find( i.nKey, []( value_type& item, int ) { ++item.s.nFindCall; } ));
+ EXPECT_EQ( i.s.nFindCall, 1 );
+ EXPECT_TRUE( l.find( i, []( value_type& item, value_type const& ) { ++item.s.nFindCall; } ));
+ EXPECT_EQ( i.s.nFindCall, 2 );
+ EXPECT_TRUE( l.find_with( other_item( i.nKey ), other_less(), []( value_type& item, other_item const& ) { ++item.s.nFindCall; } ));
+ EXPECT_EQ( i.s.nFindCall, 3 );
+
+ EXPECT_FALSE( l.insert( i ) );
+ ASSERT_FALSE( l.empty() );
+
+ int const ckey = i.nKey;
+ iterator it = l.find( ckey );
+ ASSERT_FALSE( it == l.end() );
+ EXPECT_EQ( it->nKey, i.nKey );
+ EXPECT_EQ( (*it).nVal, i.nVal );
+ check_ordered( it, l.end() );
+
+ it = l.find( i.nKey );
+ ASSERT_FALSE( it == l.end() );
+ EXPECT_EQ( it->nKey, i.nKey );
+ EXPECT_EQ( (*it).nVal, i.nVal );
+ check_ordered( it, l.end() );
+
+ it = l.find_with( other_item( i.nKey ), other_less() );
+ ASSERT_FALSE( it == l.end() );
+ EXPECT_EQ( it->nKey, i.nKey );
+ EXPECT_EQ( it->nVal, i.nVal );
+ check_ordered( it, l.end() );
+
+ }
+ ASSERT_CONTAINER_SIZE( l, nSize );
+
+ // check all items
+ for ( auto const& i : arr ) {
+ EXPECT_TRUE( l.contains( i.nKey ));
+ EXPECT_TRUE( l.contains( i ));
+ EXPECT_TRUE( l.contains( other_item( i.nKey ), other_less()));
+ EXPECT_TRUE( l.find( i.nKey, []( value_type& item, int ) { ++item.s.nFindCall; } ));
+ EXPECT_EQ( i.s.nFindCall, 4 );
+ EXPECT_TRUE( l.find( i, []( value_type& item, value_type const& ) { ++item.s.nFindCall; } ));
+ EXPECT_EQ( i.s.nFindCall, 5 );
+ EXPECT_TRUE( l.find_with( other_item( i.nKey ), other_less(), []( value_type& item, other_item const& ) { ++item.s.nFindCall; } ));
+ EXPECT_EQ( i.s.nFindCall, 6 );
+ }
+ ASSERT_FALSE( l.empty() );
+ ASSERT_CONTAINER_SIZE( l, nSize );
+
+ // update existing test
+ for ( auto& i : arr2 ) {
+ EXPECT_EQ( i.s.nUpdateExistsCall, 0 );
+ std::pair<bool, bool> ret = l.update( i, update_functor() );
+ EXPECT_TRUE( ret.first );
+ EXPECT_FALSE( ret.second );
+ EXPECT_EQ( i.s.nUpdateExistsCall, 1 );
+ }
+
+ // update with the same value must be empty - no functor is called
+ for ( auto& i : arr2 ) {
+ EXPECT_EQ( i.s.nUpdateExistsCall, 1 );
+ std::pair<bool, bool> ret = l.update( i, update_functor() );
+ EXPECT_TRUE( ret.first );
+ EXPECT_FALSE( ret.second );
+ EXPECT_EQ( i.s.nUpdateExistsCall, 1 );
+ }
+
+ for ( auto& i : arr ) {
+ EXPECT_EQ( i.s.nUpdateExistsCall, 0 );
+ std::pair<bool, bool> ret = l.update( i, []( value_type& i, value_type * old ) {
+ EXPECT_FALSE( old == nullptr );
+ EXPECT_EQ( i.s.nUpdateExistsCall, 0 );
+ ++i.s.nUpdateExistsCall;
+ });
+ EXPECT_TRUE( ret.first );
+ EXPECT_FALSE( ret.second );
+ EXPECT_EQ( i.s.nUpdateExistsCall, 1 );
+ }
+
+ // erase test
+ for ( auto const& i : arr ) {
+ if ( i.nKey & 1 )
+ EXPECT_TRUE( l.erase( i.nKey ));
+ else
+ EXPECT_TRUE( l.erase_with( other_item( i.nKey ), other_less() ));
+
+ EXPECT_FALSE( l.contains( i ));
+ }
+ EXPECT_TRUE( l.empty() );
+ EXPECT_CONTAINER_SIZE( l, 0 );
+
+ // Apply retired pointer to clean links
+ List::gc::force_dispose();
+
+ for ( auto const& i : arr )
+ EXPECT_EQ( i.s.nDisposeCount, 2 );
+ for ( auto const& i : arr2 )
+ EXPECT_EQ( i.s.nDisposeCount, 1 );
+
+ // erase with functor
+ for ( auto& i : arr ) {
+ int const updateNewCall = i.s.nUpdateNewCall;
+ std::pair<bool, bool> ret = l.update( i, update_functor(), false );
+ EXPECT_FALSE( ret.first );
+ EXPECT_FALSE( ret.second );
+ EXPECT_EQ( i.s.nUpdateNewCall, updateNewCall );
+
+ ret = l.update( i, update_functor(), true );
+ EXPECT_TRUE( ret.first );
+ EXPECT_TRUE( ret.second );
+ EXPECT_EQ( i.s.nUpdateNewCall, updateNewCall + 1 );
+ }
+ EXPECT_FALSE( l.empty() );
+ EXPECT_CONTAINER_SIZE( l, nSize );
+
+ for ( auto const& i : arr ) {
+ EXPECT_EQ( i.s.nEraseCall, 0 );
+ if ( i.nKey & 1 ) {
+ EXPECT_TRUE( l.erase_with( other_item( i.nKey ), other_less(), erase_functor()));
+ EXPECT_FALSE( l.erase_with( other_item( i.nKey ), other_less(), erase_functor()));
+ }
+ else {
+ EXPECT_TRUE( l.erase( i.nKey, []( value_type& item) { ++item.s.nEraseCall; } ));
+ EXPECT_FALSE( l.erase( i.nKey, []( value_type& item) { ++item.s.nEraseCall; } ));
+ }
+ EXPECT_EQ( i.s.nEraseCall, 1 );
+ EXPECT_FALSE( l.contains( i.nKey ));
+ }
+ EXPECT_TRUE( l.empty() );
+ EXPECT_CONTAINER_SIZE( l, 0 );
+
+ // Apply retired pointer to clean links
+ List::gc::force_dispose();
+
+ for ( auto const& i : arr )
+ EXPECT_EQ( i.s.nDisposeCount, 3 );
+
+ // clear test
+ for ( auto& i : arr )
+ EXPECT_TRUE( l.insert( i ));
+
+ EXPECT_FALSE( l.empty() );
+ EXPECT_CONTAINER_SIZE( l, nSize );
+
+ l.clear();
+
+ EXPECT_TRUE( l.empty() );
+ EXPECT_CONTAINER_SIZE( l, 0 );
+
+ // Apply retired pointer to clean links
+ List::gc::force_dispose();
+ for ( auto const& i : arr ) {
+ EXPECT_EQ( i.s.nDisposeCount, 4 );
+ EXPECT_FALSE( l.contains( i ));
+ }
+
+ // unlink test
+ for ( auto& i : arr )
+ EXPECT_TRUE( l.insert( i ) );
+ for ( auto& i : arr ) {
+ value_type val( i );
+ EXPECT_TRUE( l.contains( val ));
+ EXPECT_FALSE( l.unlink( val ));
+ EXPECT_TRUE( l.contains( val ) );
+ EXPECT_TRUE( l.unlink( i ));
+ EXPECT_FALSE( l.unlink( i ));
+ EXPECT_FALSE( l.contains( i ) );
+ }
+ EXPECT_TRUE( l.empty() );
+ EXPECT_CONTAINER_SIZE( l, 0 );
+
+ // Apply retired pointer to clean links
+ List::gc::force_dispose();
+ for ( auto const& i : arr ) {
+ EXPECT_EQ( i.s.nDisposeCount, 5 );
+ EXPECT_FALSE( l.contains( i ) );
+ }
+
+ // Iterators on empty list
+ {
+ auto it = l.begin();
+ auto itEnd = l.end();
+ auto cit = l.cbegin();
+ auto citEnd = l.cend();
+
+ EXPECT_TRUE( it == itEnd );
+ EXPECT_TRUE( it == cit );
+ EXPECT_TRUE( cit == citEnd );
+
+ ++it;
+ ++cit;
+
+ EXPECT_TRUE( it == itEnd );
+ EXPECT_TRUE( it == cit );
+ EXPECT_TRUE( cit == citEnd );
+ }
+ }
+
+ template <typename List>
+ void test_ordered_iterator( List& l )
+ {
+ // Precondition: list is empty
+ // Postcondition: list is empty
+
+ static const size_t nSize = 20;
+ typedef typename List::value_type value_type;
+ value_type arr[nSize];
+
+ for ( size_t i = 0; i < nSize; ++i ) {
+ arr[i].nKey = static_cast<int>(i);
+ arr[i].nVal = arr[i].nKey * 10;
+ }
+ shuffle( arr, arr + nSize );
+
+ ASSERT_TRUE( l.empty() );
+ ASSERT_CONTAINER_SIZE( l, 0 );
+
+ for ( auto& i : arr )
+ EXPECT_TRUE( l.insert( i ) );
+
+ int key = 0;
+ for ( auto it = l.begin(); it != l.end(); ++it ) {
+ EXPECT_EQ( it->nKey, key );
+ EXPECT_EQ( (*it).nKey, key );
+ ++key;
+ }
+
+ key = 0;
+ for ( auto it = l.cbegin(); it != l.cend(); ++it ) {
+ EXPECT_EQ( it->nKey, key );
+ EXPECT_EQ( (*it).nKey, key );
+ ++key;
+ }
+
+ l.clear();
+ List::gc::force_dispose();
+ for ( auto const& i : arr ) {
+ EXPECT_EQ( i.s.nDisposeCount, 1 );
+ EXPECT_FALSE( l.contains( i ) );
+ }
+ }
+
+ template <typename Iterator>
+ void check_ordered( Iterator first, Iterator last )
+ {
+ while ( first != last ) {
+ Iterator it = first;
+ if ( ++it != last ) {
+ EXPECT_LT( first->nKey, it->nKey );
+ }
+ first = it;
+ }
+ }
+
+ };
+
+} // namespace cds_test
+
+#endif // CDSUNIT_LIST_TEST_INTRUSIVE_ITERABLE_LIST_H
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CDSUNIT_LIST_TEST_INTRUSIVE_ITERABLE_LIST_HP_H
+#define CDSUNIT_LIST_TEST_INTRUSIVE_ITERABLE_LIST_HP_H
+
+#include "test_intrusive_iterable_list.h"
+
+namespace cds_test {
+
+ class intrusive_iterable_list_hp : public intrusive_iterable_list
+ {
+ protected:
+ template <typename List>
+ void test_hp( List& l )
+ {
+ // Precondition: list is empty
+ // Postcondition: list is empty
+
+ static const size_t nSize = 20;
+ typedef typename List::value_type value_type;
+ value_type arr[nSize];
+
+ for ( size_t i = 0; i < nSize; ++i ) {
+ arr[i].nKey = static_cast<int>(i);
+ arr[i].nVal = arr[i].nKey * 10;
+ }
+ shuffle( arr, arr + nSize );
+
+ typedef typename List::guarded_ptr guarded_ptr;
+
+ ASSERT_TRUE( l.empty() );
+ ASSERT_CONTAINER_SIZE( l, 0 );
+
+ guarded_ptr gp;
+
+ // get() test
+ for ( auto& i : arr ) {
+ gp = l.get( i.nKey );
+ EXPECT_TRUE( !gp );
+ gp = l.get_with( other_item( i.nKey ), other_less() );
+ EXPECT_TRUE( !gp );
+
+ EXPECT_TRUE( l.insert( i ) );
+
+ gp = l.get( i.nKey );
+ ASSERT_FALSE( !gp );
+ EXPECT_EQ( gp->nKey, i.nKey );
+ EXPECT_EQ( gp->nVal, i.nVal );
+ gp = l.get_with( other_item( i.nKey ), other_less() );
+ ASSERT_FALSE( !gp );
+ EXPECT_EQ( gp->nKey, i.nKey );
+ EXPECT_EQ( gp->nVal, i.nVal );
+ }
+
+ // extract() test
+ for ( int i = 0; i < static_cast<int>(nSize); ++i ) {
+ if ( i & 1 )
+ gp = l.extract( i );
+ else
+ gp = l.extract_with( other_item( i ), other_less() );
+ ASSERT_FALSE( !gp );
+ EXPECT_EQ( gp->nKey, i );
+
+ gp = l.extract( i );
+ EXPECT_TRUE( !gp );
+ gp = l.extract_with( other_item( i ), other_less() );
+ EXPECT_TRUE( !gp );
+ }
+
+ ASSERT_TRUE( l.empty() );
+ ASSERT_CONTAINER_SIZE( l, 0 );
+
+ List::gc::force_dispose();
+ for ( auto const& i : arr ) {
+ EXPECT_EQ( i.s.nDisposeCount, 1 );
+ EXPECT_FALSE( l.contains( i ) );
+ }
+ }
+ };
+
+} // namespace cds_test
+
+#endif // CDSUNIT_LIST_TEST_INTRUSIVE_ITERABLE_LIST_HP_H
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSUNIT_LIST_TEST_INTRUSIVE_LAZY_LIST_RCU_H
#define CDSUNIT_LIST_TEST_INTRUSIVE_LAZY_LIST_RCU_H
this->test_rcu( l );
}
+TYPED_TEST_P( IntrusiveLazyList, base_hook_stat )
+{
+ struct traits: public ci::lazy_list::traits {
+ typedef ci::lazy_list::base_hook< cds::opt::gc< typename TestFixture::rcu_type >> hook;
+ typedef typename TestFixture::mock_disposer disposer;
+ typedef typename TestFixture::template cmp< typename TestFixture::base_item > compare;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::intrusive::lazy_list::stat<> stat;
+ };
+ typedef ci::LazyList< typename TestFixture::rcu_type, typename TestFixture::base_item, traits > list_type;
+
+ list_type l;
+ this->test_common( l );
+ this->test_ordered_iterator( l );
+ this->test_rcu( l );
+}
+
+TYPED_TEST_P( IntrusiveLazyList, base_hook_wrapped_stat )
+{
+ struct traits: public ci::lazy_list::traits {
+ typedef ci::lazy_list::base_hook< cds::opt::gc< typename TestFixture::rcu_type >> hook;
+ typedef typename TestFixture::mock_disposer disposer;
+ typedef typename TestFixture::template cmp< typename TestFixture::base_item > compare;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::intrusive::lazy_list::wrapped_stat<> stat;
+ };
+ typedef ci::LazyList< typename TestFixture::rcu_type, typename TestFixture::base_item, traits > list_type;
+
+ cds::intrusive::lazy_list::stat<> st;
+ list_type l( st );
+ this->test_common( l );
+ this->test_ordered_iterator( l );
+ this->test_rcu( l );
+}
+
TYPED_TEST_P( IntrusiveLazyList, member_hook )
{
typedef ci::LazyList< typename TestFixture::rcu_type, typename TestFixture::member_item,
this->test_rcu( l );
}
+TYPED_TEST_P( IntrusiveLazyList, member_hook_stat )
+{
+ struct traits: public ci::lazy_list::traits {
+ typedef ci::lazy_list::member_hook< offsetof( typename TestFixture::member_item, hMember ), cds::opt::gc< typename TestFixture::rcu_type >> hook;
+ typedef typename TestFixture::mock_disposer disposer;
+ typedef typename TestFixture::template cmp< typename TestFixture::member_item > compare;
+ typedef typename TestFixture::template less< typename TestFixture::member_item > less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::intrusive::lazy_list::stat<> stat;
+ };
+ typedef ci::LazyList< typename TestFixture::rcu_type, typename TestFixture::member_item, traits > list_type;
+
+ list_type l;
+ this->test_common( l );
+ this->test_ordered_iterator( l );
+ this->test_rcu( l );
+}
+
+TYPED_TEST_P( IntrusiveLazyList, member_hook_wrapped_stat )
+{
+ struct traits: public ci::lazy_list::traits {
+ typedef ci::lazy_list::member_hook< offsetof( typename TestFixture::member_item, hMember ), cds::opt::gc< typename TestFixture::rcu_type >> hook;
+ typedef typename TestFixture::mock_disposer disposer;
+ typedef typename TestFixture::template cmp< typename TestFixture::member_item > compare;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::intrusive::lazy_list::wrapped_stat<> stat;
+ };
+ typedef ci::LazyList< typename TestFixture::rcu_type, typename TestFixture::member_item, traits > list_type;
+
+ cds::intrusive::lazy_list::stat<> st;
+ list_type l( st );
+ this->test_common( l );
+ this->test_ordered_iterator( l );
+ this->test_rcu( l );
+}
// GCC 5: All test names should be written on single line, otherwise a runtime error will be encountered like as
// "No test named <test_name> can be found in this test case"
REGISTER_TYPED_TEST_CASE_P( IntrusiveLazyList,
- base_hook, base_hook_cmp, base_hook_item_counting, base_hook_backoff, base_hook_seqcst, member_hook, member_hook_cmp, member_hook_item_counting, member_hook_seqcst, member_hook_back_off
+ base_hook, base_hook_cmp, base_hook_item_counting, base_hook_backoff, base_hook_seqcst, base_hook_stat, base_hook_wrapped_stat, member_hook, member_hook_cmp, member_hook_item_counting, member_hook_seqcst, member_hook_back_off, member_hook_stat, member_hook_wrapped_stat
);
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSUNIT_LIST_TEST_INTRUSIVE_MICHAEL_LIST_RCU_H
#define CDSUNIT_LIST_TEST_INTRUSIVE_MICHAEL_LIST_RCU_H
this->test_rcu( l );
}
+TYPED_TEST_P( IntrusiveMichaelList, base_hook_stat )
+{
+ struct traits: public ci::michael_list::traits {
+ typedef ci::michael_list::base_hook< cds::opt::gc< typename TestFixture::rcu_type >> hook;
+ typedef typename TestFixture::mock_disposer disposer;
+ typedef typename TestFixture::template cmp< typename TestFixture::base_item > compare;
+ typedef cds::intrusive::michael_list::stat<> stat;
+ };
+ typedef ci::MichaelList< typename TestFixture::rcu_type, typename TestFixture::base_item, traits > list_type;
+
+ list_type l;
+ this->test_common( l );
+ this->test_ordered_iterator( l );
+ this->test_rcu( l );
+}
+
+TYPED_TEST_P( IntrusiveMichaelList, base_hook_wrapped_stat )
+{
+ struct traits: public ci::michael_list::traits {
+ typedef ci::michael_list::base_hook< cds::opt::gc< typename TestFixture::rcu_type >> hook;
+ typedef typename TestFixture::mock_disposer disposer;
+ typedef typename TestFixture::template cmp< typename TestFixture::base_item > compare;
+ typedef cds::intrusive::michael_list::wrapped_stat<> stat;
+ };
+ typedef ci::MichaelList< typename TestFixture::rcu_type, typename TestFixture::base_item, traits > list_type;
+
+ cds::intrusive::michael_list::stat<> st;
+ list_type l( st );
+ this->test_common( l );
+ this->test_ordered_iterator( l );
+ this->test_rcu( l );
+}
+
TYPED_TEST_P( IntrusiveMichaelList, member_hook )
{
typedef ci::MichaelList< typename TestFixture::rcu_type, typename TestFixture::member_item,
this->test_rcu( l );
}
+TYPED_TEST_P( IntrusiveMichaelList, member_hook_stat )
+{
+ struct traits: public ci::michael_list::traits {
+ typedef ci::michael_list::member_hook< offsetof( typename TestFixture::member_item, hMember ), cds::opt::gc< typename TestFixture::rcu_type >> hook;
+ typedef typename TestFixture::mock_disposer disposer;
+ typedef typename TestFixture::template cmp< typename TestFixture::member_item > compare;
+ typedef cds::intrusive::michael_list::stat<> stat;
+ };
+ typedef ci::MichaelList< typename TestFixture::rcu_type, typename TestFixture::member_item, traits > list_type;
+
+ list_type l;
+ this->test_common( l );
+ this->test_ordered_iterator( l );
+ this->test_rcu( l );
+}
+
+TYPED_TEST_P( IntrusiveMichaelList, member_hook_wrapped_stat )
+{
+ struct traits: public ci::michael_list::traits {
+ typedef ci::michael_list::member_hook< offsetof( typename TestFixture::member_item, hMember ), cds::opt::gc< typename TestFixture::rcu_type >> hook;
+ typedef typename TestFixture::mock_disposer disposer;
+ typedef typename TestFixture::template cmp< typename TestFixture::member_item > compare;
+ typedef cds::intrusive::michael_list::wrapped_stat<> stat;
+ };
+ typedef ci::MichaelList< typename TestFixture::rcu_type, typename TestFixture::member_item, traits > list_type;
+
+ cds::intrusive::michael_list::stat<> st;
+ list_type l( st );
+ this->test_common( l );
+ this->test_ordered_iterator( l );
+ this->test_rcu( l );
+}
+
// GCC 5: All test names should be written on single line, otherwise a runtime error will be encountered like as
// "No test named <test_name> can be found in this test case"
REGISTER_TYPED_TEST_CASE_P( IntrusiveMichaelList,
- base_hook, base_hook_cmp, base_hook_item_counting, base_hook_backoff, base_hook_seqcst, member_hook, member_hook_cmp, member_hook_item_counting, member_hook_seqcst, member_hook_back_off
+ base_hook, base_hook_cmp, base_hook_item_counting, base_hook_backoff, base_hook_seqcst, base_hook_stat, base_hook_wrapped_stat, member_hook, member_hook_cmp, member_hook_item_counting, member_hook_seqcst, member_hook_back_off, member_hook_stat, member_hook_wrapped_stat
);
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSUNIT_LIST_TEST_ITERABLE_LIST_H
+#define CDSUNIT_LIST_TEST_ITERABLE_LIST_H
+
+#include <cds_test/check_size.h>
+#include <cds_test/fixture.h>
+
+namespace cds_test {
+
+ class iterable_list_test : public fixture
+ {
+ public:
+ struct item {
+ int nKey;
+ int nVal;
+
+ item()
+ {}
+
+ item( int key )
+ : nKey( key )
+ , nVal( key * 2 )
+ {}
+
+ item( int key, int val )
+ : nKey( key )
+ , nVal( val )
+ {}
+
+ item( const item& v )
+ : nKey( v.nKey )
+ , nVal( v.nVal )
+ {}
+
+ int key() const
+ {
+ return nKey;
+ }
+ };
+
+ template <typename T>
+ struct lt
+ {
+ bool operator ()( const T& v1, const T& v2 ) const
+ {
+ return v1.key() < v2.key();
+ }
+
+ template <typename Q>
+ bool operator ()( const T& v1, const Q& v2 ) const
+ {
+ return v1.key() < v2;
+ }
+
+ template <typename Q>
+ bool operator ()( const Q& v1, const T& v2 ) const
+ {
+ return v1 < v2.key();
+ }
+ };
+
+ template <typename T>
+ struct cmp {
+ int operator ()( const T& v1, const T& v2 ) const
+ {
+ if ( v1.key() < v2.key() )
+ return -1;
+ return v1.key() > v2.key() ? 1 : 0;
+ }
+
+ template <typename Q>
+ int operator ()( const T& v1, const Q& v2 ) const
+ {
+ if ( v1.key() < v2 )
+ return -1;
+ return v1.key() > v2 ? 1 : 0;
+ }
+
+ template <typename Q>
+ int operator ()( const Q& v1, const T& v2 ) const
+ {
+ if ( v1 < v2.key() )
+ return -1;
+ return v1 > v2.key() ? 1 : 0;
+ }
+ };
+
+ struct other_item
+ {
+ int nKey;
+
+ other_item()
+ {}
+
+ other_item( int n )
+ : nKey( n )
+ {}
+ };
+
+ struct other_less
+ {
+ template <typename T1, typename T2>
+ bool operator()( T1 const& t1, T2 const& t2 ) const
+ {
+ return t1.nKey < t2.nKey;
+ }
+ };
+
+ protected:
+ template <typename List>
+ void test_common( List& l )
+ {
+ // Precondition: list is empty
+ // Postcondition: list is empty
+
+ static const size_t nSize = 20;
+ typedef typename List::value_type value_type;
+ value_type arr[nSize];
+
+ for ( size_t i = 0; i < nSize; ++i ) {
+ arr[i].nKey = static_cast<int>(i);
+ arr[i].nVal = arr[i].nKey * 10;
+ }
+ shuffle( arr, arr + nSize );
+
+ ASSERT_TRUE( l.empty() );
+ ASSERT_CONTAINER_SIZE( l, 0 );
+
+ // insert/find
+ for ( auto const& i : arr ) {
+ EXPECT_FALSE( l.contains( i ));
+ EXPECT_FALSE( l.contains( i.nKey ));
+ EXPECT_FALSE( l.contains( other_item( i.nKey ), other_less()));
+ EXPECT_TRUE( l.find( i ) == l.end());
+ EXPECT_FALSE( l.find( i, []( value_type&, value_type const&) {} ));
+ EXPECT_FALSE( l.find( i.nKey, []( value_type&, int ) {} ));
+ EXPECT_FALSE( l.find_with( other_item( i.nKey ), other_less(), []( value_type&, other_item const& ) {} ));
+ EXPECT_TRUE( l.find_with( other_item( i.nKey ), other_less()) == l.end());
+
+ switch ( i.nKey % 5 ) {
+ case 0:
+ EXPECT_TRUE( l.insert( i.nKey ));
+ EXPECT_TRUE( l.find( i.nKey, []( value_type& n, int key ) {
+ EXPECT_EQ( n.nVal, key * 2 );
+ } ));
+ EXPECT_FALSE( l.insert( i.nKey ));
+ break;
+ case 1:
+ EXPECT_TRUE( l.insert( i, []( value_type& n ) {
+ n.nVal = n.nKey * 3;
+ }));
+ EXPECT_TRUE( l.find( i.nKey, []( value_type& n, int key ) {
+ EXPECT_EQ( n.nVal, key * 3 );
+ } ));
+ EXPECT_FALSE( l.insert( i ));
+ break;
+ case 2:
+ EXPECT_TRUE( l.emplace( i.nKey, i.nKey * 100 ));
+ EXPECT_TRUE( l.find( i.nKey, []( value_type& n, int key ) {
+ EXPECT_EQ( n.nVal, key * 100 );
+ } ));
+ EXPECT_FALSE( l.insert( i ));
+ break;
+ case 3:
+ {
+ auto pair = l.update( i.nKey, []( value_type& n, value_type* old) {
+ EXPECT_TRUE( old == nullptr );
+ n.nVal = n.nKey * 3;
+ }, false );
+ EXPECT_FALSE( pair.first );
+ EXPECT_FALSE( pair.second );
+
+ pair = l.update( i.nKey, []( value_type& n, value_type* old ) {
+ EXPECT_TRUE( old == nullptr );
+ n.nVal = n.nKey * 3;
+ });
+ EXPECT_TRUE( pair.first );
+ EXPECT_TRUE( pair.second );
+
+ EXPECT_TRUE( l.find( i.nKey, []( value_type& n, int key ) {
+ EXPECT_EQ( n.nVal, key * 3 );
+ } ));
+ EXPECT_FALSE( l.insert( i ));
+ }
+ break;
+ case 4:
+ {
+ auto pair = l.upsert( i.nKey, false );
+ EXPECT_FALSE( pair.first );
+ EXPECT_FALSE( pair.second );
+
+ pair = l.upsert( i.nKey );
+ EXPECT_TRUE( pair.first );
+ EXPECT_TRUE( pair.second );
+
+ EXPECT_TRUE( l.find( i.nKey, []( value_type& n, int key ) {
+ EXPECT_EQ( n.nVal, key * 2 );
+ } ));
+ EXPECT_FALSE( l.insert( i ));
+ }
+ break;
+ }
+
+ EXPECT_TRUE( l.contains( i ));
+ EXPECT_TRUE( l.contains( i.nKey ));
+ EXPECT_TRUE( l.contains( other_item( i.nKey ), other_less()));
+ EXPECT_TRUE( l.find( i, []( value_type& n, value_type const& arg ) {
+ EXPECT_EQ( arg.nKey, n.nKey );
+ n.nVal = n.nKey;
+ } ));
+ EXPECT_TRUE( l.find( i.nKey, []( value_type& n, int key ) {
+ EXPECT_EQ( key, n.nKey );
+ EXPECT_EQ( n.nKey, n.nVal );
+ n.nVal = key * 5;
+ } ));
+ EXPECT_TRUE( l.find_with( other_item( i.nKey ), other_less(), []( value_type& n, other_item const& key ) {
+ EXPECT_EQ( key.nKey, n.nKey );
+ EXPECT_EQ( n.nKey * 5, n.nVal );
+ } ));
+ ASSERT_FALSE( l.find( i ) == l.end() );
+ EXPECT_EQ( l.find( i.nKey )->nKey, i.nKey );
+ ASSERT_FALSE( l.find_with( other_item( i.nKey ), other_less() ) == l.end() );
+ EXPECT_EQ( l.find_with( other_item( i.nKey ), other_less() )->nKey, i.nKey );
+
+ auto pair = l.upsert( i.nKey, false );
+ EXPECT_TRUE( pair.first );
+ EXPECT_FALSE( pair.second );
+
+ pair = l.update( i.nKey, []( value_type& n, value_type* old ) {
+ ASSERT_FALSE( old == nullptr );
+ EXPECT_EQ( old->nKey, n.nKey );
+ EXPECT_EQ( old->nKey * 2, n.nVal );
+ n.nVal = old->nKey * 3;
+ }, false );
+ EXPECT_TRUE( pair.first );
+ EXPECT_FALSE( pair.second );
+
+ EXPECT_FALSE( l.empty() );
+ }
+
+ ASSERT_FALSE( l.empty() );
+ EXPECT_CONTAINER_SIZE( l, nSize );
+
+ // erase
+ for ( auto const&i : arr ) {
+ ASSERT_FALSE( l.find( i.nKey ) == l.end() );
+ EXPECT_EQ( l.find( i.nKey )->nKey, i.nKey );
+ ASSERT_FALSE( l.find_with( other_item( i.nKey ), other_less() ) == l.end() );
+ EXPECT_EQ( l.find_with( other_item( i.nKey ), other_less() )->nKey, i.nKey );
+
+ switch ( i.nKey % 4 ) {
+ case 0:
+ EXPECT_TRUE( l.erase( i.nKey ));
+ break;
+ case 1:
+ EXPECT_TRUE( l.erase_with( other_item( i.nKey ), other_less()));
+ break;
+ case 2:
+ EXPECT_TRUE( l.erase( i, [ &i ]( value_type const& n ) {
+ EXPECT_EQ( n.nKey, i.nKey );
+ EXPECT_EQ( n.nKey * 3, n.nVal );
+ }));
+ break;
+ case 3:
+ EXPECT_TRUE( l.erase_with( other_item( i.nKey ), other_less(), [ &i ]( value_type const& n) {
+ EXPECT_EQ( n.nKey, i.nKey );
+ EXPECT_EQ( n.nKey * 3, n.nVal );
+ } ));
+ }
+
+ EXPECT_FALSE( l.contains( i ));
+ EXPECT_FALSE( l.contains( i.nKey ));
+ EXPECT_FALSE( l.contains( other_item( i.nKey ), other_less()));
+ EXPECT_FALSE( l.find( i, []( value_type&, value_type const&) {} ));
+ EXPECT_FALSE( l.find( i.nKey, []( value_type&, int ) {} ));
+ EXPECT_FALSE( l.find_with( other_item( i.nKey ), other_less(), []( value_type&, other_item const& ) {} ));
+ EXPECT_TRUE( l.find( i ) == l.end() );
+ EXPECT_TRUE( l.find( i.nKey ) == l.end() );
+ EXPECT_TRUE( l.find_with( other_item( i.nKey ), other_less() ) == l.end() );
+ }
+
+ ASSERT_TRUE( l.empty() );
+ EXPECT_CONTAINER_SIZE( l, 0 );
+
+ // clear test
+ for ( auto& i : arr )
+ EXPECT_TRUE( l.insert( i ));
+
+ ASSERT_FALSE( l.empty() );
+ EXPECT_CONTAINER_SIZE( l, nSize );
+
+ l.clear();
+
+ ASSERT_TRUE( l.empty() );
+ EXPECT_CONTAINER_SIZE( l, 0 );
+
+ // empty list iterator test
+ {
+ List const& cl = l;
+ EXPECT_TRUE( l.begin() == l.end());
+ EXPECT_TRUE( l.cbegin() == l.cend());
+ EXPECT_TRUE( cl.begin() == cl.end());
+ EXPECT_TRUE( l.begin() == l.cend());
+ EXPECT_TRUE( cl.begin() == l.end());
+ }
+ }
+
+ template <typename List>
+ void test_ordered_iterator( List& l )
+ {
+ // Precondition: list is empty
+ // Postcondition: list is empty
+
+ static const size_t nSize = 20;
+ typedef typename List::value_type value_type;
+ value_type arr[nSize];
+
+ for ( size_t i = 0; i < nSize; ++i ) {
+ arr[i].nKey = static_cast<int>(i);
+ arr[i].nVal = arr[i].nKey;
+ }
+ shuffle( arr, arr + nSize );
+
+ ASSERT_TRUE( l.empty() );
+ ASSERT_CONTAINER_SIZE( l, 0 );
+
+ for ( auto& i : arr )
+ EXPECT_TRUE( l.insert( i ));
+
+ int key = 0;
+ for ( auto& it : l ) {
+ EXPECT_EQ( key, it.nKey );
+ EXPECT_EQ( it.nVal, it.nKey );
+ it.nVal = it.nKey * 10;
+ ++key;
+ }
+ EXPECT_EQ( static_cast<size_t>(key), nSize );
+
+ key = 0;
+ for ( auto it = l.cbegin(); it != l.cend(); ++it ) {
+ EXPECT_EQ( key, it->nKey );
+ EXPECT_EQ( key, (*it).nKey );
+ EXPECT_EQ( it->nKey * 10, it->nVal );
+ ++key;
+ }
+ EXPECT_EQ( static_cast<size_t>(key), nSize );
+
+ key = 0;
+ for ( auto it = l.begin(); it != l.end(); ++it ) {
+ EXPECT_EQ( key, it->nKey );
+ EXPECT_EQ( key, (*it).nKey );
+ EXPECT_EQ( it->nKey * 10, it->nVal );
+ it->nVal = it->nKey * 2;
+ ++key;
+ }
+ EXPECT_EQ( static_cast<size_t>(key), nSize );
+
+ List const& cl = l;
+ key = 0;
+ for ( auto it = cl.begin(); it != cl.end(); ++it ) {
+ EXPECT_EQ( key, it->nKey );
+ EXPECT_EQ( key, (*it).nKey );
+ EXPECT_EQ( it->nKey * 2, it->nVal );
+ ++key;
+ }
+ EXPECT_EQ( static_cast<size_t>(key), nSize );
+
+ l.clear();
+ ASSERT_TRUE( l.empty() );
+ EXPECT_CONTAINER_SIZE( l, 0 );
+ }
+ };
+
+} // namespace cds_test
+
+#endif // CDSUNIT_LIST_TEST_ITERABLE_LIST_H
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSUNIT_LIST_TEST_ITERABLE_LIST_HP_H
+#define CDSUNIT_LIST_TEST_ITERABLE_LIST_HP_H
+
+#include "test_iterable_list.h"
+
+namespace cds_test {
+
+ class iterable_list_hp : public iterable_list_test
+ {
+ protected:
+ template <typename List>
+ void test_hp( List& l )
+ {
+ // Precondition: list is empty
+ // Postcondition: list is empty
+
+ static const size_t nSize = 20;
+ typedef typename List::value_type value_type;
+ typedef typename List::guarded_ptr guarded_ptr;
+ value_type arr[nSize];
+
+ for ( size_t i = 0; i < nSize; ++i ) {
+ arr[i].nKey = static_cast<int>(i);
+ arr[i].nVal = arr[i].nKey * 10;
+ }
+ shuffle( arr, arr + nSize );
+
+ ASSERT_TRUE( l.empty() );
+ ASSERT_CONTAINER_SIZE( l, 0 );
+
+ guarded_ptr gp;
+ size_t nCount = 0;
+
+ // get() test
+ for ( auto& i : arr ) {
+ gp = l.get( i.nKey );
+ EXPECT_TRUE( !gp );
+ gp = l.get_with( other_item( i.nKey ), other_less());
+ EXPECT_TRUE( !gp );
+
+ EXPECT_TRUE( l.insert( i ));
+
+ gp = l.get( i );
+ ASSERT_FALSE( !gp );
+ EXPECT_EQ( gp->nKey, i.nKey );
+ EXPECT_EQ( gp->nVal, gp->nKey * 10 );
+ gp->nVal = gp->nKey * 5;
+
+ gp = l.get_with( other_item( i.nKey ), other_less());
+ ASSERT_FALSE( !gp );
+ EXPECT_EQ( gp->nKey, i.nKey );
+ EXPECT_EQ( gp->nVal, gp->nKey * 5 );
+ gp->nVal = gp->nKey * 10;
+
+ ++nCount;
+ ASSERT_FALSE( l.empty() );
+ ASSERT_CONTAINER_SIZE( l, nCount );
+ }
+
+ ASSERT_FALSE( l.empty() );
+ ASSERT_CONTAINER_SIZE( l, nSize );
+
+ // extract() test
+ for ( auto const& i : arr ) {
+ ASSERT_FALSE( l.empty() );
+ ASSERT_CONTAINER_SIZE( l, nCount );
+ --nCount;
+
+ gp = l.get( i );
+ ASSERT_FALSE( !gp );
+ EXPECT_EQ( gp->nKey, i.nKey );
+
+ switch ( i.nKey & 3 ) {
+ case 0:
+ gp = l.extract( i );
+ break;
+ case 1:
+ gp = l.extract_with( other_item( i.nKey ), other_less());
+ break;
+ default:
+ gp = l.extract( i.nKey );
+ break;
+ }
+ ASSERT_FALSE( !gp );
+ EXPECT_EQ( gp->nKey, i.nKey );
+ EXPECT_EQ( gp->nVal, gp->nKey * 10 );
+
+ gp = l.get( i.nKey );
+ EXPECT_FALSE( gp );
+
+ gp = l.extract( i );
+ EXPECT_FALSE( gp );
+ gp = l.extract_with( other_item( i.nKey ), other_less());
+ EXPECT_FALSE( gp );
+ gp = l.extract( i.nKey );
+ EXPECT_FALSE( gp );
+ }
+
+ ASSERT_TRUE( l.empty() );
+ ASSERT_CONTAINER_SIZE( l, 0 );
+ }
+ };
+
+} // namespace cds_list
+
+#endif // CDSUNIT_LIST_TEST_ITERABLE_LIST_HP_H
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSUNIT_LIST_TEST_KV_ITERABLE_LIST_H
+#define CDSUNIT_LIST_TEST_KV_ITERABLE_LIST_H
+
+#include <cds_test/check_size.h>
+#include <cds_test/fixture.h>
+
+namespace cds_test {
+
+ class kv_iterable_list : public fixture
+ {
+ public:
+ struct key_type {
+ int nKey;
+
+ key_type() = delete;
+ explicit key_type( int n )
+ : nKey( n )
+ {}
+
+ key_type( key_type const& s )
+ : nKey( s.nKey )
+ {}
+
+ key_type( key_type&& s )
+ : nKey( s.nKey )
+ {
+ s.nKey = 0;
+ }
+
+ int key() const
+ {
+ return nKey;
+ }
+ };
+
+ struct value_type {
+ int val;
+
+ value_type()
+ : val( 0 )
+ {}
+
+ explicit value_type( int n )
+ : val( n )
+ {}
+ };
+
+ struct lt
+ {
+ bool operator()( key_type const& lhs, key_type const& rhs ) const
+ {
+ return lhs.key() < rhs.key();
+ }
+
+ bool operator()( key_type const& lhs, int rhs ) const
+ {
+ return lhs.key() < rhs;
+ }
+
+ bool operator()( int lhs, key_type const& rhs ) const
+ {
+ return lhs < rhs.key();
+ }
+
+ template <typename T>
+ bool operator ()( T const& v1, T const& v2 ) const
+ {
+ return v1.key() < v2.key();
+ }
+ };
+
+ struct cmp
+ {
+ int operator()( key_type const& lhs, key_type const& rhs ) const
+ {
+ return lhs.key() - rhs.key();
+ }
+
+ int operator()( key_type const& lhs, int rhs ) const
+ {
+ return lhs.key() - rhs;
+ }
+
+ int operator()( int lhs, key_type const& rhs ) const
+ {
+ return lhs - rhs.key();
+ }
+
+ template <typename T>
+ int operator ()( T const& lhs, T const& rhs ) const
+ {
+ return lhs.key() - rhs.key();
+ }
+ };
+
+ struct other_key
+ {
+ int nKey;
+
+ other_key()
+ {}
+
+ other_key( int n )
+ : nKey( n )
+ {}
+
+ int key() const
+ {
+ return nKey;
+ }
+ };
+
+ struct other_less
+ {
+ template <typename T1, typename T2>
+ bool operator()( T1 const& t1, T2 const& t2 ) const
+ {
+ return t1.key() < t2.key();
+ }
+ };
+
+ protected:
+ template <typename List>
+ void test_common( List& l )
+ {
+ // Precondition: list is empty
+ // Postcondition: list is empty
+
+ static const size_t nSize = 20;
+ typedef typename List::key_type list_key_type;
+ typedef typename List::mapped_type list_mapped_type;
+ typedef typename List::value_type list_value_type;
+ struct key_val {
+ int key;
+ int val;
+ };
+ key_val arr[nSize];
+
+ for ( size_t i = 0; i < nSize; ++i ) {
+ arr[i].key = static_cast<int>(i) + 1;
+ arr[i].val = arr[i].key * 10;
+ }
+ shuffle( arr, arr + nSize );
+
+ ASSERT_TRUE( l.empty() );
+ ASSERT_CONTAINER_SIZE( l, 0 );
+
+ // insert/find
+ for ( auto const& i : arr ) {
+ EXPECT_FALSE( l.contains( i.key ));
+ EXPECT_FALSE( l.contains( key_type( i.key )));
+ EXPECT_FALSE( l.contains( other_key( i.key ), other_less()));
+ EXPECT_FALSE( l.find( i.key, []( list_value_type& ) {} ));
+ EXPECT_FALSE( l.find( key_type( i.key ), []( list_value_type& ) {} ));
+ EXPECT_FALSE( l.find_with( other_key( i.key ), other_less(), []( list_value_type& ) {} ));
+ EXPECT_TRUE( l.find( i.key ) == l.end() );
+ EXPECT_TRUE( l.find_with( other_key( i.key ), other_less()) == l.end());
+
+ switch ( i.key % 6 ) {
+ case 0:
+ EXPECT_TRUE( l.insert( i.key ));
+ EXPECT_TRUE( l.find( i.key, []( list_value_type& n ) {
+ EXPECT_EQ( n.second.val, 0 );
+ } ));
+ EXPECT_FALSE( l.insert( i.key ));
+ break;
+
+ case 1:
+ EXPECT_TRUE( l.insert( i.key, i.val ));
+ EXPECT_TRUE( l.find( key_type(i.key), []( list_value_type& n ) {
+ EXPECT_EQ( n.second.val, n.first.nKey * 10 );
+ } ));
+ EXPECT_FALSE( l.insert( key_type( i.key )));
+ break;
+
+ case 2:
+ EXPECT_TRUE( l.insert_with( i.key, []( list_value_type& n ) {
+ n.second.val = n.first.nKey * 2;
+ }));
+ EXPECT_TRUE( l.find( i.key, []( list_value_type& n ) {
+ EXPECT_EQ( n.second.val, n.first.key() * 2 );
+ } ));
+ EXPECT_FALSE( l.insert_with( i.key, []( list_value_type& n ) {
+ n.second.val = n.first.nKey * 3;
+ } ));
+ EXPECT_TRUE( l.find( i.key, []( list_value_type& n ) {
+ EXPECT_EQ( n.second.val, n.first.key() * 2 );
+ } ));
+ break;
+
+ case 3:
+ {
+ key_type k( i.key );
+ EXPECT_TRUE( l.emplace( std::move(k), i.key * 100 ));
+ EXPECT_EQ( k.key(), 0 );
+ EXPECT_TRUE( l.find( i.key, []( list_value_type& n ) {
+ EXPECT_EQ( n.second.val, n.first.nKey * 100 );
+ } ));
+ k.nKey = i.key;
+ EXPECT_FALSE( l.emplace( std::move( k ), i.key ));
+ //EXPECT_EQ( k.key(), i.key ); // ???
+ EXPECT_TRUE( l.find( i.key, []( list_value_type& n ) {
+ EXPECT_EQ( n.second.val, n.first.nKey * 100 );
+ } ));
+ }
+ break;
+
+ case 4:
+ {
+ auto pair = l.update( i.key, []( list_value_type& n, list_value_type* old ) {
+ ASSERT_TRUE( false );
+ }, false );
+ EXPECT_FALSE( pair.first );
+ EXPECT_FALSE( pair.second );
+
+ pair = l.update( list_key_type(i.key), []( list_value_type& n, list_value_type* old ) {
+ EXPECT_TRUE( old == nullptr );
+ n.second.val = n.first.nKey * 3;
+ });
+ EXPECT_TRUE( pair.first );
+ EXPECT_TRUE( pair.second );
+
+ EXPECT_TRUE( l.find( i.key, []( list_value_type& n ) {
+ EXPECT_EQ( n.second.val, n.first.key() * 3 );
+ } ));
+
+ pair = l.update( list_key_type(i.key), []( list_value_type& n, list_value_type* old ) {
+ EXPECT_FALSE( old == nullptr );
+ n.second.val = n.first.nKey * 5;
+ });
+ EXPECT_TRUE( pair.first );
+ EXPECT_FALSE( pair.second );
+
+ EXPECT_TRUE( l.find( i.key, []( list_value_type& n ) {
+ EXPECT_EQ( n.second.val, n.first.key() * 5 );
+ } ));
+ }
+ break;
+ case 5:
+ {
+ auto ret = l.upsert( i.key, i.val, false );
+ EXPECT_FALSE( ret.first );
+ EXPECT_FALSE( ret.second );
+ EXPECT_FALSE( l.contains( i.key ));
+
+ ret = l.upsert( i.key, i.val );
+ EXPECT_TRUE( ret.first );
+ EXPECT_TRUE( ret.second );
+ EXPECT_TRUE( l.contains( i.key ) );
+
+ ret = l.upsert( i.key, i.key * 12 );
+ EXPECT_TRUE( ret.first );
+ EXPECT_FALSE( ret.second );
+ EXPECT_TRUE( l.find( i.key, []( list_value_type& n ) {
+ EXPECT_EQ( n.second.val, n.first.key() * 12 );
+ }));
+ }
+ break;
+ }
+
+ EXPECT_TRUE( l.contains( i.key ));
+ EXPECT_TRUE( l.contains( list_key_type(i.key)));
+ EXPECT_TRUE( l.contains( other_key( i.key ), other_less()));
+ EXPECT_TRUE( l.find( i.key, []( list_value_type& n ) {
+ n.second.val = n.first.nKey;
+ } ));
+ EXPECT_TRUE( l.find( i.key, []( list_value_type& n ) {
+ EXPECT_EQ( n.first.nKey, n.second.val );
+ n.second.val = n.first.nKey * 5;
+ } ));
+ EXPECT_TRUE( l.find_with( other_key( i.key ), other_less(), []( list_value_type& n ) {
+ EXPECT_EQ( n.first.nKey * 5, n.second.val );
+ } ));
+
+ auto pair = l.update( i.key, []( list_value_type& n, list_value_type* old ) {
+ ASSERT_FALSE( old == nullptr );
+ EXPECT_EQ( n.first.nKey * 5, old->second.val );
+ n.second.val = n.first.nKey * 3;
+ }, false );
+ EXPECT_TRUE( pair.first );
+ EXPECT_FALSE( pair.second );
+
+ EXPECT_FALSE( l.find( i.key ) == l.end() );
+ EXPECT_EQ( l.find( i.key )->first.nKey, i.key );
+ EXPECT_EQ( l.find( i.key )->second.val, i.key * 3 );
+ EXPECT_FALSE( l.find_with( other_key( i.key ), other_less() ) == l.end() );
+ EXPECT_EQ( l.find_with( other_key( i.key ), other_less())->first.nKey, i.key );
+ EXPECT_EQ( l.find_with( other_key( i.key ), other_less())->second.val, i.key * 3 );
+
+ EXPECT_FALSE( l.empty() );
+ }
+
+ ASSERT_FALSE( l.empty() );
+ EXPECT_CONTAINER_SIZE( l, nSize );
+
+ // erase
+ for ( auto const&i : arr ) {
+ switch ( i.key % 4 ) {
+ case 0:
+ EXPECT_TRUE( l.erase( i.key ));
+ break;
+ case 1:
+ EXPECT_TRUE( l.erase_with( other_key( i.key ), other_less()));
+ break;
+ case 2:
+ EXPECT_TRUE( l.erase( i.key, [ &i ]( list_value_type const& n ) {
+ EXPECT_EQ( n.first.nKey, i.key );
+ EXPECT_EQ( n.first.nKey * 3, n.second.val );
+ }));
+ break;
+ case 3:
+ EXPECT_TRUE( l.erase_with( other_key( i.key ), other_less(), [ &i ]( list_value_type const& n) {
+ EXPECT_EQ( n.first.nKey, i.key );
+ EXPECT_EQ( n.first.nKey * 3, n.second.val );
+ } ));
+ }
+
+ EXPECT_FALSE( l.contains( i.key ));
+ EXPECT_FALSE( l.contains( key_type( i.key )));
+ EXPECT_FALSE( l.contains( other_key( i.key ), other_less()));
+ EXPECT_FALSE( l.find( key_type( i.key ), []( list_value_type& ) {} ));
+ EXPECT_FALSE( l.find( i.key, []( list_value_type& ) {} ));
+ EXPECT_FALSE( l.find_with( other_key( i.key ), other_less(), []( list_value_type& ) {} ));
+ }
+
+ ASSERT_TRUE( l.empty() );
+ EXPECT_CONTAINER_SIZE( l, 0 );
+
+ // clear test
+ for ( auto& i : arr )
+ EXPECT_TRUE( l.insert( i.key, i.val ));
+
+ ASSERT_FALSE( l.empty() );
+ EXPECT_CONTAINER_SIZE( l, nSize );
+
+ l.clear();
+
+ ASSERT_TRUE( l.empty() );
+ EXPECT_CONTAINER_SIZE( l, 0 );
+
+ // empty list iterator test
+ {
+ List const& cl = l;
+ EXPECT_TRUE( l.begin() == l.end());
+ EXPECT_TRUE( l.cbegin() == l.cend());
+ EXPECT_TRUE( cl.begin() == cl.end());
+ EXPECT_TRUE( l.begin() == l.cend());
+ EXPECT_TRUE( cl.begin() == l.end());
+ }
+ }
+
+ template <typename List>
+ void test_ordered_iterator( List& l )
+ {
+ // Precondition: list is empty
+ // Postcondition: list is empty
+
+ static const size_t nSize = 20;
+ struct key_val {
+ int key;
+ int val;
+ };
+ key_val arr[nSize];
+
+ for ( size_t i = 0; i < nSize; ++i ) {
+ arr[i].key = static_cast<int>(i);
+ arr[i].val = arr[i].key;
+ }
+ shuffle( arr, arr + nSize );
+
+ ASSERT_TRUE( l.empty() );
+ ASSERT_CONTAINER_SIZE( l, 0 );
+
+ for ( auto& i : arr )
+ EXPECT_TRUE( l.insert( i.key, i.val ));
+
+ int key = 0;
+ for ( auto& it : l ) {
+ EXPECT_EQ( key, it.first.key() );
+ EXPECT_EQ( it.second.val, it.first.key() );
+ it.second.val = it.first.key() * 10;
+ ++key;
+ }
+ EXPECT_EQ( static_cast<size_t>(key), nSize );
+
+ key = 0;
+ for ( auto it = l.cbegin(); it != l.cend(); ++it ) {
+ EXPECT_EQ( key, it->first.key() );
+ EXPECT_EQ( it->first.key() * 10, it->second.val );
+ ++key;
+ }
+ EXPECT_EQ( static_cast<size_t>(key), nSize );
+
+ key = 0;
+ for ( auto it = l.begin(); it != l.end(); ++it ) {
+ EXPECT_EQ( key, it->first.key() );
+ EXPECT_EQ( it->first.key() * 10, it->second.val );
+ it->second.val = it->first.key() * 2;
+ ++key;
+ }
+ EXPECT_EQ( static_cast<size_t>(key), nSize );
+
+ List const& cl = l;
+ key = 0;
+ for ( auto it = cl.begin(); it != cl.end(); ++it ) {
+ EXPECT_EQ( key, it->first.nKey );
+ EXPECT_EQ( it->first.nKey * 2, it->second.val );
+ ++key;
+ }
+ EXPECT_EQ( static_cast<size_t>(key), nSize );
+
+ l.clear();
+ ASSERT_TRUE( l.empty() );
+ EXPECT_CONTAINER_SIZE( l, 0 );
+ }
+ };
+
+} // namespace cds_test
+
+#endif // CDSUNIT_LIST_TEST_KV_ITERABLE_LIST_H
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSUNIT_LIST_TEST_KV_ITERABLE_LIST_HP_H
+#define CDSUNIT_LIST_TEST_KV_ITERABLE_LIST_HP_H
+
+#include "test_kv_iterable_list.h"
+
+namespace cds_test {
+
+ class kv_iterable_list_hp : public kv_iterable_list
+ {
+ protected:
+ template <typename List>
+ void test_hp( List& l )
+ {
+ // Precondition: list is empty
+ // Postcondition: list is empty
+
+ static const size_t nSize = 20;
+ typedef typename List::key_type list_key_type;
+ typedef typename List::mapped_type list_mapped_type;
+ typedef typename List::value_type list_value_type;
+ typedef typename List::guarded_ptr guarded_ptr;
+
+ struct key_val {
+ int key;
+ int val;
+ };
+ key_val arr[nSize];
+
+ for ( size_t i = 0; i < nSize; ++i ) {
+ arr[i].key = static_cast<int>(i);
+ arr[i].val = arr[i].key * 10;
+ }
+ shuffle( arr, arr + nSize );
+
+ ASSERT_TRUE( l.empty() );
+ ASSERT_CONTAINER_SIZE( l, 0 );
+
+ guarded_ptr gp;
+ size_t nCount = 0;
+
+ // get() test
+ for ( auto& i : arr ) {
+ gp = l.get( i.key );
+ EXPECT_TRUE( !gp );
+ gp = l.get_with( other_key( i.key ), other_less());
+ EXPECT_TRUE( !gp );
+
+ EXPECT_TRUE( l.insert( i.key, i.val ));
+
+ gp = l.get( i.key );
+ ASSERT_FALSE( !gp );
+ EXPECT_EQ( gp->first.nKey, i.key );
+ EXPECT_EQ( gp->second.val, gp->first.nKey * 10 );
+ gp->second.val = gp->first.nKey * 5;
+
+ gp = l.get_with( other_key( i.key ), other_less());
+ ASSERT_FALSE( !gp );
+ EXPECT_EQ( gp->first.nKey, i.key );
+ EXPECT_EQ( gp->second.val, gp->first.nKey * 5 );
+ gp->second.val = gp->first.nKey * 10;
+
+ ++nCount;
+ ASSERT_FALSE( l.empty() );
+ ASSERT_CONTAINER_SIZE( l, nCount );
+ }
+
+ ASSERT_FALSE( l.empty() );
+ ASSERT_CONTAINER_SIZE( l, nSize );
+
+ // extract() test
+ for ( auto const& i : arr ) {
+ ASSERT_FALSE( l.empty() );
+ ASSERT_CONTAINER_SIZE( l, nCount );
+ --nCount;
+
+ gp = l.get( i.key );
+ ASSERT_FALSE( !gp );
+ EXPECT_EQ( gp->first.nKey, i.key );
+
+ switch ( i.key & 1 ) {
+ case 0:
+ gp = l.extract( i.key );
+ break;
+ case 1:
+ gp = l.extract_with( other_key( i.key ), other_less());
+ break;
+ }
+ ASSERT_FALSE( !gp );
+ EXPECT_EQ( gp->first.nKey, i.key );
+ EXPECT_EQ( gp->second.val, gp->first.nKey * 10 );
+
+ gp = l.get( i.key );
+ EXPECT_FALSE( gp );
+
+ gp = l.extract( i.key );
+ EXPECT_FALSE( gp );
+ gp = l.extract_with( other_key( i.key ), other_less());
+ EXPECT_FALSE( gp );
+ }
+
+ ASSERT_TRUE( l.empty() );
+ ASSERT_CONTAINER_SIZE( l, 0 );
+ }
+ };
+
+} // namespace cds_list
+
+#endif // CDSUNIT_LIST_TEST_KV_ITERABLE_LIST_HP_H
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSUNIT_LIST_TEST_KV_LAZY_LIST_RCU_H
this->test_rcu( l );
}
+TYPED_TEST_P( LazyKVList, stat )
+{
+ struct traits: public cc::lazy_list::traits
+ {
+ typedef typename TestFixture::lt less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::lazy_list::stat<> stat;
+ };
+ typedef cc::LazyKVList<typename TestFixture::rcu_type, typename TestFixture::key_type, typename TestFixture::value_type, traits > list_type;
+
+ list_type l;
+ this->test_common( l );
+ this->test_ordered_iterator( l );
+ this->test_rcu( l );
+}
+
+TYPED_TEST_P( LazyKVList, wrapped_stat )
+{
+ struct traits: public cc::lazy_list::traits
+ {
+ typedef typename TestFixture::lt less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::lazy_list::wrapped_stat<> stat;
+ };
+ typedef cc::LazyKVList<typename TestFixture::rcu_type, typename TestFixture::key_type, typename TestFixture::value_type, traits > list_type;
+
+ cds::container::lazy_list::stat<> st;
+ list_type l( st );
+ this->test_common( l );
+ this->test_ordered_iterator( l );
+ this->test_rcu( l );
+}
+
// GCC 5: All test names should be written on single line, otherwise a runtime error will be encountered like as
// "No test named <test_name> can be found in this test case"
REGISTER_TYPED_TEST_CASE_P( LazyKVList,
- less_ordered, compare_ordered, mix_ordered, item_counting, backoff, seq_cst, mutex
+ less_ordered, compare_ordered, mix_ordered, item_counting, backoff, seq_cst, mutex, stat, wrapped_stat
);
#endif // CDSUNIT_LIST_TEST_KV_LAZY_LIST_RCU_H
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSUNIT_LIST_TEST_MICHAEL_KV_LIST_RCU_H
#define CDSUNIT_LIST_TEST_MICHAEL_KV_LIST_RCU_H
this->test_rcu( l );
}
+TYPED_TEST_P( MichaelKVList, stat )
+{
+ struct traits: public cc::michael_list::traits
+ {
+ typedef typename TestFixture::lt less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::michael_list::stat<> stat;
+ };
+ typedef cc::MichaelKVList<typename TestFixture::rcu_type, typename TestFixture::key_type, typename TestFixture::value_type, traits > list_type;
+
+ list_type l;
+ this->test_common( l );
+ this->test_ordered_iterator( l );
+ this->test_rcu( l );
+}
+
+TYPED_TEST_P( MichaelKVList, wrapped_stat )
+{
+ struct traits: public cc::michael_list::traits
+ {
+ typedef typename TestFixture::lt less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::michael_list::wrapped_stat<> stat;
+ };
+ typedef cc::MichaelKVList<typename TestFixture::rcu_type, typename TestFixture::key_type, typename TestFixture::value_type, traits > list_type;
+
+ cds::container::michael_list::stat<> st;
+ list_type l( st );
+ this->test_common( l );
+ this->test_ordered_iterator( l );
+ this->test_rcu( l );
+}
+
// GCC 5: All test names should be written on single line, otherwise a runtime error will be encountered like as
// "No test named <test_name> can be found in this test case"
REGISTER_TYPED_TEST_CASE_P( MichaelKVList,
- less_ordered, compare_ordered, mix_ordered, item_counting, backoff, seq_cst
+ less_ordered, compare_ordered, mix_ordered, item_counting, backoff, seq_cst, stat, wrapped_stat
);
#endif // CDSUNIT_LIST_TEST_MICHAEL_KV_LIST_RCU_H
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSUNIT_LIST_TEST_LAZY_LIST_RCU_H
this->test_rcu( l );
}
+TYPED_TEST_P( LazyList, stat )
+{
+ struct traits: public cc::lazy_list::traits
+ {
+ typedef typename TestFixture::template lt< typename TestFixture::item> less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::lazy_list::stat<> stat;
+ };
+ typedef cc::LazyList<typename TestFixture::rcu_type, typename TestFixture::item, traits > list_type;
+
+ list_type l;
+ this->test_common( l );
+ this->test_ordered_iterator( l );
+ this->test_rcu( l );
+}
+
+TYPED_TEST_P( LazyList, wrapped_stat )
+{
+ struct traits: public cc::lazy_list::traits
+ {
+ typedef typename TestFixture::template lt< typename TestFixture::item> less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::lazy_list::wrapped_stat<> stat;
+ };
+ typedef cc::LazyList<typename TestFixture::rcu_type, typename TestFixture::item, traits > list_type;
+
+ cds::container::lazy_list::stat<> st;
+ list_type l( st );
+ this->test_common( l );
+ this->test_ordered_iterator( l );
+ this->test_rcu( l );
+}
+
TYPED_TEST_P( LazyList, mutex )
{
struct traits : public cc::lazy_list::traits
// GCC 5: All test names should be written on single line, otherwise a runtime error will be encountered like as
// "No test named <test_name> can be found in this test case"
REGISTER_TYPED_TEST_CASE_P( LazyList,
- less_ordered, compare_ordered, mix_ordered, item_counting, backoff, seq_cst, mutex
+ less_ordered, compare_ordered, mix_ordered, item_counting, backoff, seq_cst, mutex, stat, wrapped_stat
);
#endif // CDSUNIT_LIST_TEST_LAZY_LIST_RCU_H
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSUNIT_LIST_TEST_MICHAEL_LIST_RCU_H
#define CDSUNIT_LIST_TEST_MICHAEL_LIST_RCU_H
this->test_rcu( l );
}
+TYPED_TEST_P( MichaelList, stat )
+{
+ struct traits: public cc::michael_list::traits
+ {
+ typedef typename TestFixture::template lt< typename TestFixture::item> less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::michael_list::stat<> stat;
+ };
+ typedef cc::MichaelList<typename TestFixture::rcu_type, typename TestFixture::item, traits > list_type;
+
+ list_type l;
+ this->test_common( l );
+ this->test_ordered_iterator( l );
+ this->test_rcu( l );
+}
+
+TYPED_TEST_P( MichaelList, wrapped_stat )
+{
+ struct traits: public cc::michael_list::traits
+ {
+ typedef typename TestFixture::template lt< typename TestFixture::item> less;
+ typedef cds::atomicity::item_counter item_counter;
+ typedef cds::container::michael_list::wrapped_stat<> stat;
+ };
+ typedef cc::MichaelList<typename TestFixture::rcu_type, typename TestFixture::item, traits > list_type;
+
+ cds::container::michael_list::stat<> st;
+ list_type l( st );
+ this->test_common( l );
+ this->test_ordered_iterator( l );
+ this->test_rcu( l );
+}
+
// GCC 5: All test names should be written on single line, otherwise a runtime error will be encountered like as
// "No test named <test_name> can be found in this test case"
REGISTER_TYPED_TEST_CASE_P( MichaelList,
- less_ordered, compare_ordered, mix_ordered, item_counting, backoff, seq_cst
+ less_ordered, compare_ordered, mix_ordered, item_counting, backoff, seq_cst, stat, wrapped_stat
);
#endif // CDSUNIT_LIST_TEST_MICHAEL_LIST_RCU_H
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <gtest/gtest.h>
#include <cds/algo/int_algo.h>
-#include <cds/os/timer.h>
+//#include <cds/details/bit_reverse_counter.h>
namespace {
class bitop : public ::testing::Test
}
}
+ /*
+ TEST_F( bitop, bit_reverse_counter )
+ {
+ cds::bitop::bit_reverse_counter<> c;
+
+ while ( c.value() < 8 ) {
+ size_t res = c.inc();
+ std::cout << "inc result: " << res
+ << " value: " << c.value()
+ << " reversed: " << c.reversed_value()
+ << " high_bit: " << c.high_bit() << "\n";
+ }
+
+ while ( c.value() > 0 ) {
+ size_t res = c.dec();
+ std::cout << "dec result: " << res
+ << " value: " << c.value()
+ << " reversed: " << c.reversed_value()
+ << " high_bit: " << c.high_bit() << "\n";
+ }
+ }
+ */
+
} // namespace
feldman_hashset_rcu_gpt.cpp
feldman_hashset_rcu_shb.cpp
feldman_hashset_rcu_sht.cpp
+ michael_iterable_hp.cpp
+ michael_iterable_dhp.cpp
michael_lazy_hp.cpp
michael_lazy_dhp.cpp
michael_lazy_nogc.cpp
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "test_michael_iterable_hp.h"
+
+#include <cds/container/iterable_list_dhp.h>
+#include <cds/container/michael_set.h>
+
+namespace {
+ namespace cc = cds::container;
+ typedef cds::gc::DHP gc_type;
+
+ class MichaelIterableSet_DHP : public cds_test::michael_iterable_set_hp
+ {
+ protected:
+ typedef cds_test::michael_iterable_set_hp base_class;
+
+ void SetUp()
+ {
+ typedef cc::IterableList< gc_type, int_item > list_type;
+ typedef cc::MichaelHashSet< gc_type, list_type > set_type;
+
+ cds::gc::dhp::GarbageCollector::Construct( 16, set_type::c_nHazardPtrCount );
+ cds::threading::Manager::attachThread();
+ }
+
+ void TearDown()
+ {
+ cds::threading::Manager::detachThread();
+ cds::gc::dhp::GarbageCollector::Destruct();
+ }
+ };
+
+ TEST_F( MichaelIterableSet_DHP, compare )
+ {
+ typedef cc::IterableList< gc_type, int_item,
+ typename cc::iterable_list::make_traits<
+ cds::opt::compare< cmp >
+ >::type
+ > list_type;
+
+ typedef cc::MichaelHashSet< gc_type, list_type,
+ typename cc::michael_set::make_traits<
+ cds::opt::hash< hash_int >
+ >::type
+ > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
+ TEST_F( MichaelIterableSet_DHP, less )
+ {
+ typedef cc::IterableList< gc_type, int_item,
+ typename cc::iterable_list::make_traits<
+ cds::opt::less< base_class::less >
+ >::type
+ > list_type;
+
+ typedef cc::MichaelHashSet< gc_type, list_type,
+ typename cc::michael_set::make_traits<
+ cds::opt::hash< hash_int >
+ >::type
+ > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
+ TEST_F( MichaelIterableSet_DHP, cmpmix )
+ {
+ struct list_traits : public cc::iterable_list::traits
+ {
+ typedef base_class::less less;
+ typedef cmp compare;
+ };
+ typedef cc::IterableList< gc_type, int_item, list_traits > list_type;
+
+ typedef cc::MichaelHashSet< gc_type, list_type,
+ typename cc::michael_set::make_traits<
+ cds::opt::hash< hash_int >
+ >::type
+ > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
+ TEST_F( MichaelIterableSet_DHP, item_counting )
+ {
+ struct list_traits : public cc::iterable_list::traits
+ {
+ typedef cmp compare;
+ };
+ typedef cc::IterableList< gc_type, int_item, list_traits > list_type;
+
+ struct set_traits: public cc::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef cc::MichaelHashSet< gc_type, list_type, set_traits > set_type;
+
+ set_type s( kSize, 3 );
+ test( s );
+ }
+
+ TEST_F( MichaelIterableSet_DHP, backoff )
+ {
+ struct list_traits : public cc::iterable_list::traits
+ {
+ typedef cmp compare;
+ typedef cds::backoff::exponential<cds::backoff::pause, cds::backoff::yield> back_off;
+ };
+ typedef cc::IterableList< gc_type, int_item, list_traits > list_type;
+
+ struct set_traits : public cc::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef cds::atomicity::item_counter item_counter;
+ };
+ typedef cc::MichaelHashSet< gc_type, list_type, set_traits > set_type;
+
+ set_type s( kSize, 4 );
+ test( s );
+ }
+
+ TEST_F( MichaelIterableSet_DHP, seq_cst )
+ {
+ struct list_traits : public cc::iterable_list::traits
+ {
+ typedef base_class::less less;
+ typedef cds::backoff::pause back_off;
+ typedef cds::opt::v::sequential_consistent memory_model;
+ };
+ typedef cc::IterableList< gc_type, int_item, list_traits > list_type;
+
+ struct set_traits : public cc::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef cds::atomicity::item_counter item_counter;
+ };
+ typedef cc::MichaelHashSet< gc_type, list_type, set_traits > set_type;
+
+ set_type s( kSize, 4 );
+ test( s );
+ }
+
+ TEST_F( MichaelIterableSet_DHP, stat )
+ {
+ struct list_traits: public cc::iterable_list::traits
+ {
+ typedef base_class::less less;
+ typedef cds::backoff::pause back_off;
+ typedef cc::iterable_list::stat<> stat;
+ };
+ typedef cc::IterableList< gc_type, int_item, list_traits > list_type;
+
+ struct set_traits: public cc::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef cds::atomicity::item_counter item_counter;
+ };
+ typedef cc::MichaelHashSet< gc_type, list_type, set_traits > set_type;
+
+ set_type s( kSize, 4 );
+ test( s );
+ }
+
+ TEST_F( MichaelIterableSet_DHP, wrapped_stat )
+ {
+ struct list_traits: public cc::iterable_list::traits
+ {
+ typedef base_class::less less;
+ typedef cds::backoff::pause back_off;
+ typedef cc::iterable_list::wrapped_stat<> stat;
+ };
+ typedef cc::IterableList< gc_type, int_item, list_traits > list_type;
+
+ struct set_traits: public cc::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef cds::atomicity::item_counter item_counter;
+ };
+ typedef cc::MichaelHashSet< gc_type, list_type, set_traits > set_type;
+
+ set_type s( kSize, 4 );
+ test( s );
+ }
+
+} // namespace
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "test_michael_iterable_hp.h"
+
+#include <cds/container/iterable_list_hp.h>
+#include <cds/container/michael_set.h>
+
+namespace {
+ namespace cc = cds::container;
+ typedef cds::gc::HP gc_type;
+
+ class MichaelIterableSet_HP : public cds_test::michael_iterable_set_hp
+ {
+ protected:
+ typedef cds_test::michael_iterable_set_hp base_class;
+
+ void SetUp()
+ {
+ typedef cc::IterableList< gc_type, int_item > list_type;
+ typedef cc::MichaelHashSet< gc_type, list_type > set_type;
+
+ // +3 - for guarded_ptr, iterators
+ cds::gc::hp::GarbageCollector::Construct( set_type::c_nHazardPtrCount + 3, 1, 16 );
+ cds::threading::Manager::attachThread();
+ }
+
+ void TearDown()
+ {
+ cds::threading::Manager::detachThread();
+ cds::gc::hp::GarbageCollector::Destruct( true );
+ }
+ };
+
+ TEST_F( MichaelIterableSet_HP, compare )
+ {
+ typedef cc::IterableList< gc_type, int_item,
+ typename cc::iterable_list::make_traits<
+ cds::opt::compare< cmp >
+ >::type
+ > list_type;
+
+ typedef cc::MichaelHashSet< gc_type, list_type,
+ typename cc::michael_set::make_traits<
+ cds::opt::hash< hash_int >
+ >::type
+ > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
+ TEST_F( MichaelIterableSet_HP, less )
+ {
+ typedef cc::IterableList< gc_type, int_item,
+ typename cc::iterable_list::make_traits<
+ cds::opt::less< base_class::less >
+ >::type
+ > list_type;
+
+ typedef cc::MichaelHashSet< gc_type, list_type,
+ typename cc::michael_set::make_traits<
+ cds::opt::hash< hash_int >
+ >::type
+ > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
+ TEST_F( MichaelIterableSet_HP, cmpmix )
+ {
+ struct list_traits : public cc::iterable_list::traits
+ {
+ typedef base_class::less less;
+ typedef cmp compare;
+ };
+ typedef cc::IterableList< gc_type, int_item, list_traits > list_type;
+
+ typedef cc::MichaelHashSet< gc_type, list_type,
+ typename cc::michael_set::make_traits<
+ cds::opt::hash< hash_int >
+ >::type
+ > set_type;
+
+ set_type s( kSize, 2 );
+ test( s );
+ }
+
+ TEST_F( MichaelIterableSet_HP, item_counting )
+ {
+ struct list_traits : public cc::iterable_list::traits
+ {
+ typedef cmp compare;
+ };
+ typedef cc::IterableList< gc_type, int_item, list_traits > list_type;
+
+ struct set_traits: public cc::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef simple_item_counter item_counter;
+ };
+ typedef cc::MichaelHashSet< gc_type, list_type, set_traits > set_type;
+
+ set_type s( kSize, 3 );
+ test( s );
+ }
+
+ TEST_F( MichaelIterableSet_HP, backoff )
+ {
+ struct list_traits : public cc::iterable_list::traits
+ {
+ typedef cmp compare;
+ typedef cds::backoff::exponential<cds::backoff::pause, cds::backoff::yield> back_off;
+ };
+ typedef cc::IterableList< gc_type, int_item, list_traits > list_type;
+
+ struct set_traits : public cc::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef cds::atomicity::item_counter item_counter;
+ };
+ typedef cc::MichaelHashSet< gc_type, list_type, set_traits > set_type;
+
+ set_type s( kSize, 4 );
+ test( s );
+ }
+
+ TEST_F( MichaelIterableSet_HP, seq_cst )
+ {
+ struct list_traits : public cc::iterable_list::traits
+ {
+ typedef base_class::less less;
+ typedef cds::backoff::pause back_off;
+ typedef cds::opt::v::sequential_consistent memory_model;
+ };
+ typedef cc::IterableList< gc_type, int_item, list_traits > list_type;
+
+ struct set_traits : public cc::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef cds::atomicity::item_counter item_counter;
+ };
+ typedef cc::MichaelHashSet< gc_type, list_type, set_traits > set_type;
+
+ set_type s( kSize, 4 );
+ test( s );
+ }
+
+ TEST_F( MichaelIterableSet_HP, stat )
+ {
+ struct list_traits: public cc::iterable_list::traits
+ {
+ typedef base_class::less less;
+ typedef cds::backoff::pause back_off;
+ typedef cc::iterable_list::stat<> stat;
+ };
+ typedef cc::IterableList< gc_type, int_item, list_traits > list_type;
+
+ struct set_traits: public cc::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef cds::atomicity::item_counter item_counter;
+ };
+ typedef cc::MichaelHashSet< gc_type, list_type, set_traits > set_type;
+
+ set_type s( kSize, 4 );
+ test( s );
+ }
+
+ TEST_F( MichaelIterableSet_HP, wrapped_stat )
+ {
+ struct list_traits: public cc::iterable_list::traits
+ {
+ typedef base_class::less less;
+ typedef cds::backoff::pause back_off;
+ typedef cc::iterable_list::wrapped_stat<> stat;
+ };
+ typedef cc::IterableList< gc_type, int_item, list_traits > list_type;
+
+ struct set_traits: public cc::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef cds::atomicity::item_counter item_counter;
+ };
+ typedef cc::MichaelHashSet< gc_type, list_type, set_traits > set_type;
+
+ set_type s( kSize, 4 );
+ test( s );
+ }
+
+} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_set_hp.h"
test( s );
}
+ TEST_F( MichaelLazySet_DHP, stat )
+ {
+ struct list_traits: public cc::lazy_list::traits
+ {
+ typedef base_class::less less;
+ typedef cds::backoff::pause back_off;
+ typedef cc::lazy_list::stat<> stat;
+ };
+ typedef cc::LazyList< gc_type, int_item, list_traits > list_type;
+
+ struct set_traits: public cc::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef cds::atomicity::item_counter item_counter;
+ };
+ typedef cc::MichaelHashSet< gc_type, list_type, set_traits >set_type;
+
+ set_type s( kSize, 4 );
+ test( s );
+ }
+
+ TEST_F( MichaelLazySet_DHP, wrapped_stat )
+ {
+ struct list_traits: public cc::lazy_list::traits
+ {
+ typedef base_class::less less;
+ typedef cds::backoff::pause back_off;
+ typedef cc::lazy_list::wrapped_stat<> stat;
+ };
+ typedef cc::LazyList< gc_type, int_item, list_traits > list_type;
+
+ struct set_traits: public cc::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef cds::atomicity::item_counter item_counter;
+ };
+ typedef cc::MichaelHashSet< gc_type, list_type, set_traits >set_type;
+
+ set_type s( kSize, 4 );
+ test( s );
+ }
+
} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_set_hp.h"
test( s );
}
+ TEST_F( MichaelLazySet_HP, stat )
+ {
+ struct list_traits: public cc::lazy_list::traits
+ {
+ typedef base_class::less less;
+ typedef cds::backoff::pause back_off;
+ typedef cc::lazy_list::stat<> stat;
+ };
+ typedef cc::LazyList< gc_type, int_item, list_traits > list_type;
+
+ struct set_traits: public cc::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef cds::atomicity::item_counter item_counter;
+ };
+ typedef cc::MichaelHashSet< gc_type, list_type, set_traits >set_type;
+
+ set_type s( kSize, 4 );
+ test( s );
+ }
+
+ TEST_F( MichaelLazySet_HP, wrapped_stat )
+ {
+ struct list_traits: public cc::lazy_list::traits
+ {
+ typedef base_class::less less;
+ typedef cds::backoff::pause back_off;
+ typedef cc::lazy_list::wrapped_stat<> stat;
+ };
+ typedef cc::LazyList< gc_type, int_item, list_traits > list_type;
+
+ struct set_traits: public cc::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef cds::atomicity::item_counter item_counter;
+ };
+ typedef cc::MichaelHashSet< gc_type, list_type, set_traits >set_type;
+
+ set_type s( kSize, 4 );
+ test( s );
+ }
+
} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_set_nogc.h"
test( s );
}
+ TEST_F( MichaelLazySet_NoGC, stat )
+ {
+ struct list_traits: public cc::lazy_list::traits
+ {
+ typedef base_class::less less;
+ typedef cds::backoff::pause back_off;
+ typedef cc::lazy_list::stat<> stat;
+ };
+ typedef cc::LazyList< gc_type, int_item, list_traits > list_type;
+
+ struct set_traits: public cc::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef cds::atomicity::item_counter item_counter;
+ };
+ typedef cc::MichaelHashSet< gc_type, list_type, set_traits >set_type;
+
+ set_type s( kSize, 4 );
+ test( s );
+ }
+
+ TEST_F( MichaelLazySet_NoGC, wrapped_stat )
+ {
+ struct list_traits: public cc::lazy_list::traits
+ {
+ typedef base_class::less less;
+ typedef cds::backoff::pause back_off;
+ typedef cc::lazy_list::wrapped_stat<> stat;
+ };
+ typedef cc::LazyList< gc_type, int_item, list_traits > list_type;
+
+ struct set_traits: public cc::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef cds::atomicity::item_counter item_counter;
+ };
+ typedef cc::MichaelHashSet< gc_type, list_type, set_traits >set_type;
+
+ set_type s( kSize, 4 );
+ test( s );
+ }
+
} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_set_hp.h"
test( s );
}
+ TEST_F( MichaelSet_DHP, stat )
+ {
+ struct list_traits: public cc::michael_list::traits
+ {
+ typedef base_class::less less;
+ typedef cds::backoff::pause back_off;
+ typedef cc::michael_list::stat<> stat;
+ };
+ typedef cc::MichaelList< gc_type, int_item, list_traits > list_type;
+
+ struct set_traits: public cc::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef cds::atomicity::item_counter item_counter;
+ };
+ typedef cc::MichaelHashSet< gc_type, list_type, set_traits >set_type;
+
+ set_type s( kSize, 4 );
+ test( s );
+ }
+
+ TEST_F( MichaelSet_DHP, wrapped_stat )
+ {
+ struct list_traits: public cc::michael_list::traits
+ {
+ typedef base_class::less less;
+ typedef cds::backoff::pause back_off;
+ typedef cc::michael_list::wrapped_stat<> stat;
+ };
+ typedef cc::MichaelList< gc_type, int_item, list_traits > list_type;
+
+ struct set_traits: public cc::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef cds::atomicity::item_counter item_counter;
+ };
+ typedef cc::MichaelHashSet< gc_type, list_type, set_traits >set_type;
+
+ set_type s( kSize, 4 );
+ test( s );
+ }
+
} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_set_hp.h"
test( s );
}
+ TEST_F( MichaelSet_HP, stat )
+ {
+ struct list_traits: public cc::michael_list::traits
+ {
+ typedef base_class::less less;
+ typedef cds::backoff::pause back_off;
+ typedef cc::michael_list::stat<> stat;
+ };
+ typedef cc::MichaelList< gc_type, int_item, list_traits > list_type;
+
+ struct set_traits: public cc::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef cds::atomicity::item_counter item_counter;
+ };
+ typedef cc::MichaelHashSet< gc_type, list_type, set_traits > set_type;
+
+ set_type s( kSize, 4 );
+ test( s );
+ }
+
+ TEST_F( MichaelSet_HP, wrapped_stat )
+ {
+ struct list_traits: public cc::michael_list::traits
+ {
+ typedef base_class::less less;
+ typedef cds::backoff::pause back_off;
+ typedef cc::michael_list::wrapped_stat<> stat;
+ };
+ typedef cc::MichaelList< gc_type, int_item, list_traits > list_type;
+
+ struct set_traits: public cc::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef cds::atomicity::item_counter item_counter;
+ };
+ typedef cc::MichaelHashSet< gc_type, list_type, set_traits > set_type;
+
+ set_type s( kSize, 4 );
+ test( s );
+ }
+
} // namespace
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_set_nogc.h"
test( s );
}
+ TEST_F( MichaelSet_NoGC, stat )
+ {
+ struct list_traits: public cc::michael_list::traits
+ {
+ typedef base_class::less less;
+ typedef cds::backoff::pause back_off;
+ typedef cc::michael_list::stat<> stat;
+ };
+ typedef cc::MichaelList< gc_type, int_item, list_traits > list_type;
+
+ struct set_traits: public cc::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef cds::atomicity::item_counter item_counter;
+ };
+ typedef cc::MichaelHashSet< gc_type, list_type, set_traits >set_type;
+
+ set_type s( kSize, 4 );
+ test( s );
+ }
+
+ TEST_F( MichaelSet_NoGC, wrapped_stat )
+ {
+ struct list_traits: public cc::michael_list::traits
+ {
+ typedef base_class::less less;
+ typedef cds::backoff::pause back_off;
+ typedef cc::michael_list::wrapped_stat<> stat;
+ };
+ typedef cc::MichaelList< gc_type, int_item, list_traits > list_type;
+
+ struct set_traits: public cc::michael_set::traits
+ {
+ typedef hash_int hash;
+ typedef cds::atomicity::item_counter item_counter;
+ };
+ typedef cc::MichaelHashSet< gc_type, list_type, set_traits >set_type;
+
+ set_type s( kSize, 4 );
+ test( s );
+ }
+
} // namespace
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSUNIT_SET_TEST_MICHAEL_ITERABLE_H
+#define CDSUNIT_SET_TEST_MICHAEL_ITERABLE_H
+
+#include "test_set_data.h"
+
+namespace cds_test {
+
+ class michael_iterable_set: public container_set_data
+ {
+ protected:
+ template <typename Set>
+ void test( Set& s )
+ {
+ // Precondition: set is empty
+ // Postcondition: set is empty
+
+ EXPECT_TRUE( s.empty() );
+ EXPECT_CONTAINER_SIZE( s, 0 );
+ size_t const nSetSize = kSize;
+
+ typedef typename Set::value_type value_type;
+
+ std::vector< value_type > data;
+ std::vector< size_t> indices;
+ data.reserve( kSize );
+ indices.reserve( kSize );
+ for ( size_t key = 0; key < kSize; ++key ) {
+ data.push_back( value_type( static_cast<int>(key) ) );
+ indices.push_back( key );
+ }
+ shuffle( indices.begin(), indices.end() );
+
+ // insert/find
+ for ( auto idx : indices ) {
+ auto& i = data[idx];
+
+ EXPECT_FALSE( s.contains( i.nKey ) );
+ EXPECT_FALSE( s.contains( i ) );
+ EXPECT_FALSE( s.contains( other_item( i.key() ), other_less()));
+ EXPECT_FALSE( s.find( i.nKey, []( value_type&, int ) {} ));
+ EXPECT_FALSE( s.find( i, []( value_type&, value_type const& ) {} ));
+ EXPECT_FALSE( s.find_with( other_item( i.key()), other_less(), []( value_type&, other_item const& ) {} ));
+ EXPECT_TRUE( s.find( i ) == s.end());
+ EXPECT_TRUE( s.find( i.nKey ) == s.end() );
+ EXPECT_TRUE( s.find_with( other_item( i.key()), other_less()) == s.end() );
+
+ std::pair<bool, bool> updResult;
+
+ std::string str;
+ updResult = s.update( i.key(), []( value_type&, value_type* old )
+ {
+ EXPECT_TRUE( old == nullptr );
+ }, false );
+ EXPECT_FALSE( updResult.first );
+ EXPECT_FALSE( updResult.second );
+
+ switch ( idx % 11 ) {
+ case 0:
+ EXPECT_TRUE( s.insert( i ));
+ EXPECT_FALSE( s.insert( i ));
+ updResult = s.update( i, []( value_type& val, value_type* old)
+ {
+ ASSERT_FALSE( old == nullptr );
+ EXPECT_EQ( val.key(), old->key() );
+ }, false );
+ EXPECT_TRUE( updResult.first );
+ EXPECT_FALSE( updResult.second );
+ break;
+ case 1:
+ EXPECT_TRUE( s.insert( i.key() ));
+ EXPECT_FALSE( s.insert( i.key() ));
+ updResult = s.update( i.key(), []( value_type& val, value_type* old)
+ {
+ ASSERT_FALSE( old == nullptr );
+ EXPECT_EQ( val.key(), old->key() );
+ }, false );
+ EXPECT_TRUE( updResult.first );
+ EXPECT_FALSE( updResult.second );
+ break;
+ case 2:
+ EXPECT_TRUE( s.insert( i, []( value_type& v ) { ++v.nFindCount; } ));
+ EXPECT_FALSE( s.insert( i, []( value_type& v ) { ++v.nFindCount; } ));
+ EXPECT_TRUE( s.find( i.nKey, []( value_type const& v, int key )
+ {
+ EXPECT_EQ( v.key(), key );
+ EXPECT_EQ( v.nFindCount, 1 );
+ }));
+ break;
+ case 3:
+ EXPECT_TRUE( s.insert( i.key(), []( value_type& v ) { ++v.nFindCount; } ));
+ EXPECT_FALSE( s.insert( i.key(), []( value_type& v ) { ++v.nFindCount; } ));
+ EXPECT_TRUE( s.find( i.nKey, []( value_type const& v, int key )
+ {
+ EXPECT_EQ( v.key(), key );
+ EXPECT_EQ( v.nFindCount, 1 );
+ }));
+ break;
+ case 4:
+ updResult = s.update( i, [&i]( value_type& v, value_type* old )
+ {
+ EXPECT_TRUE( old == nullptr );
+ EXPECT_EQ( v.key(), i.key() );
+ ++v.nUpdateNewCount;
+ });
+ EXPECT_TRUE( updResult.first );
+ EXPECT_TRUE( updResult.second );
+
+ updResult = s.update( i, []( value_type& v, value_type* old )
+ {
+ ASSERT_FALSE( old == nullptr );
+ EXPECT_EQ( v.key(), old->key() );
+ EXPECT_EQ( old->nUpdateNewCount, 1 );
+ v.nUpdateNewCount = old->nUpdateNewCount;
+ ++v.nUpdateCount;
+ }, false );
+ EXPECT_TRUE( updResult.first );
+ EXPECT_FALSE( updResult.second );
+
+ EXPECT_TRUE( s.find( i.nKey, []( value_type const& v, int key )
+ {
+ EXPECT_EQ( v.key(), key );
+ EXPECT_EQ( v.nUpdateNewCount, 1 );
+ EXPECT_EQ( v.nUpdateCount, 1 );
+ }));
+ break;
+ case 5:
+ updResult = s.update( i.key(), [&i]( value_type& v, value_type* old )
+ {
+ EXPECT_TRUE( old == nullptr );
+ EXPECT_EQ( v.key(), i.key() );
+ ++v.nUpdateNewCount;
+ });
+ EXPECT_TRUE( updResult.first );
+ EXPECT_TRUE( updResult.second );
+
+ updResult = s.update( i.key(), []( value_type& v, value_type* old )
+ {
+ EXPECT_FALSE( old == nullptr );
+ EXPECT_EQ( v.key(), old->key() );
+ EXPECT_EQ( old->nUpdateNewCount, 1 );
+ v.nUpdateNewCount = old->nUpdateNewCount;
+ ++v.nUpdateCount;
+ }, false );
+ EXPECT_TRUE( updResult.first );
+ EXPECT_FALSE( updResult.second );
+
+ EXPECT_TRUE( s.find( i, []( value_type const& v, value_type const& arg )
+ {
+ EXPECT_EQ( v.key(), arg.key() );
+ EXPECT_EQ( v.nUpdateNewCount, 1 );
+ EXPECT_EQ( v.nUpdateCount, 1 );
+ }));
+ break;
+ case 6:
+ EXPECT_TRUE( s.emplace( i.key()));
+ EXPECT_TRUE( s.find( i, []( value_type const& v, value_type const& arg )
+ {
+ EXPECT_EQ( v.key(), arg.key() );
+ EXPECT_EQ( v.nVal, arg.nVal );
+ }));
+ break;
+ case 7:
+ str = "Hello!";
+ EXPECT_TRUE( s.emplace( i.key(), std::move( str )));
+ EXPECT_TRUE( str.empty());
+ EXPECT_TRUE( s.find( i, []( value_type const& v, value_type const& arg )
+ {
+ EXPECT_EQ( v.key(), arg.key() );
+ EXPECT_EQ( v.nVal, arg.nVal );
+ EXPECT_EQ( v.strVal, std::string( "Hello!" ));
+ } ));
+ break;
+ case 8:
+ str = "Hello!";
+ EXPECT_TRUE( s.insert( value_type( i.key(), std::move( str ))) );
+ EXPECT_TRUE( str.empty() );
+ EXPECT_TRUE( s.find( i, []( value_type const& v, value_type const& arg )
+ {
+ EXPECT_EQ( v.key(), arg.key() );
+ EXPECT_EQ( v.nVal, arg.nVal );
+ EXPECT_EQ( v.strVal, std::string( "Hello!" ) );
+ } ) );
+ break;
+ case 9:
+ updResult = s.upsert( i.key(), false );
+ EXPECT_FALSE( updResult.first );
+ EXPECT_FALSE( updResult.second );
+
+ updResult = s.upsert( i.key());
+ EXPECT_TRUE( updResult.first );
+ EXPECT_TRUE( updResult.second );
+
+ updResult = s.upsert( i.key(), false );
+ EXPECT_TRUE( updResult.first );
+ EXPECT_FALSE( updResult.second );
+
+ EXPECT_TRUE( s.find( i, []( value_type const& v, value_type const& arg )
+ {
+ EXPECT_EQ( v.key(), arg.key() );
+ } ) );
+ break;
+ case 10:
+ updResult = s.upsert( i, false );
+ EXPECT_FALSE( updResult.first );
+ EXPECT_FALSE( updResult.second );
+
+ updResult = s.upsert( i );
+ EXPECT_TRUE( updResult.first );
+ EXPECT_TRUE( updResult.second );
+
+ updResult = s.upsert( i, false );
+ EXPECT_TRUE( updResult.first );
+ EXPECT_FALSE( updResult.second );
+
+ EXPECT_TRUE( s.find( i, []( value_type const& v, value_type const& arg )
+ {
+ EXPECT_EQ( v.key(), arg.key() );
+ } ) );
+ break;
+ default:
+ // forgot anything?..
+ EXPECT_TRUE( false );
+ }
+
+ EXPECT_TRUE( s.contains( i.nKey ) );
+ EXPECT_TRUE( s.contains( i ) );
+ EXPECT_TRUE( s.contains( other_item( i.key() ), other_less() ) );
+ EXPECT_TRUE( s.find( i.nKey, []( value_type&, int ) {} ) );
+ EXPECT_TRUE( s.find( i, []( value_type&, value_type const& ) {} ) );
+ EXPECT_TRUE( s.find_with( other_item( i.key() ), other_less(), []( value_type&, other_item const& ) {} ) );
+ EXPECT_FALSE( s.find( i.nKey ) == s.end());
+ EXPECT_FALSE( s.find( i ) == s.end() );
+ EXPECT_FALSE( s.find_with( other_item( i.key() ), other_less()) == s.end() );
+ }
+
+ EXPECT_FALSE( s.empty() );
+ EXPECT_CONTAINER_SIZE( s, nSetSize );
+
+ // erase
+ shuffle( indices.begin(), indices.end() );
+ for ( auto idx : indices ) {
+ auto& i = data[idx];
+
+ EXPECT_TRUE( s.contains( i.nKey ) );
+ EXPECT_TRUE( s.contains( i ) );
+ EXPECT_TRUE( s.contains( other_item( i.key() ), other_less() ) );
+ EXPECT_TRUE( s.find( i.nKey, []( value_type& v, int )
+ {
+ v.nFindCount = 1;
+ }));
+ EXPECT_TRUE( s.find( i, []( value_type& v, value_type const& )
+ {
+ EXPECT_EQ( ++v.nFindCount, 2 );
+ }));
+ EXPECT_TRUE( s.find_with( other_item( i.key() ), other_less(), []( value_type& v, other_item const& )
+ {
+ EXPECT_EQ( ++v.nFindCount, 3 );
+ }));
+
+ int nKey = i.key() - 1;
+ switch ( idx % 6 ) {
+ case 0:
+ EXPECT_TRUE( s.erase( i.key()));
+ EXPECT_FALSE( s.erase( i.key()));
+ break;
+ case 1:
+ EXPECT_TRUE( s.erase( i ));
+ EXPECT_FALSE( s.erase( i ));
+ break;
+ case 2:
+ EXPECT_TRUE( s.erase_with( other_item( i.key()), other_less()));
+ EXPECT_FALSE( s.erase_with( other_item( i.key() ), other_less() ) );
+ break;
+ case 3:
+ EXPECT_TRUE( s.erase( i.key(), [&nKey]( value_type const& v )
+ {
+ nKey = v.key();
+ } ));
+ EXPECT_EQ( i.key(), nKey );
+
+ nKey = i.key() - 1;
+ EXPECT_FALSE( s.erase( i.key(), [&nKey]( value_type const& v )
+ {
+ nKey = v.key();
+ } ));
+ EXPECT_EQ( i.key(), nKey + 1 );
+ break;
+ case 4:
+ EXPECT_TRUE( s.erase( i, [&nKey]( value_type const& v )
+ {
+ nKey = v.key();
+ } ));
+ EXPECT_EQ( i.key(), nKey );
+
+ nKey = i.key() - 1;
+ EXPECT_FALSE( s.erase( i, [&nKey]( value_type const& v )
+ {
+ nKey = v.key();
+ } ));
+ EXPECT_EQ( i.key(), nKey + 1 );
+ break;
+ case 5:
+ EXPECT_TRUE( s.erase_with( other_item( i.key()), other_less(), [&nKey]( value_type const& v )
+ {
+ nKey = v.key();
+ } ));
+ EXPECT_EQ( i.key(), nKey );
+
+ nKey = i.key() - 1;
+ EXPECT_FALSE( s.erase_with( other_item( i.key()), other_less(), [&nKey]( value_type const& v )
+ {
+ nKey = v.key();
+ } ));
+ EXPECT_EQ( i.key(), nKey + 1 );
+ break;
+ }
+
+ EXPECT_FALSE( s.contains( i.nKey ) );
+ EXPECT_FALSE( s.contains( i ) );
+ EXPECT_FALSE( s.contains( other_item( i.key() ), other_less()));
+ EXPECT_FALSE( s.find( i.nKey, []( value_type&, int ) {} ));
+ EXPECT_FALSE( s.find( i, []( value_type&, value_type const& ) {} ));
+ EXPECT_FALSE( s.find_with( other_item( i.key()), other_less(), []( value_type&, other_item const& ) {} ));
+ }
+ EXPECT_TRUE( s.empty() );
+ EXPECT_CONTAINER_SIZE( s, 0 );
+
+
+ // clear
+ for ( auto& i : data ) {
+ EXPECT_TRUE( s.insert( i ) );
+ }
+
+ EXPECT_FALSE( s.empty() );
+ EXPECT_CONTAINER_SIZE( s, nSetSize );
+
+ s.clear();
+
+ EXPECT_TRUE( s.empty() );
+ EXPECT_CONTAINER_SIZE( s, 0 );
+
+ EXPECT_TRUE( s.begin() == s.end() );
+ EXPECT_TRUE( s.cbegin() == s.cend() );
+ }
+ };
+
+} // namespace cds_test
+
+#endif // CDSUNIT_SET_TEST_MICHAEL_ITERABLE_H
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSUNIT_SET_TEST_SET_HP_H
+#define CDSUNIT_SET_TEST_SET_HP_H
+
+#include "test_michael_iterable.h"
+
+namespace cds_test {
+
+ class michael_iterable_set_hp: public michael_iterable_set
+ {
+ typedef michael_iterable_set base_class;
+
+ protected:
+ template <typename Set>
+ void test( Set& s )
+ {
+ // Precondition: set is empty
+ // Postcondition: set is empty
+
+ EXPECT_TRUE( s.empty() );
+ EXPECT_CONTAINER_SIZE( s, 0 );
+
+ base_class::test( s );
+
+ typedef typename Set::value_type value_type;
+
+ size_t const nSetSize = kSize;
+ std::vector< value_type > data;
+ std::vector< size_t> indices;
+ data.reserve( kSize );
+ indices.reserve( kSize );
+ for ( size_t key = 0; key < kSize; ++key ) {
+ data.push_back( value_type( static_cast<int>(key) ) );
+ indices.push_back( key );
+ }
+ shuffle( indices.begin(), indices.end() );
+
+ for ( auto& i : data ) {
+ EXPECT_TRUE( s.insert( i ) );
+ }
+ EXPECT_FALSE( s.empty() );
+ EXPECT_CONTAINER_SIZE( s, nSetSize );
+
+ // iterator test
+ for ( auto it = s.begin(); it != s.end(); ++it ) {
+ it->nFindCount = it->key() * 3;
+ }
+
+ for ( auto it = s.cbegin(); it != s.cend(); ++it ) {
+ EXPECT_EQ( it->nFindCount, it->key() * 3 );
+ }
+
+ typedef typename Set::guarded_ptr guarded_ptr;
+ guarded_ptr gp;
+
+ // get()
+ for ( auto idx : indices ) {
+ auto& i = data[idx];
+
+ EXPECT_TRUE( !gp );
+ switch ( idx % 3 ) {
+ case 0:
+ gp = s.get( i.key() );
+ ASSERT_FALSE( !gp );
+ break;
+ case 1:
+ gp = s.get( i );
+ ASSERT_FALSE( !gp );
+ break;
+ case 2:
+ gp = s.get_with( other_item( i.key() ), other_less() );
+ ASSERT_FALSE( !gp );
+ }
+ EXPECT_EQ( gp->key(), i.key() );
+ EXPECT_EQ( gp->nFindCount, i.key() * 3 );
+ gp->nFindCount *= 2;
+
+ gp.release();
+ }
+
+ // extract()
+ for ( auto idx : indices ) {
+ auto& i = data[idx];
+
+ EXPECT_TRUE( !gp );
+ switch ( idx % 3 ) {
+ case 0:
+ gp = s.extract( i.key() );
+ ASSERT_FALSE( !gp );
+ break;
+ case 1:
+ gp = s.extract( i );
+ ASSERT_FALSE( !gp );
+ break;
+ case 2:
+ gp = s.extract_with( other_item( i.key() ), other_less() );
+ ASSERT_FALSE( !gp );
+ break;
+ }
+ EXPECT_EQ( gp->key(), i.key() );
+ EXPECT_EQ( gp->nFindCount, i.key() * 6 );
+
+ switch ( idx % 3 ) {
+ case 0:
+ gp = s.extract( i.key() );
+ break;
+ case 1:
+ gp = s.extract( i );
+ break;
+ case 2:
+ gp = s.extract_with( other_item( i.key() ), other_less() );
+ break;
+ }
+ EXPECT_TRUE( !gp );
+ }
+
+ EXPECT_TRUE( s.empty() );
+ EXPECT_CONTAINER_SIZE( s, 0 );
+ }
+
+ };
+} // namespace cds_test
+
+#endif // CDSUNIT_SET_TEST_SET_HP_H
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSUNIT_SET_TEST_MICHAEL_LAZY_RCU_H
#define CDSUNIT_SET_TEST_MICHAEL_LAZY_RCU_H
this->test( s );
}
+TYPED_TEST_P( MichaelLazySet, stat )
+{
+ typedef typename TestFixture::rcu_type rcu_type;
+ typedef typename TestFixture::int_item int_item;
+
+ struct list_traits: public cc::lazy_list::traits
+ {
+ typedef typename TestFixture::less less;
+ typedef cds::backoff::pause back_off;
+ typedef cc::lazy_list::stat<> stat;
+ };
+ typedef cc::LazyList< rcu_type, int_item, list_traits > list_type;
+
+ struct set_traits: public cc::michael_set::traits
+ {
+ typedef typename TestFixture::hash_int hash;
+ typedef cds::atomicity::item_counter item_counter;
+ };
+ typedef cc::MichaelHashSet< rcu_type, list_type, set_traits >set_type;
+
+ set_type s( TestFixture::kSize, 4 );
+ this->test( s );
+}
+
+TYPED_TEST_P( MichaelLazySet, wrapped_stat )
+{
+ typedef typename TestFixture::rcu_type rcu_type;
+ typedef typename TestFixture::int_item int_item;
+
+ struct list_traits: public cc::lazy_list::traits
+ {
+ typedef typename TestFixture::less less;
+ typedef cds::backoff::pause back_off;
+ typedef cc::lazy_list::wrapped_stat<> stat;
+ };
+ typedef cc::LazyList< rcu_type, int_item, list_traits > list_type;
+
+ struct set_traits: public cc::michael_set::traits
+ {
+ typedef typename TestFixture::hash_int hash;
+ typedef cds::atomicity::item_counter item_counter;
+ };
+ typedef cc::MichaelHashSet< rcu_type, list_type, set_traits >set_type;
+
+ set_type s( TestFixture::kSize, 4 );
+ this->test( s );
+}
// GCC 5: All test names should be written on single line, otherwise a runtime error will be encountered like as
// "No test named <test_name> can be found in this test case"
REGISTER_TYPED_TEST_CASE_P( MichaelLazySet,
- compare, less, cmpmix, item_counting, backoff, seq_cst, mutex
+ compare, less, cmpmix, item_counting, backoff, seq_cst, mutex, stat, wrapped_stat
);
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CDSUNIT_SET_TEST_MICHAEL_MICHAEL_RCU_H
#define CDSUNIT_SET_TEST_MICHAEL_MICHAEL_RCU_H
this->test( s );
}
+TYPED_TEST_P( MichaelSet, stat )
+{
+ typedef typename TestFixture::rcu_type rcu_type;
+ typedef typename TestFixture::int_item int_item;
+
+ struct list_traits: public cc::michael_list::traits
+ {
+ typedef typename TestFixture::less less;
+ typedef cds::backoff::pause back_off;
+ typedef cc::michael_list::stat<> stat;
+ };
+ typedef cc::MichaelList< rcu_type, int_item, list_traits > list_type;
+
+ struct set_traits: public cc::michael_set::traits
+ {
+ typedef typename TestFixture::hash_int hash;
+ typedef cds::atomicity::item_counter item_counter;
+ };
+ typedef cc::MichaelHashSet< rcu_type, list_type, set_traits >set_type;
+
+ set_type s( TestFixture::kSize, 4 );
+ this->test( s );
+}
+
+TYPED_TEST_P( MichaelSet, wrapped_stat )
+{
+ typedef typename TestFixture::rcu_type rcu_type;
+ typedef typename TestFixture::int_item int_item;
+
+ struct list_traits: public cc::michael_list::traits
+ {
+ typedef typename TestFixture::less less;
+ typedef cds::backoff::pause back_off;
+ typedef cc::michael_list::wrapped_stat<> stat;
+ };
+ typedef cc::MichaelList< rcu_type, int_item, list_traits > list_type;
+
+ struct set_traits: public cc::michael_set::traits
+ {
+ typedef typename TestFixture::hash_int hash;
+ typedef cds::atomicity::item_counter item_counter;
+ };
+ typedef cc::MichaelHashSet< rcu_type, list_type, set_traits >set_type;
+
+ set_type s( TestFixture::kSize, 4 );
+ this->test( s );
+}
// GCC 5: All test names should be written on single line, otherwise a runtime error will be encountered like as
// "No test named <test_name> can be found in this test case"
REGISTER_TYPED_TEST_CASE_P( MichaelSet,
- compare, less, cmpmix, item_counting, backoff, seq_cst
+ compare, less, cmpmix, item_counting, backoff, seq_cst, stat, wrapped_stat
);
#ifndef CDSUNIT_SET_TEST_SET_H
#define CDSUNIT_SET_TEST_SET_H
-#include <cds_test/check_size.h>
-#include <cds_test/fixture.h>
+#include "test_set_data.h"
#include <cds/opt/hash.h>
-#include <functional> // ref
-
-// forward declaration
-namespace cds { namespace container {}}
namespace cds_test {
- namespace co = cds::opt;
- class container_set : public fixture
+ class container_set : public container_set_data
{
- public:
- static size_t const kSize = 1000;
-
- struct stat
- {
- unsigned int nFindCount;
- unsigned int nUpdateNewCount;
- unsigned int nUpdateCount;
- mutable unsigned int nEraseCount;
-
- stat()
- {
- clear_stat();
- }
-
- void clear_stat()
- {
- memset( this, 0, sizeof( *this ) );
- }
- };
-
- struct other_item {
- int nKey;
-
- explicit other_item( int k )
- : nKey( k )
- {}
-
- int key() const
- {
- return nKey;
- }
- };
-
- struct int_item: public stat
- {
- int nKey;
- int nVal;
- std::string strVal;
-
- int_item()
- : nKey( 0 )
- , nVal( 0 )
- {}
-
- explicit int_item( int k )
- : nKey( k )
- , nVal( k * 2 )
- {}
-
- template <typename Q>
- explicit int_item( Q const& src )
- : nKey( src.key() )
- , nVal( 0 )
- {}
-
- int_item( int_item const& src )
- : nKey( src.nKey )
- , nVal( src.nVal )
- , strVal( src.strVal )
- {}
-
- int_item( int_item&& src )
- : nKey( src.nKey )
- , nVal( src.nVal )
- , strVal( std::move( src.strVal ) )
- {}
-
- int_item( int k, std::string&& s )
- : nKey( k )
- , nVal( k * 2 )
- , strVal( std::move( s ) )
- {}
-
- explicit int_item( other_item const& s )
- : nKey( s.key() )
- , nVal( s.key() * 2 )
- {}
-
- int key() const
- {
- return nKey;
- }
- };
-
- struct hash_int {
- size_t operator()( int i ) const
- {
- return co::v::hash<int>()(i);
- }
- template <typename Item>
- size_t operator()( const Item& i ) const
- {
- return (*this)(i.key());
- }
- };
-
- struct simple_item_counter {
- size_t m_nCount;
-
- simple_item_counter()
- : m_nCount( 0 )
- {}
-
- size_t operator ++()
- {
- return ++m_nCount;
- }
-
- size_t operator --()
- {
- return --m_nCount;
- }
-
- void reset()
- {
- m_nCount = 0;
- }
-
- operator size_t() const
- {
- return m_nCount;
- }
-
- };
-
- struct less
- {
- bool operator ()( int_item const& v1, int_item const& v2 ) const
- {
- return v1.key() < v2.key();
- }
-
- template <typename Q>
- bool operator ()( int_item const& v1, const Q& v2 ) const
- {
- return v1.key() < v2;
- }
-
- template <typename Q>
- bool operator ()( const Q& v1, int_item const& v2 ) const
- {
- return v1 < v2.key();
- }
- };
-
- struct cmp {
- int operator ()( int_item const& v1, int_item const& v2 ) const
- {
- if ( v1.key() < v2.key() )
- return -1;
- return v1.key() > v2.key() ? 1 : 0;
- }
-
- template <typename T>
- int operator ()( T const& v1, int v2 ) const
- {
- if ( v1.key() < v2 )
- return -1;
- return v1.key() > v2 ? 1 : 0;
- }
-
- template <typename T>
- int operator ()( int v1, T const& v2 ) const
- {
- if ( v1 < v2.key() )
- return -1;
- return v1 > v2.key() ? 1 : 0;
- }
- };
-
- struct other_less {
- template <typename Q, typename T>
- bool operator()( Q const& lhs, T const& rhs ) const
- {
- return lhs.key() < rhs.key();
- }
- };
-
protected:
template <typename Set>
void test( Set& s )
--- /dev/null
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+ Source code repo: http://github.com/khizmax/libcds/
+ Download: http://sourceforge.net/projects/libcds/files/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSUNIT_SET_TEST_SET_DATA_H
+#define CDSUNIT_SET_TEST_SET_DATA_H
+
+#include <cds_test/check_size.h>
+#include <cds_test/fixture.h>
+
+#include <cds/opt/hash.h>
+
+// forward declaration
+namespace cds { namespace container {}}
+
+namespace cds_test {
+ namespace co = cds::opt;
+
+ class container_set_data : public fixture
+ {
+ public:
+ static size_t const kSize = 1000;
+
+ struct stat
+ {
+ unsigned int nFindCount;
+ unsigned int nUpdateNewCount;
+ unsigned int nUpdateCount;
+ mutable unsigned int nEraseCount;
+
+ stat()
+ {
+ clear_stat();
+ }
+
+ void clear_stat()
+ {
+ memset( this, 0, sizeof( *this ) );
+ }
+ };
+
+ struct other_item {
+ int nKey;
+
+ explicit other_item( int k )
+ : nKey( k )
+ {}
+
+ int key() const
+ {
+ return nKey;
+ }
+ };
+
+ struct int_item: public stat
+ {
+ int nKey;
+ int nVal;
+ std::string strVal;
+
+ int_item()
+ : nKey( 0 )
+ , nVal( 0 )
+ {}
+
+ explicit int_item( int k )
+ : nKey( k )
+ , nVal( k * 2 )
+ {}
+
+ template <typename Q>
+ explicit int_item( Q const& src )
+ : nKey( src.key() )
+ , nVal( 0 )
+ {}
+
+ int_item( int_item const& src )
+ : nKey( src.nKey )
+ , nVal( src.nVal )
+ , strVal( src.strVal )
+ {}
+
+ int_item( int_item&& src )
+ : nKey( src.nKey )
+ , nVal( src.nVal )
+ , strVal( std::move( src.strVal ) )
+ {}
+
+ int_item( int k, std::string&& s )
+ : nKey( k )
+ , nVal( k * 2 )
+ , strVal( std::move( s ) )
+ {}
+
+ explicit int_item( other_item const& s )
+ : nKey( s.key() )
+ , nVal( s.key() * 2 )
+ {}
+
+ int key() const
+ {
+ return nKey;
+ }
+ };
+
+ struct hash_int {
+ size_t operator()( int i ) const
+ {
+ return co::v::hash<int>()(i);
+ }
+ template <typename Item>
+ size_t operator()( const Item& i ) const
+ {
+ return (*this)(i.key());
+ }
+ };
+
+ struct simple_item_counter {
+ size_t m_nCount;
+
+ simple_item_counter()
+ : m_nCount( 0 )
+ {}
+
+ size_t operator ++()
+ {
+ return ++m_nCount;
+ }
+
+ size_t operator --()
+ {
+ return --m_nCount;
+ }
+
+ void reset()
+ {
+ m_nCount = 0;
+ }
+
+ operator size_t() const
+ {
+ return m_nCount;
+ }
+
+ };
+
+ struct less
+ {
+ bool operator ()( int_item const& v1, int_item const& v2 ) const
+ {
+ return v1.key() < v2.key();
+ }
+
+ template <typename Q>
+ bool operator ()( int_item const& v1, const Q& v2 ) const
+ {
+ return v1.key() < v2;
+ }
+
+ template <typename Q>
+ bool operator ()( const Q& v1, int_item const& v2 ) const
+ {
+ return v1 < v2.key();
+ }
+ };
+
+ struct cmp {
+ int operator ()( int_item const& v1, int_item const& v2 ) const
+ {
+ if ( v1.key() < v2.key() )
+ return -1;
+ return v1.key() > v2.key() ? 1 : 0;
+ }
+
+ template <typename T>
+ int operator ()( T const& v1, int v2 ) const
+ {
+ if ( v1.key() < v2 )
+ return -1;
+ return v1.key() > v2 ? 1 : 0;
+ }
+
+ template <typename T>
+ int operator ()( int v1, T const& v2 ) const
+ {
+ if ( v1 < v2.key() )
+ return -1;
+ return v1 > v2.key() ? 1 : 0;
+ }
+ };
+
+ struct other_less {
+ template <typename Q, typename T>
+ bool operator()( Q const& lhs, T const& rhs ) const
+ {
+ return lhs.key() < rhs.key();
+ }
+ };
+ };
+
+} // namespace cds_test
+
+#endif // CDSUNIT_SET_TEST_SET_DATA_H