• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
96namespace boost { namespace hof { namespace detail {
97    template<int N>
98    struct simple_placeholder
99    {};
100}}} // namespace boost::hof
101
102namespace 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
110namespace 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
162namespace operators {
163
164struct 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
176struct and_
177{
178    template<class T, class U>
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
185struct or_
186{
187    template<class T, class U>
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
221BOOST_HOF_FOREACH_BINARY_OP(BOOST_HOF_BINARY_OP)
222BOOST_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
233BOOST_HOF_FOREACH_UNARY_OP(BOOST_HOF_UNARY_OP)
234
235
236}
237
238template<int N>
239struct 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
259BOOST_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
266BOOST_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
301BOOST_HOF_FOREACH_BINARY_OP(BOOST_HOF_PLACEHOLDER_BINARY_OP)
302
303namespace placeholders {
304BOOST_HOF_DECLARE_STATIC_VAR(_1, placeholder<1>);
305BOOST_HOF_DECLARE_STATIC_VAR(_2, placeholder<2>);
306BOOST_HOF_DECLARE_STATIC_VAR(_3, placeholder<3>);
307BOOST_HOF_DECLARE_STATIC_VAR(_4, placeholder<4>);
308BOOST_HOF_DECLARE_STATIC_VAR(_5, placeholder<5>);
309BOOST_HOF_DECLARE_STATIC_VAR(_6, placeholder<6>);
310BOOST_HOF_DECLARE_STATIC_VAR(_7, placeholder<7>);
311BOOST_HOF_DECLARE_STATIC_VAR(_8, placeholder<8>);
312BOOST_HOF_DECLARE_STATIC_VAR(_9, placeholder<9>);
313}
314
315using placeholders::_1;
316using placeholders::_2;
317using placeholders::_3;
318using placeholders::_4;
319using placeholders::_5;
320using placeholders::_6;
321using placeholders::_7;
322using placeholders::_8;
323using placeholders::_9;
324
325namespace detail {
326
327
328
329struct unamed_placeholder
330{
331template<class T, class Invoker>
332struct partial_ap
333{
334    T val;
335
336    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
371template<class Invoker, class T>
372static constexpr partial_ap<T, Invoker> make_partial_ap(T&& x)
373{
374    return {BOOST_HOF_FORWARD(T)(x)};
375}
376
377template<class Op>
378struct 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
389template<class Op>
390struct 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
418BOOST_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
425BOOST_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
437BOOST_HOF_FOREACH_BINARY_OP(BOOST_HOF_UNAMED_PLACEHOLDER_BINARY_OP)
438}
439
440namespace placeholders {
441BOOST_HOF_DECLARE_STATIC_VAR(_, detail::unamed_placeholder);
442}
443
444using placeholders::_;
445
446}} // namespace boost::hof
447
448namespace std {
449    template<int N>
450    struct is_placeholder<boost::hof::placeholder<N>>
451    : std::integral_constant<int, N>
452    {};
453}
454
455namespace 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