Commit ffed360f authored by Dominik Charousset's avatar Dominik Charousset

fixed several issues with typed actors

parent 3b25a510
...@@ -31,9 +31,11 @@ ...@@ -31,9 +31,11 @@
#ifndef CPPA_ABSTRACT_ACTOR_HPP #ifndef CPPA_ABSTRACT_ACTOR_HPP
#define CPPA_ABSTRACT_ACTOR_HPP #define CPPA_ABSTRACT_ACTOR_HPP
#include <set>
#include <mutex> #include <mutex>
#include <atomic> #include <atomic>
#include <memory> #include <memory>
#include <string>
#include <vector> #include <vector>
#include <cstdint> #include <cstdint>
#include <type_traits> #include <type_traits>
...@@ -119,7 +121,10 @@ class abstract_actor : public abstract_channel { ...@@ -119,7 +121,10 @@ class abstract_actor : public abstract_channel {
/** /**
* @copydoc abstract_actor::link_to(const actor_addr&) * @copydoc abstract_actor::link_to(const actor_addr&)
*/ */
void link_to(const actor& whom); template<typename ActorHandle>
void link_to(const ActorHandle& whom) {
link_to(whom.address());
}
/** /**
* @brief Unlinks this actor from @p whom. * @brief Unlinks this actor from @p whom.
...@@ -131,7 +136,10 @@ class abstract_actor : public abstract_channel { ...@@ -131,7 +136,10 @@ class abstract_actor : public abstract_channel {
/** /**
* @copydoc abstract_actor::unlink_from(const actor_addr&) * @copydoc abstract_actor::unlink_from(const actor_addr&)
*/ */
void unlink_from(const actor& whom); template<class ActorHandle>
void unlink_from(const ActorHandle& whom) {
unlink_from(whom.address());
}
/** /**
* @brief Establishes a link relation between this actor and @p other. * @brief Establishes a link relation between this actor and @p other.
...@@ -174,6 +182,12 @@ class abstract_actor : public abstract_channel { ...@@ -174,6 +182,12 @@ class abstract_actor : public abstract_channel {
*/ */
inline std::uint32_t exit_reason() const; inline std::uint32_t exit_reason() const;
/**
* @brief Returns the type interface as set of strings.
* @note The returned set is empty for all untyped actors.
*/
virtual std::set<std::string> interface() const;
protected: protected:
abstract_actor(); abstract_actor();
......
...@@ -484,7 +484,8 @@ void anon_send_exit(const actor_addr& whom, std::uint32_t reason); ...@@ -484,7 +484,8 @@ void anon_send_exit(const actor_addr& whom, std::uint32_t reason);
/** /**
* @brief Anonymously sends @p whom an exit message. * @brief Anonymously sends @p whom an exit message.
*/ */
inline void anon_send_exit(const actor& whom, std::uint32_t reason) { template<typename ActorHandle>
inline void anon_send_exit(const ActorHandle& whom, std::uint32_t reason) {
anon_send_exit(whom.address(), reason); anon_send_exit(whom.address(), reason);
} }
...@@ -548,10 +549,10 @@ actor remote_actor(io::stream_ptr_pair connection); ...@@ -548,10 +549,10 @@ actor remote_actor(io::stream_ptr_pair connection);
* @brief Spawns an IO actor of type @p Impl. * @brief Spawns an IO actor of type @p Impl.
* @param args Constructor arguments. * @param args Constructor arguments.
* @tparam Impl Subtype of {@link io::broker}. * @tparam Impl Subtype of {@link io::broker}.
* @tparam Options Optional flags to modify <tt>spawn</tt>'s behavior. * @tparam Os Optional flags to modify <tt>spawn</tt>'s behavior.
* @returns An {@link actor_ptr} to the spawned {@link actor}. * @returns An {@link actor_ptr} to the spawned {@link actor}.
*/ */
template<class Impl, spawn_options Options = no_spawn_options, typename... Ts> template<class Impl, spawn_options Os = no_spawn_options, typename... Ts>
actor spawn_io(Ts&&... args) { actor spawn_io(Ts&&... args) {
auto ptr = make_counted<Impl>(std::forward<Ts>(args)...); auto ptr = make_counted<Impl>(std::forward<Ts>(args)...);
return {io::init_and_launch(std::move(ptr))}; return {io::init_and_launch(std::move(ptr))};
...@@ -563,10 +564,10 @@ actor spawn_io(Ts&&... args) { ...@@ -563,10 +564,10 @@ actor spawn_io(Ts&&... args) {
* @param in The actor's input stream. * @param in The actor's input stream.
* @param out The actor's output stream. * @param out The actor's output stream.
* @param args Optional arguments for @p fun. * @param args Optional arguments for @p fun.
* @tparam Options Optional flags to modify <tt>spawn</tt>'s behavior. * @tparam Os Optional flags to modify <tt>spawn</tt>'s behavior.
* @returns A {@link actor handle} to the spawned actor. * @returns A {@link actor handle} to the spawned actor.
*/ */
template<spawn_options Options = no_spawn_options, template<spawn_options Os = no_spawn_options,
typename F = std::function<void (io::broker*)>, typename F = std::function<void (io::broker*)>,
typename... Ts> typename... Ts>
actor spawn_io(F fun, actor spawn_io(F fun,
...@@ -578,7 +579,7 @@ actor spawn_io(F fun, ...@@ -578,7 +579,7 @@ actor spawn_io(F fun,
return {io::init_and_launch(std::move(ptr))}; return {io::init_and_launch(std::move(ptr))};
} }
template<spawn_options Options = no_spawn_options, template<spawn_options Os = no_spawn_options,
typename F = std::function<void (io::broker*)>, typename F = std::function<void (io::broker*)>,
typename... Ts> typename... Ts>
actor spawn_io(F fun, const std::string& host, uint16_t port, Ts&&... args) { actor spawn_io(F fun, const std::string& host, uint16_t port, Ts&&... args) {
...@@ -586,13 +587,13 @@ actor spawn_io(F fun, const std::string& host, uint16_t port, Ts&&... args) { ...@@ -586,13 +587,13 @@ actor spawn_io(F fun, const std::string& host, uint16_t port, Ts&&... args) {
return spawn_io(std::move(fun), ptr, ptr, std::forward<Ts>(args)...); return spawn_io(std::move(fun), ptr, ptr, std::forward<Ts>(args)...);
} }
template<spawn_options Options = no_spawn_options, template<spawn_options Os = no_spawn_options,
typename F = std::function<void (io::broker*)>, typename F = std::function<void (io::broker*)>,
typename... Ts> typename... Ts>
actor spawn_io_server(F fun, uint16_t port, Ts&&... args) { actor spawn_io_server(F fun, uint16_t port, Ts&&... args) {
static_assert(!has_detach_flag(Options), static_assert(!has_detach_flag(Os),
"brokers cannot be detached"); "brokers cannot be detached");
static_assert(is_unbound(Options), static_assert(is_unbound(Os),
"top-level spawns cannot have monitor or link flag"); "top-level spawns cannot have monitor or link flag");
using namespace std; using namespace std;
auto ptr = io::broker::from(move(fun), auto ptr = io::broker::from(move(fun),
......
...@@ -44,8 +44,6 @@ ...@@ -44,8 +44,6 @@
namespace cppa { namespace cppa {
class event_based_actor;
/** /**
* @brief A cooperatively scheduled, event-based actor implementation. * @brief A cooperatively scheduled, event-based actor implementation.
* *
......
...@@ -127,13 +127,17 @@ class local_actor : public extend<abstract_actor>::with<memory_cached> { ...@@ -127,13 +127,17 @@ class local_actor : public extend<abstract_actor>::with<memory_cached> {
* spawn typed actors * * spawn typed actors *
**************************************************************************/ **************************************************************************/
template<spawn_options Os = no_spawn_options, typename F> template<spawn_options Os = no_spawn_options, typename F, typename... Ts>
typename detail::actor_handle_from_typed_behavior< typename detail::infer_typed_actor_handle<
typename util::get_callable_trait<F>::result_type typename util::get_callable_trait<F>::result_type,
typename util::tl_head<
typename util::get_callable_trait<F>::arg_types
>::type >::type
spawn_typed(F fun) { >::type
spawn_typed(F fun, Ts&&... args) {
constexpr auto os = make_unbound(Os); constexpr auto os = make_unbound(Os);
auto res = cppa::spawn_typed<os>(std::move(fun)); auto res = cppa::spawn_typed<os>(std::move(fun),
std::forward<Ts>(args)...);
return eval_opts(Os, std::move(res)); return eval_opts(Os, std::move(res));
} }
...@@ -195,9 +199,9 @@ class local_actor : public extend<abstract_actor>::with<memory_cached> { ...@@ -195,9 +199,9 @@ class local_actor : public extend<abstract_actor>::with<memory_cached> {
* @param whom Receiver of the message. * @param whom Receiver of the message.
* @param what Message content as a tuple. * @param what Message content as a tuple.
*/ */
template<typename... Signatures, typename... Ts> template<typename... Rs, typename... Ts>
void send_tuple(message_priority prio, void send_tuple(message_priority prio,
const typed_actor<Signatures...>& whom, const typed_actor<Rs...>& whom,
cow_tuple<Ts...> what) { cow_tuple<Ts...> what) {
check_typed_input(whom, what); check_typed_input(whom, what);
send_tuple(prio, whom.m_ptr, any_tuple{std::move(what)}); send_tuple(prio, whom.m_ptr, any_tuple{std::move(what)});
...@@ -208,8 +212,8 @@ class local_actor : public extend<abstract_actor>::with<memory_cached> { ...@@ -208,8 +212,8 @@ class local_actor : public extend<abstract_actor>::with<memory_cached> {
* @param whom Receiver of the message. * @param whom Receiver of the message.
* @param what Message content as a tuple. * @param what Message content as a tuple.
*/ */
template<typename... Signatures, typename... Ts> template<typename... Rs, typename... Ts>
void send_tuple(const typed_actor<Signatures...>& whom, void send_tuple(const typed_actor<Rs...>& whom,
cow_tuple<Ts...> what) { cow_tuple<Ts...> what) {
check_typed_input(whom, what); check_typed_input(whom, what);
send_tuple_impl(message_priority::normal, whom, std::move(what)); send_tuple_impl(message_priority::normal, whom, std::move(what));
...@@ -222,9 +226,9 @@ class local_actor : public extend<abstract_actor>::with<memory_cached> { ...@@ -222,9 +226,9 @@ class local_actor : public extend<abstract_actor>::with<memory_cached> {
* @param what Message elements. * @param what Message elements.
* @pre <tt>sizeof...(Ts) > 0</tt>. * @pre <tt>sizeof...(Ts) > 0</tt>.
*/ */
template<typename... Signatures, typename... Ts> template<typename... Rs, typename... Ts>
void send(message_priority prio, void send(message_priority prio,
const typed_actor<Signatures...>& whom, const typed_actor<Rs...>& whom,
cow_tuple<Ts...> what) { cow_tuple<Ts...> what) {
send_tuple(prio, whom, make_cow_tuple(std::forward<Ts>(what)...)); send_tuple(prio, whom, make_cow_tuple(std::forward<Ts>(what)...));
} }
...@@ -235,8 +239,8 @@ class local_actor : public extend<abstract_actor>::with<memory_cached> { ...@@ -235,8 +239,8 @@ class local_actor : public extend<abstract_actor>::with<memory_cached> {
* @param what Message elements. * @param what Message elements.
* @pre <tt>sizeof...(Ts) > 0</tt>. * @pre <tt>sizeof...(Ts) > 0</tt>.
*/ */
template<typename... Signatures, typename... Ts> template<typename... Rs, typename... Ts>
void send(const typed_actor<Signatures...>& whom, Ts... what) { void send(const typed_actor<Rs...>& whom, Ts... what) {
send_tuple(message_priority::normal, whom, send_tuple(message_priority::normal, whom,
make_cow_tuple(std::forward<Ts>(what)...)); make_cow_tuple(std::forward<Ts>(what)...));
} }
...@@ -256,8 +260,8 @@ class local_actor : public extend<abstract_actor>::with<memory_cached> { ...@@ -256,8 +260,8 @@ class local_actor : public extend<abstract_actor>::with<memory_cached> {
/** /**
* @copydoc send_exit(const actor_addr&, std::uint32_t) * @copydoc send_exit(const actor_addr&, std::uint32_t)
*/ */
template<typename... Signatures> template<typename... Rs>
void send_exit(const typed_actor<Signatures...>& whom, void send_exit(const typed_actor<Rs...>& whom,
std::uint32_t reason) { std::uint32_t reason) {
send_exit(whom.address(), reason); send_exit(whom.address(), reason);
} }
...@@ -516,9 +520,9 @@ class local_actor : public extend<abstract_actor>::with<memory_cached> { ...@@ -516,9 +520,9 @@ class local_actor : public extend<abstract_actor>::with<memory_cached> {
any_tuple&& what); any_tuple&& what);
// returns the response ID // returns the response ID
template<typename... Signatures, typename... Ts> template<typename... Rs, typename... Ts>
message_id sync_send_tuple_impl(message_priority mp, message_id sync_send_tuple_impl(message_priority mp,
const typed_actor<Signatures...>& whom, const typed_actor<Rs...>& whom,
cow_tuple<Ts...>&& what) { cow_tuple<Ts...>&& what) {
check_typed_input(whom, what); check_typed_input(whom, what);
return sync_send_tuple_impl(mp, return sync_send_tuple_impl(mp,
...@@ -601,11 +605,11 @@ class local_actor : public extend<abstract_actor>::with<memory_cached> { ...@@ -601,11 +605,11 @@ class local_actor : public extend<abstract_actor>::with<memory_cached> {
private: private:
template<typename... Signatures, typename... Ts> template<typename... Rs, typename... Ts>
static void check_typed_input(const typed_actor<Signatures...>&, static void check_typed_input(const typed_actor<Rs...>&,
const cow_tuple<Ts...>&) { const cow_tuple<Ts...>&) {
static constexpr int input_pos = util::tl_find_if< static constexpr int input_pos = util::tl_find_if<
util::type_list<Signatures...>, util::type_list<Rs...>,
detail::input_is< detail::input_is<
util::type_list<Ts...> util::type_list<Ts...>
>::template eval >::template eval
......
...@@ -217,23 +217,44 @@ actor spawn_in_group(const group& grp, Ts&&... args) { ...@@ -217,23 +217,44 @@ actor spawn_in_group(const group& grp, Ts&&... args) {
namespace detail { namespace detail {
template<typename... Sigs> template<typename... Rs>
class functor_based_typed_actor : public typed_event_based_actor<Sigs...> { class functor_based_typed_actor : public typed_event_based_actor<Rs...> {
typedef typed_event_based_actor<Sigs...> super; typedef typed_event_based_actor<Rs...> super;
public: public:
typedef typed_event_based_actor<Sigs...>* pointer; typedef typed_event_based_actor<Rs...>* pointer;
typedef typename super::behavior_type behavior_type; typedef typename super::behavior_type behavior_type;
typedef std::function<typed_behavior<Sigs...> ()> no_arg_fun; typedef std::function<behavior_type ()> no_arg_fun;
typedef std::function<typed_behavior<Sigs...> (pointer)> one_arg_fun; typedef std::function<behavior_type (pointer)> one_arg_fun1;
typedef std::function<void (pointer)> one_arg_fun2;
functor_based_typed_actor(one_arg_fun fun) : m_fun(std::move(fun)) { } functor_based_typed_actor(one_arg_fun1 fun) {
set(std::move(fun));
}
functor_based_typed_actor(one_arg_fun2 fun) {
set(std::move(fun));
}
functor_based_typed_actor(no_arg_fun fun) { functor_based_typed_actor(no_arg_fun fun) {
m_fun = [fun](pointer) { return fun(); }; set(std::move(fun));
}
template<typename F, typename T, typename... Ts>
functor_based_typed_actor(F fun, T&& arg, Ts&&... args) {
typedef typename util::get_callable_trait<F>::arg_types arg_types;
constexpr bool uses_first_arg = std::is_same<
typename util::tl_head<
arg_types
>::type,
pointer
>::value;
std::integral_constant<bool, uses_first_arg> token;
bind_and_set(token, std::move(fun),
std::forward<T>(arg), std::forward<Ts>(args)...);
} }
protected: protected:
...@@ -244,45 +265,93 @@ class functor_based_typed_actor : public typed_event_based_actor<Sigs...> { ...@@ -244,45 +265,93 @@ class functor_based_typed_actor : public typed_event_based_actor<Sigs...> {
private: private:
one_arg_fun m_fun; void set(one_arg_fun1 fun) {
m_fun = std::move(fun);
}
}; void set(one_arg_fun2 fun) {
m_fun = [fun](pointer ptr) {
fun(ptr);
return behavior_type{};
};
}
template<typename TypedBehavior> void set(no_arg_fun fun) {
struct actor_type_from_typed_behavior; m_fun = [fun](pointer) { return fun(); };
}
template<typename F, typename... Ts>
void bind_and_set(std::true_type, F fun, Ts&&... args) {
set(std::bind(fun, std::placeholders::_1, std::forward<Ts>(args)...));
}
template<typename F, typename... Ts>
void bind_and_set(std::false_type, F fun, Ts&&... args) {
set(std::bind(fun, std::forward<Ts>(args)...));
}
one_arg_fun1 m_fun;
template<typename... Signatures>
struct actor_type_from_typed_behavior<typed_behavior<Signatures...>> {
typedef functor_based_typed_actor<Signatures...> type;
}; };
} // namespace detail template<class TypedBehavior, class FirstArg>
struct infer_typed_actor_base;
template<spawn_options Options, typename F> template<typename... Rs, class FirstArg>
typename detail::actor_handle_from_typed_behavior< struct infer_typed_actor_base<typed_behavior<Rs...>, FirstArg> {
typename util::get_callable_trait<F>::result_type typedef functor_based_typed_actor<Rs...> type;
>::type };
spawn_typed(F fun) {
typedef typename detail::actor_type_from_typed_behavior< template<typename... Rs>
typename util::get_callable_trait<F>::result_type struct infer_typed_actor_base<void, typed_event_based_actor<Rs...>*> {
>::type typedef functor_based_typed_actor<Rs...> type;
impl; };
return detail::spawn_fwd_args<impl, Options>(
[&](impl*) { },
std::move(fun));
}
} // namespace detail
template<class C, spawn_options Options, typename... Ts> /**
* @brief Spawns a typed actor of type @p C.
* @param args Constructor arguments.
* @tparam C Subtype of {@link typed_event_based_actor}.
* @tparam Os Optional flags to modify <tt>spawn</tt>'s behavior.
* @returns A {@link typed_actor} handle to the spawned actor.
*/
template<class C, spawn_options Os, typename... Ts>
typename detail::actor_handle_from_signature_list< typename detail::actor_handle_from_signature_list<
typename C::signatures typename C::signatures
>::type >::type
spawn_typed(Ts&&... args) { spawn_typed(Ts&&... args) {
return detail::spawn_fwd_args<C, Options>( return detail::spawn_fwd_args<C, Os>(
[&](C*) { }, [&](C*) { },
std::forward<Ts>(args)...); std::forward<Ts>(args)...);
} }
/**
* @brief Spawns a typed actor from a functor.
* @param args A functor followed by its arguments.
* @tparam Os Optional flags to modify <tt>spawn</tt>'s behavior.
* @returns An {@link actor} to the spawned {@link actor}.
*/
template<spawn_options Os, typename F, typename... Ts>
typename detail::infer_typed_actor_handle<
typename util::get_callable_trait<F>::result_type,
typename util::tl_head<
typename util::get_callable_trait<F>::arg_types
>::type
>::type
spawn_typed(F fun, Ts&&... args) {
typedef typename detail::infer_typed_actor_base<
typename util::get_callable_trait<F>::result_type,
typename util::tl_head<
typename util::get_callable_trait<F>::arg_types
>::type
>::type
impl;
return detail::spawn_fwd_args<impl, Os>(
[&](impl*) { },
std::move(fun), std::forward<Ts>(args)...);
}
/** @} */ /** @} */
} // namespace cppa } // namespace cppa
......
...@@ -45,16 +45,16 @@ namespace cppa { ...@@ -45,16 +45,16 @@ namespace cppa {
* untyped actors * * untyped actors *
******************************************************************************/ ******************************************************************************/
template<class Impl, spawn_options Options = no_spawn_options, typename... Ts> template<class Impl, spawn_options Os = no_spawn_options, typename... Ts>
actor spawn(Ts&&... args); actor spawn(Ts&&... args);
template<spawn_options Options = no_spawn_options, typename... Ts> template<spawn_options Os = no_spawn_options, typename... Ts>
actor spawn(Ts&&... args); actor spawn(Ts&&... args);
template<class Impl, spawn_options Options = no_spawn_options, typename... Ts> template<class Impl, spawn_options Os = no_spawn_options, typename... Ts>
actor spawn_in_group(const group&, Ts&&... args); actor spawn_in_group(const group&, Ts&&... args);
template<spawn_options Options = no_spawn_options, typename... Ts> template<spawn_options Os = no_spawn_options, typename... Ts>
actor spawn_in_group(const group&, Ts&&... args); actor spawn_in_group(const group&, Ts&&... args);
/****************************************************************************** /******************************************************************************
...@@ -63,36 +63,46 @@ actor spawn_in_group(const group&, Ts&&... args); ...@@ -63,36 +63,46 @@ actor spawn_in_group(const group&, Ts&&... args);
namespace detail { // some utility namespace detail { // some utility
template<typename TypedBehavior> template<class TypedBehavior, class FirstArg>
struct actor_handle_from_typed_behavior; struct infer_typed_actor_handle;
template<typename... Signatures> // infer actor type from result type if possible
struct actor_handle_from_typed_behavior<typed_behavior<Signatures...>> { template<typename... Rs, class FirstArg>
typedef typed_actor<Signatures...> type; struct infer_typed_actor_handle<typed_behavior<Rs...>, FirstArg> {
typedef typed_actor<Rs...> type;
};
// infer actor type from first argument if result type is void
template<typename... Rs>
struct infer_typed_actor_handle<void, typed_event_based_actor<Rs...>*> {
typedef typed_actor<Rs...> type;
}; };
template<typename SignatureList> template<typename SignatureList>
struct actor_handle_from_signature_list; struct actor_handle_from_signature_list;
template<typename... Signatures> template<typename... Rs>
struct actor_handle_from_signature_list<util::type_list<Signatures...>> { struct actor_handle_from_signature_list<util::type_list<Rs...>> {
typedef typed_actor<Signatures...> type; typedef typed_actor<Rs...> type;
}; };
} // namespace detail } // namespace detail
template<spawn_options Options = no_spawn_options, typename F> template<class Impl, spawn_options Os = no_spawn_options, typename... Ts>
typename detail::actor_handle_from_typed_behavior<
typename util::get_callable_trait<F>::result_type
>::type
spawn_typed(F fun);
template<class Impl, spawn_options Options = no_spawn_options, typename... Ts>
typename detail::actor_handle_from_signature_list< typename detail::actor_handle_from_signature_list<
typename Impl::signatures typename Impl::signatures
>::type >::type
spawn_typed(Ts&&... args); spawn_typed(Ts&&... args);
template<spawn_options Os = no_spawn_options, typename F, typename... Ts>
typename detail::infer_typed_actor_handle<
typename util::get_callable_trait<F>::result_type,
typename util::tl_head<
typename util::get_callable_trait<F>::arg_types
>::type
>::type
spawn_typed(F fun, Ts&&... args);
} // namespace cppa } // namespace cppa
#endif // CPPA_SPAWN_FWD_HPP #endif // CPPA_SPAWN_FWD_HPP
...@@ -44,38 +44,43 @@ class local_actor; ...@@ -44,38 +44,43 @@ class local_actor;
struct invalid_actor_addr_t; struct invalid_actor_addr_t;
template<typename... Signatures> template<typename... Rs>
class typed_event_based_actor; class typed_event_based_actor;
/** /**
* @brief Identifies a strongly typed actor. * @brief Identifies a strongly typed actor.
* @tparam Rs Interface as @p replies_to<...>::with<...> parameter pack.
*/ */
template<typename... Signatures> template<typename... Rs>
class typed_actor : util::comparable<typed_actor<Signatures...>> class typed_actor : util::comparable<typed_actor<Rs...>>
, util::comparable<typed_actor<Signatures...>, actor_addr> , util::comparable<typed_actor<Rs...>, actor_addr>
, util::comparable<typed_actor<Signatures...>, invalid_actor_addr_t> { , util::comparable<typed_actor<Rs...>, invalid_actor_addr_t> {
friend class local_actor; friend class local_actor;
// friend with all possible instantiations
template<typename...>
friend class typed_actor;
public: public:
/** /**
* @brief Identifies the behavior type actors of this kind use * @brief Identifies the behavior type actors of this kind use
* for their behavior stack. * for their behavior stack.
*/ */
typedef typed_behavior<Signatures...> behavior_type; typedef typed_behavior<Rs...> behavior_type;
/** /**
* @brief Identifies pointers to instances of this kind of actor. * @brief Identifies pointers to instances of this kind of actor.
*/ */
typedef typed_event_based_actor<Signatures...>* pointer; typedef typed_event_based_actor<Rs...>* pointer;
/** /**
* @brief Identifies the base class for this kind of actor. * @brief Identifies the base class for this kind of actor.
*/ */
typedef typed_event_based_actor<Signatures...> base; typedef typed_event_based_actor<Rs...> base;
typedef util::type_list<Signatures...> signatures; typedef util::type_list<Rs...> signatures;
typed_actor() = default; typed_actor() = default;
typed_actor(typed_actor&&) = default; typed_actor(typed_actor&&) = default;
...@@ -83,13 +88,13 @@ class typed_actor : util::comparable<typed_actor<Signatures...>> ...@@ -83,13 +88,13 @@ class typed_actor : util::comparable<typed_actor<Signatures...>>
typed_actor& operator=(typed_actor&&) = default; typed_actor& operator=(typed_actor&&) = default;
typed_actor& operator=(const typed_actor&) = default; typed_actor& operator=(const typed_actor&) = default;
template<typename... OtherSignatures> template<typename... OtherRs>
typed_actor(const typed_actor<OtherSignatures...>& other) { typed_actor(const typed_actor<OtherRs...>& other) {
set(std::move(other)); set(std::move(other));
} }
template<typename... OtherSignatures> template<typename... OtherRs>
typed_actor& operator=(const typed_actor<OtherSignatures...>& other) { typed_actor& operator=(const typed_actor<OtherRs...>& other) {
set(std::move(other)); set(std::move(other));
return *this; return *this;
} }
...@@ -99,6 +104,14 @@ class typed_actor : util::comparable<typed_actor<Signatures...>> ...@@ -99,6 +104,14 @@ class typed_actor : util::comparable<typed_actor<Signatures...>>
set(other); set(other);
} }
pointer operator->() const {
return static_cast<pointer>(m_ptr.get());
}
base& operator*() const {
return static_cast<base&>(*m_ptr.get());
}
/** /**
* @brief Queries the address of the stored actor. * @brief Queries the address of the stored actor.
*/ */
...@@ -110,6 +123,10 @@ class typed_actor : util::comparable<typed_actor<Signatures...>> ...@@ -110,6 +123,10 @@ class typed_actor : util::comparable<typed_actor<Signatures...>>
return address().compare(rhs); return address().compare(rhs);
} }
inline intptr_t compare(const typed_actor& other) const {
return compare(other.address());
}
inline intptr_t compare(const invalid_actor_addr_t&) const { inline intptr_t compare(const invalid_actor_addr_t&) const {
return m_ptr ? 1 : 0; return m_ptr ? 1 : 0;
} }
...@@ -122,9 +139,9 @@ class typed_actor : util::comparable<typed_actor<Signatures...>> ...@@ -122,9 +139,9 @@ class typed_actor : util::comparable<typed_actor<Signatures...>>
"'this' must be a strict subset of 'other'"); "'this' must be a strict subset of 'other'");
} }
template<typename... OtherSignatures> template<typename... OtherRs>
inline void set(const typed_actor<OtherSignatures...>& other) { inline void set(const typed_actor<OtherRs...>& other) {
check_signatures<signatures, util::type_list<OtherSignatures...>>(); check_signatures<signatures, util::type_list<OtherRs...>>();
m_ptr = other.m_ptr; m_ptr = other.m_ptr;
} }
......
...@@ -40,6 +40,9 @@ namespace cppa { ...@@ -40,6 +40,9 @@ namespace cppa {
namespace detail { namespace detail {
template<typename... Rs>
class functor_based_typed_actor;
template<typename T> template<typename T>
struct match_hint_to_void { struct match_hint_to_void {
typedef T type; typedef T type;
...@@ -49,18 +52,40 @@ template<> ...@@ -49,18 +52,40 @@ template<>
struct match_hint_to_void<match_hint> { struct match_hint_to_void<match_hint> {
typedef void type; typedef void type;
}; };
template<typename T>
struct infer_result_from_continue_helper {
typedef T type;
};
template<typename R>
struct infer_result_from_continue_helper<typed_continue_helper<R>> {
typedef R type;
};
template<class List>
struct collapse_infered_list {
typedef List type;
};
template<typename... Ts>
struct collapse_infered_list<util::type_list<util::type_list<Ts...>>> {
typedef util::type_list<Ts...> type;
};
template<typename T> template<typename T>
struct all_match_hints_to_void { struct infer_response_types {
typedef typename T::input_types input_types; typedef typename T::input_types input_types;
typedef typename util::tl_map< typedef typename util::tl_map<
typename T::output_types, typename T::output_types,
match_hint_to_void match_hint_to_void,
infer_result_from_continue_helper
>::type >::type
output_types; output_types;
typedef typename replies_to_from_type_list< typedef typename replies_to_from_type_list<
input_types, input_types,
output_types // continue_helper stores a type list,
// so we need to collapse the list here
typename collapse_infered_list<output_types>::type
>::type >::type
type; type;
}; };
...@@ -81,22 +106,23 @@ void static_check_typed_behavior_input() { ...@@ -81,22 +106,23 @@ void static_check_typed_behavior_input() {
} // namespace detail } // namespace detail
template<typename... Signatures> template<typename... Rs>
class typed_actor; class typed_actor;
template<class Base, class Subtype, class BehaviorType> template<class Base, class Subtype, class BehaviorType>
class behavior_stack_based_impl; class behavior_stack_based_impl;
template<typename... Signatures> template<typename... Rs>
class typed_behavior { class typed_behavior {
template<typename... OtherSignatures> template<typename... OtherRs>
friend class typed_actor; friend class typed_actor;
template<class Base, class Subtype, class BehaviorType> template<class Base, class Subtype, class BehaviorType>
friend class behavior_stack_based_impl; friend class behavior_stack_based_impl;
typed_behavior() = delete; template<typename...>
friend class detail::functor_based_typed_actor;
public: public:
...@@ -105,7 +131,7 @@ class typed_behavior { ...@@ -105,7 +131,7 @@ class typed_behavior {
typed_behavior& operator=(typed_behavior&&) = default; typed_behavior& operator=(typed_behavior&&) = default;
typed_behavior& operator=(const typed_behavior&) = default; typed_behavior& operator=(const typed_behavior&) = default;
typedef util::type_list<Signatures...> signatures; typedef util::type_list<Rs...> signatures;
template<typename... Cs, typename... Ts> template<typename... Cs, typename... Ts>
typed_behavior(match_expr<Cs...> expr, Ts&&... args) { typed_behavior(match_expr<Cs...> expr, Ts&&... args) {
...@@ -139,6 +165,8 @@ class typed_behavior { ...@@ -139,6 +165,8 @@ class typed_behavior {
private: private:
typed_behavior() = default;
behavior& unbox() { return m_bhvr; } behavior& unbox() { return m_bhvr; }
template<typename... Cs> template<typename... Cs>
...@@ -148,15 +176,18 @@ class typed_behavior { ...@@ -148,15 +176,18 @@ class typed_behavior {
detail::match_expr_has_no_guard<Cs>::value... detail::match_expr_has_no_guard<Cs>::value...
>::value, >::value,
"typed actors are not allowed to use guard expressions"); "typed actors are not allowed to use guard expressions");
// returning a match_hint from a message handler does // do some transformation before type-checking the input signatures
// not send anything back, so we can consider match_hint to be void
typedef typename util::tl_map< typedef typename util::tl_map<
util::type_list< util::type_list<
typename detail::deduce_signature<Cs>::type... typename detail::deduce_signature<Cs>::type...
>, >,
detail::all_match_hints_to_void // returning a match_hint from a message handler does
// not send anything back, so we can consider
// match_hint to be void
detail::infer_response_types
>::type >::type
input; input;
// check types
detail::static_check_typed_behavior_input<signatures, input>(); detail::static_check_typed_behavior_input<signatures, input>();
// final (type-erasure) step // final (type-erasure) step
m_bhvr = std::move(expr); m_bhvr = std::move(expr);
......
...@@ -40,12 +40,22 @@ ...@@ -40,12 +40,22 @@
namespace cppa { namespace cppa {
template<typename... Signatures> /**
* @brief A cooperatively scheduled, event-based actor implementation
* with strong type checking.
*
* This is the recommended base class for user-defined actors and is used
* implicitly when spawning typed, functor-based actors without the
* {@link blocking_api} flag.
*
* @extends local_actor
*/
template<typename... Rs>
class typed_event_based_actor class typed_event_based_actor
: public extend<local_actor, typed_event_based_actor<Signatures...>>::template : public extend<local_actor, typed_event_based_actor<Rs...>>::template
with<mailbox_based, with<mailbox_based,
behavior_stack_based< behavior_stack_based<
typed_behavior<Signatures...> typed_behavior<Rs...>
>::template impl, >::template impl,
sync_sender< sync_sender<
nonblocking_response_handle_tag nonblocking_response_handle_tag
...@@ -53,9 +63,13 @@ class typed_event_based_actor ...@@ -53,9 +63,13 @@ class typed_event_based_actor
public: public:
typedef util::type_list<Signatures...> signatures; typedef util::type_list<Rs...> signatures;
typedef typed_behavior<Signatures...> behavior_type; typedef typed_behavior<Rs...> behavior_type;
std::set<std::string> interface() const override {
return {detail::to_uniform_name<Rs>()...};
}
protected: protected:
......
...@@ -85,7 +85,7 @@ struct tl_head; ...@@ -85,7 +85,7 @@ struct tl_head;
template<template<typename...> class List> template<template<typename...> class List>
struct tl_head<List<>> { struct tl_head<List<>> {
typedef empty_type_list type; typedef void type;
}; };
template<template<typename...> class List, typename T0, typename... Ts> template<template<typename...> class List, typename T0, typename... Ts>
......
...@@ -66,14 +66,6 @@ abstract_actor::abstract_actor() ...@@ -66,14 +66,6 @@ abstract_actor::abstract_actor()
: m_id(get_actor_registry()->next_id()), m_is_proxy(false) : m_id(get_actor_registry()->next_id()), m_is_proxy(false)
, m_exit_reason(exit_reason::not_exited) { } , m_exit_reason(exit_reason::not_exited) { }
void abstract_actor::link_to(const actor& whom) {
link_to(whom.address());
}
void abstract_actor::unlink_from(const actor& whom) {
unlink_from(whom.address());
}
bool abstract_actor::link_to_impl(const actor_addr& other) { bool abstract_actor::link_to_impl(const actor_addr& other) {
if (other && other != this) { if (other && other != this) {
guard_type guard{m_mtx}; guard_type guard{m_mtx};
...@@ -226,4 +218,9 @@ void abstract_actor::cleanup(std::uint32_t reason) { ...@@ -226,4 +218,9 @@ void abstract_actor::cleanup(std::uint32_t reason) {
} }
} }
std::set<std::string> abstract_actor::interface() const {
// defaults to untyped
return std::set<std::string>{};
}
} // namespace cppa } // namespace cppa
...@@ -174,7 +174,7 @@ inline void deserialize_impl(unit_t&, deserializer*) { } ...@@ -174,7 +174,7 @@ inline void deserialize_impl(unit_t&, deserializer*) { }
void serialize_impl(const actor_addr& addr, serializer* sink) { void serialize_impl(const actor_addr& addr, serializer* sink) {
auto ns = sink->get_namespace(); auto ns = sink->get_namespace();
if (ns) ns->write(sink, addr); if (ns) ns->write(sink, addr);
else throw std::runtime_error("unable to serialize actor_ptr: " else throw std::runtime_error("unable to serialize actor_addr: "
"no actor addressing defined"); "no actor addressing defined");
} }
......
...@@ -204,7 +204,13 @@ void test_event_testee() { ...@@ -204,7 +204,13 @@ void test_event_testee() {
self->send(et, .3f); self->send(et, .3f);
self->send(et, "hello again event testee!"); self->send(et, "hello again event testee!");
self->send(et, "goodbye event testee!"); self->send(et, "goodbye event testee!");
self->send(et, get_state_msg{}); typed_actor<replies_to<get_state_msg>::with<string>> sub_et = et;
set<string> iface{"cppa::replies_to<get_state_msg>::with<@str>",
"cppa::replies_to<@str>::with<void>",
"cppa::replies_to<float>::with<void>",
"cppa::replies_to<@i32>::with<void>"};
CPPA_CHECK(sub_et->interface() == iface);
self->send(sub_et, get_state_msg{});
self->receive ( self->receive (
on_arg_match >> [&](const string& str) { on_arg_match >> [&](const string& str) {
result = str; result = str;
...@@ -219,6 +225,88 @@ void test_event_testee() { ...@@ -219,6 +225,88 @@ void test_event_testee() {
CPPA_CHECK_EQUAL(result, "wait4int"); CPPA_CHECK_EQUAL(result, "wait4int");
} }
/******************************************************************************
* simple 'forwarding' chain *
******************************************************************************/
typedef typed_actor<replies_to<string>::with<string>> string_actor;
void simple_relay(string_actor::pointer self, string_actor master, bool leaf) {
string_actor next = leaf ? spawn_typed(simple_relay, master, false) : master;
self->link_to(next);
self->become(
on_arg_match >> [=](const string& str) {
return self->sync_send(next, str).then(
[](const string& answer) -> string {
return answer;
}
);
}
);
}
string_actor::behavior_type simple_string_reverter() {
return {
on_arg_match >> [](const string& str) {
return string{str.rbegin(), str.rend()};
}
};
}
void test_simple_string_reverter() {
scoped_actor self;
// actor-under-test
auto aut = self->spawn_typed<monitored>(simple_relay,
spawn_typed(simple_string_reverter),
true);
set<string> iface{"cppa::replies_to<@str>::with<@str>"};
CPPA_CHECK(aut->interface() == iface);
self->sync_send(aut, "Hello World!").await(
[](const string& answer) {
CPPA_CHECK_EQUAL(answer, "!dlroW olleH");
}
);
anon_send_exit(aut, exit_reason::user_shutdown);
}
/******************************************************************************
* sending typed actor handles *
******************************************************************************/
typedef typed_actor<replies_to<int>::with<int>> int_actor;
int_actor::behavior_type int_fun() {
return {
on_arg_match >> [](int i) {
return i * i;
}
};
}
behavior foo(event_based_actor* self) {
return {
on_arg_match >> [=](int i, int_actor server) {
return self->sync_send(server, i).then(
[=](int result) -> int {
self->quit(exit_reason::normal);
return result;
}
);
}
};
}
void test_sending_typed_actors() {
scoped_actor self;
auto aut = spawn_typed(int_fun);
self->send(spawn(foo), 10, aut);
self->receive(
on_arg_match >> [](int i) {
CPPA_CHECK_EQUAL(i, 100);
}
);
self->send_exit(aut, exit_reason::user_shutdown);
}
/****************************************************************************** /******************************************************************************
* put it all together * * put it all together *
...@@ -229,9 +317,10 @@ int main() { ...@@ -229,9 +317,10 @@ int main() {
// announce stuff // announce stuff
announce_tag<get_state_msg>(); announce_tag<get_state_msg>();
announce<int_actor>();
announce<my_request>(&my_request::a, &my_request::b); announce<my_request>(&my_request::a, &my_request::b);
// run test series with typed_server* // run test series with typed_server(1|2)
test_typed_spawn(spawn_typed(typed_server1)); test_typed_spawn(spawn_typed(typed_server1));
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
await_all_actors_done(); await_all_actors_done();
...@@ -255,117 +344,17 @@ int main() { ...@@ -255,117 +344,17 @@ int main() {
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
await_all_actors_done(); await_all_actors_done();
// call it a day // run test series with string reverter
shutdown(); test_simple_string_reverter();
/* CPPA_CHECKPOINT();
auto sptr = spawn_typed_server();
sync_send(sptr, my_request{2, 2}).await(
[](bool value) {
CPPA_CHECK_EQUAL(value, true);
}
);
send_exit(sptr, exit_reason::user_shutdown);
sptr = spawn_typed<typed_testee>();
sync_send(sptr, my_request{2, 2}).await(
[](bool value) {
CPPA_CHECK_EQUAL(value, true);
}
);
send_exit(sptr, exit_reason::user_shutdown);
auto ptr0 = spawn_typed(
on_arg_match >> [](double d) {
return d * d;
},
on_arg_match >> [](float f) {
return f / 2.0f;
}
);
CPPA_CHECK((std::is_same<
decltype(ptr0),
typed_actor_ptr<
replies_to<double>::with<double>,
replies_to<float>::with<float>
>
>::value));
typed_actor_ptr<replies_to<double>::with<double>> ptr0_double = ptr0;
typed_actor_ptr<replies_to<float>::with<float>> ptr0_float = ptr0;
auto ptr = spawn_typed(
on<int>() >> [] { return "wtf"; },
on<string>() >> [] { return 42; },
on<float>() >> [] { return make_cow_tuple(1, 2, 3); },
on<double>() >> [=](double d) {
return sync_send(ptr0_double, d).then(
[](double res) { return res + res; }
);
}
);
// check async messages
send(ptr0_float, 4.0f);
receive(
on_arg_match >> [](float f) {
CPPA_CHECK_EQUAL(f, 4.0f / 2.0f);
}
);
// check sync messages
sync_send(ptr0_float, 4.0f).await(
[](float f) {
CPPA_CHECK_EQUAL(f, 4.0f / 2.0f);
}
);
sync_send(ptr, 10.0).await(
[](double d) {
CPPA_CHECK_EQUAL(d, 200.0);
}
);
sync_send(ptr, 42).await(
[](const std::string& str) {
CPPA_CHECK_EQUAL(str, "wtf");
}
);
sync_send(ptr, 1.2f).await(
[](int a, int b, int c) {
CPPA_CHECK_EQUAL(a, 1);
CPPA_CHECK_EQUAL(b, 2);
CPPA_CHECK_EQUAL(c, 3);
}
);
sync_send(ptr, 1.2f).await(
[](int b, int c) {
CPPA_CHECK_EQUAL(b, 2);
CPPA_CHECK_EQUAL(c, 3);
}
);
sync_send(ptr, 1.2f).await(
[](int c) {
CPPA_CHECK_EQUAL(c, 3);
}
);
sync_send(ptr, 1.2f).await(
[] { CPPA_CHECKPOINT(); }
);
spawn([=] {
sync_send(ptr, 2.3f).then(
[] (int c) {
CPPA_CHECK_EQUAL(c, 3);
return "hello continuation";
}
).continue_with(
[] (const string& str) {
CPPA_CHECK_EQUAL(str, "hello continuation");
return 4.2;
}
).continue_with(
[=] (double d) {
CPPA_CHECK_EQUAL(d, 4.2);
send_exit(ptr0, exit_reason::user_shutdown);
send_exit(ptr, exit_reason::user_shutdown);
self->quit();
}
);
});
await_all_actors_done(); await_all_actors_done();
// run test series with sending of typed actors
test_sending_typed_actors();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
await_all_actors_done();
// call it a day
shutdown(); shutdown();
*/
return CPPA_TEST_RESULT(); return CPPA_TEST_RESULT();
} }
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