Improved intrusive::StripedSet unit tests
[libcds.git] / cds / opt / options.h
index c893cddb823ee6fc0f62567caa37ca79c6281f32..c2d39f3e294870a40c0993b576144cbfc1226e2a 100644 (file)
@@ -1,4 +1,32 @@
-//$$CDS-header$$
+/*
+    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_OPT_OPTIONS_H
 #define CDSLIB_OPT_OPTIONS_H
         2011.01.23 khizmax  Created
 */
 
+#include <stdlib.h> // rand, srand
+
 #include <cds/details/aligned_type.h>
 #include <cds/user_setup/allocator.h>
 #include <cds/user_setup/cache_line.h>
 #include <cds/algo/atomic.h>
-#include <stdlib.h> // rand, srand
 
 namespace cds {
 
@@ -26,9 +55,6 @@ 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
     {
@@ -276,17 +302,17 @@ namespace opt {
         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 atomically item counting
+        - \p opt::v::sequential_item_counter - simple non-atomic item counter. This item 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.
+        Thus, the item counter may be used for statistical purposes only.
     */
     template <typename Type>
     struct item_counter {
@@ -298,78 +324,6 @@ namespace opt {
         //@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
@@ -408,7 +362,6 @@ namespace opt {
         struct alignment_setter<Type, cache_line_alignment> {
             typedef typename cds::details::aligned_type< Type, c_nCacheLineSize >::type  type;
         };
-
     } // namespace details
     //@endcond
 
@@ -417,7 +370,7 @@ namespace opt {
         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 of size less than required padding
+        /// 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 casheline size, the padding is applyed.
             Otherwise no padding will be applyed.
@@ -468,6 +421,7 @@ namespace opt {
             struct type {
                 T   data;
             };
+            typedef void padding_type;
         };
 
         template <typename T, unsigned int Padding, bool TinyOnly >
@@ -476,23 +430,27 @@ namespace opt {
             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;
-                uint8_t pad_[Padding - sizeof( T )];
+                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;
-                uint8_t pad_[Padding - sizeof( T ) % Padding];
+                padding_type pad_;
             };
         };
 
@@ -502,6 +460,7 @@ namespace opt {
             struct type {
                 T data;
             };
+            typedef void padding_type;
         };
 
         template <typename T, unsigned int Padding >
@@ -517,12 +476,20 @@ namespace opt {
 
             static_assert( (c_nPadding & (c_nPadding - 1)) == 0, "Padding must be a power-of-two number" );
 
-            typedef typename apply_padding_helper< T,
+            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
-            >::type type;
+            > 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
@@ -569,62 +536,6 @@ namespace opt {
         //@endcond
     };
 
-    namespace v {
-        /// Relaxed memory ordering model
-        /**
-            In this memory model the memory constraints are defined according to C++ Memory Model specification:
-            each constraint is mapped to \p std::memory_order constraints one-to-one
-
-            See \p opt::memory_model for explanations
-        */
-        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 memory ordering model
-        /**
-            In this memory model any memory constraint is equivalent to \p memory_order_seq_cst.
-
-            See \p opt::memory_model for explanations
-        */
-        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
-        };
-
-        /// Totally relaxed memory ordering model (do not use!)
-        /**
-            In this memory model any memory constraint is equivalent to \p memory_order_relaxed.
-            @warning Do not use this model! It intended for testing purposes only
-            to verify debugging instruments like Thread Sanitizer.
-
-            See \p opt::memory_model for explanations
-        */
-        struct total_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_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
-        };
-    } // namespace v
-
     /// [type-option] Base type traits option setter
     /**
         This option setter is intended generally for internal use for type rebinding.
@@ -697,22 +608,6 @@ namespace opt {
         //@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.
@@ -741,19 +636,6 @@ namespace opt {
         //@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>)
@@ -793,7 +675,7 @@ namespace opt {
         \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>
@@ -806,8 +688,181 @@ namespace opt {
         //@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).
         */
@@ -826,30 +881,305 @@ namespace opt {
                 return (result_type) 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
 
-#include <cds/opt/make_options_var.h>
 
 #endif  // #ifndef CDSLIB_OPT_OPTIONS_H