Commit a1e64089 authored by Dominik Charousset's avatar Dominik Charousset

Simplify implementation of functor-based actors

parent 1613ffb2
......@@ -114,6 +114,10 @@ public:
// nop
}
inline behavior& unbox() {
return *this;
}
/// @endcond
private:
......
......@@ -46,8 +46,6 @@ class blocking_actor
: public extend<local_actor, blocking_actor>::
with<mixin::sync_sender<blocking_response_handle_tag>::impl> {
public:
class functor_based;
blocking_actor();
~blocking_actor();
......@@ -178,7 +176,7 @@ public:
void await_all_other_actors_done();
/// Implements the actor's behavior.
virtual void act() = 0;
virtual void act();
/// @cond PRIVATE
......@@ -195,41 +193,6 @@ protected:
}
};
class blocking_actor::functor_based : public blocking_actor {
public:
using act_fun = std::function<void(blocking_actor*)>;
template <class F, class... Ts>
functor_based(F f, Ts&&... xs) {
using trait = typename detail::get_callable_trait<F>::type;
using arg0 = typename detail::tl_head<typename trait::arg_types>::type;
blocking_actor* dummy = nullptr;
std::integral_constant<bool, std::is_same<arg0, blocking_actor*>::value> tk;
create(dummy, tk, f, std::forward<Ts>(xs)...);
}
void cleanup(uint32_t reason);
protected:
void act() override;
private:
void create(blocking_actor*, act_fun);
template <class Actor, typename F, class... Ts>
void create(Actor* dummy, std::true_type, F f, Ts&&... xs) {
create(dummy, std::bind(f, std::placeholders::_1, std::forward<Ts>(xs)...));
}
template <class Actor, typename F, class... Ts>
void create(Actor* dummy, std::false_type, F f, Ts&&... xs) {
std::function<void()> fun = std::bind(f, std::forward<Ts>(xs)...);
create(dummy, [fun](Actor*) { fun(); });
}
act_fun act_;
};
} // namespace caf
#endif // CAF_BLOCKING_ACTOR_HPP
......@@ -17,102 +17,91 @@
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_MIXIN_FUNCTOR_BASED_HPP
#define CAF_MIXIN_FUNCTOR_BASED_HPP
#ifndef CAF_DETAIL_INIT_FUN_FACTORY_HPP
#define CAF_DETAIL_INIT_FUN_FACTORY_HPP
namespace caf {
namespace mixin {
template <class Base, class Subtype>
class functor_based : public Base {
public:
using combined_type = functor_based;
using pointer = Base*;
#include <functional>
using make_behavior_fun = std::function<behavior(pointer)>;
#include "caf/fwd.hpp"
using void_fun = std::function<void(pointer)>;
#include "caf/detail/type_traits.hpp"
functor_based() {
// nop
}
namespace caf {
namespace detail {
template <class F, class... Ts>
functor_based(F f, Ts&&... xs) {
init(std::move(f), std::forward<Ts>(xs)...);
}
template <class Base, class F>
class init_fun_factory {
public:
using fun = std::function<behavior (local_actor*)>;
template <class F, class... Ts>
void init(F f, Ts&&... xs) {
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;
constexpr bool returns_behavior =
std::is_convertible<result_type, behavior>::value;
constexpr bool uses_first_arg = std::is_same<
typename detail::tl_head<arg_types>::type, pointer>::value;
constexpr bool uses_first_arg = std::is_pointer<
typename detail::tl_head<arg_types>::type>::value;
std::integral_constant<bool, returns_behavior> token1;
std::integral_constant<bool, uses_first_arg> token2;
set(token1, token2, std::move(f), std::forward<Ts>(xs)...);
return make(token1, token2, std::move(f), std::forward<Ts>(xs)...);
}
struct initializer {
template <class F, class... Ts>
void operator()(functor_based* thisptr, F f, Ts&&... xs) const {
thisptr->init(std::move(f), std::forward<Ts>(xs)...);
}
};
protected:
make_behavior_fun make_behavior_;
private:
template <class F>
void set(std::true_type, std::true_type, F&& fun) {
// behavior (pointer)
make_behavior_ = std::forward<F>(fun);
// behavior (pointer)
template <class Fun>
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());
};
}
template <class F>
void set(std::false_type, std::true_type, F fun) {
// void (pointer)
make_behavior_ = [fun](pointer ptr) {
fun(ptr);
// void (pointer)
template <class Fun>
fun make(std::false_type, std::true_type, Fun fun) {
return [fun](local_actor* ptr) -> behavior {
fun(static_cast<Base*>(ptr));
return behavior{};
};
}
template <class F>
void set(std::true_type, std::false_type, F fun) {
// behavior (void)
make_behavior_ = [fun](pointer) { return fun(); };
// behavior ()
template <class Fun>
fun make(std::true_type, std::false_type, Fun fun) {
return [fun](local_actor*) -> behavior {
auto res = fun();
return std::move(res.unbox());
};
}
template <class F>
void set(std::false_type, std::false_type, F fun) {
// void (void)
make_behavior_ = [fun](pointer) {
// void ()
template <class Fun>
fun make(std::false_type, std::false_type, Fun fun) {
return [fun](local_actor*) -> behavior {
fun();
return behavior{};
};
}
template <class Token, typename F, typename T0, class... Ts>
void set(Token t1, std::true_type t2, F fun, T0&& x, Ts&&... xs) {
set(t1, t2, std::bind(fun, std::placeholders::_1, std::forward<T0>(x),
std::forward<Ts>(xs)...));
template <class Token, typename T0, class... Ts>
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)...));
}
template <class Token, typename F, typename T0, class... Ts>
void set(Token t1, std::false_type t2, F fun, T0&& x, Ts&&... xs) {
set(t1, t2, std::bind(fun, std::forward<T0>(x), std::forward<Ts>(xs)...));
template <class Token, typename T0, class... Ts>
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)...));
}
};
} // namespace mixin
} // namespace detail
} // namespace caf
#endif // CAF_MIXIN_FUNCTOR_BASED_HPP
#endif // CAF_DETAIL_INIT_FUN_FACTORY_HPP
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2015 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_DETAIL_SPAWN_FWD_HPP
#define CAF_DETAIL_SPAWN_FWD_HPP
#include <functional>
#include "caf/fwd.hpp"
#include "caf/detail/type_traits.hpp"
namespace caf {
namespace detail {
/// Converts `scoped_actor` and pointers to actors to handles of type `actor`
/// but simply forwards any other argument in the same way `std::forward` does.
template <class T>
typename std::conditional<
is_convertible_to_actor<typename std::decay<T>::type>::value,
actor,
T&&
>::type
spawn_fwd(typename std::remove_reference<T>::type& arg) noexcept {
return static_cast<T&&>(arg);
}
/// Converts `scoped_actor` and pointers to actors to handles of type `actor`
/// but simply forwards any other argument in the same way `std::forward` does.
template <class T>
typename std::conditional<
is_convertible_to_actor<typename std::decay<T>::type>::value,
actor,
T&&
>::type
spawn_fwd(typename std::remove_reference<T>::type&& arg) noexcept {
static_assert(! std::is_lvalue_reference<T>::value,
"silently converting an lvalue to an rvalue");
return static_cast<T&&>(arg);
}
} // namespace detail
} // namespace caf
#endif // CAF_DETAIL_SPAWN_FWD_HPP
......@@ -28,8 +28,6 @@
#include "caf/response_handle.hpp"
#include "caf/abstract_event_based_actor.hpp"
#include "caf/mixin/functor_based.hpp"
#include "caf/detail/logging.hpp"
namespace caf {
......@@ -48,26 +46,11 @@ public:
~event_based_actor();
class functor_based;
void initialize() override;
protected:
/// Returns the initial actor behavior.
virtual behavior make_behavior() = 0;
};
/// Implicitly used whenever spawning a cooperatively scheduled actor
/// using a function of function object.
/// @extends event_based_actor
class event_based_actor::functor_based : public extend<event_based_actor>::
with<mixin::functor_based> {
public:
template <class... Ts>
functor_based(Ts&&... xs) : combined_type(std::forward<Ts>(xs)...) {
// nop
}
behavior make_behavior() override;
virtual behavior make_behavior();
};
} // namespace caf
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2015 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_EXPERIMENTAL_STATEFUL_ACTOR_HPP
#define CAF_EXPERIMENTAL_STATEFUL_ACTOR_HPP
#include "caf/event_based_actor.hpp"
namespace caf {
namespace experimental {
template <class State>
class stateful_actor : public event_based_actor {
};
} // namespace experimental
} // namespace caf
......@@ -562,6 +562,10 @@ public:
bool invoke_from_cache(behavior&, message_id);
inline void initial_behavior_fac(std::function<behavior (local_actor*)> fun) {
initial_behavior_fac_ = std::move(fun);
}
protected:
void do_become(behavior bhvr, bool discard_old);
......@@ -590,6 +594,9 @@ protected:
// used by both event-based and blocking actors
mailbox_type mailbox_;
// used by functor-based actors to implemented make_behavior() or act()
std::function<behavior (local_actor*)> initial_behavior_fac_;
/// @endcond
private:
......
......@@ -114,6 +114,14 @@ public:
return tmp.as_behavior_impl();
}
/// @cond PRIVATE
inline message_handler& unbox() {
return *this;
}
/// @endcond
private:
impl_ptr impl_;
};
......
......@@ -23,13 +23,16 @@
#include <type_traits>
#include "caf/spawn_fwd.hpp"
#include "caf/message_id.hpp"
#include "caf/typed_actor.hpp"
#include "caf/make_counted.hpp"
#include "caf/spawn_options.hpp"
#include "caf/typed_event_based_actor.hpp"
#include "caf/detail/logging.hpp"
#include "caf/detail/spawn_fwd.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/detail/init_fun_factory.hpp"
#include "caf/detail/typed_actor_util.hpp"
#include "caf/detail/implicit_conversions.hpp"
......@@ -65,40 +68,14 @@ intrusive_ptr<C> spawn_impl(execution_unit* host,
return ptr;
}
/// Converts `scoped_actor` and pointers to actors to handles of type `actor`
/// but simply forwards any other argument in the same way `std::forward` does.
template <class T>
typename std::conditional<
is_convertible_to_actor<typename std::decay<T>::type>::value,
actor,
T&&
>::type
spawn_fwd(typename std::remove_reference<T>::type& arg) noexcept {
return static_cast<T&&>(arg);
}
/// Converts `scoped_actor` and pointers to actors to handles of type `actor`
/// but simply forwards any other argument in the same way `std::forward` does.
template <class T>
typename std::conditional<
is_convertible_to_actor<typename std::decay<T>::type>::value,
actor,
T&&
>::type
spawn_fwd(typename std::remove_reference<T>::type&& arg) noexcept {
static_assert(! std::is_lvalue_reference<T>::value,
"silently converting an lvalue to an rvalue");
return static_cast<T&&>(arg);
}
/// Called by `spawn` when used to create a class-based actor (usually
/// should not be called by users of the library). This function
/// simply forwards its arguments to `spawn_impl` using `spawn_fwd`.
/// simply forwards its arguments to `spawn_impl` using `detail::spawn_fwd`.
template <class C, spawn_options Os, typename BeforeLaunch, class... Ts>
intrusive_ptr<C> spawn_class(execution_unit* host,
BeforeLaunch before_launch_fun, Ts&&... xs) {
return spawn_impl<C, Os>(host, before_launch_fun,
spawn_fwd<Ts>(xs)...);
detail::spawn_fwd<Ts>(xs)...);
}
/// Called by `spawn` when used to create a functor-based actor (usually
......@@ -127,8 +104,13 @@ actor spawn_functor(execution_unit* eu, BeforeLaunch cb, F fun, Ts&&... xs) {
static_assert(! has_blocking_base || has_blocking_api_flag(Os),
"non-blocking functor-based actors "
"cannot be spawned using the blocking_api flag");
using impl_class = typename base_class::functor_based;
return spawn_class<impl_class, Os>(eu, cb, fun, std::forward<Ts>(xs)...);
detail::init_fun_factory<base_class, F> fac;
auto init = fac(std::move(fun), std::forward<Ts>(xs)...);
auto bl = [&](base_class* ptr) {
cb(ptr);
ptr->initial_behavior_fac(std::move(init));
};
return spawn_class<base_class, Os>(eu, bl);
}
/// @ingroup ActorCreation
......@@ -208,91 +190,6 @@ actor spawn_in_group(const group& grp, Ts&&... xs) {
return spawn_in_groups<Os>({grp}, std::forward<Ts>(xs)...);
}
/// Base class for strongly typed actors using a functor-based implementation.
template <class... Sigs>
class functor_based_typed_actor : public typed_event_based_actor<Sigs...> {
public:
/// Base class for actors using given interface.
using base = typed_event_based_actor<Sigs...>;
/// Pointer to the base class.
using pointer = base*;
/// Behavior with proper type information.
using behavior_type = typename base::behavior_type;
/// First valid functor signature.
using no_arg_fun = std::function<behavior_type()>;
/// Second valid functor signature.
using one_arg_fun1 = std::function<behavior_type(pointer)>;
/// Third (and last) valid functor signature.
using one_arg_fun2 = std::function<void(pointer)>;
/// Creates a new instance from given functor, binding `xs...`
/// to the functor.
template <class F, class... Ts>
functor_based_typed_actor(F fun, Ts&&... xs) {
using trait = typename detail::get_callable_trait<F>::type;
using arg_types = typename trait::arg_types;
using result_type = typename trait::result_type;
constexpr bool returns_behavior =
std::is_same<result_type, behavior_type>::value;
constexpr bool uses_first_arg = std::is_same<
typename detail::tl_head<arg_types>::type, pointer>::value;
std::integral_constant<bool, returns_behavior> token1;
std::integral_constant<bool, uses_first_arg> token2;
set(token1, token2, std::move(fun), std::forward<Ts>(xs)...);
}
protected:
behavior_type make_behavior() override {
return fun_(this);
}
private:
template <class F>
void set(std::true_type, std::true_type, F&& fun) {
// behavior_type (pointer)
fun_ = std::forward<F>(fun);
}
template <class F>
void set(std::false_type, std::true_type, F fun) {
// void (pointer)
fun_ = [fun](pointer ptr) {
fun(ptr);
return behavior_type{};
};
}
template <class F>
void set(std::true_type, std::false_type, F fun) {
// behavior_type ()
fun_ = [fun](pointer) { return fun(); };
}
// (false_type, false_type) is an invalid functor for typed actors
template <class Token, typename F, typename T0, class... Ts>
void set(Token t1, std::true_type t2, F fun, T0&& arg0, Ts&&... xs) {
set(t1, t2,
std::bind(fun, std::placeholders::_1, std::forward<T0>(arg0),
std::forward<Ts>(xs)...));
}
template <class Token, typename F, typename T0, class... Ts>
void set(Token t1, std::false_type t2, F fun, T0&& arg0, Ts&&... xs) {
set(t1, t2,
std::bind(fun, std::forward<T0>(arg0), std::forward<Ts>(xs)...));
}
// we convert any of the three accepted signatures to this one
one_arg_fun1 fun_;
};
/// Infers the appropriate base class for a functor-based typed actor
/// from the result and the first argument of the functor.
template <class Result, class FirstArg>
......@@ -300,12 +197,12 @@ struct infer_typed_actor_base;
template <class... Sigs, class FirstArg>
struct infer_typed_actor_base<typed_behavior<Sigs...>, FirstArg> {
using type = functor_based_typed_actor<Sigs...>;
using type = typed_event_based_actor<Sigs...>;
};
template <class... Sigs>
struct infer_typed_actor_base<void, typed_event_based_actor<Sigs...>*> {
using type = functor_based_typed_actor<Sigs...>;
using type = typed_event_based_actor<Sigs...>;
};
/// Returns a new typed actor of type `C` using `xs...` as
......@@ -325,7 +222,7 @@ typename infer_typed_actor_handle<
typename detail::get_callable_trait<F>::arg_types
>::type
>::type
spawn_typed_functor(execution_unit* eu, BeforeLaunch bl, F fun, Ts&&... xs) {
spawn_typed_functor(execution_unit* eu, BeforeLaunch cb, F fun, Ts&&... xs) {
using impl =
typename infer_typed_actor_base<
typename detail::get_callable_trait<F>::result_type,
......@@ -333,7 +230,13 @@ spawn_typed_functor(execution_unit* eu, BeforeLaunch bl, F fun, Ts&&... xs) {
typename detail::get_callable_trait<F>::arg_types
>::type
>::type;
return spawn_class<impl, Os>(eu, bl, fun, std::forward<Ts>(xs)...);
detail::init_fun_factory<impl, F> fac;
auto init = fac(std::move(fun), std::forward<Ts>(xs)...);
auto bl = [&](impl* ptr) {
cb(ptr);
ptr->initial_behavior_fac(std::move(init));
};
return spawn_class<impl, Os>(eu, bl);
}
/// Returns a new typed actor from a functor. The first element
......
......@@ -30,9 +30,6 @@
namespace caf {
template <class... Sigs>
class functor_based_typed_actor;
namespace detail {
// converts a list of replies_to<...>::with<...> elements to a list of
......@@ -173,9 +170,6 @@ public:
template <class, class, class>
friend class mixin::behavior_stack_based_impl;
template <class...>
friend class functor_based_typed_actor;
typed_behavior(typed_behavior&&) = default;
typed_behavior(const typed_behavior&) = default;
typed_behavior& operator=(typed_behavior&&) = default;
......@@ -209,6 +203,10 @@ public:
return bhvr_;
}
static typed_behavior make_empty_behavior() {
return {};
}
/// @endcond
private:
......
......@@ -124,7 +124,15 @@ public:
}
protected:
virtual behavior_type make_behavior() = 0;
virtual behavior_type make_behavior() {
if (this->initial_behavior_fac_) {
auto bhvr = this->initial_behavior_fac_(this);
this->initial_behavior_fac_ = nullptr;
if (bhvr)
this->do_become(std::move(bhvr), true);
}
return behavior_type::make_empty_behavior();
}
};
} // namespace caf
......
......@@ -38,18 +38,10 @@ void blocking_actor::await_all_other_actors_done() {
detail::singletons::get_actor_registry()->await_running_count_equal(1);
}
void blocking_actor::functor_based::create(blocking_actor*, act_fun fun) {
act_ = fun;
}
void blocking_actor::functor_based::act() {
void blocking_actor::act() {
CAF_LOG_TRACE("");
act_(this);
}
void blocking_actor::functor_based::cleanup(uint32_t reason) {
act_ = nullptr;
blocking_actor::cleanup(reason);
if (initial_behavior_fac_)
initial_behavior_fac_(this);
}
void blocking_actor::initialize() {
......
......@@ -46,12 +46,12 @@ void event_based_actor::initialize() {
}
}
behavior event_based_actor::functor_based::make_behavior() {
auto res = make_behavior_(this);
// reset make_behavior_fun to get rid of any
// references held by the function object
make_behavior_fun tmp;
make_behavior_.swap(tmp);
behavior event_based_actor::make_behavior() {
behavior res;
if (initial_behavior_fac_) {
res = initial_behavior_fac_(this);
initial_behavior_fac_ = nullptr;
}
return res;
}
......
......@@ -27,8 +27,6 @@
#include "caf/extend.hpp"
#include "caf/local_actor.hpp"
#include "caf/mixin/functor_based.hpp"
#include "caf/detail/intrusive_partitioned_list.hpp"
#include "caf/io/fwd.hpp"
......@@ -273,8 +271,6 @@ public:
/// Checks whether an acceptor for `handle` exists.
bool valid(accept_handle handle);
class functor_based;
void launch(execution_unit* eu, bool lazy, bool hide);
void cleanup(uint32_t reason);
......@@ -299,7 +295,7 @@ protected:
broker(middleman& parent_ref);
virtual behavior make_behavior() = 0;
virtual behavior make_behavior();
/// Can be overridden to perform cleanup code before the
/// broker closes all its connections.
......@@ -344,21 +340,6 @@ private:
detail::intrusive_partitioned_list<mailbox_element, detail::disposer> cache_;
};
class broker::functor_based : public extend<broker>::
with<mixin::functor_based> {
public:
using super = combined_type;
template <class... Ts>
functor_based(Ts&&... xs) : super(std::forward<Ts>(xs)...) {
// nop
}
~functor_based();
behavior make_behavior() override;
};
} // namespace io
} // namespace caf
......
......@@ -27,6 +27,7 @@
#include "caf/io/broker.hpp"
#include "caf/io/middleman.hpp"
#include "caf/mailbox_element.hpp"
#include "caf/io/connection_handle.hpp"
#include "caf/io/network/native_socket.hpp"
......@@ -38,7 +39,12 @@ namespace io {
template <spawn_options Os = no_spawn_options,
typename F = std::function<void(broker*)>, class... Ts>
actor spawn_io(F fun, Ts&&... xs) {
return spawn<broker::functor_based>(std::move(fun), std::forward<Ts>(xs)...);
detail::init_fun_factory<broker, F> fac;
auto init = fac(std::move(fun), std::forward<Ts>(xs)...);
auto bl = [&](broker* ptr) {
ptr->initial_behavior_fac(std::move(init));
};
return spawn_class<broker>(nullptr, bl);
}
/// Spawns a new functor-based broker connecting to `host:port.
......@@ -46,42 +52,32 @@ template <spawn_options Os = no_spawn_options,
typename F = std::function<void(broker*)>, class... Ts>
actor spawn_io_client(F fun, const std::string& host,
uint16_t port, Ts&&... xs) {
// provoke compiler error early
using fun_res = decltype(fun(static_cast<broker*>(nullptr),
connection_handle{},
std::forward<Ts>(xs)...));
// prevent warning about unused local type
static_assert(std::is_same<fun_res, fun_res>::value,
"your compiler is lying to you");
// works around an issue with GCC 4.8 that could not handle
// variadic template parameter packs inside lambdas
auto args = std::forward_as_tuple(std::forward<Ts>(xs)...);
return spawn_class<broker::functor_based>(
nullptr,
[&](broker::functor_based* ptr) {
auto mm = middleman::instance();
auto hdl = mm->backend().add_tcp_scribe(ptr, host, port);
broker::functor_based::initializer init;
detail::apply_args_prefixed(init, detail::get_indices(args), args,
ptr, std::move(fun), std::move(hdl));
});
auto bl = [&](broker* ptr) {
auto mm = middleman::instance();
auto hdl = mm->backend().add_tcp_scribe(ptr, host, port);
detail::init_fun_factory<broker, F> fac;
auto init = detail::apply_args_prefixed(fac, detail::get_indices(args),
args, std::move(fun), hdl);
ptr->initial_behavior_fac(std::move(init));
};
return spawn_class<broker>(nullptr, bl);
}
/// Spawns a new broker as server running on given `port`.
template <spawn_options Os = no_spawn_options,
class F = std::function<void(broker*)>, class... Ts>
actor spawn_io_server(F fun, uint16_t port, Ts&&... xs) {
// same workaround as above
auto args = std::forward_as_tuple(std::forward<Ts>(xs)...);
return spawn_class<broker::functor_based>(
nullptr,
[&](broker::functor_based* ptr) {
auto mm = middleman::instance();
mm->backend().add_tcp_doorman(ptr, port);
broker::functor_based::initializer init;
detail::apply_args_prefixed(init, detail::get_indices(args), args,
ptr, std::move(fun));
});
detail::init_fun_factory<broker, F> fac;
auto init = fac(std::move(fun), std::forward<Ts>(xs)...);
auto bl = [&](broker* ptr) {
auto mm = middleman::instance();
mm->backend().add_tcp_doorman(ptr, port);
ptr->initial_behavior_fac(std::move(init));
};
return spawn_class<broker>(nullptr, bl);
}
} // namespace io
......
......@@ -276,6 +276,15 @@ void broker::cleanup(uint32_t reason) {
deref(); // release implicit reference count from middleman
}
behavior broker::make_behavior() {
behavior res;
if (initial_behavior_fac_) {
res = initial_behavior_fac_(this);
initial_behavior_fac_ = nullptr;
}
return res;
}
void broker::on_exit() {
// nop
}
......@@ -366,14 +375,6 @@ void broker::initialize() {
// nop
}
broker::functor_based::~functor_based() {
// nop
}
behavior broker::functor_based::make_behavior() {
return make_behavior_(this);
}
network::multiplexer& broker::backend() {
return mm_.backend();
}
......
......@@ -97,11 +97,13 @@ size_t pongs() {
}
void event_based_ping(event_based_actor* self, size_t ping_msgs) {
printf("event_based_ping\n");
s_pongs = 0;
self->become(ping_behavior(self, ping_msgs));
}
void pong(blocking_actor* self, actor ping_actor) {
printf("event_based_pong\n");
self->send(ping_actor, pong_atom::value, 0); // kickoff
self->receive_loop(pong_behavior(self));
}
......@@ -462,7 +464,7 @@ void test_remote_actor(const char* app_path, bool run_remote_actor) {
"--", "-c", port2, "-c", port1, "-g", gport);
} else {
CAF_MESSAGE("please run client with: "
<< "-c " << port2 << " " << port1 << " " << gport);
<< "-c " << port2 << " -c " << port1 << " -g " << gport);
}
self->receive(
[&](const down_msg& dm) {
......
......@@ -59,7 +59,7 @@ using client_type = typed_actor<>;
server_type::behavior_type server() {
return {
[](const ping & p) -> pong {
CAF_MESSAGE("received `ping`");
CAF_CHECK_EQUAL(p.value, 42);
return pong{p.value};
}
};
......
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