From 533a09625cf0f2f290ec81065de5dc94b75b7563 Mon Sep 17 00:00:00 2001 From: Christos Houtouridis Date: Tue, 29 Jan 2019 16:01:57 +0200 Subject: [PATCH] meta: a draft version of typelist and operations for it --- include/utl/meta/typelist.h | 818 +++++++++++++++++++++++++++--------- test/tests/Tmeta.cpp | 241 ++++++++++- 2 files changed, 850 insertions(+), 209 deletions(-) diff --git a/include/utl/meta/typelist.h b/include/utl/meta/typelist.h index d40e8bd..62111e9 100644 --- a/include/utl/meta/typelist.h +++ b/include/utl/meta/typelist.h @@ -36,7 +36,9 @@ namespace utl { namespace meta { /*! - * A class template that just holds a parameter pack. + * \brief + * 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. @@ -45,12 +47,15 @@ namespace meta { * 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; + * \example + * \code + * using l1 = typelist; + * l1 a {}; + * \endcode * * 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 + * responsibility that come 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/ @@ -69,11 +74,43 @@ namespace meta { static constexpr bool empty() noexcept { return (sizeof...(Ts) == 0); } + // ======= times utility ======= + private: + template + struct times_ { }; + + template + struct times_, Ts...> { + // append one and recurse + using type = type_< + if_c , Ts...>, + typelist + >>; + }; + public: + /*! + * Generate typelist of size \c N arguments. + * \example + * \code + * static_assert ( + * std::is_same::times<2>, + * typelist + * >, "" ); + * \endcode + * complexity \f$ O(N) \f$ + */ + template + using times = type_< + times_, Ts...> + >; }; /*! * 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 */ @@ -82,7 +119,9 @@ namespace meta { /*! * An Boolean constant wrapper that returns if the typelist is empty + * * Complexity \f$ O(1) \f$. + * * \param List A typelist * \return Empty or not */ @@ -91,46 +130,205 @@ namespace meta { //! pair //! A special typelist with only 2 Types - //! @{ template using pair = typelist; + + //! repeat + //! @{ + + /*! + * A wrapper to typelist<>::times<> utility for integer argument \p N + */ + template + using repeat_c = typename typelist::template times; + + /*! + * A wrapper to typelist<>::times<> utility for integral_c argument \p N + */ + template + using repeat = repeat_c; //! @} - //! apply - //! like: - //! template - //! constexpr decltype(auto) apply(F&& f, Tuple&& t); - namespace detail { - template + /*! + * Apply + */ + //! @{ + namespace apply_impl { + 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 + //! \p Sequence == typelist<> + template + struct apply_> { + using type = invoke; + }; + //! Sequence == integer_sequence<> template - struct apply_> - : invoke...> { }; + struct apply_> { + using type = invoke...>; + }; } - //! Apply the Invocable \p Fn using the types in the type \p Param as arguments. - template - using apply = detail::apply_; + /*! + * Apply the Invocable \p Fn using the types in the type \p Seq as arguments. + * \note + * This is the opposed operation of typelist + * + * If \p Seq == typelist<> then + * Unpack typelist and apply to \c Fn + * It \p Seq == integer_sequence<> then + * Unpack and use the integral_c<> of each integer + */ + template + using apply = apply_impl::apply_; //! @} + /* + * ========= element access ======== + */ + //! at: random element access + //! @{ + namespace at_impl { + + template struct _as_pointer__ { using type = T*; }; + template struct _as_pointer__ { using type = T*; }; + template using as_pointer_ = type_< + _as_pointer__ + >; + + template + struct at_head_ { }; + + template + struct at_head_ > { + // successful selection N voids, one T* and the rest + template static constexpr T select(voids..., T*, ...); + // selection on error + static constexpr nil_ select (...); + }; + + template + struct at_ { }; + + template + struct at_, N> { + using head_ = at_head_::times>; //< make at_head_<> with N void* + using type = decltype( + head_::select(static_cast>(nullptr)...) //< pass all as List*... + ); + }; + } + + /*! + * Return the \p N th element in the \c meta::typelist \p List. + * + * Complexity \f$ O(N) \f$. + */ + template + using at_c = type_< + at_impl::at_ + >; + + /*! + * Return the \p N th element in the \c meta::typelist \p List. + * + * Complexity \f$ O(N) \f$. + */ + template + using at = at_c; + //!@} + + + //! front + //! @{ + namespace front_impl { + template + struct front_ { }; + + template + struct front_> { + using type = Head; + }; + } + + //! Return the first element in \c meta::typelist \p List. + //! Complexity \f$ O(1) \f$. + template + using front = type_< + front_impl::front_ + >; + //! @} + + //! back + //! @{ + namespace back_impl { + template + struct back_ { }; + + template + struct back_> { + using type = at_c < + typelist, sizeof...(Tail) + >; + }; + } + + //! Return the last element in \c meta::typelist \p List. + //! Complexity \f$ O(N) \f$. + template + using back = type_< + back_impl::back_ + >; + //! @} /* * ========= typelist operations ========= */ + + //! Concatenation + //! @{ + namespace cat_impl { + template + struct cat_ { }; + + template <> + struct cat_<> { + using type = typelist<>; + }; + + template + struct cat_> { + using type = typelist; + }; + + template + struct cat_, typelist> { + using type = typelist; + }; + + template + struct cat_, typelist, Ln...> + : cat_ , Ln...> { }; + + } + + /*! + * Transformation that concatenates several lists into a single typelist. + * The parameters must all be instantiations of \c meta::typelist. + * Complexity: \f$ O(N) \f$ + * where \f$ N \f$ is the number of lists passed to the algorithm. + */ + template + using cat = type_< + cat_impl::cat_ + >; + //! @} + + //! fold, rev_fold //! @{ - namespace detail { + namespace fold_impl { // fold<, V, F> == F, T2>, T3> template struct fold_ { }; // ill formed @@ -140,19 +338,42 @@ namespace meta { typename V, typename Fn> struct fold_, V, Fn> { - using type = type_< - fold_< - typelist, - invoke, - Fn - > - >; + // recursive call of fold_ by consuming typelist and invoking Fn + using type = type_< + fold_< + typelist, + invoke, + Fn + > + >; }; // termination call template struct fold_, V0, Fn> { using type = V0; }; + } + + /*! + * 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$ + * \example + * fold, V, F> == F, T2>, T3> + * \example + * fold, V, F> == V + * \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; + + namespace rev_fold_impl { // rev_fold<, V, F> == F>> template @@ -163,17 +384,18 @@ namespace meta { typename V, typename Fn> struct rev_fold_, V, Fn> { - using type = invoke < - Fn, Head, type_< - rev_fold_ < - typelist, - V, - Fn - > - > - >; + // recursive call inside invoke. This way the 2nd argument of Fn + // becoming the recursive "thing", inside Fn<> + using type = invoke < + Fn, Head, type_< + rev_fold_ < + typelist, + V, + Fn + >> + >; }; - // termination call + // pre-termination call template struct rev_fold_ , V, Fn> { using type = invoke; @@ -181,239 +403,461 @@ namespace meta { // termination call template struct rev_fold_ , V, Fn> { - using type = invoke; + using type = V; }; } /*! - * transform the \p List to a new one by doing a left fold using binary Invocable \p Fn + * transform the \p List to a new one by doing a right fold using binary Invocable \p Fn * and initial value \p V * Complexity \f$ O(N) \f$ + * \example + * rev_fold, V, F> == F>> + * \example + * rev_fold, V, F> == V * \param List The list to fold - * \param V The initial item feeded to Fn + * \param V The initial item fed to Fn * \param Fn The binary Invocable */ template - using fold = type_>; - - //! accumulate is an stl name for fold - template - using accumulate = fold; + using rev_fold = type_< + rev_fold_impl::rev_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 + * Return a new \c typelist by adding the elements \p Ts to the front of \p List. + * Complexity \f$ O(1) \f$ */ - template - using rev_fold = type_>; - //! @} + template + using push_front = type_< + apply < + bind_front, Ts...>, List + > + >; - //! Concatenation + /*! + * Return a new \c typelist by adding the elements \p Ts to the back of \p List. + * Complexity \f$ O(1) \f$ + */ + template + using push_back = type_< + apply < + bind_back, Ts...>, List + > + >; + + //! reverse //! @{ - namespace detail { - template - struct concat_ { }; + namespace reverse_impl { - template <> - struct concat_<> { - using type = typelist<>; + template > + struct reverse_ { + using type = fold>; }; + } - template - struct concat_> { - using type = typelist; - }; + /*! + * Return a new \c typelist by reversing the elements in the list \p List. + * Complexity \f$ O(N) \f$ + */ + template + using reverse = type_< + reverse_impl::reverse_ + >; + //! @} - template - struct concat_, typelist> { - using type = typelist; - }; + //! pop_front + //! @{ + namespace pop_front_impl { + template + struct pop_front_ { }; - template - struct concat_, typelist, typelist> { - using type = typelist; + template + struct pop_front_> { + using type = typelist; }; + } - template - struct concat_, typelist, typelist, Rest...> - : concat_, Rest...> { }; - - template - struct concat_, typelist, typelist, typelist, Rest...> - : concat_, Rest...> { }; + /*! + * Return a new \c typelist by removing the first element from the + * front of \p List. + * Complexity \f$ O(1) \f$ + */ + template + using pop_front = type_< + pop_front_impl::pop_front_ + >; + //! @} + //! pop_back + //! @{ + namespace pop_back_impl { + template + struct pop_back_ { + using type = reverse< + pop_front> + >; + }; } /*! - * 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. + * Return a new \c typelist by removing the last element from the \p List. + * Complexity \f$ O(N) \f$. + * \note + * This operation, in addition from other push/pop operations, is + * heavy(2 reverse operations). */ - template - using concat = type_>; + template + using pop_back = type_ < + pop_back_impl::pop_back_ + >; //! @} //! Transform //! @{ - namespace detail { + namespace transform_impl { template struct transform_ { }; template - struct transform_, Fn>, void_...>> { - using type = typelist...>; + struct transform_, Fn>, + void_t...> > /* SFINAE check */ { + using type = typelist< + invoke_t... + >; }; template struct transform_, typelist, Fn>, - void_...>> { - using type = typelist...>; + void_t...>> /* SFINAE check */ { + using type = typelist< + invoke_t... + >; }; - - } // 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 + * Transformation by applying an invocable \c Fn to one or two lists + * and return the resulting typelist + * * Complexity \f$ O(N) \f$. + * \example + * \code + * using l1 = typelist; + * using l2 = typelist; + * using r1 = transform; // F1, unary invocable + * using r2 = transform; // F2, binary invocable + * \endcode */ template - using transform = type_>>; + using transform = type_< + transform_impl::transform_> + >; //! @} - //! repeat_n + //! Transform lazy //! @{ - namespace detail { - template - using first_ = T; + namespace transform_lazy_impl { + template + struct transform_lazy_ { }; - template - struct repeat_n_c_ { }; + // Match for Unary Fn with one typelist + template + struct transform_lazy_, Fn>, + void_t...> > /* SFINAE check */ { + using type = typelist< + invoke... + >; + }; - template - struct repeat_n_c_> { - using type = typelist...>; + // Match for Binary Fn with two typelists + template + struct transform_lazy_, typelist, Fn>, + void_t...>> /* SFINAE check */ { + using type = typelist< + invoke... + >; }; } /*! - * 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$. + * Transformation by applying an invocable \c Fn to one or two lists + * and return a typelist containing the invocables with their arguments, + * not their resulting types. + * + * Complexity \f$ O(N) \f$ + * + * \example + * \code + * using l1 = typelist; + * using l2 = typelist; + * using r1 = transform; // F1, unary invocable + * using r2 = transform; // F2, binary invocable + * \endcode */ - template - using repeat_n = repeat_n_c; + template + using transform_lazy = type_< + transform_lazy_impl::transform_lazy_> + >; //! @} - //! at - //! @{ - namespace detail { - - template - struct at_impl_; - template - struct at_impl_> { - static nil_ eval(...); + //! find_if, find + //! @{ + namespace find_if_impl { + template + struct find_if_ { }; + + template + struct find_if_, Fn, N> { + // Recursive call to find_if_ until Fn returns true_ + using type = if_ < + invoke_t, + index_t_, // done, return current index + type_, Fn, N+1> + > + >; + }; - template - static T eval(VoidPtrs..., T *, Us *...); + // When empty or when we are one place after the last item return Npos + template + struct find_if_, Fn, N> { + using type = Npos; }; + } - template - struct at_ { }; + /*! + * Search for the first \c Item on the \p List for which the predicate \p Pred + * returns true_ when `type_>` + * + * Complexity \f$ O(N) \f$ + * + * \param List A typelist + * \param Pred A Unary invocable predicate + * \return An integral constant of index_t with the location of the first match, + * or Npos otherwise. + */ + template + using find_if = type_< + find_if_impl::find_if_ + >; - template - struct at_, N> - : decltype( - at_impl_>::eval(static_cast *>(nullptr)...) - ) { }; - } // namespace detail + /*! + * Search for the first occurrence of type \p T on a \p List + */ + template + using find = find_if>; + //! @} - /// Return the \p N th element in the \c meta::typelist \p L. - /// Complexity \f$ O(1) \f$. - template - using at_c = type_>; + //! seek_if + //! @{ + namespace seek_if_impl { + template + struct seek_if_ { }; + + template + struct seek_if_, Fn, N> { + // recursive call to seek_if_ until Fn returns true_ + using type = if_ < + invoke_t, + typelist, // done, return the typelist starting from here + type_, Fn, N+1> + > + >; + }; - //! Return the \p N th element in the \c meta::typelist \p L. - //! Complexity \f$ O(1) \f$. - template - using at = at_c; - //!@} + // When empty or when we are one place after the last item return empty typelist + template + struct seek_if_, Fn, N> { + using type = typelist<>; + }; + } + /*! + * Search for the first \c Item on the \p List for which the predicate \p Pred + * returns true_ when `type_>` and return the rest of the \p List + * starting from that position as new typelist + * + * Complexity \f$ O(N) \f$ + * + * \param List A typelist + * \param Pred A Unary invocable predicate + * \return An integral constant with the location of the first match, on Npos otherwise + */ + template + using seek_if = type_< + seek_if_impl::seek_if_ + >; + /*! + * Search for the first \c Item on the \p List of type \p T and return the rest + * of the \p List starting from that position as new typelist + */ + template + using seek = seek_if >; + //! @} - //! front + //! count_if //! @{ - namespace detail { - template - struct front_ { }; + namespace count_if_impl { + template + struct count_if_ { }; + + template + struct count_if_, Fn, N> { + // Recursive call to count_if_ up to the end of List, counting all invokes of Fn + // returning true_ + using type = if_ < + invoke_t, + type_< + count_if_, Fn, N+1> // increase and re-call + >, + type_< + count_if_, Fn, N> // re-call without increasing + > + >; + }; - template - struct front_> { - using type = Head; + // At the end of the List return the counter + template + struct count_if_, Fn, N> { + using type = size_t_; }; } - //! Return the first element in \c meta::typelist \p L. - //! Complexity \f$ O(1) \f$. - template - using front = type_>; + /*! + * Count all \c Items on the \p List for which the predicate \p Pred + * returns true_ when `type_>` + * + * Complexity \f$ O(N) \f$ + * + * \param List A typelist + * \param Pred A Unary invocable predicate + * \return The total count of occurrences as an integral constant of size_t + */ + template + using count_if = type_< + count_if_impl::count_if_ + >; + + /*! + * Count all occurrences of type \p T int \p List + */ + template + using count = count_if>; //! @} - //! back + //! filter //! @{ - namespace detail { - template - struct back_ { }; + namespace filter_impl { + template + struct filter_ { }; + + template + struct filter_, Fn, L> { + // Recursive call to filter_ up to the end of the List, creating a new list + // of items for which the invoke of Fn returns true_ + using type = if_ < + invoke_t , + type_, Fn, cat>>>, // Add the element and re-call + type_, Fn, L>> // re-call with the same list + >; + }; - template - struct back_> { - using type = at_c, sizeof...(Tail)>; + // At the end return the produced list + template + struct filter_, Fn, L> { + using type = L; }; } - //! Return the last element in \c meta::typelist \p L. - //! Complexity \f$ O(1) \f$. - template - using back = type_>; + /*! + * Return a new typelist with elements, the elements of \p List that satisfy the + * invocable \p Pred such that `type_>` is \c true_ + * + * Complexity \f$ O(N) \f$ + * + * \param List The input typelist + * \param Pred A unary invocable predicate + */ + template + using filter = type_< + filter_impl::filter_> + >; //! @} - //! pop_front + //! replace //! @{ - namespace detail { - template - struct pop_front_ { }; + namespace replace_if_impl { + template + struct replace_if_ { }; + + template + struct replace_if_, Fn, T, Ret> { + // Recursive call to replace_if_ up to the end of the List, creating a new list + // of items based on invocation of Fn + using type = if_ < + invoke_t, + type_, Fn, T, cat>>>, // re-call with change to T + type_, Fn, T, cat>>> // re-call with no change + >; + }; - template - struct pop_front_> { - using type = typelist; + // At the end return the produced list + template + struct replace_if_ , Fn, T, Ret> { + using type = Ret; }; } /*! - * Return a new \c meta::typelist by removing the first element from the - * front of \p L. - * Complexity \f$ O(1) \f$. + * Return a new typelist where all the instances for which the invocation of\p Pred + * returns \c true_, are replaced with \p T + * + * Complexity \f$ O(N) \f$ + * + * \param List The input typelist + * \param Pred A unary invocable predicate + * \param T The new type to replace the item of the \p List, when type_> + * returns \c true_ */ - template - using pop_front = type_>; + template + using replace_if = type_< + replace_if_impl::replace_if_> + >; + + //! Alias wrapper that returns a new \c typelist where all instances of type \p T have + //! been replaced with \p U. + template + using replace = type_ < + replace_if , U> + >; //! @} + + //! Returns \c true_ if \p Pred returns \c true_ for all the elements in the \p List or if the + //! \p List is empty and \c false_ otherwise. + template + using all_of = empty< + filter , Pred>> + >; + + //! Returns \c true_ if \p Pred returns \c true_ for any of the elements in the \p List + //! and \c false_ otherwise. + template + using any_of = not_< + empty> + >; + + //! Returns \c true_ if \p Pred returns \c false_ for all the elements in the \p List + //! or if the \p List is empty and \c false otherwise. + template + using none_of = empty< + filter + >; + }} //! @} diff --git a/test/tests/Tmeta.cpp b/test/tests/Tmeta.cpp index bc67fd7..d7ed699 100644 --- a/test/tests/Tmeta.cpp +++ b/test/tests/Tmeta.cpp @@ -26,12 +26,36 @@ namespace test_meta { using namespace meta; /* - * Test integral constant + * Types to behave like Fixtures */ // Test type_of fixture template struct TestTypeOf { using type = T; }; + template struct MfunBin { + using type = int; + }; + template struct MfunBin_i { + using type = int; + }; + template struct MfunUn1 { + using type = int; + }; + template struct MfunUn2 { + using type = int; + }; + + template struct Pred_isInt { + using type = std::is_integral; + }; + + template struct Pred_isVoid { + using type = std::is_void; + }; + + /* + * Test integral constant + */ TEST(Tmeta_integral, Integreal_type_) { EXPECT_EQ(true, (std::is_same>>::value)); } @@ -146,16 +170,102 @@ namespace test_meta { /* * Test invoke */ - template struct MetaFunction { using type = int; }; - template struct MetaClass {using apply = int; }; TEST(Tmeta_invoke, Invoke) { - //EXPECT_EQ (true, (is_evaluable())); + using Q = quote; + using Qi = quote_i; + using Q1 = quote; + using Q2 = quote; + + EXPECT_EQ (true, (std::is_same>())); + + EXPECT_EQ (true, (is_applicable_t())); + EXPECT_EQ (false, (is_applicable_t())); + EXPECT_EQ (true, (is_applicable_qt())); + EXPECT_EQ (false, (is_applicable_qt())); + + EXPECT_EQ (true, (is_applicable_it())); + EXPECT_EQ (false, (is_applicable_it())); + + EXPECT_EQ (true, (std::is_same::type, MfunBin>())); + EXPECT_EQ (true, (std::is_same::type, nil_>())); + EXPECT_EQ (true, (std::is_same::type, MfunBin_i<7, 42>>())); + EXPECT_EQ (true, (std::is_same::type, nil_>())); + + EXPECT_EQ (true, (std::is_same, nil_>())); + EXPECT_EQ (true, (std::is_same, MfunBin>())); + EXPECT_EQ (true, (std::is_same, int_<42>>, MfunBin_i<7, 42>>())); + EXPECT_EQ (true, (std::is_same>, nil_>())); + + EXPECT_EQ (true, (std::is_same, int>, MfunUn1>>())); + EXPECT_EQ (true, (std::is_same< + invoke, int_<7>, int_<42>>, + MfunUn1>> + >())); + EXPECT_EQ (true, (std::is_same< + invoke, int_<42>>, + MfunUn1> + >())); + + EXPECT_EQ (true, (std::is_same, long>, MfunBin>())); + EXPECT_EQ (true, (std::is_same, long>, MfunBin>())); + } /* * Test typelist */ - template struct F {}; - TEST(Tmeta_typelist, List_fold) { + TEST(Tmeta_typelist, Basics) { + using l1 = typelist; + using l2 = typelist; + using l3 = typelist<>; + + EXPECT_EQ (true, (std::is_same::times<3>>())); + EXPECT_EQ (true, (std::is_same::times<2>>())); + EXPECT_EQ (true, (std::is_same::times<3>>())); + EXPECT_EQ (true, (std::is_same::times<0>>())); + EXPECT_EQ (true, (std::is_same, pair>())); + + EXPECT_EQ (true, (std::is_same, int>>())); + EXPECT_EQ (true, (std::is_same>())); + + + EXPECT_EQ (3, size()); + EXPECT_EQ (true, empty()); + + // pass typelist to an invocable + EXPECT_EQ (true, (std::is_same, typelist> + >, + MfunBin + >())); + } + + TEST(Tmeta_typelist, Element_access) { + using l = typelist; + + EXPECT_EQ (true, (std::is_same>())); + EXPECT_EQ (true, (std::is_same>())); + EXPECT_EQ (true, (std::is_same>())); + EXPECT_EQ (true, (std::is_same>>())); + + EXPECT_EQ (true, (std::is_same>())); + EXPECT_EQ (true, (std::is_same>())); + } + + TEST(Tmeta_typelist, Concat) { + using l1 = typelist; + using l2 = typelist; + using l3 = typelist; + using l4 = typelist<>; + using conc = typelist; + + EXPECT_EQ(true, (std::is_same>())); + EXPECT_EQ(true, (std::is_same>())); + EXPECT_EQ(true, (std::is_same>())); + EXPECT_EQ(true, (std::is_same>())); + } + + template struct F {}; // binary invocable + TEST(Tmeta_typelist, Fold) { struct X1 {}; struct X2 {}; struct X3 {}; @@ -168,29 +278,116 @@ namespace test_meta { EXPECT_EQ(true, (std::is_same, void, Q>, F, X2>, X3>>())); EXPECT_EQ(true, (std::is_same, void, Q>, F, X2>, X3>, X4>>())); - //EXPECT_EQ(true, (std::is_same, void, Q>, void>())); + EXPECT_EQ(true, (std::is_same, void, Q>, void>())); EXPECT_EQ(true, (std::is_same, void, Q>, F>())); EXPECT_EQ(true, (std::is_same, void, Q>, F>>())); EXPECT_EQ(true, (std::is_same, void, Q>, F>>>())); EXPECT_EQ(true, (std::is_same, void, Q>, F>>>>())); } - TEST(Tmeta_typelist, ListOperations) { - using l1 = typelist; - using l2 = typelist<>; - using l3 = typelist; - using l4 = typelist; - using conc = typelist; - using rep = typelist; - EXPECT_EQ(3, size()); - EXPECT_EQ(true, empty()); + TEST(Tmeta_typelist, PushPopReverse) { + using list = typelist ; + using l_char = typelist ; + using l_cc = typelist ; + using char_l = typelist ; + using cc_l = typelist; + using rev = typelist; + + EXPECT_EQ (true, (std::is_same>())); + EXPECT_EQ (true, (std::is_same>())); + EXPECT_EQ (true, (std::is_same>())); + EXPECT_EQ (true, (std::is_same>())); + EXPECT_EQ (true, (std::is_same>())); + EXPECT_EQ (true, (std::is_same>())); + + EXPECT_EQ (true, (std::is_same>())); + } + + TEST(Tmeta_typelist, Transform) { + using QBin = quote; + using QUn = quote; + + using l1 = typelist; + using l2 = typelist; + using r = typelist; + using r_ulazy = typelist , MfunUn1, MfunUn1>; + using r_blazy = typelist , MfunBin, MfunBin>; + + EXPECT_EQ (true, (std::is_same>())); + EXPECT_EQ (true, (std::is_same>())); + + EXPECT_EQ (true, (std::is_same>())); + EXPECT_EQ (true, (std::is_same>())); + } + + + TEST(Tmeta_typelist, Find) { + using l1 = typelist ; + using l2 = typelist ; + using l3 = typelist ; + using empty = typelist<>; + + EXPECT_EQ(true, (std::is_same, find_if>>())); + EXPECT_EQ(true, (std::is_same>>())); + EXPECT_EQ(true, (std::is_same>>())); + + EXPECT_EQ(true, (std::is_same, find>())); + + EXPECT_EQ(true, (std::is_same>>())); + EXPECT_EQ(true, (std::is_same>>())); + EXPECT_EQ(true, (std::is_same>>())); + + EXPECT_EQ(true, (std::is_same>())); + } + + TEST(Tmeta_typelist, Count) { + using list = typelist; + using empty = typelist<>; + + EXPECT_EQ (true, (std::is_same, count_if>>())); + EXPECT_EQ (true, (std::is_same, count_if>>())); + EXPECT_EQ (true, (std::is_same, count_if>>())); + EXPECT_EQ (true, (std::is_same, count_if>())); + + EXPECT_EQ (true, (std::is_same, count>())); + } + + TEST(Tmeta_typelist, Filter) { + using Q1 = quote; + using Q2 = quote; + using list = typelist; + using filtered = typelist; + + EXPECT_EQ (true, (std::is_same>())); + EXPECT_EQ (true, (std::is_same, filter, Q1>>())); + EXPECT_EQ (true, (std::is_same, filter>())); + } + + TEST(Tmeta_typelist, Replace) { + using Q = quote; + using list = typelist; + using res = typelist; + using repl = typelist; + + EXPECT_EQ (true, (std::is_same>())); + EXPECT_EQ (true, (std::is_same, replace_if, Q, void>>())); + EXPECT_EQ (true, (std::is_same>())); + + EXPECT_EQ (true, (std::is_same>())); + } + + TEST (Tmeta_typelist, AllAnyNone) { + using l1 = typelist; + using l2 = typelist; - EXPECT_EQ(true, (std::is_same>())); - EXPECT_EQ(true, (std::is_same, int>>())); - EXPECT_EQ(true, (std::is_same>())); - EXPECT_EQ(true, (std::is_same>())); - EXPECT_EQ(true, (std::is_same>>())); + EXPECT_EQ (true, (std::is_same>>())); + EXPECT_EQ (true, (std::is_same>>())); - EXPECT_EQ(true, (std::is_same, pop_front>())); + EXPECT_EQ (true, (std::is_same>>())); + EXPECT_EQ (true, (std::is_same>>())); + + EXPECT_EQ (true, (std::is_same>>())); + EXPECT_EQ (true, (std::is_same>>())); } + }