Browse Source

!compile: Some meta:: rework

doc
Christos Houtouridis 5 years ago
parent
commit
031349a44d
17 changed files with 1342 additions and 131 deletions
  1. +0
    -0
      include/utl/core/concepts/concepts.h
  2. +0
    -0
      include/utl/core/crtp.h
  3. +0
    -0
      include/utl/core/impl.h
  4. +0
    -0
      include/utl/core/types.h
  5. +0
    -0
      include/utl/core/version.h
  6. +113
    -0
      include/utl/meta/idx_sequence.h
  7. +76
    -12
      include/utl/meta/integral.h
  8. +63
    -0
      include/utl/meta/invoke.h
  9. +54
    -36
      include/utl/meta/logical.h
  10. +33
    -0
      include/utl/meta/meta.h
  11. +132
    -0
      include/utl/meta/operations.h
  12. +74
    -0
      include/utl/meta/selection.h
  13. +38
    -53
      include/utl/meta/sfinae.h
  14. +420
    -0
      include/utl/meta/typelist.h
  15. +70
    -0
      include/utl/meta/useif.h
  16. +246
    -0
      include/utl/meta/utility.h
  17. +23
    -30
      include/utl/meta/void.h

include/utl/impl/concepts.h → include/utl/core/concepts/concepts.h View File


include/utl/helper/crtp.h → include/utl/core/crtp.h View File


include/utl/impl/impl.h → include/utl/core/impl.h View File


include/utl/impl/types.h → include/utl/core/types.h View File


include/utl/impl/version.h → include/utl/core/version.h View File


+ 113
- 0
include/utl/meta/idx_sequence.h View File

@@ -0,0 +1,113 @@
/*!
* \file pack.h
* \brief Template meta-programming parameter pack container
*
* Copyright (C) 2018 Christos Choutouridis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __utl_meta_idx_sequence_h__
#define __utl_meta_idx_sequence_h__
#include <utl/core/impl.h>
#include <utl/meta/integral.h>
/*!
* \ingroup meta
* \defgroup index_sequence
*/
//! @{
namespace utl {
namespace meta {
/*!
* Class template integer_sequence
*/
template<typename _Tp, _Tp... _Idx>
struct integer_sequence {
using value_type = _Tp;
static constexpr size_t size() noexcept {
return sizeof...(_Idx);
}
};
//! Alias template index_sequence
template<index_t... _Idx>
using index_sequence = integer_sequence<index_t, _Idx...>;
//! make_integer_sequence
//! @{
namespace detail {
// Stores a tuple of indices
template<size_t... Idxs> struct index_tuple { };
// Concatenates two index_tuples.
template<typename It1, typename It2> struct it_cat_;
template<size_t... It1, size_t... It2>
struct it_cat_ <index_tuple<It1...>, index_tuple<It2...>> {
using type = index_tuple<It1..., (It2 + sizeof...(It1))...>;
};
// Builds an index_tuple<0, 1, 2, ..., _Num-1>.
template<size_t _Num>
struct make_index_tuple_
: it_cat_<type_<make_index_tuple_<_Num / 2>>,
type_<make_index_tuple_<_Num - _Num / 2>>>
{ };
// termination specialization for 1
template<>
struct make_index_tuple_<1> {
using type = index_tuple<0>;
};
// termination specialization for 0
template<>
struct make_index_tuple_<0> {
using type = index_tuple<>;
};
// factory type
template<typename _Tp, _Tp _Num,
typename _ISeq = type_<make_index_tuple_<_Num>>>
struct make_integer_sequence_;
template<typename _Tp, _Tp _Num, size_t... _Idx>
struct make_integer_sequence_<_Tp, _Num, index_tuple<_Idx...>> {
static_assert( _Num >= 0,
"Cannot make integer sequence of negative length" );
using type = integer_sequence<_Tp, static_cast<_Tp>(_Idx)...>;
};
}
//! Alias template make_integer_sequence
//! Complexity \f$ O(log N) \f$
template<typename _Tp, _Tp N>
using make_integer_sequence = type_<detail::make_integer_sequence_<_Tp, N>>;
//! Alias template make_index_sequence
//! Complexity \f$ O(log N) \f$
template<index_t N>
using make_index_sequence = make_integer_sequence<index_t, N>;
//! Alias template index_sequence_for
//! Complexity \f$ O(log N) \f$
//! where N is sizeof...(_Ts)
template<typename... _Ts>
using index_sequence_for = make_index_sequence<sizeof...(_Ts)>;
//! @}
}}
//! @}
#endif /* __utl_meta_idx_sequence_h__ */

+ 76
- 12
include/utl/meta/integral.h View File

