| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434 |
- /// \file meta.cpp Tests for Meta: a tiny metaprogramming library
- // Meta: a tiny metaprogramming library
- //
- // Copyright Eric Niebler 2013-present
- //
- // Use, modification and distribution is subject to the
- // Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- //
- // Acknowledgements: Thanks for Paul Fultz for the suggestions that
- // concepts can be ordinary Boolean metafunctions.
- //
- // Project home: https://github.com/ericniebler/range-v3
- //
- #include <tuple>
- #include <meta/meta.hpp>
- #include "../simple_test.hpp"
- using namespace meta;
- // An implementation of tuple_cat gives Range v3's meta-programming and list
- // utilities a good workout. It's a good compiler stress test, too.
- namespace tc_detail
- {
- template<typename Ret, typename... Is, typename... Ks, typename Tuples>
- Ret tuple_cat_(list<Is...>, list<Ks...>, Tuples tpls)
- {
- return Ret{std::get<Ks::value>(std::get<Is::value>(tpls))...};
- }
- }
- template<typename... Tuples,
- typename Res = apply<quote<std::tuple>, concat<as_list<Tuples>...>>>
- Res tuple_cat(Tuples &&... tpls)
- {
- static constexpr std::size_t N = sizeof...(Tuples);
- // E.g. [0,0,0,2,2,2,3,3]
- using inner = join<
- transform<list<as_list<Tuples>...>,
- transform<as_list<make_index_sequence<N>>, quote<id>>, quote<transform>>>;
- // E.g. [0,1,2,0,1,2,0,1]
- using outer = join<
- transform<list<as_list<Tuples>...>,
- compose<quote<as_list>, quote_i<std::size_t, make_index_sequence>, quote<size>>>>;
- return tc_detail::tuple_cat_<Res>(inner{}, outer{},
- std::forward_as_tuple(std::forward<Tuples>(tpls)...));
- }
- void test_tuple_cat()
- {
- std::tuple<int, short, long> t1;
- std::tuple<> t2;
- std::tuple<float, double, long double> t3;
- std::tuple<void *, char *> t4;
- auto x = ::tuple_cat(t1, t2, t3, t4);
- using expected_type = std::tuple<int, short, long, float, double, long double, void *, char *>;
- static_assert(std::is_same<decltype(x), expected_type>::value, "");
- }
- // Other misc tests
- static_assert(std::is_same<reverse<list<int, short, double>>, list<double, short, int>>::value, "");
- static_assert(std::is_same<reverse<list<int, short, double, float>>, list<float, double, short, int>>::value, "");
- static_assert(std::is_same<reverse<list<int[1], int[2], int[3], int[4], int[5], int[6], int[7], int[8], int[9], int[10], int[11], int[12], int[13], int[14], int[15], int[16], int[17]>>, list<int[17], int[16], int[15], int[14], int[13], int[12], int[11], int[10], int[9], int[8], int[7], int[6], int[5], int[4], int[3], int[2], int[1]>>::value, "");
- static_assert(all_of<list<int, short, long>, quote<std::is_integral>>::value, "");
- static_assert(none_of<list<int, short, long>, quote<std::is_floating_point>>::value, "");
- static_assert(!any_of<list<int, short, long>, quote<std::is_floating_point>>::value, "");
- static_assert(any_of<list<int, short, long, float>, quote<std::is_floating_point>>::value, "");
- static_assert(std::is_same<invoke<uncurry<curry<quote_trait<id>>>, std::tuple<int, short, double>>,
- list<int, short, double>>::value,
- "");
- template<typename, typename, typename = void>
- struct can_invoke_ : std::false_type
- {
- };
- template<typename F, typename... As>
- struct can_invoke_<F, meta::list<As...>, meta::void_<meta::invoke<F, As...>>> : std::true_type
- {
- };
- template<typename F, typename... As>
- struct can_invoke : can_invoke_<F, meta::list<As...>>
- {
- };
- static_assert(can_invoke<meta::quote<std::pair>, int, int>::value, "");
- // I'm guessing this failure is due to GCC #64970
- // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64970
- #if !defined(__GNUC__) || defined(__clang__) || __GNUC__ >= 5
- static_assert(!can_invoke<meta::quote<std::pair>, int, int, int>::value, "");
- #endif
- // Sanity-check meta::lambda
- using Lambda0 = lambda<_a, _b, std::pair<_a, _b>>;
- using Lambda1 = lambda<_a, _b, std::pair<_b, _a>>;
- using Lambda2 = lambda<_a, _b, std::pair<_b, std::pair<_a, _a>>>;
- using Pair0 = invoke<Lambda0, int, short>;
- using Pair1 = invoke<Lambda1, int, short>;
- using Pair2 = invoke<Lambda2, int, short>;
- static_assert(std::is_same<Pair0, std::pair<int, short>>::value, "");
- static_assert(std::is_same<Pair1, std::pair<short, int>>::value, "");
- static_assert(std::is_same<Pair2, std::pair<short, std::pair<int, int>>>::value, "");
- // Not saying you should do it this way, but it's a good test.
- namespace l = meta::lazy;
- template<class L>
- using cart_prod = reverse_fold<
- L, list<list<>>,
- lambda<
- _a, _b,
- l::join<l::transform<
- _b, lambda<_c, l::join<l::transform<_a, lambda<_d, list<l::push_front<_d, _c>>>>>>>>>>;
- using CartProd = cart_prod<meta::list<meta::list<int, short>, meta::list<float, double>>>;
- static_assert(
- std::is_same<CartProd, meta::list<meta::list<int, float>, meta::list<int, double>,
- meta::list<short, float>, meta::list<short, double>>>::value,
- "");
- static_assert(can_invoke<lambda<_a, lazy::if_<std::is_integral<_a>, _a>>, int>::value, "");
- // I'm guessing this failure is due to GCC #64970
- // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64970
- #if !defined(__GNUC__) || defined(__clang__) || __GNUC__ >= 5
- static_assert(!can_invoke<lambda<_a, lazy::if_<std::is_integral<_a>, _a>>, float>::value, "");
- #endif
- template<typename List>
- using rev = reverse_fold<List, list<>, lambda<_a, _b, defer<push_back, _a, _b>>>;
- static_assert(std::is_same<rev<list<int, short, double>>, list<double, short, int>>::value, "");
- using uncvref_fn = lambda<_a, l::_t<std::remove_cv<l::_t<std::remove_reference<_a>>>>>;
- static_assert(std::is_same<invoke<uncvref_fn, int const &>, int>::value, "");
- using L = list<int, short, int, float>;
- static_assert(std::is_same<find<L, int>, list<int, short, int, float>>::value, "");
- static_assert(std::is_same<find_if<L, bind_front<quote<std::is_same>, int>>, list<int, short, int, float>>::value, "");
- static_assert(std::is_same<find_if<L, bind_front<quote<std::is_same>, double>>, list<>>::value, "");
- static_assert(std::is_same<reverse_find<L, int>, list<int, float>>::value, "");
- static_assert(std::is_same<reverse_find_if<L, bind_front<quote<std::is_same>, int>>, list<int, float>>::value, "");
- static_assert(std::is_same<reverse_find_if<L, bind_front<quote<std::is_same>, double>>, list<>>::value, "");
- struct check_integral
- {
- template<class T>
- constexpr T operator()(T &&i) const
- {
- static_assert(std::is_integral<T>{}, "");
- return i;
- }
- };
- // Test for meta::let
- template<typename T, typename List>
- using find_index_ = let<
- var<_a, List>, var<_b, lazy::find<_a, T>>,
- lazy::if_<std::is_same<_b, list<>>, meta::npos, lazy::minus<lazy::size<_a>, lazy::size<_b>>>>;
- static_assert(find_index_<int, list<short, int, float>>{} == 1, "");
- static_assert(find_index_<double, list<short, int, float>>{} == meta::npos{}, "");
- // Test that the unselected branch does not get evaluated:
- template<typename T>
- using test_lazy_if_ = let<lazy::if_<std::is_void<T>, T, defer<std::pair, T>>>;
- static_assert(std::is_same<test_lazy_if_<void>, void>::value, "");
- // Test that and_ gets short-circuited:
- template<typename T>
- using test_lazy_and_ = let<lazy::and_<std::is_void<T>, defer<std::is_convertible, T>>>;
- static_assert(std::is_same<test_lazy_and_<int>, std::false_type>::value, "");
- // Test that and_ gets short-circuited:
- template<typename T>
- using test_lazy_or_ = let<lazy::or_<std::is_void<T>, defer<std::is_convertible, T>>>;
- static_assert(std::is_same<test_lazy_or_<void>, std::true_type>::value, "");
- template<typename A, int B = 0>
- struct lambda_test
- {
- };
- template<typename N>
- struct fact
- : let<lazy::if_c<(N::value > 0), lazy::multiplies<N, defer<fact, dec<N>>>, meta::size_t<1>>>
- {
- };
- static_assert(fact<meta::size_t<0>>::value == 1, "");
- static_assert(fact<meta::size_t<1>>::value == 1, "");
- static_assert(fact<meta::size_t<2>>::value == 2, "");
- static_assert(fact<meta::size_t<3>>::value == 6, "");
- static_assert(fact<meta::size_t<4>>::value == 24, "");
- template<std::size_t N>
- struct fact2
- : let<lazy::if_c<(N > 0), lazy::multiplies<meta::size_t<N>, defer_i<std::size_t, fact2, N - 1>>,
- meta::size_t<1>>>
- {
- };
- static_assert(fact2<0>::value == 1, "");
- static_assert(fact2<1>::value == 1, "");
- static_assert(fact2<2>::value == 2, "");
- static_assert(fact2<3>::value == 6, "");
- static_assert(fact2<4>::value == 24, "");
- template<typename N>
- struct factorial
- : let<if_c<N::value == 0, meta::size_t<1>, lazy::multiplies<N, factorial<lazy::dec<N>>>>>
- {
- };
- static_assert(factorial<meta::size_t<0>>::value == 1, "");
- static_assert(factorial<meta::size_t<1>>::value == 1, "");
- static_assert(factorial<meta::size_t<2>>::value == 2, "");
- static_assert(factorial<meta::size_t<3>>::value == 6, "");
- static_assert(factorial<meta::size_t<4>>::value == 24, "");
- int main()
- {
- // meta::sizeof_
- static_assert(meta::sizeof_<int>{} == sizeof(int), "");
- // meta::min
- static_assert(meta::min<meta::size_t<0>, meta::size_t<1>>{} == 0, "");
- static_assert(meta::min<meta::size_t<0>, meta::size_t<0>>{} == 0, "");
- static_assert(meta::min<meta::size_t<1>, meta::size_t<0>>{} == 0, "");
- // meta::max
- static_assert(meta::max<meta::size_t<0>, meta::size_t<1>>{} == 1, "");
- static_assert(meta::max<meta::size_t<1>, meta::size_t<0>>{} == 1, "");
- static_assert(meta::max<meta::size_t<1>, meta::size_t<1>>{} == 1, "");
- // meta::filter
- {
- using l = meta::list<int, double, short, float, long, char>;
- using il = meta::list<int, short, long, char>;
- using fl = meta::list<double, float>;
- static_assert(std::is_same<il, meta::filter<l, meta::quote<std::is_integral>>>{}, "");
- static_assert(std::is_same<fl, meta::filter<l, meta::quote<std::is_floating_point>>>{}, "");
- }
- // meta::for_each
- {
- using l = meta::list<int, long, short>;
- constexpr auto r = meta::for_each(l{}, check_integral());
- static_assert(std::is_same<meta::_t<std::remove_cv<decltype(r)>>, check_integral>::value,
- "");
- }
- // meta::find_index
- {
- using l = meta::list<int, long, short, int>;
- static_assert(meta::find_index<l, int>{} == 0, "");
- static_assert(meta::find_index<l, long>{} == 1, "");
- static_assert(meta::find_index<l, short>{} == 2, "");
- static_assert(meta::find_index<l, double>{} == meta::npos{}, "");
- static_assert(meta::find_index<l, float>{} == meta::npos{}, "");
- using l2 = meta::list<>;
- static_assert(meta::find_index<l2, double>{} == meta::npos{}, "");
- using namespace meta::placeholders;
- using lambda = meta::lambda<_a, _b, meta::lazy::find_index<_b, _a>>;
- using result = meta::invoke<lambda, long, l>;
- static_assert(result{} == 1, "");
- }
- // meta::reverse_find_index
- {
- using l = meta::list<int, long, short, int>;
- static_assert(meta::reverse_find_index<l, int>{} == 3, "");
- static_assert(meta::reverse_find_index<l, long>{} == 1, "");
- static_assert(meta::reverse_find_index<l, short>{} == 2, "");
- static_assert(meta::reverse_find_index<l, double>{} == meta::npos{}, "");
- static_assert(meta::reverse_find_index<l, float>{} == meta::npos{}, "");
- using l2 = meta::list<>;
- static_assert(meta::reverse_find_index<l2, double>{} == meta::npos{}, "");
- using lambda = meta::lambda<_a, _b, meta::lazy::reverse_find_index<_b, _a>>;
- using result = meta::invoke<lambda, long, l>;
- static_assert(result{} == 1, "");
- }
- // meta::count
- {
- using l = meta::list<int, long, short, int>;
- static_assert(meta::count<l, int>{} == 2, "");
- static_assert(meta::count<l, short>{} == 1, "");
- static_assert(meta::count<l, double>{} == 0, "");
- }
- // meta::count_if
- {
- using l = meta::list<int, long, short, int>;
- static_assert(meta::count_if<l, lambda<_a, std::is_same<_a, int>>>{} == 2, "");
- static_assert(meta::count_if<l, lambda<_b, std::is_same<_b, short>>>{} == 1, "");
- static_assert(meta::count_if<l, lambda<_c, std::is_same<_c, double>>>{} == 0, "");
- }
- // pathological lambda test
- {
- using X = invoke<lambda<_a, lambda_test<_a>>, int>;
- static_assert(std::is_same<X, lambda_test<_a>>::value, "");
- }
- // meta::unique
- {
- using l = meta::list<int, short, int, double, short, double, double>;
- static_assert(std::is_same<meta::unique<l>, list<int, short, double>>::value, "");
- }
- // meta::in
- {
- static_assert(in<list<int, int, short, float>, int>::value, "");
- static_assert(in<list<int, int, short, float>, short>::value, "");
- static_assert(in<list<int, int, short, float>, float>::value, "");
- static_assert(!in<list<int, int, short, float>, double>::value, "");
- }
- // lambda with variadic placeholders
- {
- using X = invoke<lambda<_args, list<_args>>, int, short, double>;
- static_assert(std::is_same<X, list<int, short, double>>::value, "");
- using X2 = invoke<lambda<_a, lambda_test<_a>>, int>;
- static_assert(std::is_same<X2, lambda_test<_a>>::value, "");
- using Y = invoke<lambda<_args, defer<std::pair, _args>>, int, short>;
- static_assert(std::is_same<Y, std::pair<int, short>>::value, "");
- using Y2 = invoke<lambda<_args, list<_args, list<_args>>>, int, short>;
- static_assert(std::is_same<Y2, list<int, short, list<int, short>>>::value, "");
- using Z = invoke<lambda<_a, _args, list<int, _args, double, _a>>, short *, short, float>;
- static_assert(std::is_same<Z, list<int, short, float, double, short *>>::value, "");
- // Nesting variadic lambdas in non-variadic lambdas:
- using A = invoke<lambda<_a, lazy::invoke<lambda<_b, _args, list<_args, _b>>, _a,
- lazy::_t<std::add_pointer<_a>>,
- lazy::_t<std::add_lvalue_reference<_a>>>>,
- int>;
- static_assert(std::is_same<A, list<int *, int &, int>>::value, "");
- // Nesting non-variadic lambdas in variadic lambdas:
- using B = invoke<lambda<_a, _args, lazy::invoke<lambda<_b, list<_b, _args, _a>>, _a>>, int,
- short, double>;
- static_assert(std::is_same<B, list<int, short, double, int>>::value, "");
- // Nesting variadic lambdas in variadic lambdas:
- using ZZ = invoke<
- lambda<_a, _args_a,
- lazy::invoke<lambda<_b, _args_b, list<_b, _a, list<_args_b>, list<_args_a>>>,
- _args_a>>,
- int, short, float, double>;
- static_assert(
- std::is_same<ZZ,
- list<short, int, list<float, double>, list<short, float, double>>>::value,
- "");
- // I'm guessing this failure is due to GCC #64970
- // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64970
- #if !defined(__GNUC__) || defined(__clang__) || __GNUC__ >= 5
- static_assert(!can_invoke<lambda<_args, defer<std::pair, _args>>, int>::value, "");
- static_assert(!can_invoke<lambda<_args, defer<std::pair, _args>>, int, short, double>::value,
- "");
- static_assert(!can_invoke<lambda<_a, defer<std::pair, _a, _a>>, int, short>::value, "");
- static_assert(!can_invoke<lambda<_a, _b, _c, _args, defer<std::pair, _a, _a>>>::value, "");
- #endif
- }
- // Test for meta::sort
- {
- using L0 = list<char[5], char[3], char[2], char[6], char[1], char[5], char[10]>;
- using L2 = meta::sort<L0, lambda<_a, _b, lazy::less<lazy::sizeof_<_a>, lazy::sizeof_<_b>>>>;
- static_assert(
- std::is_same<
- L2, list<char[1], char[2], char[3], char[5], char[5], char[6], char[10]>>::value,
- "");
- }
- // Check the _z user-defined literal:
- static_assert(42_z == 42, "");
- // Check integer_range
- {
- constexpr std::size_t a = meta::fold<meta::as_list<meta::integer_range<std::size_t, 0, 5>>,
- meta::size_t<0>, meta::quote<meta::plus>>{};
- static_assert(a == 10, "");
- constexpr std::size_t b = meta::fold<meta::as_list<meta::integer_range<std::size_t, 5, 10>>,
- meta::size_t<0>, meta::quote<meta::plus>>{};
- static_assert(b == 35, "");
- constexpr std::size_t c = meta::fold<meta::as_list<meta::integer_range<std::size_t, 0, 20>>,
- meta::size_t<0>, meta::quote<meta::plus>>{};
- static_assert(c == 190, "");
- using d = meta::integer_range<std::size_t, 5, 10>;
- static_assert(std::is_same<d, meta::integer_sequence<std::size_t, 5, 6, 7, 8, 9>>{}, "");
- }
- // Check reverse_fold
- {
- constexpr std::size_t a = meta::reverse_fold<meta::as_list<meta::integer_range<std::size_t, 0, 5>>,
- meta::size_t<0>, meta::quote<meta::plus>>{};
- static_assert(a == 10, "");
- constexpr std::size_t b = meta::reverse_fold<meta::as_list<meta::integer_range<std::size_t, 5, 10>>,
- meta::size_t<0>, meta::quote<meta::plus>>{};
- static_assert(b == 35, "");
- constexpr std::size_t c = meta::reverse_fold<meta::as_list<meta::integer_range<std::size_t, 0, 20>>,
- meta::size_t<0>, meta::quote<meta::plus>>{};
- static_assert(c == 190, "");
- }
- test_tuple_cat();
- return ::test_result();
- }
|