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) ...@@ -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)...); 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> template <class F, long... Is, class Tuple, class... Ts>
auto apply_args_suffxied(F& f, detail::int_list<Is...>, Tuple& tup, Ts&&... xs) auto apply_args_suffxied(F& f, detail::int_list<Is...>, Tuple& tup, Ts&&... xs)
-> decltype(f(get<Is>(tup)..., std::forward<Ts>(xs)...)) { -> decltype(f(get<Is>(tup)..., std::forward<Ts>(xs)...)) {
......
...@@ -20,81 +20,89 @@ ...@@ -20,81 +20,89 @@
#ifndef CAF_DETAIL_INIT_FUN_FACTORY_HPP #ifndef CAF_DETAIL_INIT_FUN_FACTORY_HPP
#define CAF_DETAIL_INIT_FUN_FACTORY_HPP #define CAF_DETAIL_INIT_FUN_FACTORY_HPP
#include <tuple>
#include <functional> #include <functional>
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/detail/apply_args.hpp"
#include "caf/detail/type_traits.hpp" #include "caf/detail/type_traits.hpp"
namespace caf { namespace caf {
namespace detail { namespace detail {
template <class Base, class F> template <class Base, class F, class ArgsPtr,
class init_fun_factory { bool ReturnsBehavior, bool HasSelfPtr>
class init_fun_factory_helper {
public: 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> init_fun_factory_helper(F fun, ArgsPtr args)
fun operator()(F f, Ts&&... xs) { : fun_(std::move(fun)),
static_assert(std::is_base_of<local_actor, Base>::value, args_(std::move(args)) {
"Given Base does not extend local_actor"); // nop
using trait = typename detail::get_callable_trait<F>::type; }
using arg_types = typename trait::arg_types;
using result_type = typename trait::result_type; behavior operator()(local_actor* self) {
using first_arg = typename detail::tl_head<arg_types>::type; bool_token<ReturnsBehavior> returns_behavior_token;
bool_token<std::is_convertible<result_type, behavior>::value> token1; bool_token<HasSelfPtr> captures_self_token;
bool_token<std::is_pointer<first_arg>::value> token2; return apply(returns_behavior_token, captures_self_token, self);
return make(token1, token2, std::move(f), std::forward<Ts>(xs)...);
} }
private: private:
// behavior (pointer) // behavior (pointer)
template <class Fun> behavior apply(std::true_type, std::true_type, local_actor* ptr) {
static fun make(std::true_type, std::true_type, Fun fun) { auto res = apply_moved_args_prefixed(fun_, get_indices(*args_), *args_,
return [fun](local_actor* ptr) -> behavior { static_cast<Base*>(ptr));
auto res = fun(static_cast<Base*>(ptr));
return std::move(res.unbox()); return std::move(res.unbox());
};
} }
// void (pointer) // void (pointer)
template <class Fun> behavior apply(std::false_type, std::true_type, local_actor* ptr) {
static fun make(std::false_type, std::true_type, Fun fun) { apply_moved_args_prefixed(fun_, get_indices(*args_),
return [fun](local_actor* ptr) -> behavior { *args_, static_cast<Base*>(ptr));
fun(static_cast<Base*>(ptr));
return behavior{}; return behavior{};
};
} }
// behavior () // behavior ()
template <class Fun> behavior apply(std::true_type, std::false_type, local_actor*) {
static fun make(std::true_type, std::false_type, Fun fun) { auto res = apply_args(fun_, get_indices(*args_), *args_);
return [fun](local_actor*) -> behavior {
auto res = fun();
return std::move(res.unbox()); return std::move(res.unbox());
};
} }
// void () // void ()
template <class Fun> behavior apply(std::false_type, std::false_type, local_actor*) {
static fun make(std::false_type, std::false_type, Fun fun) { apply_args(fun_, get_indices(*args_), *args_);
return [fun](local_actor*) -> behavior {
fun();
return behavior{}; return behavior{};
};
} }
template <class Token, typename T0, class... Ts> F fun_;
static fun make(Token t1, std::true_type t2, F fun, T0&& x, Ts&&... xs) { ArgsPtr args_;
return make(t1, t2, };
std::bind(fun, std::placeholders::_1, detail::spawn_fwd<T0>(x),
detail::spawn_fwd<Ts>(xs)...));
}
template <class Token, typename T0, class... Ts> template <class Base, class F>
static fun make(Token t1, std::false_type t2, F fun, T0&& x, Ts&&... xs) { class init_fun_factory {
return make(t1, t2, std::bind(fun, detail::spawn_fwd<T0>(x), public:
detail::spawn_fwd<Ts>(xs)...)); 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) { ...@@ -857,4 +857,25 @@ CAF_TEST(exit_reason_in_scoped_actor) {
self->planned_exit_reason(exit_reason::user_defined); 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() 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