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