1 /*=============================================================================
2 Copyright (c) 2014 Paul Fultz II
3 placeholders.h
4 Distributed under the Boost Software License, Version 1.0. (See accompanying
5 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 ==============================================================================*/
7
8 #ifndef BOOST_HOF_GUARD_FUNCTION_PLACEHOLDERS_H
9 #define BOOST_HOF_GUARD_FUNCTION_PLACEHOLDERS_H
10
11 /// placeholders
12 /// ============
13 ///
14 /// Description
15 /// -----------
16 ///
17 /// The placeholders provide `std::bind` compatible placeholders that
18 /// additionally provide basic C++ operators that creates bind expressions.
19 /// Each bind expression supports `constexpr` function evaluation.
20 ///
21 /// Synopsis
22 /// --------
23 ///
24 /// namespace placeholders {
25 /// placeholder<1> _1 = {};
26 /// placeholder<2> _2 = {};
27 /// placeholder<3> _3 = {};
28 /// placeholder<4> _4 = {};
29 /// placeholder<5> _5 = {};
30 /// placeholder<6> _6 = {};
31 /// placeholder<7> _7 = {};
32 /// placeholder<8> _8 = {};
33 /// placeholder<9> _9 = {};
34 /// }
35 ///
36 /// Operators
37 /// ---------
38 ///
39 /// * Binary operators: +,-,*,/,%,>>,<<,>,<,<=,>=,==,!=,&,^,|,&&,||
40 /// * Assign operators: +=,-=,*=,/=,%=,>>=,<<=,&=,|=,^=
41 /// * Unary operators: !,~,+,-,*,++,--
42 ///
43 ///
44 /// Example
45 /// -------
46 ///
47 /// #include <boost/hof.hpp>
48 /// #include <cassert>
49 /// using namespace boost::hof;
50 ///
51 /// int main() {
52 /// auto sum = _1 + _2;
53 /// assert(3 == sum(1, 2));
54 /// }
55 ///
56 ///
57 /// unamed placeholder
58 /// ==================
59 ///
60 /// Description
61 /// -----------
62 ///
63 /// The unamed placeholder can be used to build simple functions from C++
64 /// operators.
65 ///
66 /// Note: The function produced by the unamed placeholder is not a bind expression.
67 ///
68 /// Synopsis
69 /// --------
70 ///
71 /// namespace placeholders {
72 /// /* unspecified */ _ = {};
73 /// }
74 ///
75 /// Example
76 /// -------
77 ///
78 /// #include <boost/hof.hpp>
79 /// #include <cassert>
80 /// using namespace boost::hof;
81 ///
82 /// int main() {
83 /// auto sum = _ + _;
84 /// assert(3 == sum(1, 2));
85 /// }
86 ///
87
88 #include <boost/hof/returns.hpp>
89 #include <boost/hof/lazy.hpp>
90 #include <boost/hof/protect.hpp>
91
92 #if defined(_MSC_VER) && _MSC_VER >= 1910
93 #include <boost/hof/detail/pp.hpp>
94 #endif
95
96 namespace boost { namespace hof { namespace detail {
97 template<int N>
98 struct simple_placeholder
99 {};
100 }}} // namespace boost::hof
101
102 namespace std {
103 template<int N>
104 struct is_placeholder<boost::hof::detail::simple_placeholder<N>>
105 : std::integral_constant<int, N>
106 {};
107 }
108
109
110 namespace boost { namespace hof {
111
112 #define BOOST_HOF_FOREACH_BINARY_OP(m) \
113 m(+, add) \
114 m(-, subtract) \
115 m(*, multiply) \
116 m(/, divide) \
117 m(%, remainder) \
118 m(>>, shift_right) \
119 m(<<, shift_left) \
120 m(>, greater_than) \
121 m(<, less_than) \
122 m(<=, less_than_equal) \
123 m(>=, greater_than_equal) \
124 m(==, equal) \
125 m(!=, not_equal) \
126 m(&, bit_and) \
127 m(^, xor_) \
128 m(|, bit_or) \
129 m(&&, and_) \
130 m(||, or_)
131
132 #define BOOST_HOF_FOREACH_ASSIGN_OP(m) \
133 m(+=, assign_add) \
134 m(-=, assign_subtract) \
135 m(*=, assign_multiply) \
136 m(/=, assign_divide) \
137 m(%=, assign_remainder) \
138 m(>>=, assign_right_shift) \
139 m(<<=, assign_left_shift) \
140 m(&=, assign_bit_and) \
141 m(|=, assign_bit_or) \
142 m(^=, assign_xor)
143
144 #ifndef _MSC_VER
145 #define BOOST_HOF_FOREACH_UNARY_OP(m) \
146 m(!, not_) \
147 m(~, compl_) \
148 m(+, unary_plus) \
149 m(-, unary_subtract) \
150 m(*, dereference) \
151 m(++, increment) \
152 m(--, decrement)
153 #else
154 #define BOOST_HOF_FOREACH_UNARY_OP(m) \
155 m(!, not_) \
156 m(~, compl_) \
157 m(+, unary_plus) \
158 m(-, unary_subtract) \
159 m(*, dereference)
160 #endif
161
162 namespace operators {
163
164 struct call
165 {
166 template<class F, class... Ts>
167 constexpr auto operator()(F&& f, Ts&&... xs) const BOOST_HOF_RETURNS
168 (f(BOOST_HOF_FORWARD(Ts)(xs)...));
169 };
170
171 // MSVC 2017 ICEs on && and || in conxtexpr, so we fallback on bitwise operators
172 #if defined(_MSC_VER) && _MSC_VER >= 1910
173 #define BOOST_HOF_BINARY_OP_SKIP_and_ ()
174 #define BOOST_HOF_BINARY_OP_SKIP_or_ ()
175
176 struct and_
177 {
178 template<class T, class U>
operator ()boost::hof::operators::and_179 constexpr auto operator()(T&& x, U&& y) const
180 noexcept(noexcept(BOOST_HOF_FORWARD(T)(x) && BOOST_HOF_FORWARD(U)(y)))
181 -> decltype(BOOST_HOF_FORWARD(T)(x) && BOOST_HOF_FORWARD(U)(y))
182 { return BOOST_HOF_FORWARD(T)(x) & BOOST_HOF_FORWARD(U)(y); }
183 };
184
185 struct or_
186 {
187 template<class T, class U>
operator ()boost::hof::operators::or_188 constexpr auto operator()(T&& x, U&& y) const
189 noexcept(noexcept(BOOST_HOF_FORWARD(T)(x) || BOOST_HOF_FORWARD(U)(y)))
190 -> decltype(BOOST_HOF_FORWARD(T)(x) || BOOST_HOF_FORWARD(U)(y))
191 { return BOOST_HOF_FORWARD(T)(x) | BOOST_HOF_FORWARD(U)(y); }
192 };
193
194 #define BOOST_HOF_BINARY_OP_IMPL(op, name) \
195 struct name \
196 { \
197 template<class T, class U> \
198 BOOST_HOF_USING(ex_failure, decltype(std::declval<T>() op std::declval<U>())); \
199 struct failure : as_failure<ex_failure> {}; \
200 template<class T, class U> \
201 constexpr auto operator()(T&& x, U&& y) const BOOST_HOF_RETURNS \
202 (BOOST_HOF_FORWARD(T)(x) op BOOST_HOF_FORWARD(U)(y)); \
203 };
204
205 #define BOOST_HOF_BINARY_OP(op, name) \
206 BOOST_HOF_PP_IIF(BOOST_HOF_PP_IS_PAREN(BOOST_HOF_PP_CAT(BOOST_HOF_BINARY_OP_SKIP_, name))) \
207 (BOOST_HOF_PP_EMPTY, BOOST_HOF_BINARY_OP_IMPL)(op, name)
208
209 #else
210
211 #define BOOST_HOF_BINARY_OP(op, name) \
212 struct name \
213 { \
214 template<class T, class U> \
215 constexpr auto operator()(T&& x, U&& y) const BOOST_HOF_RETURNS \
216 (BOOST_HOF_FORWARD(T)(x) op BOOST_HOF_FORWARD(U)(y)); \
217 };
218
219 #endif
220
221 BOOST_HOF_FOREACH_BINARY_OP(BOOST_HOF_BINARY_OP)
222 BOOST_HOF_FOREACH_ASSIGN_OP(BOOST_HOF_BINARY_OP)
223
224 #define BOOST_HOF_UNARY_OP(op, name) \
225 struct name \
226 { \
227 template<class T> \
228 constexpr auto operator()(T&& x) const BOOST_HOF_RETURNS \
229 (op(BOOST_HOF_FORWARD(T)(x))); \
230 };
231
232
233 BOOST_HOF_FOREACH_UNARY_OP(BOOST_HOF_UNARY_OP)
234
235
236 }
237
238 template<int N>
239 struct placeholder
240 {
241 #if BOOST_HOF_HAS_MANGLE_OVERLOAD
242 template<class... Ts>
243 constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS
244 ( boost::hof::lazy(operators::call())(detail::simple_placeholder<N>(), BOOST_HOF_FORWARD(Ts)(xs)...) );
245 #else
246 template<class... Ts>
247 struct result_call
248 { typedef decltype(boost::hof::lazy(operators::call())(detail::simple_placeholder<N>(), std::declval<Ts>()...)) type; };
249 template<class... Ts>
250 constexpr typename result_call<Ts...>::type operator()(Ts&&... xs) const
251 { return boost::hof::lazy(operators::call())(detail::simple_placeholder<N>(), BOOST_HOF_FORWARD(Ts)(xs)...); };
252
253 #endif
254
255 #define BOOST_HOF_PLACEHOLDER_UNARY_OP(op, name) \
256 constexpr auto operator op () const BOOST_HOF_RETURNS \
257 ( boost::hof::lazy(operators::name())(detail::simple_placeholder<N>()) );
258
259 BOOST_HOF_FOREACH_UNARY_OP(BOOST_HOF_PLACEHOLDER_UNARY_OP)
260
261 #define BOOST_HOF_PLACEHOLDER_ASSIGN_OP(op, name) \
262 template<class T> \
263 constexpr auto operator op (T&& x) const BOOST_HOF_RETURNS \
264 ( boost::hof::lazy(operators::name())(detail::simple_placeholder<N>(), BOOST_HOF_FORWARD(T)(x)) );
265
266 BOOST_HOF_FOREACH_ASSIGN_OP(BOOST_HOF_PLACEHOLDER_ASSIGN_OP)
267
268 };
269
270 #if BOOST_HOF_HAS_MANGLE_OVERLOAD
271
272 #define BOOST_HOF_PLACEHOLDER_BINARY_OP(op, name) \
273 template<class T, int N> \
274 constexpr inline auto operator op (const placeholder<N>&, T&& x) BOOST_HOF_RETURNS \
275 ( boost::hof::lazy(operators::name())(detail::simple_placeholder<N>(), BOOST_HOF_FORWARD(T)(x)) ); \
276 template<class T, int N> \
277 constexpr inline auto operator op (T&& x, const placeholder<N>&) BOOST_HOF_RETURNS \
278 ( boost::hof::lazy(operators::name())(BOOST_HOF_FORWARD(T)(x), detail::simple_placeholder<N>()) ); \
279 template<int N, int M> \
280 constexpr inline auto operator op (const placeholder<N>&, const placeholder<M>&) BOOST_HOF_RETURNS \
281 ( boost::hof::lazy(operators::name())(detail::simple_placeholder<N>(), detail::simple_placeholder<M>()) );
282
283 #else
284
285 #define BOOST_HOF_PLACEHOLDER_BINARY_OP(op, name) \
286 template<class T, class U> \
287 struct result_ ## name \
288 { typedef decltype(boost::hof::lazy(operators::name())(std::declval<T>(), std::declval<U>())) type; }; \
289 template<class T, int N> \
290 constexpr inline typename result_ ## name<detail::simple_placeholder<N>, T>::type operator op (const placeholder<N>&, T&& x) \
291 { return boost::hof::lazy(operators::name())(detail::simple_placeholder<N>(), BOOST_HOF_FORWARD(T)(x)); } \
292 template<class T, int N> \
293 constexpr inline typename result_ ## name<T, detail::simple_placeholder<N>>::type operator op (T&& x, const placeholder<N>&) \
294 { return boost::hof::lazy(operators::name())(BOOST_HOF_FORWARD(T)(x), detail::simple_placeholder<N>()); } \
295 template<int N, int M> \
296 constexpr inline typename result_ ## name<detail::simple_placeholder<N>, detail::simple_placeholder<M>>::type operator op (const placeholder<N>&, const placeholder<M>&) \
297 { return boost::hof::lazy(operators::name())(detail::simple_placeholder<N>(), detail::simple_placeholder<M>()); }
298
299 #endif
300
301 BOOST_HOF_FOREACH_BINARY_OP(BOOST_HOF_PLACEHOLDER_BINARY_OP)
302
303 namespace placeholders {
304 BOOST_HOF_DECLARE_STATIC_VAR(_1, placeholder<1>);
305 BOOST_HOF_DECLARE_STATIC_VAR(_2, placeholder<2>);
306 BOOST_HOF_DECLARE_STATIC_VAR(_3, placeholder<3>);
307 BOOST_HOF_DECLARE_STATIC_VAR(_4, placeholder<4>);
308 BOOST_HOF_DECLARE_STATIC_VAR(_5, placeholder<5>);
309 BOOST_HOF_DECLARE_STATIC_VAR(_6, placeholder<6>);
310 BOOST_HOF_DECLARE_STATIC_VAR(_7, placeholder<7>);
311 BOOST_HOF_DECLARE_STATIC_VAR(_8, placeholder<8>);
312 BOOST_HOF_DECLARE_STATIC_VAR(_9, placeholder<9>);
313 }
314
315 using placeholders::_1;
316 using placeholders::_2;
317 using placeholders::_3;
318 using placeholders::_4;
319 using placeholders::_5;
320 using placeholders::_6;
321 using placeholders::_7;
322 using placeholders::_8;
323 using placeholders::_9;
324
325 namespace detail {
326
327
328
329 struct unamed_placeholder
330 {
331 template<class T, class Invoker>
332 struct partial_ap
333 {
334 T val;
335
BOOST_HOF_INHERIT_DEFAULT_EMPTYboost::hof::detail::unamed_placeholder::partial_ap336 BOOST_HOF_INHERIT_DEFAULT_EMPTY(partial_ap, T)
337
338 template<class X, class... Xs, BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(T, X&&, Xs&&...)>
339 constexpr partial_ap(X&& x, Xs&&... xs) : val(BOOST_HOF_FORWARD(X)(x), BOOST_HOF_FORWARD(Xs)(xs)...)
340 {}
341
342 BOOST_HOF_RETURNS_CLASS(partial_ap);
343
344 struct partial_ap_failure
345 {
346 template<class Failure>
347 struct apply
348 {
349 template<class... Xs>
350 struct of;
351
352 template<class X>
353 struct of<X>
354 : Failure::template of<typename std::add_const<T>::type, X>
355 {};
356 };
357 };
358
359 struct failure
360 : failure_map<partial_ap_failure, Invoker>
361 {};
362
363 template<class X>
364 constexpr BOOST_HOF_SFINAE_RESULT(const Invoker&, id_<T>, id_<X>)
365 operator()(X&& x) const BOOST_HOF_SFINAE_RETURNS
366 (
367 Invoker()(BOOST_HOF_CONST_THIS->val, BOOST_HOF_FORWARD(X)(x))
368 );
369 };
370
371 template<class Invoker, class T>
make_partial_apboost::hof::detail::unamed_placeholder372 static constexpr partial_ap<T, Invoker> make_partial_ap(T&& x)
373 {
374 return {BOOST_HOF_FORWARD(T)(x)};
375 }
376
377 template<class Op>
378 struct left
379 {
380 struct failure
381 : failure_for<Op>
382 {};
383 template<class T, class X>
384 constexpr BOOST_HOF_SFINAE_RESULT(const Op&, id_<T>, id_<X>)
385 operator()(T&& val, X&& x) const BOOST_HOF_SFINAE_RETURNS
386 (Op()(BOOST_HOF_FORWARD(T)(val), BOOST_HOF_FORWARD(X)(x)));
387 };
388
389 template<class Op>
390 struct right
391 {
392 struct right_failure
393 {
394 template<class Failure>
395 struct apply
396 {
397 template<class T, class U, class... Ts>
398 struct of
399 : Failure::template of<U, T, Ts...>
400 {};
401 };
402 };
403
404 struct failure
405 : failure_map<right_failure, Op>
406 {};
407
408 template<class T, class X>
409 constexpr BOOST_HOF_SFINAE_RESULT(const Op&, id_<X>, id_<T>)
410 operator()(T&& val, X&& x) const BOOST_HOF_SFINAE_RETURNS
411 (Op()(BOOST_HOF_FORWARD(X)(x), BOOST_HOF_FORWARD(T)(val)));
412 };
413
414 #define BOOST_HOF_UNAMED_PLACEHOLDER_UNARY_OP(op, name) \
415 constexpr auto operator op () const BOOST_HOF_RETURNS \
416 ( operators::name() );
417
418 BOOST_HOF_FOREACH_UNARY_OP(BOOST_HOF_UNAMED_PLACEHOLDER_UNARY_OP)
419
420 #define BOOST_HOF_UNAMED_PLACEHOLDER_ASSIGN_OP(op, name) \
421 template<class T> \
422 constexpr auto operator op (const T& x) const BOOST_HOF_RETURNS \
423 ( partial_ap<T, left<operators::name>>(x) );
424
425 BOOST_HOF_FOREACH_ASSIGN_OP(BOOST_HOF_UNAMED_PLACEHOLDER_ASSIGN_OP)
426 };
427 #define BOOST_HOF_UNAMED_PLACEHOLDER_BINARY_OP(op, name) \
428 template<class T> \
429 constexpr inline auto operator op (const unamed_placeholder&, const T& x) BOOST_HOF_RETURNS \
430 ( unamed_placeholder::make_partial_ap<unamed_placeholder::right<operators::name>>(boost::hof::decay(x)) ); \
431 template<class T> \
432 constexpr inline auto operator op (const T& x, const unamed_placeholder&) BOOST_HOF_RETURNS \
433 ( unamed_placeholder::make_partial_ap<unamed_placeholder::left<operators::name>>(boost::hof::decay(x)) ); \
434 constexpr inline auto operator op (const unamed_placeholder&, const unamed_placeholder&) BOOST_HOF_RETURNS \
435 ( operators::name() );
436
437 BOOST_HOF_FOREACH_BINARY_OP(BOOST_HOF_UNAMED_PLACEHOLDER_BINARY_OP)
438 }
439
440 namespace placeholders {
441 BOOST_HOF_DECLARE_STATIC_VAR(_, detail::unamed_placeholder);
442 }
443
444 using placeholders::_;
445
446 }} // namespace boost::hof
447
448 namespace std {
449 template<int N>
450 struct is_placeholder<boost::hof::placeholder<N>>
451 : std::integral_constant<int, N>
452 {};
453 }
454
455 namespace boost {
456
457 template<class T>
458 struct is_placeholder;
459
460 template<int N>
461 struct is_placeholder<boost::hof::placeholder<N>>
462 : std::integral_constant<int, N>
463 {};
464
465
466 }
467
468 #endif
469