]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | //---------------------------------------------------------------------------// |
2 | // Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> | |
3 | // | |
4 | // Distributed under the Boost Software License, Version 1.0 | |
5 | // See accompanying file LICENSE_1_0.txt or copy at | |
6 | // http://www.boost.org/LICENSE_1_0.txt | |
7 | // | |
8 | // See http://boostorg.github.com/compute for more information. | |
9 | //---------------------------------------------------------------------------// | |
10 | ||
11 | #ifndef BOOST_COMPUTE_FUNCTIONAL_BIND_HPP | |
12 | #define BOOST_COMPUTE_FUNCTIONAL_BIND_HPP | |
13 | ||
14 | #include <boost/mpl/int.hpp> | |
15 | #include <boost/tuple/tuple.hpp> | |
16 | #include <boost/type_traits/conditional.hpp> | |
17 | ||
18 | #include <boost/compute/config.hpp> | |
19 | #include <boost/compute/detail/meta_kernel.hpp> | |
20 | ||
21 | namespace boost { | |
22 | namespace compute { | |
23 | namespace placeholders { | |
24 | ||
25 | /// \internal_ | |
26 | template<int I> | |
27 | struct placeholder : boost::integral_constant<int, I> | |
28 | { | |
29 | placeholder() { } | |
30 | }; | |
31 | ||
32 | placeholder<0> const _1; | |
33 | placeholder<1> const _2; | |
34 | ||
35 | } // end placeholders namespace | |
36 | ||
37 | /// Meta-function returning \c true if \c T is a placeholder type. | |
38 | template<class T> | |
39 | struct is_placeholder : boost::false_type | |
40 | { | |
41 | }; | |
42 | ||
43 | /// \internal_ | |
44 | template<int I> | |
45 | struct is_placeholder<placeholders::placeholder<I> > : boost::true_type | |
46 | { | |
47 | }; | |
48 | ||
49 | namespace detail { | |
50 | ||
51 | template<class Function, class BoundArgs, class Args> | |
52 | struct invoked_bound_function | |
53 | { | |
54 | invoked_bound_function(Function f, BoundArgs bound_args, Args args) | |
55 | : m_function(f), | |
56 | m_bound_args(bound_args), | |
57 | m_args(args) | |
58 | { | |
59 | } | |
60 | ||
61 | // meta-function returning true if the N'th argument is a placeholder | |
62 | template<int N> | |
63 | struct is_placeholder_arg | |
64 | { | |
65 | typedef typename boost::tuples::element<N, BoundArgs>::type nth_bound_arg; | |
66 | ||
67 | typedef typename is_placeholder<nth_bound_arg>::type type; | |
68 | static const bool value = is_placeholder<nth_bound_arg>::value; | |
69 | }; | |
70 | ||
71 | template<class Arg> | |
72 | struct get_arg_type | |
73 | { | |
74 | typedef Arg type; | |
75 | }; | |
76 | ||
77 | template<int I> | |
78 | struct get_arg_type<placeholders::placeholder<I> > | |
79 | { | |
80 | typedef typename boost::tuples::element<I, Args>::type type; | |
81 | }; | |
82 | ||
83 | // meta-function returning the type of the N'th argument when invoked | |
84 | template<int N> | |
85 | struct get_nth_arg_type | |
86 | { | |
87 | typedef typename boost::tuples::element<N, BoundArgs>::type nth_bound_arg; | |
88 | ||
89 | typedef typename get_arg_type<nth_bound_arg>::type type; | |
90 | }; | |
91 | ||
92 | template<int N> | |
93 | typename get_nth_arg_type<N>::type get_nth_arg( | |
94 | typename boost::enable_if_c<is_placeholder_arg<N>::value>::type* = 0 | |
95 | ) const | |
96 | { | |
97 | typedef typename boost::tuples::element<N, BoundArgs>::type nth_bound_arg; | |
98 | ||
99 | return boost::get<nth_bound_arg::value>(m_args); | |
100 | } | |
101 | ||
102 | template<int N> | |
103 | typename get_nth_arg_type<N>::type get_nth_arg( | |
104 | typename boost::disable_if_c<is_placeholder_arg<N>::value>::type* = 0 | |
105 | ) const | |
106 | { | |
107 | return boost::get<N>(m_bound_args); | |
108 | } | |
109 | ||
110 | Function m_function; | |
111 | BoundArgs m_bound_args; | |
112 | Args m_args; | |
113 | }; | |
114 | ||
115 | template<class Function, class BoundArgs, class Args> | |
116 | inline meta_kernel& apply_invoked_bound_function( | |
117 | meta_kernel &k, | |
118 | const invoked_bound_function<Function, BoundArgs, Args> &expr, | |
119 | typename boost::enable_if_c< | |
120 | boost::tuples::length<BoundArgs>::value == 1 | |
121 | >::type* = 0 | |
122 | ) | |
123 | { | |
124 | return k << expr.m_function(expr.template get_nth_arg<0>()); | |
125 | } | |
126 | ||
127 | template<class Function, class BoundArgs, class Args> | |
128 | inline meta_kernel& apply_invoked_bound_function( | |
129 | meta_kernel &k, | |
130 | const invoked_bound_function<Function, BoundArgs, Args> &expr, | |
131 | typename boost::enable_if_c< | |
132 | boost::tuples::length<BoundArgs>::value == 2 | |
133 | >::type* = 0 | |
134 | ) | |
135 | { | |
136 | return k << expr.m_function(expr.template get_nth_arg<0>(), | |
137 | expr.template get_nth_arg<1>()); | |
138 | } | |
139 | ||
140 | template<class Function, class BoundArgs, class Args> | |
141 | inline meta_kernel& apply_invoked_bound_function( | |
142 | meta_kernel &k, | |
143 | const invoked_bound_function<Function, BoundArgs, Args> &expr, | |
144 | typename boost::enable_if_c< | |
145 | boost::tuples::length<BoundArgs>::value == 3 | |
146 | >::type* = 0 | |
147 | ) | |
148 | { | |
149 | return k << expr.m_function(expr.template get_nth_arg<0>(), | |
150 | expr.template get_nth_arg<1>(), | |
151 | expr.template get_nth_arg<2>()); | |
152 | } | |
153 | ||
154 | template<class Function, class BoundArgs, class Args> | |
155 | inline meta_kernel& operator<<( | |
156 | meta_kernel &k, | |
157 | const invoked_bound_function<Function, BoundArgs, Args> &expr | |
158 | ) | |
159 | { | |
160 | return apply_invoked_bound_function(k, expr); | |
161 | } | |
162 | ||
163 | template<class Function, class BoundArgs> | |
164 | struct bound_function | |
165 | { | |
166 | typedef int result_type; | |
167 | ||
168 | bound_function(Function f, BoundArgs args) | |
169 | : m_function(f), | |
170 | m_args(args) | |
171 | { | |
172 | } | |
173 | ||
174 | template<class Arg1> | |
175 | detail::invoked_bound_function< | |
176 | Function, | |
177 | BoundArgs, | |
178 | boost::tuple<Arg1> | |
179 | > | |
180 | operator()(const Arg1 &arg1) const | |
181 | { | |
182 | return detail::invoked_bound_function< | |
183 | Function, | |
184 | BoundArgs, | |
185 | boost::tuple<Arg1> | |
186 | >(m_function, m_args, boost::make_tuple(arg1)); | |
187 | } | |
188 | ||
189 | template<class Arg1, class Arg2> | |
190 | detail::invoked_bound_function< | |
191 | Function, | |
192 | BoundArgs, | |
193 | boost::tuple<Arg1, Arg2> | |
194 | > | |
195 | operator()(const Arg1 &arg1, const Arg2 &arg2) const | |
196 | { | |
197 | return detail::invoked_bound_function< | |
198 | Function, | |
199 | BoundArgs, | |
200 | boost::tuple<Arg1, Arg2> | |
201 | >(m_function, m_args, boost::make_tuple(arg1, arg2)); | |
202 | } | |
203 | ||
204 | Function m_function; | |
205 | BoundArgs m_args; | |
206 | }; | |
207 | ||
208 | } // end detail namespace | |
209 | ||
210 | #if !defined(BOOST_COMPUTE_NO_VARIADIC_TEMPLATES) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED) | |
211 | /// Returns a function wrapper which invokes \p f with \p args when called. | |
212 | /// | |
213 | /// For example, to generate a unary function object which returns \c true | |
214 | /// when its argument is less than \c 7: | |
215 | /// \code | |
216 | /// using boost::compute::less; | |
217 | /// using boost::compute::placeholders::_1; | |
218 | /// | |
219 | /// auto less_than_seven = boost::compute::bind(less<int>(), _1, 7); | |
220 | /// \endcode | |
221 | template<class F, class... Args> | |
222 | inline detail::bound_function<F, boost::tuple<Args...> > | |
223 | bind(F f, Args... args) | |
224 | { | |
225 | typedef typename boost::tuple<Args...> ArgsTuple; | |
226 | ||
227 | return detail::bound_function<F, ArgsTuple>(f, boost::make_tuple(args...)); | |
228 | } | |
229 | #else | |
230 | template<class F, class A1> | |
231 | inline detail::bound_function<F, boost::tuple<A1> > | |
232 | bind(F f, A1 a1) | |
233 | { | |
234 | typedef typename boost::tuple<A1> Args; | |
235 | ||
236 | return detail::bound_function<F, Args>(f, boost::make_tuple(a1)); | |
237 | } | |
238 | ||
239 | template<class F, class A1, class A2> | |
240 | inline detail::bound_function<F, boost::tuple<A1, A2> > | |
241 | bind(F f, A1 a1, A2 a2) | |
242 | { | |
243 | typedef typename boost::tuple<A1, A2> Args; | |
244 | ||
245 | return detail::bound_function<F, Args>(f, boost::make_tuple(a1, a2)); | |
246 | } | |
247 | ||
248 | template<class F, class A1, class A2, class A3> | |
249 | inline detail::bound_function<F, boost::tuple<A1, A2, A3> > | |
250 | bind(F f, A1 a1, A2 a2, A3 a3) | |
251 | { | |
252 | typedef typename boost::tuple<A1, A2, A3> Args; | |
253 | ||
254 | return detail::bound_function<F, Args>(f, boost::make_tuple(a1, a2, a3)); | |
255 | } | |
256 | #endif // BOOST_COMPUTE_NO_VARIADIC_TEMPLATES | |
257 | ||
258 | } // end compute namespace | |
259 | } // end boost namespace | |
260 | ||
261 | #endif // BOOST_COMPUTE_FUNCTIONAL_BIND_HPP |