diff options
Diffstat (limited to 'boost/compute/functional/bind.hpp')
-rw-r--r-- | boost/compute/functional/bind.hpp | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/boost/compute/functional/bind.hpp b/boost/compute/functional/bind.hpp new file mode 100644 index 0000000000..0c5929f3b9 --- /dev/null +++ b/boost/compute/functional/bind.hpp @@ -0,0 +1,261 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#ifndef BOOST_COMPUTE_FUNCTIONAL_BIND_HPP +#define BOOST_COMPUTE_FUNCTIONAL_BIND_HPP + +#include <boost/mpl/int.hpp> +#include <boost/tuple/tuple.hpp> +#include <boost/type_traits/conditional.hpp> + +#include <boost/compute/config.hpp> +#include <boost/compute/detail/meta_kernel.hpp> + +namespace boost { +namespace compute { +namespace placeholders { + +/// \internal_ +template<int I> +struct placeholder : boost::integral_constant<int, I> +{ + placeholder() { } +}; + +placeholder<0> const _1; +placeholder<1> const _2; + +} // end placeholders namespace + +/// Meta-function returning \c true if \c T is a placeholder type. +template<class T> +struct is_placeholder : boost::false_type +{ +}; + +/// \internal_ +template<int I> +struct is_placeholder<placeholders::placeholder<I> > : boost::true_type +{ +}; + +namespace detail { + +template<class Function, class BoundArgs, class Args> +struct invoked_bound_function +{ + invoked_bound_function(Function f, BoundArgs bound_args, Args args) + : m_function(f), + m_bound_args(bound_args), + m_args(args) + { + } + + // meta-function returning true if the N'th argument is a placeholder + template<int N> + struct is_placeholder_arg + { + typedef typename boost::tuples::element<N, BoundArgs>::type nth_bound_arg; + + typedef typename is_placeholder<nth_bound_arg>::type type; + static const bool value = is_placeholder<nth_bound_arg>::value; + }; + + template<class Arg> + struct get_arg_type + { + typedef Arg type; + }; + + template<int I> + struct get_arg_type<placeholders::placeholder<I> > + { + typedef typename boost::tuples::element<I, Args>::type type; + }; + + // meta-function returning the type of the N'th argument when invoked + template<int N> + struct get_nth_arg_type + { + typedef typename boost::tuples::element<N, BoundArgs>::type nth_bound_arg; + + typedef typename get_arg_type<nth_bound_arg>::type type; + }; + + template<int N> + typename get_nth_arg_type<N>::type get_nth_arg( + typename boost::enable_if_c<is_placeholder_arg<N>::value>::type* = 0 + ) const + { + typedef typename boost::tuples::element<N, BoundArgs>::type nth_bound_arg; + + return boost::get<nth_bound_arg::value>(m_args); + } + + template<int N> + typename get_nth_arg_type<N>::type get_nth_arg( + typename boost::disable_if_c<is_placeholder_arg<N>::value>::type* = 0 + ) const + { + return boost::get<N>(m_bound_args); + } + + Function m_function; + BoundArgs m_bound_args; + Args m_args; +}; + +template<class Function, class BoundArgs, class Args> +inline meta_kernel& 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 +) +{ + return k << expr.m_function(expr.template get_nth_arg<0>()); +} + +template<class Function, class BoundArgs, class Args> +inline meta_kernel& 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 +) +{ + return k << expr.m_function(expr.template get_nth_arg<0>(), + expr.template get_nth_arg<1>()); +} + +template<class Function, class BoundArgs, class Args> +inline meta_kernel& 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 +) +{ + return k << expr.m_function(expr.template get_nth_arg<0>(), + expr.template get_nth_arg<1>(), + expr.template get_nth_arg<2>()); +} + +template<class Function, class BoundArgs, class Args> +inline meta_kernel& operator<<( + meta_kernel &k, + const invoked_bound_function<Function, BoundArgs, Args> &expr +) +{ + return apply_invoked_bound_function(k, expr); +} + +template<class Function, class BoundArgs> +struct bound_function +{ + typedef int result_type; + + bound_function(Function f, BoundArgs args) + : m_function(f), + m_args(args) + { + } + + template<class Arg1> + detail::invoked_bound_function< + Function, + BoundArgs, + boost::tuple<Arg1> + > + operator()(const Arg1 &arg1) const + { + return detail::invoked_bound_function< + Function, + BoundArgs, + boost::tuple<Arg1> + >(m_function, m_args, boost::make_tuple(arg1)); + } + + template<class Arg1, class Arg2> + detail::invoked_bound_function< + Function, + BoundArgs, + boost::tuple<Arg1, Arg2> + > + operator()(const Arg1 &arg1, const Arg2 &arg2) const + { + return detail::invoked_bound_function< + Function, + BoundArgs, + boost::tuple<Arg1, Arg2> + >(m_function, m_args, boost::make_tuple(arg1, arg2)); + } + + Function m_function; + BoundArgs m_args; +}; + +} // end detail namespace + +#if !defined(BOOST_COMPUTE_NO_VARIADIC_TEMPLATES) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED) +/// Returns a function wrapper which invokes \p f with \p args when called. +/// +/// For example, to generate a unary function object which returns \c true +/// when its argument is less than \c 7: +/// \code +/// using boost::compute::less; +/// using boost::compute::placeholders::_1; +/// +/// auto less_than_seven = boost::compute::bind(less<int>(), _1, 7); +/// \endcode +template<class F, class... Args> +inline detail::bound_function<F, boost::tuple<Args...> > +bind(F f, Args... args) +{ + typedef typename boost::tuple<Args...> ArgsTuple; + + return detail::bound_function<F, ArgsTuple>(f, boost::make_tuple(args...)); +} +#else +template<class F, class A1> +inline detail::bound_function<F, boost::tuple<A1> > +bind(F f, A1 a1) +{ + typedef typename boost::tuple<A1> Args; + + return detail::bound_function<F, Args>(f, boost::make_tuple(a1)); +} + +template<class F, class A1, class A2> +inline detail::bound_function<F, boost::tuple<A1, A2> > +bind(F f, A1 a1, A2 a2) +{ + typedef typename boost::tuple<A1, A2> Args; + + return detail::bound_function<F, Args>(f, boost::make_tuple(a1, a2)); +} + +template<class F, class A1, class A2, class A3> +inline detail::bound_function<F, boost::tuple<A1, A2, A3> > +bind(F f, A1 a1, A2 a2, A3 a3) +{ + typedef typename boost::tuple<A1, A2, A3> Args; + + return detail::bound_function<F, Args>(f, boost::make_tuple(a1, a2, a3)); +} +#endif // BOOST_COMPUTE_NO_VARIADIC_TEMPLATES + +} // end compute namespace +} // end boost namespace + +#endif // BOOST_COMPUTE_FUNCTIONAL_BIND_HPP |