diff --git a/include/utl/impl/concepts.h b/include/utl/core/concepts/concepts.h similarity index 100% rename from include/utl/impl/concepts.h rename to include/utl/core/concepts/concepts.h diff --git a/include/utl/helper/crtp.h b/include/utl/core/crtp.h similarity index 100% rename from include/utl/helper/crtp.h rename to include/utl/core/crtp.h diff --git a/include/utl/impl/impl.h b/include/utl/core/impl.h similarity index 100% rename from include/utl/impl/impl.h rename to include/utl/core/impl.h diff --git a/include/utl/impl/types.h b/include/utl/core/types.h similarity index 100% rename from include/utl/impl/types.h rename to include/utl/core/types.h diff --git a/include/utl/impl/version.h b/include/utl/core/version.h similarity index 100% rename from include/utl/impl/version.h rename to include/utl/core/version.h diff --git a/include/utl/meta/idx_sequence.h b/include/utl/meta/idx_sequence.h new file mode 100644 index 0000000..19b1dcc --- /dev/null +++ b/include/utl/meta/idx_sequence.h @@ -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 . + */ +#ifndef __utl_meta_idx_sequence_h__ +#define __utl_meta_idx_sequence_h__ + +#include +#include + + +/*! + * \ingroup meta + * \defgroup index_sequence + */ +//! @{ + +namespace utl { +namespace meta { + + /*! + * Class template integer_sequence + */ + template + struct integer_sequence { + using value_type = _Tp; + static constexpr size_t size() noexcept { + return sizeof...(_Idx); + } + }; + + //! Alias template index_sequence + template + using index_sequence = integer_sequence; + + //! make_integer_sequence + //! @{ + namespace detail { + // Stores a tuple of indices + template struct index_tuple { }; + + // Concatenates two index_tuples. + template struct it_cat_; + + template + struct it_cat_ , index_tuple> { + using type = index_tuple; + }; + + // Builds an index_tuple<0, 1, 2, ..., _Num-1>. + template + struct make_index_tuple_ + : it_cat_>, + type_>> + { }; + // 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>> + struct make_integer_sequence_; + + template + 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 + using make_integer_sequence = type_>; + + //! Alias template make_index_sequence + //! Complexity \f$ O(log N) \f$ + template + using make_index_sequence = make_integer_sequence; + + //! Alias template index_sequence_for + //! Complexity \f$ O(log N) \f$ + //! where N is sizeof...(_Ts) + template + using index_sequence_for = make_index_sequence; + //! @} + +}} +//! @} +#endif /* __utl_meta_idx_sequence_h__ */ diff --git a/include/utl/meta/integral.h b/include/utl/meta/integral.h index 11a2993..4dda51b 100644 --- a/include/utl/meta/integral.h +++ b/include/utl/meta/integral.h @@ -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 . */ -#ifndef __utl_meta_integral_h__ -#define __utl_meta_integral_h__ +#ifndef __utl_meta_integralconstant_h__ +#define __utl_meta_integralconstant_h__ + +#include -#include /*! * \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 + 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 - 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 - constexpr _Tp integral_<_Tp, _v>::value; -} + constexpr _Tp integral_constant<_Tp, _v>::value; + //! @} + + //! Wrappers for basic types + //! @{ + + //! integral constant + template + using integral_c = integral_constant<_Tp, _v>; + + //! bool_ type: integral constant wrapper for bool + template + using bool_ = integral_c; + + using true_ = bool_; //!< The type used as a compile-time boolean with true value. + using false_ = bool_; //!< The type used as a compile-time boolean with false value. + + //! char_ type: integral constant wrapper for \c char + template + using char_ = integral_c; + + //! int_ type: integral constant wrapper for \c int + template + using int_ = integral_c; + + //! long_ type: integral constant wrapper for \c long + template + using long_ = integral_c; + + //! index_t_ type: integral constant wrapper for \c index_t a.k.a std::size_t + template + using index_t_ = integral_c; + + //! size_t_ type: integral constant wrapper for \c size_t a.k.a std::size_t + template + using size_t_ = integral_constant; + + //! Computes the size of the type \p _Tp. + //! Complexity \f$ O(1) \f$. + template + using sizeof_ = size_t_; + + //! Computes the alignment required for any instance of the type \p _Tp. + //! Complexity \f$ O(1) \f$. + template + using alignof_ = size_t_; + //! @} + + //! The last position we can express for indexing + using Npos = size_t_; + +}} //!@} -#endif /* __utl_meta_integral_h__ */ +#endif /* __utl_meta_integralconstant_h__ */ diff --git a/include/utl/meta/invoke.h b/include/utl/meta/invoke.h new file mode 100644 index 0000000..2211b47 --- /dev/null +++ b/include/utl/meta/invoke.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 . + */ +#ifndef __utl_meta_void_h__ +#define __utl_meta_void_h__ + +#include +#include + +/*! \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 + struct is_void_ + : false_ { }; + + template<> + struct is_void_ + : true_ { }; + + template + struct is_not_void_ + : true_ { }; + + template<> + struct is_not_void_ + : false_ { }; + +} + +//!@} + +#endif /* __utl_meta_void_h__ */ diff --git a/include/utl/meta/logical.h b/include/utl/meta/logical.h index 6b8ce35..79c6df3 100644 --- a/include/utl/meta/logical.h +++ b/include/utl/meta/logical.h @@ -20,9 +20,8 @@ #ifndef __utl_meta_logical_h__ #define __utl_meta_logical_h__ -#include -#include -#include +#include +#include /*! * \ingroup meta @@ -31,51 +30,69 @@ */ //! @{ namespace utl { +namespace meta{ - //! NOT implementation - template - struct not_ : bool_ { }; + /*! + * Logical relation for types + */ + //! @{ + + //! Negate the *bool* constant parameter + template + using not_c = bool_; + + //! not + template + using not_ = not_c<_Tp::type::value>; //! OR implementation //! @{ - template struct or_; + namespace detail { + template struct _or_; - template<> - struct or_<> - : false_ { }; + template<> + struct _or_<> : false_ { }; - template - struct or_<_T1> - : _T1 { }; + template + struct _or_<_T1> : _T1 { }; - template - struct or_ <_T1, _T2> - : select_<_T1::value, _T1, _T2> { }; + template + struct _or_ <_T1, _T2> + : if_<_T1, _T1, _T2> { }; + + template + struct _or_<_T1, _T2, _T3, _Tn...> + : if_<_T1, _T1, _or_<_T2, _T3, _Tn...>> { }; + } - template - struct or_<_T1, _T2, _T3, _Tn...> - : select_<_T1::value, _T1, or_<_T2, _T3, _Tn...>> { }; + template + using or_ = type_>; //! @} //! AND implementation //! @{ - template struct and_; + namespace detail { + template struct _and_; - template<> - struct and_<> - : true_ { }; + template<> + struct _and_<> + : true_ { }; - template - struct and_ <_T1> - : _T1 { }; + template + struct _and_ <_T1> + : _T1 { }; - template - struct and_<_T1, _T2> - : select_<_T1::value, _T2, _T1> { }; + template + struct _and_<_T1, _T2> + : if_<_T1, _T2, _T1> { }; + + template + struct _and_<_T1, _T2, _T3, _Tn...> + : if_<_T1, _and_<_T2, _T3, _Tn...>, _T1> { }; + } - template - struct and_<_T1, _T2, _T3, _Tn...> - : select_<_T1::value, and_<_T2, _T3, _Tn...>, _T1> { }; + template + using and_ = type_>; //! @} //! same @@ -90,11 +107,12 @@ namespace utl { //! not same //! @{ template - struct not_same_ : true_ { }; + using not_same_ = not_>>; + //! @} - template - struct not_same_ <_Tp, _Tp> : false_ { }; //! @} -} +}} + +//! @} #endif /* __utl_meta_logical_h__ */ diff --git a/include/utl/meta/meta.h b/include/utl/meta/meta.h new file mode 100644 index 0000000..16966e5 --- /dev/null +++ b/include/utl/meta/meta.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 . + * + */ +#ifndef __utl_meta_meta_h__ +#define __utl_meta_meta_h__ + +#include +#include +#include +#include +#include +#include +#include + + +#endif /* __utl_meta_meta_h__ */ diff --git a/include/utl/meta/operations.h b/include/utl/meta/operations.h new file mode 100644 index 0000000..595f3f7 --- /dev/null +++ b/include/utl/meta/operations.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 . + */ +#ifndef __utl_meta_arithmetic_h__ +#define __utl_meta_arithmetic_h__ + +#include +#include + +/*! + * \ingroup meta + * \defgroup integral operators + * Type arithmetic and operators + */ +//! @{ + +namespace utl { +namespace meta { + + /*! + * Math operations + * requires IntegralConstant(_Tp) + */ + //! @{ + + //! Negation + template + using negate = integral_constant; + //! Addition + template + using add = integral_constant< + decltype(_Tp1() + _Tp2()), + _Tp1() + _Tp2() + >; + //! Multiplication + template + using mult = integral_constant< + decltype(_Tp2() * _Tp2()), + _Tp1() * _Tp2() + >; + //! Division + template + using divide = integral_constant< + decltype(_Tp2() / _Tp2()), + _Tp1() / _Tp2() + >; + //! Modulo + template + using modulo = integral_constant< + decltype(_Tp1() % _Tp2()), + _Tp1() % _Tp2() + >; + //! Substruction + template + using sub = add<_Tp1, negate<_Tp2>>; + + //! Increase + template + using inc = add<_Tp, int_<1>>; + + //! decrease + template + using dec = add<_Tp, int_<-1>>; + + //! @} + + /*! + * Comparison operations + * requires IntegralConstant(_Tp) + */ + //! @{ + + //! \return a true-valued Integral Constant if _Tp1 and _Tp2 are equal. + template using comp_eq = bool_<_Tp1() == _Tp2()>; + //! \return a true-valued Integral Constant if _Tp1 is less than _Tp2. + template using comp_lt = bool_<(_Tp1() < _Tp2())>; + + //! Not equal + template using comp_ne = not_>; + //! Greater than + template using comp_gt = comp_lt <_Tp2, _Tp1>; + //! Less or equal + template using comp_le = not_>; + //! Greater or equal + template using comp_ge = not_>; + //! @} + + /*! + * Bitwise operations + * requires IntegralConstant(_Tp) + */ + //! @{ + + //! \return bitwise not (~) operation of its argument. + template using bitnot_ = integral_c; + //! \return bitwise and (&) operation of its arguments + template + using bitand_ = integral_c; + //! \return bitwise or (|) operation of its arguments. + template + using bitor_ = integral_c; + + //! \return bitwise xor (^) operation of its arguments. + template + using bitxor_ = integral_c; + //! \return the result of bitwise shift left (<<) operation on _Tp. + template + using shift_left = integral_c; + //! \return the result of bitwise shift right (>>) operation on _Tp. + template + using shift_right = integral_c> shift()), (_Tp() >> shift())>; + //! @} +}} +//!@} + +#endif /* __utl_meta_integral_h__ */ diff --git a/include/utl/meta/selection.h b/include/utl/meta/selection.h new file mode 100644 index 0000000..15fe781 --- /dev/null +++ b/include/utl/meta/selection.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 . + */ +#ifndef __utl_meta_selection_h__ +#define __utl_meta_selection_h__ + +#include +#include +#include + +/*! + * \ingroup meta + * \defgroup type selection + * Type selection support header + */ +//! @{ +namespace utl { +namespace meta{ + + /*! + * Type selection + */ + //! @{ + + //! if_, if_c + //! @{ + namespace detail { + template + struct if_c_ { + using type = nil_; //!< avoid ill formed result + }; + template + struct if_c_ { + using type = Then; + }; + template + struct if_c_ { + using type = Then; + }; + template + struct if_c_ { + using type = Else; + }; + } + //! Select one type or another depending on a compile-time Boolean. + template + using if_c = type_>; + + //! Select one type or another depending on a compile-time Boolean type + template + using if_ = if_c; + + //! @} +}} + +//! @} + +#endif /* __utl_meta_selection_h__ */ diff --git a/include/utl/meta/sfinae.h b/include/utl/meta/sfinae.h index 9ec6dc1..27f775c 100644 --- a/include/utl/meta/sfinae.h +++ b/include/utl/meta/sfinae.h @@ -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 . */ -#ifndef __utl_meta_use_h__ -#define __utl_meta_use_h__ - -#include -#include +#ifndef __utl_meta_sfinae_h__ +#define __utl_meta_sfinae_h__ +#include /*! * \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 - * 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 - struct void_t_impl { - typedef void type; - }; - //! The actual void_t type alias - template - using void_t = typename void_t_impl<_Ts...>::type; + namespace detail { + template + struct when_ { }; + template <> struct when_ { using type = void; }; + } + //! Well formed only if \p If is true + template + using when = type_>; //! @} - //! Alias template for if_ - template - using if_t = typename if_<_Check, _Tp>::type; - - //! Publicly recognized alias template for if_ - template - using enable_if_t = typename if_<_Check, _Tp>::type; - - //! Uniform alias template for if_ - template - using use_if_t = typename if_<_Check, _Tp>::type; - - //! If same type resolves to _Ret, else SFINAE - template - using use_if_same_t = typename if_::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 from stl + //! @{ + template + struct enable_if { + using type = _Tp; + }; + template + struct enable_if { /* SFINAE*/ }; - //! If not same type resolves to _Ret, else SFINAE - template - using use_if_not_same_t = typename if_::value, _Ret>::type; + //! Alias template for enable_if + template + using use_if = enable_if; - //! If any type (_T1 or _T2) type resolves to _Ret, else to SFINAE - template - using use_if_any_t = typename if_::value, _Ret>::type; + //! Publicly recognized alias template for enable_if + template + using enable_if_t = type_>; - //! If both type (_T1 and _T2) type resolves to _Ret, else to SFINAE - template - using use_if_both_t = typename if_::value, _Ret>::type; + //! Uniform alias template for use_if + template + using use_if_t = type_>; + //! @} -} +}} //! @} -#endif /* __utl_meta_use_h__ */ + +#endif /* __utl_meta_sfinae_h__ */ diff --git a/include/utl/meta/typelist.h b/include/utl/meta/typelist.h new file mode 100644 index 0000000..d490b3d --- /dev/null +++ b/include/utl/meta/typelist.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 . + */ +#ifndef __utl_meta_pack_h__ +#define __utl_meta_pack_h__ + +#include +#include +#include +#include +#include + +/*! + * \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; + * + * 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 + 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 + using size = size_t_; + + /*! + * 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 + using empty = bool_; + + //! pair + //! A special typelist with only 2 Types + //! @{ + template + using pair = typelist; + + //! @} + + //! apply + //! like: + //! template + //! constexpr decltype(auto) apply(F&& f, Tuple&& t); + namespace detail { + template + struct apply_ { }; + + // apply Param =Ret(Args...) + template + struct apply_ + : invoke { }; + // apply Param = F + template class F, typename... Args> + struct apply_> + : invoke { }; + // apply Param = integer_sequence + template + struct apply_> + : invoke...> { }; + } + + //! Apply the Invocable \p Fn using the types in the type \p Param as arguments. + template + using apply = detail::apply_; + + //! @} + + /* + * ========= typelist operations ========= + */ + //! fold, rev_fold + //! @{ + namespace detail { + // fold<, V, F> == F, T2>, T3> + template + struct fold_ { }; // ill formed + + // recursive call + template + struct fold_, V, Fn> { + using type = type_< + fold_< + typelist, + invoke, + Fn + > + >; + }; + // termination call + template + struct fold_, V0, Fn> { + using type = V0; + }; + + // rev_fold<, V, F> == F>> + template + struct rev_fold_ { }; // ill formed + + // recursive call + template + struct rev_fold_, V, Fn> { + using type = invoke < + Fn, Head, type_< + rev_fold_ < + typelist, + V, + Fn + > + > + >; + }; + // termination call + template + struct rev_fold_ , V, Fn> { + using type = invoke; + }; + // termination call + template + struct rev_fold_ , V, Fn> { + using type = invoke; + }; + } + + /*! + * 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 + using fold = type_>; + + //! accumulate is an stl name for fold + template + using accumulate = fold; + + /*! + * 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 + using rev_fold = type_>; + //! @} + + //! Concatenation + //! @{ + namespace detail { + template + struct concat_ { }; + + template <> + struct concat_<> { + using type = typelist<>; + }; + + template + struct concat_> { + using type = typelist; + }; + + template + struct concat_, typelist> { + using type = typelist; + }; + + template + struct concat_, typelist, typelist> { + using type = typelist; + }; + + template + struct concat_, typelist, typelist, Rest...> + : concat_, Rest...> { }; + + template + struct concat_, typelist, typelist, typelist, Rest...> + : concat_, 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 + using concat = type_>; + //! @} + + //! Transform + //! @{ + namespace detail { + template + struct transform_ { }; + + template + struct transform_, Fn>, void_...>> { + using type = typelist...>; + }; + + template + struct transform_, typelist, Fn>, + void_...>> { + using type = typelist...>; + }; + + } // namespace detail + + /*! + * Transform One or two lists with invocable \c Fn and return a new typelist + * Syntax: + * 1) transform Unary invocable + * 2) transform Binary invocable + * Complexity \f$ O(N) \f$. + */ + template + using transform = type_>>; + //! @} + + //! repeat_n + //! @{ + namespace detail { + template + using first_ = T; + + template + struct repeat_n_c_ { }; + + template + struct repeat_n_c_> { + using type = typelist...>; + }; + } + + /*! + * Generate typelist of size \c N arguments. + * Complexity \f$ O(log N) \f$. + */ + template + using repeat_n_c = type_>>; + + /*! + * Generate typelist of size \c N::type::value arguments. + * Complexity \f$ O(log N) \f$. + */ + template + using repeat_n = repeat_n_c; + //! @} + + //! at + //! @{ + namespace detail { + + template + struct at_impl_; + + template + struct at_impl_> { + static nil_ eval(...); + + template + static T eval(VoidPtrs..., T *, Us *...); + }; + + template + struct at_ { }; + + template + struct at_, N> + : decltype( + at_impl_>::eval(static_cast *>(nullptr)...) + ) { }; + } // namespace detail + + /// Return the \p N th element in the \c meta::typelist \p L. + /// Complexity \f$ O(1) \f$. + template + using at_c = type_>; + + //! Return the \p N th element in the \c meta::typelist \p L. + //! Complexity \f$ O(1) \f$. + template + using at = at_c; + //!@} + + + //! front + //! @{ + namespace detail { + template + struct front_ { }; + + template + struct front_> { + using type = Head; + }; + } + + //! Return the first element in \c meta::typelist \p L. + //! Complexity \f$ O(1) \f$. + template + using front = type_>; + //! @} + + //! back + //! @{ + namespace detail { + template + struct back_ { }; + + template + struct back_> { + using type = at_c, sizeof...(Tail)>; + }; + } + + //! Return the last element in \c meta::typelist \p L. + //! Complexity \f$ O(1) \f$. + template + using back = type_>; + //! @} + + //! pop_front + //! @{ + namespace detail { + template + struct pop_front_ { }; + + template + struct pop_front_> { + using type = typelist; + }; + } + + /*! + * Return a new \c meta::typelist by removing the first element from the + * front of \p L. + * Complexity \f$ O(1) \f$. + */ + template + using pop_front = type_>; + //! @} + +}} + +//! @} +#endif /* __utl_meta_pack_h__ */ diff --git a/include/utl/meta/useif.h b/include/utl/meta/useif.h new file mode 100644 index 0000000..e1623b4 --- /dev/null +++ b/include/utl/meta/useif.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 . + */ +#ifndef __utl_meta_useif_h__ +#define __utl_meta_useif_h__ + +#include +#include +#include + +/*! + * \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 + using use_if_same_t = type_< + enable_if< + same_<_T1, _T2>::value, _Ret + > + >; + //! If not same type resolves to _Ret, else SFINAE + template + 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 + 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 + using use_if_both_t = type_< + enable_if< + and_<_T1, _T2>::value, _Ret + > + >; + +}} + +//! @} + +#endif /* __utl_meta_useif_h__ */ diff --git a/include/utl/meta/utility.h b/include/utl/meta/utility.h new file mode 100644 index 0000000..6c61c9a --- /dev/null +++ b/include/utl/meta/utility.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 . + */ +#ifndef __utl_meta_utility_h__ +#define __utl_meta_utility_h__ + +#include +#include +#include +#include + +/*! + * \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 + struct identity { + #if defined (UTL_WORKAROUND_CWG_1558) + // decltype via use_() using Ts... to set the apply type + template + using _dummy = void_t; + using apply = _Tp; //!< identity is invokable, must also have apply + #else + template + using apply = _Tp; //!< identity is invokable, must also have apply + #endif + using type = _Tp; //!< identity + }; + + //! identity type alias + template + using identity_t = type_>; + //! @} + + //! Is evaluable trait + //! @{ + namespace detail { + + // we check for template \p F to be a metafunction with parameters \p T + template class F, typename... T> + struct is_evaluable_ { + template class G, typename = G> + static true_ check (int); + template class> + static false_ check (...); + + using type = decltype(check(0)); + }; + + // we check for template \p F with integral constant parameters \p Is of type \p T +// template class F, T... Is> +// struct is_evaluable_i_ { +// template class G, class = G> +// static true_ check (int); +// template class> +// static false_ check (...); +// +// using type = decltype(check(0)); +// }; + } + + template class F, typename... T> + using is_evaluable = type_< + detail::is_evaluable_ + >; + +// template class F, T... Is> +// using is_evaluable_i = type_>>; + + //! @} + + //! defer + //! @{ + namespace detail { + //! @{ + template class F, typename... Ts> + struct defer_ { + using type = F; + }; + +// template class F, T... Is> +// struct defer_i_ { +// using type = F; +// }; + //! + //! We use struct instead of: + //! template class F, typename... Ts> + //! using defer_ = F; + //! + //! 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 + template class F, class... Ts> + using defer = if_< + is_evaluable, + detail::defer_, + nil_ + >; + + //! defer_i alias template for F +// template class F, T... Is> +// using defer_i = if_ < +// is_evaluable_i>, +// detail::defer_i_, +// nil_ +// >; + //! @} + + /*! + * quote is a higher-order primitive that wraps an n-ary Metafunction + * to create a corresponding Metafunction Class (Invocable). + */ + template