-//$$CDS-header$$
+/*
+ This file is a part of libcds - Concurrent Data Structures library
+
+ (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
+
+ 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 __CDS_OPT_OPTIONS_H
-#define __CDS_OPT_OPTIONS_H
+#ifndef CDSLIB_OPT_OPTIONS_H
+#define CDSLIB_OPT_OPTIONS_H
/*
Framework to define template options
2011.01.23 khizmax Created
*/
+#include <cstdlib> // rand, srand
+
#include <cds/details/aligned_type.h>
#include <cds/user_setup/allocator.h>
#include <cds/user_setup/cache_line.h>
-#include <cds/cxx11_atomic.h>
-#include <cds/details/void_selector.h>
-#include <stdlib.h> // rand, srand
+#include <cds/algo/atomic.h>
namespace cds {
*/
namespace opt {
- /// Predefined options value (generally, for the options that determine the data types)
- namespace v {}
-
/// Type indicates that an option is not specified and the default one should be used
struct none
{
Examples:
\code
- // default_spin is cds::lock::Spin
- typedef typename cds::opt::select_default< cds::opt::none, cds::lock::Spin >::type default_spin;
+ // default_spin is cds::sync::spin
+ typedef typename cds::opt::select_default< cds::opt::none, cds::sync::spin >::type default_spin;
- // spin_32bit is cds::lock::Spin32
- typedef typename cds::opt::select_default< cds::lock::Spin32, cds::lock::Spin >::type spin_32bit;
+ // spin_32bit is cds::sync::reentrant_spin32
+ typedef typename cds::opt::select_default< cds::opt::none, cds::sync::reentrant_spin32 >::type spin_32bit;
\endcode
*/
template <typename Option, typename Default, typename Value = Option>
//@endcond
};
+ /// [type-option] @ref cds_sync_monitor "Monitor" type setter
+ /**
+ This option setter specifyes @ref cds_sync_monitor "synchronization monitor"
+ for blocking container.
+ */
+ template <typename Type>
+ struct sync_monitor {
+ //@cond
+ template <class Base> struct pack : public Base
+ {
+ typedef Type sync_monitor;
+ };
+ //@endcond
+ };
+
/// [type-option] Back-off strategy option setter
/**
Back-off strategy used in some algorithm.
/**
Possible values of \p GC template parameter are:
- cds::gc::HP - Hazard Pointer garbage collector
- - cds::gc::HRC - Gidenstam's garbage collector
- - cds::gc::PTB - Pass-the-Buck garbage collector
+ - cds::gc::DHP - Dynamic Hazard Pointer garbage collector
- cds::gc::none::GC - No garbage collector (not supported for some containers)
*/
template <typename GC>
This option allows to set up appropriate item counting policy for that data structure.
Predefined option \p Type:
- - atomicity::empty_item_counter - no item counting performed. It is default policy for many
+ - \p atomicity::empty_item_counter - no item counting performed. It is default policy for many
containers
- - atomicity::item_counter - the class that provides atomically item counting
- - opt::v::sequential_item_counter - simple non-atomic item counter. This item counter is not intended for
+ - \p atomicity::item_counter - the class that provides atomic item counting
+ - \p atomicity::cache_friendly_item_counter - cache-friendly atomic item counter
+ - \p opt::v::sequential_item_counter - simple non-atomic item counter. This counter is not intended for
concurrent containers and may be used only if it is explicitly noted.
- You may provide other implementation of atomicity::item_counter interface for your needs.
+ You may provide other implementation of \p atomicity::item_counter interface for your needs.
Note, the item counting in lock-free containers cannot be exact; for example, if
item counter for a container returns zero it is not mean that the container is empty.
- Thus, item counter may be used for statistical purposes only.
+ So, the item counter may be used for statistical purposes only.
*/
template <typename Type>
struct item_counter {
//@endcond
};
- namespace v {
- /// Sequential non-atomic item counter
- /**
- This type of item counter is not intended for concurrent containers
- and may be used only if it is explicitly noted.
- */
- class sequential_item_counter
- {
- public:
- typedef size_t counter_type ; ///< Counter type
- protected:
- counter_type m_nCounter ; ///< Counter
-
- public:
- sequential_item_counter()
- : m_nCounter(0)
- {}
-
- /// Returns current value of the counter
- counter_type value() const
- {
- return m_nCounter;
- }
-
- /// Same as \ref value() with relaxed memory ordering
- operator counter_type() const
- {
- return value();
- }
-
- /// Increments the counter. Semantics: postincrement
- counter_type inc()
- {
- return m_nCounter++;
- }
-
- /// Decrements the counter. Semantics: postdecrement
- counter_type dec()
- {
- return m_nCounter--;
- }
-
- /// Preincrement
- counter_type operator ++()
- {
- return inc() + 1;
- }
- /// Postincrement
- counter_type operator ++(int)
- {
- return inc();
- }
-
- /// Predecrement
- counter_type operator --()
- {
- return dec() - 1;
- }
- /// Postdecrement
- counter_type operator --(int)
- {
- return dec();
- }
-
- /// Resets count to 0
- void reset()
- {
- m_nCounter = 0;
- }
- };
- } // namespace v
-
/// Special alignment constants for \ref cds::opt::alignment option
enum special_alignment {
no_special_alignment = 0, ///< no special alignment
struct alignment_setter<Type, cache_line_alignment> {
typedef typename cds::details::aligned_type< Type, c_nCacheLineSize >::type type;
};
+ } // namespace details
+ //@endcond
+
+ /// Special padding constants for \p cds::opt::padding option
+ enum special_padding {
+ no_special_padding = 0, ///< no special padding
+ cache_line_padding = 1, ///< use cache line size defined in cds/user_setup/cache_line.h
+
+ /// Apply padding only for tiny data when data size is less than required padding
+ /**
+ The flag means that if your data size is less than the cacheline size, the padding is applyed.
+ Otherwise no padding will be applyed.
+
+ This flag is applyed for padding value:
+ \code
+ cds::opt::padding< cds::opt::cache_line_padding | cds::opt::padding_tiny_data_only >;
+ cds::opt::padding< 256 | cds::opt::padding_tiny_data_only >;
+ \endcode
+ */
+ padding_tiny_data_only = 0x80000000,
+
+ //@cond
+ padding_flags = padding_tiny_data_only
+ //@endcond
+ };
+
+ /// [value-option] Padding option setter
+ /**
+ The padding for the internal data of some containers. May be useful to solve false sharing problem.
+ \p Value defines desired padding and it may be power of two integer or predefined values from
+ \p special_padding enum.
+ */
+ template <unsigned int Value>
+ struct padding {
+ //@cond
+ template <typename Base> struct pack: public Base
+ {
+ enum { padding = Value };
+ };
+ //@endcond
+ };
+
+ //@cond
+ template <unsigned Padding>
+ struct actual_padding
+ {
+ enum { value = Padding & ~padding_flags };
+ };
+
+ template <>
+ struct actual_padding<cache_line_padding>
+ {
+ enum { value = cds::c_nCacheLineSize };
+ };
+
+ template <>
+ struct actual_padding<cache_line_padding| padding_tiny_data_only>
+ {
+ enum { value = cds::c_nCacheLineSize };
+ };
+ //@endcond
+
+ //@cond
+ namespace details {
+ enum padding_vs_datasize {
+ padding_datasize_less,
+ padding_datasize_equal,
+ padding_datasize_greater
+ };
+
+ template < typename T, unsigned int Padding, bool NoPadding, padding_vs_datasize Relation, bool TinyOnly >
+ struct apply_padding_helper;
+
+ template <typename T, padding_vs_datasize Relation, bool TinyOnly >
+ struct apply_padding_helper < T, 0, true, Relation, TinyOnly >
+ {
+ struct type {
+ T data;
+ };
+ typedef void padding_type;
+ };
+
+ template <typename T, unsigned int Padding, bool TinyOnly >
+ struct apply_padding_helper < T, Padding, false, padding_datasize_equal, TinyOnly >
+ {
+ struct type {
+ T data;
+ };
+ typedef void padding_type;
+ };
+
+ template <typename T, unsigned int Padding, bool TinyOnly >
+ struct apply_padding_helper < T, Padding, false, padding_datasize_less, TinyOnly >
+ {
+ typedef uint8_t padding_type[Padding - sizeof( T )];
+ struct type {
+ T data;
+ padding_type pad_;
+ };
+
+ };
+
+ template <typename T, unsigned int Padding >
+ struct apply_padding_helper < T, Padding, false, padding_datasize_greater, false >
+ {
+ typedef uint8_t padding_type[Padding - sizeof( T ) % Padding];
+ struct type {
+ T data;
+ padding_type pad_;
+ };
+ };
+
+ template <typename T, unsigned int Padding >
+ struct apply_padding_helper < T, Padding, false, padding_datasize_greater, true >
+ {
+ struct type {
+ T data;
+ };
+ typedef void padding_type;
+ };
+
+ template <typename T, unsigned int Padding >
+ struct apply_padding
+ {
+ private:
+ enum { padding = Padding & ~padding_flags };
+
+ public:
+ static CDS_CONSTEXPR const size_t c_nPadding =
+ static_cast<unsigned int>(padding) == static_cast<unsigned int>(cache_line_padding) ? cds::c_nCacheLineSize :
+ static_cast<unsigned int>(padding) == static_cast<unsigned int>(no_special_padding) ? 0 : padding;
+
+ static_assert( (c_nPadding & (c_nPadding - 1)) == 0, "Padding must be a power-of-two number" );
+
+ typedef apply_padding_helper< T,
+ c_nPadding,
+ c_nPadding == 0,
+ sizeof( T ) < c_nPadding ? padding_datasize_less : sizeof( T ) == c_nPadding ? padding_datasize_equal : padding_datasize_greater,
+ (Padding & padding_tiny_data_only) != 0
+ > result;
+
+ typedef typename result::type type;
+
+ typedef typename std::conditional<
+ std::is_same< typename result::padding_type, void >::value,
+ unsigned int,
+ typename result::padding_type
+ >::type padding_type;
+ };
} // namespace details
//@endcond
+
/// [type-option] Generic option setter for statisitcs
/**
This option sets a type to gather statistics.
/// [type-option] Option setter for C++ memory model
/**
The <b>cds</b> library supports following memory ordering constraints for atomic operations in container implementation:
- - v::relaxed_ordering - relaxed C++ memory model. This mode supports full set of memory ordering constraints:
+ - \p v::relaxed_ordering - relaxed C++ memory model. This mode supports full set of memory ordering constraints:
\p memory_order_relaxed, \p memory_order_acquire, \p memory_order_release and so on.
- - v::sequential_consistent - sequentially consistent C++ memory model (default memory ordering for C++). In
+ - \p v::sequential_consistent - sequentially consistent C++ memory model (default memory ordering for C++). In
this mode any memory ordering constraint maps to \p memory_order_seq_cst.
- The \p Type template parameter can be v::relaxed_ordering or v::sequential_consistent.
+ The \p Type template parameter can be \p v::relaxed_ordering or \p v::sequential_consistent.
You may mix different memory ordering options for different containers: one declare as sequentially consistent,
another declare as relaxed.
- Usually, v::relaxed_ordering is the default memory ordering for <b>cds</b> containers.
+ Usually, \p v::relaxed_ordering is the default memory ordering for <b>libcds</b> containers.
*/
template <typename Type>
struct memory_model {
//@endcond
};
- namespace v {
- /// Relaxed memory ordering model
- /**
- In this memory model the memory constraints are defined according to C++ Memory Model specification.
-
- See opt::memory_model for explanations
- */
- struct relaxed_ordering {
- //@cond
-
- // For new C++11 (cds-1.1.0)
- static const atomics::memory_order memory_order_relaxed = atomics::memory_order_relaxed;
- static const atomics::memory_order memory_order_consume = atomics::memory_order_consume;
- static const atomics::memory_order memory_order_acquire = atomics::memory_order_acquire;
- static const atomics::memory_order memory_order_release = atomics::memory_order_release;
- static const atomics::memory_order memory_order_acq_rel = atomics::memory_order_acq_rel;
- static const atomics::memory_order memory_order_seq_cst = atomics::memory_order_seq_cst;
- //@endcond
- };
-
- /// Sequential consistent memory ordering model
- /**
- In this memory model any memory constraint is equivalent to \p memory_order_seq_cst.
-
- See opt::memory_model for explanations
- */
- struct sequential_consistent {
- //@cond
-
- // For new C++11 (cds-1.1.0)
- static const atomics::memory_order memory_order_relaxed = atomics::memory_order_seq_cst;
- static const atomics::memory_order memory_order_consume = atomics::memory_order_seq_cst;
- static const atomics::memory_order memory_order_acquire = atomics::memory_order_seq_cst;
- static const atomics::memory_order memory_order_release = atomics::memory_order_seq_cst;
- static const atomics::memory_order memory_order_acq_rel = atomics::memory_order_seq_cst;
- static const atomics::memory_order memory_order_seq_cst = atomics::memory_order_seq_cst;
- //@endcond
- };
- } // namespace v
-
/// [type-option] Base type traits option setter
/**
This option setter is intended generally for internal use for type rebinding.
//@endcond
};
- namespace v {
-
- /// Default swap policy (see opt::swap_policy option)
- /**
- The default swap policy is wrappr around \p std::swap algorithm.
- */
- struct default_swap_policy {
- /// Performs swapping of \p v1 and \p v2 using \p std::swap algo
- template <typename T>
- void operator()( T& v1, T& v2 ) const
- {
- std::swap( v1, v2 );
- }
- };
- } // namespace v
-
/// Move policy option
/**
The move policy specifies an algorithm for moving object content.
//@endcond
};
- namespace v {
- /// \ref opt::move_policy "Move policy" based on assignment operator
- struct assignment_move_policy
- {
- /// <tt> dest = src </tt>
- template <typename T>
- void operator()( T& dest, T const& src ) const
- {
- dest = src;
- }
- };
- } // namespace v
-
/// [value-option] Enable sorting
/**
This option enables (<tt>Enable = true</tt>) or disables (<tt>Enable == false</tt>)
\p Random can be any STL random number generator producing
unsigned integer: \p std::linear_congruential_engine,
\p std::mersenne_twister_engine, \p std::subtract_with_carry_engine
- and so on, or opt::v::c_rand.
+ and so on, or \p opt::v::c_rand.
*/
template <typename Random>
//@endcond
};
+ /// [type-option] Free-list implementation
+ /**
+ See \p cds::intrusive::FreeList for free-list interface
+ */
+ template <typename FreeList>
+ struct free_list {
+ //@cond
+ template <typename Base> struct pack: public Base
+ {
+ typedef FreeList free_list;
+ };
+ //@endcond
+ };
+
+ //@cond
+ // For internal use
+ template <typename Accessor>
+ struct key_accessor {
+ template <typename Base> struct pack: public Base
+ {
+ typedef Accessor key_accessor;
+ };
+ };
+
+ template <typename Traits, typename ReplaceWith, typename WhatReplace = none >
+ struct replace_key_accessor {
+ typedef typename std::conditional<
+ std::is_same< typename Traits::key_accessor, WhatReplace >::value,
+ typename opt::key_accessor< ReplaceWith >::template pack< Traits >,
+ Traits
+ >::type type;
+ };
+ //@endcond
+
+}} // namespace cds::opt
+
+
+// ****************************************************
+// Options predefined types and values
+
+namespace cds { namespace opt {
+
+ /// Predefined options value
namespace v {
- /// \p rand() -base random number generator
+
+ /// Sequential non-atomic item counter
+ /**
+ This type of \p opt::item_counter option is not intended for concurrent containers
+ and may be used only if it is explicitly noted.
+ */
+ class sequential_item_counter
+ {
+ public:
+ typedef size_t counter_type ; ///< Counter type
+ protected:
+ counter_type m_nCounter ; ///< Counter
+
+ public:
+ sequential_item_counter()
+ : m_nCounter(0)
+ {}
+
+ /// Returns current value of the counter
+ counter_type value() const
+ {
+ return m_nCounter;
+ }
+
+ /// Same as \ref value() with relaxed memory ordering
+ operator counter_type() const
+ {
+ return value();
+ }
+
+ /// Increments the counter. Semantics: postincrement
+ counter_type inc()
+ {
+ return m_nCounter++;
+ }
+
+ /// Decrements the counter. Semantics: postdecrement
+ counter_type dec()
+ {
+ return m_nCounter--;
+ }
+
+ /// Preincrement
+ counter_type operator ++()
+ {
+ return inc() + 1;
+ }
+ /// Postincrement
+ counter_type operator ++(int)
+ {
+ return inc();
+ }
+
+ /// Predecrement
+ counter_type operator --()
+ {
+ return dec() - 1;
+ }
+ /// Postdecrement
+ counter_type operator --(int)
+ {
+ return dec();
+ }
+
+ /// Resets count to 0
+ void reset()
+ {
+ m_nCounter = 0;
+ }
+ };
+
+ /// Relaxed memory ordering \p opt::memory_model
+ /**
+ In this ordering the memory constraints are defined according to C++ Memory Model specification:
+ each constraint is mapped to \p std::memory_order constraints one-to-one
+ */
+ struct relaxed_ordering {
+ //@cond
+ static const atomics::memory_order memory_order_relaxed = atomics::memory_order_relaxed;
+ static const atomics::memory_order memory_order_consume = atomics::memory_order_consume;
+ static const atomics::memory_order memory_order_acquire = atomics::memory_order_acquire;
+ static const atomics::memory_order memory_order_release = atomics::memory_order_release;
+ static const atomics::memory_order memory_order_acq_rel = atomics::memory_order_acq_rel;
+ static const atomics::memory_order memory_order_seq_cst = atomics::memory_order_seq_cst;
+ //@endcond
+ };
+
+ /// Sequential consistent \p opt::memory_memory ordering
+ /**
+ In this memory model any memory constraint is equivalent to \p std::memory_order_seq_cst.
+ */
+ struct sequential_consistent {
+ //@cond
+ static const atomics::memory_order memory_order_relaxed = atomics::memory_order_seq_cst;
+ static const atomics::memory_order memory_order_consume = atomics::memory_order_seq_cst;
+ static const atomics::memory_order memory_order_acquire = atomics::memory_order_seq_cst;
+ static const atomics::memory_order memory_order_release = atomics::memory_order_seq_cst;
+ static const atomics::memory_order memory_order_acq_rel = atomics::memory_order_seq_cst;
+ static const atomics::memory_order memory_order_seq_cst = atomics::memory_order_seq_cst;
+ //@endcond
+ };
+
+ //@cond
+ /// Totally relaxed \p opt::memory_model ordering (do not use!)
+ /**
+ In this memory model any memory constraint is equivalent to \p std::memory_order_relaxed.
+ @warning Do not use this model! It intended for testing purposes only
+ to verify debugging instruments like Thread Sanitizer.
+ */
+ struct total_relaxed_ordering {
+ static const atomics::memory_order memory_order_relaxed = atomics::memory_order_relaxed;
+ static const atomics::memory_order memory_order_consume = atomics::memory_order_relaxed;
+ static const atomics::memory_order memory_order_acquire = atomics::memory_order_relaxed;
+ static const atomics::memory_order memory_order_release = atomics::memory_order_relaxed;
+ static const atomics::memory_order memory_order_acq_rel = atomics::memory_order_relaxed;
+ static const atomics::memory_order memory_order_seq_cst = atomics::memory_order_relaxed;
+ };
+ //@endcond
+
+
+ /// Default swap policy for \p opt::swap_policy option
+ /**
+ The default swap policy is wrappr around \p std::swap algorithm.
+ */
+ struct default_swap_policy {
+ /// Performs swapping of \p v1 and \p v2 using \p std::swap algo
+ template <typename T>
+ void operator()( T& v1, T& v2 ) const
+ {
+ std::swap( v1, v2 );
+ }
+ };
+
+ /// \p opt::move_policy based on move-assignment operator
+ struct assignment_move_policy
+ {
+ /// <tt> dest = std::move( src ) </tt>
+ template <typename T>
+ void operator()( T& dest, T&& src ) const
+ {
+ dest = std::move( src );
+ }
+ };
+
+ /// \p rand() -base random number generator for \p opt::random_engine
/**
This generator returns a pseudorandom integer in the range 0 to \p RAND_MAX (32767).
*/
struct c_rand {
typedef unsigned int result_type; ///< Result type
- /// Constructor initializes object calling \p srand()
+ /// Constructor initializes object calling \p std::srand()
c_rand()
{
- srand(1);
+ std::srand(1);
}
- /// Returns next random number calling \p rand()
+ /// Returns next random number calling \p std::rand()
result_type operator()()
{
- return (result_type) rand();
+ return (result_type) std::rand();
}
};
} // namespace v
+}} // namespace cds::opt
+
+
+// ****************************************************
+// Options metafunctions
+
+namespace cds { namespace opt {
+
//@cond
- // For internal use
- template <typename Accessor>
- struct key_accessor {
- template <typename Base> struct pack: public Base
+ namespace details {
+ template <typename OptionList, typename Option>
+ struct do_pack
{
- typedef Accessor key_accessor;
+ // Use "pack" member template to pack options
+ typedef typename Option::template pack<OptionList> type;
+ };
+
+ template <typename ...T> class typelist;
+
+ template <typename Typelist> struct typelist_head;
+ template <typename Head, typename ...Tail>
+ struct typelist_head< typelist<Head, Tail...> > {
+ typedef Head type;
+ };
+ template <typename Head>
+ struct typelist_head< typelist<Head> > {
+ typedef Head type;
+ };
+
+ template <typename Typelist> struct typelist_tail;
+ template <typename Head, typename ...Tail>
+ struct typelist_tail< typelist<Head, Tail...> > {
+ typedef typelist<Tail...> type;
};
+ template <typename Head>
+ struct typelist_tail< typelist<Head> > {
+ typedef typelist<> type;
+ };
+
+ template <typename OptionList, typename Typelist>
+ struct make_options_impl {
+ typedef typename make_options_impl<
+ typename do_pack<
+ OptionList,
+ typename typelist_head< Typelist >::type
+ >::type,
+ typename typelist_tail<Typelist>::type
+ >::type type;
+ };
+
+ template <typename OptionList>
+ struct make_options_impl<OptionList, typelist<> > {
+ typedef OptionList type;
+ };
+ } // namespace details
+ //@endcond
+
+ /// make_options metafunction
+ /** @headerfile cds/opt/options.h
+
+ The metafunction converts option list \p Options to traits structure.
+ The result of metafunction is \p type.
+
+ Template parameter \p OptionList is default option set (default traits).
+ \p Options is option list.
+ */
+ template <typename OptionList, typename... Options>
+ struct make_options {
+#ifdef CDS_DOXYGEN_INVOKED
+ typedef implementation_defined type ; ///< Result of the metafunction
+#else
+ typedef typename details::make_options_impl< OptionList, details::typelist<Options...> >::type type;
+#endif
};
- template <typename Traits, typename ReplaceWith, typename WhatReplace = none >
- struct replace_key_accessor {
- typedef typename std::conditional<
- std::is_same< typename Traits::key_accessor, WhatReplace >::value,
- typename opt::key_accessor< ReplaceWith >::template pack< Traits >,
- Traits
- >::type type;
+
+ // *****************************************************************
+ // find_type_traits metafunction
+ // *****************************************************************
+
+ //@cond
+ namespace details {
+ template <typename... Options>
+ struct find_type_traits_option;
+
+ template <>
+ struct find_type_traits_option<> {
+ typedef cds::opt::none type;
+ };
+
+ template <typename Any>
+ struct find_type_traits_option< Any > {
+ typedef cds::opt::none type;
+ };
+
+ template <typename Any>
+ struct find_type_traits_option< cds::opt::type_traits< Any > > {
+ typedef Any type;
+ };
+
+ template <typename Any, typename... Options>
+ struct find_type_traits_option< cds::opt::type_traits< Any >, Options... > {
+ typedef Any type;
+ };
+
+ template <typename Any, typename... Options>
+ struct find_type_traits_option< Any, Options... > {
+ typedef typename find_type_traits_option< Options... >::type type;
+ };
+ } // namespace details
+ //@endcond
+
+ /// Metafunction to find opt::type_traits option in \p Options list
+ /** @headerfile cds/opt/options.h
+
+ If \p Options contains \p opt::type_traits option then it is the metafunction result.
+ Otherwise the result is \p DefaultOptons.
+ */
+ template <typename DefaultOptions, typename... Options>
+ struct find_type_traits {
+ typedef typename select_default< typename details::find_type_traits_option<Options...>::type, DefaultOptions>::type type ; ///< Metafunction result
};
+
+
+ // *****************************************************************
+ // find_option metafunction
+ // *****************************************************************
+
+ //@cond
+ namespace details {
+ template <typename What, typename... Options>
+ struct find_option;
+
+ struct compare_ok;
+ struct compare_fail;
+
+ template <typename A, typename B>
+ struct compare_option
+ {
+ typedef compare_fail type;
+ };
+
+ template <template <typename> class Opt, typename A, typename B>
+ struct compare_option< Opt<A>, Opt<B> >
+ {
+ typedef compare_ok type;
+ };
+
+ // Specializations for integral type of option
+#define CDS_FIND_OPTION_INTEGRAL_SPECIALIZATION_( _type ) template <template <_type> class What, _type A, _type B> \
+ struct compare_option< What<A>, What<B> > { typedef compare_ok type ; };
+
+ // For user-defined enum types
+#define CDS_DECLARE_FIND_OPTION_INTEGRAL_SPECIALIZATION( _type ) namespace cds { namespace opt { namespace details { CDS_FIND_OPTION_INTEGRAL_SPECIALIZATION_(_type ) }}}
+
+ CDS_FIND_OPTION_INTEGRAL_SPECIALIZATION_(bool)
+ CDS_FIND_OPTION_INTEGRAL_SPECIALIZATION_(char)
+ CDS_FIND_OPTION_INTEGRAL_SPECIALIZATION_(unsigned char)
+ CDS_FIND_OPTION_INTEGRAL_SPECIALIZATION_(signed char)
+ CDS_FIND_OPTION_INTEGRAL_SPECIALIZATION_(short int)
+ CDS_FIND_OPTION_INTEGRAL_SPECIALIZATION_(unsigned short int)
+ CDS_FIND_OPTION_INTEGRAL_SPECIALIZATION_(int)
+ CDS_FIND_OPTION_INTEGRAL_SPECIALIZATION_(unsigned int)
+ CDS_FIND_OPTION_INTEGRAL_SPECIALIZATION_(long)
+ CDS_FIND_OPTION_INTEGRAL_SPECIALIZATION_(unsigned long)
+ CDS_FIND_OPTION_INTEGRAL_SPECIALIZATION_(long long)
+ CDS_FIND_OPTION_INTEGRAL_SPECIALIZATION_(unsigned long long)
+
+
+ template <typename CompResult, typename Ok, typename Fail>
+ struct select_option
+ {
+ typedef Fail type;
+ };
+
+ template <typename Ok, typename Fail>
+ struct select_option< compare_ok, Ok, Fail >
+ {
+ typedef Ok type;
+ };
+
+ template <typename What>
+ struct find_option< What > {
+ typedef What type;
+ };
+
+ template <typename What, typename Opt>
+ struct find_option< What, Opt > {
+ typedef typename select_option<
+ typename compare_option< What, Opt >::type
+ ,Opt
+ ,What
+ >::type type;
+ };
+
+ template <typename What, typename Opt, typename... Options>
+ struct find_option< What, Opt, Options... > {
+ typedef typename select_option<
+ typename compare_option< What, Opt >::type
+ ,Opt
+ ,typename find_option< What, Options... >::type
+ >::type type;
+ };
+ } // namespace details
+ //@endcond
+
+ /// Metafunction to find \p What option in \p Options list
+ /** @headerfile cds/opt/options.h
+
+ If \p Options contains \p What< Val > option for any \p Val then the result is \p What< Val >
+ Otherwise the result is \p What.
+
+ Example:
+ \code
+ #include <cds/opt/options.h>
+ namespace co = cds::opt;
+
+ struct default_tag;
+ struct tag_a;
+ struct tag_b;
+
+ // Find option co::tag.
+
+ // res1 is co::tag< tag_a >
+ typedef co::find_option< co::tag< default_tag >, co::gc< cds::gc::HP >, co::tag< tag_a > >::type res1;
+
+ // res2 is default co::tag< default_tag >
+ typedef co::find_option< co::tag< default_tag >, co::less< x >, co::hash< H > >::type res2;
+
+ // Multiple option co::tag. The first option is selected
+ // res3 is default co::tag< tag_a >
+ typedef co::find_option< co::tag< default_tag >, co::tag< tag_a >, co::tag< tag_b > >::type res3;
+
+ \endcode
+ */
+ template <typename What, typename... Options>
+ struct find_option {
+ typedef typename details::find_option<What, Options...>::type type ; ///< Metafunction result
+ };
+
+
+ // *****************************************************************
+ // select metafunction
+ // *****************************************************************
+
+ //@cond
+ namespace details {
+
+ template <typename What, typename... Pairs>
+ struct select;
+
+ template <typename What, typename Value>
+ struct select< What, What, Value>
+ {
+ typedef Value type;
+ };
+
+ template <typename What, typename Tag, typename Value>
+ struct select<What, Tag, Value>
+ {
+ typedef What type;
+ };
+
+ template <typename What, typename Value, typename... Pairs>
+ struct select< What, What, Value, Pairs...>
+ {
+ typedef Value type;
+ };
+
+ template <typename What, typename Tag, typename Value, typename... Pairs>
+ struct select< What, Tag, Value, Pairs...>
+ {
+ typedef typename select<What, Pairs...>::type type;
+ };
+ } // namespace details
//@endcond
+ /// Select option metafunction
+ /** @headerfile cds/opt/options.h
+
+ Pseudocode:
+ \code
+ select <What, T1, R1, T2, R2, ... Tn, Rn> ::=
+ if What == T1 then return R1
+ if What == T2 then return R2
+ ...
+ if What == Tn then return Rn
+ else return What
+ \endcode
+ */
+ template <typename What, typename... Pairs>
+ struct select {
+ typedef typename details::select< What, Pairs...>::type type ; ///< Metafunction result
+ };
+
}} // namespace cds::opt
-#ifdef CDS_CXX11_VARIADIC_TEMPLATE_SUPPORT
-# include <cds/opt/make_options_var.h>
-#else
-# include <cds/opt/make_options_std.h>
-#endif
-#endif // #ifndef __CDS_OPT_OPTIONS_H
+#endif // #ifndef CDSLIB_OPT_OPTIONS_H