Commit a1e64089 authored by Dominik Charousset's avatar Dominik Charousset

Simplify implementation of functor-based actors

parent 1613ffb2
...@@ -114,6 +114,10 @@ public: ...@@ -114,6 +114,10 @@ public:
// nop // nop
} }
inline behavior& unbox() {
return *this;
}
/// @endcond /// @endcond
private: private:
......
...@@ -46,8 +46,6 @@ class blocking_actor ...@@ -46,8 +46,6 @@ class blocking_actor
: public extend<local_actor, blocking_actor>:: : public extend<local_actor, blocking_actor>::
with<mixin::sync_sender<blocking_response_handle_tag>::impl> { with<mixin::sync_sender<blocking_response_handle_tag>::impl> {
public: public:
class functor_based;
blocking_actor(); blocking_actor();
~blocking_actor(); ~blocking_actor();
...@@ -178,7 +176,7 @@ public: ...@@ -178,7 +176,7 @@ public:
void await_all_other_actors_done(); void await_all_other_actors_done();
/// Implements the actor's behavior. /// Implements the actor's behavior.
virtual void act() = 0; virtual void act();
/// @cond PRIVATE /// @cond PRIVATE
...@@ -195,41 +193,6 @@ protected: ...@@ -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 } // namespace caf
#endif // CAF_BLOCKING_ACTOR_HPP #endif // CAF_BLOCKING_ACTOR_HPP
...@@ -17,102 +17,91 @@ ...@@ -17,102 +17,91 @@
* http://www.boost.org/LICENSE_1_0.txt. * * http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/ ******************************************************************************/
#ifndef CAF_MIXIN_FUNCTOR_BASED_HPP #ifndef CAF_DETAIL_INIT_FUN_FACTORY_HPP
#define CAF_MIXIN_FUNCTOR_BASED_HPP #define CAF_DETAIL_INIT_FUN_FACTORY_HPP
namespace caf { #include <functional>
namespace mixin {
template <class Base, class Subtype>
class functor_based : public Base {
public:
using combined_type = functor_based;
using pointer = Base*;
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() { namespace caf {
// nop namespace detail {
}
template <class F, class... Ts> template <class Base, class F>
functor_based(F f, Ts&&... xs) { class init_fun_factory {
init(std::move(f), std::forward<Ts>(xs)...); public:
} using fun = std::function<behavior (local_actor*)>;
template <class F, class... Ts> template <class... Ts>
void init(F f, Ts&&... xs) { 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 trait = typename detail::get_callable_trait<F>::type;
using arg_types = typename trait::arg_types; using arg_types = typename trait::arg_types;
using result_type = typename trait::result_type; using result_type = typename trait::result_type;
constexpr bool returns_behavior = constexpr bool returns_behavior =
std::is_convertible<result_type, behavior>::value; std::is_convertible<result_type, behavior>::value;
constexpr bool uses_first_arg = std::is_same< constexpr bool uses_first_arg = std::is_pointer<
typename detail::tl_head<arg_types>::type, pointer>::value; typename detail::tl_head<arg_types>::type>::value;
std::integral_constant<bool, returns_behavior> token1; std::integral_constant<bool, returns_behavior> token1;
std::integral_constant<bool, uses_first_arg> token2; 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: private:
template <class F> // behavior (pointer)
void set(std::true_type, std::true_type, F&& fun) { template <class Fun>
// behavior (pointer) fun make(std::true_type, std::true_type, Fun fun) {
make_behavior_ = std::forward<F>(fun); return [fun](local_actor* ptr) -> behavior {
auto res = fun(static_cast<Base*>(ptr));
return std::move(res.unbox());
};
} }
template <class F> // void (pointer)
void set(std::false_type, std::true_type, F fun) { template <class Fun>
// void (pointer) fun make(std::false_type, std::true_type, Fun fun) {
make_behavior_ = [fun](pointer ptr) { return [fun](local_actor* ptr) -> behavior {
fun(ptr); fun(static_cast<Base*>(ptr));
return behavior{}; return behavior{};
}; };
} }
template <class F> // behavior ()
void set(std::true_type, std::false_type, F fun) { template <class Fun>
// behavior (void) fun make(std::true_type, std::false_type, Fun fun) {
make_behavior_ = [fun](pointer) { return fun(); }; return [fun](local_actor*) -> behavior {
auto res = fun();
return std::move(res.unbox());
};
} }
template <class F> // void ()
void set(std::false_type, std::false_type, F fun) { template <class Fun>
// void (void) fun make(std::false_type, std::false_type, Fun fun) {
make_behavior_ = [fun](pointer) { return [fun](local_actor*) -> behavior {
fun(); fun();
return behavior{}; return behavior{};
}; };
} }
template <class Token, typename F, typename T0, class... Ts> template <class Token, typename T0, class... Ts>
void set(Token t1, std::true_type t2, F fun, T0&& x, Ts&&... xs) { fun make(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), return make(t1, t2,
std::forward<Ts>(xs)...)); 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> template <class Token, typename T0, class... Ts>
void set(Token t1, std::false_type t2, F fun, T0&& x, Ts&&... xs) { fun make(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)...)); return make(t1, t2, std::bind(fun, detail::spawn_fwd<T0>(x),
detail::spawn_fwd<Ts>(xs)...));
} }
}; };
} // namespace mixin } // namespace detail
} // namespace caf } // 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 @@ ...@@ -28,8 +28,6 @@
#include "caf/response_handle.hpp" #include "caf/response_handle.hpp"
#include "caf/abstract_event_based_actor.hpp" #include "caf/abstract_event_based_actor.hpp"
#include "caf/mixin/functor_based.hpp"
#include "caf/detail/logging.hpp" #include "caf/detail/logging.hpp"
namespace caf { namespace caf {
...@@ -48,26 +46,11 @@ public: ...@@ -48,26 +46,11 @@ public:
~event_based_actor(); ~event_based_actor();
class functor_based;
void initialize() override; void initialize() override;
protected: protected:
/// Returns the initial actor behavior. /// Returns the initial actor behavior.
virtual behavior make_behavior() = 0; virtual behavior make_behavior();
};
/// 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;
}; };
} // namespace caf } // 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: ...@@ -562,6 +562,10 @@ public:
bool invoke_from_cache(behavior&, message_id); 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: protected:
void do_become(behavior bhvr, bool discard_old); void do_become(behavior bhvr, bool discard_old);
...@@ -590,6 +594,9 @@ protected: ...@@ -590,6 +594,9 @@ protected:
// used by both event-based and blocking actors // used by both event-based and blocking actors
mailbox_type mailbox_; mailbox_type mailbox_;
// used by functor-based actors to implemented make_behavior() or act()
std::function<behavior (local_actor*)> initial_behavior_fac_;
/// @endcond /// @endcond
private: private:
......
...@@ -114,6 +114,14 @@ public: ...@@ -114,6 +114,14 @@ public:
return tmp.as_behavior_impl(); return tmp.as_behavior_impl();
} }
/// @cond PRIVATE
inline message_handler& unbox() {
return *this;
}
/// @endcond
private: private:
impl_ptr impl_; impl_ptr impl_;
}; };
......
...@@ -23,13 +23,16 @@ ...@@ -23,13 +23,16 @@
#include <type_traits> #include <type_traits>
#include "caf/spawn_fwd.hpp" #include "caf/spawn_fwd.hpp"
#include "caf/message_id.hpp"
#include "caf/typed_actor.hpp" #include "caf/typed_actor.hpp"
#include "caf/make_counted.hpp" #include "caf/make_counted.hpp"
#include "caf/spawn_options.hpp" #include "caf/spawn_options.hpp"
#include "caf/typed_event_based_actor.hpp" #include "caf/typed_event_based_actor.hpp"
#include "caf/detail/logging.hpp" #include "caf/detail/logging.hpp"
#include "caf/detail/spawn_fwd.hpp"
#include "caf/detail/type_traits.hpp" #include "caf/detail/type_traits.hpp"
#include "caf/detail/init_fun_factory.hpp"
#include "caf/detail/typed_actor_util.hpp" #include "caf/detail/typed_actor_util.hpp"
#include "caf/detail/implicit_conversions.hpp" #include "caf/detail/implicit_conversions.hpp"
...@@ -65,40 +68,14 @@ intrusive_ptr<C> spawn_impl(execution_unit* host, ...@@ -65,40 +68,14 @@ intrusive_ptr<C> spawn_impl(execution_unit* host,
return ptr; 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 /// Called by `spawn` when used to create a class-based actor (usually
/// should not be called by users of the library). This function /// 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> template <class C, spawn_options Os, typename BeforeLaunch, class... Ts>
intrusive_ptr<C> spawn_class(execution_unit* host, intrusive_ptr<C> spawn_class(execution_unit* host,
BeforeLaunch before_launch_fun, Ts&&... xs) { BeforeLaunch before_launch_fun, Ts&&... xs) {
return spawn_impl<C, Os>(host, before_launch_fun, 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 /// 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) { ...@@ -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), static_assert(! has_blocking_base || has_blocking_api_flag(Os),
"non-blocking functor-based actors " "non-blocking functor-based actors "
"cannot be spawned using the blocking_api flag"); "cannot be spawned using the blocking_api flag");
using impl_class = typename base_class::functor_based; detail::init_fun_factory<base_class, F> fac;
return spawn_class<impl_class, Os>(eu, cb, fun, std::forward<Ts>(xs)...); 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 /// @ingroup ActorCreation
...@@ -208,91 +190,6 @@ actor spawn_in_group(const group& grp, Ts&&... xs) { ...@@ -208,91 +190,6 @@ actor spawn_in_group(const group& grp, Ts&&... xs) {
return spawn_in_groups<Os>({grp}, std::forward<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 /// Infers the appropriate base class for a functor-based typed actor
/// from the result and the first argument of the functor. /// from the result and the first argument of the functor.
template <class Result, class FirstArg> template <class Result, class FirstArg>
...@@ -300,12 +197,12 @@ struct infer_typed_actor_base; ...@@ -300,12 +197,12 @@ struct infer_typed_actor_base;
template <class... Sigs, class FirstArg> template <class... Sigs, class FirstArg>
struct infer_typed_actor_base<typed_behavior<Sigs...>, 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> template <class... Sigs>
struct infer_typed_actor_base<void, typed_event_based_actor<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 /// Returns a new typed actor of type `C` using `xs...` as
...@@ -325,7 +222,7 @@ typename infer_typed_actor_handle< ...@@ -325,7 +222,7 @@ typename infer_typed_actor_handle<
typename detail::get_callable_trait<F>::arg_types typename detail::get_callable_trait<F>::arg_types
>::type >::type
>::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 = using impl =
typename infer_typed_actor_base< typename infer_typed_actor_base<
typename detail::get_callable_trait<F>::result_type, typename detail::get_callable_trait<F>::result_type,
...@@ -333,7 +230,13 @@ spawn_typed_functor(execution_unit* eu, BeforeLaunch bl, F fun, Ts&&... xs) { ...@@ -333,7 +230,13 @@ spawn_typed_functor(execution_unit* eu, BeforeLaunch bl, F fun, Ts&&... xs) {
typename detail::get_callable_trait<F>::arg_types typename detail::get_callable_trait<F>::arg_types
>::type >::type
>::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 /// Returns a new typed actor from a functor. The first element
......
...@@ -30,9 +30,6 @@ ...@@ -30,9 +30,6 @@
namespace caf { namespace caf {
template <class... Sigs>
class functor_based_typed_actor;
namespace detail { namespace detail {
// converts a list of replies_to<...>::with<...> elements to a list of // converts a list of replies_to<...>::with<...> elements to a list of
...@@ -173,9 +170,6 @@ public: ...@@ -173,9 +170,6 @@ public:
template <class, class, class> template <class, class, class>
friend class mixin::behavior_stack_based_impl; friend class mixin::behavior_stack_based_impl;
template <class...>
friend class functor_based_typed_actor;
typed_behavior(typed_behavior&&) = default; typed_behavior(typed_behavior&&) = default;
typed_behavior(const typed_behavior&) = default; typed_behavior(const typed_behavior&) = default;
typed_behavior& operator=(typed_behavior&&) = default; typed_behavior& operator=(typed_behavior&&) = default;
...@@ -209,6 +203,10 @@ public: ...@@ -209,6 +203,10 @@ public:
return bhvr_; return bhvr_;
} }
static typed_behavior make_empty_behavior() {
return {};
}
/// @endcond /// @endcond
private: private:
......
...@@ -124,7 +124,15 @@ public: ...@@ -124,7 +124,15 @@ public:
} }
protected: 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 } // namespace caf
......
...@@ -38,18 +38,10 @@ void blocking_actor::await_all_other_actors_done() { ...@@ -38,18 +38,10 @@ void blocking_actor::await_all_other_actors_done() {
detail::singletons::get_actor_registry()->await_running_count_equal(1); detail::singletons::get_actor_registry()->await_running_count_equal(1);
} }
void blocking_actor::functor_based::create(blocking_actor*, act_fun fun) { void blocking_actor::act() {
act_ = fun;
}
void blocking_actor::functor_based::act() {
CAF_LOG_TRACE(""); CAF_LOG_TRACE("");
act_(this); if (initial_behavior_fac_)
} initial_behavior_fac_(this);
void blocking_actor::functor_based::cleanup(uint32_t reason) {
act_ = nullptr;
blocking_actor::cleanup(reason);
} }
void blocking_actor::initialize() { void blocking_actor::initialize() {
......
...@@ -46,12 +46,12 @@ void event_based_actor::initialize() { ...@@ -46,12 +46,12 @@ void event_based_actor::initialize() {
} }
} }
behavior event_based_actor::functor_based::make_behavior() { behavior event_based_actor::make_behavior() {
auto res = make_behavior_(this); behavior res;
// reset make_behavior_fun to get rid of any if (initial_behavior_fac_) {
// references held by the function object res = initial_behavior_fac_(this);
make_behavior_fun tmp; initial_behavior_fac_ = nullptr;
make_behavior_.swap(tmp); }
return res; return res;
} }
......
...@@ -27,8 +27,6 @@ ...@@ -27,8 +27,6 @@
#include "caf/extend.hpp" #include "caf/extend.hpp"
#include "caf/local_actor.hpp" #include "caf/local_actor.hpp"
#include "caf/mixin/functor_based.hpp"
#include "caf/detail/intrusive_partitioned_list.hpp" #include "caf/detail/intrusive_partitioned_list.hpp"
#include "caf/io/fwd.hpp" #include "caf/io/fwd.hpp"
...@@ -273,8 +271,6 @@ public: ...@@ -273,8 +271,6 @@ public:
/// Checks whether an acceptor for `handle` exists. /// Checks whether an acceptor for `handle` exists.
bool valid(accept_handle handle); bool valid(accept_handle handle);
class functor_based;
void launch(execution_unit* eu, bool lazy, bool hide); void launch(execution_unit* eu, bool lazy, bool hide);
void cleanup(uint32_t reason); void cleanup(uint32_t reason);
...@@ -299,7 +295,7 @@ protected: ...@@ -299,7 +295,7 @@ protected:
broker(middleman& parent_ref); broker(middleman& parent_ref);
virtual behavior make_behavior() = 0; virtual behavior make_behavior();
/// Can be overridden to perform cleanup code before the /// Can be overridden to perform cleanup code before the
/// broker closes all its connections. /// broker closes all its connections.
...@@ -344,21 +340,6 @@ private: ...@@ -344,21 +340,6 @@ private:
detail::intrusive_partitioned_list<mailbox_element, detail::disposer> cache_; 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 io
} // namespace caf } // namespace caf
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "caf/io/broker.hpp" #include "caf/io/broker.hpp"
#include "caf/io/middleman.hpp" #include "caf/io/middleman.hpp"
#include "caf/mailbox_element.hpp"
#include "caf/io/connection_handle.hpp" #include "caf/io/connection_handle.hpp"
#include "caf/io/network/native_socket.hpp" #include "caf/io/network/native_socket.hpp"
...@@ -38,7 +39,12 @@ namespace io { ...@@ -38,7 +39,12 @@ namespace io {
template <spawn_options Os = no_spawn_options, template <spawn_options Os = no_spawn_options,
typename F = std::function<void(broker*)>, class... Ts> typename F = std::function<void(broker*)>, class... Ts>
actor spawn_io(F fun, Ts&&... xs) { 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. /// Spawns a new functor-based broker connecting to `host:port.
...@@ -46,42 +52,32 @@ template <spawn_options Os = no_spawn_options, ...@@ -46,42 +52,32 @@ template <spawn_options Os = no_spawn_options,
typename F = std::function<void(broker*)>, class... Ts> typename F = std::function<void(broker*)>, class... Ts>
actor spawn_io_client(F fun, const std::string& host, actor spawn_io_client(F fun, const std::string& host,
uint16_t port, Ts&&... xs) { 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 // works around an issue with GCC 4.8 that could not handle
// variadic template parameter packs inside lambdas // variadic template parameter packs inside lambdas
auto args = std::forward_as_tuple(std::forward<Ts>(xs)...); auto args = std::forward_as_tuple(std::forward<Ts>(xs)...);
return spawn_class<broker::functor_based>( auto bl = [&](broker* ptr) {
nullptr, auto mm = middleman::instance();
[&](broker::functor_based* ptr) { auto hdl = mm->backend().add_tcp_scribe(ptr, host, port);
auto mm = middleman::instance(); detail::init_fun_factory<broker, F> fac;
auto hdl = mm->backend().add_tcp_scribe(ptr, host, port); auto init = detail::apply_args_prefixed(fac, detail::get_indices(args),
broker::functor_based::initializer init; args, std::move(fun), hdl);
detail::apply_args_prefixed(init, detail::get_indices(args), args, ptr->initial_behavior_fac(std::move(init));
ptr, std::move(fun), std::move(hdl)); };
}); return spawn_class<broker>(nullptr, bl);
} }
/// Spawns a new broker as server running on given `port`. /// Spawns a new broker as server running on given `port`.
template <spawn_options Os = no_spawn_options, template <spawn_options Os = no_spawn_options,
class F = std::function<void(broker*)>, class... Ts> class F = std::function<void(broker*)>, class... Ts>
actor spawn_io_server(F fun, uint16_t port, Ts&&... xs) { actor spawn_io_server(F fun, uint16_t port, Ts&&... xs) {
// same workaround as above detail::init_fun_factory<broker, F> fac;
auto args = std::forward_as_tuple(std::forward<Ts>(xs)...); auto init = fac(std::move(fun), std::forward<Ts>(xs)...);
return spawn_class<broker::functor_based>( auto bl = [&](broker* ptr) {
nullptr, auto mm = middleman::instance();
[&](broker::functor_based* ptr) { mm->backend().add_tcp_doorman(ptr, port);
auto mm = middleman::instance(); ptr->initial_behavior_fac(std::move(init));
mm->backend().add_tcp_doorman(ptr, port); };
broker::functor_based::initializer init; return spawn_class<broker>(nullptr, bl);
detail::apply_args_prefixed(init, detail::get_indices(args), args,
ptr, std::move(fun));
});
} }
} // namespace io } // namespace io
......
...@@ -276,6 +276,15 @@ void broker::cleanup(uint32_t reason) { ...@@ -276,6 +276,15 @@ void broker::cleanup(uint32_t reason) {
deref(); // release implicit reference count from middleman 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() { void broker::on_exit() {
// nop // nop
} }
...@@ -366,14 +375,6 @@ void broker::initialize() { ...@@ -366,14 +375,6 @@ void broker::initialize() {
// nop // nop
} }
broker::functor_based::~functor_based() {
// nop
}
behavior broker::functor_based::make_behavior() {
return make_behavior_(this);
}
network::multiplexer& broker::backend() { network::multiplexer& broker::backend() {
return mm_.backend(); return mm_.backend();
} }
......
...@@ -97,11 +97,13 @@ size_t pongs() { ...@@ -97,11 +97,13 @@ size_t pongs() {
} }
void event_based_ping(event_based_actor* self, size_t ping_msgs) { void event_based_ping(event_based_actor* self, size_t ping_msgs) {
printf("event_based_ping\n");
s_pongs = 0; s_pongs = 0;
self->become(ping_behavior(self, ping_msgs)); self->become(ping_behavior(self, ping_msgs));
} }
void pong(blocking_actor* self, actor ping_actor) { void pong(blocking_actor* self, actor ping_actor) {
printf("event_based_pong\n");
self->send(ping_actor, pong_atom::value, 0); // kickoff self->send(ping_actor, pong_atom::value, 0); // kickoff
self->receive_loop(pong_behavior(self)); self->receive_loop(pong_behavior(self));
} }
...@@ -462,7 +464,7 @@ void test_remote_actor(const char* app_path, bool run_remote_actor) { ...@@ -462,7 +464,7 @@ void test_remote_actor(const char* app_path, bool run_remote_actor) {
"--", "-c", port2, "-c", port1, "-g", gport); "--", "-c", port2, "-c", port1, "-g", gport);
} else { } else {
CAF_MESSAGE("please run client with: " CAF_MESSAGE("please run client with: "
<< "-c " << port2 << " " << port1 << " " << gport); << "-c " << port2 << " -c " << port1 << " -g " << gport);
} }
self->receive( self->receive(
[&](const down_msg& dm) { [&](const down_msg& dm) {
......
...@@ -59,7 +59,7 @@ using client_type = typed_actor<>; ...@@ -59,7 +59,7 @@ using client_type = typed_actor<>;
server_type::behavior_type server() { server_type::behavior_type server() {
return { return {
[](const ping & p) -> pong { [](const ping & p) -> pong {
CAF_MESSAGE("received `ping`"); CAF_CHECK_EQUAL(p.value, 42);
return pong{p.value}; 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