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

Simplify implementation of behaviors

parent 37b08840
...@@ -54,12 +54,6 @@ class message_handler; ...@@ -54,12 +54,6 @@ class message_handler;
namespace caf { namespace caf {
namespace detail { 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 { class behavior_impl : public ref_counted {
public: public:
using pointer = intrusive_ptr<behavior_impl>; using pointer = intrusive_ptr<behavior_impl>;
...@@ -95,154 +89,143 @@ protected: ...@@ -95,154 +89,143 @@ protected:
match_case_info* end_; match_case_info* end_;
}; };
template <size_t Pos, size_t Size> template <class Tuple>
struct defaut_bhvr_impl_init { void call_timeout_handler(Tuple& tup, std::true_type) {
template <class Array, class Tuple> auto& f = std::get<std::tuple_size<Tuple>::value - 1>(tup);
static void init(Array& arr, Tuple& tup) { f.handler();
auto& x = arr[Pos]; }
x.ptr = &std::get<Pos>(tup);
x.type_token = x.ptr->type_token(); template <class Tuple>
defaut_bhvr_impl_init<Pos + 1, Size>::init(arr, tup); 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> template <class T>
struct defaut_bhvr_impl_init<Size, Size> { struct lift_behavior<T, true> {
template <class Array, class Tuple> using type = T;
static void init(Array&, Tuple&) {
// nop
}
}; };
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> 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: public:
static constexpr size_t num_cases = std::tuple_size<Tuple>::value; using tuple_type = std::tuple<Ts...>;
template <class T> using back_type = typename tl_back<type_list<Ts...>>::type;
default_behavior_impl(const T& tup) : cases_(std::move(tup)) {
init(); 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(tuple_type&& tup) : cases_(std::move(tup)) {
default_behavior_impl(const T& tup, const timeout_definition<F>& d)
: behavior_impl(d.timeout),
cases_(tup),
fun_(d.handler) {
init(); init();
} }
typename behavior_impl::pointer template <class... Us>
copy(const generic_timeout_definition& tdef) const override { default_behavior_impl(Us&&... xs) : cases_(std::forward<Us>(xs)...) {
return make_counted<default_behavior_impl<Tuple>>(cases_, tdef); init();
} }
void handle_timeout() override { 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: private:
void init() { void init() {
defaut_bhvr_impl_init<0, num_cases>::init(arr_, cases_); std::integral_constant<size_t, 0> first;
begin_ = arr_.data(); std::integral_constant<size_t, num_cases> last;
end_ = begin_ + arr_.size(); init(first, last);
} }
Tuple cases_; template <size_t Last>
std::array<match_case_info, num_cases> arr_; void init(std::integral_constant<size_t, Last>,
std::function<void()> fun_; 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 template <size_t First, size_t Last>
// ra = reorganize arguments 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> void set_timeout(std::true_type) {
intrusive_ptr<R> make_behavior_eor(const std::tuple<Ts...>& match_cases) { this->timeout_ = std::get<num_cases>(cases_).timeout;
return make_counted<R>(match_cases); }
}
template <class R, class... Ts, class F> void set_timeout(std::false_type) {
intrusive_ptr<R> make_behavior_eor(const std::tuple<Ts...>& match_cases, // nop
const timeout_definition<F>& td) { }
return make_counted<R>(match_cases, td);
}
template <class F, bool IsMC = std::is_base_of<match_case, F>::value> tuple_type cases_;
struct lift_to_mctuple { std::array<match_case_info, num_cases> arr_;
using type = std::tuple<trivial_match_case<F>>;
}; };
template <class T> template <class Tuple>
struct lift_to_mctuple<T, true> { struct behavior_factory {
using type = std::tuple<T>; 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> template <class... Ts>
struct lift_to_mctuple<std::tuple<Ts...>, false> { typename behavior_impl::pointer
using type = std::tuple<Ts...>; 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>>;
template <class F> typename il_range<0, num_cases>::type indices;
struct lift_to_mctuple<timeout_definition<F>, false> { return apply_args_suffxied(factory, indices, cases_, td);
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);
} }
// this function reorganizes its arguments to shift the timeout definition
// to the front (receives it at the tail)
template <class... Ts> template <class... Ts>
intrusive_ptr< intrusive_ptr<default_behavior_impl<std::tuple<typename lift_behavior<Ts>::type...>>>
default_behavior_impl< make_behavior(Ts... xs) {
typename join_std_tuples< using type = default_behavior_impl<std::tuple<typename lift_behavior<Ts>::type...>>;
typename lift_to_mctuple<Ts>::type... return make_counted<type>(std::move(xs)...);
>::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);
} }
using behavior_impl_ptr = intrusive_ptr<behavior_impl>; using behavior_impl_ptr = intrusive_ptr<behavior_impl>;
......
...@@ -111,6 +111,14 @@ get_right_indices(const T&) { ...@@ -111,6 +111,14 @@ get_right_indices(const T&) {
return {}; 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 detail
} // namespace caf } // namespace caf
......
...@@ -632,6 +632,22 @@ struct tl_pop_back<empty_type_list> { ...@@ -632,6 +632,22 @@ struct tl_pop_back<empty_type_list> {
using type = 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) // type at(size_t)
template <size_t N, class... E> template <size_t N, class... E>
...@@ -1037,7 +1053,7 @@ template <class ListA, class ListB> ...@@ -1037,7 +1053,7 @@ template <class ListA, class ListB>
struct tl_subset_of<ListA, ListB, false> : std::false_type {}; struct tl_subset_of<ListA, ListB, false> : std::false_type {};
template <class T, class... Ts, class List> 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> {}; : tl_subset_of<type_list<Ts...>, List, tl_contains<List, T>::value> {};
/// Tests whether ListA contains the same elements as ListB /// Tests whether ListA contains the same elements as ListB
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#define CAF_TIMEOUT_DEFINITION_HPP #define CAF_TIMEOUT_DEFINITION_HPP
#include <functional> #include <functional>
#include <type_traits>
#include "caf/duration.hpp" #include "caf/duration.hpp"
...@@ -37,13 +38,37 @@ behavior_impl* new_default_behavior(duration d, std::function<void()> fun); ...@@ -37,13 +38,37 @@ behavior_impl* new_default_behavior(duration d, std::function<void()> fun);
template <class F> template <class F>
struct timeout_definition { struct timeout_definition {
static constexpr bool may_have_timeout = true; static constexpr bool may_have_timeout = true;
duration timeout; duration timeout;
F handler; F handler;
detail::behavior_impl* as_behavior_impl() const { detail::behavior_impl* as_behavior_impl() const {
return detail::new_default_behavior(timeout, handler); 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()>>; using generic_timeout_definition = timeout_definition<std::function<void()>>;
} // namespace caf } // namespace caf
......
...@@ -164,7 +164,7 @@ public: ...@@ -164,7 +164,7 @@ public:
template <class T, class... Ts> template <class T, class... Ts>
typed_behavior(T x, Ts... xs) { 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 { }; struct unsafe_init { };
...@@ -209,7 +209,12 @@ private: ...@@ -209,7 +209,12 @@ private:
template <class... Ts> template <class... Ts>
void set(intrusive_ptr<detail::default_behavior_impl<std::tuple<Ts...>>> bp) { 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, static_assert(detail::tl_is_distinct<mpi>::value,
"multiple handler defintions found"); "multiple handler defintions found");
detail::static_asserter<signatures, mpi, detail::ctm>::verify_match(); 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