416 lines
12 KiB
C++
416 lines
12 KiB
C++
/*!
|
|
* \file utl/meta/basic.h
|
|
* \brief Template meta-programming basic definitions
|
|
*/
|
|
#ifndef __utl_meta_basic_h__
|
|
#define __utl_meta_basic_h__
|
|
|
|
#include <utl/core/impl.h>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
|
|
/*!
|
|
* \ingroup meta
|
|
* \defgroup basic Basic
|
|
* Basic definitions
|
|
*/
|
|
//! @{
|
|
|
|
/*!
|
|
* \ingroup basic
|
|
* \defgroup meta_core Core
|
|
* Core definitions
|
|
*/
|
|
//! @{
|
|
|
|
namespace utl {
|
|
namespace meta {
|
|
|
|
/*!
|
|
* \brief meta's empty type
|
|
*
|
|
* utl::meta's nil type is not pure nil. It's a recursive "de-referencable nil.
|
|
* Each time someone applies \c \::type to it, he gets back nil_. This way we can prevent
|
|
* a lot of compilation errors in a wrong meta:: handling.
|
|
*/
|
|
struct nil_ {
|
|
using type = nil_;
|
|
};
|
|
|
|
//! Type alias for \c Tp::type.
|
|
//! Is used to evaluate/extract return type of metafunctions
|
|
//! \tparam Tp The metafunction to evaluate
|
|
//! \return The inner \::type
|
|
template <typename Tp>
|
|
using eval = typename Tp::type;
|
|
|
|
//! Type alias for \c Tp::type::value.
|
|
//! Is used to evaluate/extract return value of metafunctions
|
|
//! \tparam Tp The metafunction to evaluate
|
|
//! \return The inner \::type::value
|
|
template <typename Tp>
|
|
using eval_v = typename eval<Tp>::value;
|
|
|
|
|
|
|
|
//!
|
|
//! integral_ is a holder class for a compile-time value of an integral type.
|
|
//!
|
|
//! Every Integral Constant is also a null-ary Metafunction, returning itself.\n
|
|
//! An integral constant object is implicitly convertible to the corresponding
|
|
//! run-time value of the wrapped integral type
|
|
template <typename Tp, Tp v>
|
|
using integral_ = std::integral_constant<Tp, v>;
|
|
|
|
|
|
//! \name Wrappers for basic types
|
|
//! @{
|
|
|
|
//! bool_ type: integral constant wrapper for bool
|
|
template<bool v>
|
|
using bool_ = integral_<bool, v>;
|
|
|
|
using true_ = bool_<true>; //!< The type used as a compile-time boolean with true value.
|
|
using false_ = bool_<false>; //!< The type used as a compile-time boolean with false value.
|
|
|
|
//! int8_ type: integral constant wrapper for \c int8_t
|
|
template<int8_t v>
|
|
using int8_ = integral_<int8_t, v>;
|
|
//! uint8_ type: integral constant wrapper for \c uint8_t
|
|
template<uint8_t v>
|
|
using uint8_ = integral_<uint8_t, v>;
|
|
|
|
//! int16_ type: integral constant wrapper for \c int16_t
|
|
template<int16_t v>
|
|
using int16_ = integral_<int16_t, v>;
|
|
//! uint16_ type: integral constant wrapper for \c uint16_t
|
|
template<uint16_t v>
|
|
using uint16_ = integral_<uint16_t, v>;
|
|
|
|
//! int32_ type: integral constant wrapper for \c int32_t
|
|
template<int32_t v>
|
|
using int32_ = integral_<int32_t, v>;
|
|
//! uint32_ type: integral constant wrapper for \c uint32_t
|
|
template<uint32_t v>
|
|
using uint32_ = integral_<uint32_t, v>;
|
|
|
|
//! char_ type: integral constant wrapper for \c char
|
|
template<char v>
|
|
using char_ = integral_<char, v>;
|
|
|
|
//! int_ type: integral constant wrapper for \c int
|
|
template<int v>
|
|
using int_ = integral_<int, v>;
|
|
|
|
//! long_ type: integral constant wrapper for \c long
|
|
template<long v>
|
|
using long_ = integral_<long, v>;
|
|
|
|
//! index_ type: integral constant wrapper for \c index_t a.k.a std::size_t
|
|
template<index_t v>
|
|
using index_ = integral_<index_t, v>;
|
|
|
|
//! size_ type: integral constant wrapper for \c size_t a.k.a std::size_t
|
|
template<size_t v>
|
|
using size_ = integral_<size_t, v>;
|
|
|
|
//! The last position we can express for indexing
|
|
using Npos = size_<index_t(-1)>;
|
|
//! @}
|
|
|
|
//! \name unevaluated expressions
|
|
//! @{
|
|
|
|
//! Computes the size of the type \p Tp.
|
|
//! Complexity \f$ O(1) \f$.
|
|
template <typename Tp>
|
|
using sizeof_ = size_<sizeof(Tp)>;
|
|
|
|
//! Computes the alignment required for any instance of the type \p Tp.
|
|
//! Complexity \f$ O(1) \f$.
|
|
template <typename Tp>
|
|
using alignof_ = size_<alignof(Tp)>;
|
|
//! @}
|
|
|
|
//! \name integer sequence
|
|
//! @{
|
|
template< class Tp, Tp... Ints >
|
|
using integer_sequence = std::integer_sequence<Tp, Ints...>;
|
|
|
|
template<typename Tp, Tp Num>
|
|
using make_integer_sequence = std::make_integer_sequence<Tp, Num>;
|
|
|
|
//! Alias template index_sequence
|
|
template<index_t... Idx>
|
|
using index_sequence = integer_sequence<index_t, Idx...>;
|
|
|
|
//! Alias template make_index_sequence
|
|
template<index_t Num>
|
|
using make_index_sequence = make_integer_sequence <index_t, Num>;
|
|
|
|
//! Alias template index_sequence_for
|
|
template<typename... Types>
|
|
using index_sequence_for = make_index_sequence<sizeof...(Types)>;
|
|
//! @}
|
|
}}
|
|
|
|
//!@}
|
|
|
|
/*!
|
|
* \ingroup basic
|
|
* \defgroup selection Selection
|
|
* Type selection support header
|
|
*/
|
|
//! @{
|
|
namespace utl {
|
|
namespace meta{
|
|
|
|
//! \name if implementation
|
|
//! @{
|
|
namespace details {
|
|
template <bool If, typename...>
|
|
struct if_c_ {
|
|
using type = nil_; //< avoid ill formed result
|
|
};
|
|
template<typename Then>
|
|
struct if_c_<true, Then> {
|
|
using type = Then;
|
|
};
|
|
template<typename Then, typename Else>
|
|
struct if_c_<true, Then, Else> {
|
|
using type = Then;
|
|
};
|
|
template<typename Then, typename Else>
|
|
struct if_c_<false, Then, Else> {
|
|
using type = Else;
|
|
};
|
|
}
|
|
//! Select one type or another depending on a compile-time Boolean.
|
|
template <bool B, typename... Args>
|
|
using if_c = eval<details::if_c_<B, Args...>>;
|
|
|
|
//! Select one type or another depending on a compile-time Boolean type
|
|
template <typename If, typename... Args>
|
|
using if_ = if_c<If::type::value, Args...>;
|
|
//! @}
|
|
|
|
/*!
|
|
* \name Named type selectors
|
|
*/
|
|
//! @{
|
|
|
|
//! Select the first type of a type sequence
|
|
template <typename T1, typename ...> using first_of = T1;
|
|
|
|
//! Select the second type of a type sequence
|
|
template <typename T1, typename T2, typename ...> using second_of = T2;
|
|
//! @}
|
|
}}
|
|
|
|
//! @}
|
|
|
|
|
|
|
|
/*!
|
|
* \ingroup basic
|
|
* \defgroup logic_operations Logic Operations
|
|
* logic operators and type relations support
|
|
*/
|
|
//! @{
|
|
namespace utl {
|
|
namespace meta{
|
|
|
|
/*!
|
|
* \name Logical relation for types
|
|
*/
|
|
//! @{
|
|
|
|
//! Negate the *bool* constant parameter and return bool_
|
|
template <bool B>
|
|
using not_c = bool_<!B>;
|
|
|
|
//! negate the bool_ parameter and return bool_
|
|
template<typename Tp>
|
|
using not_ = not_c<Tp::type::value>;
|
|
|
|
//! \name OR implementation
|
|
//! @{
|
|
namespace details {
|
|
template<typename...> struct _or_;
|
|
|
|
template<>
|
|
struct _or_<> : false_ { };
|
|
|
|
template<typename T1>
|
|
struct _or_<T1> : T1 { };
|
|
|
|
template<typename T1, typename T2>
|
|
struct _or_ <T1, T2>
|
|
: if_<T1, T1, T2> { };
|
|
|
|
template<typename T1, typename T2, typename T3, typename... Tn>
|
|
struct _or_<T1, T2, T3, Tn...>
|
|
: if_<T1, T1, _or_<T2, T3, Tn...>> { };
|
|
}
|
|
|
|
//! Operator or for bool_ types
|
|
//! \tparam Ts Variadic args of type bool_
|
|
//! \return Logical or as bool_
|
|
template <typename... Ts>
|
|
using or_ = eval<details::_or_<Ts...>>;
|
|
//! @}
|
|
|
|
//! \name AND implementation
|
|
//! @{
|
|
namespace details {
|
|
template<typename...> struct _and_;
|
|
|
|
template<>
|
|
struct _and_<>
|
|
: true_ { };
|
|
|
|
template<typename T1>
|
|
struct _and_ <T1>
|
|
: T1 { };
|
|
|
|
template<typename T1, typename T2>
|
|
struct _and_<T1, T2>
|
|
: if_<T1, T2, T1> { };
|
|
|
|
template<typename T1, typename T2, typename T3, typename... Tn>
|
|
struct _and_<T1, T2, T3, Tn...>
|
|
: if_<T1, _and_<T2, T3, Tn...>, T1> { };
|
|
}
|
|
|
|
//! Operator and for bool_ types
|
|
//! \tparam Ts Variadic args of type bool_
|
|
//! \return Logical and as bool_
|
|
template <typename... Ts>
|
|
using and_ = eval<details::_and_<Ts...>>;
|
|
//! @}
|
|
|
|
//! \name same
|
|
//! @{
|
|
template<typename T1, typename T2>
|
|
struct same_ : false_ { };
|
|
|
|
template<typename Tp>
|
|
struct same_ <Tp, Tp> : true_ { };
|
|
|
|
template<typename T1, typename T2>
|
|
using not_same_ = not_<eval<same_<T1, T2>>>;
|
|
//! @}
|
|
|
|
//! @}
|
|
}}
|
|
|
|
//! @}
|
|
|
|
|
|
/*!
|
|
* \ingroup basic
|
|
* \defgroup integral_operators integral operators
|
|
* Type arithmetic and operations
|
|
*/
|
|
//! @{
|
|
|
|
namespace utl {
|
|
namespace meta {
|
|
|
|
/*!
|
|
* \name Math operations
|
|
*/
|
|
//! @{
|
|
|
|
//! Negation
|
|
template <typename Tp>
|
|
using negate = integral_<decltype(-Tp()), -Tp()>;
|
|
//! Addition
|
|
template <typename Tp1, typename Tp2>
|
|
using add = integral_<
|
|
decltype(Tp1() + Tp2()),
|
|
Tp1() + Tp2()
|
|
>;
|
|
//! Multiplication
|
|
template <typename Tp1, typename Tp2>
|
|
using mult = integral_<
|
|
decltype(Tp2() * Tp2()),
|
|
Tp1() * Tp2()
|
|
>;
|
|
//! Division
|
|
template <typename Tp1, typename Tp2>
|
|
using divide = integral_<
|
|
decltype(Tp2() / Tp2()),
|
|
Tp1() / Tp2()
|
|
>;
|
|
//! Modulo
|
|
template <typename Tp1, typename Tp2>
|
|
using modulo = integral_<
|
|
decltype(Tp1() % Tp2()),
|
|
Tp1() % Tp2()
|
|
>;
|
|
//! Substruction
|
|
template <typename Tp1, typename Tp2>
|
|
using sub = add<Tp1, negate<Tp2>>;
|
|
|
|
//! Increase
|
|
template <typename Tp>
|
|
using inc = add<Tp, int_<1>>;
|
|
|
|
//! decrease
|
|
template <typename Tp>
|
|
using dec = add<Tp, int_<-1>>;
|
|
|
|
//! @}
|
|
|
|
/*!
|
|
* \name Comparison operations
|
|
*/
|
|
//! @{
|
|
|
|
//! \return a true-valued Integral Constant if Tp1 and Tp2 are equal.
|
|
template <typename Tp1, typename Tp2> using comp_eq = bool_<Tp1() == Tp2()>;
|
|
//! \return a true-valued Integral Constant if Tp1 is less than Tp2.
|
|
template <typename Tp1, typename Tp2> using comp_lt = bool_<(Tp1() < Tp2())>;
|
|
|
|
//! Not equal
|
|
template <typename Tp1, typename Tp2> using comp_ne = not_<comp_eq<Tp1, Tp2>>;
|
|
//! Greater than
|
|
template <typename Tp1, typename Tp2> using comp_gt = comp_lt <Tp2, Tp1>;
|
|
//! Less or equal
|
|
template <typename Tp1, typename Tp2> using comp_le = not_<comp_lt<Tp2, Tp1>>;
|
|
//! Greater or equal
|
|
template <typename Tp1, typename Tp2> using comp_ge = not_<comp_lt<Tp1, Tp2>>;
|
|
//! @}
|
|
|
|
/*!
|
|
* \name Bitwise operations
|
|
*/
|
|
//! @{
|
|
|
|
//! \return bitwise not (~) operation of its argument.
|
|
template <typename T> using bitnot_ = integral_<typename T::value_type, (typename T::value_type)(~T())>;
|
|
//! \return bitwise and (&) operation of its arguments
|
|
template <typename Tp1, typename Tp2>
|
|
using bitand_ = integral_<decltype(Tp1() & Tp2()), Tp1() & Tp2()>;
|
|
//! \return bitwise or (|) operation of its arguments.
|
|
template <typename Tp1, typename Tp2>
|
|
using bitor_ = integral_<decltype(Tp1() | Tp2()), Tp1() | Tp2()>;
|
|
|
|
//! \return bitwise xor (^) operation of its arguments.
|
|
template <typename Tp1, typename Tp2>
|
|
using bitxor_ = integral_<decltype(Tp1() ^ Tp2()), Tp1() ^ Tp2()>;
|
|
//! \return the result of bitwise shift left (<<) operation on Tp.
|
|
template <typename Tp, typename shift>
|
|
using shift_left = integral_<typename Tp::value_type, (typename Tp::value_type)(Tp() << shift())>;
|
|
//! \return the result of bitwise shift right (>>) operation on Tp.
|
|
template <typename Tp, typename shift>
|
|
using shift_right = integral_<typename Tp::value_type, (typename Tp::value_type)(Tp() >> shift())>;
|
|
//! @}
|
|
}}
|
|
//! @}
|
|
|
|
//! @}
|
|
|
|
#endif /* __utl_meta_basic_h__ */
|