262 lines
7.3 KiB
C++
262 lines
7.3 KiB
C++
|
//---------------------------------------------------------------------------//
|
||
|
// 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
|