// 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 #include #include #include #include #include #include #include namespace hana = boost::hana; namespace mpl = boost::mpl; namespace hpl { ////////////////////////////////////////////////////////////////////////////// // Utilities ////////////////////////////////////////////////////////////////////////////// namespace detail { template constexpr auto mpl_predicate = hana::integral(hana::metafunction_class< typename mpl::lambda::type >); template constexpr auto mpl_metafunction = hana::metafunction_class< typename mpl::lambda::type >; } ////////////////////////////////////////////////////////////////////////////// // integral_c ////////////////////////////////////////////////////////////////////////////// template using integral_c = std::integral_constant; template using int_ = integral_c; template using long_ = integral_c; template using bool_ = integral_c; using true_ = bool_; using false_ = bool_; ////////////////////////////////////////////////////////////////////////////// // Sequences, compile-time integers & al // // Differences with the MPL: // 1. `pair<...>::first` and `pair<...>::second` won't work; // use `first>` instead ////////////////////////////////////////////////////////////////////////////// template using vector = hana::tuple...>; template using vector_c = hana::tuple...>; template using range_c = decltype(hana::range_c); template using pair = hana::pair, hana::type>; template struct first : decltype(+hana::first(P{})) { }; template struct second : decltype(+hana::second(P{})) { }; ////////////////////////////////////////////////////////////////////////////// // Miscellaneous metafunctions ////////////////////////////////////////////////////////////////////////////// template struct equal_to : bool_ { }; template struct less : bool_<(C1::value < C2::value)> { }; template struct greater : bool_<(C1::value > C2::value)> { }; template struct next : integral_c { }; ////////////////////////////////////////////////////////////////////////////// // 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 struct at : decltype(hana::at(Sequence{}, N{})) { }; template using at_c = at>; template struct back : decltype(+hana::back(Sequence{})) { }; template struct empty : decltype(hana::is_empty(Sequence{})) { }; template struct front : decltype(+hana::front(Sequence{})) { }; template struct pop_back { using type = decltype(hana::drop_back( hana::to_tuple(Sequence{}), hana::size_c<1> )); }; template struct pop_front { using type = decltype(hana::drop_front(Sequence{})); }; template struct push_back { using type = decltype(hana::append(Sequence{}, hana::type_c)); }; template struct push_front { using type = decltype(hana::prepend(Sequence{}, hana::type_c)); }; template 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 struct fold : decltype(hana::fold( Sequence{}, hana::type_c, detail::mpl_metafunction )) { }; template struct reverse_fold : decltype(hana::reverse_fold( Sequence{}, hana::type_c, detail::mpl_metafunction )) { }; template using accumulate = fold; ////////////////////////////////////////////////////////////////////////////// // 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 struct find_if : decltype(hana::find_if(Sequence{}, detail::mpl_predicate)) { }; template struct find : decltype(hana::find(Sequence{}, hana::type_c)) { }; template struct contains : decltype(hana::contains(Sequence{}, hana::type_c)) { }; template struct count : decltype(hana::count(Sequence{}, hana::type_c)) { }; template struct count_if : decltype(hana::count_if(Sequence{}, detail::mpl_predicate)) { }; template > struct min_element : decltype(hana::minimum(Sequence{}, detail::mpl_predicate)) { }; template > struct max_element : decltype(hana::maximum(Sequence{}, detail::mpl_predicate)) { }; template > struct equal : decltype( // inefficient but whatever hana::length(S1{}) == hana::length(S2{}) && hana::all(hana::zip_shortest_with(detail::mpl_predicate, 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 struct copy { using type = decltype(hana::to_tuple(Sequence{})); }; template struct copy_if { using type = decltype(hana::filter( hana::to_tuple(Sequence{}), detail::mpl_predicate )); }; template struct transform; template struct transform { using type = decltype(hana::transform( hana::to_tuple(Sequence{}), detail::mpl_metafunction )); }; template struct transform { using type = decltype(hana::zip_with( detail::mpl_metafunction, hana::to_tuple(S1{}), hana::to_tuple(S2{}) )); }; template struct replace { using type = decltype(hana::replace( hana::to_tuple(Sequence{}), hana::type_c, hana::type_c )); }; template struct replace_if { using type = decltype(hana::replace_if( hana::to_tuple(Sequence{}), detail::mpl_predicate, hana::type_c )); }; template struct remove { using type = decltype(hana::filter( hana::to_tuple(Sequence{}), hana::not_equal.to(hana::type_c) )); }; template struct remove_if { using type = decltype(hana::filter( hana::to_tuple(Sequence{}), hana::compose(hana::not_, detail::mpl_predicate) )); }; template struct unique { using type = decltype(hana::unique( hana::to_tuple(Sequence{}), detail::mpl_predicate )); }; template struct partition { using hana_pair = decltype(hana::partition( hana::to_tuple(Sequence{}), detail::mpl_predicate )); using type = pair< decltype(hana::first(hana_pair{})), decltype(hana::second(hana_pair{})) >; }; template > struct sort { using type = decltype(hana::sort( hana::to_tuple(Sequence{}), detail::mpl_predicate )); }; template struct reverse { using type = decltype(hana::reverse(hana::to_tuple(Sequence{}))); }; ////////////////////////////////////////////////////////////////////////////// // Runtime algorithms ////////////////////////////////////////////////////////////////////////////// template void for_each(F f) { hana::for_each(Sequence{}, [&f](auto t) { f(typename decltype(t)::type{}); }); } template void for_each(F f) { for_each::type>(f); } } // end namespace hpl template struct is_odd : hpl::bool_<(N::value % 2)> { }; int main() { using namespace hpl; ////////////////////////////////////////////////////////////////////////////// // Misc ////////////////////////////////////////////////////////////////////////////// // pair { static_assert(std::is_same>::type, int>{}, ""); static_assert(std::is_same>::type, float>{}, ""); } ////////////////////////////////////////////////////////////////////////////// // Intrinsics ////////////////////////////////////////////////////////////////////////////// // at { using range = range_c; static_assert(at>::value == 10, ""); static_assert(at>::value == 20, ""); static_assert(at>::value == 50, ""); } // at_c { using range = range_c; static_assert(at_c::value == 10, ""); static_assert(at_c::value == 20, ""); static_assert(at_c::value == 50, ""); } // back { using range1 = range_c; using range2 = range_c; using range3 = range_c; using types = vector; static_assert(back::value == 0, ""); static_assert(back::value == 9, ""); static_assert(back::value == -1, ""); static_assert(std::is_same::type, float>{}, ""); } // empty { using empty_range = range_c; using types = vector; static_assert(empty{}, ""); static_assert(!empty{}, ""); } // front { using types1 = vector; using types2 = vector; using types3 = vector; static_assert(std::is_same::type, long>{}, ""); static_assert(std::is_same::type, int>{}, ""); static_assert(std::is_same::type, char>{}, ""); } // pop_back { using types1 = vector; using types2 = vector; using types3 = vector; using result1 = pop_back::type; using result2 = pop_back::type; using result3 = pop_back::type; static_assert(size::value == 0, ""); static_assert(size::value == 1, ""); static_assert(size::value == 2, ""); static_assert(std::is_same< back::type, long>{}, ""); static_assert(std::is_same< back::type, int>{}, ""); } // pop_front { using types1 = vector; using types2 = vector; using types3 = vector; using result1 = pop_front::type; using result2 = pop_front::type; using result3 = pop_front::type; static_assert(size::value == 0, ""); static_assert(size::value == 1, ""); static_assert(size::value == 2, ""); static_assert(std::is_same::type, long>{}, ""); static_assert(std::is_same::type, int>{}, ""); } // push_back { using bools = vector_c; using message = push_back::type; static_assert(back::type::value == false, ""); static_assert(count_if>{} == 6u, ""); } // push_front { using v = vector_c; static_assert(size{} == 7u, ""); using fibonacci = push_front>::type; static_assert(size{} == 8u, ""); static_assert(equal< fibonacci, vector_c, equal_to >{}, ""); } // size { using empty_list = vector<>; using numbers = vector_c; using more_numbers = range_c; static_assert(size{} == 0u, ""); static_assert(size{} == 6u, ""); static_assert(size{} == 100u, ""); } ////////////////////////////////////////////////////////////////////////////// // Iteration algorithms ////////////////////////////////////////////////////////////////////////////// // fold { using types = vector; using number_of_floats = fold, mpl::if_, next, mpl::_1 > >::type; static_assert(number_of_floats{} == 4, ""); } // reverse_fold { using numbers = vector_c; using negatives = vector_c; using result = reverse_fold, mpl::if_>, push_front, mpl::_1 > >::type; static_assert(equal{}, ""); } ////////////////////////////////////////////////////////////////////////////// // Query algorithms ////////////////////////////////////////////////////////////////////////////// // find_if { using types = vector; using found = find_if>::type; static_assert(std::is_same{}, ""); } // find { using types = vector; static_assert(std::is_same::type, unsigned>{}, ""); } // contains { using types = vector; static_assert(!contains{}, ""); } // count { using types = vector; static_assert(count{} == 2u, ""); } // count_if { using types = vector; static_assert(count_if>{} == 1u, ""); static_assert(count_if>{} == 2u, ""); static_assert(count_if>{} == 0u, ""); } // min_element (MPL's example is completely broken) { } // max_element (MPL's example is completely broken) { } // equal { using s1 = vector; using s2 = vector; static_assert(!equal{}, ""); } ////////////////////////////////////////////////////////////////////////////// // Transformaton algorithms ////////////////////////////////////////////////////////////////////////////// // copy { using numbers = vector_c; using result = copy>::type; static_assert(size{} == 10u, ""); static_assert(equal>{}, ""); } // copy_if { using result = copy_if, less>>::type; static_assert(size{} == 5u, ""); static_assert(equal>{}, ""); } // transform { using types = vector; using pointers = vector; using result = transform>::type; static_assert(equal{}, ""); } // replace { using types = vector; using expected = vector; using result = replace< types,float,double >::type; static_assert(equal{}, ""); } // replace_if { using numbers = vector_c; using expected = vector_c; using result = replace_if>, int_<0>>::type; static_assert(equal>{}, ""); } // remove { using types = vector; using result = hpl::remove::type; static_assert(equal>{}, ""); } // remove_if { using numbers = vector_c; using result = remove_if > >::type; static_assert(equal, mpl::quote2>{}, ""); } // unique { using types = vector; using expected = vector; using result = unique>::type; static_assert(equal{}, ""); } // partition { using r = partition, is_odd>::type; static_assert(equal::type, vector_c>{}, ""); static_assert(equal::type, vector_c>{}, ""); } // sort { using numbers = vector_c; using expected = vector_c; using result = sort::type; static_assert(equal>{}, ""); } // reverse { using numbers = vector_c; using result = reverse::type; static_assert(equal>{}, ""); } ////////////////////////////////////////////////////////////////////////////// // Runtime algorithms ////////////////////////////////////////////////////////////////////////////// // for_each { auto value_printer = [](auto x) { std::cout << x << '\n'; }; for_each >(value_printer); } }