@@ -1,5 +1,5 @@
/*!
* \file integral.h
* \file integralconstant.h
* \brief Template meta-programming integral constant
*
* Copyright (C) 2018 Christos Choutouridis
@@ -17,38 +17,102 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __utl_meta_integral_h__
#define __utl_meta_integral_h__
#ifndef __utl_meta_integralconstant_h__
#define __utl_meta_integralconstant_h__
#include <utl/core/impl.h>
#include <utl/impl/impl.h>
/*!
* \ingroup meta
* \defgroup integral
* integral constand support header
* integral constant support header
*/
//! @{
namespace utl {
namespace meta {
//! Empty type
struct nil_ { };
//! Type alias for \p _Tp::type. Used to extract return type of metafunctions
template <typename _Tp>
using type_ = typename _Tp::type;
//! integral_constant
//! An Integral Constant is a holder class for a compile-time value of an integral type.
//! Every Integral Constant is also a nullary Metafunction, returning itself.
//! An integral constant object is implicitly convertible to the corresponding
//! run-time value of the wrapped integral type
//! @{
template <typename _Tp, _Tp _v>
struct integral_ {
struct integral_constant {
using value_type = _Tp;
using type = integral_<_Tp, _v>;
using type = integral_constant<_Tp, _v>;
constexpr operator value_type() const {
constexpr operator value_type() const noexcept {
return value;
}
constexpr value_type operator()() const {
constexpr value_type operator()() const noexcept {
return value;
}
static constexpr _Tp value = _v;
};
template<typename _Tp, _Tp _v>
constexpr _Tp integral_<_Tp, _v>::value;
}
constexpr _Tp integral_constant<_Tp, _v>::value;
//! @}
//! Wrappers for basic types
//! @{
//! integral constant
template <typename _Tp, _Tp _v>
using integral_c = integral_constant<_Tp, _v>;
//! bool_ type: integral constant wrapper for bool
template<bool _v>
using bool_ = integral_c<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.
//! char_ type: integral constant wrapper for \c char
template<char _v>
using char_ = integral_c<char, _v>;
//! int_ type: integral constant wrapper for \c int
template<int _v>
using int_ = integral_c<int, _v>;
//! long_ type: integral constant wrapper for \c long
template<long _v>
using long_ = integral_c<long, _v>;
//! index_t_ type: integral constant wrapper for \c index_t a.k.a std::size_t
template<index_t _v>
using index_t_ = integral_c<index_t, _v>;
//! size_t_ type: integral constant wrapper for \c size_t a.k.a std::size_t
template<size_t _v>
using size_t_ = integral_constant<size_t, _v>;
//! Computes the size of the type \p _Tp.
//! Complexity \f$ O(1) \f$.
template <typename _Tp>
using sizeof_ = size_t_<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_t_<alignof(_Tp)>;
//! @}
//! The last position we can express for indexing
using Npos = size_t_<index_t(-1)>;
}}
//!@}
#endif /* __utl_meta_integral_h__ */
#endif /* __utl_meta_integralconstant_h__ */

+ 63
- 0
include/utl/meta/invoke.h View File

@@ -0,0 +1,63 @@
/*!
* \file void.h
* \brief Template meta-programming void helpers
*
* Copyright (C) 2018 Christos Choutouridis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __utl_meta_void_h__
#define __utl_meta_void_h__
#include <utl/impl/impl.h>
#include <utl/meta/bool.h>
/*! \ingroup meta
* \defgroup void
* void_ support header
*/
//! @{
namespace utl {
/*!
* Like boost::mpl we made void_ a complete type to allow it to be
* instantiated so that it can be passed in as an object that can be
* used to select an overloaded function.
*/
struct void_ {
typedef void_ type;
};
template<typename _Tp>
struct is_void_
: false_ { };
template<>
struct is_void_ <void_>
: true_ { };
template<typename _Tp>
struct is_not_void_
: true_ { };
template<>
struct is_not_void_<void_>
: false_ { };
}
//!@}
#endif /* __utl_meta_void_h__ */

+ 54
- 36
include/utl/meta/logical.h View File

@@ -20,9 +20,8 @@
#ifndef __utl_meta_logical_h__
#define __utl_meta_logical_h__
#include <utl/impl/impl.h>
#include <utl/meta/bool.h>
#include <utl/meta/if.h>
#include <utl/core/impl.h>
#include <utl/meta/selection.h>
/*!
* \ingroup meta
@@ -31,51 +30,69 @@
*/
//! @{
namespace utl {
namespace meta{
//! NOT implementation
template<bool C_>
struct not_ : bool_<!C_> { };
/*!
* Logical relation for types
*/
//! @{
//! Negate the *bool* constant parameter
template <bool B>
using not_c = bool_<!B>;
//! not
template<typename _Tp>
using not_ = not_c<_Tp::type::value>;
//! OR implementation
//! @{
template<typename...> struct or_;
namespace detail {
template<typename...> struct _or_;
template<>
struct or_<>
: false_ { };
template<>
struct _or_<> : false_ { };
template<typename _T1>
struct or_<_T1>
: _T1 { };
template<typename _T1>
struct _or_<_T1> : _T1 { };
template<typename _T1, typename _T2>
struct or_ <_T1, _T2>
: select_<_T1::value, _T1, _T2> { };
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...>> { };
}
template<typename _T1, typename _T2, typename _T3, typename... _Tn>
struct or_<_T1, _T2, _T3, _Tn...>
: select_<_T1::value, _T1, or_<_T2, _T3, _Tn...>> { };
template <typename... _Ts>
using or_ = type_<detail::_or_<_Ts...>>;
//! @}
//! AND implementation
//! @{
template<typename...> struct and_;
namespace detail {
template<typename...> struct _and_;
template<>
struct and_<>
: true_ { };
template<>
struct _and_<>
: true_ { };
template<typename _T1>
struct and_ <_T1>
: _T1 { };
template<typename _T1>
struct _and_ <_T1>
: _T1 { };
template<typename _T1, typename _T2>
struct and_<_T1, _T2>
: select_<_T1::value, _T2, _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> { };
}
template<typename _T1, typename _T2, typename _T3, typename... _Tn>
struct and_<_T1, _T2, _T3, _Tn...>
: select_<_T1::value, and_<_T2, _T3, _Tn...>, _T1> { };
template <typename... _Ts>
using and_ = type_<detail::_and_<_Ts...>>;
//! @}
//! same
@@ -90,11 +107,12 @@ namespace utl {
//! not same
//! @{
template<typename _T1, typename _T2>
struct not_same_ : true_ { };
using not_same_ = not_<type_<same_<_T1, _T2>>>;
//! @}
template<typename _Tp>
struct not_same_ <_Tp, _Tp> : false_ { };
//! @}
}
}}
//! @}
#endif /* __utl_meta_logical_h__ */

+ 33
- 0
include/utl/meta/meta.h View File

@@ -0,0 +1,33 @@
/*!
* \file /utl/core/version.h
* \brief version and cpp version checks
*
* Copyright (C) 2018 Christos Choutouridis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef __utl_meta_meta_h__
#define __utl_meta_meta_h__
#include <utl/meta/void.h>
#include <utl/meta/integral.h>
#include <utl/meta/typelist.h>
#include <utl/meta/selection.h>
#include <utl/meta/logical.h>
#include <utl/meta/operations.h>
#include <utl/meta/useif.h>
#endif /* __utl_meta_meta_h__ */

+ 132
- 0
include/utl/meta/operations.h View File

@@ -0,0 +1,132 @@
/*!
* \file operators.h
* \brief Template meta-programming integral constant arithmetic
*
* Copyright (C) 2018 Christos Choutouridis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __utl_meta_arithmetic_h__
#define __utl_meta_arithmetic_h__
#include <utl/core/impl.h>
#include <utl/meta/logical.h>
/*!
* \ingroup meta
* \defgroup integral operators
* Type arithmetic and operators
*/
//! @{
namespace utl {
namespace meta {
/*!
* Math operations
* requires IntegralConstant(_Tp)
*/
//! @{
//! Negation
template <typename _Tp>
using negate = integral_constant<decltype(-_Tp()), -_Tp()>;
//! Addition
template <typename _Tp1, typename _Tp2>
using add = integral_constant<
decltype(_Tp1() + _Tp2()),
_Tp1() + _Tp2()
>;
//! Multiplication
template <typename _Tp1, typename _Tp2>
using mult = integral_constant<
decltype(_Tp2() * _Tp2()),
_Tp1() * _Tp2()
>;
//! Division
template <typename _Tp1, typename _Tp2>
using divide = integral_constant<
decltype(_Tp2() / _Tp2()),
_Tp1() / _Tp2()
>;
//! Modulo
template <typename _Tp1, typename _Tp2>
using modulo = integral_constant<
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>>;
//! @}
/*!
* Comparison operations
* requires IntegralConstant(_Tp)
*/
//! @{
//! \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>>;
//! @}
/*!
* Bitwise operations
* requires IntegralConstant(_Tp)
*/
//! @{
//! \return bitwise not (~) operation of its argument.
template <typename _T> using bitnot_ = integral_c<decltype(~_T()), ~_T()>;
//! \return bitwise and (&) operation of its arguments
template <typename _Tp1, typename _Tp2>
using bitand_ = integral_c<decltype(_Tp1() & _Tp2()), _Tp1() & _Tp2()>;
//! \return bitwise or (|) operation of its arguments.
template <typename _Tp1, typename _Tp2>
using bitor_ = integral_c<decltype(_Tp1() | _Tp2()), _Tp1() | _Tp2()>;
//! \return bitwise xor (^) operation of its arguments.
template <typename _Tp1, typename _Tp2>
using bitxor_ = integral_c<decltype(_Tp1() ^ _Tp2()), _Tp1() ^ _Tp2()>;
//! \return the result of bitwise shift left (<<) operation on _Tp.
template <typename _Tp, typename shift>
using shift_left = integral_c<decltype(_Tp() << shift()), (_Tp() << shift())>;
//! \return the result of bitwise shift right (>>) operation on _Tp.
template <typename _Tp, typename shift>
using shift_right = integral_c<decltype(_Tp() >> shift()), (_Tp() >> shift())>;
//! @}
}}
//!@}
#endif /* __utl_meta_integral_h__ */

+ 74
- 0
include/utl/meta/selection.h View File

@@ -0,0 +1,74 @@
/*!
* \file selection.h
* \brief Template meta-programming type selections.
*
* Copyright (C) 2018 Christos Choutouridis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __utl_meta_selection_h__
#define __utl_meta_selection_h__
#include <utl/core/impl.h>
#include <utl/meta/integral.h>
#include <utl/meta/sfinae.h>
/*!
* \ingroup meta
* \defgroup type selection
* Type selection support header
*/
//! @{
namespace utl {
namespace meta{
/*!
* Type selection
*/
//! @{
//! if_, if_c
//! @{
namespace detail {
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 = type_<detail::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...>;
//! @}
}}
//! @}
#endif /* __utl_meta_selection_h__ */

+ 38
- 53
include/utl/meta/sfinae.h View File

@@ -1,5 +1,5 @@
/*!
* \file use.h
* \file sfinae.h
* \brief Template meta-programming SFINAE helpers
*
* Copyright (C) 2018 Christos Choutouridis
@@ -17,72 +17,57 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __utl_meta_use_h__
#define __utl_meta_use_h__
#include <utl/impl/impl.h>
#include <utl/meta/logical.h>
#ifndef __utl_meta_sfinae_h__
#define __utl_meta_sfinae_h__
#include <utl/core/impl.h>
/*!
* \ingroup meta
* \defgroup use
* conditional use support header. This is a SFINAE helper
* \defgroup sfinae
* conditional use support header.
*/
//! @{
namespace utl {
namespace meta {
/*!
* void_t
* Utility meta-function that maps a sequence of any types to the type void
* \note The idea is:
* template <typename ...>
* using void_t = void;
*
* Until CWG 1558 (a C++14 defect), unused parameters in alias templates were not
* guaranteed to ensure SFINAE and could be ignored, so earlier compilers require
* a more complex definition of void_t, such as the following implementation
* https://en.cppreference.com
*/
//! Tool to enable a partial specialization only if a boolean condition is true.
//! @{
template<typename... _Ts>
struct void_t_impl {
typedef void type;
};
//! The actual void_t type alias
template<typename... _Ts>
using void_t = typename void_t_impl<_Ts...>::type;
namespace detail {
template <bool If>
struct when_ { };
template <> struct when_<true> { using type = void; };
}
//! Well formed only if \p If is true
template <bool If>
using when = type_<detail::when_<If>>;
//! @}
//! Alias template for if_
template<bool _Check, typename _Tp = void>
using if_t = typename if_<_Check, _Tp>::type;
//! Publicly recognized alias template for if_
template<bool _Check, typename _Tp = void>
using enable_if_t = typename if_<_Check, _Tp>::type;
//! Uniform alias template for if_
template<bool _Check, typename _Tp = void>
using use_if_t = typename if_<_Check, _Tp>::type;
//! If same type resolves to _Ret, else SFINAE
template <typename _T1, typename _T2, typename _Ret =_T1>
using use_if_same_t = typename if_<same_<_T1, _T2>::value, _Ret>::type;
//! select _Tp if \p If is true, else SFINAE
//! We implement eneble_if so we don't have to pull entire \c <type_traits> from stl
//! @{
template <bool If, typename _Tp = void>
struct enable_if {
using type = _Tp;
};
template<typename _Tp>
struct enable_if <false, _Tp> { /* SFINAE*/ };
//! If not same type resolves to _Ret, else SFINAE
template <typename _T1, typename _T2, typename _Ret =_T1>
using use_if_not_same_t = typename if_<!same_<_T1, _T2>::value, _Ret>::type;
//! Alias template for enable_if
template <bool If, typename _Tp = void>
using use_if = enable_if<If, _Tp>;
//! If any type (_T1 or _T2) type resolves to _Ret, else to SFINAE
template <typename _T1, typename _T2, typename _Ret =_T1>
using use_if_any_t = typename if_<or_<_T1, _T2>::value, _Ret>::type;
//! Publicly recognized alias template for enable_if
template<bool If, typename _Tp = void>
using enable_if_t = type_<enable_if<If, _Tp>>;
//! If both type (_T1 and _T2) type resolves to _Ret, else to SFINAE
template <typename _T1, typename _T2, typename _Ret =_T1>
using use_if_both_t = typename if_<and_<_T1, _T2>::value, _Ret>::type;
//! Uniform alias template for use_if
template<bool If, typename _Tp = void>
using use_if_t = type_<enable_if<If, _Tp>>;
//! @}
}
}}
//! @}
#endif /* __utl_meta_use_h__ */
#endif /* __utl_meta_sfinae_h__ */

+ 420
- 0
include/utl/meta/typelist.h View File

@@ -0,0 +1,420 @@
/*!
* \file typelist.h
* \brief A template parameter "container"
*
* Copyright (C) 2018 Christos Choutouridis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __utl_meta_pack_h__
#define __utl_meta_pack_h__
#include <utl/core/impl.h>
#include <utl/meta/integral.h>
#include <utl/meta/idx_sequence.h>
#include <utl/meta/void.h>
#include <utl/meta/utility.h>
/*!
* \ingroup meta
* \defgroup typelist
*/
//! @{
namespace utl {
namespace meta {
/*!
* A class template that just holds a parameter pack.
* The idea came from MPL's sequence concept[1] and from N4115[2].
* In addition to N4115's name "packer" we just prefer a name which is object, not a subject.
* This way the name gives the feeling of a container and smells like Python.
*
* In addition to tuple we lack members, so typelist could serve as an empty base class,
* and an object of the ultimate type could always be instantiated
* (even if the parameter typelist contains void or some type that lacks
* a default constructor).
* ex:
* using l1 = typelist<int, void*, double>;
*
* boost::hana[3] suggest a more powerful scheme were type invariant structures can be used
* for metaprograming also. This lib does not need (yet) this kind of power (we afraid the
* responsibility that comse along). So a simple python-like list with some extra vector-like
* element access functionalities and no iterators is good enough(for now).
*
* [1]: https://www.boost.org/doc/
* [2]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4115.html
* [3]: https://github.com/boostorg/hana
*/
template <typename... Ts>
struct typelist {
using type = typelist; //!< act as identity
//! \return sizeof...(Ts)
static constexpr size_t size() noexcept {
return sizeof...(Ts);
}
//! \return true if empty
static constexpr bool empty() noexcept {
return (sizeof...(Ts) == 0);
}
};
/*!
* An integral constant wrapper that is the size of the \c meta::typelist
* Complexity \f$ O(1) \f$.
* \param List A typelist
* \return The size of the typelist
*/
template <typename List>
using size = size_t_<List::size()>;
/*!
* An Boolean constant wrapper that returns if the typelist is empty
* Complexity \f$ O(1) \f$.
* \param List A typelist
* \return Empty or not
*/
template <typename List>
using empty = bool_<List::empty()>;
//! pair
//! A special typelist with only 2 Types
//! @{
template <typename T1, typename T2>
using pair = typelist<T1, T2>;
//! @}
//! apply
//! like:
//! template <class F, class Tuple>
//! constexpr decltype(auto) apply(F&& f, Tuple&& t);
namespace detail {
template <typename Fn, typename Param>
struct apply_ { };
// apply Param =Ret(Args...)
template <typename Fn, typename Ret, typename... Args>
struct apply_<Fn, Ret(Args...)>
: invoke<Fn, Ret, Args...> { };
// apply Param = F<Args...>
template <typename Fn, template <typename...> class F, typename... Args>
struct apply_<Fn, F<Args...>>
: invoke<Fn, Args...> { };
// apply Param = integer_sequence<T, Is...>
template <typename Fn, typename T, T... Is>
struct apply_<Fn, integer_sequence<T, Is...>>
: invoke<Fn, integral_constant<T, Is>...> { };
}
//! Apply the Invocable \p Fn using the types in the type \p Param as arguments.
template <typename Fn, typename Param>
using apply = detail::apply_<Fn, Param>;
//! @}
/*
* ========= typelist operations =========
*/
//! fold<List, V, Fn>, rev_fold<List, V, Fn>
//! @{
namespace detail {
// fold<<T1, T2, T3>, V, F> == F<F<F<V, T1>, T2>, T3>
template<typename, typename, typename>
struct fold_ { }; // ill formed
// recursive call
template<typename Head, typename... Tail,
typename V,
typename Fn>
struct fold_<typelist<Head, Tail...>, V, Fn> {
using type = type_<
fold_<
typelist<Tail...>,
invoke<Fn, V, Head>,
Fn
>
>;
};
// termination call
template<typename V0, typename Fn>
struct fold_<typelist<>, V0, Fn> {
using type = V0;
};
// rev_fold<<T1, T2, T3>, V, F> == F<T1, F<T2, F<T3, V>>>
template<typename, typename, typename>
struct rev_fold_ { }; // ill formed
// recursive call
template<typename Head, typename... Tail,
typename V,
typename Fn>
struct rev_fold_<typelist<Head, Tail...>, V, Fn> {
using type = invoke <
Fn, Head, type_<
rev_fold_ <
typelist<Tail...>,
V,
Fn
>
>
>;
};
// termination call
template<typename Tail, typename V, typename Fn>
struct rev_fold_ <typelist<Tail>, V, Fn> {
using type = invoke<Fn, Tail, V>;
};
// termination call
template<typename V, typename Fn>
struct rev_fold_ <typelist<>, V, Fn> {
using type = invoke<Fn, V>;
};
}
/*!
* transform the \p List to a new one by doing a left fold using binary Invocable \p Fn
* and initial value \p V
* Complexity \f$ O(N) \f$
* \param List The list to fold
* \param V The initial item feeded to Fn
* \param Fn The binary Invocable
*/
template <typename List, typename V, typename Fn>
using fold = type_<detail::fold_<List, V, Fn>>;
//! accumulate is an stl name for fold
template <typename List, typename V, typename Fn>
using accumulate = fold<List, V, Fn>;
/*!
* transform the \p List to a new one by doing a left fold using binary Invocable \p Fn
* and initial value \p V
* Complexity \f$ O(N) \f$
* \param List The list to fold
* \param V The initial item feeded to Fn
* \param Fn The binary Invocable
*/
template <typename List, typename V, typename Fn>
using rev_fold = type_<detail::rev_fold_<List, V, Fn>>;
//! @}
//! Concatenation
//! @{
namespace detail {
template <typename... Lists>
struct concat_ { };
template <>
struct concat_<> {
using type = typelist<>;
};
template <typename... L1>
struct concat_<typelist<L1...>> {
using type = typelist<L1...>;
};
template <typename... L1, typename... L2>
struct concat_<typelist<L1...>, typelist<L2...>> {
using type = typelist<L1..., L2...>;
};
template <typename... L1, typename... L2, typename... L3>
struct concat_<typelist<L1...>, typelist<L2...>, typelist<L3...>> {
using type = typelist<L1..., L2..., L3...>;
};
template <typename... L1, typename... L2, typename... L3, typename... Rest>
struct concat_<typelist<L1...>, typelist<L2...>, typelist<L3...>, Rest...>
: concat_<typelist<L1..., L2..., L3...>, Rest...> { };
template <typename... L1, typename... L2,
typename... L3, typename... L4,
typename... Rest>
struct concat_<typelist<L1...>, typelist<L2...>, typelist<L3...>, typelist<L4...>, Rest...>
: concat_<typelist<L1..., L2..., L3..., L4...>, Rest...> { };
}
/*!
* Transformation that concatenates several lists into a single typelist.
* The parameters must all be instantiations of \c meta::typelist.
* Complexity: \f$ O(L) \f$
* where \f$ L \f$ is the number of lists in the typelist of lists.
*/
template <typename... Lists>
using concat = type_<detail::concat_<Lists...>>;
//! @}
//! Transform
//! @{
namespace detail {
template <typename, typename = void>
struct transform_ { };
template <typename... Ts, typename Fn>
struct transform_<typelist<typelist<Ts...>, Fn>, void_<invoke<Fn, Ts>...>> {
using type = typelist<invoke<Fn, Ts>...>;
};
template <typename... Ts0, typename... Ts1, typename Fn>
struct transform_<typelist<typelist<Ts0...>, typelist<Ts1...>, Fn>,
void_<invoke<Fn, Ts0, Ts1>...>> {
using type = typelist<invoke<Fn, Ts0, Ts1>...>;
};
} // namespace detail
/*!
* Transform One or two lists with invocable \c Fn and return a new typelist
* Syntax:
* 1) transform<List..., Fn> Unary invocable
* 2) transform<List1, List2, Fn> Binary invocable
* Complexity \f$ O(N) \f$.
*/
template <typename... Args>
using transform = type_<detail::transform_<typelist<Args...>>>;
//! @}
//! repeat_n
//! @{
namespace detail {
template <typename T, size_t>
using first_ = T;
template <typename T, typename Ints>
struct repeat_n_c_ { };
template <typename T, size_t... Is>
struct repeat_n_c_<T, index_sequence<Is...>> {
using type = typelist<first_<T, Is>...>;
};
}
/*!
* Generate typelist<T,T,T...T> of size \c N arguments.
* Complexity \f$ O(log N) \f$.
*/
template <index_t N, typename T = void>
using repeat_n_c = type_<detail::repeat_n_c_<T, make_index_sequence<N>>>;
/*!
* Generate typelist<T,T,T...T> of size \c N::type::value arguments.
* Complexity \f$ O(log N) \f$.
*/
template <typename N, typename T = void>
using repeat_n = repeat_n_c<N::type::value, T>;
//! @}
//! at
//! @{
namespace detail {
template <typename VoidPtrs>
struct at_impl_;
template <typename... VoidPtrs>
struct at_impl_<typelist<VoidPtrs...>> {
static nil_ eval(...);
template <typename T, typename... Us>
static T eval(VoidPtrs..., T *, Us *...);
};
template <typename L, index_t N>
struct at_ { };
template <typename... Ts, index_t N>
struct at_<typelist<Ts...>, N>
: decltype(
at_impl_<repeat_n_c<N, void *>>::eval(static_cast<identity<Ts> *>(nullptr)...)
) { };
} // namespace detail
/// Return the \p N th element in the \c meta::typelist \p L.
/// Complexity \f$ O(1) \f$.
template <typename L, index_t N>
using at_c = type_<detail::at_<L, N>>;
//! Return the \p N th element in the \c meta::typelist \p L.
//! Complexity \f$ O(1) \f$.
template <typename L, typename N>
using at = at_c<L, N::type::value>;
//!@}
//! front
//! @{
namespace detail {
template <typename L>
struct front_ { };
template <typename Head, typename... Tail>
struct front_<typelist<Head, Tail...>> {
using type = Head;
};
}
//! Return the first element in \c meta::typelist \p L.
//! Complexity \f$ O(1) \f$.
template <typename L>
using front = type_<detail::front_<L>>;
//! @}
//! back
//! @{
namespace detail {
template <typename L>
struct back_ { };
template <typename Head, typename... Tail>
struct back_<typelist<Head, Tail...>> {
using type = at_c<typelist<Head, Tail...>, sizeof...(Tail)>;
};
}
//! Return the last element in \c meta::typelist \p L.
//! Complexity \f$ O(1) \f$.
template <typename L>
using back = type_<detail::back_<L>>;
//! @}
//! pop_front
//! @{
namespace detail {
template <typename L>
struct pop_front_ { };
template <typename Head, typename... L>
struct pop_front_<typelist<Head, L...>> {
using type = typelist<L...>;
};
}
/*!
* Return a new \c meta::typelist by removing the first element from the
* front of \p L.
* Complexity \f$ O(1) \f$.
*/
template <typename L>
using pop_front = type_<detail::pop_front_<L>>;
//! @}
}}
//! @}
#endif /* __utl_meta_pack_h__ */

+ 70
- 0
include/utl/meta/useif.h View File

@@ -0,0 +1,70 @@
/*!
* \file useif.h
* \brief Template meta-programming SFINAE helpers
*
* Copyright (C) 2018 Christos Choutouridis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __utl_meta_useif_h__
#define __utl_meta_useif_h__
#include <utl/core/impl.h>
#include <utl/meta/logical.h>
#include <utl/meta/sfinae.h>
/*!
* \ingroup meta
* \defgroup sfinae
* conditional use support header. This is a SFINAE wrapper
*/
//! @{
namespace utl {
namespace meta {
//! If same type resolves to _Ret, else SFINAE
template <typename _T1, typename _T2, typename _Ret =_T1>
using use_if_same_t = type_<
enable_if<
same_<_T1, _T2>::value, _Ret
>
>;
//! If not same type resolves to _Ret, else SFINAE
template <typename _T1, typename _T2, typename _Ret =_T1>
using use_if_not_same_t = type_<
enable_if<
!same_<_T1, _T2>::value, _Ret
>
>;
//! If any type (_T1 or _T2) type resolves to _Ret, else to SFINAE
template <typename _T1, typename _T2, typename _Ret =_T1>
using use_if_any_t = type_<
enable_if<
or_<_T1, _T2>::value, _Ret
>
>;
//! If both type (_T1 and _T2) type resolves to _Ret, else to SFINAE
template <typename _T1, typename _T2, typename _Ret =_T1>
using use_if_both_t = type_<
enable_if<
and_<_T1, _T2>::value, _Ret
>
>;
}}
//! @}
#endif /* __utl_meta_useif_h__ */

+ 246
- 0
include/utl/meta/utility.h View File

@@ -0,0 +1,246 @@
/*!
* \file utility.h
* \brief Template meta-programming utilities
*
* Copyright (C) 2018 Christos Choutouridis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __utl_meta_utility_h__
#define __utl_meta_utility_h__
#include <utl/core/impl.h>
#include <utl/meta/integral.h>
#include <utl/meta/void.h>
#include <utl/meta/selection.h>
/*!
* \ingroup meta
* \defgroup utility
*
*/
//! @{
namespace utl {
namespace meta{
/*!
*
* \name invoke
* All Metafunction classes shall contain apply, which is Metafunction
*
* Metafunction:
* A metafunction is a class or a class template that represents a function invocable at compile-time.
* An non-nullary metafunction is invoked by instantiating the class template with particular template
* parameters (metafunction arguments). The result of the metafunction application is accessible
* through the instantiation's nested type typedef.
* All metafunction's arguments must be types (i.e. only type template parameters are allowed).
* A metafunction can have a variable number of parameters.
* A nullary metafunction is represented as a (template) class with a nested type typename member.
*
* Metafunction Class:
* A metafunction class is a certain form of metafunction representation that enables higher-order
* metaprogramming. More precisely, it's a class with a publicly-accessible nested Metafunction called
* apply. Correspondingly, a metafunction class invocation is defined as invocation of its nested apply
* metafunction.
*
* Concept here is `Invokable` (contains apply metafunction)
*/
//! @{
/*!
* *invocable* identity, identity_t.
*/
//! @{
template <typename _Tp>
struct identity {
#if defined (UTL_WORKAROUND_CWG_1558)
// decltype via use_() using Ts... to set the apply type
template <typename... Ts>
using _dummy = void_t<Ts...>;
using apply = _Tp; //!< identity is invokable, must also have apply
#else
template <typename...>
using apply = _Tp; //!< identity is invokable, must also have apply
#endif
using type = _Tp; //!< identity
};
//! identity type alias
template <typename _Tp>
using identity_t = type_<identity<_Tp>>;
//! @}
//! Is evaluable trait
//! @{
namespace detail {
// we check for template \p F to be a metafunction with parameters \p T
template<template<typename...> class F, typename... T>
struct is_evaluable_ {
template<template<typename...> class G, typename = G<T...>>
static true_ check (int);
template<template<typename...> class>
static false_ check (...);
using type = decltype(check<F>(0));
};
// we check for template \p F with integral constant parameters \p Is of type \p T
// template<typename T, template <T...> class F, T... Is>
// struct is_evaluable_i_ {
// template<typename TT, template <TT...> class G, class = G<Is...>>
// static true_ check (int);
// template<typename, template<typename...> class>
// static false_ check (...);
//
// using type = decltype(check<T, F>(0));
// };
}
template<template<typename...> class F, typename... T>
using is_evaluable = type_<
detail::is_evaluable_<F, T...>
>;
// template <typename T, template<T...> class F, T... Is>
// using is_evaluable_i = type_<detail::is_evaluable_i_<T, F<Is...>>>;
//! @}
//! defer
//! @{
namespace detail {
//! @{
template<template<typename...> class F, typename... Ts>
struct defer_ {
using type = F<Ts...>;
};
// template<typename T, template<T...> class F, T... Is>
// struct defer_i_ {
// using type = F<Is...>;
// };
//!
//! We use struct instead of:
//! template<template<typename...> class F, typename... Ts>
//! using defer_ = F<Ts...>;
//!
//! The use of struct here is due to Core issue 1430 [1] and is used
//! as suggested by Roy Crihfield in [2].
//! In short, this is due to language's inability to expand Ts... into
//! a fixed parameter list of an alias template.
//!
//! [1]: https://wg21.link/cwg1430
//! [2]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59498
//! @}
}
//! defer alias template for F<Ts...>
template<template<class...> class F, class... Ts>
using defer = if_<
is_evaluable<F, Ts...>,
detail::defer_<F, Ts...>,
nil_
>;
//! defer_i alias template for F<T, Is...>
// template <typename T, template<T...> class F, T... Is>
// using defer_i = if_ <
// is_evaluable_i<T, F<Is...>>,
// detail::defer_i_<F, Is...>,
// nil_
// >;
//! @}
/*!
* quote is a higher-order primitive that wraps an n-ary Metafunction
* to create a corresponding Metafunction Class (Invocable).
*/
template <template <typename...> class F>
struct quote {
template <typename... Args>
using apply = type_<defer<F, Args...>>; //!< defer here to avoid DR1430
};
//! Wrap a template \p F taking literals of type \p T into an Invokable
// template <typename T, template <T...> class F>
// struct quote_i {
// // requires meta::Integral
// template <typename... Is>
// using apply = type_<
// defer_i<T, F, Is...> //!< defer here to avoid DR1430
// >;
// };
/*!
* Invoke the nested apply metafunction from \c Fn
* with the arguments \c Args.
* requires Invocable(Fn)
*/
template <typename Fn, typename... Args>
using invoke = typename Fn::template apply<Args...>;
//! compose
//! @{
namespace detail {
template<typename ...Fns> struct compose_ { };
// recursive call to all invokes
template<typename Fn0, typename ...Fns>
struct compose_<Fn0, Fns...> {
template <typename ...Args>
using apply = invoke<
Fn0,
invoke<compose_<Fns...>, Args...>
>;
};
// Termination specialization, finally pass the arguments
template<typename Fn0>
struct compose_<Fn0> {
template <typename... Args>
using apply = invoke<Fn0, Args...>;
};
}
/*!
* Create an invokable from other invokables by composition
* ex:
* compose<Fns...> will result to something like F0<F1<F2<F3<...>>>>
*/
template <typename... Fns>
using compose = detail::compose_<Fns...>;
//! @}
//! Applies the Invocable \p Fn by binding the arguments \p Ts
//! to the \e front of \p Fn.
template<typename Fn, typename... Ts>
struct bind_front {
template<typename... Us>
using apply = invoke<Fn, Ts..., Us...>;
};
//! Applies the Invocable \p Fn by binding the arguments \p Ts
//! to the \e back of \p Fn.
template<typename Fn, typename... Ts>
struct bind_back {
template<typename... Us>
using apply = invoke<Fn, Us..., Ts...>;
};
//! @}
}}
//! @}
#endif /* __utl_meta_utility_h__ */

+ 23
- 30
include/utl/meta/void.h View File

@@ -1,6 +1,6 @@
/*!
* \file void.h
* \brief Template meta-programming void helpers
* \brief void_t meta-function
*
* Copyright (C) 2018 Christos Choutouridis
*
@@ -20,44 +20,37 @@
#ifndef __utl_meta_void_h__
#define __utl_meta_void_h__
#include <utl/impl/impl.h>
#include <utl/meta/bool.h>
#include <utl/core/impl.h>
/*! \ingroup meta
/*!
* \ingroup meta
* \defgroup void
* void_ support header
*/
//! @{
namespace utl {
namespace meta {
/*!
* Like boost::mpl we made void_ a complete type to allow it to be
* instantiated so that it can be passed in as an object that can be
* used to select an overloaded function.
* void_t meta-function that maps a sequence of any types to the type void
*/
struct void_ {
typedef void_ type;
};
template<typename _Tp>
struct is_void_
: false_ { };
template<>
struct is_void_ <void_>
: true_ { };
template<typename _Tp>
struct is_not_void_
: true_ { };
template<>
struct is_not_void_<void_>
: false_ { };
}
//! @{
#if defined(UTL_WORKAROUND_CWG_1558)
template<typename... _Ts>
struct void_ {
using type = void;
};
//! void_t type alias
template<typename... _Ts>
using void_t = type_of<void_<_Ts...>>;
#else
//! void_ type alias
template <typename...> using void_ = void;
//! void_t type alias
template <typename...> using void_t = void;
#endif
//! @}
}}
//!@}
#endif /* __utl_meta_void_h__ */

Loading…
Cancel
Save