3 #ifndef CDSLIB_OPT_OPTIONS_H
4 #define CDSLIB_OPT_OPTIONS_H
7 Framework to define template options
10 2011.01.23 khizmax Created
13 #include <stdlib.h> // rand, srand
15 #include <cds/details/aligned_type.h>
16 #include <cds/user_setup/allocator.h>
17 #include <cds/user_setup/cache_line.h>
18 #include <cds/algo/atomic.h>
22 /// Framework to define template options
24 There are two kind of options:
25 - \p type-option - option that determines a data type. The template argument \p Type of the option is a type.
26 - \p value-option - option that determines a value. The template argument \p Value of the option is a value.
30 /// Type indicates that an option is not specified and the default one should be used
34 template <class Base> struct pack: public Base
39 /// Metafunction for selecting default option value
42 - \p Option - option value
43 - \p Default - default option value
44 - \p Value - option value if \p Option is not opt::none
46 If \p Option is opt::none, the metafunction result is \p Default, otherwise
47 the result is \p Value.
51 // default_spin is cds::sync::spin
52 typedef typename cds::opt::select_default< cds::opt::none, cds::sync::spin >::type default_spin;
54 // spin_32bit is cds::sync::reentrant_spin32
55 typedef typename cds::opt::select_default< cds::opt::none, cds::sync::reentrant_spin32 >::type spin_32bit;
58 template <typename Option, typename Default, typename Value = Option>
61 typedef Value type ; ///< metafunction result
64 template <typename Default>
65 struct select_default< none, Default >
71 /// Metafunction to select option value
73 This metafunction is intended for extracting the value of the \p Option option.
76 #include <cds/opt/options.h>
77 #include <type_traits> // only for testing purpose (static_assert)
82 typedef cds::opt::tag< tag_a > tag_option;
84 // What is the value of the tag_option?
85 // How we can extract tag_a from tag_option?
86 // Here is a solution:
87 typedef cds::opt::value< tag_option >::tag tag_option_value;
89 // tag_option_value is the same as tag_a
90 static_assert( std::is_same< tag_option_value, tag_a >::value, "Error: tag_option_value != tag_a" );
94 template <typename Option>
95 struct value: public Option::template pack<none>
99 /// [type-option] Option setter specifies a tag
101 Suppose, you have a struct
106 and you want that your class \p X would be derived from several \p Feature:
108 class X: public Feature, public Feature
112 How can you distinguish one \p Feature from another?
113 You may use a tag option:
115 template <typename Tag>
121 class X: public Feature< tag_a >, public Feature< tag_b >
124 Now you can distinguish one \p Feature from another:
127 Feature<tag_a>& fa = static_cast< Feature<tag_a> >( x );
128 Feature<tag_b>& fb = static_cast< Feature<tag_b> >( x );
131 \p tag option setter allows you to do things like this for an option-centric approach:
133 template <typename ...Options>
139 class X: public Feature< tag<tag_a> >, public Feature< tag<tag_b> >
143 This option setter is widely used in cds::intrusive containers to distinguish
144 between different intrusive part of container's node.
146 An incomplete type can serve as a \p Tag.
148 template <typename Tag>
151 template<class Base> struct pack: public Base
158 /// [type-option] Option setter specifies lock class
160 Specification of the \p Type class is:
168 template <typename Type>
171 template<class Base> struct pack: public Base
173 typedef Type lock_type;
178 /// [type-option] @ref cds_sync_monitor "Monitor" type setter
180 This option setter specifyes @ref cds_sync_monitor "synchronization monitor"
181 for blocking container.
183 template <typename Type>
184 struct sync_monitor {
186 template <class Base> struct pack : public Base
188 typedef Type sync_monitor;
193 /// [type-option] Back-off strategy option setter
195 Back-off strategy used in some algorithm.
196 See cds::backoff namespace for back-off explanation and supported interface.
198 template <typename Type>
201 template <class Base> struct pack: public Base
203 typedef Type back_off;
208 /// [type-option] Option setter for garbage collecting schema used
210 Possible values of \p GC template parameter are:
211 - cds::gc::HP - Hazard Pointer garbage collector
212 - cds::gc::DHP - Dynamic Hazard Pointer garbage collector
213 - cds::gc::none::GC - No garbage collector (not supported for some containers)
215 template <typename GC>
218 template <class Base> struct pack: public Base
225 /// [type-option] Option setter for an allocator
227 \p Type is allocator with \p std::allocator interface. Default is value of macro CDS_DEFAULT_ALLOCATOR
228 that, in turn, is \p std::allocator.
230 The \p libcds containers actively use rebinding to convert an allocator of one type to another. Thus,
231 you may specify any valid type as std::allocator's template parameter.
233 See also opt::node_allocator
235 template <typename Type>
238 template <typename Base> struct pack: public Base
240 typedef Type allocator;
245 /// [type-option] Option setter for node allocator
247 \p Type is allocator with \p std::allocator interface. Default is value of macro CDS_DEFAULT_ALLOCATOR
248 that, in turn, is \p std::allocator.
250 Many node-base containers require an allocator for maintaining data (container's node) and for internal use.
251 Sometimes, this types of allocator should be different for performance reason.
252 For example, we should like to allocate the node from a pool of preallocated nodes.
253 Such pool can be seen as the node allocator.
255 Usually, if a container supports \p opt::allocator and \p %opt::node_allocator options
256 and \p opt::node_allocator is not specified the \p %opt::allocator option is used for maintaining the nodes.
258 The \p libcds containers actively use rebinding to convert an allocator of one type to another. Thus,
259 you may specify any valid type as std::allocator's template parameter.
261 template <typename Type>
262 struct node_allocator {
264 template <typename Base> struct pack: public Base
266 typedef Type node_allocator;
271 /// [type-option] Option setter for item counting
273 Some data structure (for example, queues) has additional feature for item counting.
274 This option allows to set up appropriate item counting policy for that data structure.
276 Predefined option \p Type:
277 - atomicity::empty_item_counter - no item counting performed. It is default policy for many
279 - atomicity::item_counter - the class that provides atomically item counting
280 - opt::v::sequential_item_counter - simple non-atomic item counter. This item counter is not intended for
281 concurrent containers and may be used only if it is explicitly noted.
283 You may provide other implementation of atomicity::item_counter interface for your needs.
285 Note, the item counting in lock-free containers cannot be exact; for example, if
286 item counter for a container returns zero it is not mean that the container is empty.
287 Thus, item counter may be used for statistical purposes only.
289 template <typename Type>
290 struct item_counter {
292 template <typename Base> struct pack: public Base
294 typedef Type item_counter;
299 /// Special alignment constants for \ref cds::opt::alignment option
300 enum special_alignment {
301 no_special_alignment = 0, ///< no special alignment
302 cache_line_alignment = 1 ///< use cache line size defined in cds/user_setup/cache_line.h
305 /// [value-option] Alignment option setter
307 Alignment for some internal data of containers. May be useful to solve false sharing problem.
308 \p Value defines desired alignment and it may be power of two integer or predefined values from
309 \ref special_alignment enum.
311 template <unsigned int Value>
314 template <typename Base> struct pack: public Base
316 enum { alignment = Value };
323 template <typename Type, unsigned int Alignment>
324 struct alignment_setter {
325 typedef typename cds::details::aligned_type< Type, Alignment >::type type;
328 template <typename Type>
329 struct alignment_setter<Type, no_special_alignment> {
333 template <typename Type>
334 struct alignment_setter<Type, cache_line_alignment> {
335 typedef typename cds::details::aligned_type< Type, c_nCacheLineSize >::type type;
337 } // namespace details
340 /// Special padding constants for \p cds::opt::padding option
341 enum special_padding {
342 no_special_padding = 0, ///< no special padding
343 cache_line_padding = 1, ///< use cache line size defined in cds/user_setup/cache_line.h
345 /// Apply padding only for tiny data of size less than required padding
347 The flag means that if your data size is less than the casheline size, the padding is applyed.
348 Otherwise no padding will be applyed.
350 This flag is applyed for padding value:
352 cds::opt::padding< cds::opt::cache_line_padding | cds::opt::padding_tiny_data_only >;
353 cds::opt::padding< 256 | cds::opt::padding_tiny_data_only >;
356 padding_tiny_data_only = 0x80000000,
359 padding_flags = padding_tiny_data_only
363 /// [value-option] Padding option setter
365 The padding for the internal data of some containers. May be useful to solve false sharing problem.
366 \p Value defines desired padding and it may be power of two integer or predefined values from
367 \p special_padding enum.
369 template <unsigned int Value>
372 template <typename Base> struct pack: public Base
374 enum { padding = Value };
381 enum padding_vs_datasize {
382 padding_datasize_less,
383 padding_datasize_equal,
384 padding_datasize_greater
387 template < typename T, unsigned int Padding, bool NoPadding, padding_vs_datasize Relation, bool TinyOnly >
388 struct apply_padding_helper;
390 template <typename T, padding_vs_datasize Relation, bool TinyOnly >
391 struct apply_padding_helper < T, 0, true, Relation, TinyOnly >
396 typedef void padding_type;
399 template <typename T, unsigned int Padding, bool TinyOnly >
400 struct apply_padding_helper < T, Padding, false, padding_datasize_equal, TinyOnly >
405 typedef void padding_type;
408 template <typename T, unsigned int Padding, bool TinyOnly >
409 struct apply_padding_helper < T, Padding, false, padding_datasize_less, TinyOnly >
411 typedef uint8_t padding_type[Padding - sizeof( T )];
419 template <typename T, unsigned int Padding >
420 struct apply_padding_helper < T, Padding, false, padding_datasize_greater, false >
422 typedef uint8_t padding_type[Padding - sizeof( T ) % Padding];
429 template <typename T, unsigned int Padding >
430 struct apply_padding_helper < T, Padding, false, padding_datasize_greater, true >
435 typedef void padding_type;
438 template <typename T, unsigned int Padding >
442 enum { padding = Padding & ~padding_flags };
445 static CDS_CONSTEXPR const size_t c_nPadding =
446 static_cast<unsigned int>(padding) == static_cast<unsigned int>(cache_line_padding) ? cds::c_nCacheLineSize :
447 static_cast<unsigned int>(padding) == static_cast<unsigned int>(no_special_padding) ? 0 : padding;
449 static_assert( (c_nPadding & (c_nPadding - 1)) == 0, "Padding must be a power-of-two number" );
451 typedef apply_padding_helper< T,
454 sizeof( T ) < c_nPadding ? padding_datasize_less : sizeof( T ) == c_nPadding ? padding_datasize_equal : padding_datasize_greater,
455 (Padding & padding_tiny_data_only) != 0
458 typedef typename result::type type;
460 typedef typename std::conditional<
461 std::is_same< typename result::padding_type, void >::value,
463 typename result::padding_type
464 >::type padding_type;
467 } // namespace details
471 /// [type-option] Generic option setter for statisitcs
473 This option sets a type to gather statistics.
474 The option is generic - no predefined type(s) is provided.
475 The particular \p Type of statistics depends on internal structure of the object.
477 template <typename Type>
480 template <typename Base> struct pack: public Base
487 /// [type-option] Option setter for C++ memory model
489 The <b>cds</b> library supports following memory ordering constraints for atomic operations in container implementation:
490 - \p v::relaxed_ordering - relaxed C++ memory model. This mode supports full set of memory ordering constraints:
491 \p memory_order_relaxed, \p memory_order_acquire, \p memory_order_release and so on.
492 - \p v::sequential_consistent - sequentially consistent C++ memory model (default memory ordering for C++). In
493 this mode any memory ordering constraint maps to \p memory_order_seq_cst.
495 The \p Type template parameter can be \p v::relaxed_ordering or \p v::sequential_consistent.
497 You may mix different memory ordering options for different containers: one declare as sequentially consistent,
498 another declare as relaxed.
499 Usually, \p v::relaxed_ordering is the default memory ordering for <b>libcds</b> containers.
501 template <typename Type>
502 struct memory_model {
504 template <typename Base> struct pack: public Base
506 typedef Type memory_model;
511 /// [type-option] Base type traits option setter
513 This option setter is intended generally for internal use for type rebinding.
515 template <typename Type>
518 template <typename Base> struct pack: public Base
520 typedef Type type_traits;
525 /// Resizing policy option
527 This option specifies the resizing policy that decides when to resize a container.
528 Used in some containers, for example, in container::StripedHashSet, intrusive::StripedHashSet.
530 The real resizing policy specified by \p Type does strongly depend on a container
531 that supports this option, see container documentation about possibly \p Type values.
533 template <typename Type>
534 struct resizing_policy {
536 template <typename Base> struct pack: public Base
538 typedef Type resizing_policy;
543 /// Copy policy option
545 The copy policy defines an item copying algorithm which is used, for example, when a container is resized.
546 It is very specific algorithm depending on type of the container.
548 template <typename Type>
551 template <typename Base> struct pack: public Base
553 typedef Type copy_policy;
558 /// Swap policy option
560 The swap policy specifies an algorithm for swapping two objects.
561 Usually, the default policy is \p std::swap (see opt::v::default_swap_policy):
565 template <typename T>
566 void operator ()( T& v1, T& v2 )
573 template <typename Type>
576 template <typename Base> struct pack: public Base
578 typedef Type swap_policy;
583 /// Move policy option
585 The move policy specifies an algorithm for moving object content.
586 In trivial case, it can be simple assignment.
588 The move interface is:
590 template <typename T>
592 void operator()( T& dest, T& src );
596 Note that in move algorithm the \p src source argument can be changed too.
597 So you can use move semantics.
599 Usually, the default move policy is opt::v::assignment_move_policy
601 template <typename Type>
604 template <typename Base> struct pack: public Base
606 typedef Type move_policy;
611 /// [value-option] Enable sorting
613 This option enables (<tt>Enable = true</tt>) or disables (<tt>Enable == false</tt>)
614 sorting of a container.
616 template <bool Enable>
619 template <typename Base> struct pack: public Base
621 static bool const sort = Enable;
626 /// [type-option] Concurrent access policy
628 This option specifies synchronization strategy for fine-grained lock-based containers.
629 The option has no predefined \p Policy type.
630 For each container that accepts this option the range of available \p Policy types
633 template <typename Policy>
634 struct mutex_policy {
636 template <typename Base> struct pack: public Base
638 typedef Policy mutex_policy;
644 /// [type-option] Random number generator
646 The option specifies a random number generator.
647 \p Random can be any STL random number generator producing
648 unsigned integer: \p std::linear_congruential_engine,
649 \p std::mersenne_twister_engine, \p std::subtract_with_carry_engine
650 and so on, or \p opt::v::c_rand.
653 template <typename Random>
654 struct random_engine {
656 template <typename Base> struct pack: public Base
658 typedef Random random_engine;
665 template <typename Accessor>
666 struct key_accessor {
667 template <typename Base> struct pack: public Base
669 typedef Accessor key_accessor;
673 template <typename Traits, typename ReplaceWith, typename WhatReplace = none >
674 struct replace_key_accessor {
675 typedef typename std::conditional<
676 std::is_same< typename Traits::key_accessor, WhatReplace >::value,
677 typename opt::key_accessor< ReplaceWith >::template pack< Traits >,
683 }} // namespace cds::opt
686 // ****************************************************
687 // Options predefined types and values
689 namespace cds { namespace opt {
691 /// Predefined options value
694 /// Sequential non-atomic item counter
696 This type of \p opt::item_counter option is not intended for concurrent containers
697 and may be used only if it is explicitly noted.
699 class sequential_item_counter
702 typedef size_t counter_type ; ///< Counter type
704 counter_type m_nCounter ; ///< Counter
707 sequential_item_counter()
711 /// Returns current value of the counter
712 counter_type value() const
717 /// Same as \ref value() with relaxed memory ordering
718 operator counter_type() const
723 /// Increments the counter. Semantics: postincrement
729 /// Decrements the counter. Semantics: postdecrement
736 counter_type operator ++()
741 counter_type operator ++(int)
747 counter_type operator --()
752 counter_type operator --(int)
757 /// Resets count to 0
764 /// Relaxed memory ordering \p opt::memory_model
766 In this ordering the memory constraints are defined according to C++ Memory Model specification:
767 each constraint is mapped to \p std::memory_order constraints one-to-one
769 struct relaxed_ordering {
771 static const atomics::memory_order memory_order_relaxed = atomics::memory_order_relaxed;
772 static const atomics::memory_order memory_order_consume = atomics::memory_order_consume;
773 static const atomics::memory_order memory_order_acquire = atomics::memory_order_acquire;
774 static const atomics::memory_order memory_order_release = atomics::memory_order_release;
775 static const atomics::memory_order memory_order_acq_rel = atomics::memory_order_acq_rel;
776 static const atomics::memory_order memory_order_seq_cst = atomics::memory_order_seq_cst;
780 /// Sequential consistent \p opt::memory_memory ordering
782 In this memory model any memory constraint is equivalent to \p std::memory_order_seq_cst.
784 struct sequential_consistent {
786 static const atomics::memory_order memory_order_relaxed = atomics::memory_order_seq_cst;
787 static const atomics::memory_order memory_order_consume = atomics::memory_order_seq_cst;
788 static const atomics::memory_order memory_order_acquire = atomics::memory_order_seq_cst;
789 static const atomics::memory_order memory_order_release = atomics::memory_order_seq_cst;
790 static const atomics::memory_order memory_order_acq_rel = atomics::memory_order_seq_cst;
791 static const atomics::memory_order memory_order_seq_cst = atomics::memory_order_seq_cst;
796 /// Totally relaxed \p opt::memory_model ordering (do not use!)
798 In this memory model any memory constraint is equivalent to \p std::memory_order_relaxed.
799 @warning Do not use this model! It intended for testing purposes only
800 to verify debugging instruments like Thread Sanitizer.
802 struct total_relaxed_ordering {
803 static const atomics::memory_order memory_order_relaxed = atomics::memory_order_relaxed;
804 static const atomics::memory_order memory_order_consume = atomics::memory_order_relaxed;
805 static const atomics::memory_order memory_order_acquire = atomics::memory_order_relaxed;
806 static const atomics::memory_order memory_order_release = atomics::memory_order_relaxed;
807 static const atomics::memory_order memory_order_acq_rel = atomics::memory_order_relaxed;
808 static const atomics::memory_order memory_order_seq_cst = atomics::memory_order_relaxed;
813 /// Default swap policy for \p opt::swap_policy option
815 The default swap policy is wrappr around \p std::swap algorithm.
817 struct default_swap_policy {
818 /// Performs swapping of \p v1 and \p v2 using \p std::swap algo
819 template <typename T>
820 void operator()( T& v1, T& v2 ) const
826 /// \p opt::move_policy based on assignment operator
827 struct assignment_move_policy
829 /// <tt> dest = src </tt>
830 template <typename T>
831 void operator()( T& dest, T const& src ) const
837 /// \p rand() -base random number generator for \p opt::random_engine
839 This generator returns a pseudorandom integer in the range 0 to \p RAND_MAX (32767).
842 typedef unsigned int result_type; ///< Result type
844 /// Constructor initializes object calling \p srand()
850 /// Returns next random number calling \p rand()
851 result_type operator()()
853 return (result_type) rand();
859 }} // namespace cds::opt
862 // ****************************************************
863 // Options metafunctions
865 namespace cds { namespace opt {
869 template <typename OptionList, typename Option>
872 // Use "pack" member template to pack options
873 typedef typename Option::template pack<OptionList> type;
876 template <typename ...T> class typelist;
878 template <typename Typelist> struct typelist_head;
879 template <typename Head, typename ...Tail>
880 struct typelist_head< typelist<Head, Tail...> > {
883 template <typename Head>
884 struct typelist_head< typelist<Head> > {
888 template <typename Typelist> struct typelist_tail;
889 template <typename Head, typename ...Tail>
890 struct typelist_tail< typelist<Head, Tail...> > {
891 typedef typelist<Tail...> type;
893 template <typename Head>
894 struct typelist_tail< typelist<Head> > {
895 typedef typelist<> type;
898 template <typename OptionList, typename Typelist>
899 struct make_options_impl {
900 typedef typename make_options_impl<
903 typename typelist_head< Typelist >::type
905 typename typelist_tail<Typelist>::type
909 template <typename OptionList>
910 struct make_options_impl<OptionList, typelist<> > {
911 typedef OptionList type;
913 } // namespace details
916 /// make_options metafunction
917 /** @headerfile cds/opt/options.h
919 The metafunction converts option list \p Options to traits structure.
920 The result of metafunction is \p type.
922 Template parameter \p OptionList is default option set (default traits).
923 \p Options is option list.
925 template <typename OptionList, typename... Options>
926 struct make_options {
927 #ifdef CDS_DOXYGEN_INVOKED
928 typedef implementation_defined type ; ///< Result of the metafunction
930 typedef typename details::make_options_impl< OptionList, details::typelist<Options...> >::type type;
935 // *****************************************************************
936 // find_type_traits metafunction
937 // *****************************************************************
941 template <typename... Options>
942 struct find_type_traits_option;
945 struct find_type_traits_option<> {
946 typedef cds::opt::none type;
949 template <typename Any>
950 struct find_type_traits_option< Any > {
951 typedef cds::opt::none type;
954 template <typename Any>
955 struct find_type_traits_option< cds::opt::type_traits< Any > > {
959 template <typename Any, typename... Options>
960 struct find_type_traits_option< cds::opt::type_traits< Any >, Options... > {
964 template <typename Any, typename... Options>
965 struct find_type_traits_option< Any, Options... > {
966 typedef typename find_type_traits_option< Options... >::type type;
968 } // namespace details
971 /// Metafunction to find opt::type_traits option in \p Options list
972 /** @headerfile cds/opt/options.h
974 If \p Options contains \p opt::type_traits option then it is the metafunction result.
975 Otherwise the result is \p DefaultOptons.
977 template <typename DefaultOptions, typename... Options>
978 struct find_type_traits {
979 typedef typename select_default< typename details::find_type_traits_option<Options...>::type, DefaultOptions>::type type ; ///< Metafunction result
983 // *****************************************************************
984 // find_option metafunction
985 // *****************************************************************
989 template <typename What, typename... Options>
995 template <typename A, typename B>
996 struct compare_option
998 typedef compare_fail type;
1001 template <template <typename> class Opt, typename A, typename B>
1002 struct compare_option< Opt<A>, Opt<B> >
1004 typedef compare_ok type;
1007 // Specializations for integral type of option
1008 #define CDS_FIND_OPTION_INTEGRAL_SPECIALIZATION_( _type ) template <template <_type> class What, _type A, _type B> \
1009 struct compare_option< What<A>, What<B> > { typedef compare_ok type ; };
1011 // For user-defined enum types
1012 #define CDS_DECLARE_FIND_OPTION_INTEGRAL_SPECIALIZATION( _type ) namespace cds { namespace opt { namespace details { CDS_FIND_OPTION_INTEGRAL_SPECIALIZATION_(_type ) }}}
1014 CDS_FIND_OPTION_INTEGRAL_SPECIALIZATION_(bool)
1015 CDS_FIND_OPTION_INTEGRAL_SPECIALIZATION_(char)
1016 CDS_FIND_OPTION_INTEGRAL_SPECIALIZATION_(unsigned char)
1017 CDS_FIND_OPTION_INTEGRAL_SPECIALIZATION_(signed char)
1018 CDS_FIND_OPTION_INTEGRAL_SPECIALIZATION_(short int)
1019 CDS_FIND_OPTION_INTEGRAL_SPECIALIZATION_(unsigned short int)
1020 CDS_FIND_OPTION_INTEGRAL_SPECIALIZATION_(int)
1021 CDS_FIND_OPTION_INTEGRAL_SPECIALIZATION_(unsigned int)
1022 CDS_FIND_OPTION_INTEGRAL_SPECIALIZATION_(long)
1023 CDS_FIND_OPTION_INTEGRAL_SPECIALIZATION_(unsigned long)
1024 CDS_FIND_OPTION_INTEGRAL_SPECIALIZATION_(long long)
1025 CDS_FIND_OPTION_INTEGRAL_SPECIALIZATION_(unsigned long long)
1028 template <typename CompResult, typename Ok, typename Fail>
1029 struct select_option
1034 template <typename Ok, typename Fail>
1035 struct select_option< compare_ok, Ok, Fail >
1040 template <typename What>
1041 struct find_option< What > {
1045 template <typename What, typename Opt>
1046 struct find_option< What, Opt > {
1047 typedef typename select_option<
1048 typename compare_option< What, Opt >::type
1054 template <typename What, typename Opt, typename... Options>
1055 struct find_option< What, Opt, Options... > {
1056 typedef typename select_option<
1057 typename compare_option< What, Opt >::type
1059 ,typename find_option< What, Options... >::type
1062 } // namespace details
1065 /// Metafunction to find \p What option in \p Options list
1066 /** @headerfile cds/opt/options.h
1068 If \p Options contains \p What< Val > option for any \p Val then the result is \p What< Val >
1069 Otherwise the result is \p What.
1073 #include <cds/opt/options.h>
1074 namespace co = cds::opt;
1080 // Find option co::tag.
1082 // res1 is co::tag< tag_a >
1083 typedef co::find_option< co::tag< default_tag >, co::gc< cds::gc::HP >, co::tag< tag_a > >::type res1;
1085 // res2 is default co::tag< default_tag >
1086 typedef co::find_option< co::tag< default_tag >, co::less< x >, co::hash< H > >::type res2;
1088 // Multiple option co::tag. The first option is selected
1089 // res3 is default co::tag< tag_a >
1090 typedef co::find_option< co::tag< default_tag >, co::tag< tag_a >, co::tag< tag_b > >::type res3;
1094 template <typename What, typename... Options>
1095 struct find_option {
1096 typedef typename details::find_option<What, Options...>::type type ; ///< Metafunction result
1100 // *****************************************************************
1101 // select metafunction
1102 // *****************************************************************
1107 template <typename What, typename... Pairs>
1110 template <typename What, typename Value>
1111 struct select< What, What, Value>
1116 template <typename What, typename Tag, typename Value>
1117 struct select<What, Tag, Value>
1122 template <typename What, typename Value, typename... Pairs>
1123 struct select< What, What, Value, Pairs...>
1128 template <typename What, typename Tag, typename Value, typename... Pairs>
1129 struct select< What, Tag, Value, Pairs...>
1131 typedef typename select<What, Pairs...>::type type;
1133 } // namespace details
1136 /// Select option metafunction
1137 /** @headerfile cds/opt/options.h
1141 select <What, T1, R1, T2, R2, ... Tn, Rn> ::=
1142 if What == T1 then return R1
1143 if What == T2 then return R2
1145 if What == Tn then return Rn
1149 template <typename What, typename... Pairs>
1151 typedef typename details::select< What, Pairs...>::type type ; ///< Metafunction result
1154 }} // namespace cds::opt
1157 #endif // #ifndef CDSLIB_OPT_OPTIONS_H