Commit c88f290b authored by Dominik Charousset's avatar Dominik Charousset

detail::delegate_helper -> delegated + cleanup

parent eecbf4ec
......@@ -17,20 +17,17 @@
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_DETAIL_DELEGATE_HELPER_HPP
#define CAF_DETAIL_DELEGATE_HELPER_HPP
#ifndef CAF_DELEGATED_HPP
#define CAF_DELEGATED_HPP
namespace caf {
namespace detail {
/// Helper class to indicate that this has been
/// properly forwarded in typed actors.
/// Helper class to indicate that a request has been forwarded.
template <class... Ts>
struct delegate_helper {
struct delegated {
// nop
};
} // namespace detail
} // namespace caf
#endif // CAF_DETAIL_DELEGATE_HELPER_HPP
#endif // CAF_DELEGATED_HPP
......@@ -20,11 +20,11 @@
#ifndef CAF_DETAIL_CTM_HPP
#define CAF_DETAIL_CTM_HPP
#include "caf/delegated.hpp"
#include "caf/replies_to.hpp"
#include "caf/typed_response_promise.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/detail/delegate_helper.hpp"
#include "caf/detail/typed_actor_util.hpp"
namespace caf {
......@@ -43,19 +43,6 @@ struct ctm_cmp<typed_mpi<In, L, R1>,
|| std::is_same<R2, empty_type_list>::value;
};
/*
template <class In, class Out>
struct ctm_cmp<typed_mpi<In, Out, empty_type_list>,
typed_mpi<In, Out, empty_type_list>>
: std::true_type { };
template <class In, class L, class R>
struct ctm_cmp<typed_mpi<In, L, R>,
typed_mpi<In, L, R>>
: std::true_type { };
*/
template <class In, class Out>
struct ctm_cmp<typed_mpi<In, Out, empty_type_list>,
typed_mpi<In, type_list<typed_continue_helper<Out>>, empty_type_list>>
......@@ -76,22 +63,15 @@ struct ctm_cmp<typed_mpi<In, L, R>,
typed_mpi<In, type_list<typed_response_promise<either_or_t<L, R>>>, empty_type_list>>
: std::true_type { };
template <class In, class Out>
struct ctm_cmp<typed_mpi<In, Out, empty_type_list>,
typed_mpi<In, type_list<delegate_helper<>>, empty_type_list>>
: std::true_type { };
template <class In, class L, class R>
struct ctm_cmp<typed_mpi<In, L, R>,
typed_mpi<In, type_list<delegate_helper<either_or_t<L, R>>>, empty_type_list>>
template <class In, class... Ts>
struct ctm_cmp<typed_mpi<In, type_list<Ts...>, empty_type_list>,
typed_mpi<In, type_list<delegated<Ts...>>, empty_type_list>>
: std::true_type { };
/*
template <class In, class L, class R>
struct ctm_cmp<typed_mpi<In, L, R>,
typed_mpi<In, L, empty_type_list>>
typed_mpi<In, type_list<delegated<either_or_t<L, R>>>, empty_type_list>>
: std::true_type { };
*/
template <class In, class L, class R>
struct ctm_cmp<typed_mpi<In, L, R>,
......
......@@ -22,6 +22,7 @@
#include <tuple>
#include "caf/delegated.hpp"
#include "caf/replies_to.hpp"
#include "caf/system_messages.hpp"
......@@ -207,8 +208,16 @@ struct deduce_output_type {
>::value;
static_assert(input_pos != -1, "typed actor does not support given input");
using signature = typename tl_at<Signatures, input_pos>::type;
using type = detail::type_pair<typename signature::output_opt1_types,
typename signature::output_opt2_types>;
using opt1 = typename signature::output_opt1_types;
using opt2 = typename signature::output_opt2_types;
using type = detail::type_pair<opt1, opt2>;
// generates the appropriate `delegated<...>` type from given signatures
using delegated_type =
typename std::conditional<
std::is_same<opt2, detail::empty_type_list>::value,
typename detail::tl_apply<opt1, delegated>::type,
delegated<either_or_t<opt1, opt2>>
>::type;
};
template <class... Ts>
......
......@@ -34,6 +34,7 @@
#include "caf/channel.hpp"
#include "caf/duration.hpp"
#include "caf/behavior.hpp"
#include "caf/delegated.hpp"
#include "caf/spawn_fwd.hpp"
#include "caf/resumable.hpp"
#include "caf/actor_cast.hpp"
......@@ -53,7 +54,6 @@
#include "caf/detail/logging.hpp"
#include "caf/detail/disposer.hpp"
#include "caf/detail/behavior_stack.hpp"
#include "caf/detail/delegate_helper.hpp"
#include "caf/detail/typed_actor_util.hpp"
#include "caf/detail/single_reader_queue.hpp"
#include "caf/detail/memory_cache_flag_type.hpp"
......@@ -461,50 +461,33 @@ public:
void forward_message(const actor& dest, message_priority mp);
template <class... Ts>
detail::delegate_helper<>
delegate(message_priority mp, const actor& dest, Ts&&... xs) {
void delegate(message_priority mp, const actor& dest, Ts&&... xs) {
static_assert(sizeof...(Ts) > 0, "no message to send");
if (! dest) {
return {};
}
if (! dest)
return;
auto mid = current_element_->mid;
current_element_->mid = mp == message_priority::high
? mid.with_high_priority()
: mid.with_normal_priority();
current_element_->msg = make_message(std::forward<Ts>(xs)...);
dest->enqueue(std::move(current_element_), host());
return {};
}
template <class... Ts>
detail::delegate_helper<> delegate(const actor& dest, Ts&&... xs) {
return delegate(message_priority::normal,
dest, std::forward<Ts>(xs)...);
}
template <class... DestSigs, class... Ts>
detail::delegate_helper<
either_or_t<
typename detail::deduce_output_type<
detail::type_list<DestSigs...>,
detail::type_list<
typename detail::implicit_conversions<
typename std::decay<Ts>::type
>::type...
>
>::type::first,
typename detail::deduce_output_type<
detail::type_list<DestSigs...>,
detail::type_list<
typename detail::implicit_conversions<
typename std::decay<Ts>::type
>::type...
>
>::type::second
void delegate(const actor& dest, Ts&&... xs) {
delegate(message_priority::normal, dest, std::forward<Ts>(xs)...);
}
template <class... Sigs, class... Ts>
typename detail::deduce_output_type<
detail::type_list<Sigs...>,
detail::type_list<
typename detail::implicit_conversions<
typename std::decay<Ts>::type
>::type...
>
> delegate(message_priority mp,
const typed_actor<DestSigs...>& dest,
Ts&&... xs) {
>::delegated_type
delegate(message_priority mp, const typed_actor<Sigs...>& dest, Ts&&... xs) {
static_assert(sizeof...(Ts) > 0, "no message to send");
using token =
detail::type_list<
......@@ -513,9 +496,8 @@ public:
>::type...>;
token tk;
check_typed_input(dest, tk);
if (! dest) {
if (! dest)
return {};
}
auto mid = current_element_->mid;
current_element_->mid = mp == message_priority::high
? mid.with_high_priority()
......@@ -525,15 +507,19 @@ public:
return {};
}
template <class... DestSigs, class... Ts>
auto delegate(const typed_actor<DestSigs...>& dest,
Ts&&... xs) -> decltype(delegate(message_priority::normal,
dest,
std::forward<Ts>(xs)...)) {
return delegate(message_priority::normal,
dest, std::forward<Ts>(xs)...);
template <class... Sigs, class... Ts>
typename detail::deduce_output_type<
detail::type_list<Sigs...>,
detail::type_list<
typename detail::implicit_conversions<
typename std::decay<Ts>::type
>::type...
>
>::delegated_type
delegate(const typed_actor<Sigs...>& dest, Ts&&... xs) {
return delegate(message_priority::normal, dest, std::forward<Ts>(xs)...);
}
inline uint32_t planned_exit_reason() const {
return planned_exit_reason_;
}
......
......@@ -49,7 +49,7 @@ static_assert(! std::is_convertible<dummy1, dummy2>::value,
"handle is assignable to broader definition");
/******************************************************************************
* simple request/response test *
* simple request/response test *
******************************************************************************/
struct my_request {
......@@ -138,7 +138,7 @@ void test_typed_spawn(server_type ts) {
}
/******************************************************************************
* test skipping of messages intentionally + using become() *
* test skipping of messages intentionally + using become() *
******************************************************************************/
struct get_state_msg {};
......@@ -184,70 +184,75 @@ public:
};
/******************************************************************************
* simple 'forwarding' chain *
* simple 'forwarding' chain *
******************************************************************************/
using string_actor = typed_actor<replies_to<string>::with<string>>;
void simple_relay(string_actor::pointer self, string_actor master, bool leaf) {
string_actor next =
leaf ? spawn_typed(simple_relay, master, false) : master;
string_actor::behavior_type string_reverter() {
return {
[](string& str) {
std::reverse(str.begin(), str.end());
return std::move(str);
}
};
}
// uses `return sync_send(...).then(...)`
string_actor::behavior_type string_relay(string_actor::pointer self,
string_actor master, bool leaf) {
auto next = leaf ? spawn_typed(string_relay, master, false) : master;
self->link_to(next);
self->become(
return {
[=](const string& str) {
return self->sync_send(next, str).then(
[](const string & answer)->string {
return answer;
[](string& answer) -> string {
return std::move(answer);
}
);
});
}
};
}
void simple_relay_delegate(string_actor::pointer self, string_actor master, bool leaf) {
string_actor next =
leaf ? spawn_typed(simple_relay_delegate, master, false) : master;
// uses `return delegate(...)`
string_actor::behavior_type string_delegator(string_actor::pointer self,
string_actor master, bool leaf) {
auto next = leaf ? spawn_typed(string_delegator, master, false) : master;
self->link_to(next);
self->become(
[=](const string& str) {
return self->delegate(next, str);
});
return {
[=](string& str) -> delegated<string> {
return self->delegate(next, std::move(str));
}
};
}
void dynamic_relay_delegate(string_actor::pointer self, actor master, bool leaf) {
if (leaf) {
auto next = spawn_typed(dynamic_relay_delegate, master, false);
self->link_to(next);
self->become(
[=](const string& str) {
return self->delegate(next, str);
});
} else {
self->link_to(master);
self->become(
[=](const string& str) {
return self->delegate(master, str);
});
}
}
using maybe_string_actor = typed_actor<replies_to<string>
::with_either<ok_atom, string>
::or_else<error_atom>>;
string_actor::behavior_type simple_string_reverter() {
maybe_string_actor::behavior_type maybe_string_reverter() {
return {
[](const string& str) {
return string{str.rbegin(), str.rend()};
[](string& str) -> either<ok_atom, string>::or_else<error_atom> {
if (str.empty())
return {error_atom::value};
std::reverse(str.begin(), str.end());
return {ok_atom::value, std::move(str)};
}
};
}
behavior dynamic_string_reverter() {
maybe_string_actor::behavior_type
maybe_string_delegator(maybe_string_actor::pointer self, maybe_string_actor x) {
self->link_to(x);
return {
[](const string& str) {
return string{str.rbegin(), str.rend()};
[=](string& s) -> delegated<either<ok_atom, string>::or_else<error_atom>> {
return self->delegate(x, std::move(s));
}
};
}
/******************************************************************************
* sending typed actor handles *
* sending typed actor handles *
******************************************************************************/
using int_actor = typed_actor<replies_to<int>::with<int>>;
......@@ -376,48 +381,60 @@ CAF_TEST(test_event_testee) {
CAF_CHECK_EQUAL(result, "wait4int");
}
CAF_TEST(test_simple_string_reverter) {
CAF_TEST(reverter_relay_chain) {
// run test series with string reverter
scoped_actor self;
// actor-under-test
auto aut = self->spawn_typed<monitored>(simple_relay,
spawn_typed(simple_string_reverter),
auto aut = self->spawn_typed<monitored>(string_relay,
spawn_typed(string_reverter),
true);
set<string> iface{"caf::replies_to<@str>::with<@str>"};
CAF_CHECK(aut->message_types() == iface);
self->sync_send(aut, "Hello World!").await([](const string& answer) {
CAF_CHECK_EQUAL(answer, "!dlroW olleH");
});
self->sync_send(aut, "Hello World!").await(
[](const string& answer) {
CAF_CHECK_EQUAL(answer, "!dlroW olleH");
}
);
anon_send_exit(aut, exit_reason::user_shutdown);
}
CAF_TEST(test_simple_string_reverter_delegate) {
CAF_TEST(string_delegator_chain) {
// run test series with string reverter
scoped_actor self;
// actor-under-test
auto aut = self->spawn_typed<monitored>(simple_relay_delegate,
spawn_typed(simple_string_reverter),
auto aut = self->spawn_typed<monitored>(string_delegator,
spawn_typed(string_reverter),
true);
set<string> iface{"caf::replies_to<@str>::with<@str>"};
CAF_CHECK(aut->message_types() == iface);
self->sync_send(aut, "Hello World!").await([](const string& answer) {
CAF_CHECK_EQUAL(answer, "!dlroW olleH");
});
self->sync_send(aut, "Hello World!").await(
[](const string& answer) {
CAF_CHECK_EQUAL(answer, "!dlroW olleH");
}
);
anon_send_exit(aut, exit_reason::user_shutdown);
}
CAF_TEST(test_dynamic_string_reverter_delegate) {
// run test series with string reverter
CAF_TEST(maybe_string_delegator_chain) {
scoped_actor self;
// actor-under-test
auto aut = self->spawn_typed<monitored>(dynamic_relay_delegate,
spawn(dynamic_string_reverter),
true);
set<string> iface{"caf::replies_to<@str>::with<@str>"};
CAF_CHECK(aut->message_types() == iface);
self->sync_send(aut, "Hello World!").await([](const string& answer) {
CAF_CHECK_EQUAL(answer, "!dlroW olleH");
});
auto aut = spawn_typed(maybe_string_delegator,
spawn_typed(maybe_string_reverter));
self->sync_send(aut, "").await(
[](ok_atom, const string&) {
throw std::logic_error("unexpected result!");
},
[](error_atom) {
// nop
}
);
self->sync_send(aut, "abcd").await(
[](ok_atom, const string& str) {
CAF_CHECK_EQUAL(str, "dcba");
},
[](error_atom) {
throw std::logic_error("unexpected error_atom!");
}
);
anon_send_exit(aut, exit_reason::user_shutdown);
}
......
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