Commit 19fa65e0 authored by Dominik Charousset's avatar Dominik Charousset

Improve variant and its unit test

parent 45c5452c
......@@ -31,19 +31,9 @@
#include "caf/detail/type_traits.hpp"
#include "caf/detail/variant_data.hpp"
#define CAF_VARIANT_CASE(x) \
case x: \
return visitor(from.get( \
std::integral_constant<int, (x < max_type_id ? x : max_type_id)>()))
#define CAF_VARIANT_DISPATCH_CASE(n) \
case n: { \
using tmp_t = typename detail::tl_at< \
detail::type_list<Ts...>, \
(n < sizeof...(Ts) ? n : 0) \
>::type; \
return f(get<tmp_t>(x.x)); \
}
#define CAF_VARIANT_CASE(n) \
case n: \
return f(x.get(std::integral_constant<int, (n <= max_type_id ? n : 0)>()))
#define CAF_VARIANT_ASSIGN_CASE(n) \
case n: { \
......@@ -112,7 +102,7 @@ public:
static constexpr int max_type_id = sizeof...(Ts) - 1;
static_assert(sizeof...(Ts) < 20, "Too many template arguments");
static_assert(sizeof...(Ts) <= 20, "Too many template arguments");
static_assert(!detail::tl_exists<types, std::is_reference>::value,
"Cannot create a variant of references");
......@@ -190,12 +180,11 @@ public:
int8_t type_tag() {
return static_cast<int8_t>(type_);
}
/// @endcond
private:
template <class Self, typename Visitor>
static typename Visitor::result_type apply_impl(Self& from, Visitor& visitor) {
switch (from.type_) {
template <class Self, class Visitor>
static typename Visitor::result_type
apply_impl(Self& x, Visitor& f) {
switch (x.type_) {
default: CAF_RAISE_ERROR("invalid type found");
CAF_VARIANT_CASE(0);
CAF_VARIANT_CASE(1);
......@@ -217,10 +206,11 @@ private:
CAF_VARIANT_CASE(17);
CAF_VARIANT_CASE(18);
CAF_VARIANT_CASE(19);
CAF_VARIANT_CASE(20);
}
}
/// @endcond
private:
inline void destroy_data() {
if (type_ == -1) return; // nothing to do
detail::variant_data_destructor f;
......@@ -258,6 +248,11 @@ private:
other.apply(helper);
}
template <class... Us>
void set(variant<Us...>& other) {
set(const_cast<const variant<Us...>&>(other));
}
template <class... Us>
void set(variant<Us...>&& other) {
using namespace detail;
......@@ -311,23 +306,26 @@ const T* get(const variant<Us...>* value) {
/// @relates variant
template <class Visitor, class... Ts>
typename Visitor::result_type apply_visitor(Visitor& visitor,
const variant<Ts...>& data) {
typename Visitor::result_type
apply_visitor(Visitor& visitor, const variant<Ts...>& data) {
return data.apply(visitor);
}
/// @relates variant
template <class Visitor, class... Ts>
typename Visitor::result_type apply_visitor(Visitor& visitor,
variant<Ts...>& data) {
typename Visitor::result_type
apply_visitor(Visitor& visitor, variant<Ts...>& data) {
return data.apply(visitor);
}
/// @relates variant
template <class T>
struct variant_compare_helper {
using result_type = bool;
const T& lhs;
variant_compare_helper(const T& lhs_ref) : lhs(lhs_ref) { }
variant_compare_helper(const T& lhs_ref) : lhs(lhs_ref) {
// nop
}
template <class U>
bool operator()(const U& rhs) const {
auto ptr = get<U>(&lhs);
......@@ -335,47 +333,41 @@ struct variant_compare_helper {
}
};
/// @relates variant
template <class... Ts>
bool operator==(const variant<Ts...>& x, const variant<Ts...>& y) {
variant_compare_helper<variant<Ts...>> f{x};
return apply_visitor(f, y);
}
/// @relates variant
template <class T, class... Ts>
bool operator==(const T& x, const variant<Ts...>& y) {
variant_compare_helper<variant<Ts...>> f{y};
return f(x);
}
/// @relates variant
template <class T, class... Ts>
bool operator==(const variant<Ts...>& x, const T& y) {
return y == x;
}
/// @relates variant
template <class T>
struct variant_reader {
int8_t& type_tag;
T& x;
};
/// @relates variant
template <class Inspector, class... Ts>
typename Inspector::result_type
inspect(Inspector& f, variant_reader<variant<Ts...>>& x) {
switch (x.type_tag) {
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);
CAF_VARIANT_DISPATCH_CASE(20);
}
return variant<Ts...>::apply_impl(x.x, f);
}
/// @relates variant
template <class Inspector, class... Ts>
typename std::enable_if<Inspector::reads_state,
typename Inspector::result_type>::type
......@@ -385,12 +377,14 @@ inspect(Inspector& f, variant<Ts...>& x) {
return f(meta::omittable(), type_tag, helper);
}
/// @relates variant
template <class T>
struct variant_writer {
int8_t& type_tag;
T& x;
};
/// @relates variant
template <class Inspector, class... Ts>
typename Inspector::result_type
inspect(Inspector& f, variant_writer<variant<Ts...>>& x) {
......@@ -416,10 +410,10 @@ inspect(Inspector& f, variant_writer<variant<Ts...>>& x) {
CAF_VARIANT_ASSIGN_CASE(17);
CAF_VARIANT_ASSIGN_CASE(18);
CAF_VARIANT_ASSIGN_CASE(19);
CAF_VARIANT_ASSIGN_CASE(20);
}
}
/// @relates variant
template <class Inspector, class... Ts>
typename std::enable_if<Inspector::writes_state,
typename Inspector::result_type>::type
......
......@@ -24,7 +24,13 @@
#include <string>
#include "caf/none.hpp"
#include "caf/variant.hpp"
#include "caf/actor_system.hpp"
#include "caf/deep_to_string.hpp"
#include "caf/binary_serializer.hpp"
#include "caf/binary_deserializer.hpp"
#include "caf/actor_system_config.hpp"
using namespace std;
using namespace caf;
......@@ -36,13 +42,89 @@ struct tostring_visitor : static_visitor<string> {
}
};
CAF_TEST(string_convertible) {
tostring_visitor tv;
// test never-empty guarantee, i.e., expect default-constucted first arg
variant<int, float> v1;
CAF_CHECK_EQUAL(apply_visitor(tv, v1), "0");
variant<int, float> v2 = 42;
CAF_CHECK_EQUAL(apply_visitor(tv, v2), "42");
v2 = 0.2f;
CAF_CHECK_EQUAL(apply_visitor(tv, v2), to_string(0.2f));
// 20 integer wrappers for building a variant with 20 distint types
#define i_n(n) \
class i##n { \
public: \
i##n(int y = 0) : x(y) { \
} \
i##n(i##n&& other) : x(other.x) { \
other.x = 0; \
} \
i##n& operator=(i##n&& other) { \
x = other.x; \
other.x = 0; \
return *this; \
} \
i##n(const i##n&) = default; \
i##n& operator=(const i##n&) = default; \
int x; \
}; \
bool operator==(int x, i##n y) { \
return x == y.x; \
} \
bool operator==(i##n x, int y) { \
return y == x; \
} \
bool operator==(i##n x, i##n y) { \
return x.x == y.x; \
} \
template <class Inspector> \
typename Inspector::result_type inspect(Inspector& f, i##n& x) { \
return f(meta::type_name(CAF_STR(i##n)), x.x); \
}
#define macro_repeat20(macro) \
macro(01) macro(02) macro(03) macro(04) macro(05) macro(06) macro(07) \
macro(08) macro(09) macro(10) macro(11) macro(12) macro(13) macro(14) \
macro(15) macro(16) macro(17) macro(18) macro(19) macro(20)
macro_repeat20(i_n)
// a variant with 20 element types
using v20 = variant<i01, i02, i03, i04, i05, i06, i07, i08, i09, i10,
i11, i12, i13, i14, i15, i16, i17, i18, i19, i20>;
#define announce_n(n) cfg.add_message_type<i##n>(CAF_STR(i##n));
#define v20_test(n) \
x3 = i##n{0x##n}; \
CAF_CHECK_EQUAL(deep_to_string(x3), CAF_STR(i##n) + std::string("(") \
+ std::to_string(0x##n) + ")"); \
CAF_CHECK_EQUAL(v20{x3}, i##n{0x##n}); \
x4 = x3; \
CAF_CHECK_EQUAL(x4, i##n{0x##n}); \
CAF_CHECK_EQUAL(v20{std::move(x3)}, i##n{0x##n}); \
CAF_CHECK_EQUAL(x3, i##n{0}); \
x3 = std::move(x4); \
CAF_CHECK_EQUAL(x4, i##n{0}); \
CAF_CHECK_EQUAL(x3, i##n{0x##n}); \
{ \
std::vector<char> buf; \
binary_serializer bs{sys.dummy_execution_unit(), buf}; \
inspect(bs, x3); \
CAF_CHECK_EQUAL(x3, i##n{0x##n}); \
v20 tmp; \
binary_deserializer bd{sys.dummy_execution_unit(), buf}; \
inspect(bd, tmp); \
CAF_CHECK_EQUAL(tmp, i##n{0x##n}); \
CAF_CHECK_EQUAL(tmp, x3); \
}
// copy construction, copy assign, move construction, move assign
// and finally serialization round-trip
CAF_TEST(copying_moving_roundtrips) {
actor_system_config cfg;
macro_repeat20(announce_n)
actor_system sys{cfg};
// default construction
variant<none_t> x1;
CAF_CHECK_EQUAL(x1, none);
variant<int, none_t> x2;
CAF_CHECK_EQUAL(x2, 0);
v20 x3;
CAF_CHECK_EQUAL(x3, i01{0});
v20 x4;
macro_repeat20(v20_test);
}
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