Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use a lightweight bind implementation when no placeholders are given #2116

Merged
merged 4 commits into from Apr 30, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 6 additions & 1 deletion hpx/traits/is_bind_expression.hpp
Expand Up @@ -24,6 +24,11 @@ namespace hpx { namespace traits
: boost::false_type
#endif
{};

template <typename T>
struct is_bind_expression<T const>
: is_bind_expression<T>
{};
}}

#endif
#endif /*HPX_TRAITS_IS_BIND_EXPRESSION_HPP*/
7 changes: 6 additions & 1 deletion hpx/traits/is_placeholder.hpp
Expand Up @@ -30,6 +30,11 @@ namespace hpx { namespace traits
: boost::is_placeholder<T>
#endif
{};

template <typename T>
struct is_placeholder<T const>
: is_placeholder<T>
{};
}}

#endif
#endif /*HPX_TRAITS_IS_PLACEHOLDER_HPP*/
171 changes: 95 additions & 76 deletions hpx/util/bind.hpp
@@ -1,5 +1,5 @@
// Copyright (c) 2011-2012 Thomas Heller
// Copyright (c) 2013-2015 Agustin Berge
// Copyright (c) 2013-2016 Agustin Berge
//
// 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)
Expand All @@ -21,9 +21,7 @@
#include <hpx/util/detail/pack.hpp>

#include <boost/type_traits/integral_constant.hpp>
#include <boost/ref.hpp>

#include <functional>
#include <type_traits>
#include <utility>

Expand Down Expand Up @@ -84,27 +82,27 @@ namespace hpx { namespace util
static HPX_FORCEINLINE
type call(T& t, Us&& /*unbound*/)
{
return std::move(t);
return std::forward<T>(t);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agustin, why is std::forward used here (when t is not forwarding reference)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

T is a forwarding reference in this context, it will be an lvalue-reference when the bound argument is a reference_wrapper.

}
};

template <
typename F, typename T, typename TD, typename Us,
typename F, typename T, typename Us,
typename Enable = void
>
struct bind_eval_impl
: bind_eval_bound_impl<F, T>
{};

template <
std::size_t I, typename T, typename Us,
std::size_t I, typename Us,
typename Enable = void
>
struct bind_eval_placeholder_impl
{};

template <std::size_t I, typename T, typename Us>
struct bind_eval_placeholder_impl<I, T, Us,
template <std::size_t I, typename Us>
struct bind_eval_placeholder_impl<I, Us,
typename std::enable_if<
(I < util::tuple_size<Us>::value)
>::type
Expand All @@ -114,28 +112,28 @@ namespace hpx { namespace util
I, typename util::decay<Us>::type
>::type&& type;

template <typename T>
static HPX_FORCEINLINE
type call(T /*t*/, Us&& unbound)
type call(T&& /*t*/, Us&& unbound)
{
return util::get<I>(std::forward<Us>(unbound));
}
};

template <typename F, typename T, typename TD, typename Us>
struct bind_eval_impl<F, T, TD, Us,
template <typename F, typename T, typename Us>
struct bind_eval_impl<F, T, Us,
typename std::enable_if<
traits::is_placeholder<TD>::value != 0
traits::is_placeholder<T>::value != 0
>::type
> : bind_eval_placeholder_impl<
static_cast<std::size_t>(traits::is_placeholder<TD>::value - 1),
T, Us
(std::size_t)traits::is_placeholder<T>::value - 1, Us
>
{};

