Commit a8c7dd29 authored by Dominik Charousset's avatar Dominik Charousset

Merge branch 'topic/multi-variant-visit'

parents 58fc8dd8 3890119e
......@@ -48,6 +48,7 @@ template <class, class, class> class random_topic_scatterer;
// -- variadic templates -------------------------------------------------------
template <class...> class result;
template <class...> class variant;
template <class...> class delegated;
template <class...> class typed_actor;
template <class...> class typed_actor_pointer;
......
......@@ -22,6 +22,7 @@
#include <type_traits>
#include "caf/config.hpp"
#include "caf/fwd.hpp"
#include "caf/static_visitor.hpp"
#include "caf/meta/omittable.hpp"
......@@ -32,7 +33,15 @@
#define CAF_VARIANT_CASE(n) \
case n: \
return f(x.get(std::integral_constant<int, (n <= max_type_id ? n : 0)>()))
return f(std::forward<Us>(xs)..., \
x.get(std::integral_constant<int, (n <= max_type_id ? n : 0)>()))
#define CAF_VARIANT_DISPATCH_CASE(n) \
case n: \
return next.template apply_impl<Result>( \
std::forward<Variant>(next), std::forward<Visitor>(f), \
std::forward<Us>(xs)..., \
x.get(std::integral_constant<int, (n <= max_type_id ? n : 0)>()))
#define CAF_VARIANT_ASSIGN_CASE(n) \
case n: { \
......@@ -48,6 +57,10 @@ namespace caf {
constexpr size_t variant_npos = static_cast<size_t>(-1);
struct variant_marker_t {};
constexpr variant_marker_t variant_marker = variant_marker_t{};
template <class T>
struct variant_assign_helper {
using result_type = void;
......@@ -70,6 +83,17 @@ struct variant_move_helper {
}
};
template <class F, class... Ts>
struct variant_visit_result {
using type =
decltype((std::declval<F&>())(std::declval<typename Ts::type0&>()...));
};
template <class F, class... Ts>
using variant_visit_result_t =
typename variant_visit_result<detail::decay_t<F>,
detail::decay_t<Ts>...>::type;
template <class T, class U,
bool Enable = std::is_integral<T>::value
&& std::is_integral<U>::value
......@@ -95,6 +119,21 @@ struct is_same_ish
is_equal_int_type<T, U>
>::type { };
template <class T>
struct is_variant : std::false_type {};
template <class... Ts>
struct is_variant<variant<Ts...>> : std::true_type {};
template <class... Ts>
struct is_variant<variant<Ts...>&> : std::true_type {};
template <class... Ts>
struct is_variant<const variant<Ts...>&> : std::true_type {};
template <class... Ts>
struct is_variant<const variant<Ts...>&&> : std::true_type {};
/// A variant represents always a valid value of one of the types `Ts...`.
template <class... Ts>
class variant {
......@@ -114,13 +153,13 @@ public:
variant& operator=(const variant& other) {
variant_assign_helper<variant> helper{*this};
other.apply(helper);
other.template apply<void>(helper);
return *this;
}
variant& operator=(variant&& other) {
variant_move_helper<variant> helper{*this};
other.apply(helper);
other.template apply<void>(helper);
return *this;
}
......@@ -144,12 +183,12 @@ public:
variant(const variant& other) : type_(variant_npos) {
variant_assign_helper<variant> helper{*this};
other.apply(helper);
other.template apply<void>(helper);
}
variant(variant&& other) : type_(variant_npos) {
variant_move_helper<variant> helper{*this};
other.apply(helper);
other.template apply<void>(helper);
}
~variant() {
......@@ -191,21 +230,20 @@ public:
return data_.get(token);
}
template <class Visitor>
auto apply(Visitor&& visitor) const
-> decltype(visitor(std::declval<const type0&>())) {
return apply_impl(*this, std::forward<Visitor>(visitor));
template <class Result, class Visitor, class... Variants>
Result apply(Visitor&& visitor, Variants&&... xs) const {
return apply_impl<Result>(*this, std::forward<Visitor>(visitor),
std::forward<Variants>(xs)..., variant_marker);
}
template <class Visitor>
auto apply(Visitor&& visitor) -> decltype(visitor(std::declval<type0&>())) {
return apply_impl(*this, std::forward<Visitor>(visitor));
template <class Result, class Visitor, class... Variants>
Result apply(Visitor&& visitor, Variants&&... xs) {
return apply_impl<Result>(*this, std::forward<Visitor>(visitor),
std::forward<Variants>(xs)..., variant_marker);
}
template <class Self, class Visitor>
static auto apply_impl(Self& x, Visitor&& f) -> decltype(
f(std::declval<typename std::conditional<std::is_const<Self>::value,
const type0, type0>::type&>())) {
template <class Result, class Self, class Visitor, class... Us>
static Result apply_impl(Self& x, Visitor&& f, variant_marker_t, Us&&... xs) {
switch (x.type_) {
default: CAF_RAISE_ERROR("invalid type found");
CAF_VARIANT_CASE(0);
......@@ -230,13 +268,41 @@ public:
CAF_VARIANT_CASE(19);
}
}
template <class Result, class Self, class Visitor, class Variant, class... Us>
static detail::enable_if_t<is_variant<Variant>::value, Result>
apply_impl(Self& x, Visitor&& f, Variant&& next, Us&&... xs) {
switch (x.type_) {
default: CAF_RAISE_ERROR("invalid type found");
CAF_VARIANT_DISPATCH_CASE(0);
CAF_VARIANT_DISPATCH_CASE(1);
CAF_VARIANT_DISPATCH_CASE(2);
CAF_VARIANT_DISPATCH_CASE(3);
CAF_VARIANT_DISPATCH_CASE(4);
CAF_VARIANT_DISPATCH_CASE(5);
CAF_VARIANT_DISPATCH_CASE(6);
CAF_VARIANT_DISPATCH_CASE(7);
CAF_VARIANT_DISPATCH_CASE(8);
CAF_VARIANT_DISPATCH_CASE(9);
CAF_VARIANT_DISPATCH_CASE(10);
CAF_VARIANT_DISPATCH_CASE(11);
CAF_VARIANT_DISPATCH_CASE(12);
CAF_VARIANT_DISPATCH_CASE(13);
CAF_VARIANT_DISPATCH_CASE(14);
CAF_VARIANT_DISPATCH_CASE(15);
CAF_VARIANT_DISPATCH_CASE(16);
CAF_VARIANT_DISPATCH_CASE(17);
CAF_VARIANT_DISPATCH_CASE(18);
CAF_VARIANT_DISPATCH_CASE(19);
}
}
/// @endcond
private:
inline void destroy_data() {
if (type_ == variant_npos) return; // nothing to do
detail::variant_data_destructor f;
apply(f);
apply<void>(f);
}
template <class U>
......@@ -267,7 +333,7 @@ private:
"unless the element types of A are a strict subset of "
"the element types of B");
variant_assign_helper<variant> helper{*this};
other.apply(helper);
other.template apply<void>(helper);
}
template <class... Us>
......@@ -283,19 +349,13 @@ private:
"unless the element types of A are a strict subset of "
"the element types of B");
variant_move_helper<variant> helper{*this};
other.apply(helper);
other.template apply<void>(helper);
}
size_t type_;
detail::variant_data<typename lift_void<Ts>::type...> data_;
};
template <class T>
struct is_variant : std::false_type {};
template <class... Ts>
struct is_variant<variant<Ts...>> : std::true_type {};
/// @relates variant
template <class T, class... Us>
T& get(variant<Us...>& value) {
......@@ -333,28 +393,11 @@ const T* get_if(const variant<Us...>* value) {
}
/// @relates variant
template <class Visitor, class... Ts>
typename Visitor::result_type
CAF_DEPRECATED apply_visitor(Visitor& visitor, const variant<Ts...>& data) {
return data.apply(visitor);
}
/// @relates variant
template <class Visitor, class Variant,
class E =
typename std::enable_if<
is_variant<typename std::decay<Variant>::type>::value
>::type>
auto visit(Visitor&& visitor, Variant&& data)
-> decltype(data.apply(std::forward<Visitor>(visitor))) {
return data.apply(visitor);
}
/// @relates variant
template <class Visitor, class... Ts>
typename Visitor::result_type
CAF_DEPRECATED apply_visitor(Visitor& visitor, variant<Ts...>& data) {
return data.apply(visitor);
template <class Visitor, class Variant, class... Variants,
class Result = variant_visit_result_t<Visitor, Variant, Variants...>>
Result visit(Visitor&& f, Variant&& x, Variants&&... xs) {
return x.template apply<Result>(std::forward<Visitor>(f),
std::forward<Variants>(xs)...);
}
template <class T, class... Ts>
......@@ -408,8 +451,7 @@ struct variant_reader {
template <class Inspector, class... Ts>
typename Inspector::result_type
inspect(Inspector& f, variant_reader<variant<Ts...>>& x) {
return x.x.apply(f);
//return variant<Ts...>::apply_impl(x.x, f);
return x.x.template apply<typename Inspector::result_type>(f);
}
/// @relates variant
......
......@@ -127,3 +127,25 @@ CAF_TEST(copying_moving_roundtrips) {
macro_repeat20(v20_test);
}
namespace {
struct test_visitor {
template <class... Ts>
string operator()(const Ts&... xs) {
return deep_to_string(std::forward_as_tuple(xs...));
}
};
} // namespace <anonymous>
CAF_TEST(n_ary_visit) {
variant<int, string> a{42};
variant<string, atom_value> b{atom("foo")};
variant<float, int, string> c{string{"bar"}};
variant<int, string, double> d{123};
test_visitor f;
CAF_CHECK_EQUAL(visit(f, a, b), "(42, 'foo')");
CAF_CHECK_EQUAL(visit(f, a, b, c), "(42, 'foo', \"bar\")");
CAF_CHECK_EQUAL(visit(f, a, b, c, d), "(42, 'foo', \"bar\", 123)");
}
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