2
0
mirror of https://github.com/boostorg/hana.git synced 2026-01-22 17:22:30 +00:00
Files
hana/test/lazy.cpp
2015-02-01 10:35:17 -05:00

209 lines
5.8 KiB
C++

/*
@copyright Louis Dionne 2014
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/lazy.hpp>
#include <boost/hana/assert.hpp>
#include <boost/hana/comparable.hpp>
#include <boost/hana/detail/constexpr.hpp>
#include <boost/hana/functional/compose.hpp>
#include <boost/hana/tuple.hpp>
#include <boost/hana/type.hpp>
#include <array>
#include <iostream>
#include <test/auto/base.hpp>
#include <test/injection.hpp>
using namespace boost::hana;
namespace boost { namespace hana {
// We provide this instance for unit tests only because it is _so_ much
// more convenient, but this instance is too dangerous for general usage.
// See the documentation of `Lazy` for more info.
template <>
struct equal_impl<Lazy, Lazy> {
template <typename X, typename Y>
static constexpr auto apply(X x, Y y)
{ return equal(eval(x), eval(y)); }
};
namespace test {
template <>
auto instances<Lazy> = tuple(
type<Functor>,
type<Applicative>,
type<Monad>
);
template <>
auto objects<Lazy> = tuple(
lazy(x<0>), lazy(x<1>), lazy(x<2>)
);
}
}}
auto invalid = [](auto x)
{ return x.this_function_must_not_be_instantiated; };
int main() {
test::check_datatype<Lazy>();
// Lazy methods
{
auto f = test::injection([]{});
using test::x;
// lazy
{
BOOST_HANA_CONSTANT_CHECK(equal(
lazy(f)(),
lazy(f())
));
BOOST_HANA_CONSTANT_CHECK(equal(
lazy(f)(x<0>),
lazy(f(x<0>))
));
BOOST_HANA_CONSTANT_CHECK(equal(
lazy(f)(x<0>, x<1>),
lazy(f(x<0>, x<1>))
));
BOOST_HANA_CONSTANT_CHECK(equal(
lazy(f)(x<0>, x<1>, x<2>),
lazy(f(x<0>, x<1>, x<2>))
));
// The function is not applied.
lazy(invalid)();
lazy(invalid)(x<0>);
lazy(invalid)(x<0>, x<1>);
lazy(invalid)(x<0>, x<1>, x<2>);
}
// eval
{
BOOST_HANA_CONSTANT_CHECK(equal(eval(lazy(x<0>)), x<0>));
BOOST_HANA_CONSTANT_CHECK(equal(eval(lazy(x<1>)), x<1>));
}
}
// Functor
{
auto x = test::injection([]{})();
auto f = test::injection([]{});
// transform
{
BOOST_HANA_CONSTANT_CHECK(equal(
transform(lazy(x), f),
lazy(f(x))
));
}
}
// Applicative
{
auto f = test::injection([]{});
using test::x;
// ap
{
BOOST_HANA_CONSTANT_CHECK(equal(
ap(lazy(f), lazy(x<0>)),
lazy(f(x<0>))
));
BOOST_HANA_CONSTANT_CHECK(equal(
ap(lazy(f), lazy(x<0>), lazy(x<1>)),
lazy(f(x<0>, x<1>))
));
BOOST_HANA_CONSTANT_CHECK(equal(
ap(lazy(f), lazy(x<0>), lazy(x<1>), lazy(x<2>)),
lazy(f(x<0>, x<1>, x<2>))
));
// The function is not applied.
ap(lazy(invalid), lazy(x<0>));
ap(lazy(invalid), lazy(x<0>), lazy(x<1>));
ap(lazy(invalid), lazy(x<0>), lazy(x<1>), lazy(x<2>));
}
// lift
{
BOOST_HANA_CONSTANT_CHECK(equal(lift<Lazy>(x<0>), lazy(x<0>)));
BOOST_HANA_CONSTANT_CHECK(equal(lift<Lazy>(x<1>), lazy(x<1>)));
}
}
// Monad
{
using test::x;
auto f = compose(lazy, test::injection([]{}));
// bind
{
BOOST_HANA_CONSTANT_CHECK(equal(bind(lazy(x<0>), f), f(x<0>)));
BOOST_HANA_CONSTANT_CHECK(equal(bind(lazy(x<1>), f), f(x<1>)));
}
// flatten
{
BOOST_HANA_CONSTANT_CHECK(equal(
flatten(lazy(lazy(x<0>))),
lazy(x<0>)
));
BOOST_HANA_CONSTANT_CHECK(equal(
flatten(lazy(lazy(x<1>))),
lazy(x<1>)
));
BOOST_HANA_CONSTANT_CHECK(equal(
flatten(lazy(lazy(lazy(x<1>)))),
lazy(lazy(x<1>))
));
}
// Make sure the monadic chain is evaluated in the right order.
{
std::array<bool, 3> executed = {{false, false, false}};
int dummy = 0;
std::cerr << "creating the monadic chain...\n";
auto chain = lazy(dummy)
| [&](int dummy) {
std::cerr << "executing the first computation...\n";
executed[0] = true;
BOOST_HANA_RUNTIME_CHECK(
executed == std::array<bool, 3>{{true, false, false}}
);
return lazy(dummy);
}
| [&](int dummy) {
std::cerr << "executing the second computation...\n";
executed[1] = true;
BOOST_HANA_RUNTIME_CHECK(
executed == std::array<bool, 3>{{true, true, false}}
);
return lazy(dummy);
}
| [&](int dummy) {
std::cerr << "executing the third computation...\n";
executed[2] = true;
BOOST_HANA_RUNTIME_CHECK(
executed == std::array<bool, 3>{{true, true, true}}
);
return lazy(dummy);
};
BOOST_HANA_RUNTIME_CHECK(
executed == std::array<bool, 3>{{false, false, false}}
);
std::cerr << "evaluating the chain...\n";
eval(chain);
}
}
}