Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
Actor Framework
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cpp-libs
Actor Framework
Commits
19fa65e0
Commit
19fa65e0
authored
Oct 14, 2016
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improve variant and its unit test
parent
45c5452c
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
135 additions
and
59 deletions
+135
-59
libcaf_core/caf/variant.hpp
libcaf_core/caf/variant.hpp
+44
-50
libcaf_core/test/variant.cpp
libcaf_core/test/variant.cpp
+91
-9
No files found.
libcaf_core/caf/variant.hpp
View file @
19fa65e0
...
...
@@ -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
...
...
libcaf_core/test/variant.cpp
View file @
19fa65e0
...
...
@@ -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.2
f
;
CAF_CHECK_EQUAL
(
apply_visitor
(
tv
,
v2
),
to_string
(
0.2
f
));
// 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
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment