/* @copyright Louis Dionne 2015 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 #include #include #include #include #include #include #include #include using namespace boost::hana; int main() { ////////////////////////////////////////////////////////////////////////////// // Models ////////////////////////////////////////////////////////////////////////////// { //! [Applicative] static_assert(lift('x') == make('x'), ""); static_assert(equal(lift('x'), std::make_tuple('x')), ""); constexpr auto f = make_pair; constexpr auto g = flip(make_pair); static_assert( ap(make(f, g), make(1, 2, 3), make('a', 'b')) == make( f(1, 'a'), f(1, 'b'), f(2, 'a'), f(2, 'b'), f(3, 'a'), f(3, 'b'), g(1, 'a'), g(1, 'b'), g(2, 'a'), g(2, 'b'), g(3, 'a'), g(3, 'b') ) , ""); //! [Applicative] }{ //! [Comparable] BOOST_HANA_CONSTEXPR_CHECK(make(1, 2, 3) == make(1, 2, 3)); BOOST_HANA_CONSTANT_CHECK(make(1, 2, 3) != make(1, 2, 3, 4)); //! [Comparable] }{ //! [Orderable] BOOST_HANA_CONSTEXPR_CHECK(make(1, 2, 3) < make(2, 3, 4)); BOOST_HANA_CONSTEXPR_CHECK(make(1, 2, 3) < make(1, 2, 3, 4)); //! [Orderable] }{ //! [Foldable] auto to_string = [](auto x) { return static_cast(std::ostringstream{} << x).str(); }; auto show = [=](auto x, auto y) { return "(" + to_string(x) + " + " + to_string(y) + ")"; }; BOOST_HANA_RUNTIME_CHECK( fold.left(make_tuple(2, "3", '4'), "1", show) == "(((1 + 2) + 3) + 4)" ); //! [Foldable] }{ //! [Functor] auto to_string = [](auto x) { return static_cast(std::ostringstream{} << x).str(); }; BOOST_HANA_RUNTIME_CHECK( transform(make(1, '2', "345", std::string{"67"}), to_string) == make("1", "2", "345", "67") ); //! [Functor] }{ //! [Iterable] BOOST_HANA_CONSTEXPR_CHECK(head(make_tuple(1, '2', 3.3)) == 1); BOOST_HANA_CONSTEXPR_CHECK(tail(make_tuple(1, '2', 3.3)) == make_tuple('2', 3.3)); BOOST_HANA_CONSTANT_CHECK(!is_empty(make_tuple(1, '2', 3.3))); BOOST_HANA_CONSTANT_CHECK(is_empty(make_tuple())); //! [Iterable] }{ //! [Monad.ints] BOOST_HANA_CONSTEXPR_CHECK( flatten(make_tuple( make_tuple(1, 2), make_tuple(3, 4), make_tuple(make_tuple(5, 6)) )) == make_tuple(1, 2, 3, 4, make_tuple(5, 6)) ); //! [Monad.ints] }{ //! [Monad.types] // Using the Tuple Monad, we generate all the possible combinations of // cv-qualifiers and reference qualifiers. Then, we use the Optional Monad // to make sure that our generic function can be called with arguments // of any of those types. // cv_qualifiers : Type -> Tuple(Type) auto cv_qualifiers = [](auto t) { return make_tuple( t, traits::add_const(t), traits::add_volatile(t), traits::add_volatile(traits::add_const(t)) ); }; // ref_qualifiers : Type -> Tuple(Type) auto ref_qualifiers = [](auto t) { return make_tuple( traits::add_lvalue_reference(t), traits::add_rvalue_reference(t) ); }; auto possible_args = cv_qualifiers(type) | ref_qualifiers; BOOST_HANA_CONSTANT_CHECK( possible_args == make( type, type, type, type, type, type, type, type ) ); auto my_generic_function = [](auto&&) { return 1; }; for_each(possible_args, [=](auto t) { using T = typename decltype(t)::type; static_assert(decltype(is_just(sfinae(my_generic_function)(std::declval()))){}, "my_generic_function should be callable with any type of argument"); }); //! [Monad.types] }{ //! [MonadPlus] using namespace std::string_literals; BOOST_HANA_CONSTANT_CHECK(empty() == make()); BOOST_HANA_CONSTEXPR_CHECK( append(make(1, '2', 3.3), nullptr) == make(1, '2', 3.3, nullptr) ); BOOST_HANA_CONSTEXPR_CHECK( concat(make(1, '2', 3.3), make("abcdef"s)) == make(1, '2', 3.3, "abcdef"s) ); //! [MonadPlus] }{ //! [Searchable] using namespace std::string_literals; BOOST_HANA_RUNTIME_CHECK( find_if(make(1, '2', 3.3, "abc"s), is_a) == just("abc"s) ); BOOST_HANA_RUNTIME_CHECK( "abc"s ^in^ make(1, '2', 3.3, "abc"s) ); //! [Searchable] } ////////////////////////////////////////////////////////////////////////////// // Methods ////////////////////////////////////////////////////////////////////////////// { //! [cartesian_product] static_assert( cartesian_product( make_tuple( make_tuple(1, 2, 3), make_tuple('a', 'b'), make_tuple(type, type) ) ) == make_tuple( make_tuple(1, 'a', type), make_tuple(1, 'a', type), make_tuple(1, 'b', type), make_tuple(1, 'b', type), make_tuple(2, 'a', type), make_tuple(2, 'a', type), make_tuple(2, 'b', type), make_tuple(2, 'b', type), make_tuple(3, 'a', type), make_tuple(3, 'a', type), make_tuple(3, 'b', type), make_tuple(3, 'b', type) ) , ""); //! [cartesian_product] }{ //! [group] // without a predicate BOOST_HANA_CONSTANT_CHECK( group(make_tuple(int_<1>, long_<1>, type, char_<'x'>, char_<'x'>)) == make_tuple( make_tuple(int_<1>, long_<1>), make_tuple(type), make_tuple(char_<'x'>, char_<'x'>) ) ); // with a predicate auto tuples = make_tuple( range_c, range_c, range_c, range_c ); BOOST_HANA_CONSTANT_CHECK( group(tuples, comparing(length)) == make_tuple( make_tuple( range_c ), make_tuple( range_c, range_c ), make_tuple( range_c ) ) ); //! [group] }{ //! [group.by] BOOST_HANA_CONSTEXPR_CHECK( group.by(comparing(decltype_), make_tuple(1, 2, 3, 'x', 'y', 4.4, 5.5)) == make_tuple( make_tuple(1, 2, 3), make_tuple('x', 'y'), make_tuple(4.4, 5.5) ) ); //! [group.by] }{ //! [init] using namespace boost::hana::literals; BOOST_HANA_CONSTANT_CHECK(init(make_tuple(1)) == make_tuple()); BOOST_HANA_CONSTEXPR_CHECK(init(make_tuple(1, '2', 3.3, 4_c)) == make_tuple(1, '2', 3.3)); //! [init] }{ //! [insert] using namespace boost::hana::literals; using namespace std::literals; auto xs = make_tuple("Hello"s, "world!"s); BOOST_HANA_RUNTIME_CHECK(insert(xs, 1_c, " "s) == make_tuple("Hello"s, " "s, "world!"s)); //! [insert] }{ //! [insert_range] using namespace boost::hana::literals; using namespace std::literals; auto xs = make_tuple("Hello"s, "world!"s); BOOST_HANA_RUNTIME_CHECK( insert_range(xs, 1_c, make_tuple(1, 2, 3)) == make_tuple("Hello"s, 1, 2, 3, "world!"s) ); //! [insert_range] }{ //! [intersperse] BOOST_HANA_CONSTEXPR_CHECK( intersperse(make_tuple(1, '2', 3.3), 'x') == make_tuple(1, 'x', '2', 'x', 3.3) ); BOOST_HANA_CONSTANT_CHECK(intersperse(make_tuple(), 'x') == make_tuple()); //! [intersperse] }{ //! [make] BOOST_HANA_CONSTANT_CHECK(make() == make_tuple()); BOOST_HANA_CONSTEXPR_CHECK(make(1, '2', 3.3) == make_tuple(1, '2', 3.3)); //! [make] }{ //! [permutations] BOOST_HANA_CONSTEXPR_LAMBDA auto is_permutation_of = curry<2>([](auto xs, auto perm) { return contains(permutations(xs), perm); }); BOOST_HANA_CONSTEXPR_CHECK( all_of( make_tuple( make_tuple('1', 2, 3.0), make_tuple('1', 3.0, 2), make_tuple(2, '1', 3.0), make_tuple(2, 3.0, '1'), make_tuple(3.0, '1', 2), make_tuple(3.0, 2, '1') ), is_permutation_of(make_tuple('1', 2, 3.0)) ) ); //! [permutations] }{ //! [partition] BOOST_HANA_CONSTANT_CHECK( partition(tuple_c, [](auto x) { return x % int_<2> != int_<0>; }) == make_pair( tuple_c, tuple_c ) ); BOOST_HANA_CONSTANT_CHECK( partition(tuple_t, trait) == make_pair( tuple_t, tuple_t ) ); //! [partition] }{ //! [partition.by] BOOST_HANA_CONSTANT_CHECK( partition.by(traits::is_floating_point, tuple_t) == make_pair( tuple_t, tuple_t ) ); //! [partition.by] }{ //! [remove_at] BOOST_HANA_CONSTEXPR_CHECK( remove_at(make_tuple(0, '1', 2.2, 3u), int_<2>) == make_tuple(0, '1', 3u) ); //! [remove_at] }{ //! [remove_at_c] BOOST_HANA_CONSTEXPR_CHECK( remove_at_c<2>(make_tuple(0, '1', 2.2, 3u)) == make_tuple(0, '1', 3u) ); //! [remove_at_c] }{ //! [reverse] BOOST_HANA_CONSTEXPR_CHECK(reverse(make_tuple(1, '2', 3.3)) == make_tuple(3.3, '2', 1)); //! [reverse] }{ //! [scan.left] auto to_string = [](auto x) { std::ostringstream ss; ss << x; return ss.str(); }; auto f = [=](auto state, auto element) { return "f(" + to_string(state) + ", " + to_string(element) + ")"; }; // with initial state BOOST_HANA_RUNTIME_CHECK(scan.left(make_tuple(2, "3", '4'), 1, f) == make_tuple( 1, "f(1, 2)", "f(f(1, 2), 3)", "f(f(f(1, 2), 3), 4)" )); // without initial state BOOST_HANA_RUNTIME_CHECK(scan.left(make_tuple(1, "2", '3'), f) == make_tuple( 1, "f(1, 2)", "f(f(1, 2), 3)" )); //! [scan.left] }{ //! [scan.right] auto to_string = [](auto x) { std::ostringstream ss; ss << x; return ss.str(); }; auto f = [=](auto element, auto state) { return "f(" + to_string(element) + ", " + to_string(state) + ")"; }; // with initial state BOOST_HANA_RUNTIME_CHECK(scan.right(make_tuple(1, "2", '3'), 4, f) == make_tuple( "f(1, f(2, f(3, 4)))", "f(2, f(3, 4))", "f(3, 4)", 4 )); // without initial state BOOST_HANA_RUNTIME_CHECK(scan.right(make_tuple(1, "2", '3'), f) == make_tuple( "f(1, f(2, 3))", "f(2, 3)", '3' )); //! [scan.right] }{ //! [slice] BOOST_HANA_CONSTEXPR_CHECK( slice(make_tuple(1, '2', 3.3, type), int_<1>, int_<3>) == make_tuple('2', 3.3) ); //! [slice] }{ //! [slice_c] BOOST_HANA_CONSTEXPR_CHECK( slice_c<1, 3>(make_tuple(1, '2', 3.3, type)) == make_tuple('2', 3.3) ); //! [slice_c] }{ //! [sort] using namespace boost::hana::literals; // without a predicate BOOST_HANA_CONSTANT_CHECK( sort(make_tuple(1_c, -2_c, 3_c, 0_c)) == make_tuple(-2_c, 0_c, 1_c, 3_c) ); // with a predicate BOOST_HANA_CONSTANT_CHECK( sort(make_tuple(1_c, -2_c, 3_c, 0_c), greater) == make_tuple(3_c, 1_c, 0_c, -2_c) ); //! [sort] }{ //! [sort.by] using namespace std::literals; using namespace boost::hana::literals; auto tuples = make( make(2_c, 'x', nullptr), make(1_c, "foobar"s, int_<4>) ); BOOST_HANA_RUNTIME_CHECK( sort.by(ordering(head), tuples) == make( make(1_c, "foobar"s, int_<4>), make(2_c, 'x', nullptr) ) ); //! [sort.by] }{ //! [span] constexpr auto xs = make_tuple(int_<1>, int_<2>, int_<3>, int_<4>); BOOST_HANA_CONSTANT_CHECK( span(xs, _ < int_<3>) == make_pair(make_tuple(int_<1>, int_<2>), make_tuple(int_<3>, int_<4>)) ); BOOST_HANA_CONSTANT_CHECK( span(xs, _ < int_<0>) == make_pair(make_tuple(), xs) ); BOOST_HANA_CONSTANT_CHECK( span(xs, _ < int_<5>) == make_pair(xs, make_tuple()) ); //! [span] }{ //! [span.by] constexpr auto xs = make_tuple(int_<1>, int_<2>, int_<3>, int_<4>); BOOST_HANA_CONSTANT_CHECK( span.by(_ < int_<3>, xs) == make_pair(make_tuple(int_<1>, int_<2>), make_tuple(int_<3>, int_<4>)) ); //! [span.by] }{ //! [subsequence] constexpr auto letters = to(range_c); constexpr auto indices = to(make(int_<0>, length(letters))); BOOST_HANA_CONSTEXPR_LAMBDA auto even_indices = filter(indices, [](auto n) { return n % uint<2> == uint<0>; }); BOOST_HANA_CONSTANT_CHECK( subsequence(letters, even_indices) == tuple_c ); //! [subsequence] }{ //! [take] using namespace boost::hana::literals; BOOST_HANA_CONSTANT_CHECK( take(make_tuple(1, '2', 3.3), 0_c) == make_tuple()); BOOST_HANA_CONSTEXPR_CHECK(take(make_tuple(1, '2', 3.3), 1_c) == make_tuple(1)); BOOST_HANA_CONSTEXPR_CHECK(take(make_tuple(1, '2', 3.3), 2_c) == make_tuple(1, '2')); BOOST_HANA_CONSTEXPR_CHECK(take(make_tuple(1, '2', 3.3), 3_c) == make_tuple(1, '2', 3.3)); BOOST_HANA_CONSTEXPR_CHECK(take(make_tuple(1, '2', 3.3), 4_c) == make_tuple(1, '2', 3.3)); //! [take] }{ //! [take_c] BOOST_HANA_CONSTEXPR_CHECK(take_c<2>(make_tuple(1, '2', 3.3)) == make_tuple(1, '2')); //! [take_c] }{ //! [take_until] using namespace boost::hana::literals; BOOST_HANA_CONSTANT_CHECK( take_until(tuple_c, _ < 2_c) == tuple_c ); //! [take_until] }{ //! [take_while] using namespace boost::hana::literals; BOOST_HANA_CONSTANT_CHECK( take_while(tuple_c, _ < 2_c) == tuple_c ); //! [take_while] }{ //! [unfold] BOOST_HANA_CONSTANT_CHECK( unfold.left(int_<10>, [](auto x) { return if_(x == int_<0>, nothing, just(make_pair(x - int_<1>, x)) ); }) == tuple_c ); BOOST_HANA_CONSTANT_CHECK( unfold.right(int_<10>, [](auto x) { return if_(x == int_<0>, nothing, just(make_pair(x, x - int_<1>)) ); }) == tuple_c ); //! [unfold] }{ //! [unique] using namespace std::literals; // without a predicate constexpr auto types = tuple_t; BOOST_HANA_CONSTANT_CHECK( unique(types) == tuple_t ); // with a predicate auto objects = make_tuple(1, 2, "abc"s, 'd', "efg"s, "hij"s, 3.4f); BOOST_HANA_RUNTIME_CHECK( unique(objects, [](auto const& t, auto const& u) { return decltype_(t) == decltype_(u); }) == make_tuple(1, "abc"s, 'd', "efg"s, 3.4f) ); //! [unique] }{ //! [unique.by] using namespace std::literals; auto objects = make_tuple(1, 2, "abc"s, 'd', "efg"s, "hij"s, 3.4f); BOOST_HANA_RUNTIME_CHECK( unique.by(comparing(decltype_), objects) == make_tuple(1, "abc"s, 'd', "efg"s, 3.4f) ); //! [unique.by] }{ //! [unzip] BOOST_HANA_CONSTEXPR_CHECK( unzip(make_tuple(make_tuple(1, '2', 3.3), make_tuple('4', 5.5, 6))) == make_tuple(make_tuple(1, '4'), make_tuple('2', 5.5), make_tuple(3.3, 6)) ); BOOST_HANA_CONSTEXPR_CHECK( unzip(make_tuple(make_tuple(1, '2', 3.3), make_tuple('4', 5.5, 6, "ignored"))) == make_tuple(make_tuple(1, '4'), make_tuple('2', 5.5), make_tuple(3.3, 6)) ); //! [unzip] }{ //! [zip] BOOST_HANA_CONSTEXPR_CHECK( zip(make_tuple(1, 'a'), make_tuple(2, 3.3)) == make_tuple(make_tuple(1, 2), make_tuple('a', 3.3)) ); BOOST_HANA_CONSTEXPR_CHECK( zip(make_tuple(1, 'a'), make_tuple(2, 3.3), make_tuple(3, 'c', "ignored")) == make_tuple(make_tuple(1, 2, 3), make_tuple('a', 3.3, 'c')) ); //! [zip] }{ //! [zip_with] BOOST_HANA_CONSTEXPR_CHECK( zip.with(_ * _, make_tuple(1, 2, 3, 4), make_tuple(5, 6, 7, 8, "ignored")) == make_tuple(5, 12, 21, 32) ); //! [zip_with] } }