/// \file meta.hpp Tiny meta-programming library. // // Meta library // // Copyright Eric Niebler 2014-present // // Use, modification and distribution is subject to the // Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // Project home: https://github.com/ericniebler/meta // #ifndef META_HPP #define META_HPP #include #include #include #include #include #ifdef __clang__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunknown-pragmas" #pragma GCC diagnostic ignored "-Wpragmas" #pragma GCC diagnostic ignored "-Wdocumentation-deprecated-sync" #pragma GCC diagnostic ignored "-Wmissing-variable-declarations" #endif /// \defgroup meta Meta /// /// A tiny metaprogramming library /// \defgroup trait Trait /// Trait invocation/composition. /// \ingroup meta /// \defgroup invocation Invocation /// Trait invocation /// \ingroup trait /// \defgroup composition Composition /// Trait composition /// \ingroup trait /// \defgroup logical Logical /// Logical operations /// \ingroup meta /// \defgroup algorithm Algorithms /// Algorithms. /// \ingroup meta /// \defgroup query Query/Search /// Query and search algorithms /// \ingroup algorithm /// \defgroup transformation Transformation /// Transformation algorithms /// \ingroup algorithm /// \defgroup runtime Runtime /// Runtime algorithms /// \ingroup algorithm /// \defgroup datatype Datatype /// Datatypes. /// \ingroup meta /// \defgroup list list_like /// \ingroup datatype /// \defgroup integral Integer sequence /// Equivalent to C++14's `std::integer_sequence` /// \ingroup datatype /// \defgroup extension Extension /// Extend meta with your own datatypes. /// \ingroup datatype /// \defgroup math Math /// Integral constant arithmetic. /// \ingroup meta /// \defgroup lazy_trait lazy /// \ingroup trait /// \defgroup lazy_invocation lazy /// \ingroup invocation /// \defgroup lazy_composition lazy /// \ingroup composition /// \defgroup lazy_logical lazy /// \ingroup logical /// \defgroup lazy_query lazy /// \ingroup query /// \defgroup lazy_transformation lazy /// \ingroup transformation /// \defgroup lazy_list lazy /// \ingroup list /// \defgroup lazy_datatype lazy /// \ingroup datatype /// \defgroup lazy_math lazy /// \ingroup math /// Tiny metaprogramming library namespace meta { namespace detail { /// Returns a \p T nullptr template constexpr T *_nullptr_v() { return nullptr; } #if META_CXX_VARIABLE_TEMPLATES template META_INLINE_VAR constexpr T *nullptr_v = nullptr; #endif } // namespace detail /// An empty type. /// \ingroup datatype struct nil_ { }; /// Type alias for \p T::type. /// \ingroup invocation template using _t = typename T::type; #if META_CXX_VARIABLE_TEMPLATES || defined(META_DOXYGEN_INVOKED) /// Variable alias for \c T::type::value /// \note Requires C++14 or greater. /// \ingroup invocation template constexpr typename T::type::value_type _v = T::type::value; #endif /// Lazy versions of meta actions namespace lazy { /// \sa `meta::_t` /// \ingroup lazy_invocation template using _t = defer<_t, T>; } // namespace lazy /// An integral constant wrapper for \c std::size_t. /// \ingroup integral template using size_t = std::integral_constant; /// An integral constant wrapper for \c bool. /// \ingroup integral template using bool_ = std::integral_constant; /// An integral constant wrapper for \c int. /// \ingroup integral template using int_ = std::integral_constant; /// An integral constant wrapper for \c char. /// \ingroup integral template using char_ = std::integral_constant; /////////////////////////////////////////////////////////////////////////////////////////// // Math operations /// An integral constant wrapper around the result of incrementing the wrapped integer \c /// T::type::value. template using inc = std::integral_constant; /// An integral constant wrapper around the result of decrementing the wrapped integer \c /// T::type::value. template using dec = std::integral_constant; /// An integral constant wrapper around the result of adding the two wrapped integers /// \c T::type::value and \c U::type::value. /// \ingroup math template using plus = std::integral_constant; /// An integral constant wrapper around the result of subtracting the two wrapped integers /// \c T::type::value and \c U::type::value. /// \ingroup math template using minus = std::integral_constant; /// An integral constant wrapper around the result of multiplying the two wrapped integers /// \c T::type::value and \c U::type::value. /// \ingroup math template using multiplies = std::integral_constant; /// An integral constant wrapper around the result of dividing the two wrapped integers \c /// T::type::value and \c U::type::value. /// \ingroup math template using divides = std::integral_constant; /// An integral constant wrapper around the result of negating the wrapped integer /// \c T::type::value. /// \ingroup math template using negate = std::integral_constant; /// An integral constant wrapper around the remainder of dividing the two wrapped integers /// \c T::type::value and \c U::type::value. /// \ingroup math template using modulus = std::integral_constant; /// A Boolean integral constant wrapper around the result of comparing \c T::type::value and /// \c U::type::value for equality. /// \ingroup math template using equal_to = bool_; /// A Boolean integral constant wrapper around the result of comparing \c T::type::value and /// \c U::type::value for inequality. /// \ingroup math template using not_equal_to = bool_; /// A Boolean integral constant wrapper around \c true if \c T::type::value is greater than /// \c U::type::value; \c false, otherwise. /// \ingroup math template using greater = bool_<(T::type::value > U::type::value)>; /// A Boolean integral constant wrapper around \c true if \c T::type::value is less than \c /// U::type::value; \c false, otherwise. /// \ingroup math template using less = bool_<(T::type::value < U::type::value)>; /// A Boolean integral constant wrapper around \c true if \c T::type::value is greater than /// or equal to \c U::type::value; \c false, otherwise. /// \ingroup math template using greater_equal = bool_<(T::type::value >= U::type::value)>; /// A Boolean integral constant wrapper around \c true if \c T::type::value is less than or /// equal to \c U::type::value; \c false, otherwise. /// \ingroup math template using less_equal = bool_<(T::type::value <= U::type::value)>; /// An integral constant wrapper around the result of bitwise-and'ing the two wrapped /// integers \c T::type::value and \c U::type::value. /// \ingroup math template using bit_and = std::integral_constant; /// An integral constant wrapper around the result of bitwise-or'ing the two wrapped /// integers \c T::type::value and \c U::type::value. /// \ingroup math template using bit_or = std::integral_constant; /// An integral constant wrapper around the result of bitwise-exclusive-or'ing the two /// wrapped integers \c T::type::value and \c U::type::value. /// \ingroup math template using bit_xor = std::integral_constant; /// An integral constant wrapper around the result of bitwise-complementing the wrapped /// integer \c T::type::value. /// \ingroup math template using bit_not = std::integral_constant; namespace lazy { /// \sa 'meta::int' /// \ingroup lazy_math template using inc = defer; /// \sa 'meta::dec' /// \ingroup lazy_math template using dec = defer; /// \sa 'meta::plus' /// \ingroup lazy_math template using plus = defer; /// \sa 'meta::minus' /// \ingroup lazy_math template using minus = defer; /// \sa 'meta::multiplies' /// \ingroup lazy_math template using multiplies = defer; /// \sa 'meta::divides' /// \ingroup lazy_math template using divides = defer; /// \sa 'meta::negate' /// \ingroup lazy_math template using negate = defer; /// \sa 'meta::modulus' /// \ingroup lazy_math template using modulus = defer; /// \sa 'meta::equal_to' /// \ingroup lazy_math template using equal_to = defer; /// \sa 'meta::not_equal_t' /// \ingroup lazy_math template using not_equal_to = defer; /// \sa 'meta::greater' /// \ingroup lazy_math template using greater = defer; /// \sa 'meta::less' /// \ingroup lazy_math template using less = defer; /// \sa 'meta::greater_equal' /// \ingroup lazy_math template using greater_equal = defer; /// \sa 'meta::less_equal' /// \ingroup lazy_math template using less_equal = defer; /// \sa 'meta::bit_and' /// \ingroup lazy_math template using bit_and = defer; /// \sa 'meta::bit_or' /// \ingroup lazy_math template using bit_or = defer; /// \sa 'meta::bit_xor' /// \ingroup lazy_math template using bit_xor = defer; /// \sa 'meta::bit_not' /// \ingroup lazy_math template using bit_not = defer; } // namespace lazy /// \cond namespace detail { enum class indices_strategy_ { done, repeat, recurse }; constexpr indices_strategy_ strategy_(std::size_t cur, std::size_t end) { return cur >= end ? indices_strategy_::done : cur * 2 <= end ? indices_strategy_::repeat : indices_strategy_::recurse; } template constexpr std::size_t range_distance_(T begin, T end) { return begin <= end ? static_cast(end - begin) : throw "The start of the integer_sequence must not be " "greater than the end"; } template struct make_indices_ { using type = State; }; template struct coerce_indices_ { }; } // namespace detail /// \endcond /////////////////////////////////////////////////////////////////////////////////////////// // integer_sequence #if !META_CXX_INTEGER_SEQUENCE /// A container for a sequence of compile-time integer constants. /// \ingroup integral template struct integer_sequence { using value_type = T; /// \return `sizeof...(Is)` static constexpr std::size_t size() noexcept { return sizeof...(Is); } }; #endif /////////////////////////////////////////////////////////////////////////////////////////// // index_sequence /// A container for a sequence of compile-time integer constants of type /// \c std::size_t /// \ingroup integral template using index_sequence = integer_sequence; #if META_HAS_MAKE_INTEGER_SEQ && !defined(META_DOXYGEN_INVOKED) // Implement make_integer_sequence and make_index_sequence with the // __make_integer_seq builtin on compilers that provide it. (Redirect // through decltype to workaround suspected clang bug.) /// \cond namespace detail { template __make_integer_seq make_integer_sequence_(); } /// \endcond template using make_integer_sequence = decltype(detail::make_integer_sequence_()); template using make_index_sequence = make_integer_sequence; #else /// Generate \c index_sequence containing integer constants [0,1,2,...,N-1]. /// \par Complexity /// `O(log(N))`. /// \ingroup integral template using make_index_sequence = _t, detail::strategy_(1, N)>>; /// Generate \c integer_sequence containing integer constants [0,1,2,...,N-1]. /// \par Complexity /// `O(log(N))`. /// \ingroup integral template using make_integer_sequence = _t(N)>>>; #endif /////////////////////////////////////////////////////////////////////////////////////////// // integer_range /// Makes the integer sequence `[From, To)`. /// \par Complexity /// `O(log(To - From))`. /// \ingroup integral template using integer_range = _t>>; /// \cond namespace detail { template struct concat_indices_ { }; template struct concat_indices_, index_sequence> { using type = index_sequence; }; template <> struct make_indices_<0u, index_sequence<0>, indices_strategy_::done> { using type = index_sequence<>; }; template struct make_indices_, indices_strategy_::repeat> : make_indices_, detail::strategy_(sizeof...(Values) * 2, End)> { }; template struct make_indices_, indices_strategy_::recurse> : concat_indices_, make_index_sequence> { }; template struct coerce_indices_> { using type = integer_sequence(static_cast(Values) + Offset)...>; }; } // namespace detail /// \endcond /// Evaluate the invocable \p Fn with the arguments \p Args. /// \ingroup invocation template using invoke = typename Fn::template invoke; /// Lazy versions of meta actions namespace lazy { /// \sa `meta::invoke` /// \ingroup lazy_invocation template using invoke = defer; } // namespace lazy /// A trait that always returns its argument \p T. It is also an invocable /// that always returns \p T. /// \ingroup trait /// \ingroup invocation template struct id { #if defined(META_WORKAROUND_CWG_1558) && !defined(META_DOXYGEN_INVOKED) // Redirect through decltype for compilers that have not // yet implemented CWG 1558: static id impl(void *); template using invoke = _t *>(nullptr)))>; #else template using invoke = T; #endif using type = T; }; /// An alias for type \p T. Useful in non-deduced contexts. /// \ingroup trait template using id_t = _t>; namespace lazy { /// \sa `meta::id` /// \ingroup lazy_trait /// \ingroup lazy_invocation template using id = defer; } // namespace lazy /// An alias for `void`. /// \ingroup trait #if defined(META_WORKAROUND_CWG_1558) && !defined(META_DOXYGEN_INVOKED) // Redirect through decltype for compilers that have not // yet implemented CWG 1558: template using void_ = invoke, Ts...>; #else template using void_ = void; #endif #if META_CXX_VARIABLE_TEMPLATES #ifdef META_CONCEPT /// `true` if `T::type` exists and names a type; `false` otherwise. /// \ingroup trait template META_INLINE_VAR constexpr bool is_trait_v = trait; /// `true` if `T::invoke` exists and names a class template; `false` otherwise. /// \ingroup trait template META_INLINE_VAR constexpr bool is_callable_v = invocable; #else // ^^^ Concepts / No concepts vvv /// \cond namespace detail { template META_INLINE_VAR constexpr bool is_trait_ = false; template META_INLINE_VAR constexpr bool is_trait_> = true; template META_INLINE_VAR constexpr bool is_callable_ = false; template META_INLINE_VAR constexpr bool is_callable_>> = true; } // namespace detail /// \endcond /// `true` if `T::type` exists and names a type; `false` otherwise. /// \ingroup trait template META_INLINE_VAR constexpr bool is_trait_v = detail::is_trait_; /// `true` if `T::invoke` exists and names a class template; `false` otherwise. /// \ingroup trait template META_INLINE_VAR constexpr bool is_callable_v = detail::is_callable_; #endif // Concepts vs. variable templates /// An alias for `std::true_type` if `T::type` exists and names a type; otherwise, it's an /// alias for `std::false_type`. /// \ingroup trait template using is_trait = bool_>; /// An alias for `std::true_type` if `T::invoke` exists and names a class template; /// otherwise, it's an alias for `std::false_type`. /// \ingroup trait template using is_callable = bool_>; #else // ^^^ META_CXX_VARIABLE_TEMPLATES / !META_CXX_VARIABLE_TEMPLATES vvv /// \cond namespace detail { template struct is_trait_ { using type = std::false_type; }; template struct is_trait_> { using type = std::true_type; }; template struct is_callable_ { using type = std::false_type; }; template struct is_callable_>> { using type = std::true_type; }; } // namespace detail /// \endcond template using is_trait = _t>; /// An alias for `std::true_type` if `T::invoke` exists and names a class /// template or alias template; otherwise, it's an alias for /// `std::false_type`. /// \ingroup trait template using is_callable = _t>; #endif /// \cond namespace detail { #ifdef META_CONCEPT template