Commit 702041e6 authored by Dominik Charousset's avatar Dominik Charousset

Support move-only types in spawn, close #348

parent a9878bbc
Subproject commit 28a6b04ea653a80724517c570c9ae8325b90cf52
Subproject commit 2c45d8c1c2b934e062baf378809201ac66d169a7
......@@ -52,6 +52,18 @@ auto apply_args_prefixed(F& f, detail::int_list<Is...>, Tuple& tup, Ts&&... xs)
return f(std::forward<Ts>(xs)..., get<Is>(tup)...);
}
template <class F, class Tuple, class... Ts>
auto apply_moved_args_prefixed(F& f, detail::int_list<>, Tuple&, Ts&&... xs)
-> decltype(f(std::forward<Ts>(xs)...)) {
return f(std::forward<Ts>(xs)...);
}
template <class F, long... Is, class Tuple, class... Ts>
auto apply_moved_args_prefixed(F& f, detail::int_list<Is...>, Tuple& tup, Ts&&... xs)
-> decltype(f(std::forward<Ts>(xs)..., std::move(get<Is>(tup))...)) {
return f(std::forward<Ts>(xs)..., std::move(get<Is>(tup))...);
}
template <class F, long... Is, class Tuple, class... Ts>
auto apply_args_suffxied(F& f, detail::int_list<Is...>, Tuple& tup, Ts&&... xs)
-> decltype(f(get<Is>(tup)..., std::forward<Ts>(xs)...)) {
......
......@@ -20,81 +20,89 @@
#ifndef CAF_DETAIL_INIT_FUN_FACTORY_HPP
#define CAF_DETAIL_INIT_FUN_FACTORY_HPP
#include <tuple>
#include <functional>
#include "caf/fwd.hpp"
#include "caf/detail/apply_args.hpp"
#include "caf/detail/type_traits.hpp"
namespace caf {
namespace detail {
template <class Base, class F>
class init_fun_factory {
template <class Base, class F, class ArgsPtr,
bool ReturnsBehavior, bool HasSelfPtr>
class init_fun_factory_helper {
public:
using fun = std::function<behavior (local_actor*)>;
init_fun_factory_helper(init_fun_factory_helper&&) = default;
init_fun_factory_helper(const init_fun_factory_helper&) = default;
template <class... Ts>
fun operator()(F f, Ts&&... xs) {
static_assert(std::is_base_of<local_actor, Base>::value,
"Given Base does not extend local_actor");
using trait = typename detail::get_callable_trait<F>::type;
using arg_types = typename trait::arg_types;
using result_type = typename trait::result_type;
using first_arg = typename detail::tl_head<arg_types>::type;
bool_token<std::is_convertible<result_type, behavior>::value> token1;
bool_token<std::is_pointer<first_arg>::value> token2;
return make(token1, token2, std::move(f), std::forward<Ts>(xs)...);
init_fun_factory_helper(F fun, ArgsPtr args)
: fun_(std::move(fun)),
args_(std::move(args)) {
// nop
}
behavior operator()(local_actor* self) {
bool_token<ReturnsBehavior> returns_behavior_token;
bool_token<HasSelfPtr> captures_self_token;
return apply(returns_behavior_token, captures_self_token, self);
}
private:
// behavior (pointer)
template <class Fun>
static fun make(std::true_type, std::true_type, Fun fun) {
return [fun](local_actor* ptr) -> behavior {
auto res = fun(static_cast<Base*>(ptr));
return std::move(res.unbox());
};
behavior apply(std::true_type, std::true_type, local_actor* ptr) {
auto res = apply_moved_args_prefixed(fun_, get_indices(*args_), *args_,
static_cast<Base*>(ptr));
return std::move(res.unbox());
}
// void (pointer)
template <class Fun>
static fun make(std::false_type, std::true_type, Fun fun) {
return [fun](local_actor* ptr) -> behavior {
fun(static_cast<Base*>(ptr));
return behavior{};
};
behavior apply(std::false_type, std::true_type, local_actor* ptr) {
apply_moved_args_prefixed(fun_, get_indices(*args_),
*args_, static_cast<Base*>(ptr));
return behavior{};
}
// behavior ()
template <class Fun>
static fun make(std::true_type, std::false_type, Fun fun) {
return [fun](local_actor*) -> behavior {
auto res = fun();
return std::move(res.unbox());
};
behavior apply(std::true_type, std::false_type, local_actor*) {
auto res = apply_args(fun_, get_indices(*args_), *args_);
return std::move(res.unbox());
}
// void ()
template <class Fun>
static fun make(std::false_type, std::false_type, Fun fun) {
return [fun](local_actor*) -> behavior {
fun();
return behavior{};
};
behavior apply(std::false_type, std::false_type, local_actor*) {
apply_args(fun_, get_indices(*args_), *args_);
return behavior{};
}
template <class Token, typename T0, class... Ts>
static fun make(Token t1, std::true_type t2, F fun, T0&& x, Ts&&... xs) {
return make(t1, t2,
std::bind(fun, std::placeholders::_1, detail::spawn_fwd<T0>(x),
detail::spawn_fwd<Ts>(xs)...));
}
F fun_;
ArgsPtr args_;
};
template <class Token, typename T0, class... Ts>
static fun make(Token t1, std::false_type t2, F fun, T0&& x, Ts&&... xs) {
return make(t1, t2, std::bind(fun, detail::spawn_fwd<T0>(x),
detail::spawn_fwd<Ts>(xs)...));
template <class Base, class F>
class init_fun_factory {
public:
using fun = std::function<behavior (local_actor*)>;
template <class... Ts>
fun operator()(F f, Ts&&... xs) {
static_assert(std::is_base_of<local_actor, Base>::value,
"Given Base does not extend local_actor");
using trait = typename detail::get_callable_trait<F>::type;
using arg_types = typename trait::arg_types;
using res_type = typename trait::result_type;
using first_arg = typename detail::tl_head<arg_types>::type;
constexpr bool selfptr = std::is_pointer<first_arg>::value;
constexpr bool rets = std::is_convertible<res_type, behavior>::value;
using tuple_type = decltype(std::make_tuple(detail::spawn_fwd<Ts>(xs)...));
using tuple_ptr = std::shared_ptr<tuple_type>;
using helper = init_fun_factory_helper<Base, F, tuple_ptr, rets, selfptr>;
return helper{std::move(f),
sizeof...(Ts) > 0
? std::make_shared<tuple_type>(detail::spawn_fwd<Ts>(xs)...)
: nullptr};
}
};
......
......@@ -857,4 +857,25 @@ CAF_TEST(exit_reason_in_scoped_actor) {
self->planned_exit_reason(exit_reason::user_defined);
}
CAF_TEST(move_only_argument) {
using unique_int = std::unique_ptr<int>;
unique_int ptr{new int(42)};
auto f = [](event_based_actor* self, unique_int ptr) -> behavior {
auto i = *ptr;
return {
others >> [=] {
self->quit();
return i;
}
};
};
auto testee = spawn(f, std::move(ptr));
scoped_actor self;
self->sync_send(testee, 1.f).await(
[](int i) {
CAF_CHECK(i == 42);
}
);
}
CAF_TEST_FIXTURE_SCOPE_END()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment