123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697 |
- // Copyright Louis Dionne 2013-2017
- // Distributed under the Boost Software License, Version 1.0.
- // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
- #include <boost/hana.hpp>
- #include <boost/hana/ext/boost/mpl.hpp>
- #include <boost/hana/ext/std.hpp>
- #include <boost/mpl/lambda.hpp>
- #include <boost/mpl/placeholders.hpp>
- #include <boost/mpl/quote.hpp>
- #include <iostream>
- #include <type_traits>
- namespace hana = boost::hana;
- namespace mpl = boost::mpl;
- namespace hpl {
- //////////////////////////////////////////////////////////////////////////////
- // Utilities
- //////////////////////////////////////////////////////////////////////////////
- namespace detail {
- template <typename Pred>
- constexpr auto mpl_predicate = hana::integral(hana::metafunction_class<
- typename mpl::lambda<Pred>::type
- >);
- template <typename F>
- constexpr auto mpl_metafunction = hana::metafunction_class<
- typename mpl::lambda<F>::type
- >;
- }
- //////////////////////////////////////////////////////////////////////////////
- // integral_c
- //////////////////////////////////////////////////////////////////////////////
- template <typename T, T v>
- using integral_c = std::integral_constant<T, v>;
- template <int i>
- using int_ = integral_c<int, i>;
- template <long i>
- using long_ = integral_c<long, i>;
- template <bool b>
- using bool_ = integral_c<bool, b>;
- using true_ = bool_<true>;
- using false_ = bool_<false>;
- //////////////////////////////////////////////////////////////////////////////
- // Sequences, compile-time integers & al
- //
- // Differences with the MPL:
- // 1. `pair<...>::first` and `pair<...>::second` won't work;
- // use `first<pair<...>>` instead
- //////////////////////////////////////////////////////////////////////////////
- template <typename ...T>
- using vector = hana::tuple<hana::type<T>...>;
- template <typename T, T ...v>
- using vector_c = hana::tuple<hana::integral_constant<T, v>...>;
- template <typename T, T from, T to>
- using range_c = decltype(hana::range_c<T, from, to>);
- template <typename T, typename U>
- using pair = hana::pair<hana::type<T>, hana::type<U>>;
- template <typename P>
- struct first : decltype(+hana::first(P{})) { };
- template <typename P>
- struct second : decltype(+hana::second(P{})) { };
- //////////////////////////////////////////////////////////////////////////////
- // Miscellaneous metafunctions
- //////////////////////////////////////////////////////////////////////////////
- template <typename C1, typename C2>
- struct equal_to
- : bool_<C1::value == C2::value>
- { };
- template <typename C1, typename C2>
- struct less
- : bool_<(C1::value < C2::value)>
- { };
- template <typename C1, typename C2>
- struct greater
- : bool_<(C1::value > C2::value)>
- { };
- template <typename N>
- struct next
- : integral_c<typename N::value_type, N::value + 1>
- { };
- //////////////////////////////////////////////////////////////////////////////
- // Intrinsics
- //
- // Differences with the MPL:
- // 1. `at` does not work for associative sequences; use `find` instead.
- // 2. `begin`, `end`, `clear`, `erase`, `erase_key`, `insert`, `insert_range`,
- // `is_sequence`, `key_type`, `order`, `sequence_tag`, `value_type`: not implemented
- //////////////////////////////////////////////////////////////////////////////
- template <typename Sequence, typename N>
- struct at
- : decltype(hana::at(Sequence{}, N{}))
- { };
- template <typename Sequence, long n>
- using at_c = at<Sequence, long_<n>>;
- template <typename Sequence>
- struct back
- : decltype(+hana::back(Sequence{}))
- { };
- template <typename Sequence>
- struct empty
- : decltype(hana::is_empty(Sequence{}))
- { };
- template <typename Sequence>
- struct front
- : decltype(+hana::front(Sequence{}))
- { };
- template <typename Sequence>
- struct pop_back {
- using type = decltype(hana::drop_back(
- hana::to_tuple(Sequence{}), hana::size_c<1>
- ));
- };
- template <typename Sequence>
- struct pop_front {
- using type = decltype(hana::drop_front(Sequence{}));
- };
- template <typename Sequence, typename T>
- struct push_back {
- using type = decltype(hana::append(Sequence{}, hana::type_c<T>));
- };
- template <typename Sequence, typename T>
- struct push_front {
- using type = decltype(hana::prepend(Sequence{}, hana::type_c<T>));
- };
- template <typename Sequence>
- struct size
- : decltype(hana::length(Sequence{}))
- { };
- //////////////////////////////////////////////////////////////////////////////
- // Iteration algorithms
- //
- // Differences with the MPL:
- // 1. reverse_fold:
- // Does not take an optional additional ForwardOp argument.
- //
- // 2. iter_fold, reverse_iter_fold:
- // Not implemented because we don't use iterators
- //////////////////////////////////////////////////////////////////////////////
- template <typename Sequence, typename State, typename F>
- struct fold
- : decltype(hana::fold(
- Sequence{}, hana::type_c<State>, detail::mpl_metafunction<F>
- ))
- { };
- template <typename Sequence, typename State, typename F>
- struct reverse_fold
- : decltype(hana::reverse_fold(
- Sequence{}, hana::type_c<State>, detail::mpl_metafunction<F>
- ))
- { };
- template <typename Sequence, typename State, typename F>
- using accumulate = fold<Sequence, State, F>;
- //////////////////////////////////////////////////////////////////////////////
- // Query algorithms
- //
- // Differences with the MPL:
- // 1. find_if and find:
- // Instead of returning an iterator, they either have a nested `::type`
- // alias to the answer, or they have no nested `::type` at all, which
- // makes them SFINAE-friendly.
- //
- // 2. lower_bound, upper_bound:
- // Not implemented.
- //
- // 3. {min,max}_element:
- // Not returning an iterator, and also won't work on empty sequences.
- //////////////////////////////////////////////////////////////////////////////
- template <typename Sequence, typename Pred>
- struct find_if
- : decltype(hana::find_if(Sequence{}, detail::mpl_predicate<Pred>))
- { };
- template <typename Sequence, typename T>
- struct find
- : decltype(hana::find(Sequence{}, hana::type_c<T>))
- { };
- template <typename Sequence, typename T>
- struct contains
- : decltype(hana::contains(Sequence{}, hana::type_c<T>))
- { };
- template <typename Sequence, typename T>
- struct count
- : decltype(hana::count(Sequence{}, hana::type_c<T>))
- { };
- template <typename Sequence, typename Pred>
- struct count_if
- : decltype(hana::count_if(Sequence{}, detail::mpl_predicate<Pred>))
- { };
- template <typename Sequence, typename Pred = mpl::quote2<less>>
- struct min_element
- : decltype(hana::minimum(Sequence{}, detail::mpl_predicate<Pred>))
- { };
- template <typename Sequence, typename Pred = mpl::quote2<less>>
- struct max_element
- : decltype(hana::maximum(Sequence{}, detail::mpl_predicate<Pred>))
- { };
- template <typename S1, typename S2, typename Pred = mpl::quote2<std::is_same>>
- struct equal
- : decltype( // inefficient but whatever
- hana::length(S1{}) == hana::length(S2{}) &&
- hana::all(hana::zip_shortest_with(detail::mpl_predicate<Pred>,
- hana::to_tuple(S1{}),
- hana::to_tuple(S2{})))
- )
- { };
- //////////////////////////////////////////////////////////////////////////////
- // Transformation algorithms
- //
- // Differences from the MPL:
- // 1. The algorithms do not accept an optional inserter, and they always
- // return a `vector`.
- // 2. stable_partition: not implemented
- // 3. All the reverse_* algorithms are not implemented.
- //////////////////////////////////////////////////////////////////////////////
- template <typename Sequence>
- struct copy {
- using type = decltype(hana::to_tuple(Sequence{}));
- };
- template <typename Sequence, typename Pred>
- struct copy_if {
- using type = decltype(hana::filter(
- hana::to_tuple(Sequence{}),
- detail::mpl_predicate<Pred>
- ));
- };
- template <typename Sequence, typename Sequence_or_Op, typename = void>
- struct transform;
- template <typename Sequence, typename Op>
- struct transform<Sequence, Op> {
- using type = decltype(hana::transform(
- hana::to_tuple(Sequence{}), detail::mpl_metafunction<Op>
- ));
- };
- template <typename S1, typename S2, typename Op>
- struct transform {
- using type = decltype(hana::zip_with(
- detail::mpl_metafunction<Op>,
- hana::to_tuple(S1{}),
- hana::to_tuple(S2{})
- ));
- };
- template <typename Sequence, typename OldType, typename NewType>
- struct replace {
- using type = decltype(hana::replace(
- hana::to_tuple(Sequence{}),
- hana::type_c<OldType>,
- hana::type_c<NewType>
- ));
- };
- template <typename Sequence, typename Pred, typename NewType>
- struct replace_if {
- using type = decltype(hana::replace_if(
- hana::to_tuple(Sequence{}),
- detail::mpl_predicate<Pred>,
- hana::type_c<NewType>
- ));
- };
- template <typename Sequence, typename T>
- struct remove {
- using type = decltype(hana::filter(
- hana::to_tuple(Sequence{}),
- hana::not_equal.to(hana::type_c<T>)
- ));
- };
- template <typename Sequence, typename Pred>
- struct remove_if {
- using type = decltype(hana::filter(
- hana::to_tuple(Sequence{}),
- hana::compose(hana::not_, detail::mpl_predicate<Pred>)
- ));
- };
- template <typename Sequence, typename Pred>
- struct unique {
- using type = decltype(hana::unique(
- hana::to_tuple(Sequence{}),
- detail::mpl_predicate<Pred>
- ));
- };
- template <typename Sequence, typename Pred>
- struct partition {
- using hana_pair = decltype(hana::partition(
- hana::to_tuple(Sequence{}),
- detail::mpl_predicate<Pred>
- ));
- using type = pair<
- decltype(hana::first(hana_pair{})),
- decltype(hana::second(hana_pair{}))
- >;
- };
- template <typename Sequence, typename Pred = mpl::quote2<less>>
- struct sort {
- using type = decltype(hana::sort(
- hana::to_tuple(Sequence{}), detail::mpl_predicate<Pred>
- ));
- };
- template <typename Sequence>
- struct reverse {
- using type = decltype(hana::reverse(hana::to_tuple(Sequence{})));
- };
- //////////////////////////////////////////////////////////////////////////////
- // Runtime algorithms
- //////////////////////////////////////////////////////////////////////////////
- template <typename Sequence, typename F>
- void for_each(F f) {
- hana::for_each(Sequence{}, [&f](auto t) {
- f(typename decltype(t)::type{});
- });
- }
- template <typename Sequence, typename TransformOp, typename F>
- void for_each(F f) {
- for_each<typename transform<Sequence, TransformOp>::type>(f);
- }
- } // end namespace hpl
- template <typename N>
- struct is_odd
- : hpl::bool_<(N::value % 2)>
- { };
- int main() {
- using namespace hpl;
- //////////////////////////////////////////////////////////////////////////////
- // Misc
- //////////////////////////////////////////////////////////////////////////////
- // pair
- {
- static_assert(std::is_same<first<pair<int, float>>::type, int>{}, "");
- static_assert(std::is_same<second<pair<int, float>>::type, float>{}, "");
- }
- //////////////////////////////////////////////////////////////////////////////
- // Intrinsics
- //////////////////////////////////////////////////////////////////////////////
- // at
- {
- using range = range_c<long,10,50>;
- static_assert(at<range, int_<0>>::value == 10, "");
- static_assert(at<range, int_<10>>::value == 20, "");
- static_assert(at<range, int_<40>>::value == 50, "");
- }
- // at_c
- {
- using range = range_c<long, 10, 50>;
- static_assert(at_c<range, 0>::value == 10, "");
- static_assert(at_c<range, 10>::value == 20, "");
- static_assert(at_c<range, 40>::value == 50, "");
- }
- // back
- {
- using range1 = range_c<int,0,1>;
- using range2 = range_c<int,0,10>;
- using range3 = range_c<int,-10,0>;
- using types = vector<int, char, float>;
- static_assert(back<range1>::value == 0, "");
- static_assert(back<range2>::value == 9, "");
- static_assert(back<range3>::value == -1, "");
- static_assert(std::is_same<back<types>::type, float>{}, "");
- }
- // empty
- {
- using empty_range = range_c<int,0,0>;
- using types = vector<long,float,double>;
- static_assert(empty<empty_range>{}, "");
- static_assert(!empty<types>{}, "");
- }
- // front
- {
- using types1 = vector<long>;
- using types2 = vector<int,long>;
- using types3 = vector<char,int,long>;
- static_assert(std::is_same<front<types1>::type, long>{}, "");
- static_assert(std::is_same<front<types2>::type, int>{}, "");
- static_assert(std::is_same<front<types3>::type, char>{}, "");
- }
- // pop_back
- {
- using types1 = vector<long>;
- using types2 = vector<long,int>;
- using types3 = vector<long,int,char>;
- using result1 = pop_back<types1>::type;
- using result2 = pop_back<types2>::type;
- using result3 = pop_back<types3>::type;
- static_assert(size<result1>::value == 0, "");
- static_assert(size<result2>::value == 1, "");
- static_assert(size<result3>::value == 2, "");
- static_assert(std::is_same< back<result2>::type, long>{}, "");
- static_assert(std::is_same< back<result3>::type, int>{}, "");
- }
- // pop_front
- {
- using types1 = vector<long>;
- using types2 = vector<int,long>;
- using types3 = vector<char,int,long>;
- using result1 = pop_front<types1>::type;
- using result2 = pop_front<types2>::type;
- using result3 = pop_front<types3>::type;
- static_assert(size<result1>::value == 0, "");
- static_assert(size<result2>::value == 1, "");
- static_assert(size<result3>::value == 2, "");
- static_assert(std::is_same<front<result2>::type, long>{}, "");
- static_assert(std::is_same<front<result3>::type, int>{}, "");
- }
- // push_back
- {
- using bools = vector_c<bool,false,false,false,true,true,true,false,false>;
- using message = push_back<bools, false_>::type;
- static_assert(back<message>::type::value == false, "");
- static_assert(count_if<message, equal_to<mpl::_1, false_>>{} == 6u, "");
- }
- // push_front
- {
- using v = vector_c<int,1,2,3,5,8,13,21>;
- static_assert(size<v>{} == 7u, "");
- using fibonacci = push_front<v, int_<1>>::type;
- static_assert(size<fibonacci>{} == 8u, "");
- static_assert(equal<
- fibonacci,
- vector_c<int,1,1,2,3,5,8,13,21>,
- equal_to<mpl::_, mpl::_>
- >{}, "");
- }
- // size
- {
- using empty_list = vector<>;
- using numbers = vector_c<int,0,1,2,3,4,5>;
- using more_numbers = range_c<int,0,100>;
- static_assert(size<empty_list>{} == 0u, "");
- static_assert(size<numbers>{} == 6u, "");
- static_assert(size<more_numbers>{} == 100u, "");
- }
- //////////////////////////////////////////////////////////////////////////////
- // Iteration algorithms
- //////////////////////////////////////////////////////////////////////////////
- // fold
- {
- using types = vector<long,float,short,double,float,long,long double>;
- using number_of_floats = fold<types, int_<0>,
- mpl::if_<std::is_floating_point<mpl::_2>,
- next<mpl::_1>,
- mpl::_1
- >
- >::type;
- static_assert(number_of_floats{} == 4, "");
- }
- // reverse_fold
- {
- using numbers = vector_c<int,5,-1,0,-7,-2,0,-5,4>;
- using negatives = vector_c<int,-1,-7,-2,-5>;
- using result = reverse_fold<numbers, vector_c<int>,
- mpl::if_<less<mpl::_2, int_<0>>,
- push_front<mpl::_1, mpl::_2>,
- mpl::_1
- >
- >::type;
- static_assert(equal<negatives, result>{}, "");
- }
- //////////////////////////////////////////////////////////////////////////////
- // Query algorithms
- //////////////////////////////////////////////////////////////////////////////
- // find_if
- {
- using types = vector<char,int,unsigned,long,unsigned long>;
- using found = find_if<types, std::is_same<mpl::_1, unsigned>>::type;
- static_assert(std::is_same<found, unsigned>{}, "");
- }
- // find
- {
- using types = vector<char,int,unsigned,long,unsigned long>;
- static_assert(std::is_same<find<types, unsigned>::type, unsigned>{}, "");
- }
- // contains
- {
- using types = vector<char,int,unsigned,long,unsigned long>;
- static_assert(!contains<types, bool>{}, "");
- }
- // count
- {
- using types = vector<int,char,long,short,char,short,double,long>;
- static_assert(count<types, short>{} == 2u, "");
- }
- // count_if
- {
- using types = vector<int,char,long,short,char,long,double,long>;
- static_assert(count_if<types, std::is_floating_point<mpl::_>>{} == 1u, "");
- static_assert(count_if<types, std::is_same<mpl::_, char>>{} == 2u, "");
- static_assert(count_if<types, std::is_same<mpl::_, void>>{} == 0u, "");
- }
- // min_element (MPL's example is completely broken)
- {
- }
- // max_element (MPL's example is completely broken)
- {
- }
- // equal
- {
- using s1 = vector<char,int,unsigned,long,unsigned long>;
- using s2 = vector<char,int,unsigned,long>;
- static_assert(!equal<s1,s2>{}, "");
- }
- //////////////////////////////////////////////////////////////////////////////
- // Transformaton algorithms
- //////////////////////////////////////////////////////////////////////////////
- // copy
- {
- using numbers = vector_c<int,10, 11, 12, 13, 14, 15, 16, 17, 18, 19>;
- using result = copy<range_c<int, 10, 20>>::type;
- static_assert(size<result>{} == 10u, "");
- static_assert(equal<result, numbers, mpl::quote2<equal_to>>{}, "");
- }
- // copy_if
- {
- using result = copy_if<range_c<int, 0, 10>, less<mpl::_1, int_<5>>>::type;
- static_assert(size<result>{} == 5u, "");
- static_assert(equal<result, range_c<int, 0, 5>>{}, "");
- }
- // transform
- {
- using types = vector<char,short,int,long,float,double>;
- using pointers = vector<char*,short*,int*,long*,float*,double*>;
- using result = transform<types,std::add_pointer<mpl::_1>>::type;
- static_assert(equal<result, pointers>{}, "");
- }
- // replace
- {
- using types = vector<int,float,char,float,float,double>;
- using expected = vector<int,double,char,double,double,double>;
- using result = replace< types,float,double >::type;
- static_assert(equal<result, expected>{}, "");
- }
- // replace_if
- {
- using numbers = vector_c<int,1,4,5,2,7,5,3,5>;
- using expected = vector_c<int,1,4,0,2,0,0,3,0>;
- using result = replace_if<numbers, greater<mpl::_, int_<4>>, int_<0>>::type;
- static_assert(equal<result, expected, mpl::quote2<equal_to>>{}, "");
- }
- // remove
- {
- using types = vector<int,float,char,float,float,double>;
- using result = hpl::remove<types, float>::type;
- static_assert(equal<result, vector<int, char, double>>{}, "");
- }
- // remove_if
- {
- using numbers = vector_c<int,1,4,5,2,7,5,3,5>;
- using result = remove_if<numbers, greater<mpl::_, int_<4> > >::type;
- static_assert(equal<result, vector_c<int,1,4,2,3>, mpl::quote2<equal_to>>{}, "");
- }
- // unique
- {
- using types = vector<int,float,float,char,int,int,int,double>;
- using expected = vector<int,float,char,int,double>;
- using result = unique<types, std::is_same<mpl::_1, mpl::_2>>::type;
- static_assert(equal<result, expected>{}, "");
- }
- // partition
- {
- using r = partition<range_c<int,0,10>, is_odd<mpl::_1>>::type;
- static_assert(equal<first<r>::type, vector_c<int,1,3,5,7,9>>{}, "");
- static_assert(equal<second<r>::type, vector_c<int,0,2,4,6,8>>{}, "");
- }
- // sort
- {
- using numbers = vector_c<int,3,4,0,-5,8,-1,7>;
- using expected = vector_c<int,-5,-1,0,3,4,7,8>;
- using result = sort<numbers>::type;
- static_assert(equal<result, expected, equal_to<mpl::_, mpl::_>>{}, "");
- }
- // reverse
- {
- using numbers = vector_c<int,9,8,7,6,5,4,3,2,1,0>;
- using result = reverse<numbers>::type;
- static_assert(equal<result, range_c<int,0,10>>{}, "");
- }
- //////////////////////////////////////////////////////////////////////////////
- // Runtime algorithms
- //////////////////////////////////////////////////////////////////////////////
- // for_each
- {
- auto value_printer = [](auto x) {
- std::cout << x << '\n';
- };
- for_each<range_c<int, 0, 10> >(value_printer);
- }
- }
|