Commit c733f29c authored by Dominik Charousset's avatar Dominik Charousset

typed actors

this patch adds support for typed actors as well as unit tests for
this new feature
parent 258c14db
......@@ -63,6 +63,7 @@ cppa/detail/tuple_iterator.hpp
cppa/detail/tuple_vals.hpp
cppa/detail/tuple_view.hpp
cppa/detail/type_to_ptype.hpp
cppa/detail/typed_actor_util.hpp
cppa/detail/types_array.hpp
cppa/detail/unboxed.hpp
cppa/detail/uniform_type_info_map.hpp
......@@ -136,6 +137,7 @@ cppa/process_information.hpp
cppa/qtsupport/actor_widget_mixin.hpp
cppa/receive.hpp
cppa/ref_counted.hpp
cppa/replies_to.hpp
cppa/response_handle.hpp
cppa/sb_actor.hpp
cppa/scheduled_actor.hpp
......@@ -144,6 +146,7 @@ cppa/self.hpp
cppa/send.hpp
cppa/serializer.hpp
cppa/singletons.hpp
cppa/spawn.hpp
cppa/spawn_options.hpp
cppa/stacked.hpp
cppa/stackless.hpp
......@@ -155,6 +158,8 @@ cppa/to_string.hpp
cppa/tpartial_function.hpp
cppa/tuple_cast.hpp
cppa/type_lookup_table.hpp
cppa/typed_actor.hpp
cppa/typed_actor_ptr.hpp
cppa/uniform_type_info.hpp
cppa/unit.hpp
cppa/util/abstract_uniform_type_info.hpp
......
......@@ -108,8 +108,10 @@ class behavior {
* whenever this behavior was successfully applied to
* a message.
*/
template<typename F>
inline behavior add_continuation(F fun);
behavior add_continuation(const partial_function& fun);
//template<typename F>
//inline behavior add_continuation(F fun);
private:
......@@ -168,10 +170,10 @@ inline auto behavior::as_behavior_impl() const -> const impl_ptr& {
return m_impl;
}
template<typename F>
inline behavior behavior::add_continuation(F fun) {
return {new detail::continuation_decorator<F>(std::move(fun), m_impl)};
}
//template<typename F>
//inline behavior behavior::add_continuation(F fun) {
// return {new detail::continuation_decorator<F>(std::move(fun), m_impl)};
//}
} // namespace cppa
......
......@@ -44,6 +44,7 @@
#include "cppa/self.hpp"
#include "cppa/actor.hpp"
#include "cppa/match.hpp"
#include "cppa/spawn.hpp"
#include "cppa/channel.hpp"
#include "cppa/receive.hpp"
#include "cppa/factory.hpp"
......@@ -57,12 +58,14 @@
#include "cppa/cow_tuple.hpp"
#include "cppa/tuple_cast.hpp"
#include "cppa/singletons.hpp"
#include "cppa/typed_actor.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/prioritizing.hpp"
#include "cppa/spawn_options.hpp"
#include "cppa/message_future.hpp"
#include "cppa/response_handle.hpp"
#include "cppa/typed_actor_ptr.hpp"
#include "cppa/scheduled_actor.hpp"
#include "cppa/event_based_actor.hpp"
......@@ -469,95 +472,6 @@ inline const self_type& operator<<(const self_type& s, any_tuple what) {
* @}
*/
inline actor_ptr eval_sopts(spawn_options opts, local_actor_ptr ptr) {
CPPA_LOGF_INFO("spawned new local actor with ID " << ptr->id()
<< " of type " << detail::demangle(typeid(*ptr)));
if (has_monitor_flag(opts)) self->monitor(ptr);
if (has_link_flag(opts)) self->link_to(ptr);
return std::move(ptr);
}
/**
* @ingroup ActorCreation
* @{
*/
/**
* @brief Spawns a new {@link actor} that evaluates given arguments.
* @param args A functor followed by its arguments.
* @tparam Options Optional flags to modify <tt>spawn</tt>'s behavior.
* @returns An {@link actor_ptr} to the spawned {@link actor}.
*/
template<spawn_options Options = no_spawn_options, typename... Ts>
actor_ptr spawn(Ts&&... args) {
static_assert(sizeof...(Ts) > 0, "too few arguments provided");
return eval_sopts(Options,
get_scheduler()->exec(Options,
scheduler::init_callback{},
std::forward<Ts>(args)...));
}
/**
* @brief Spawns an actor of type @p Impl.
* @param args Constructor arguments.
* @tparam Impl Subtype of {@link event_based_actor} or {@link sb_actor}.
* @tparam Options Optional flags to modify <tt>spawn</tt>'s behavior.
* @returns An {@link actor_ptr} to the spawned {@link actor}.
*/
template<class Impl, spawn_options Options = no_spawn_options, typename... Ts>
actor_ptr spawn(Ts&&... args) {
static_assert(std::is_base_of<event_based_actor, Impl>::value,
"Impl is not a derived type of event_based_actor");
scheduled_actor_ptr ptr;
if (has_priority_aware_flag(Options)) {
using derived = typename extend<Impl>::template with<threaded, prioritizing>;
ptr = make_counted<derived>(std::forward<Ts>(args)...);
}
else if (has_detach_flag(Options)) {
using derived = typename extend<Impl>::template with<threaded>;
ptr = make_counted<derived>(std::forward<Ts>(args)...);
}
else ptr = make_counted<Impl>(std::forward<Ts>(args)...);
return eval_sopts(Options, get_scheduler()->exec(Options, std::move(ptr)));
}
/**
* @brief Spawns a new actor that evaluates given arguments and
* immediately joins @p grp.
* @param args A functor followed by its arguments.
* @tparam Options Optional flags to modify <tt>spawn</tt>'s behavior.
* @returns An {@link actor_ptr} to the spawned {@link actor}.
* @note The spawned has joined the group before this function returns.
*/
template<spawn_options Options = no_spawn_options, typename... Ts>
actor_ptr spawn_in_group(const group_ptr& grp, Ts&&... args) {
static_assert(sizeof...(Ts) > 0, "too few arguments provided");
auto init_cb = [=](local_actor* ptr) {
ptr->join(grp);
};
return eval_sopts(Options,
get_scheduler()->exec(Options,
init_cb,
std::forward<Ts>(args)...));
}
/**
* @brief Spawns an actor of type @p Impl that immediately joins @p grp.
* @param args Constructor arguments.
* @tparam Impl Subtype of {@link event_based_actor} or {@link sb_actor}.
* @tparam Options Optional flags to modify <tt>spawn</tt>'s behavior.
* @returns An {@link actor_ptr} to the spawned {@link actor}.
* @note The spawned has joined the group before this function returns.
*/
template<class Impl, spawn_options Options = no_spawn_options, typename... Ts>
actor_ptr spawn_in_group(const group_ptr& grp, Ts&&... args) {
auto ptr = make_counted<Impl>(std::forward<Ts>(args)...);
ptr->join(grp);
return eval_sopts(Options, get_scheduler()->exec(Options, ptr));
}
/** @} */
/**
* @brief Blocks execution of this actor until all
* other actors finished execution.
......@@ -683,18 +597,6 @@ actor_ptr spawn_io_server(F fun, uint16_t port, Ts&&... args) {
*/
void shutdown(); // note: implemented in singleton_manager.cpp
/**
* @brief Sends an exit message to @p whom with @p reason.
*
* This function is syntactic sugar for
* <tt>send(whom, atom("EXIT"), reason)</tt>.
* @pre <tt>reason != exit_reason::normal</tt>
*/
inline void send_exit(actor_ptr whom, std::uint32_t reason) {
CPPA_REQUIRE(reason != exit_reason::normal);
send(std::move(whom), atom("EXIT"), reason);
}
/**
* @brief Sets the actor's behavior and discards the previous behavior
* unless {@link keep_behavior} is given as first argument.
......
......@@ -205,54 +205,6 @@ default_behavior_impl<dummy_match_expr, F>* new_default_behavior(util::duration
return new default_behavior_impl<dummy_match_expr, F>(dummy_match_expr{}, d, f);
}
template<typename F>
class continuation_decorator : public behavior_impl {
typedef behavior_impl super;
public:
typedef typename behavior_impl::pointer pointer;
template<typename Fun>
continuation_decorator(Fun&& fun, pointer decorated)
: super(decorated->timeout()), m_fun(std::forward<Fun>(fun))
, m_decorated(std::move(decorated)) {
CPPA_REQUIRE(m_decorated != nullptr);
}
template<typename T>
inline optional<any_tuple> invoke_impl(T& tup) {
auto res = m_decorated->invoke(tup);
if (res) m_fun();
return res;
}
optional<any_tuple> invoke(any_tuple& tup) {
return invoke_impl(tup);
}
optional<any_tuple> invoke(const any_tuple& tup) {
return invoke_impl(tup);
}
bool defined_at(const any_tuple& tup) {
return m_decorated->defined_at(tup);
}
pointer copy(const generic_timeout_definition& tdef) const {
return new continuation_decorator<F>(m_fun, m_decorated->copy(tdef));
}
void handle_timeout() { m_decorated->handle_timeout(); }
private:
F m_fun;
pointer m_decorated;
};
typedef intrusive_ptr<behavior_impl> behavior_impl_ptr;
} } // namespace cppa::detail
......
......@@ -32,6 +32,7 @@
#define CPPA_TYPE_TO_PTYPE_HPP
#include <string>
#include <limits>
#include <cstdint>
#include <type_traits>
......@@ -44,6 +45,32 @@ namespace cppa { namespace detail {
template<primitive_type PT>
struct wrapped_ptype { static const primitive_type ptype = PT; };
template<bool IsInteger, bool IsSigned, size_t Sizeof>
struct type_to_ptype_int {
static constexpr primitive_type ptype = pt_null;
};
template<> struct type_to_ptype_int<true, true , 1> : wrapped_ptype<pt_int8 > { };
template<> struct type_to_ptype_int<true, false, 1> : wrapped_ptype<pt_uint8 > { };
template<> struct type_to_ptype_int<true, true , 2> : wrapped_ptype<pt_int16 > { };
template<> struct type_to_ptype_int<true, false, 2> : wrapped_ptype<pt_uint16> { };
template<> struct type_to_ptype_int<true, true , 4> : wrapped_ptype<pt_int32 > { };
template<> struct type_to_ptype_int<true, false, 4> : wrapped_ptype<pt_uint32> { };
template<> struct type_to_ptype_int<true, true , 8> : wrapped_ptype<pt_int64 > { };
template<> struct type_to_ptype_int<true, false, 8> : wrapped_ptype<pt_uint64> { };
template<bool IsArithmetic, typename T>
struct type_to_ptype_impl_helper : wrapped_ptype<pt_null> { };
template<typename T>
struct type_to_ptype_impl_helper<true, T> {
static constexpr auto ptype = type_to_ptype_int<
std::numeric_limits<T>::is_integer,
std::numeric_limits<T>::is_signed,
sizeof(T)
>::ptype;
};
// maps type T the the corresponding fundamental_type
template<typename T>
struct type_to_ptype_impl {
......@@ -54,19 +81,9 @@ struct type_to_ptype_impl {
? pt_u16string
: (std::is_convertible<T, std::u32string>::value
? pt_u32string
: pt_null));
: type_to_ptype_impl_helper<std::is_arithmetic<T>::value, T>::ptype));
};
// integers
template<> struct type_to_ptype_impl<std::int8_t > : wrapped_ptype<pt_int8 > { };
template<> struct type_to_ptype_impl<std::uint8_t > : wrapped_ptype<pt_uint8 > { };
template<> struct type_to_ptype_impl<std::int16_t > : wrapped_ptype<pt_int16 > { };
template<> struct type_to_ptype_impl<std::uint16_t> : wrapped_ptype<pt_uint16> { };
template<> struct type_to_ptype_impl<std::int32_t > : wrapped_ptype<pt_int32 > { };
template<> struct type_to_ptype_impl<std::uint32_t> : wrapped_ptype<pt_uint32> { };
template<> struct type_to_ptype_impl<std::int64_t > : wrapped_ptype<pt_int64 > { };
template<> struct type_to_ptype_impl<std::uint64_t> : wrapped_ptype<pt_uint64> { };
// floating points
template<> struct type_to_ptype_impl<float> : wrapped_ptype<pt_float > { };
template<> struct type_to_ptype_impl<double> : wrapped_ptype<pt_double > { };
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_TYPED_ACTOR_UTIL_HPP
#define CPPA_TYPED_ACTOR_UTIL_HPP
#include "cppa/cow_tuple.hpp"
#include "cppa/replies_to.hpp"
#include "cppa/util/type_list.hpp"
namespace cppa { // forward declarations
template<typename R>
class typed_continue_helper;
} // namespace cppa
namespace cppa { namespace detail {
template<typename R, typename T>
struct deduce_signature_helper;
template<typename R, typename... Ts>
struct deduce_signature_helper<R, util::type_list<Ts...>> {
typedef typename replies_to<Ts...>::template with<R> type;
};
template<typename... Rs, typename... Ts>
struct deduce_signature_helper<cow_tuple<Rs...>, util::type_list<Ts...>> {
typedef typename replies_to<Ts...>::template with<Rs...> type;
};
template<typename T>
struct deduce_signature {
typedef typename detail::implicit_conversions<
typename T::second_type::result_type
>::type
result_type;
typedef typename util::tl_map<
typename T::second_type::arg_types,
util::rm_const_and_ref
>::type
arg_types;
typedef typename deduce_signature_helper<result_type, arg_types>::type type;
};
template<typename T>
struct match_expr_has_no_guard {
static constexpr bool value = std::is_same<
typename T::second_type::guard_type,
detail::empty_value_guard
>::value;
};
template<typename Arguments>
struct input_is {
template<typename Signature>
struct eval {
static constexpr bool value = std::is_same<
Arguments,
typename Signature::input_types
>::value;
};
};
template<typename OutputList, typename F>
inline void assert_types() {
typedef typename util::tl_map<
typename util::get_callable_trait<F>::arg_types,
util::rm_const_and_ref
>::type
arg_types;
static constexpr size_t fun_args = util::tl_size<arg_types>::value;
static_assert(fun_args <= util::tl_size<OutputList>::value,
"functor takes too much arguments");
typedef typename util::tl_right<OutputList, fun_args>::type recv_types;
static_assert(std::is_same<arg_types, recv_types>::value,
"wrong functor signature");
}
template<typename T>
struct lifted_result_type {
typedef util::type_list<T> type;
};
template<typename... Ts>
struct lifted_result_type<cow_tuple<Ts...>> {
typedef util::type_list<Ts...> type;
};
template<typename T>
struct deduce_output_type_step2 {
typedef T type;
};
template<typename R>
struct deduce_output_type_step2<util::type_list<typed_continue_helper<R>>> {
typedef typename lifted_result_type<R>::type type;
};
template<typename Signatures, typename InputTypes>
struct deduce_output_type {
static constexpr int input_pos = util::tl_find_if<
Signatures,
input_is<InputTypes>::template eval
>::value;
static_assert(input_pos >= 0, "typed actor does not support given input");
typedef typename util::tl_at<Signatures, input_pos>::type signature;
typedef typename deduce_output_type_step2<
typename signature::output_types
>::type
type;
};
} } // namespace cppa::detail
#endif // CPPA_TYPED_ACTOR_UTIL_HPP
......@@ -28,8 +28,8 @@
\******************************************************************************/
#ifndef MESSAGE_FUTURE_HPP
#define MESSAGE_FUTURE_HPP
#ifndef CPPA_MESSAGE_FUTURE_HPP
#define CPPA_MESSAGE_FUTURE_HPP
#include <cstdint>
#include <type_traits>
......@@ -40,42 +40,47 @@
#include "cppa/behavior.hpp"
#include "cppa/match_expr.hpp"
#include "cppa/message_id.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/util/type_traits.hpp"
#include "cppa/detail/typed_actor_util.hpp"
namespace cppa {
/**
* @brief Represents the result of a synchronous send.
* @brief Provides the @p continue_with member function as used in
* <tt>sync_send(...).then(...).continue_with(...)</tt>.
*/
class message_future {
class continue_helper {
public:
class continue_helper {
inline continue_helper(message_id mid) : m_mid(mid) { }
public:
template<typename F>
void continue_with(F fun) {
auto ref_opt = self->bhvr_stack().sync_handler(m_mid);
if (ref_opt) {
auto& ref = *ref_opt;
// copy original behavior
behavior cpy = ref;
ref = cpy.add_continuation(on(any_vals, arg_match) >> fun);
}
else CPPA_LOG_ERROR(".continue_with: failed to add continuation");
}
inline continue_helper(message_id mid) : m_mid(mid) { }
private:
template<typename F>
void continue_with(F fun) {
auto ref_opt = self->bhvr_stack().sync_handler(m_mid);
if (ref_opt) {
auto& ref = *ref_opt;
// copy original behavior
behavior cpy = ref;
ref = cpy.add_continuation(std::move(fun));
}
else CPPA_LOG_ERROR(".continue_with: failed to add continuation");
}
message_id m_mid;
private:
};
message_id m_mid;
/**
* @brief Represents the result of a synchronous send.
*/
class message_future {
};
public:
message_future() = delete;
......@@ -165,6 +170,55 @@ class message_future {
};
template<typename R>
class typed_continue_helper {
public:
typedef typename detail::lifted_result_type<R>::type result_types;
typed_continue_helper(continue_helper ch) : m_ch(std::move(ch)) { }
template<typename F>
void continue_with(F fun) {
detail::assert_types<result_types, F>();
m_ch.continue_with(std::move(fun));
}
private:
continue_helper m_ch;
};
template<typename OutputList>
class typed_message_future {
public:
typed_message_future(message_future&& mf) : m_mf(std::move(mf)) { }
template<typename F>
void await(F fun) {
detail::assert_types<OutputList, F>();
m_mf.await(fun);
}
template<typename F>
typed_continue_helper<
typename util::get_callable_trait<F>::result_type
>
then(F fun) {
detail::assert_types<OutputList, F>();
return m_mf.then(fun);
}
private:
message_future m_mf;
};
class sync_handle_helper {
public:
......@@ -172,7 +226,7 @@ class sync_handle_helper {
inline sync_handle_helper(const message_future& mf) : m_mf(mf) { }
template<typename... Ts>
inline message_future::continue_helper operator()(Ts&&... args) {
inline continue_helper operator()(Ts&&... args) {
return m_mf.then(std::forward<Ts>(args)...);
}
......@@ -223,4 +277,4 @@ inline sync_receive_helper receive_response(const message_future& f) {
} // namespace cppa
#endif // MESSAGE_FUTURE_HPP
#endif // CPPA_MESSAGE_FUTURE_HPP
......@@ -185,7 +185,8 @@ class primitive_variant {
*/
template<typename V>
primitive_variant(V&& value) : m_ptype(pt_null) {
static constexpr primitive_type ptype = detail::type_to_ptype<V>::ptype;
typedef typename util::rm_const_and_ref<V>::type raw_type;
static constexpr auto ptype = detail::type_to_ptype<raw_type>::ptype;
static_assert(ptype != pt_null, "V is not a primitive type");
detail::ptv_set<ptype>(m_ptype,
get(util::pt_token<ptype>()),
......@@ -219,7 +220,8 @@ class primitive_variant {
*/
template<typename V>
primitive_variant& operator=(V&& value) {
static constexpr primitive_type ptype = detail::type_to_ptype<V>::ptype;
typedef typename util::rm_const_and_ref<V>::type raw_type;
static constexpr primitive_type ptype = detail::type_to_ptype<raw_type>::ptype;
static_assert(ptype != pt_null, "V is not a primitive type");
util::pt_token<ptype> token;
if (ptype == m_ptype) {
......@@ -228,7 +230,6 @@ class primitive_variant {
else {
destroy();
detail::ptv_set<ptype>(m_ptype, get(token), std::forward<V>(value));
//set(std::forward<V>(value));
}
return *this;
}
......@@ -276,7 +277,9 @@ class primitive_variant {
template<typename T>
const T& get(const primitive_variant& pv) {
static const primitive_type ptype = detail::type_to_ptype<T>::ptype;
return pv.get_as<ptype>();
// this cast shuts down annoying erorrs such as
// "reference to 'char' cannot bind to 'signed char'"
return reinterpret_cast<const T&>(pv.get_as<ptype>());
}
/**
......@@ -290,7 +293,9 @@ const T& get(const primitive_variant& pv) {
template<typename T>
T& get_ref(primitive_variant& pv) {
static const primitive_type ptype = detail::type_to_ptype<T>::ptype;
return pv.get_as<ptype>();
// this cast shuts down annoying erorrs such as
// "reference to 'char' cannot bind to 'signed char'"
return reinterpret_cast<T&>(pv.get_as<ptype>());
}
/**
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_REPLIES_TO_HPP
#define CPPA_REPLIES_TO_HPP
#include "cppa/util/type_list.hpp"
namespace cppa {
template<typename... Is>
struct replies_to {
template<typename... Os>
struct with {
typedef util::type_list<Is...> input_types;
typedef util::type_list<Os...> output_types;
};
};
} // namespace cppa
#endif // CPPA_REPLIES_TO_HPP
......@@ -44,7 +44,7 @@
#include "cppa/attachable.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/spawn_options.hpp"
#include "cppa/scheduled_actor.hpp"
//#include "cppa/scheduled_actor.hpp"
#include "cppa/util/duration.hpp"
......@@ -53,7 +53,9 @@
namespace cppa {
class self_type;
class scheduled_actor;
class scheduler_helper;
typedef intrusive_ptr<scheduled_actor> scheduled_actor_ptr;
namespace detail { class singleton_manager; } // namespace detail
/**
......@@ -140,7 +142,8 @@ class scheduler {
/**
* @brief Executes @p ptr in this scheduler.
*/
virtual local_actor_ptr exec(spawn_options opts, scheduled_actor_ptr ptr) = 0;
virtual local_actor_ptr exec(spawn_options opts,
scheduled_actor_ptr ptr) = 0;
/**
* @brief Creates a new actor from @p actor_behavior and executes it
......
......@@ -34,9 +34,10 @@
#include "cppa/self.hpp"
#include "cppa/actor.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/message_header.hpp"
#include "cppa/message_future.hpp"
#include "cppa/typed_actor_ptr.hpp"
#include "cppa/util/duration.hpp"
......@@ -47,6 +48,9 @@ namespace cppa {
* @{
*/
/**
* @brief Stores sender, receiver, and message priority.
*/
struct destination_header {
channel_ptr receiver;
message_priority priority;
......@@ -118,18 +122,7 @@ inline void send_as(actor_ptr from, channel_ptr whom, Ts&&... what) {
* message cannot be received by another actor.
* @throws std::invalid_argument if <tt>whom == nullptr</tt>
*/
inline message_future sync_send_tuple(actor_ptr whom, any_tuple what) {
if (!whom) throw std::invalid_argument("whom == nullptr");
auto req = self->new_request_id();
message_header hdr{self, std::move(whom), req};
if (self->chaining_enabled()) {
if (hdr.receiver->chained_enqueue(hdr, std::move(what))) {
self->chained_actor(hdr.receiver.downcast<actor>());
}
}
else hdr.deliver(std::move(what));
return req.response_id();
}
message_future sync_send_tuple(actor_ptr whom, any_tuple what);
/**
* @brief Sends <tt>{what...}</tt> as a synchronous message to @p whom.
......@@ -148,6 +141,33 @@ inline message_future sync_send(actor_ptr whom, Ts&&... what) {
make_any_tuple(std::forward<Ts>(what)...));
}
/**
* @brief Sends <tt>{what...}</tt> as a synchronous message to @p whom.
* @param whom Receiver of the message.
* @param what Message elements.
* @returns A handle identifying a future to the response of @p whom.
* @warning The returned handle is actor specific and the response to the sent
* message cannot be received by another actor.
* @pre <tt>sizeof...(Ts) > 0</tt>
* @throws std::invalid_argument if <tt>whom == nullptr</tt>
*/
template<typename... Signatures, typename... Ts>
typed_message_future<
typename detail::deduce_output_type<
util::type_list<Signatures...>,
util::type_list<
typename detail::implicit_conversions<
typename util::rm_const_and_ref<
Ts
>::type
>::type...
>
>::type
>
sync_send(const typed_actor_ptr<Signatures...>& whom, Ts&&... what) {
return sync_send(whom.unbox(), std::forward<Ts>(what)...);
}
/**
* @brief Sends a message to @p whom that is delayed by @p rel_time.
* @param whom Receiver of the message.
......@@ -338,6 +358,27 @@ inline void delayed_reply(const std::chrono::duration<Rep, Period>& rtime,
delayed_reply_tuple(rtime, make_any_tuple(std::forward<Ts>(what)...));
}
/**
* @brief Sends an exit message to @p whom with @p reason.
*
* This function is syntactic sugar for
* <tt>send(whom, atom("EXIT"), reason)</tt>.
* @pre <tt>reason != exit_reason::normal</tt>
*/
inline void send_exit(actor_ptr whom, std::uint32_t rsn) {
CPPA_REQUIRE(rsn != exit_reason::normal);
send(std::move(whom), atom("EXIT"), rsn);
}
/**
* @brief Sends an exit message to @p whom with @p reason.
* @pre <tt>reason != exit_reason::normal</tt>
*/
template<typename... Signatures>
void send_exit(const typed_actor_ptr<Signatures...>& whom, std::uint32_t rsn) {
send_exit(whom.unbox(), rsn);
}
/**
* @}
*/
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_SPAWN_HPP
#define CPPA_SPAWN_HPP
#include <type_traits>
#include "cppa/threaded.hpp"
#include "cppa/scheduler.hpp"
#include "cppa/typed_actor.hpp"
#include "cppa/prioritizing.hpp"
#include "cppa/spawn_options.hpp"
#include "cppa/event_based_actor.hpp"
namespace cppa {
/** @cond PRIVATE */
inline actor_ptr eval_sopts(spawn_options opts, local_actor_ptr ptr) {
CPPA_LOGF_INFO("spawned new local actor with ID " << ptr->id()
<< " of type " << detail::demangle(typeid(*ptr)));
if (has_monitor_flag(opts)) self->monitor(ptr);
if (has_link_flag(opts)) self->link_to(ptr);
return std::move(ptr);
}
/** @endcond */
/**
* @ingroup ActorCreation
* @{
*/
/**
* @brief Spawns a new {@link actor} that evaluates given arguments.
* @param args A functor followed by its arguments.
* @tparam Options Optional flags to modify <tt>spawn</tt>'s behavior.
* @returns An {@link actor_ptr} to the spawned {@link actor}.
*/
template<spawn_options Options = no_spawn_options, typename... Ts>
actor_ptr spawn(Ts&&... args) {
static_assert(sizeof...(Ts) > 0, "too few arguments provided");
return eval_sopts(Options,
get_scheduler()->exec(Options,
scheduler::init_callback{},
std::forward<Ts>(args)...));
}
/**
* @brief Spawns an actor of type @p Impl.
* @param args Constructor arguments.
* @tparam Impl Subtype of {@link event_based_actor} or {@link sb_actor}.
* @tparam Options Optional flags to modify <tt>spawn</tt>'s behavior.
* @returns An {@link actor_ptr} to the spawned {@link actor}.
*/
template<class Impl, spawn_options Options = no_spawn_options, typename... Ts>
actor_ptr spawn(Ts&&... args) {
static_assert(std::is_base_of<event_based_actor, Impl>::value,
"Impl is not a derived type of event_based_actor");
scheduled_actor_ptr ptr;
if (has_priority_aware_flag(Options)) {
using derived = typename extend<Impl>::template with<threaded, prioritizing>;
ptr = make_counted<derived>(std::forward<Ts>(args)...);
}
else if (has_detach_flag(Options)) {
using derived = typename extend<Impl>::template with<threaded>;
ptr = make_counted<derived>(std::forward<Ts>(args)...);
}
else ptr = make_counted<Impl>(std::forward<Ts>(args)...);
return eval_sopts(Options, get_scheduler()->exec(Options, std::move(ptr)));
}
/**
* @brief Spawns a new actor that evaluates given arguments and
* immediately joins @p grp.
* @param args A functor followed by its arguments.
* @tparam Options Optional flags to modify <tt>spawn</tt>'s behavior.
* @returns An {@link actor_ptr} to the spawned {@link actor}.
* @note The spawned has joined the group before this function returns.
*/
template<spawn_options Options = no_spawn_options, typename... Ts>
actor_ptr spawn_in_group(const group_ptr& grp, Ts&&... args) {
static_assert(sizeof...(Ts) > 0, "too few arguments provided");
auto init_cb = [=](local_actor* ptr) {
ptr->join(grp);
};
return eval_sopts(Options,
get_scheduler()->exec(Options,
init_cb,
std::forward<Ts>(args)...));
}
/**
* @brief Spawns an actor of type @p Impl that immediately joins @p grp.
* @param args Constructor arguments.
* @tparam Impl Subtype of {@link event_based_actor} or {@link sb_actor}.
* @tparam Options Optional flags to modify <tt>spawn</tt>'s behavior.
* @returns An {@link actor_ptr} to the spawned {@link actor}.
* @note The spawned has joined the group before this function returns.
*/
template<class Impl, spawn_options Options = no_spawn_options, typename... Ts>
actor_ptr spawn_in_group(const group_ptr& grp, Ts&&... args) {
auto ptr = make_counted<Impl>(std::forward<Ts>(args)...);
ptr->join(grp);
return eval_sopts(Options, get_scheduler()->exec(Options, ptr));
}
template<spawn_options Options, typename... Ts>
typed_actor_ptr<typename detail::deduce_signature<Ts>::type...>
spawn_typed(const match_expr<Ts...>& me) {
typedef typed_actor_ptr<replies_to<std::string>::template with<int>> ta;
static_assert(util::conjunction<
detail::match_expr_has_no_guard<Ts>::value...
>::value,
"typed actors are not allowed to use guard expressions");
typedef util::type_list<
typename detail::deduce_signature<Ts>::arg_types...
>
args;
static_assert(util::tl_is_distinct<args>::value,
"typed actors are not allowed to define multiple patterns "
"with identical signature");
auto ptr = make_counted<typed_actor<match_expr<Ts...>>>(me);
return {eval_sopts(Options, get_scheduler()->exec(Options, std::move(ptr)))};
}
template<typename... Ts>
typed_actor_ptr<typename detail::deduce_signature<Ts>::type...>
spawn_typed(const match_expr<Ts...>& me) {
return spawn_typed<no_spawn_options>(me);
}
template<typename T0, typename T1, typename... Ts>
auto spawn_typed(T0&& v0, T1&& v1, Ts&&... vs)
-> decltype(spawn_typed(match_expr_collect(std::forward<T0>(v0),
std::forward<T1>(v1),
std::forward<Ts>(vs)...))) {
return spawn_typed(match_expr_collect(std::forward<T0>(v0),
std::forward<T1>(v1),
std::forward<Ts>(vs)...));
}
/** @} */
} // namespace cppa
#endif // CPPA_SPAWN_HPP
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_TYPED_ACTOR_HPP
#define CPPA_TYPED_ACTOR_HPP
#include "cppa/replies_to.hpp"
#include "cppa/message_future.hpp"
#include "cppa/event_based_actor.hpp"
#include "cppa/detail/typed_actor_util.hpp"
namespace cppa {
struct typed_actor_result_visitor {
inline void operator()(const none_t&) const {
CPPA_LOG_ERROR("a typed actor received a "
"non-matching message: "
<< to_string(self->last_dequeued()));
}
inline void operator()() const { }
template<typename T>
inline void operator()(T& value) const {
reply(std::move(value));
}
template<typename... Ts>
inline void operator()(cow_tuple<Ts...>& value) const {
reply_tuple(std::move(value));
}
template<typename R>
inline void operator()(typed_continue_helper<R>& ch) const {
auto hdl = self->make_response_handle();
ch.continue_with([=](R value) {
reply_to(hdl, std::move(value));
});
}
template<typename... Rs>
inline void operator()(typed_continue_helper<cow_tuple<Rs...>>& ch) const {
auto hdl = self->make_response_handle();
ch.continue_with([=](cow_tuple<Rs...> value) {
reply_tuple_to(hdl, std::move(value));
});
}
};
template<typename MatchExpr>
class typed_actor : public event_based_actor {
public:
typed_actor(MatchExpr expr) : m_fun(std::move(expr)) { }
protected:
void init() override {
m_bhvr_stack.push_back(partial_function{
on<anything>() >> [=] {
auto result = m_fun(last_dequeued());
apply_visitor(typed_actor_result_visitor{}, result);
}
});
}
virtual void do_become(behavior&&, bool) override {
CPPA_LOG_ERROR("typed actors are not allowed to call become()");
quit(exit_reason::unallowed_function_call);
}
private:
MatchExpr m_fun;
};
} // namespace cppa
#endif // CPPA_TYPED_ACTOR_HPP
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_TYPED_ACTOR_PTR_HPP
#define CPPA_TYPED_ACTOR_PTR_HPP
#include "cppa/replies_to.hpp"
#include "cppa/match_expr.hpp"
#include "cppa/spawn_options.hpp"
#include "cppa/detail/typed_actor_util.hpp"
namespace cppa {
template<typename... Signatures>
class typed_actor_ptr;
// functions that need access to typed_actor_ptr::unbox()
template<spawn_options Options, typename... Ts>
typed_actor_ptr<typename detail::deduce_signature<Ts>::type...>
spawn_typed(const match_expr<Ts...>&);
template<typename... Ts>
void send_exit(const typed_actor_ptr<Ts...>&, std::uint32_t);
template<typename... Ts, typename... Us>
typed_message_future<
typename detail::deduce_output_type<
util::type_list<Ts...>,
util::type_list<
typename detail::implicit_conversions<
typename util::rm_const_and_ref<
Us
>::type
>::type...
>
>::type
>
sync_send(const typed_actor_ptr<Ts...>&, Us&&...);
template<typename... Signatures>
class typed_actor_ptr {
template<spawn_options Options, typename... Ts>
friend typed_actor_ptr<typename detail::deduce_signature<Ts>::type...>
spawn_typed(const match_expr<Ts...>&);
template<typename... Ts>
friend void send_exit(const typed_actor_ptr<Ts...>&, std::uint32_t);
template<typename... Ts, typename... Us>
friend typed_message_future<
typename detail::deduce_output_type<
util::type_list<Ts...>,
util::type_list<
typename detail::implicit_conversions<
typename util::rm_const_and_ref<
Us
>::type
>::type...
>
>::type
>
sync_send(const typed_actor_ptr<Ts...>&, Us&&...);
public:
typedef util::type_list<Signatures...> signatures;
typed_actor_ptr() = default;
typed_actor_ptr(typed_actor_ptr&&) = default;
typed_actor_ptr(const typed_actor_ptr&) = default;
typed_actor_ptr& operator=(typed_actor_ptr&&) = default;
typed_actor_ptr& operator=(const typed_actor_ptr&) = default;
private:
const actor_ptr& unbox() const { return m_ptr; }
typed_actor_ptr(actor_ptr ptr) : m_ptr(std::move(ptr)) { }
actor_ptr m_ptr;
};
} // namespace cppa
#endif // CPPA_TYPED_ACTOR_PTR_HPP
......@@ -22,6 +22,13 @@ add(distributed_calculator remote_actors)
add(group_server remote_actors)
add(group_chat remote_actors)
find_package(CURL)
if (CURL_FOUND)
add_executable(curl_fuse curl/curl_fuse.cpp)
target_link_libraries(curl_fuse ${CMAKE_DL_LIBS} ${CPPA_LIBRARY} ${PTHREAD_LIBRARIES} ${CURL_LIBRARY})
add_dependencies(curl_fuse all_examples)
endif (CURL_FOUND)
if (NOT "${CPPA_NO_QT_EXAMPLES}" STREQUAL "yes")
find_package(Qt4)
......
......@@ -33,6 +33,56 @@
namespace cppa {
class continuation_decorator : public detail::behavior_impl {
typedef behavior_impl super;
public:
typedef typename behavior_impl::pointer pointer;
continuation_decorator(const partial_function& fun, pointer ptr)
: super(ptr->timeout()), m_fun(fun), m_decorated(std::move(ptr)) {
CPPA_REQUIRE(m_decorated != nullptr);
}
template<typename T>
inline optional<any_tuple> invoke_impl(T& tup) {
auto res = m_decorated->invoke(tup);
if (res) return m_fun(*res);
return none;
}
optional<any_tuple> invoke(any_tuple& tup) {
return invoke_impl(tup);
}
optional<any_tuple> invoke(const any_tuple& tup) {
return invoke_impl(tup);
}
bool defined_at(const any_tuple& tup) {
return m_decorated->defined_at(tup);
}
pointer copy(const generic_timeout_definition& tdef) const {
return new continuation_decorator(m_fun, m_decorated->copy(tdef));
}
void handle_timeout() { m_decorated->handle_timeout(); }
private:
partial_function m_fun;
pointer m_decorated;
};
behavior::behavior(const partial_function& fun) : m_impl(fun.m_impl) { }
behavior behavior::add_continuation(const partial_function& fun) {
return {new continuation_decorator(fun, m_impl)};
}
} // namespace cppa
......@@ -34,6 +34,19 @@
namespace cppa {
message_future sync_send_tuple(actor_ptr whom, any_tuple what) {
if (!whom) throw std::invalid_argument("whom == nullptr");
auto req = self->new_request_id();
message_header hdr{self, std::move(whom), req};
if (self->chaining_enabled()) {
if (hdr.receiver->chained_enqueue(hdr, std::move(what))) {
self->chained_actor(hdr.receiver.downcast<actor>());
}
}
else hdr.deliver(std::move(what));
return req.response_id();
}
void delayed_send_tuple(const channel_ptr& to,
const util::duration& rel_time,
any_tuple data) {
......
......@@ -305,254 +305,42 @@ void high_priority_testee() {
);
}
template<typename... Is>
struct replies_to {
template<typename... Os>
struct with {
typedef util::type_list<Is...> input_types;
typedef util::type_list<Os...> output_types;
};
};
struct high_priority_testee_class : event_based_actor {
void init() {
high_priority_testee();
}
};
template<typename R, typename T>
struct deduce_signature_helper;
template<typename R, typename... Ts>
struct deduce_signature_helper<R, util::type_list<Ts...>> {
typedef typename replies_to<Ts...>::template with<R> type;
};
template<typename... Rs, typename... Ts>
struct deduce_signature_helper<cow_tuple<Rs...>, util::type_list<Ts...>> {
typedef typename replies_to<Ts...>::template with<Rs...> type;
};
template<typename T>
struct deduce_signature {
typedef typename detail::implicit_conversions<
typename T::second_type::result_type
>::type
result_type;
typedef typename util::tl_map<
typename T::second_type::arg_types,
util::rm_const_and_ref
>::type
arg_types;
typedef typename deduce_signature_helper<result_type, arg_types>::type type;
};
template<typename T>
struct match_expr_has_no_guard {
static constexpr bool value = std::is_same<
typename T::second_type::guard_type,
detail::empty_value_guard
>::value;
};
/* <EXPERIMENTAL TYPED ACTORS> */
template<typename... Signatures>
class typed_actor_ptr;
template<spawn_options Options, typename... Ts>
typed_actor_ptr<typename deduce_signature<Ts>::type...>
spawn_typed(const match_expr<Ts...>& me);
template<typename... Signatures>
class typed_actor_ptr {
template<spawn_options Options, typename... Ts>
friend typed_actor_ptr<typename deduce_signature<Ts>::type...>
spawn_typed(const match_expr<Ts...>& me);
public:
typedef util::type_list<Signatures...> signatures;
typed_actor_ptr() = default;
typed_actor_ptr(typed_actor_ptr&&) = default;
typed_actor_ptr(const typed_actor_ptr&) = default;
typed_actor_ptr& operator=(typed_actor_ptr&&) = default;
typed_actor_ptr& operator=(const typed_actor_ptr&) = default;
/** @cond PRIVATE */
const actor_ptr& unbox() const { return m_ptr; }
/** @endcond */
private:
typed_actor_ptr(actor_ptr ptr) : m_ptr(std::move(ptr)) { }
actor_ptr m_ptr;
};
class typed_actor : public event_based_actor {
public:
template<typename MatchExpr>
typed_actor(MatchExpr&& expr) : m_fun(std::forward<MatchExpr>(expr)) { }
protected:
void init() override {
m_bhvr_stack.push_back(partial_function{
on<anything>() >> [=] {
auto result = m_fun(last_dequeued());
if (result) reply_tuple(*result);
else {
CPPA_LOG_ERROR("a typed actor received a "
"non-matching message: "
<< to_string(last_dequeued()));
}
}
});
}
virtual void do_become(behavior&&, bool) override {
CPPA_LOG_ERROR("typed actors are not allowed to call become()");
quit(exit_reason::unallowed_function_call);
}
private:
partial_function m_fun;
};
template<spawn_options Options, typename... Ts>
typed_actor_ptr<typename deduce_signature<Ts>::type...>
spawn_typed(const match_expr<Ts...>& me) {
typedef typed_actor_ptr<replies_to<std::string>::template with<int>> ta;
static_assert(util::conjunction<match_expr_has_no_guard<Ts>::value...>::value,
"typed actors are not allowed to use guard expressions");
typedef util::type_list<typename deduce_signature<Ts>::arg_types...> args;
static_assert(util::tl_is_distinct<args>::value,
"typed actors are not allowed to define multiple patterns "
"with identical signature");
auto ptr = make_counted<typed_actor>(me);
return {eval_sopts(Options, get_scheduler()->exec(Options, std::move(ptr)))};
}
template<typename... Ts>
typed_actor_ptr<typename deduce_signature<Ts>::type...>
spawn_typed(const match_expr<Ts...>& me) {
return spawn_typed<no_spawn_options>(me);
}
template<typename T0, typename T1, typename... Ts>
auto spawn_typed(T0&& v0, T1&& v1, Ts&&... vs)
-> decltype(spawn_typed(match_expr_collect(std::forward<T0>(v0),
std::forward<T1>(v1),
std::forward<Ts>(vs)...))) {
return spawn_typed(match_expr_collect(std::forward<T0>(v0),
std::forward<T1>(v1),
std::forward<Ts>(vs)...));
}
template<typename Arguments>
struct input_is {
template<typename Signature>
struct eval {
static constexpr bool value = std::is_same<
Arguments,
typename Signature::input_types
>::value;
};
};
template<typename Signatures, typename InputTypes>
struct deduce_output_type {
static constexpr int input_pos = util::tl_find_if<
Signatures,
input_is<InputTypes>::template eval
>::value;
static_assert(input_pos >= 0, "typed actor does not support given input");
typedef typename util::tl_at<Signatures, input_pos>::type signature;
typedef typename signature::output_types type;
};
template<typename OutputList>
struct typed_sync_send_helper {
typed_sync_send_helper(message_future&& mf) : m_mf(std::move(mf)) { }
template<typename F>
void await(F fun) {
typedef typename util::tl_map<
typename util::get_callable_trait<F>::arg_types,
util::rm_const_and_ref
>::type
arg_types;
static constexpr size_t fun_args = util::tl_size<arg_types>::value;
static_assert(fun_args <= util::tl_size<OutputList>::value,
"functor takes too much arguments");
typedef typename util::tl_right<OutputList, fun_args>::type recv_types;
static_assert(std::is_same<arg_types, recv_types>::value,
"wrong functor signature");
m_mf.await(fun);
}
private:
message_future m_mf;
};
template<typename... Signatures, typename... Ts>
typed_sync_send_helper<
typename deduce_output_type<
util::type_list<Signatures...>,
util::type_list<Ts...>
>::type
>
sync_send(const typed_actor_ptr<Signatures...>& whom, Ts&&... what) {
return sync_send(whom.unbox(), std::forward<Ts>(what)...);
}
/* </EXPERIMENTAL TYPED ACTORS> */
int main() {
CPPA_TEST(test_spawn);
/* <EXPERIMENTAL TYPED ACTORS> */
void test_typed_actors() {
auto ptr0 = spawn_typed(
on_arg_match >> [](double d) {
return d * d;
}
);
CPPA_CHECK((std::is_same<
decltype(ptr0),
typed_actor_ptr<
replies_to<double>::with<double>
>
>::value));
auto ptr = spawn_typed(
on<int>() >> [] { return "wtf"; },
on<string>() >> [] { return 42; },
on<float>() >> [] { return make_cow_tuple(1, 2, 3); },
on<double>() >> [] { }
on<double>() >> [=](double d) {
return sync_send(ptr0, d).then(
[](double res) { return res + res; }
);
}
);
sync_send(ptr, 10.0).await(
[](double d) {
CPPA_CHECK_EQUAL(d, 200.0);
}
);
sync_send(ptr, 42).await(
[](const std::string& str) {
cout << "42 => " << str << endl;
CPPA_CHECK_EQUAL(str, "wtf");
}
);
sync_send(ptr, 1.2f).await(
......@@ -576,15 +364,20 @@ int main() {
sync_send(ptr, 1.2f).await(
[] { CPPA_CHECKPOINT(); }
);
send_exit(ptr0, exit_reason::user_defined);
send_exit(ptr, exit_reason::user_defined);
await_all_others_done();
CPPA_CHECKPOINT();
}
send_exit(ptr.unbox(), exit_reason::user_defined);
/* </EXPERIMENTAL TYPED ACTORS> */
int main() {
CPPA_TEST(test_spawn);
cout << "sizeof(event_based_actor) = " << sizeof(event_based_actor) << endl;
cout << "sizeof(broker) = " << sizeof(io::broker) << endl;
test_typed_actors();
CPPA_PRINT("test send()");
send(self, 1, 2, 3, true);
receive(on(1, 2, 3, true) >> [] { });
......
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