Commit 90b06d78 authored by Dominik Charousset's avatar Dominik Charousset

Add missing `anon_send` for typed actors

Move `check_typed_input` to its own header, add `anon_send` for typed actors
and do some cleanup in `local_actor`.
parent c3b37711
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2014 *
* 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 LICENCE_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_CHECK_TYPED_INPUT_HPP
#define CAF_CHECK_TYPED_INPUT_HPP
#include "caf/detail/type_list.hpp"
#include "caf/detail/typed_actor_util.hpp"
namespace caf {
/**
* Checks whether `R` does support an input of type `{Ls...}` via a
* static assertion (always returns 0).
*/
template <template <class...> class R, class... Rs,
template <class...> class L, class... Ls>
constexpr int check_typed_input(const R<Rs...>&, const L<Ls...>&) {
static_assert(detail::tl_find_if<
detail::type_list<Rs...>,
detail::input_is<detail::type_list<Ls...>>::template eval
>::value >= 0, "typed actor does not support given input");
return 0;
}
} // namespace caf
#endif // CAF_CHECK_TYPED_INPUT_HPP
......@@ -42,6 +42,7 @@
#include "caf/message_handler.hpp"
#include "caf/response_promise.hpp"
#include "caf/message_priority.hpp"
#include "caf/check_typed_input.hpp"
#include "caf/mixin/memory_cached.hpp"
......@@ -279,23 +280,31 @@ class local_actor : public extend<abstract_actor>::with<mixin::memory_cached> {
/**
* Checks whether this actor traps exit messages.
*/
inline bool trap_exit() const;
inline bool trap_exit() const {
return m_trap_exit;
}
/**
* Enables or disables trapping of exit messages.
*/
inline void trap_exit(bool new_value);
inline void trap_exit(bool new_value) {
m_trap_exit = new_value;
}
/**
* Returns the last message that was dequeued from the actor's mailbox.
* @warning Only set during callback invocation.
*/
inline message& last_dequeued();
inline message& last_dequeued() {
return m_current_node->msg;
}
/**
* Returns the address of the last sender of the last dequeued message.
*/
inline actor_addr& last_sender();
inline actor_addr& last_sender() {
return m_current_node->sender;
}
/**
* Adds a unidirectional `monitor` to `whom`.
......@@ -437,19 +446,36 @@ class local_actor : public extend<abstract_actor>::with<mixin::memory_cached> {
// returns 0 if last_dequeued() is an asynchronous or sync request message,
// a response id generated from the request id otherwise
inline message_id get_response_id();
inline message_id get_response_id() {
auto id = m_current_node->mid;
return (id.is_request()) ? id.response_id() : message_id();
}
void reply_message(message&& what);
void forward_message(const actor& new_receiver, message_priority prio);
inline bool awaits(message_id response_id);
inline bool awaits(message_id response_id) {
CAF_REQUIRE(response_id.is_response());
return std::any_of(m_pending_responses.begin(), m_pending_responses.end(),
[=](message_id other) { return response_id == other; });
}
inline void mark_arrived(message_id response_id);
inline void mark_arrived(message_id response_id) {
auto last = m_pending_responses.end();
auto i = std::find(m_pending_responses.begin(), last, response_id);
if (i != last) {
m_pending_responses.erase(i);
}
}
inline uint32_t planned_exit_reason() const;
inline uint32_t planned_exit_reason() const {
return m_planned_exit_reason;
}
inline void planned_exit_reason(uint32_t value);
inline void planned_exit_reason(uint32_t value) {
m_planned_exit_reason = value;
}
void cleanup(uint32_t reason) override;
......@@ -459,15 +485,6 @@ class local_actor : public extend<abstract_actor>::with<mixin::memory_cached> {
protected:
template <class... Rs, template <class...> class T, class... Ts>
static void check_typed_input(const typed_actor<Rs...>&, const T<Ts...>&) {
static constexpr int input_pos = detail::tl_find_if<
detail::type_list<Rs...>,
detail::input_is<detail::type_list<Ts...>>::template eval>::value;
static_assert(input_pos >= 0,
"typed actor does not support given input");
}
template <class... Ts>
inline mailbox_element* new_mailbox_element(Ts&&... args) {
return mailbox_element::create(std::forward<Ts>(args)...);
......@@ -510,47 +527,6 @@ class local_actor : public extend<abstract_actor>::with<mixin::memory_cached> {
*/
using local_actor_ptr = intrusive_ptr<local_actor>;
/******************************************************************************
* inline and template member function implementations *
******************************************************************************/
/** @cond PRIVATE */
inline bool local_actor::trap_exit() const { return m_trap_exit; }
inline void local_actor::trap_exit(bool new_value) { m_trap_exit = new_value; }
inline message& local_actor::last_dequeued() { return m_current_node->msg; }
inline actor_addr& local_actor::last_sender() { return m_current_node->sender; }
inline message_id local_actor::get_response_id() {
auto id = m_current_node->mid;
return (id.is_request()) ? id.response_id() : message_id();
}
inline bool local_actor::awaits(message_id response_id) {
CAF_REQUIRE(response_id.is_response());
return std::any_of(m_pending_responses.begin(), m_pending_responses.end(),
[=](message_id other) { return response_id == other; });
}
inline void local_actor::mark_arrived(message_id response_id) {
auto last = m_pending_responses.end();
auto i = std::find(m_pending_responses.begin(), last, response_id);
if (i != last) m_pending_responses.erase(i);
}
inline uint32_t local_actor::planned_exit_reason() const {
return m_planned_exit_reason;
}
inline void local_actor::planned_exit_reason(uint32_t value) {
m_planned_exit_reason = value;
}
/** @endcond */
} // namespace caf
#endif // CAF_CONTEXT_HPP
......@@ -27,6 +27,7 @@
#include "caf/duration.hpp"
#include "caf/response_handle.hpp"
#include "caf/message_priority.hpp"
#include "caf/check_typed_input.hpp"
namespace caf {
namespace mixin {
......@@ -264,7 +265,7 @@ class sync_sender_impl : public Base {
ResponseHandleTag>
sync_send_impl(message_priority prio, const typed_actor<Rs...>& dest,
detail::type_list<Ts...> token, message&& what) {
dptr()->check_typed_input(dest, token);
check_typed_input(dest, token);
return {dptr()->sync_send_tuple_impl(prio, dest, std::move(what)),
dptr()};
}
......
......@@ -23,7 +23,12 @@
#include "caf/actor.hpp"
#include "caf/channel.hpp"
#include "caf/message.hpp"
#include "caf/actor_cast.hpp"
#include "caf/actor_addr.hpp"
#include "caf/message_id.hpp"
#include "caf/typed_actor.hpp"
#include "caf/system_messages.hpp"
#include "caf/check_typed_input.hpp"
namespace caf {
......@@ -31,9 +36,9 @@ namespace caf {
* Sends `to` a message under the identity of `from`.
*/
inline void send_tuple_as(const actor& from, const channel& to, message msg) {
if (to)
to->enqueue(from.address(), message_id::invalid, std::move(msg),
nullptr);
if (to) {
to->enqueue(from.address(), message_id::invalid, std::move(msg), nullptr);
}
}
/**
......@@ -52,24 +57,42 @@ inline void anon_send_tuple(const channel& to, message msg) {
}
/**
* Anonymously sends `to` a message.
* Anonymously sends `whom` a message.
*/
template <class... Ts>
inline void anon_send(const channel& to, Ts&&... args) {
void anon_send(const channel& to, Ts&&... args) {
send_as(invalid_actor, to, std::forward<Ts>(args)...);
}
// implemented in local_actor.cpp
/**
* Anonymously sends `whom` a message.
*/
template <class... Rs, class... Ts>
void anon_send(const typed_actor<Rs...>& whom, Ts&&... args) {
check_typed_input(whom,
detail::type_list<typename detail::implicit_conversions<
typename detail::rm_const_and_ref<Ts>::type
>::type...>{});
anon_send(actor_cast<channel>(whom), std::forward<Ts>(args)...);
}
/**
* Anonymously sends `whom` an exit message.
*/
void anon_send_exit(const actor_addr& whom, uint32_t reason);
inline void anon_send_exit(const actor_addr& whom, uint32_t reason) {
if (!whom){
return;
}
auto ptr = actor_cast<actor>(whom);
ptr->enqueue(invalid_actor_addr, message_id {}.with_high_priority(),
make_message(exit_msg{invalid_actor_addr, reason}), nullptr);
}
/**
* Anonymously sends `whom` an exit message.
*/
template <class ActorHandle>
inline void anon_send_exit(const ActorHandle& whom, uint32_t reason) {
void anon_send_exit(const ActorHandle& whom, uint32_t reason) {
anon_send_exit(whom.address(), reason);
}
......
......@@ -235,13 +235,4 @@ message_id local_actor::sync_send_tuple_impl(message_priority mp,
return nri.response_id();
}
void anon_send_exit(const actor_addr& whom, uint32_t reason) {
if (!whom){
return;
}
auto ptr = actor_cast<actor>(whom);
ptr->enqueue(invalid_actor_addr, message_id {}.with_high_priority(),
make_message(exit_msg{invalid_actor_addr, reason}), nullptr);
}
} // namespace caf
......@@ -35,8 +35,8 @@ namespace io {
template <class List>
struct typed_remote_actor_helper;
template <class... Ts>
struct typed_remote_actor_helper<detail::type_list<Ts...>> {
template <template<class...> class List, class... Ts>
struct typed_remote_actor_helper<List<Ts...>> {
using return_type = typed_actor<Ts...>;
template <class... Vs>
return_type operator()(Vs&&... vs) {
......
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