template <typename F, typename T, typename TD, typename Us>
struct bind_eval_impl<F, T, TD, Us,
template <typename F, typename T, typename Us>
struct bind_eval_impl<F, T, Us,
typename std::enable_if<
traits::is_bind_expression<TD>::value
traits::is_bind_expression<T>::value
>::type
>
{
Expand All @@ -146,90 +144,111 @@ namespace hpx { namespace util
static HPX_FORCEINLINE
type call(T& t, Us&& unbound)
{
return util::invoke_fused(
t, std::forward<Us>(unbound));
}
};

template <typename F, typename T, typename X, typename Us>
struct bind_eval_impl<F, T, ::boost::reference_wrapper<X>, Us>
{
typedef X& type;

static HPX_FORCEINLINE
type call(T& t, Us&& /*unbound*/)
{
return t.get();
return util::invoke_fused(t, std::forward<Us>(unbound));
}
};

#if defined(HPX_HAVE_CXX11_STD_REFERENCE_WRAPPER)
template <typename F, typename T, typename X, typename Us>
struct bind_eval_impl<F, T, ::std::reference_wrapper<X>, Us>
{
typedef X& type;

static HPX_FORCEINLINE
type call(T& t, Us&& /*unbound*/)
{
return t.get();
}
};
#endif

template <typename F, typename T, typename Us>
HPX_FORCEINLINE
typename bind_eval_impl<F, T, typename std::decay<T>::type, Us>::type
typename bind_eval_impl<F, T, Us>::type
bind_eval(T& t, Us&& unbound)
{
return bind_eval_impl<F, T, typename std::decay<T>::type, Us>::call(
t, std::forward<Us>(unbound));
return bind_eval_impl<F, T, Us>::call(
t, std::forward<Us>(unbound));
}

///////////////////////////////////////////////////////////////////////
template <typename Ts>
struct is_simple_bind;

template <typename ...Ts>
struct is_simple_bind<util::tuple<Ts...> >
: detail::none_of<
traits::is_placeholder<Ts>...,
traits::is_bind_expression<Ts>...
>
{};

template <typename ...Ts>
struct is_simple_bind<util::tuple<Ts...> const>
: is_simple_bind<util::tuple<Ts const...> >
{};

///////////////////////////////////////////////////////////////////////
template <typename F, typename Ts, typename Us>
struct bound_result_of;
struct bound_result_of_impl;

template <typename F, typename ...Ts, typename Us>
struct bound_result_of<
F, util::tuple<Ts...>, Us
> : util::result_of<
F(typename bind_eval_impl<
F, Ts, typename std::decay<Ts>::type, Us
>::type&&...)
struct bound_result_of_impl<F, util::tuple<Ts...>, Us>
: util::result_of<
F&(typename bind_eval_impl<F, Ts, Us>::type&&...)
>
{};

template <typename F, typename ...Ts, typename Us>
struct bound_result_of<
F, util::tuple<Ts...> const, Us
> : util::result_of<
F(typename bind_eval_impl<
F, Ts const, typename std::decay<Ts>::type, Us
>::type&&...)
>
template <typename F, typename Ts>
struct bound_result_of_simple_impl;

template <typename F, typename ...Ts>
struct bound_result_of_simple_impl<F, util::tuple<Ts...> >
: util::result_of<F&(Ts&...)>
{};

template <typename F, typename ...Ts>
struct bound_result_of_simple_impl<one_shot_wrapper<F>, util::tuple<Ts...> >
: util::result_of<F&&(Ts&&...)>
{};

///////////////////////////////////////////////////////////////////////
template <typename F, typename Ts, typename Us>
struct bound_result_of
: std::conditional<
!detail::is_simple_bind<Ts>::value,
bound_result_of_impl<F, Ts, Us>,
bound_result_of_simple_impl<F, Ts>
>::type
{};

template <typename F, typename ...Ts, typename Us>
struct bound_result_of<
one_shot_wrapper<F> const, util::tuple<Ts...>, Us
>
struct bound_result_of<F, util::tuple<Ts...> const, Us>
: bound_result_of<F, util::tuple<Ts const...>, Us>
{};

template <typename F, typename ...Ts, typename Us>
struct bound_result_of<
one_shot_wrapper<F> const, util::tuple<Ts...> const, Us
>
{};
one_shot_wrapper<F> const, util::tuple<Ts...> const, Us>
{}; // one-shot wrapper is not const callable

///////////////////////////////////////////////////////////////////////
template <typename F, typename Ts, typename Us, std::size_t ...Is>
typename bound_result_of<F, Ts, Us>::type
bound_impl(F& f, Ts& bound, Us&& unbound,
typename std::enable_if<
!detail::is_simple_bind<Ts>::value,
typename bound_result_of<F, Ts, Us>::type
>::type bound_impl(F& f, Ts& bound, Us&& unbound,
pack_c<std::size_t, Is...>)
{
return util::invoke(f,
detail::bind_eval<F, typename util::tuple_element<Is, Ts>::type>(
util::get<Is>(bound), std::forward<Us>(unbound))...);
}

template <typename F, typename Ts, typename Us, std::size_t ...Is>
typename std::enable_if<
detail::is_simple_bind<Ts>::value,
typename bound_result_of<F, Ts, Us>::type
>::type bound_impl(F& f, Ts& bound, Us&& /*unbound*/,
pack_c<std::size_t, Is...>)
{
return util::invoke(f, util::get<Is>(bound)...);
}

template <typename F, typename Ts, typename Us, std::size_t ...Is>
typename std::enable_if<
detail::is_simple_bind<Ts>::value,
typename bound_result_of<one_shot_wrapper<F>, Ts, Us>::type
>::type bound_impl(one_shot_wrapper<F>& f, Ts& bound, Us&& /*unbound*/,
pack_c<std::size_t, Is...>)
{
return util::invoke(f, detail::bind_eval<F>(
util::get<Is>(bound), std::forward<Us>(unbound))...);
return util::invoke(std::move(f), util::get<Is>(std::move(bound))...);
}

template <typename T>
Expand Down Expand Up @@ -267,7 +286,7 @@ namespace hpx { namespace util
template <typename ...Us>
inline typename bound_result_of<
typename std::decay<F>::type,
util::tuple<typename std::decay<Ts>::type...>,
util::tuple<typename util::decay_unwrap<Ts>::type...>,
util::tuple<Us&&...>
>::type operator()(Us&&... vs)
{
Expand All @@ -279,7 +298,7 @@ namespace hpx { namespace util
template <typename ...Us>
inline typename bound_result_of<
typename std::decay<F>::type const,
util::tuple<typename std::decay<Ts>::type const...>,
util::tuple<typename util::decay_unwrap<Ts>::type...> const,
util::tuple<Us&&...>
>::type operator()(Us&&... vs) const
{
Expand All @@ -304,7 +323,7 @@ namespace hpx { namespace util

private:
typename std::decay<F>::type _f;
util::tuple<typename std::decay<Ts>::type...> _args;
util::tuple<typename util::decay_unwrap<Ts>::type...> _args;
};
}

Expand Down