Commit eb1fb939 authored by Dominik Charousset's avatar Dominik Charousset

fixed partial_function args in match_expr_concat

parent c25d2453
......@@ -112,9 +112,6 @@ class behavior {
*/
behavior add_continuation(continuation_fun fun);
//template<typename F>
//inline behavior add_continuation(F fun);
private:
impl_ptr m_impl;
......
......@@ -44,6 +44,7 @@
namespace cppa {
class partial_function;
typedef optional<any_tuple> bhvr_invoke_result;
} // namespace cppa
......@@ -224,6 +225,11 @@ default_behavior_impl<dummy_match_expr, F>* new_default_behavior(util::duration
typedef intrusive_ptr<behavior_impl> behavior_impl_ptr;
// implemented in partial_function.cpp
behavior_impl_ptr combine(behavior_impl_ptr, const partial_function&);
behavior_impl_ptr combine(const partial_function&, behavior_impl_ptr);
behavior_impl_ptr extract(const partial_function&);
} } // namespace cppa::detail
#endif // BEHAVIOR_IMPL_HPP
......@@ -108,7 +108,7 @@ inline void assert_types() {
template<typename T>
struct lifted_result_type {
typedef util::type_list<T> type;
typedef util::type_list<typename detail::implicit_conversions<T>::type> type;
};
template<typename... Ts>
......
......@@ -520,8 +520,8 @@ Result unroll_expr(PPFPs& fs,
}
// PPFP = projection_partial_function_pair
template<class PPFPs, class Tuple>
inline bool can_unroll_expr(PPFPs&, minus1l, const std::type_info&, const Tuple&) {
template<class PPFPs, class T>
inline bool can_unroll_expr(PPFPs&, minus1l, const std::type_info&, const T&) {
return false;
}
......@@ -906,21 +906,40 @@ match_expr_collect(const T& arg, const Ts&... args) {
namespace detail {
typedef std::true_type with_timeout;
typedef std::false_type without_timeout;
// with timeout
//typedef std::true_type with_timeout;
//typedef std::false_type without_timeout;
// end of recursion
template<class Data, class Token>
behavior_impl_ptr concat_rec(const Data& data, Token) {
typedef typename match_expr_from_type_list<Token>::type combined_type;
auto lvoid = [] { };
typedef default_behavior_impl<combined_type, decltype(lvoid)> impl_type;
return new impl_type(data, util::duration{}, lvoid);
}
// end of recursion with nothing but a partial function
inline behavior_impl_ptr concat_rec(const tdata<>&,
util::empty_type_list,
const partial_function& pfun) {
return extract(pfun);
}
// end of recursion with timeout
template<class Data, class Token, typename F>
behavior_impl* concat_rec(const Data& data, Token, const timeout_definition<F>& arg) {
behavior_impl_ptr concat_rec(const Data& data,
Token,
const timeout_definition<F>& arg) {
typedef typename match_expr_from_type_list<Token>::type combined_type;
return new default_behavior_impl<combined_type, F>{data, arg};
}
// recursive concatenation function
template<class Data, class Token, typename T, typename... Ts>
behavior_impl* concat_rec(const Data& data, Token, const T& arg, const Ts&... args) {
behavior_impl_ptr concat_rec(const Data& data,
Token,
const T& arg,
const Ts&... args) {
typedef typename util::tl_concat<
Token,
typename T::cases_list
......@@ -938,57 +957,41 @@ behavior_impl* concat_rec(const Data& data, Token, const T& arg, const Ts&... ar
return concat_rec(next_data, next_token, args...);
}
template<typename F>
behavior_impl* concat_expr(with_timeout, const timeout_definition<F>& arg) {
typedef default_behavior_impl<dummy_match_expr, F> impl_type;
return new impl_type(dummy_match_expr{}, arg);
// handle partial functions at end of recursion
template<class Data, class Token>
behavior_impl_ptr concat_rec(const Data& data,
Token token,
const partial_function& pfun) {
return combine(concat_rec(data, token), pfun);
}
template<typename T, typename... Ts>
behavior_impl* concat_expr(with_timeout, const T& arg, const Ts&... args) {
typename tdata_from_type_list<
typename util::tl_map<
typename T::cases_list,
gref_wrapped
>::type
>::type
wrapper;
detail::rebind_tdata(wrapper, arg.cases());
return concat_rec(wrapper, typename T::cases_list{}, args...);
// handle partial functions in between
template<class Data, class Token, typename T, typename... Ts>
behavior_impl_ptr concat_rec(const Data& data,
Token token,
const partial_function& pfun,
const T& arg,
const Ts&... args) {
auto lhs = concat_rec(data, token);
detail::tdata<> dummy;
auto rhs = concat_rec(dummy, util::empty_type_list{}, arg, args...);
return combine(lhs, pfun)->or_else(rhs);
}
// without timeout
// handle partial functions at recursion start
template<typename T, typename... Ts>
behavior_impl* concat_expr(without_timeout, const T& arg, const Ts&... args) {
typename tdata_from_type_list<
typename util::tl_map<
typename util::tl_concat<
typename T::cases_list,
typename Ts::cases_list...
>::type,
gref_wrapped
>::type
>::type
all_cases;
typedef typename match_expr_from_type_list<
typename util::tl_concat<
typename T::cases_list,
typename Ts::cases_list...
>::type
>::type
combined_type;
auto lvoid = [] { };
typedef default_behavior_impl<combined_type, decltype(lvoid)> impl_type;
rebind_tdata(all_cases, arg.cases(), args.cases()...);
return new impl_type(all_cases, util::duration{}, lvoid);
behavior_impl_ptr concat_rec(const tdata<>& data,
util::empty_type_list token,
const partial_function& pfun,
const T& arg,
const Ts&... args) {
return combine(pfun, concat_rec(data, token, arg, args...));
}
template<typename T, typename... Ts>
behavior_impl_ptr match_expr_concat(const T& arg, const Ts&... args) {
std::integral_constant<bool, util::disjunction<T::may_have_timeout, Ts::may_have_timeout...>::value> token;
// use static call dispatch to select correct function
return concat_expr(token, arg, args...);
detail::tdata<> dummy;
return concat_rec(dummy, util::empty_type_list{}, arg, args...);
}
} // namespace detail
......
......@@ -62,13 +62,13 @@ class continue_helper {
inline continue_helper(message_id mid) : m_mid(mid) { }
template<typename F>
void continue_with(F fun) {
continue_with(behavior::continuation_fun{partial_function{
continue_helper& continue_with(F fun) {
return continue_with(behavior::continuation_fun{partial_function{
on(any_vals, arg_match) >> fun
}});
}
inline void continue_with(behavior::continuation_fun fun) {
inline continue_helper& continue_with(behavior::continuation_fun fun) {
auto ref_opt = self->bhvr_stack().sync_handler(m_mid);
if (ref_opt) {
auto& ref = *ref_opt;
......@@ -77,6 +77,7 @@ class continue_helper {
ref = cpy.add_continuation(std::move(fun));
}
else CPPA_LOG_ERROR(".continue_with: failed to add continuation");
return *this;
}
inline message_id get_message_id() const {
......@@ -196,9 +197,41 @@ class typed_continue_helper {
typed_continue_helper(continue_helper ch) : m_ch(std::move(ch)) { }
template<typename F>
void continue_with(F fun) {
typed_continue_helper<typename util::get_callable_trait<F>::result_type>
continue_with(F fun) {
detail::assert_types<result_types, F>();
m_ch.continue_with(std::move(fun));
return {m_ch};
}
inline message_id get_message_id() const {
return m_ch.get_message_id();
}
private:
continue_helper m_ch;
};
/*
template<>
class typed_continue_helper<void> {
public:
typedef int message_id_wrapper_tag;
typedef util::type_list<void> result_types;
typed_continue_helper(continue_helper ch) : m_ch(std::move(ch)) { }
template<typename F>
void continue_with(F fun) {
using arg_types = typename util::get_callable_trait<F>::arg_types;
static_assert(std::is_same<util::empty_type_list, arg_types>::value,
"functor takes too much arguments");
m_ch.continue_with(std::move(fun));
}
inline message_id get_message_id() const {
......@@ -210,6 +243,7 @@ class typed_continue_helper {
continue_helper m_ch;
};
*/
template<typename OutputList>
class typed_message_future {
......
......@@ -65,7 +65,7 @@ class partial_function {
typedef intrusive_ptr<detail::behavior_impl> impl_ptr;
inline auto as_behavior_impl() const -> const impl_ptr&;
inline auto as_behavior_impl() const -> impl_ptr;
partial_function(impl_ptr ptr);
......@@ -142,7 +142,7 @@ match_expr_convert(const T0& arg0, const T1& arg1, const Ts&... args) {
template<typename... Cases>
partial_function operator,(const match_expr<Cases...>& mexpr,
const partial_function& pfun) {
return mexpr.as_behavior_impl()->or_else(pfun.as_behavior_impl);
return mexpr.as_behavior_impl()->or_else(pfun.as_behavior_impl());
}
/******************************************************************************
......@@ -177,7 +177,7 @@ partial_function::or_else(Ts&&... args) const {
return m_impl->or_else(tmp.as_behavior_impl());
}
inline auto partial_function::as_behavior_impl() const -> const impl_ptr& {
inline auto partial_function::as_behavior_impl() const -> impl_ptr {
return m_impl;
}
......
......@@ -40,3 +40,19 @@ partial_function::partial_function(impl_ptr ptr) : m_impl(std::move(ptr)) { }
void detail::behavior_impl::handle_timeout() { }
} // namespace cppa
namespace cppa { namespace detail {
behavior_impl_ptr combine(behavior_impl_ptr lhs, const partial_function& rhs) {
return lhs->or_else(rhs.as_behavior_impl());
}
behavior_impl_ptr combine(const partial_function& lhs, behavior_impl_ptr rhs) {
return lhs.as_behavior_impl()->or_else(rhs);
}
behavior_impl_ptr extract(const partial_function& arg) {
return arg.as_behavior_impl();
}
} } // namespace cppa::detail
......@@ -390,10 +390,86 @@ void test_serial_reply() {
}
void test_or_else() {
partial_function handle_a {
on("a") >> [] { return 1; }
};
partial_function handle_b {
on("b") >> [] { return 2; }
};
partial_function handle_c {
on("c") >> [] { return 3; }
};
auto run_testee([](actor_ptr testee) {
sync_send(testee, "a").await([](int i) {
CPPA_CHECK_EQUAL(i, 1);
});
sync_send(testee, "b").await([](int i) {
CPPA_CHECK_EQUAL(i, 2);
});
sync_send(testee, "c").await([](int i) {
CPPA_CHECK_EQUAL(i, 3);
});
send_exit(testee, exit_reason::user_shutdown);
await_all_others_done();
});
run_testee(
spawn([=] {
become(handle_a.or_else(handle_b).or_else(handle_c));
})
);
run_testee(
spawn([=] {
become(handle_a, handle_b, handle_c);
})
);
run_testee(
spawn([=] {
become(
handle_a.or_else(handle_b),
on("c") >> [] { return 3; }
);
})
);
run_testee(
spawn([=] {
become(
on("a") >> [] { return 1; },
handle_b.or_else(handle_c)
);
})
);
}
void test_continuation() {
auto mirror = spawn<simple_mirror>();
spawn([=] {
sync_send(mirror, 42).then(
on(42) >> [] {
return "fourty-two";
}
).continue_with(
[=](const string& ref) {
CPPA_CHECK_EQUAL(ref, "fourty-two");
return 4.2f;
}
).continue_with(
[=](float f) {
CPPA_CHECK_EQUAL(f, 4.2f);
send_exit(mirror, exit_reason::user_shutdown);
self->quit();
}
);
});
await_all_others_done();
}
int main() {
CPPA_TEST(test_spawn);
test_serial_reply();
test_or_else();
test_continuation();
// check whether detached actors and scheduled actors interact w/o errors
auto m = spawn<master, detached>();
......
......@@ -153,8 +153,26 @@ int main() {
sync_send(ptr, 1.2f).await(
[] { CPPA_CHECKPOINT(); }
);
send_exit(ptr0, exit_reason::user_shutdown);
send_exit(ptr, exit_reason::user_shutdown);
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_others_done();
CPPA_CHECKPOINT();
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