utl/include/utl/meta/basic.h

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__ */