/*! * \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 #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__ */