/* @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 #include #include #include #include using namespace boost::hana; template using void_t = void; template struct has_type : std::false_type { }; template struct has_type> : std::true_type { }; struct undefined { }; using test::ct_eq; using test::ct_ord; int main() { auto ords = make( nothing, just(ct_ord<0>{}), just(ct_ord<1>{}), just(ct_ord<2>{}) ); (void)ords; auto eqs = make( nothing, just(ct_eq<0>{}), just(ct_eq<1>{}), just(ct_eq<2>{}) ); (void)eqs; auto eq_values = make(ct_eq<0>{}, ct_eq<2>{}, ct_eq<3>{}); (void)eq_values; auto predicates = make( equal.to(ct_eq<0>{}), equal.to(ct_eq<2>{}), equal.to(ct_eq<3>{}), always(false_), always(true_) ); (void)predicates; auto nested_eqs = make( nothing, just(just(ct_eq<0>{})), just(nothing), just(just(ct_eq<2>{})) ); (void)nested_eqs; #if BOOST_HANA_TEST_PART == 1 ////////////////////////////////////////////////////////////////////////// // Maybe interface ////////////////////////////////////////////////////////////////////////// { test::_injection<0> f{}; test::ct_eq<2> x{}; test::ct_eq<3> y{}; // Interaction with Type (has a nested ::type) { struct T; static_assert(std::is_same))::type, T>{}, ""); static_assert(!has_type{}, ""); } // maybe { BOOST_HANA_CONSTANT_CHECK(equal(maybe(x, undefined{}, nothing), x)); BOOST_HANA_CONSTANT_CHECK(equal(maybe(undefined{}, f, just(x)), f(x))); } // is_nothing { BOOST_HANA_CONSTANT_CHECK(is_nothing(nothing)); BOOST_HANA_CONSTANT_CHECK(not_(is_nothing(just(undefined{})))); } // is_just { BOOST_HANA_CONSTANT_CHECK(is_just(just(undefined{}))); BOOST_HANA_CONSTANT_CHECK(not_(is_just(nothing))); } // from_just { BOOST_HANA_CONSTANT_CHECK(equal(from_just(just(x)), x)); { auto lvalue = just(test::ct_eq<3>{}); test::ct_eq<3>& ref = *lvalue; BOOST_HANA_CONSTANT_CHECK(equal( ref, test::ct_eq<3>{} )); auto const const_lvalue = just(test::ct_eq<3>{}); test::ct_eq<3> const& const_ref = *const_lvalue; BOOST_HANA_CONSTANT_CHECK(equal( const_ref, test::ct_eq<3>{} )); BOOST_HANA_CONSTANT_CHECK(equal( *just(test::ct_eq<3>{}), test::ct_eq<3>{} )); } { struct object { test::ct_eq<3> member; }; auto lvalue = just(object{}); test::ct_eq<3>& ref = lvalue->member; BOOST_HANA_CONSTANT_CHECK(equal( ref, test::ct_eq<3>{} )); auto const const_lvalue = just(object{}); test::ct_eq<3> const& const_ref = const_lvalue->member; BOOST_HANA_CONSTANT_CHECK(equal( const_ref, test::ct_eq<3>{} )); BOOST_HANA_CONSTANT_CHECK(equal( just(object{})->member, test::ct_eq<3>{} )); } } // from_maybe { BOOST_HANA_CONSTANT_CHECK(equal(from_maybe(x, nothing), x)); BOOST_HANA_CONSTANT_CHECK(equal(from_maybe(undefined{}, just(y)), y)); } // only_when { BOOST_HANA_CONSTANT_CHECK(equal( only_when(always(true_), f, x), just(f(x)) )); BOOST_HANA_CONSTANT_CHECK(equal( only_when(always(false_), f, x), nothing )); BOOST_HANA_CONSTANT_CHECK(equal( only_when(always(false_), undefined{}, x), nothing )); } // sfinae { test::_injection<0> f{}; BOOST_HANA_CONSTANT_CHECK(equal( sfinae(f)(), just(f()) )); BOOST_HANA_CONSTANT_CHECK(equal( sfinae(f)(ct_eq<0>{}), just(f(ct_eq<0>{})) )); BOOST_HANA_CONSTANT_CHECK(equal( sfinae(f)(ct_eq<0>{}, ct_eq<1>{}), just(f(ct_eq<0>{}, ct_eq<1>{})) )); BOOST_HANA_CONSTANT_CHECK(equal( sfinae(undefined{})(), nothing )); BOOST_HANA_CONSTANT_CHECK(equal( sfinae(undefined{})(ct_eq<0>{}), nothing )); BOOST_HANA_CONSTANT_CHECK(equal( sfinae(undefined{})(ct_eq<0>{}, ct_eq<1>{}), nothing )); BOOST_HANA_CONSTEXPR_LAMBDA auto incr = sfinae([](auto x) -> decltype(x + 1) { return x + 1; }); BOOST_HANA_CONSTEXPR_CHECK(equal( incr(1), just(2) )); BOOST_HANA_CONSTANT_CHECK(equal( incr(undefined{}), nothing )); BOOST_HANA_CONSTEXPR_CHECK(equal( bind(just(1), incr), just(2) )); // using `sfinae` with a non-pod argument used to fail sfinae(undefined{})(Tracked{1}); sfinae([t = Tracked{1}](auto) { return 1; })(Tracked{1}); } // Make sure we do not instantiate rogue contructors when trying // to copy a just. { auto expr = just(test::trap_construct{}); auto implicit_copy = expr; (void)implicit_copy; decltype(expr) explicit_copy(expr); (void)explicit_copy; } // implicit and explicit construction of just { _just j1{1}; (void)j1; _just j2 = {1}; (void)j2; } } #elif BOOST_HANA_TEST_PART == 2 ////////////////////////////////////////////////////////////////////////// // Comparable ////////////////////////////////////////////////////////////////////////// { // equal { test::ct_eq<3> x{}; test::ct_eq<4> y{}; BOOST_HANA_CONSTANT_CHECK(equal(nothing, nothing)); BOOST_HANA_CONSTANT_CHECK(not_(equal(nothing, just(x)))); BOOST_HANA_CONSTANT_CHECK(not_(equal(just(x), nothing))); BOOST_HANA_CONSTANT_CHECK(equal(just(x), just(x))); BOOST_HANA_CONSTANT_CHECK(not_(equal(just(x), just(y)))); } // laws test::TestComparable{eqs}; } #elif BOOST_HANA_TEST_PART == 3 ////////////////////////////////////////////////////////////////////////// // Orderable ////////////////////////////////////////////////////////////////////////// { // less { BOOST_HANA_CONSTANT_CHECK(less( nothing, just(undefined{}) )); BOOST_HANA_CONSTANT_CHECK(not_(less( just(undefined{}), nothing ))); BOOST_HANA_CONSTANT_CHECK(not_(less( nothing, nothing ))); BOOST_HANA_CONSTANT_CHECK(less( just(ct_ord<3>{}), just(ct_ord<4>{}) )); BOOST_HANA_CONSTANT_CHECK(not_(less( just(ct_ord<3>{}), just(ct_ord<3>{}) ))); BOOST_HANA_CONSTANT_CHECK(not_(less( just(ct_ord<4>{}), just(ct_ord<3>{}) ))); } // laws test::TestOrderable{ords}; } #elif BOOST_HANA_TEST_PART == 4 ////////////////////////////////////////////////////////////////////////// // Functor ////////////////////////////////////////////////////////////////////////// { // transform { test::_injection<0> f{}; BOOST_HANA_CONSTANT_CHECK(equal( transform(nothing, f), nothing )); BOOST_HANA_CONSTANT_CHECK(equal( transform(just(ct_eq<3>{}), f), just(f(ct_eq<3>{})) )); } // laws test::TestFunctor{eqs, eq_values}; } ////////////////////////////////////////////////////////////////////////// // Applicative ////////////////////////////////////////////////////////////////////////// { test::_injection<0> f{}; // ap { BOOST_HANA_CONSTANT_CHECK(equal( ap(nothing, nothing), nothing )); BOOST_HANA_CONSTANT_CHECK(equal( ap(just(f), nothing), nothing )); BOOST_HANA_CONSTANT_CHECK(equal( ap(nothing, just(ct_eq<3>{})), nothing )); BOOST_HANA_CONSTANT_CHECK(equal( ap(just(f), just(ct_eq<3>{})), just(f(ct_eq<3>{})) )); } // lift { BOOST_HANA_CONSTANT_CHECK(equal( lift(ct_eq<3>{}), just(ct_eq<3>{}) )); } // laws test::TestApplicative{eqs}; } ////////////////////////////////////////////////////////////////////////// // Monad ////////////////////////////////////////////////////////////////////////// { // flatten { BOOST_HANA_CONSTANT_CHECK(equal( flatten(nothing), nothing )); BOOST_HANA_CONSTANT_CHECK(equal( flatten(just(nothing)), nothing )); BOOST_HANA_CONSTANT_CHECK(equal( flatten(just(just(ct_eq<4>{}))), just(ct_eq<4>{}) )); } // laws test::TestMonad{eqs, nested_eqs}; } ////////////////////////////////////////////////////////////////////////// // MonadPlus ////////////////////////////////////////////////////////////////////////// { // empty { BOOST_HANA_CONSTANT_CHECK(equal( empty(), nothing )); } // concat { auto rv_nothing = [] { return nothing; }; // rvalue nothing BOOST_HANA_CONSTANT_CHECK(equal( concat(rv_nothing(), nothing), nothing )); BOOST_HANA_CONSTANT_CHECK(equal( concat(nothing, rv_nothing()), nothing )); BOOST_HANA_CONSTANT_CHECK(equal( concat(rv_nothing(), rv_nothing()), nothing )); BOOST_HANA_CONSTANT_CHECK(equal( concat(rv_nothing(), just(ct_eq<0>{})), just(ct_eq<0>{}) )); BOOST_HANA_CONSTANT_CHECK(equal( concat(just(ct_eq<0>{}), rv_nothing()), just(ct_eq<0>{}) )); BOOST_HANA_CONSTANT_CHECK(equal( concat(nothing, nothing), nothing )); BOOST_HANA_CONSTANT_CHECK(equal( concat(nothing, just(ct_eq<0>{})), just(ct_eq<0>{}) )); BOOST_HANA_CONSTANT_CHECK(equal( concat(just(ct_eq<0>{}), nothing), just(ct_eq<0>{}) )); BOOST_HANA_CONSTANT_CHECK(equal( concat(just(ct_eq<0>{}), just(ct_eq<1>{})), just(ct_eq<0>{}) )); } // laws test::TestMonadPlus{eqs, predicates, eq_values}; } #elif BOOST_HANA_TEST_PART == 5 ////////////////////////////////////////////////////////////////////////// // Traversable ////////////////////////////////////////////////////////////////////////// { test::_injection<0> f{}; auto applicative = test::identity; using A = test::Identity; // traverse { BOOST_HANA_CONSTANT_CHECK(equal( traverse(just(ct_eq<3>{}), compose(applicative, f)), applicative(just(f(ct_eq<3>{}))) )); BOOST_HANA_CONSTANT_CHECK(equal( traverse(nothing, compose(applicative, f)), applicative(nothing) )); } // laws test::TestTraversable{}; } ////////////////////////////////////////////////////////////////////////// // Searchable ////////////////////////////////////////////////////////////////////////// { test::ct_eq<2> x{}; test::ct_eq<3> y{}; // find_if { BOOST_HANA_CONSTANT_CHECK(equal( find_if(just(x), equal.to(x)), just(x) )); BOOST_HANA_CONSTANT_CHECK(equal( find_if(just(x), equal.to(y)), nothing )); BOOST_HANA_CONSTANT_CHECK(equal( find_if(nothing, equal.to(x)), nothing )); // Previously, there was a bug that would make this fail. auto non_const_nothing = nothing; BOOST_HANA_CONSTANT_CHECK(equal( find_if(non_const_nothing, equal.to(x)), nothing )); } // any_of { BOOST_HANA_CONSTANT_CHECK(any_of(just(x), equal.to(x))); BOOST_HANA_CONSTANT_CHECK(not_(any_of(just(x), equal.to(y)))); BOOST_HANA_CONSTANT_CHECK(not_(any_of(nothing, equal.to(x)))); } // laws test::TestSearchable{eqs, eq_values}; } #elif BOOST_HANA_TEST_PART == 6 ////////////////////////////////////////////////////////////////////////// // Foldable ////////////////////////////////////////////////////////////////////////// { test::ct_eq<2> x{}; test::ct_eq<3> s{}; test::_injection<0> f{}; // fold.left { BOOST_HANA_CONSTANT_CHECK(equal(fold.left(just(x), s, f), f(s, x))); BOOST_HANA_CONSTANT_CHECK(equal(fold.left(nothing, s, f), s)); } // fold.right { BOOST_HANA_CONSTANT_CHECK(equal(fold.right(just(x), s, f), f(x, s))); BOOST_HANA_CONSTANT_CHECK(equal(fold.right(nothing, s, f), s)); } // unpack { BOOST_HANA_CONSTANT_CHECK(equal(unpack(nothing, f), f())); BOOST_HANA_CONSTANT_CHECK(equal(unpack(just(x), f), f(x))); // Previously, there was a bug that would make this fail. auto non_const_nothing = nothing; BOOST_HANA_CONSTANT_CHECK(equal(unpack(non_const_nothing, f), f())); } // laws test::TestFoldable{eqs}; } #endif }