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 {
placeholderboost::compute::placeholders::placeholder29     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 {
invoked_bound_functionboost::compute::detail::invoked_bound_function54     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>
get_nth_argboost::compute::detail::invoked_bound_function93     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>
get_nth_argboost::compute::detail::invoked_bound_function103     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>
apply_invoked_bound_function(meta_kernel & k,const invoked_bound_function<Function,BoundArgs,Args> & expr,typename boost::enable_if_c<boost::tuples::length<BoundArgs>::value==1>::type * =0)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>
apply_invoked_bound_function(meta_kernel & k,const invoked_bound_function<Function,BoundArgs,Args> & expr,typename boost::enable_if_c<boost::tuples::length<BoundArgs>::value==2>::type * =0)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>
apply_invoked_bound_function(meta_kernel & k,const invoked_bound_function<Function,BoundArgs,Args> & expr,typename boost::enable_if_c<boost::tuples::length<BoundArgs>::value==3>::type * =0)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>
operator <<(meta_kernel & k,const invoked_bound_function<Function,BoundArgs,Args> & expr)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 
bound_functionboost::compute::detail::bound_function168     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     >
operator ()boost::compute::detail::bound_function180     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     >
operator ()boost::compute::detail::bound_function195     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...> >
bind(F f,Args...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> >
bind(F f,A1 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> >
bind(F f,A1 a1,A2 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> >
bind(F f,A1 a1,A2 a2,A3 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
262