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/config.hpp>
7 #include <boost/hana/functional.hpp>
8 
9 #include <laws/base.hpp>
10 #include <support/tracked.hpp>
11 
12 #include <utility>
13 namespace hana = boost::hana;
14 
15 
16 template <int i = 0>
17 struct nonpod : Tracked {
nonpodnonpod18     nonpod() : Tracked{i} { }
19 };
20 
21 template <int i = 0>
22 struct undefined { };
23 
24 struct move_only {
25     move_only() = default;
26     move_only(move_only&&) = default;
27     move_only(move_only const&) = delete;
28 };
29 
30 
main()31 int main() {
32     hana::test::_injection<0> f{};
33     hana::test::_injection<1> g{};
34     hana::test::_injection<2> h{};
35     using hana::test::ct_eq;
36 
37     // always
38     {
39         auto z = ct_eq<0>{};
40         BOOST_HANA_CONSTANT_CHECK(hana::equal(
41             hana::always(z)(), z
42         ));
43         BOOST_HANA_CONSTANT_CHECK(hana::equal(
44             hana::always(z)(undefined<1>{}), z
45         ));
46         BOOST_HANA_CONSTANT_CHECK(hana::equal(
47             hana::always(z)(undefined<1>{}, undefined<2>{}), z
48         ));
49         BOOST_HANA_CONSTANT_CHECK(hana::equal(
50             hana::always(z)(undefined<1>{}, undefined<2>{}, undefined<3>{}), z
51         ));
52         BOOST_HANA_CONSTANT_CHECK(hana::equal(
53             hana::always(z)(undefined<1>{}, undefined<2>{}, undefined<3>{}, undefined<4>{}), z
54         ));
55 
56         hana::always(z)(nonpod<>{});
57         auto m = hana::always(move_only{})(undefined<1>{}); (void)m;
58     }
59 
60     // apply (tested separately)
61     {
62 
63     }
64 
65     // arg
66     {
67         // moveonly friendliness:
68         move_only z = hana::arg<1>(move_only{}); (void)z;
69 
70         BOOST_HANA_CONSTANT_CHECK(hana::equal(
71             hana::arg<1>(ct_eq<1>{}),
72             ct_eq<1>{}
73         ));
74         BOOST_HANA_CONSTANT_CHECK(hana::equal(
75             hana::arg<1>(ct_eq<1>{}, undefined<2>{}),
76             ct_eq<1>{}
77         ));
78         BOOST_HANA_CONSTANT_CHECK(hana::equal(
79             hana::arg<1>(ct_eq<1>{}, undefined<2>{}, undefined<3>{}),
80             ct_eq<1>{}
81         ));
82         hana::arg<1>(nonpod<1>{});
83         hana::arg<1>(nonpod<1>{}, nonpod<2>{});
84 
85 
86         BOOST_HANA_CONSTANT_CHECK(hana::equal(
87             hana::arg<2>(undefined<1>{}, ct_eq<2>{}),
88             ct_eq<2>{}
89         ));
90         BOOST_HANA_CONSTANT_CHECK(hana::equal(
91             hana::arg<2>(undefined<1>{}, ct_eq<2>{}, undefined<3>{}),
92             ct_eq<2>{}
93         ));
94         hana::arg<2>(nonpod<1>{}, nonpod<2>{});
95         hana::arg<2>(nonpod<1>{}, nonpod<2>{}, nonpod<3>{});
96 
97 
98         BOOST_HANA_CONSTANT_CHECK(hana::equal(
99             hana::arg<3>(undefined<1>{}, undefined<2>{}, ct_eq<3>{}),
100             ct_eq<3>{}
101         ));
102         BOOST_HANA_CONSTANT_CHECK(hana::equal(
103             hana::arg<3>(undefined<1>{}, undefined<2>{}, ct_eq<3>{}, undefined<4>{}),
104             ct_eq<3>{}
105         ));
106         hana::arg<3>(nonpod<1>{}, nonpod<2>{}, nonpod<3>{});
107         hana::arg<3>(nonpod<1>{}, nonpod<2>{}, nonpod<3>{}, nonpod<4>{});
108 
109 
110         BOOST_HANA_CONSTANT_CHECK(hana::equal(
111             hana::arg<4>(undefined<1>{}, undefined<2>{}, undefined<3>{}, ct_eq<4>{}),
112             ct_eq<4>{}
113         ));
114         BOOST_HANA_CONSTANT_CHECK(hana::equal(
115             hana::arg<4>(undefined<1>{}, undefined<2>{}, undefined<3>{}, ct_eq<4>{}, undefined<5>{}),
116             ct_eq<4>{}
117         ));
118         hana::arg<4>(nonpod<1>{}, nonpod<2>{}, nonpod<3>{}, nonpod<4>{});
119         hana::arg<4>(nonpod<1>{}, nonpod<2>{}, nonpod<3>{}, nonpod<4>{}, nonpod<5>{});
120 
121 
122         BOOST_HANA_CONSTANT_CHECK(hana::equal(
123             hana::arg<5>(undefined<1>{}, undefined<2>{}, undefined<3>{}, undefined<4>{}, ct_eq<5>{}),
124             ct_eq<5>{}
125         ));
126         BOOST_HANA_CONSTANT_CHECK(hana::equal(
127             hana::arg<5>(undefined<1>{}, undefined<2>{}, undefined<3>{}, undefined<4>{}, ct_eq<5>{}, undefined<6>{}),
128             ct_eq<5>{}
129         ));
130         hana::arg<5>(nonpod<1>{}, nonpod<2>{}, nonpod<3>{}, nonpod<4>{}, nonpod<5>{});
131         hana::arg<5>(nonpod<1>{}, nonpod<2>{}, nonpod<3>{}, nonpod<4>{}, nonpod<5>{}, nonpod<6>{});
132 
133 
134         BOOST_HANA_CONSTANT_CHECK(hana::equal(
135             hana::arg<6>(undefined<1>{}, undefined<2>{}, undefined<3>{}, undefined<4>{}, undefined<5>{}, ct_eq<6>{}),
136             ct_eq<6>{}
137         ));
138         BOOST_HANA_CONSTANT_CHECK(hana::equal(
139             hana::arg<6>(undefined<1>{}, undefined<2>{}, undefined<3>{}, undefined<4>{}, undefined<5>{}, ct_eq<6>{}, undefined<7>{}),
140             ct_eq<6>{}
141         ));
142         hana::arg<6>(nonpod<1>{}, nonpod<2>{}, nonpod<3>{}, nonpod<4>{}, nonpod<5>{}, nonpod<6>{});
143         hana::arg<6>(nonpod<1>{}, nonpod<2>{}, nonpod<3>{}, nonpod<4>{}, nonpod<5>{}, nonpod<6>{}, nonpod<7>{});
144     }
145 
146     // compose
147     {
148         BOOST_HANA_CONSTANT_CHECK(hana::equal(
149             hana::compose(f, g)(ct_eq<0>{}),
150             f(g(ct_eq<0>{}))
151         ));
152         BOOST_HANA_CONSTANT_CHECK(hana::equal(
153             hana::compose(f, g)(ct_eq<0>{}, ct_eq<1>{}),
154             f(g(ct_eq<0>{}), ct_eq<1>{})
155         ));
156         BOOST_HANA_CONSTANT_CHECK(hana::equal(
157             hana::compose(f, g)(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}),
158             f(g(ct_eq<0>{}), ct_eq<1>{}, ct_eq<2>{})
159         ));
160 
161         BOOST_HANA_CONSTANT_CHECK(hana::equal(
162             hana::compose(f, g, h)(ct_eq<0>{}),
163             f(g(h(ct_eq<0>{})))
164         ));
165         BOOST_HANA_CONSTANT_CHECK(hana::equal(
166             hana::compose(f, g, h)(ct_eq<0>{}, ct_eq<1>{}),
167             f(g(h(ct_eq<0>{})), ct_eq<1>{})
168         ));
169         BOOST_HANA_CONSTANT_CHECK(hana::equal(
170             hana::compose(f, g, h)(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}),
171             f(g(h(ct_eq<0>{})), ct_eq<1>{}, ct_eq<2>{})
172         ));
173 
174         auto h = [capture = move_only{}](int) { (void)capture; return 1; };
175         auto i = [](int) { return 1; };
176         hana::compose(std::move(h), i)(1);
177 
178         {
179             // Compose move-only functions.
180             auto f = [capture = move_only{}](int) { (void)capture; return 1; };
181             auto g = [capture = move_only{}](int) { (void)capture; return 1; };
182             auto c = hana::compose(std::move(f), std::move(g)); (void)c;
183         }
184     }
185 
186     // curry
187     {
188         BOOST_HANA_CONSTANT_CHECK(hana::equal(
189             hana::curry<0>(f)(),
190             f()
191         ));
192 
193         BOOST_HANA_CONSTANT_CHECK(hana::equal(
194             hana::curry<1>(f)(ct_eq<1>{}),
195             f(ct_eq<1>{})
196         ));
197 
198         BOOST_HANA_CONSTANT_CHECK(hana::equal(
199             hana::curry<2>(f)(ct_eq<1>{})(ct_eq<2>{}),
200             f(ct_eq<1>{}, ct_eq<2>{})
201         ));
202         BOOST_HANA_CONSTANT_CHECK(hana::equal(
203             hana::curry<2>(f)(ct_eq<1>{}, ct_eq<2>{}),
204             f(ct_eq<1>{}, ct_eq<2>{})
205         ));
206 
207         BOOST_HANA_CONSTANT_CHECK(hana::equal(
208             hana::curry<3>(f)(ct_eq<1>{})(ct_eq<2>{})(ct_eq<3>{}),
209             f(ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{})
210         ));
211         BOOST_HANA_CONSTANT_CHECK(hana::equal(
212             hana::curry<3>(f)(ct_eq<1>{})(ct_eq<2>{}, ct_eq<3>{}),
213             f(ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{})
214         ));
215         BOOST_HANA_CONSTANT_CHECK(hana::equal(
216             hana::curry<3>(f)(ct_eq<1>{}, ct_eq<2>{})(ct_eq<3>{}),
217             f(ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{})
218         ));
219         BOOST_HANA_CONSTANT_CHECK(hana::equal(
220             hana::curry<3>(f)(ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{}),
221             f(ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{})
222         ));
223 
224 
225         // Make sure curry is idempotent; this is important because it allows
226         // currying a function in generic contexts where it is unknown whether
227         // the function is already curried.
228         BOOST_HANA_CONSTANT_CHECK(hana::equal(
229             hana::curry<0>(hana::curry<0>(f))(),
230             f()
231         ));
232 
233         BOOST_HANA_CONSTANT_CHECK(hana::equal(
234             hana::curry<1>(hana::curry<1>(f))(ct_eq<1>{}),
235             f(ct_eq<1>{})
236         ));
237 
238         BOOST_HANA_CONSTANT_CHECK(hana::equal(
239             hana::curry<2>(hana::curry<2>(f))(ct_eq<1>{})(ct_eq<2>{}),
240             f(ct_eq<1>{}, ct_eq<2>{})
241         ));
242         BOOST_HANA_CONSTANT_CHECK(hana::equal(
243             hana::curry<2>(hana::curry<2>(f))(ct_eq<1>{}, ct_eq<2>{}),
244             f(ct_eq<1>{}, ct_eq<2>{})
245         ));
246 
247         BOOST_HANA_CONSTANT_CHECK(hana::equal(
248             hana::curry<3>(hana::curry<3>(f))(ct_eq<1>{})(ct_eq<2>{})(ct_eq<3>{}),
249             f(ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{})
250         ));
251         BOOST_HANA_CONSTANT_CHECK(hana::equal(
252             hana::curry<3>(hana::curry<3>(f))(ct_eq<1>{})(ct_eq<2>{}, ct_eq<3>{}),
253             f(ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{})
254         ));
255         BOOST_HANA_CONSTANT_CHECK(hana::equal(
256             hana::curry<3>(hana::curry<3>(f))(ct_eq<1>{}, ct_eq<2>{})(ct_eq<3>{}),
257             f(ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{})
258         ));
259         BOOST_HANA_CONSTANT_CHECK(hana::equal(
260             hana::curry<3>(hana::curry<3>(f))(ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{}),
261             f(ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{})
262         ));
263     }
264 
265     // demux (tested separately)
266     {
267 
268     }
269 
270     // fix (tested separately)
271     {
272 
273     }
274 
275     // flip
276     {
277         BOOST_HANA_CONSTANT_CHECK(hana::equal(
278             hana::flip(f)(ct_eq<1>{}, ct_eq<2>{}),
279             f(ct_eq<2>{}, ct_eq<1>{})
280         ));
281         BOOST_HANA_CONSTANT_CHECK(hana::equal(
282             hana::flip(f)(ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{}),
283             f(ct_eq<2>{}, ct_eq<1>{}, ct_eq<3>{})
284         ));
285         BOOST_HANA_CONSTANT_CHECK(hana::equal(
286             hana::flip(f)(ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{}, ct_eq<4>{}),
287             f(ct_eq<2>{}, ct_eq<1>{}, ct_eq<3>{}, ct_eq<4>{})
288         ));
289         BOOST_HANA_CONSTANT_CHECK(hana::equal(
290             hana::flip(f)(ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{}, ct_eq<4>{}, ct_eq<5>{}),
291             f(ct_eq<2>{}, ct_eq<1>{}, ct_eq<3>{}, ct_eq<4>{}, ct_eq<5>{})
292         ));
293     }
294 
295     // id
296     {
297         BOOST_HANA_CONSTANT_CHECK(hana::equal(
298             hana::id(ct_eq<0>{}),
299             ct_eq<0>{}
300         ));
301         BOOST_HANA_CONSTANT_CHECK(hana::equal(
302             hana::id(ct_eq<1>{}),
303             ct_eq<1>{}
304         ));
305 
306         (void)hana::id(move_only{});
307 
308         // make sure we don't return a dangling reference
309         auto f = []() -> decltype(auto) { return hana::id(Tracked{1}); };
310         auto z = f(); (void)z;
311     }
312 
313     // lockstep (tested separately)
314     {
315 
316     }
317 
318     // infix
319     {
320         auto g = hana::infix(f);
321 
322         // disregard associativity
323         BOOST_HANA_CONSTANT_CHECK(hana::equal(
324             ct_eq<0>{} ^g^ ct_eq<1>{},
325             f(ct_eq<0>{}, ct_eq<1>{})
326         ));
327         BOOST_HANA_CONSTANT_CHECK(hana::equal(
328             (ct_eq<0>{} ^g)^ ct_eq<1>{},
329             f(ct_eq<0>{}, ct_eq<1>{})
330         ));
331         BOOST_HANA_CONSTANT_CHECK(hana::equal(
332             ct_eq<0>{} ^(g^ ct_eq<1>{}),
333             f(ct_eq<0>{}, ct_eq<1>{})
334         ));
335 
336         // left partial application
337         BOOST_HANA_CONSTANT_CHECK(hana::equal(
338             (ct_eq<0>{}^g)(ct_eq<1>{}),
339             f(ct_eq<0>{}, ct_eq<1>{})
340         ));
341         BOOST_HANA_CONSTANT_CHECK(hana::equal(
342             (ct_eq<0>{}^g)(ct_eq<1>{}, ct_eq<2>{}),
343             f(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{})
344         ));
345         BOOST_HANA_CONSTANT_CHECK(hana::equal(
346             (ct_eq<0>{}^g)(ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{}),
347             f(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{})
348         ));
349 
350         // right partial application
351         BOOST_HANA_CONSTANT_CHECK(hana::equal(
352             (g^ct_eq<1>{})(ct_eq<0>{}),
353             f(ct_eq<0>{}, ct_eq<1>{})
354         ));
355         BOOST_HANA_CONSTANT_CHECK(hana::equal(
356             (g^ct_eq<2>{})(ct_eq<0>{}, ct_eq<1>{}),
357             f(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{})
358         ));
359         BOOST_HANA_CONSTANT_CHECK(hana::equal(
360             (g^ct_eq<3>{})(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}),
361             f(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{})
362         ));
363 
364         // equivalence with the base function
365         BOOST_HANA_CONSTANT_CHECK(hana::equal(
366             g(ct_eq<0>{}, ct_eq<1>{}),
367             f(ct_eq<0>{}, ct_eq<1>{})
368         ));
369         BOOST_HANA_CONSTANT_CHECK(hana::equal(
370             g(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}),
371             f(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{})
372         ));
373         BOOST_HANA_CONSTANT_CHECK(hana::equal(
374             g(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{}),
375             f(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{})
376         ));
377     }
378 
379     // on
380     {
381         BOOST_HANA_CONSTANT_CHECK(hana::equal(
382             hana::on(f, g)(),
383             f()
384         ));
385         BOOST_HANA_CONSTANT_CHECK(hana::equal(
386             hana::on(f, g)(ct_eq<0>{}),
387             f(g(ct_eq<0>{}))
388         ));
389         BOOST_HANA_CONSTANT_CHECK(hana::equal(
390             hana::on(f, g)(ct_eq<0>{}, ct_eq<1>{}),
391             f(g(ct_eq<0>{}), g(ct_eq<1>{}))
392         ));
393         BOOST_HANA_CONSTANT_CHECK(hana::equal(
394             hana::on(f, g)(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}),
395             f(g(ct_eq<0>{}), g(ct_eq<1>{}), g(ct_eq<2>{}))
396         ));
397         BOOST_HANA_CONSTANT_CHECK(hana::equal(
398             hana::on(f, g)(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{}),
399             f(g(ct_eq<0>{}), g(ct_eq<1>{}), g(ct_eq<2>{}), g(ct_eq<3>{}))
400         ));
401 
402         // check the infix version
403         BOOST_HANA_CONSTANT_CHECK(hana::equal(
404             (f ^hana::on^ g)(),
405             f()
406         ));
407         BOOST_HANA_CONSTANT_CHECK(hana::equal(
408             (f ^hana::on^ g)(ct_eq<0>{}),
409             f(g(ct_eq<0>{}))
410         ));
411         BOOST_HANA_CONSTANT_CHECK(hana::equal(
412             (f ^hana::on^ g)(ct_eq<0>{}, ct_eq<1>{}),
413             f(g(ct_eq<0>{}), g(ct_eq<1>{}))
414         ));
415         BOOST_HANA_CONSTANT_CHECK(hana::equal(
416             (f ^hana::on^ g)(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}),
417             f(g(ct_eq<0>{}), g(ct_eq<1>{}), g(ct_eq<2>{}))
418         ));
419         BOOST_HANA_CONSTANT_CHECK(hana::equal(
420             (f ^hana::on^ g)(ct_eq<0>{}, ct_eq<1>{}, ct_eq<2>{}, ct_eq<3>{}),
421             f(g(ct_eq<0>{}), g(ct_eq<1>{}), g(ct_eq<2>{}), g(ct_eq<3>{}))
422         ));
423     }
424 
425     // overload
426     {
427         // 1 function
428         {
429             auto f = hana::overload([](int) { return ct_eq<1>{}; });
430             BOOST_HANA_CONSTANT_CHECK(hana::equal(f(int{}), ct_eq<1>{}));
431         }
432 
433         // 2 functions
434         {
435             auto f = hana::overload(
436                 [](int) { return ct_eq<1>{}; },
437                 [](float) { return ct_eq<2>{}; }
438             );
439             BOOST_HANA_CONSTANT_CHECK(hana::equal(f(int{}), ct_eq<1>{}));
440             BOOST_HANA_CONSTANT_CHECK(hana::equal(f(float{}), ct_eq<2>{}));
441         }
442 
443         // 3 functions
444         {
445             auto f = hana::overload(
446                 [](int) { return ct_eq<1>{}; },
447                 [](float) { return ct_eq<2>{}; },
448                 static_cast<ct_eq<3>(*)(char)>([](char) { return ct_eq<3>{}; })
449             );
450             BOOST_HANA_CONSTANT_CHECK(hana::equal(f(int{}), ct_eq<1>{}));
451             BOOST_HANA_CONSTANT_CHECK(hana::equal(f(float{}), ct_eq<2>{}));
452             BOOST_HANA_CONSTANT_CHECK(hana::equal(f(char{}), ct_eq<3>{}));
453         }
454 
455         // 4 functions
456         {
457             auto f = hana::overload(
458                 [](int) { return ct_eq<1>{}; },
459                 [](float) { return ct_eq<2>{}; },
460                 static_cast<ct_eq<3>(*)(char)>([](char) { return ct_eq<3>{}; }),
461                 [](auto) { return ct_eq<4>{}; }
462             );
463 
464             struct otherwise { };
465             BOOST_HANA_CONSTANT_CHECK(hana::equal(f(int{}), ct_eq<1>{}));
466             BOOST_HANA_CONSTANT_CHECK(hana::equal(f(float{}), ct_eq<2>{}));
467             BOOST_HANA_CONSTANT_CHECK(hana::equal(f(char{}), ct_eq<3>{}));
468             BOOST_HANA_CONSTANT_CHECK(hana::equal(f(otherwise{}), ct_eq<4>{}));
469         }
470 
471         // check move-only friendliness for bare functions
472         {
473             void (*g)(move_only) = [](move_only) { };
474             hana::overload(g)(move_only{});
475         }
476 
477         // check non-strict matches which require a conversion
478         {
479             struct convertible_to_int { operator int() const { return 1; } };
480             auto f = [](int) { return ct_eq<0>{}; };
481 
482             BOOST_HANA_CONSTANT_CHECK(hana::equal(
483                 hana::overload(f)(convertible_to_int{}),
484                 ct_eq<0>{}
485             ));
486 
487             BOOST_HANA_CONSTANT_CHECK(hana::equal(
488                 hana::overload(static_cast<ct_eq<0>(*)(int)>(f))(convertible_to_int{}),
489                 ct_eq<0>{}
490             ));
491         }
492     }
493 
494     // partial (tested separately)
495     {
496 
497     }
498 
499     // placeholder (tested separately)
500     {
501 
502     }
503 }
504