]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/hana/include/boost/hana/functional/infix.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / hana / include / boost / hana / functional / infix.hpp
1 /*!
2 @file
3 Defines `boost::hana::infix`.
4
5 @copyright Louis Dionne 2013-2016
6 Distributed under the Boost Software License, Version 1.0.
7 (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
8 */
9
10 #ifndef BOOST_HANA_FUNCTIONAL_INFIX_HPP
11 #define BOOST_HANA_FUNCTIONAL_INFIX_HPP
12
13 #include <boost/hana/config.hpp>
14 #include <boost/hana/detail/decay.hpp>
15 #include <boost/hana/functional/partial.hpp>
16 #include <boost/hana/functional/reverse_partial.hpp>
17
18 #include <type_traits>
19 #include <utility>
20
21
22 BOOST_HANA_NAMESPACE_BEGIN
23 //! @ingroup group-functional
24 //! Return an equivalent function that can also be applied in infix
25 //! notation.
26 //!
27 //! Specifically, `infix(f)` is an object such that:
28 //! @code
29 //! infix(f)(x1, ..., xn) == f(x1, ..., xn)
30 //! x ^infix(f)^ y == f(x, y)
31 //! @endcode
32 //!
33 //! Hence, the returned function can still be applied using the usual
34 //! function call syntax, but it also gains the ability to be applied in
35 //! infix notation. The infix syntax allows a great deal of expressiveness,
36 //! especially when used in combination with some higher order algorithms.
37 //! Since `operator^` is left-associative, `x ^infix(f)^ y` is actually
38 //! parsed as `(x ^infix(f))^ y`. However, for flexibility, the order in
39 //! which both arguments are applied in infix notation does not matter.
40 //! Hence, it is always the case that
41 //! @code
42 //! (x ^ infix(f)) ^ y == x ^ (infix(f) ^ y)
43 //! @endcode
44 //!
45 //! However, note that applying more than one argument in infix
46 //! notation to the same side of the operator will result in a
47 //! compile-time assertion:
48 //! @code
49 //! (infix(f) ^ x) ^ y; // compile-time assertion
50 //! y ^ (x ^ infix(f)); // compile-time assertion
51 //! @endcode
52 //!
53 //! Additionally, a function created with `infix` may be partially applied
54 //! in infix notation. Specifically,
55 //! @code
56 //! (x ^ infix(f))(y1, ..., yn) == f(x, y1, ..., yn)
57 //! (infix(f) ^ y)(x1, ..., xn) == f(x1, ..., xn, y)
58 //! @endcode
59 //!
60 //! @internal
61 //! ### Rationales
62 //! 1. The `^` operator was chosen because it is left-associative and
63 //! has a low enough priority so that most expressions will render
64 //! the expected behavior.
65 //! 2. The operator can't be customimzed because that would require more
66 //! sophistication in the implementation; I want to keep it as simple
67 //! as possible. There is also an advantage in having a uniform syntax
68 //! for infix application.
69 //! @endinternal
70 //!
71 //! @param f
72 //! The function which gains the ability to be applied in infix notation.
73 //! The function must be at least binary; a compile-time error will be
74 //! triggered otherwise.
75 //!
76 //! ### Example
77 //! @include example/functional/infix.cpp
78 #ifdef BOOST_HANA_DOXYGEN_INVOKED
79 constexpr auto infix = [](auto f) {
80 return unspecified;
81 };
82 #else
83 namespace infix_detail {
84 // This needs to be in the same namespace as `operator^` so it can be
85 // found by ADL.
86 template <bool left, bool right, typename F>
87 struct infix_t {
88 F f;
89
90 template <typename ...X>
91 constexpr decltype(auto) operator()(X&& ...x) const&
92 { return f(static_cast<X&&>(x)...); }
93
94 template <typename ...X>
95 constexpr decltype(auto) operator()(X&& ...x) &
96 { return f(static_cast<X&&>(x)...); }
97
98 template <typename ...X>
99 constexpr decltype(auto) operator()(X&& ...x) &&
100 { return std::move(f)(static_cast<X&&>(x)...); }
101 };
102
103 template <bool left, bool right>
104 struct make_infix {
105 template <typename F>
106 constexpr infix_t<left, right, typename detail::decay<F>::type>
107 operator()(F&& f) const { return {static_cast<F&&>(f)}; }
108 };
109
110 template <bool left, bool right>
111 struct Infix;
112 struct Object;
113
114 template <typename T>
115 struct dispatch { using type = Object; };
116
117 template <bool left, bool right, typename F>
118 struct dispatch<infix_t<left, right, F>> {
119 using type = Infix<left, right>;
120 };
121
122 template <typename, typename>
123 struct bind_infix;
124
125 // infix(f) ^ y
126 template <>
127 struct bind_infix<Infix<false, false>, Object> {
128 template <typename F, typename Y>
129 static constexpr decltype(auto) apply(F&& f, Y&& y) {
130 return make_infix<false, true>{}(
131 hana::reverse_partial(
132 static_cast<F&&>(f), static_cast<Y&&>(y)
133 )
134 );
135 }
136 };
137
138 // (x^infix(f)) ^ y
139 template <>
140 struct bind_infix<Infix<true, false>, Object> {
141 template <typename F, typename Y>
142 static constexpr decltype(auto) apply(F&& f, Y&& y) {
143 return static_cast<F&&>(f)(static_cast<Y&&>(y));
144 }
145 };
146
147 // x ^ infix(f)
148 template <>
149 struct bind_infix<Object, Infix<false, false>> {
150 template <typename X, typename F>
151 static constexpr decltype(auto) apply(X&& x, F&& f) {
152 return make_infix<true, false>{}(
153 hana::partial(static_cast<F&&>(f), static_cast<X&&>(x))
154 );
155 }
156 };
157
158 // x ^ (infix(f)^y)
159 template <>
160 struct bind_infix<Object, Infix<false, true>> {
161 template <typename X, typename F>
162 static constexpr decltype(auto) apply(X&& x, F&& f) {
163 return static_cast<F&&>(f)(static_cast<X&&>(x));
164 }
165 };
166
167 template <typename T>
168 using strip = typename std::remove_cv<
169 typename std::remove_reference<T>::type
170 >::type;
171
172 template <typename X, typename Y>
173 constexpr decltype(auto) operator^(X&& x, Y&& y) {
174 return bind_infix<
175 typename dispatch<strip<X>>::type,
176 typename dispatch<strip<Y>>::type
177 >::apply(static_cast<X&&>(x), static_cast<Y&&>(y));
178 }
179 } // end namespace infix_detail
180
181 constexpr infix_detail::make_infix<false, false> infix{};
182 #endif
183 BOOST_HANA_NAMESPACE_END
184
185 #endif // !BOOST_HANA_FUNCTIONAL_INFIX_HPP