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_FUNCTOR_HPP
6 #define BOOST_HANA_TEST_LAWS_FUNCTOR_HPP
7 
8 #include <boost/hana/adjust.hpp>
9 #include <boost/hana/adjust_if.hpp>
10 #include <boost/hana/assert.hpp>
11 #include <boost/hana/bool.hpp>
12 #include <boost/hana/concept/comparable.hpp>
13 #include <boost/hana/concept/functor.hpp>
14 #include <boost/hana/concept/sequence.hpp>
15 #include <boost/hana/core/make.hpp>
16 #include <boost/hana/core/when.hpp>
17 #include <boost/hana/equal.hpp>
18 #include <boost/hana/eval_if.hpp>
19 #include <boost/hana/fill.hpp>
20 #include <boost/hana/for_each.hpp>
21 #include <boost/hana/functional/always.hpp>
22 #include <boost/hana/functional/capture.hpp>
23 #include <boost/hana/functional/compose.hpp>
24 #include <boost/hana/lazy.hpp>
25 #include <boost/hana/replace.hpp>
26 #include <boost/hana/replace_if.hpp>
27 #include <boost/hana/transform.hpp>
28 
29 #include <laws/base.hpp>
30 
31 
32 namespace boost { namespace hana { namespace test {
33     template <typename F, typename = when<true>>
34     struct TestFunctor : TestFunctor<F, laws> {
35         using TestFunctor<F, laws>::TestFunctor;
36     };
37 
38     template <typename F>
39     struct TestFunctor<F, laws> {
40         template <typename Xs, typename Elements>
TestFunctorboost::hana::test::TestFunctor41         TestFunctor(Xs xs, Elements elements) {
42             hana::for_each(xs, hana::capture(elements)([](auto elements, auto x) {
43                 static_assert(Functor<decltype(x)>{}, "");
44 
45                 test::_injection<0> f{};
46                 test::_injection<1> g{};
47 
48                 // identity
49                 BOOST_HANA_CHECK(hana::equal(
50                     hana::transform(x, id),
51                     x
52                 ));
53 
54                 // composition
55                 BOOST_HANA_CHECK(hana::equal(
56                     hana::transform(x, hana::compose(f, g)),
57                     hana::transform(hana::transform(x, g), f)
58                 ));
59 
60                 // method definitions in terms of transform/adjust_if
61                 hana::for_each(elements, hana::capture(x, f, elements)(
62                 [](auto x, auto f, auto elements, auto value) {
63                     BOOST_HANA_CHECK(hana::equal(
64                         hana::adjust(x, value, f),
65                         hana::adjust_if(x, hana::equal.to(value), f)
66                     ));
67 
68                     hana::for_each(elements, hana::capture(x, value)(
69                     [](auto x, auto oldval, auto newval) {
70                         BOOST_HANA_CHECK(hana::equal(
71                             hana::replace(x, oldval, newval),
72                             hana::replace_if(x, hana::equal.to(oldval), newval)
73                         ));
74                     }));
75                 }));
76 
77                 auto pred = hana::always(true_c);
78                 BOOST_HANA_CHECK(hana::equal(
79                     hana::adjust_if(x, pred, f),
80                     hana::transform(x, [=](auto z) {
81                         return hana::eval_if(pred(z),
82                             hana::make_lazy(f)(z),
83                             hana::make_lazy(z)
84                         );
85                     })
86                 ));
87 
88                 test::_constant<0> v{};
89                 BOOST_HANA_CHECK(hana::equal(
90                     hana::replace_if(x, pred, v),
91                     hana::adjust_if(x, pred, hana::always(v))
92                 ));
93 
94                 BOOST_HANA_CHECK(hana::equal(
95                     hana::fill(x, v),
96                     hana::replace_if(x, hana::always(true_c), v)
97                 ));
98 
99             }));
100         }
101     };
102 
103     template <typename S>
104     struct TestFunctor<S, when<Sequence<S>::value>>
105         : TestFunctor<S, laws>
106     {
107         struct undefined { };
108 
109         template <typename Xs, typename Elements>
TestFunctorboost::hana::test::TestFunctor110         TestFunctor(Xs xs, Elements elements)
111             : TestFunctor<S, laws>{xs, elements}
112         {
113             using test::ct_eq;
114             using test::cx_eq;
115             constexpr auto list = make<S>;
116 
117             //////////////////////////////////////////////////////////////////
118             // replace_if
119             //////////////////////////////////////////////////////////////////
120             {
121             auto a = ct_eq<888>{};
122             auto b = ct_eq<999>{};
123 
124             BOOST_HANA_CONSTANT_CHECK(hana::equal(
125                 hana::replace_if(list(), undefined{}, undefined{}),
126                 list()
127             ));
128 
129             BOOST_HANA_CONSTANT_CHECK(hana::equal(
130                 hana::replace_if(list(ct_eq<0>{}), equal.to(a), undefined{}),
131                 list(ct_eq<0>{})
132             ));
133             BOOST_HANA_CONSTANT_CHECK(hana::equal(
134                 hana::replace_if(list(a), equal.to(a), b),
135                 list(b)
136             ));
137 
138             BOOST_HANA_CONSTANT_CHECK(hana::equal(
139                 hana::replace_if(list(ct_eq<0>{}, ct_eq<1>{}), equal.to(a), undefined{}),
140                 list(ct_eq<0>{}, ct_eq<1>{})
141             ));
142             BOOST_HANA_CONSTANT_CHECK(hana::equal(
143                 hana::replace_if(list(a, ct_eq<1>{}), equal.to(a), b),
144                 list(b, ct_eq<1>{})
145             ));
146             BOOST_HANA_CONSTANT_CHECK(hana::equal(
147                 hana::replace_if(list(ct_eq<0>{}, a), equal.to(a), b),
148                 list(ct_eq<0>{}, b)
149             ));
150             BOOST_HANA_CONSTANT_CHECK(hana::equal(
151                 hana::replace_if(list(a, a), equal.to(a), b),
152                 list(b, b)
153             ));
154 
155             BOOST_HANA_CONSTANT_CHECK(hana::equal(
156                 hana::replace_if(list(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}), equal.to(a), undefined{}),
157                 list(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{})
158             ));
159             BOOST_HANA_CONSTANT_CHECK(hana::equal(
160                 hana::replace_if(list(a, ct_eq<1>{}, ct_eq<2>{}), equal.to(a), b),
161                 list(b, ct_eq<1>{}, ct_eq<2>{})
162             ));
163             BOOST_HANA_CONSTANT_CHECK(hana::equal(
164                 hana::replace_if(list(ct_eq<0>{}, a, ct_eq<2>{}), equal.to(a), b),
165                 list(ct_eq<0>{}, b, ct_eq<2>{})
166             ));
167             BOOST_HANA_CONSTANT_CHECK(hana::equal(
168                 hana::replace_if(list(ct_eq<0>{}, ct_eq<1>{}, a), equal.to(a), b),
169                 list(ct_eq<0>{}, ct_eq<1>{}, b)
170             ));
171             BOOST_HANA_CONSTANT_CHECK(hana::equal(
172                 hana::replace_if(list(a, ct_eq<1>{}, a), equal.to(a), b),
173                 list(b, ct_eq<1>{}, b)
174             ));
175 
176             BOOST_HANA_CONSTANT_CHECK(hana::equal(
177                 hana::replace_if(list(a, ct_eq<1>{}, a, ct_eq<3>{}, a), equal.to(a), b),
178                 list(b, ct_eq<1>{}, b, ct_eq<3>{}, b)
179             ));
180             }
181 
182             //////////////////////////////////////////////////////////////////
183             // replace
184             //////////////////////////////////////////////////////////////////
185             {
186             auto a = ct_eq<888>{};
187             auto b = ct_eq<999>{};
188 
189             BOOST_HANA_CONSTANT_CHECK(hana::equal(
190                 hana::replace(list(), undefined{}, undefined{}),
191                 list()
192             ));
193 
194             BOOST_HANA_CONSTANT_CHECK(hana::equal(
195                 hana::replace(list(ct_eq<0>{}), a, undefined{}),
196                 list(ct_eq<0>{})
197             ));
198             BOOST_HANA_CONSTANT_CHECK(hana::equal(
199                 hana::replace(list(a), a, b),
200                 list(b)
201             ));
202 
203             BOOST_HANA_CONSTANT_CHECK(hana::equal(
204                 hana::replace(list(ct_eq<0>{}, ct_eq<1>{}), a, undefined{}),
205                 list(ct_eq<0>{}, ct_eq<1>{})
206             ));
207             BOOST_HANA_CONSTANT_CHECK(hana::equal(
208                 hana::replace(list(a, ct_eq<1>{}), a, b),
209                 list(b, ct_eq<1>{})
210             ));
211             BOOST_HANA_CONSTANT_CHECK(hana::equal(
212                 hana::replace(list(ct_eq<0>{}, a), a, b),
213                 list(ct_eq<0>{}, b)
214             ));
215             BOOST_HANA_CONSTANT_CHECK(hana::equal(
216                 hana::replace(list(a, a), a, b),
217                 list(b, b)
218             ));
219 
220             BOOST_HANA_CONSTANT_CHECK(hana::equal(
221                 hana::replace(list(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}), a, undefined{}),
222                 list(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{})
223             ));
224             BOOST_HANA_CONSTANT_CHECK(hana::equal(
225                 hana::replace(list(a, ct_eq<1>{}, ct_eq<2>{}), a, b),
226                 list(b, ct_eq<1>{}, ct_eq<2>{})
227             ));
228             BOOST_HANA_CONSTANT_CHECK(hana::equal(
229                 hana::replace(list(ct_eq<0>{}, a, ct_eq<2>{}), a, b),
230                 list(ct_eq<0>{}, b, ct_eq<2>{})
231             ));
232             BOOST_HANA_CONSTANT_CHECK(hana::equal(
233                 hana::replace(list(ct_eq<0>{}, ct_eq<1>{}, a), a, b),
234                 list(ct_eq<0>{}, ct_eq<1>{}, b)
235             ));
236             BOOST_HANA_CONSTANT_CHECK(hana::equal(
237                 hana::replace(list(a, ct_eq<1>{}, a), a, b),
238                 list(b, ct_eq<1>{}, b)
239             ));
240 
241             BOOST_HANA_CONSTANT_CHECK(hana::equal(
242                 hana::replace(list(a, ct_eq<1>{}, a, ct_eq<3>{}, a), a, b),
243                 list(b, ct_eq<1>{}, b, ct_eq<3>{}, b)
244             ));
245             }
246         }
247     };
248 }}} // end namespace boost::hana::test
249 
250 #endif // !BOOST_HANA_TEST_LAWS_FUNCTOR_HPP
251