]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/yap/detail/transform.hpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / boost / yap / detail / transform.hpp
1 // Copyright (C) 2016-2018 T. Zachary Laine
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See
4 // accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 #ifndef BOOST_YAP_DETAIL_TRANSFORM_HPP_INCLUDED
7 #define BOOST_YAP_DETAIL_TRANSFORM_HPP_INCLUDED
8
9 #include <boost/yap/algorithm_fwd.hpp>
10
11 #include <boost/hana/transform.hpp>
12
13 #include <cassert>
14
15
16 namespace boost { namespace yap { namespace detail {
17
18 template<int I, typename T, typename... Ts>
19 struct nth_element_impl
20 {
21 using type = typename nth_element_impl<I - 1, Ts...>::type;
22 };
23
24 template<typename T, typename... Ts>
25 struct nth_element_impl<0, T, Ts...>
26 {
27 using type = T;
28 };
29
30 template<int I, typename... Ts>
31 using nth_element = typename nth_element_impl<I, Ts...>::type;
32
33 template<typename T, bool RemoveRefs = std::is_rvalue_reference<T>::value>
34 struct rvalue_ref_to_value;
35
36 template<typename T>
37 struct rvalue_ref_to_value<T, true>
38 {
39 using type = typename std::remove_reference<T>::type;
40 };
41
42 template<typename T>
43 struct rvalue_ref_to_value<T, false>
44 {
45 using type = T;
46 };
47
48 template<typename T>
49 using rvalue_ref_to_value_t = typename rvalue_ref_to_value<T>::type;
50
51 template<bool IsRvalueRef>
52 struct rvalue_mover
53 {
54 template<typename T>
55 constexpr decltype(auto) operator()(T && t) const
56 {
57 return static_cast<T &&>(t);
58 }
59 };
60
61 template<>
62 struct rvalue_mover<true>
63 {
64 template<typename T>
65 constexpr std::remove_reference_t<T> operator()(T && t) const
66 {
67 return std::move(t);
68 }
69 };
70
71 template<typename... PlaceholderArgs>
72 struct placeholder_transform_t
73 {
74 using tuple_t = hana::tuple<rvalue_ref_to_value_t<PlaceholderArgs>...>;
75
76 constexpr placeholder_transform_t(PlaceholderArgs &&... args) :
77 placeholder_args_(static_cast<PlaceholderArgs &&>(args)...)
78 {}
79
80 template<long long I>
81 constexpr decltype(auto)
82 operator()(expr_tag<expr_kind::terminal>, boost::yap::placeholder<I>) const
83 {
84 static_assert(
85 I <= decltype(hana::size(std::declval<tuple_t>()))::value,
86 "Out of range placeholder index,");
87 using nth_type = nth_element<I - 1, PlaceholderArgs...>;
88 return as_expr<minimal_expr>(
89 rvalue_mover<!std::is_lvalue_reference<nth_type>::value>{}(
90 placeholder_args_[hana::llong<I - 1>{}]));
91 }
92
93 tuple_t placeholder_args_;
94 };
95
96 template<typename... PlaceholderArgs>
97 struct evaluation_transform_t
98 {
99 using tuple_t = hana::tuple<rvalue_ref_to_value_t<PlaceholderArgs>...>;
100
101 constexpr evaluation_transform_t(PlaceholderArgs &&... args) :
102 placeholder_args_(static_cast<PlaceholderArgs &&>(args)...)
103 {}
104
105 template<long long I>
106 constexpr decltype(auto)
107 operator()(expr_tag<expr_kind::terminal>, boost::yap::placeholder<I>) const
108 {
109 static_assert(
110 I <= decltype(hana::size(std::declval<tuple_t>()))::value,
111 "Out of range placeholder index,");
112 using nth_type = nth_element<I - 1, PlaceholderArgs...>;
113 return rvalue_mover<!std::is_lvalue_reference<nth_type>::value>{}(
114 placeholder_args_[hana::llong<I - 1>{}]);
115 }
116
117 template<typename T>
118 constexpr decltype(auto) operator()(expr_tag<expr_kind::terminal>, T && t) const
119 {
120 return static_cast<T &&>(t);
121 }
122
123 #define BOOST_YAP_UNARY_OPERATOR_CASE(op, op_name) \
124 template<typename T> \
125 constexpr decltype(auto) operator()(expr_tag<expr_kind::op_name>, T && t) const \
126 { \
127 return op transform( \
128 as_expr<minimal_expr>(static_cast<T &&>(t)), *this); \
129 }
130
131 BOOST_YAP_UNARY_OPERATOR_CASE(+, unary_plus)
132 BOOST_YAP_UNARY_OPERATOR_CASE(-, negate)
133 BOOST_YAP_UNARY_OPERATOR_CASE(*, dereference)
134 BOOST_YAP_UNARY_OPERATOR_CASE(~, complement)
135 BOOST_YAP_UNARY_OPERATOR_CASE(&, address_of)
136 BOOST_YAP_UNARY_OPERATOR_CASE(!, logical_not)
137 BOOST_YAP_UNARY_OPERATOR_CASE(++, pre_inc)
138 BOOST_YAP_UNARY_OPERATOR_CASE(--, pre_dec)
139
140 template<typename T>
141 constexpr decltype(auto) operator()(expr_tag<expr_kind::post_inc>, T && t) const
142 {
143 return transform(
144 as_expr<minimal_expr>(static_cast<T &&>(t)), *this)++;
145 }
146 template<typename T>
147 constexpr decltype(auto) operator()(expr_tag<expr_kind::post_dec>, T && t) const
148 {
149 return transform(
150 as_expr<minimal_expr>(static_cast<T &&>(t)), *this)--;
151 }
152
153 #undef BOOST_YAP_UNARY_OPERATOR_CASE
154
155 #define BOOST_YAP_BINARY_OPERATOR_CASE(op, op_name) \
156 template<typename T, typename U> \
157 constexpr decltype(auto) operator()(expr_tag<expr_kind::op_name>, T && t, U && u) const \
158 { \
159 return transform(as_expr<minimal_expr>(static_cast<T &&>(t)), *this) \
160 op transform(as_expr<minimal_expr>(static_cast<U &&>(u)), *this); \
161 }
162
163 BOOST_YAP_BINARY_OPERATOR_CASE(<<, shift_left)
164 BOOST_YAP_BINARY_OPERATOR_CASE(>>, shift_right)
165 BOOST_YAP_BINARY_OPERATOR_CASE(*, multiplies)
166 BOOST_YAP_BINARY_OPERATOR_CASE(/, divides)
167 BOOST_YAP_BINARY_OPERATOR_CASE(%, modulus)
168 BOOST_YAP_BINARY_OPERATOR_CASE(+, plus)
169 BOOST_YAP_BINARY_OPERATOR_CASE(-, minus)
170 BOOST_YAP_BINARY_OPERATOR_CASE(<, less)
171 BOOST_YAP_BINARY_OPERATOR_CASE(>, greater)
172 BOOST_YAP_BINARY_OPERATOR_CASE(<=, less_equal)
173 BOOST_YAP_BINARY_OPERATOR_CASE(>=, greater_equal)
174 BOOST_YAP_BINARY_OPERATOR_CASE(==, equal_to)
175 BOOST_YAP_BINARY_OPERATOR_CASE(!=, not_equal_to)
176 BOOST_YAP_BINARY_OPERATOR_CASE(||, logical_or)
177 BOOST_YAP_BINARY_OPERATOR_CASE(&&, logical_and)
178 BOOST_YAP_BINARY_OPERATOR_CASE(&, bitwise_and)
179 BOOST_YAP_BINARY_OPERATOR_CASE(|, bitwise_or)
180 BOOST_YAP_BINARY_OPERATOR_CASE (^, bitwise_xor)
181
182 // clang-format off
183 //[ evaluation_transform_comma
184 template<typename T, typename U>
185 constexpr decltype(auto) operator()(expr_tag<expr_kind::comma>, T && t, U && u) const
186 {
187 return transform(
188 as_expr<minimal_expr>(static_cast<T &&>(t)), *this),
189 transform(
190 as_expr<minimal_expr>(static_cast<U &&>(u)), *this);
191 }
192 //]
193 // clang-format on
194
195 BOOST_YAP_BINARY_OPERATOR_CASE(->*, mem_ptr)
196 BOOST_YAP_BINARY_OPERATOR_CASE(=, assign)
197 BOOST_YAP_BINARY_OPERATOR_CASE(<<=, shift_left_assign)
198 BOOST_YAP_BINARY_OPERATOR_CASE(>>=, shift_right_assign)
199 BOOST_YAP_BINARY_OPERATOR_CASE(*=, multiplies_assign)
200 BOOST_YAP_BINARY_OPERATOR_CASE(/=, divides_assign)
201 BOOST_YAP_BINARY_OPERATOR_CASE(%=, modulus_assign)
202 BOOST_YAP_BINARY_OPERATOR_CASE(+=, plus_assign)
203 BOOST_YAP_BINARY_OPERATOR_CASE(-=, minus_assign)
204 BOOST_YAP_BINARY_OPERATOR_CASE(&=, bitwise_and_assign)
205 BOOST_YAP_BINARY_OPERATOR_CASE(|=, bitwise_or_assign)
206 BOOST_YAP_BINARY_OPERATOR_CASE(^=, bitwise_xor_assign)
207
208 template<typename T, typename U>
209 constexpr decltype(auto)
210 operator()(expr_tag<expr_kind::subscript>, T && t, U && u) const
211 {
212 return transform(
213 as_expr<minimal_expr>(static_cast<T &&>(t)), *this)[transform(
214 as_expr<minimal_expr>(static_cast<U &&>(u)), *this)];
215 }
216
217 #undef BOOST_YAP_BINARY_OPERATOR_CASE
218
219 template<typename T, typename U, typename V>
220 constexpr decltype(auto)
221 operator()(expr_tag<expr_kind::if_else>, T && t, U && u, V && v) const
222 {
223 return transform(as_expr<minimal_expr>(static_cast<T &&>(t)), *this)
224 ? transform(
225 as_expr<minimal_expr>(static_cast<U &&>(u)), *this)
226 : transform(
227 as_expr<minimal_expr>(static_cast<V &&>(v)),
228 *this);
229 }
230
231 // clang-format off
232 //[ evaluation_transform_call
233 template<typename Callable, typename... Args>
234 constexpr decltype(auto) operator()(
235 expr_tag<expr_kind::call>, Callable && callable, Args &&... args) const
236 {
237 return transform(as_expr<minimal_expr>(static_cast<Callable &&>(callable)), *this)(
238 transform(as_expr<minimal_expr>(static_cast<Args &&>(args)), *this)...
239 );
240 }
241 //]
242 // clang-format on
243
244 tuple_t placeholder_args_;
245 };
246
247
248 template<bool Strict, int I, bool IsExprRef>
249 struct transform_impl;
250
251 template<
252 bool Strict,
253 typename Expr,
254 typename TransformTuple,
255 int I,
256 expr_arity Arity,
257 typename = void_t<>>
258 struct transform_expression_tag;
259
260
261 // Forward terminals/recurively transform noterminasl; attempted last.
262
263 template<bool IsLvalueRef, bool IsTerminal, bool Strict>
264 struct default_transform
265 {
266 template<typename Expr, typename TransformTuple>
267 constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
268 {
269 return static_cast<Expr &&>(expr);
270 }
271 };
272
273 template<bool IsLvalueRef, bool IsTerminal>
274 struct default_transform<IsLvalueRef, IsTerminal, true>
275 {
276 struct incomplete;
277
278 // If you're getting an error because this function is uncallable,
279 // that's by design. You called yap::transform_strict(expr, xfrom)
280 // and one or more subexpression of 'expr' are not callable with any
281 // overload in 'xform'.
282 template<typename Expr, typename TransformTuple>
283 constexpr incomplete operator()(Expr && expr, TransformTuple transforms) const;
284 };
285
286 template<
287 expr_kind Kind,
288 template<expr_kind, class> class ExprTemplate,
289 typename OldTuple,
290 typename NewTuple>
291 constexpr auto make_expr_from_tuple(
292 ExprTemplate<Kind, OldTuple> const & expr, NewTuple && tuple)
293 {
294 return ExprTemplate<Kind, NewTuple>{std::move(tuple)};
295 }
296
297 template<expr_kind Kind, typename Expr, typename NewTuple>
298 constexpr auto make_expr_from_tuple(Expr const & expr, NewTuple && tuple)
299 {
300 return minimal_expr<Kind, NewTuple>{std::move(tuple)};
301 }
302
303 template<typename Expr, typename Tuple, typename TransformTuple>
304 constexpr decltype(auto) transform_nonterminal(
305 Expr const & expr, Tuple && tuple, TransformTuple transforms)
306 {
307 auto transformed_tuple =
308 hana::transform(static_cast<Tuple &&>(tuple), [&](auto && element) {
309 using element_t = decltype(element);
310 auto const kind = remove_cv_ref_t<element_t>::kind;
311 ::boost::yap::detail::
312 transform_impl<false, 0, kind == expr_kind::expr_ref>
313 xform;
314 return xform(static_cast<element_t &&>(element), transforms);
315 });
316 auto const kind = remove_cv_ref_t<Expr>::kind;
317 return make_expr_from_tuple<kind>(expr, std::move(transformed_tuple));
318 }
319
320 template<>
321 struct default_transform<true, false, false>
322 {
323 template<typename Expr, typename TransformTuple>
324 constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
325 {
326 return transform_nonterminal(expr, expr.elements, transforms);
327 }
328 };
329
330 template<>
331 struct default_transform<false, false, false>
332 {
333 template<typename Expr, typename TransformTuple>
334 constexpr decltype(auto)
335 operator()(Expr && expr, TransformTuple transforms) const
336 {
337 return transform_nonterminal(
338 expr, std::move(expr.elements), transforms);
339 }
340 };
341
342 // Dispatch to the next transform, or to the default transform if there is
343 // no next transform.
344
345 template<
346 bool Strict,
347 typename Expr,
348 typename TransformTuple,
349 int I,
350 bool NextTransformExists>
351 struct next_or_default_transform
352 {
353 constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
354 {
355 // Use the next transform.
356 constexpr expr_kind kind = remove_cv_ref_t<Expr>::kind;
357 return detail::
358 transform_impl<Strict, I + 1, kind == expr_kind::expr_ref>{}(
359 static_cast<Expr &&>(expr), transforms);
360 }
361 };
362
363 template<bool Strict, typename Expr, typename TransformTuple, int I>
364 struct next_or_default_transform<Strict, Expr, TransformTuple, I, false>
365 {
366 constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
367 {
368 // No next transform exists; use the default transform.
369 constexpr expr_kind kind = remove_cv_ref_t<Expr>::kind;
370 return default_transform<
371 std::is_lvalue_reference<Expr>::value,
372 kind == expr_kind::terminal,
373 Strict>{}(static_cast<Expr &&>(expr), transforms);
374 }
375 };
376
377 // Expression-matching; attempted second.
378
379 template<
380 bool Strict,
381 typename Expr,
382 typename TransformTuple,
383 int I,
384 typename = detail::void_t<>>
385 struct transform_expression_expr
386 {
387 constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
388 {
389 // No expr-matching succeeded; use the next or default transform.
390 return next_or_default_transform<
391 Strict,
392 Expr,
393 TransformTuple,
394 I,
395 I + 1 < decltype(hana::size(
396 std::declval<TransformTuple>()))::value>{}(
397 static_cast<Expr &&>(expr), transforms);
398 }
399 };
400
401 template<bool Strict, typename Expr, typename TransformTuple, int I>
402 struct transform_expression_expr<
403 Strict,
404 Expr,
405 TransformTuple,
406 I,
407 void_t<decltype((*std::declval<TransformTuple>()[hana::llong<I>{}])(
408 std::declval<Expr>()))>>
409 {
410 constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
411 {
412 return (*transforms[hana::llong<I>{}])(static_cast<Expr &&>(expr));
413 }
414 };
415
416
417 // Tag-matching; attempted first.
418
419 template<
420 bool Strict,
421 typename Expr,
422 typename TransformTuple,
423 int I,
424 expr_arity Arity,
425 typename>
426 struct transform_expression_tag
427 {
428 constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
429 {
430 // No tag-matching succeeded; try expr-matching.
431 return transform_expression_expr<Strict, Expr, TransformTuple, I>{}(
432 static_cast<Expr &&>(expr), transforms);
433 }
434 };
435
436 template<typename T>
437 constexpr decltype(auto) terminal_value(T && x)
438 {
439 return value_impl<true>(static_cast<T &&>(x));
440 }
441
442
443 template<bool Strict, typename Expr, typename TransformTuple, int I>
444 struct transform_expression_tag<
445 Strict,
446 Expr,
447 TransformTuple,
448 I,
449 expr_arity::one,
450 void_t<decltype((*std::declval<TransformTuple>()[hana::llong<I>{}])(
451 expr_tag<remove_cv_ref_t<Expr>::kind>{},
452 terminal_value(::boost::yap::value(std::declval<Expr>()))))>>
453 {
454 constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
455 {
456 return (*transforms[hana::llong<I>{}])(
457 expr_tag<remove_cv_ref_t<Expr>::kind>{},
458 terminal_value(
459 ::boost::yap::value(static_cast<Expr &&>(expr))));
460 }
461 };
462
463 template<bool Strict, typename Expr, typename TransformTuple, int I>
464 struct transform_expression_tag<
465 Strict,
466 Expr,
467 TransformTuple,
468 I,
469 expr_arity::two,
470 void_t<decltype((*std::declval<TransformTuple>()[hana::llong<I>{}])(
471 expr_tag<remove_cv_ref_t<Expr>::kind>{},
472 terminal_value(::boost::yap::left(std::declval<Expr>())),
473 terminal_value(::boost::yap::right(std::declval<Expr>()))))>>
474 {
475 constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
476 {
477 return (*transforms[hana::llong<I>{}])(
478 expr_tag<remove_cv_ref_t<Expr>::kind>{},
479 terminal_value(::boost::yap::left(static_cast<Expr &&>(expr))),
480 terminal_value(
481 ::boost::yap::right(static_cast<Expr &&>(expr))));
482 }
483 };
484
485 template<bool Strict, typename Expr, typename TransformTuple, int I>
486 struct transform_expression_tag<
487 Strict,
488 Expr,
489 TransformTuple,
490 I,
491 expr_arity::three,
492 void_t<decltype((*std::declval<TransformTuple>()[hana::llong<I>{}])(
493 expr_tag<remove_cv_ref_t<Expr>::kind>{},
494 terminal_value(::boost::yap::cond(std::declval<Expr>())),
495 terminal_value(::boost::yap::then(std::declval<Expr>())),
496 terminal_value(::boost::yap::else_(std::declval<Expr>()))))>>
497 {
498 constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
499 {
500 return (*transforms[hana::llong<I>{}])(
501 expr_tag<remove_cv_ref_t<Expr>::kind>{},
502 terminal_value(::boost::yap::cond(static_cast<Expr &&>(expr))),
503 terminal_value(::boost::yap::then(static_cast<Expr &&>(expr))),
504 terminal_value(
505 ::boost::yap::else_(static_cast<Expr &&>(expr))));
506 }
507 };
508
509 template<typename Expr, typename Transform>
510 struct transform_call_unpacker
511 {
512 template<long long... I>
513 constexpr auto operator()(
514 Expr && expr,
515 Transform & transform,
516 std::integer_sequence<long long, I...>) const
517 -> decltype(transform(
518 expr_tag<expr_kind::call>{},
519 terminal_value(::boost::yap::get(
520 static_cast<Expr &&>(expr), hana::llong_c<I>))...))
521 {
522 return transform(
523 expr_tag<expr_kind::call>{},
524 terminal_value(::boost::yap::get(
525 static_cast<Expr &&>(expr), hana::llong_c<I>))...);
526 }
527 };
528
529 template<typename Expr>
530 constexpr auto indices_for(Expr const & expr)
531 {
532 constexpr long long size = decltype(hana::size(expr.elements))::value;
533 return std::make_integer_sequence<long long, size>();
534 }
535
536 template<bool Strict, typename Expr, typename TransformTuple, int I>
537 struct transform_expression_tag<
538 Strict,
539 Expr,
540 TransformTuple,
541 I,
542 expr_arity::n,
543 void_t<decltype(
544 transform_call_unpacker<
545 Expr,
546 decltype(*std::declval<TransformTuple>()[hana::llong<I>{}])>{}(
547 std::declval<Expr>(),
548 *std::declval<TransformTuple>()[hana::llong<I>{}],
549 indices_for(std::declval<Expr>())))>>
550 {
551 constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
552 {
553 using transform_t = decltype(*transforms[hana::llong<I>{}]);
554 return transform_call_unpacker<Expr, transform_t>{}(
555 static_cast<Expr &&>(expr),
556 *transforms[hana::llong<I>{}],
557 indices_for(expr));
558 }
559 };
560
561 template<bool Strict, int I, bool IsExprRef>
562 struct transform_impl
563 {
564 template<typename Expr, typename TransformTuple>
565 constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
566 {
567 constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
568 return detail::transform_expression_tag<
569 Strict,
570 Expr,
571 TransformTuple,
572 I,
573 detail::arity_of<kind>()>{}(
574 static_cast<Expr &&>(expr), transforms);
575 }
576 };
577
578 template<bool Strict, int I>
579 struct transform_impl<Strict, I, true>
580 {
581 template<typename Expr, typename TransformTuple>
582 constexpr decltype(auto) operator()(Expr && expr, TransformTuple transforms) const
583 {
584 return detail::transform_impl<Strict, I, false>{}(
585 ::boost::yap::deref(static_cast<Expr &&>(expr)), transforms);
586 }
587 };
588
589 }}}
590
591 #endif