|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420 |
- /*!
- * \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/invoke.h>
- #include <utl/meta/sfinae.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__ */
|