1 // Copyright Louis Dionne 2013-2017
2 // Distributed under the Boost Software License, Version 1.0.
3 // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
4 
5 #include <boost/hana/assert.hpp>
6 #include <boost/hana/at.hpp>
7 #include <boost/hana/bool.hpp>
8 #include <boost/hana/drop_front.hpp>
9 #include <boost/hana/eval.hpp>
10 #include <boost/hana/front.hpp>
11 #include <boost/hana/functional/fix.hpp>
12 #include <boost/hana/functional/iterate.hpp>
13 #include <boost/hana/fwd/at.hpp>
14 #include <boost/hana/fwd/empty.hpp>
15 #include <boost/hana/fwd/prepend.hpp>
16 #include <boost/hana/integral_constant.hpp>
17 #include <boost/hana/is_empty.hpp>
18 #include <boost/hana/lazy.hpp>
19 #include <boost/hana/not.hpp>
20 #include <boost/hana/value.hpp>
21 
22 #include <cstddef>
23 namespace hana = boost::hana;
24 
25 
26 // A naive implementation of a lazy compile-time list, i.e. a tuple that can
27 // potentially have an infinite number of elements (but that infinity must be
28 // determinable at compile-time).
29 
30 struct LazyList;
31 
32 template <typename X, typename Xs>
33 struct lazy_cons_type {
34     X x;
35     Xs xs;
36     using hana_tag = LazyList;
37 };
38 
__anonf7ea95ea0102(auto x, auto xs) 39 auto lazy_cons = [](auto x, auto xs) {
40     return lazy_cons_type<decltype(x), decltype(xs)>{x, xs};
41 };
42 
43 struct lazy_nil_type { using hana_tag = LazyList; };
44 
45 constexpr lazy_nil_type lazy_nil{};
46 
__anonf7ea95ea0202(auto repeat, auto x) 47 auto repeat = hana::fix([](auto repeat, auto x) {
48     return lazy_cons(x, hana::make_lazy(repeat)(x));
49 });
50 
51 namespace boost { namespace hana {
52     //////////////////////////////////////////////////////////////////////////
53     // Iterable
54     //////////////////////////////////////////////////////////////////////////
55     template <>
56     struct at_impl<LazyList> {
57         template <typename Xs, typename N>
applyboost::hana::at_impl58         static constexpr auto apply(Xs&& lcons, N const& n) {
59             return hana::drop_front(lcons, n).x;
60         }
61     };
62 
63     namespace detail {
64         struct eval_tail {
65             template <typename Xs>
operator ()boost::hana::detail::eval_tail66             constexpr auto operator()(Xs const& lcons) const {
67                 return hana::eval(lcons.xs);
68             }
69 
operator ()boost::hana::detail::eval_tail70             constexpr auto operator()(lazy_nil_type const&) const {
71                 return lazy_nil;
72             }
73         };
74     }
75 
76     template <>
77     struct drop_front_impl<LazyList> {
78         template <typename Xs, typename N>
applyboost::hana::drop_front_impl79         static constexpr auto apply(Xs&& lcons, N const&) {
80             return hana::iterate<N::value>(detail::eval_tail{}, lcons);
81         }
82     };
83 
84     template <>
85     struct is_empty_impl<LazyList> {
86         template <typename Xs>
applyboost::hana::is_empty_impl87         static constexpr auto apply(Xs const&)
88         { return hana::false_c; }
89 
applyboost::hana::is_empty_impl90         static constexpr auto apply(lazy_nil_type const&)
91         { return hana::true_c; }
92     };
93 
94     //////////////////////////////////////////////////////////////////////////
95     // MonadPlus
96     //////////////////////////////////////////////////////////////////////////
97     template <>
98     struct prepend_impl<LazyList> {
99         template <typename Xs, typename X>
applyboost::hana::prepend_impl100         static constexpr auto apply(Xs xs, X x)
101         { return lazy_cons(x, hana::make_lazy(xs)); }
102     };
103 
104     template <>
105     struct empty_impl<LazyList> {
applyboost::hana::empty_impl106         static constexpr auto apply()
107         { return lazy_nil; }
108     };
109 }}
110 
111 
main()112 int main() {
113     BOOST_HANA_CONSTANT_CHECK(!hana::is_empty(repeat(1)));
114     BOOST_HANA_CONSTEXPR_CHECK(hana::front(repeat(1)) == 1);
115     BOOST_HANA_CONSTEXPR_CHECK(hana::at(repeat(1), hana::size_c<10>) == 1);
116 }
117