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 #ifndef BOOST_HANA_TEST_LAWS_ITERABLE_HPP
6 #define BOOST_HANA_TEST_LAWS_ITERABLE_HPP
7 
8 #include <boost/hana/any_of.hpp>
9 #include <boost/hana/assert.hpp>
10 #include <boost/hana/at.hpp>
11 #include <boost/hana/back.hpp>
12 #include <boost/hana/bool.hpp>
13 #include <boost/hana/concept/comparable.hpp>
14 #include <boost/hana/concept/foldable.hpp>
15 #include <boost/hana/concept/sequence.hpp>
16 #include <boost/hana/core/make.hpp>
17 #include <boost/hana/core/to.hpp>
18 #include <boost/hana/core/when.hpp>
19 #include <boost/hana/drop_front.hpp>
20 #include <boost/hana/drop_front_exactly.hpp>
21 #include <boost/hana/equal.hpp>
22 #include <boost/hana/eval_if.hpp>
23 #include <boost/hana/find_if.hpp>
24 #include <boost/hana/for_each.hpp>
25 #include <boost/hana/front.hpp>
26 #include <boost/hana/functional/always.hpp>
27 #include <boost/hana/functional/capture.hpp>
28 #include <boost/hana/integral_constant.hpp>
29 #include <boost/hana/is_empty.hpp>
30 #include <boost/hana/lazy.hpp>
31 #include <boost/hana/length.hpp>
32 #include <boost/hana/minus.hpp>
33 #include <boost/hana/not.hpp>
34 #include <boost/hana/optional.hpp>
35 #include <boost/hana/range.hpp>
36 #include <boost/hana/tuple.hpp>
37 
38 #include <laws/base.hpp>
39 
40 
41 namespace boost { namespace hana { namespace test {
42     template <typename It, typename = hana::when<true>>
43     struct TestIterable : TestIterable<It, laws> {
44         using TestIterable<It, laws>::TestIterable;
45     };
46 
47     template <typename It>
48     struct TestIterable<It, laws> {
49         template <typename Xs>
TestIterableboost::hana::test::TestIterable50         TestIterable(Xs xs) {
51             hana::for_each(xs, [](auto xs) {
52                 static_assert(Iterable<decltype(xs)>{}, "");
53 
54                 BOOST_HANA_CONSTANT_CHECK(
55                     hana::is_empty(xs) ^iff^ hana::is_empty(hana::to<tuple_tag>(xs))
56                 );
57 
58                 only_when_(hana::not_(hana::is_empty(xs)), hana::make_lazy([](auto xs) {
59                     BOOST_HANA_CHECK(hana::equal(
60                         hana::front(xs),
61                         hana::front(hana::to<tuple_tag>(xs))
62                     ));
63 
64                     BOOST_HANA_CHECK(hana::equal(
65                         hana::to<tuple_tag>(hana::drop_front_exactly(xs)),
66                         hana::drop_front_exactly(hana::to<tuple_tag>(xs))
67                     ));
68 
69                     // methods
70                     // back(xs) == at(xs, length(xs)-1)
71                     BOOST_HANA_CHECK(hana::equal(
72                         hana::back(xs),
73                         hana::at(xs, hana::minus(hana::length(xs), hana::size_c<1>))
74                     ));
75 
76                 })(xs));
77 
78                 // drop_front(xs, 0) == xs
79                 BOOST_HANA_CHECK(hana::equal(
80                     hana::drop_front(xs, size_c<0>),
81                     xs
82                 ));
83 
84                 // at(xs, n) == front(drop_front(xs, n))
85                 hana::for_each(hana::make_range(size_c<0>, hana::length(xs)),
86                 hana::capture(xs)([](auto xs, auto n) {
87                     BOOST_HANA_CHECK(hana::equal(
88                         hana::at(xs, n),
89                         hana::front(hana::drop_front(xs, n))
90                     ));
91                 }));
92 
93                 // Searchable
94                 hana::eval_if(hana::is_empty(xs),
95                     hana::make_lazy([](auto xs) {
96                         BOOST_HANA_CONSTANT_CHECK(
97                             hana::not_(hana::any_of(xs, hana::always(true_c)))
98                         );
99 
100                         BOOST_HANA_CONSTANT_CHECK(hana::equal(
101                             hana::find_if(xs, hana::always(true_c)),
102                             nothing
103                         ));
104                     })(xs),
105                     hana::make_lazy([](auto xs) {
106                         BOOST_HANA_CHECK(
107                             hana::any_of(xs, hana::always(true_c))
108                         );
109                         BOOST_HANA_CHECK(
110                             hana::not_(hana::any_of(xs, hana::always(false_c)))
111                         );
112 
113                         BOOST_HANA_CHECK(hana::equal(
114                             hana::find_if(xs, hana::always(true_c)),
115                             hana::just(hana::front(xs))
116                         ));
117                     })(xs)
118                 );
119 
120             });
121         }
122     };
123 
124     template <typename S>
125     struct TestIterable<S, when<Sequence<S>::value>>
126         : TestIterable<S, laws>
127     {
128         template <int i>
129         using x = ct_eq<i>;
130 
131         template <int i = 0>
132         struct invalid { };
133 
134         struct undefined { };
135 
136         template <typename Xs>
TestIterableboost::hana::test::TestIterable137         TestIterable(Xs xs) : TestIterable<S, laws>{xs} {
138             constexpr auto list = make<S>;
139 
140             //////////////////////////////////////////////////////////////////
141             // front
142             //////////////////////////////////////////////////////////////////
143             BOOST_HANA_CONSTANT_CHECK(equal(
144                 front(list(x<0>{})),
145                 x<0>{}
146             ));
147             BOOST_HANA_CONSTANT_CHECK(equal(
148                 front(list(x<0>{}, invalid<>{})),
149                 x<0>{}
150             ));
151             BOOST_HANA_CONSTANT_CHECK(equal(
152                 front(list(x<0>{}, invalid<1>{}, invalid<2>{})),
153                 x<0>{}
154             ));
155 
156             BOOST_HANA_CONSTEXPR_CHECK(equal(
157                 front(list(1)), 1
158             ));
159             BOOST_HANA_CONSTEXPR_CHECK(equal(
160                 front(list(1, '2')), 1
161             ));
162             BOOST_HANA_CONSTEXPR_CHECK(equal(
163                 front(list(1, '2', 3.3)), 1
164             ));
165 
166             //////////////////////////////////////////////////////////////////
167             // back
168             //////////////////////////////////////////////////////////////////
169             BOOST_HANA_CONSTANT_CHECK(equal(
170                 back(list(x<0>{})),
171                 x<0>{}
172             ));
173             BOOST_HANA_CONSTANT_CHECK(equal(
174                 back(list(invalid<0>{}, x<1>{})),
175                 x<1>{}
176             ));
177             BOOST_HANA_CONSTANT_CHECK(equal(
178                 back(list(invalid<0>{}, invalid<1>{}, x<2>{})),
179                 x<2>{}
180             ));
181 
182             BOOST_HANA_CONSTEXPR_CHECK(equal(
183                 back(list(1)), 1
184             ));
185             BOOST_HANA_CONSTEXPR_CHECK(equal(
186                 back(list(1, '2')), '2'
187             ));
188             BOOST_HANA_CONSTEXPR_CHECK(equal(
189                 back(list(1, '2', 3.3)), 3.3
190             ));
191         }
192     };
193 }}} // end namespace boost::hana::test
194 
195 #endif // !BOOST_HANA_TEST_LAWS_ITERABLE_HPP
196