Commit 9aa81913 authored by Dominik Charousset's avatar Dominik Charousset

Simplify implementation of behaviors

parent 37b08840
......@@ -54,12 +54,6 @@ class message_handler;
namespace caf {
namespace detail {
template <class... Ts>
struct has_skip {
static constexpr bool value =
disjunction<std::is_same<Ts, skip_t>::value...>::value;
};
class behavior_impl : public ref_counted {
public:
using pointer = intrusive_ptr<behavior_impl>;
......@@ -95,154 +89,143 @@ protected:
match_case_info* end_;
};
template <size_t Pos, size_t Size>
struct defaut_bhvr_impl_init {
template <class Array, class Tuple>
static void init(Array& arr, Tuple& tup) {
auto& x = arr[Pos];
x.ptr = &std::get<Pos>(tup);
x.type_token = x.ptr->type_token();
defaut_bhvr_impl_init<Pos + 1, Size>::init(arr, tup);
}
template <class Tuple>
void call_timeout_handler(Tuple& tup, std::true_type) {
auto& f = std::get<std::tuple_size<Tuple>::value - 1>(tup);
f.handler();
}
template <class Tuple>
void call_timeout_handler(Tuple&, std::false_type) {
// nop
}
template <class T, bool IsTimeout = is_timeout_definition<T>::value>
struct lift_behavior {
using type = trivial_match_case<T>;
};
template <size_t Size>
struct defaut_bhvr_impl_init<Size, Size> {
template <class Array, class Tuple>
static void init(Array&, Tuple&) {
// nop
}
template <class T>
struct lift_behavior<T, true> {
using type = T;
};
template <bool HasTimeout, class Tuple>
struct with_generic_timeout;
template <class... Ts>
struct with_generic_timeout<false, std::tuple<Ts...>> {
using type = std::tuple<Ts..., generic_timeout_definition>;
};
template <class... Ts>
struct with_generic_timeout<true, std::tuple<Ts...>> {
using type =
typename tl_apply<
typename tl_replace_back<
type_list<Ts...>,
generic_timeout_definition
>::type,
std::tuple
>::type;
};
template <class Tuple>
class default_behavior_impl : public behavior_impl {
class default_behavior_impl;
template <class... Ts>
class default_behavior_impl<std::tuple<Ts...>> : public behavior_impl {
public:
static constexpr size_t num_cases = std::tuple_size<Tuple>::value;
using tuple_type = std::tuple<Ts...>;
template <class T>
default_behavior_impl(const T& tup) : cases_(std::move(tup)) {
init();
}
using back_type = typename tl_back<type_list<Ts...>>::type;
static constexpr bool has_timeout = is_timeout_definition<back_type>::value;
static constexpr size_t num_cases = sizeof...(Ts) - (has_timeout ? 1 : 0);
using cases =
typename std::conditional<
has_timeout,
typename tl_pop_back<type_list<Ts...>>::type,
type_list<Ts...>
>::type;
template <class T, class F>
default_behavior_impl(const T& tup, const timeout_definition<F>& d)
: behavior_impl(d.timeout),
cases_(tup),
fun_(d.handler) {
default_behavior_impl(tuple_type&& tup) : cases_(std::move(tup)) {
init();
}
typename behavior_impl::pointer
copy(const generic_timeout_definition& tdef) const override {
return make_counted<default_behavior_impl<Tuple>>(cases_, tdef);
template <class... Us>
default_behavior_impl(Us&&... xs) : cases_(std::forward<Us>(xs)...) {
init();
}
void handle_timeout() override {
fun_();
std::integral_constant<bool, has_timeout> token;
call_timeout_handler(cases_, token);
}
typename behavior_impl::pointer
copy(const generic_timeout_definition& td) const override;
private:
void init() {
defaut_bhvr_impl_init<0, num_cases>::init(arr_, cases_);
begin_ = arr_.data();
end_ = begin_ + arr_.size();
std::integral_constant<size_t, 0> first;
std::integral_constant<size_t, num_cases> last;
init(first, last);
}
Tuple cases_;
std::array<match_case_info, num_cases> arr_;
std::function<void()> fun_;
};
template <size_t Last>
void init(std::integral_constant<size_t, Last>,
std::integral_constant<size_t, Last>) {
this->begin_ = arr_.data();
this->end_ = arr_.data() + arr_.size();
std::integral_constant<bool, has_timeout> token;
set_timeout(token);
}
// eor = end of recursion
// ra = reorganize arguments
template <size_t First, size_t Last>
void init(std::integral_constant<size_t, First>,
std::integral_constant<size_t, Last> last) {
auto& element = std::get<First>(cases_);
arr_[First] = match_case_info{element.type_token(), &element};
init(std::integral_constant<size_t, First + 1>{}, last);
}
template <class R, class... Ts>
intrusive_ptr<R> make_behavior_eor(const std::tuple<Ts...>& match_cases) {
return make_counted<R>(match_cases);
}
void set_timeout(std::true_type) {
this->timeout_ = std::get<num_cases>(cases_).timeout;
}
template <class R, class... Ts, class F>
intrusive_ptr<R> make_behavior_eor(const std::tuple<Ts...>& match_cases,
const timeout_definition<F>& td) {
return make_counted<R>(match_cases, td);
}
void set_timeout(std::false_type) {
// nop
}
template <class F, bool IsMC = std::is_base_of<match_case, F>::value>
struct lift_to_mctuple {
using type = std::tuple<trivial_match_case<F>>;
tuple_type cases_;
std::array<match_case_info, num_cases> arr_;
};
template <class T>
struct lift_to_mctuple<T, true> {
using type = std::tuple<T>;
template <class Tuple>
struct behavior_factory {
template <class... Ts>
typename behavior_impl::pointer operator()(Ts&&... xs) const {
return make_counted<default_behavior_impl<Tuple>>(std::forward<Ts>(xs)...);
}
};
template <class... Ts>
struct lift_to_mctuple<std::tuple<Ts...>, false> {
using type = std::tuple<Ts...>;
};
template <class F>
struct lift_to_mctuple<timeout_definition<F>, false> {
using type = std::tuple<>;
};
template <class T, class... Ts>
struct join_std_tuples;
template <class T>
struct join_std_tuples<T> {
using type = T;
};
template <class... Prefix, class... Infix, class... Suffix>
struct join_std_tuples<std::tuple<Prefix...>, std::tuple<Infix...>, Suffix...>
: join_std_tuples<std::tuple<Prefix..., Infix...>, Suffix...> {
// nop
};
// this function reorganizes its arguments to shift the timeout definition
// to the front (receives it at the tail)
template <class R, class F, class... Ts>
intrusive_ptr<R> make_behavior_ra(const timeout_definition<F>& td,
const tail_argument_token&, const Ts&... xs) {
return make_behavior_eor<R>(std::tuple_cat(to_match_case_tuple(xs)...), td);
}
template <class R, class... Ts>
intrusive_ptr<R> make_behavior_ra(const tail_argument_token&, const Ts&... xs) {
return make_behavior_eor<R>(std::tuple_cat(to_match_case_tuple(xs)...));
}
// for some reason, this call is ambigious on GCC without enable_if
template <class R, class T, class... Ts>
typename std::enable_if<
! std::is_same<T, tail_argument_token>::value,
intrusive_ptr<R>
>::type
make_behavior_ra(const T& x, const Ts&... xs) {
return make_behavior_ra<R>(xs..., x);
typename behavior_impl::pointer
default_behavior_impl<std::tuple<Ts...>>::copy(const generic_timeout_definition& td) const {
using tuple_type = typename with_generic_timeout<has_timeout, std::tuple<Ts...>>::type;
behavior_factory<tuple_type> factory;// = &make_counted<default_behavior_impl<tuple_type>>;
typename il_range<0, num_cases>::type indices;
return apply_args_suffxied(factory, indices, cases_, td);
}
// this function reorganizes its arguments to shift the timeout definition
// to the front (receives it at the tail)
template <class... Ts>
intrusive_ptr<
default_behavior_impl<
typename join_std_tuples<
typename lift_to_mctuple<Ts>::type...
>::type
>>
make_behavior(const Ts&... xs) {
using result_type =
default_behavior_impl<
typename join_std_tuples<
typename lift_to_mctuple<Ts>::type...
>::type
>;
tail_argument_token eoa;
return make_behavior_ra<result_type>(xs..., eoa);
intrusive_ptr<default_behavior_impl<std::tuple<typename lift_behavior<Ts>::type...>>>
make_behavior(Ts... xs) {
using type = default_behavior_impl<std::tuple<typename lift_behavior<Ts>::type...>>;
return make_counted<type>(std::move(xs)...);
}
using behavior_impl_ptr = intrusive_ptr<behavior_impl>;
......
......@@ -111,6 +111,14 @@ get_right_indices(const T&) {
return {};
}
template <long First, long Last, long... Is>
struct il_range : il_range<First + 1, Last, Is..., First> {};
template <long Last, long... Is>
struct il_range<Last, Last, Is...> {
using type = int_list<Is...>;
};
} // namespace detail
} // namespace caf
......
......@@ -632,6 +632,22 @@ struct tl_pop_back<empty_type_list> {
using type = empty_type_list;
};
// list replace_back()
/// Creates a new list with all but the last element of `List`
/// and append `T` to the new list.
template <class List, class Back, class Intermediate = type_list<>>
struct tl_replace_back;
template <class T0, class T1, class... Ts, class Back, class... Us>
struct tl_replace_back<type_list<T0, T1, Ts...>, Back, type_list<Us...>>
: tl_replace_back<type_list<T1, Ts...>, Back, type_list<Us..., T0>> {};
template <class T, class Back, class... Us>
struct tl_replace_back<type_list<T>, Back, type_list<Us...>> {
using type = type_list<Us..., Back>;
};
// type at(size_t)
template <size_t N, class... E>
......@@ -1037,7 +1053,7 @@ template <class ListA, class ListB>
struct tl_subset_of<ListA, ListB, false> : std::false_type {};
template <class T, class... Ts, class List>
struct tl_subset_of<type_list<T, Ts...>, List>
struct tl_subset_of<type_list<T, Ts...>, List>
: tl_subset_of<type_list<Ts...>, List, tl_contains<List, T>::value> {};
/// Tests whether ListA contains the same elements as ListB
......
......@@ -21,6 +21,7 @@
#define CAF_TIMEOUT_DEFINITION_HPP
#include <functional>
#include <type_traits>
#include "caf/duration.hpp"
......@@ -37,13 +38,37 @@ behavior_impl* new_default_behavior(duration d, std::function<void()> fun);
template <class F>
struct timeout_definition {
static constexpr bool may_have_timeout = true;
duration timeout;
F handler;
detail::behavior_impl* as_behavior_impl() const {
return detail::new_default_behavior(timeout, handler);
}
timeout_definition() = default;
timeout_definition(timeout_definition&&) = default;
timeout_definition(const timeout_definition&) = default;
timeout_definition(duration d, F&& f) : timeout(d), handler(std::move(f)) {
// nop
}
template <class U>
timeout_definition(const timeout_definition<U>& other)
: timeout(other.timeout),
handler(other.handler) {
// nop
}
};
template <class T>
struct is_timeout_definition : std::false_type {};
template <class T>
struct is_timeout_definition<timeout_definition<T>> : std::true_type {};
using generic_timeout_definition = timeout_definition<std::function<void()>>;
} // namespace caf
......
......@@ -164,7 +164,7 @@ public:
template <class T, class... Ts>
typed_behavior(T x, Ts... xs) {
set(detail::make_behavior(x, xs...));
set(detail::make_behavior(std::move(x), std::move(xs)...));
}
struct unsafe_init { };
......@@ -209,7 +209,12 @@ private:
template <class... Ts>
void set(intrusive_ptr<detail::default_behavior_impl<std::tuple<Ts...>>> bp) {
using mpi = detail::type_list<typename detail::deduce_mpi<Ts>::type...>;
using impl = detail::default_behavior_impl<std::tuple<Ts...>>;
using mpi =
typename detail::tl_map<
typename impl::cases,
detail::deduce_mpi
>::type;
static_assert(detail::tl_is_distinct<mpi>::value,
"multiple handler defintions found");
detail::static_asserter<signatures, mpi, detail::ctm>::verify_match();
......
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