@@ -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__ */ |
@@ -1,5 +1,5 @@ | |||||
/*! | /*! | ||||
* \file integral.h | |||||
* \file integralconstant.h | |||||
* \brief Template meta-programming integral constant | * \brief Template meta-programming integral constant | ||||
* | * | ||||
* Copyright (C) 2018 Christos Choutouridis | * Copyright (C) 2018 Christos Choutouridis | ||||
@@ -17,38 +17,102 @@ | |||||
* You should have received a copy of the GNU Lesser General Public License | * 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/>. | * 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 | * \ingroup meta | ||||
* \defgroup integral | * \defgroup integral | ||||
* integral constand support header | |||||
* integral constant support header | |||||
*/ | */ | ||||
//! @{ | //! @{ | ||||
namespace utl { | 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 | //! 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> | template <typename _Tp, _Tp _v> | ||||
struct integral_ { | |||||
struct integral_constant { | |||||
using value_type = _Tp; | 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; | return value; | ||||
} | } | ||||
constexpr value_type operator()() const { | |||||
constexpr value_type operator()() const noexcept { | |||||
return value; | return value; | ||||
} | } | ||||
static constexpr _Tp value = _v; | static constexpr _Tp value = _v; | ||||
}; | }; | ||||
template<typename _Tp, _Tp _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__ */ |
@@ -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__ */ |
@@ -20,9 +20,8 @@ | |||||
#ifndef __utl_meta_logical_h__ | #ifndef __utl_meta_logical_h__ | ||||
#define __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 | * \ingroup meta | ||||
@@ -31,51 +30,69 @@ | |||||
*/ | */ | ||||
//! @{ | //! @{ | ||||
namespace utl { | 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 | //! 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 | //! 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 | //! same | ||||
@@ -90,11 +107,12 @@ namespace utl { | |||||
//! not same | //! not same | ||||
//! @{ | //! @{ | ||||
template<typename _T1, typename _T2> | 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__ */ | #endif /* __utl_meta_logical_h__ */ |
@@ -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__ */ |
@@ -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__ */ |
@@ -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__ */ |
@@ -1,5 +1,5 @@ | |||||
/*! | /*! | ||||
* \file use.h | |||||
* \file sfinae.h | |||||
* \brief Template meta-programming SFINAE helpers | * \brief Template meta-programming SFINAE helpers | ||||
* | * | ||||
* Copyright (C) 2018 Christos Choutouridis | * Copyright (C) 2018 Christos Choutouridis | ||||
@@ -17,72 +17,57 @@ | |||||
* You should have received a copy of the GNU Lesser General Public License | * 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/>. | * 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 | * \ingroup meta | ||||
* \defgroup use | |||||
* conditional use support header. This is a SFINAE helper | |||||
* \defgroup sfinae | |||||
* conditional use support header. | |||||
*/ | */ | ||||
//! @{ | //! @{ | ||||
namespace utl { | 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__ */ |
@@ -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__ */ |
@@ -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__ */ |
@@ -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__ */ |
@@ -1,6 +1,6 @@ | |||||
/*! | /*! | ||||
* \file void.h | * \file void.h | ||||
* \brief Template meta-programming void helpers | |||||
* \brief void_t meta-function | |||||
* | * | ||||
* Copyright (C) 2018 Christos Choutouridis | * Copyright (C) 2018 Christos Choutouridis | ||||
* | * | ||||
@@ -20,44 +20,37 @@ | |||||
#ifndef __utl_meta_void_h__ | #ifndef __utl_meta_void_h__ | ||||
#define __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 | * \defgroup void | ||||
* void_ support header | |||||
*/ | */ | ||||
//! @{ | //! @{ | ||||
namespace utl { | 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__ */ | #endif /* __utl_meta_void_h__ */ |