]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/hana/test/_include/laws/base.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / libs / hana / test / _include / laws / base.hpp
CommitLineData
b32b8144 1// Copyright Louis Dionne 2013-2017
7c673cae
FG
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_BASE_HPP
6#define BOOST_HANA_TEST_LAWS_BASE_HPP
7
8#include <boost/hana/and.hpp>
9#include <boost/hana/bool.hpp>
10#include <boost/hana/core/when.hpp>
11#include <boost/hana/detail/wrong.hpp>
12#include <boost/hana/equal.hpp>
13#include <boost/hana/eval_if.hpp>
14#include <boost/hana/for_each.hpp>
15#include <boost/hana/functional/compose.hpp>
16#include <boost/hana/functional/infix.hpp>
17#include <boost/hana/functional/partial.hpp>
18#include <boost/hana/fwd/concept/integral_constant.hpp>
19#include <boost/hana/fwd/core/to.hpp>
20#include <boost/hana/fwd/less.hpp>
21#include <boost/hana/not.hpp>
22#include <boost/hana/or.hpp>
23#include <boost/hana/tuple.hpp>
24
25#include <support/tracked.hpp>
26
27#include <type_traits>
28#include <utility>
29
30
31namespace boost { namespace hana {
32 //////////////////////////////////////////////////////////////////////////
33 // Misc
34 //////////////////////////////////////////////////////////////////////////
35 namespace test {
36 struct laws;
37
38 template <int i>
39 struct for_each_n_t {
40 static_assert(i > 0, "can't use for_each_n with i < 0");
41
42 template <typename Xs, typename F>
43 constexpr auto operator()(Xs const& xs, F const& f) const {
44 hana::for_each(xs,
45 hana::compose(
46 hana::partial(for_each_n_t<i - 1>{}, xs),
47 hana::partial(hana::partial, f)
48 )
49 );
50 }
51 };
52
53 template <>
54 struct for_each_n_t<1> {
55 template <typename Xs, typename F>
56 constexpr auto operator()(Xs const& xs, F const& f) const {
57 hana::for_each(xs, f);
58 }
59 };
60
61 template <int i>
62 constexpr for_each_n_t<i> for_each_n{};
63
64 auto foreach = hana::for_each;
65 constexpr auto foreach3 = for_each_n<3>;
66 constexpr auto foreach2 = for_each_n<2>;
67
68 struct implies_t {
69 template <typename P, typename Q>
70 constexpr decltype(auto) operator()(P&& p, Q&& q) const {
71 return hana::or_(hana::not_(static_cast<P&&>(p)),
72 static_cast<Q&&>(q));
73 }
74 };
75 constexpr auto implies = hana::infix(implies_t{});
76
77 struct iff_t {
78 template <typename P, typename Q>
79 constexpr decltype(auto) operator()(P&& p, Q&& q) const {
80 return hana::and_(implies(p, q), implies(q, p));
81 }
82 };
83 constexpr auto iff = hana::infix(iff_t{});
84
85 template <typename Cond, typename F>
86 constexpr decltype(auto) only_when_(Cond cond, F f) {
87 return hana::eval_if(cond, f, [](auto){ });
88 }
89
90 // A type with a constructor that must not be instantiated.
91 // This is to make sure we don't instantiate something else than
92 // the copy-constructor of the elements inside a container when we
93 // copy the container.
94 struct trap_construct {
95 trap_construct() = default;
96 trap_construct(trap_construct const&) = default;
92f5a8d4 97#ifndef BOOST_HANA_WORKAROUND_MSVC_MULTIPLECTOR_106654
7c673cae 98 trap_construct(trap_construct&) = default;
92f5a8d4 99#endif
7c673cae
FG
100 trap_construct(trap_construct&&) = default;
101
102 template <typename X>
103 trap_construct(X&&) {
104 static_assert(detail::wrong<X>{},
105 "this constructor must not be instantiated");
106 }
107 };
108
109 // A move-only type. Useful for testing containers.
110 struct move_only {
111 move_only() = default;
112 move_only(move_only const&) = delete;
113 move_only(move_only&&) = default;
114 };
115
116 //////////////////////////////////////////////////////////////////////
117 // InjectionResult
118 //////////////////////////////////////////////////////////////////////
119 struct InjectionResult { };
120
121 template <int i, typename ...X>
122 struct injection_result {
123 using hana_tag = InjectionResult;
124 static constexpr int injection_id = i;
125 hana::tuple<X...> args;
126 Tracked tracker;
127
128 template <typename ...Y, typename = decltype(tuple<X...>{std::declval<Y>()...})>
129 constexpr explicit injection_result(Y&& ...y)
130 : args{static_cast<Y&&>(y)...}, tracker{i}
131 { }
132 };
133
134 //! A monotonic injective function.
135 //!
136 //! This is used in the unit tests, where we often just need a function
137 //! which preserves equality and order, but which also satisfies the
138 //! following law for all `Injection`s `f` and `g`:
139 //! @code
140 //! f(x) == g(x) if and only if f === g
141 //! @endcode
142 //! where `===` means _was created by the same call to `injection`_.
143 //! This allows creating several such functions in the unit tests while
144 //! conserving precious information such as the fact that
145 //! `f(g(x)) != g(f(x))`.
146 template <int i>
147 struct _injection {
148 template <typename ...X>
149 constexpr auto operator()(X&& ...x) const {
150 return injection_result<i,
151 typename std::decay<X>::type...
152 >{static_cast<X&&>(x)...};
153 }
154 };
155 } // end namespace test
156
157 template <>
158 struct equal_impl<test::InjectionResult, test::InjectionResult> {
159 template <typename X, typename Y>
160 static constexpr auto apply(X x, Y y) {
161 return hana::and_(
162 hana::bool_c<X::injection_id == Y::injection_id>,
163 hana::equal(x.args, y.args)
164 );
165 }
166 };
167
168 template <>
169 struct less_impl<test::InjectionResult, test::InjectionResult> {
170 template <typename X, typename Y>
171 static constexpr auto apply(X x, Y y) {
172 static_assert(X::injection_id == Y::injection_id,
173 "can't order the result of two different injections");
174 return hana::less(x.args, y.args);
175 }
176 };
177
178
179 //////////////////////////////////////////////////////////////////////////
180 // Integer
181 //////////////////////////////////////////////////////////////////////////
182 namespace test {
183 enum class Policy : int {
184 // One of those is mandatory
185 Constant = 1 << 0
186 , Constexpr = 1 << 1
187 , Runtime = 1 << 2
188
189 // Those are optional
190 , Tracked = 1 << 3
191 , Comparable = 1 << 4
192 , Orderable = 1 << 5
193 };
194
195 constexpr bool operator&&(Policy a, Policy b) {
196 return static_cast<int>(a) && static_cast<int>(b);
197 }
198
199 constexpr bool operator&&(Policy a, bool b) {
200 return static_cast<int>(a) && b;
201 }
202
203 constexpr bool operator&&(bool a, Policy b) {
204 return a && static_cast<int>(b);
205 }
206
207 constexpr bool operator||(Policy a, Policy b) {
208 return static_cast<int>(a) || static_cast<int>(b);
209 }
210
211 constexpr bool operator||(Policy a, bool b) {
212 return static_cast<int>(a) || b;
213 }
214
215 constexpr bool operator||(bool a, Policy b) {
216 return a || static_cast<int>(b);
217 }
218
219 constexpr bool operator!(Policy a) {
220 return !static_cast<int>(a);
221 }
222
223 constexpr Policy operator|(Policy a, Policy b) {
224 return static_cast<Policy>(static_cast<int>(a) | static_cast<int>(b));
225 }
226
227 constexpr Policy operator&(Policy a, Policy b) {
228 return static_cast<Policy>(static_cast<int>(a) & static_cast<int>(b));
229 }
230
231 template <Policy policy, typename = void>
232 struct Integer { };
233
234 template <Policy policy>
235 struct Integer<policy, std::enable_if_t<!!(policy & Policy::Constant)>> {
236 using value_type = int;
237 };
238
239 template <int i, Policy policy, typename = void>
240 struct integer {
241 static_assert(
242 !!(policy & (Policy::Constant | Policy::Constexpr | Policy::Runtime))
243 , "You must choose at least one of Constant, Constexpr and Runtime.");
244
245 static constexpr int value = i;
246 constexpr operator int() const { return value; }
247 using hana_tag = Integer<policy>;
248 Tracked tracker{i};
249 };
250
251 template <int i, Policy policy>
252 struct integer <i, policy, std::enable_if_t<!!(policy & Policy::Constexpr)>> {
253 static constexpr int value = i;
254 constexpr operator int() const { return value; }
255 using hana_tag = Integer<policy>;
256 };
257
258 template <int i>
259 struct eq : integer<i, Policy::Comparable | Policy::Runtime> { };
260
261 template <int i>
262 struct ct_eq : integer<i, Policy::Comparable | Policy::Constant> { };
263
264 template <int i>
265 struct cx_eq : integer<i, Policy::Comparable | Policy::Constexpr> { };
266
267 template <int i>
268 struct ord : integer<i, Policy::Orderable | Policy::Runtime> { };
269
270 template <int i>
271 struct ct_ord : integer<i, Policy::Orderable | Policy::Constant> { };
272
273 template <int i>
274 struct cx_ord : integer<i, Policy::Orderable | Policy::Constexpr> { };
275
276 template <int i>
277 struct _constant
278 : integer<i, Policy::Constant | Policy::Comparable | Policy::Orderable>
279 { };
280 }
281
282 //////////////////////////////////////////////////////////////////////////
283 // Model of Constant/IntegralConstant
284 //////////////////////////////////////////////////////////////////////////
285 template <test::Policy policy>
286 struct IntegralConstant<test::Integer<policy>> {
287 static constexpr bool value = static_cast<bool>(policy & test::Policy::Constant);
288 };
289
290 template <test::Policy policy, typename C>
291 struct to_impl<test::Integer<policy>, C, when<
292 (policy & test::Policy::Constant) &&
293 hana::IntegralConstant<C>::value
294 >>
295 : embedding<is_embedded<typename C::value_type, int>::value>
296 {
297 template <typename N>
298 static constexpr auto apply(N const&) {
299 return test::integer<N::value, policy>{};
300 }
301 };
302
303 //////////////////////////////////////////////////////////////////////////
304 // Model of Comparable
305 //////////////////////////////////////////////////////////////////////////
306 template <test::Policy p1, test::Policy p2>
307 struct equal_impl<test::Integer<p1>, test::Integer<p2>, when<
308 // both Comparable or Orderable
309 (p1 & (test::Policy::Comparable | test::Policy::Orderable)) &&
310 (p2 & (test::Policy::Comparable | test::Policy::Orderable)) &&
311
312 // one Constexpr and the other Constant, or both Constexpr
313 (((p1 & test::Policy::Constant) && (p2 & test::Policy::Constexpr)) ||
314 ((p1 & test::Policy::Constexpr) && (p2 & test::Policy::Constant)) ||
315 ((p1 & test::Policy::Constexpr) && (p2 & test::Policy::Constexpr)))
316 >> {
317 template <typename X, typename Y>
318 static constexpr bool apply(X const&, Y const&)
319 { return X::value == Y::value; }
320 };
321
322 template <test::Policy p1, test::Policy p2>
323 struct equal_impl<test::Integer<p1>, test::Integer<p2>, when<
324 // both Comparable or Orderable
325 (p1 & (test::Policy::Comparable | test::Policy::Orderable)) &&
326 (p2 & (test::Policy::Comparable | test::Policy::Orderable)) &&
327
328 // either one is Runtime
329 ((p1 & test::Policy::Runtime) || (p2 & test::Policy::Runtime))
330 >> {
331 template <typename X, typename Y>
332 static bool apply(X const&, Y const&)
333 { return X::value == Y::value; }
334 };
335
336
337 //////////////////////////////////////////////////////////////////////////
338 // Model of Orderable
339 //////////////////////////////////////////////////////////////////////////
340 template <test::Policy p1, test::Policy p2>
341 struct less_impl<test::Integer<p1>, test::Integer<p2>, when<
342 // both Orderable
343 (p1 & test::Policy::Orderable) && (p2 & test::Policy::Orderable) &&
344
345 // one Constexpr and the other Constant, or both Constexpr
346 (((p1 & test::Policy::Constant) && (p2 & test::Policy::Constexpr)) ||
347 ((p1 & test::Policy::Constexpr) && (p2 & test::Policy::Constant)) ||
348 ((p1 & test::Policy::Constexpr) && (p2 & test::Policy::Constexpr)))
349 >> {
350 template <typename X, typename Y>
351 static constexpr bool apply(X const&, Y const&)
352 { return X::value < Y::value; }
353 };
354
355 template <test::Policy p1, test::Policy p2>
356 struct less_impl<test::Integer<p1>, test::Integer<p2>, when<
357 // both Orderable
358 (p1 & test::Policy::Orderable) && (p2 & test::Policy::Orderable) &&
359
360 // either one is Runtime
361 ((p1 & test::Policy::Runtime) || (p2 & test::Policy::Runtime))
362 >> {
363 template <typename X, typename Y>
364 static bool apply(X const&, Y const&)
365 { return X::value < Y::value; }
366 };
367}} // end namespace boost::hana
368
369#endif // !BOOST_HANA_TEST_LAWS_BASE_HPP