]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/hana/test/_include/laws/base.hpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / hana / test / _include / laws / base.hpp
1 // Copyright Louis Dionne 2013-2016
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
31 namespace 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;
97 trap_construct(trap_construct&) = default;
98 trap_construct(trap_construct&&) = default;
99
100 template <typename X>
101 trap_construct(X&&) {
102 static_assert(detail::wrong<X>{},
103 "this constructor must not be instantiated");
104 }
105 };
106
107 // A move-only type. Useful for testing containers.
108 struct move_only {
109 move_only() = default;
110 move_only(move_only const&) = delete;
111 move_only(move_only&&) = default;
112 };
113
114 //////////////////////////////////////////////////////////////////////
115 // InjectionResult
116 //////////////////////////////////////////////////////////////////////
117 struct InjectionResult { };
118
119 template <int i, typename ...X>
120 struct injection_result {
121 using hana_tag = InjectionResult;
122 static constexpr int injection_id = i;
123 hana::tuple<X...> args;
124 Tracked tracker;
125
126 template <typename ...Y, typename = decltype(tuple<X...>{std::declval<Y>()...})>
127 constexpr explicit injection_result(Y&& ...y)
128 : args{static_cast<Y&&>(y)...}, tracker{i}
129 { }
130 };
131
132 //! A monotonic injective function.
133 //!
134 //! This is used in the unit tests, where we often just need a function
135 //! which preserves equality and order, but which also satisfies the
136 //! following law for all `Injection`s `f` and `g`:
137 //! @code
138 //! f(x) == g(x) if and only if f === g
139 //! @endcode
140 //! where `===` means _was created by the same call to `injection`_.
141 //! This allows creating several such functions in the unit tests while
142 //! conserving precious information such as the fact that
143 //! `f(g(x)) != g(f(x))`.
144 template <int i>
145 struct _injection {
146 template <typename ...X>
147 constexpr auto operator()(X&& ...x) const {
148 return injection_result<i,
149 typename std::decay<X>::type...
150 >{static_cast<X&&>(x)...};
151 }
152 };
153 } // end namespace test
154
155 template <>
156 struct equal_impl<test::InjectionResult, test::InjectionResult> {
157 template <typename X, typename Y>
158 static constexpr auto apply(X x, Y y) {
159 return hana::and_(
160 hana::bool_c<X::injection_id == Y::injection_id>,
161 hana::equal(x.args, y.args)
162 );
163 }
164 };
165
166 template <>
167 struct less_impl<test::InjectionResult, test::InjectionResult> {
168 template <typename X, typename Y>
169 static constexpr auto apply(X x, Y y) {
170 static_assert(X::injection_id == Y::injection_id,
171 "can't order the result of two different injections");
172 return hana::less(x.args, y.args);
173 }
174 };
175
176
177 //////////////////////////////////////////////////////////////////////////
178 // Integer
179 //////////////////////////////////////////////////////////////////////////
180 namespace test {
181 enum class Policy : int {
182 // One of those is mandatory
183 Constant = 1 << 0
184 , Constexpr = 1 << 1
185 , Runtime = 1 << 2
186
187 // Those are optional
188 , Tracked = 1 << 3
189 , Comparable = 1 << 4
190 , Orderable = 1 << 5
191 };
192
193 constexpr bool operator&&(Policy a, Policy b) {
194 return static_cast<int>(a) && static_cast<int>(b);
195 }
196
197 constexpr bool operator&&(Policy a, bool b) {
198 return static_cast<int>(a) && b;
199 }
200
201 constexpr bool operator&&(bool a, Policy b) {
202 return a && static_cast<int>(b);
203 }
204
205 constexpr bool operator||(Policy a, Policy b) {
206 return static_cast<int>(a) || static_cast<int>(b);
207 }
208
209 constexpr bool operator||(Policy a, bool b) {
210 return static_cast<int>(a) || b;
211 }
212
213 constexpr bool operator||(bool a, Policy b) {
214 return a || static_cast<int>(b);
215 }
216
217 constexpr bool operator!(Policy a) {
218 return !static_cast<int>(a);
219 }
220
221 constexpr Policy operator|(Policy a, Policy b) {
222 return static_cast<Policy>(static_cast<int>(a) | static_cast<int>(b));
223 }
224
225 constexpr Policy operator&(Policy a, Policy b) {
226 return static_cast<Policy>(static_cast<int>(a) & static_cast<int>(b));
227 }
228
229 template <Policy policy, typename = void>
230 struct Integer { };
231
232 template <Policy policy>
233 struct Integer<policy, std::enable_if_t<!!(policy & Policy::Constant)>> {
234 using value_type = int;
235 };
236
237 template <int i, Policy policy, typename = void>
238 struct integer {
239 static_assert(
240 !!(policy & (Policy::Constant | Policy::Constexpr | Policy::Runtime))
241 , "You must choose at least one of Constant, Constexpr and Runtime.");
242
243 static constexpr int value = i;
244 constexpr operator int() const { return value; }
245 using hana_tag = Integer<policy>;
246 Tracked tracker{i};
247 };
248
249 template <int i, Policy policy>
250 struct integer <i, policy, std::enable_if_t<!!(policy & Policy::Constexpr)>> {
251 static constexpr int value = i;
252 constexpr operator int() const { return value; }
253 using hana_tag = Integer<policy>;
254 };
255
256 template <int i>
257 struct eq : integer<i, Policy::Comparable | Policy::Runtime> { };
258
259 template <int i>
260 struct ct_eq : integer<i, Policy::Comparable | Policy::Constant> { };
261
262 template <int i>
263 struct cx_eq : integer<i, Policy::Comparable | Policy::Constexpr> { };
264
265 template <int i>
266 struct ord : integer<i, Policy::Orderable | Policy::Runtime> { };
267
268 template <int i>
269 struct ct_ord : integer<i, Policy::Orderable | Policy::Constant> { };
270
271 template <int i>
272 struct cx_ord : integer<i, Policy::Orderable | Policy::Constexpr> { };
273
274 template <int i>
275 struct _constant
276 : integer<i, Policy::Constant | Policy::Comparable | Policy::Orderable>
277 { };
278 }
279
280 //////////////////////////////////////////////////////////////////////////
281 // Model of Constant/IntegralConstant
282 //////////////////////////////////////////////////////////////////////////
283 template <test::Policy policy>
284 struct IntegralConstant<test::Integer<policy>> {
285 static constexpr bool value = static_cast<bool>(policy & test::Policy::Constant);
286 };
287
288 template <test::Policy policy, typename C>
289 struct to_impl<test::Integer<policy>, C, when<
290 (policy & test::Policy::Constant) &&
291 hana::IntegralConstant<C>::value
292 >>
293 : embedding<is_embedded<typename C::value_type, int>::value>
294 {
295 template <typename N>
296 static constexpr auto apply(N const&) {
297 return test::integer<N::value, policy>{};
298 }
299 };
300
301 //////////////////////////////////////////////////////////////////////////
302 // Model of Comparable
303 //////////////////////////////////////////////////////////////////////////
304 template <test::Policy p1, test::Policy p2>
305 struct equal_impl<test::Integer<p1>, test::Integer<p2>, when<
306 // both Comparable or Orderable
307 (p1 & (test::Policy::Comparable | test::Policy::Orderable)) &&
308 (p2 & (test::Policy::Comparable | test::Policy::Orderable)) &&
309
310 // one Constexpr and the other Constant, or both Constexpr
311 (((p1 & test::Policy::Constant) && (p2 & test::Policy::Constexpr)) ||
312 ((p1 & test::Policy::Constexpr) && (p2 & test::Policy::Constant)) ||
313 ((p1 & test::Policy::Constexpr) && (p2 & test::Policy::Constexpr)))
314 >> {
315 template <typename X, typename Y>
316 static constexpr bool apply(X const&, Y const&)
317 { return X::value == Y::value; }
318 };
319
320 template <test::Policy p1, test::Policy p2>
321 struct equal_impl<test::Integer<p1>, test::Integer<p2>, when<
322 // both Comparable or Orderable
323 (p1 & (test::Policy::Comparable | test::Policy::Orderable)) &&
324 (p2 & (test::Policy::Comparable | test::Policy::Orderable)) &&
325
326 // either one is Runtime
327 ((p1 & test::Policy::Runtime) || (p2 & test::Policy::Runtime))
328 >> {
329 template <typename X, typename Y>
330 static bool apply(X const&, Y const&)
331 { return X::value == Y::value; }
332 };
333
334
335 //////////////////////////////////////////////////////////////////////////
336 // Model of Orderable
337 //////////////////////////////////////////////////////////////////////////
338 template <test::Policy p1, test::Policy p2>
339 struct less_impl<test::Integer<p1>, test::Integer<p2>, when<
340 // both Orderable
341 (p1 & test::Policy::Orderable) && (p2 & test::Policy::Orderable) &&
342
343 // one Constexpr and the other Constant, or both Constexpr
344 (((p1 & test::Policy::Constant) && (p2 & test::Policy::Constexpr)) ||
345 ((p1 & test::Policy::Constexpr) && (p2 & test::Policy::Constant)) ||
346 ((p1 & test::Policy::Constexpr) && (p2 & test::Policy::Constexpr)))
347 >> {
348 template <typename X, typename Y>
349 static constexpr bool apply(X const&, Y const&)
350 { return X::value < Y::value; }
351 };
352
353 template <test::Policy p1, test::Policy p2>
354 struct less_impl<test::Integer<p1>, test::Integer<p2>, when<
355 // both Orderable
356 (p1 & test::Policy::Orderable) && (p2 & test::Policy::Orderable) &&
357
358 // either one is Runtime
359 ((p1 & test::Policy::Runtime) || (p2 & test::Policy::Runtime))
360 >> {
361 template <typename X, typename Y>
362 static bool apply(X const&, Y const&)
363 { return X::value < Y::value; }
364 };
365 }} // end namespace boost::hana
366
367 #endif // !BOOST_HANA_TEST_LAWS_BASE_HPP