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
57ca0479
Commit
57ca0479
authored
Feb 04, 2015
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'topic/message-lifetime' into develop
parents
a376b31a
e789e5f5
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
252 additions
and
202 deletions
+252
-202
libcaf_core/caf/detail/behavior_impl.hpp
libcaf_core/caf/detail/behavior_impl.hpp
+6
-15
libcaf_core/caf/detail/lifted_fun.hpp
libcaf_core/caf/detail/lifted_fun.hpp
+26
-27
libcaf_core/caf/detail/type_traits.hpp
libcaf_core/caf/detail/type_traits.hpp
+7
-4
libcaf_core/caf/match_expr.hpp
libcaf_core/caf/match_expr.hpp
+48
-103
libcaf_core/caf/policy/invoke_policy.hpp
libcaf_core/caf/policy/invoke_policy.hpp
+2
-2
libcaf_core/caf/variant.hpp
libcaf_core/caf/variant.hpp
+41
-40
libcaf_core/src/behavior_impl.cpp
libcaf_core/src/behavior_impl.cpp
+2
-10
libcaf_core/src/message_data.cpp
libcaf_core/src/message_data.cpp
+1
-0
libcaf_core/src/ref_counted.cpp
libcaf_core/src/ref_counted.cpp
+1
-1
unit_testing/CMakeLists.txt
unit_testing/CMakeLists.txt
+1
-0
unit_testing/test_message_lifetime.cpp
unit_testing/test_message_lifetime.cpp
+117
-0
No files found.
libcaf_core/caf/detail/behavior_impl.hpp
View file @
57ca0479
...
...
@@ -173,8 +173,6 @@ class behavior_impl : public ref_counted {
virtual
bhvr_invoke_result
invoke
(
message
&
)
=
0
;
virtual
bhvr_invoke_result
invoke
(
const
message
&
)
=
0
;
inline
bhvr_invoke_result
invoke
(
message
&&
arg
)
{
message
tmp
(
std
::
move
(
arg
));
return
invoke
(
tmp
);
...
...
@@ -206,7 +204,7 @@ struct dummy_match_expr {
}
};
template
<
class
MatchExpr
,
typename
F
>
template
<
class
MatchExpr
,
class
F
=
std
::
function
<
void
()>
>
class
default_behavior_impl
:
public
behavior_impl
{
public:
template
<
class
Expr
>
...
...
@@ -223,25 +221,18 @@ class default_behavior_impl : public behavior_impl {
// nop
}
bhvr_invoke_result
invoke
(
message
&
tup
)
{
auto
res
=
m_expr
(
tup
);
optional_message_visitor
omv
;
return
apply_visitor
(
omv
,
res
);
}
bhvr_invoke_result
invoke
(
const
message
&
tup
)
{
auto
res
=
m_expr
(
tup
);
bhvr_invoke_result
invoke
(
message
&
msg
)
override
{
auto
res
=
m_expr
(
msg
);
optional_message_visitor
omv
;
return
apply_visitor
(
omv
,
res
);
}
typename
behavior_impl
::
pointer
copy
(
const
generic_timeout_definition
&
tdef
)
const
{
return
new
default_behavior_impl
<
MatchExpr
,
std
::
function
<
void
()
>>
(
m_expr
,
tdef
);
copy
(
const
generic_timeout_definition
&
tdef
)
const
override
{
return
new
default_behavior_impl
<
MatchExpr
>
(
m_expr
,
tdef
);
}
void
handle_timeout
()
{
void
handle_timeout
()
override
{
m_fun
();
}
...
...
libcaf_core/caf/detail/lifted_fun.hpp
View file @
57ca0479
...
...
@@ -35,21 +35,16 @@
namespace
caf
{
namespace
detail
{
class
lifted_fun_zipper
{
public:
struct
lifted_fun_zipper
{
template
<
class
F
,
typename
T
>
auto
operator
()(
const
F
&
fun
,
T
&
arg
)
->
decltype
(
fun
(
arg
))
const
{
return
fun
(
arg
);
}
// forward everything as reference if no guard/transformation is set
template
<
class
T
>
auto
operator
()(
const
unit_t
&
,
T
&
arg
)
const
->
decltype
(
std
::
ref
(
arg
))
{
return
std
::
ref
(
arg
);
}
};
template
<
class
T
>
...
...
@@ -67,62 +62,64 @@ inline bool has_none() {
}
template
<
class
T
,
class
...
Ts
>
inline
bool
has_none
(
const
T
&
,
const
Ts
&
...
vs
)
{
bool
has_none
(
const
T
&
,
const
Ts
&
...
vs
)
{
return
has_none
(
vs
...);
}
template
<
class
T
,
class
...
Ts
>
inline
bool
has_none
(
const
optional
<
T
>&
v
,
const
Ts
&
...
vs
)
{
bool
has_none
(
const
optional
<
T
>&
v
,
const
Ts
&
...
vs
)
{
return
!
v
||
has_none
(
vs
...);
}
// allows F to have fewer arguments than the lifted_fun calling it
template
<
class
R
,
typename
F
>
class
lifted_fun_invoker
{
public:
using
arg_types
=
typename
get_callable_trait
<
F
>::
arg_types
;
static
constexpr
size_t
num_args
=
tl_size
<
arg_types
>::
value
;
public:
lifted_fun_invoker
(
F
&
fun
)
:
f
(
fun
)
{
}
lifted_fun_invoker
(
F
&
fun
)
:
f
(
fun
)
{
// nop
}
template
<
class
...
Ts
>
typename
std
::
enable_if
<
sizeof
...(
Ts
)
==
num_args
,
R
>::
type
operator
()(
Ts
&
...
vs
)
const
{
if
(
has_none
(
vs
...))
return
none
;
if
(
has_none
(
vs
...))
{
return
none
;
}
return
f
(
unopt
(
vs
)...);
}
template
<
class
T
,
class
...
Ts
>
typename
std
::
enable_if
<
(
sizeof
...(
Ts
)
+
1
>
num_args
),
R
>::
type
operator
()(
T
&
v
,
Ts
&
...
vs
)
const
{
if
(
has_none
(
v
))
return
none
;
if
(
has_none
(
v
))
{
return
none
;
}
return
(
*
this
)(
vs
...);
}
private:
F
&
f
;
};
template
<
class
F
>
class
lifted_fun_invoker
<
bool
,
F
>
{
public:
using
arg_types
=
typename
get_callable_trait
<
F
>::
arg_types
;
static
constexpr
size_t
num_args
=
tl_size
<
arg_types
>::
value
;
public:
lifted_fun_invoker
(
F
&
fun
)
:
f
(
fun
)
{
}
lifted_fun_invoker
(
F
&
fun
)
:
f
(
fun
)
{
// nop
}
template
<
class
...
Ts
>
typename
std
::
enable_if
<
sizeof
...(
Ts
)
==
num_args
,
bool
>::
type
operator
()(
Ts
&&
...
vs
)
const
{
if
(
has_none
(
vs
...))
return
false
;
if
(
has_none
(
vs
...))
{
return
false
;
}
f
(
unopt
(
vs
)...);
return
true
;
}
...
...
@@ -130,14 +127,14 @@ class lifted_fun_invoker<bool, F> {
template
<
class
T
,
class
...
Ts
>
typename
std
::
enable_if
<
(
sizeof
...(
Ts
)
+
1
>
num_args
),
bool
>::
type
operator
()(
T
&&
arg
,
Ts
&&
...
vs
)
const
{
if
(
has_none
(
arg
))
return
false
;
if
(
has_none
(
arg
))
{
return
false
;
}
return
(
*
this
)(
vs
...);
}
private:
F
&
f
;
};
/**
...
...
@@ -181,7 +178,9 @@ class lifted_fun {
lifted_fun
&
operator
=
(
const
lifted_fun
&
)
=
default
;
lifted_fun
(
F
f
)
:
m_fun
(
std
::
move
(
f
))
{}
lifted_fun
(
F
f
)
:
m_fun
(
std
::
move
(
f
))
{
// nop
}
lifted_fun
(
F
f
,
projections
ps
)
:
m_fun
(
std
::
move
(
f
)),
m_ps
(
std
::
move
(
ps
))
{
// nop
...
...
libcaf_core/caf/detail/type_traits.hpp
View file @
57ca0479
...
...
@@ -251,10 +251,13 @@ struct is_legal_tuple_type {
* Checks wheter `T` is a non-const reference.
*/
template
<
class
T
>
struct
is_mutable_ref
{
static
constexpr
bool
value
=
std
::
is_reference
<
T
>::
value
&&
!
std
::
is_const
<
T
>::
value
;
};
struct
is_mutable_ref
:
std
::
false_type
{
};
template
<
class
T
>
struct
is_mutable_ref
<
const
T
&>
:
std
::
false_type
{
};
template
<
class
T
>
struct
is_mutable_ref
<
T
&>
:
std
::
true_type
{
};
/**
* Checks whether `T::static_type_name()` exists.
...
...
libcaf_core/caf/match_expr.hpp
View file @
57ca0479
...
...
@@ -43,13 +43,6 @@
namespace
caf
{
namespace
detail
{
template
<
long
N
>
struct
long_constant
{
static
constexpr
long
value
=
N
;
};
using
minus1l
=
long_constant
<-
1l
>
;
template
<
class
T1
,
typename
T2
>
T2
&
deduce_const
(
T1
&
,
T2
&
rhs
)
{
return
rhs
;
...
...
@@ -186,25 +179,10 @@ struct get_case<false, Expr, Trans, Pattern> {
>::
type
;
};
template
<
class
Fun
>
struct
has_bool_result
{
using
result_type
=
typename
Fun
::
result_type
;
static
constexpr
bool
value
=
std
::
is_same
<
bool
,
result_type
>::
value
;
using
token_type
=
std
::
integral_constant
<
bool
,
value
>
;
};
template
<
class
T
>
bool
unroll_expr_result_valid
(
const
T
&
)
{
return
true
;
}
template
<
class
T
>
bool
unroll_expr_result_valid
(
const
optional
<
T
>&
opt
)
{
return
static_cast
<
bool
>
(
opt
);
}
inline
variant
<
none_t
,
unit_t
>
unroll_expr_result_unbox
(
bool
&
value
)
{
if
(
value
)
return
unit
;
inline
variant
<
none_t
,
unit_t
>
unroll_expr_result_unbox
(
bool
value
)
{
if
(
value
)
{
return
unit
;
}
return
none
;
}
...
...
@@ -213,34 +191,28 @@ T& unroll_expr_result_unbox(optional<T>& opt) {
return
*
opt
;
}
template
<
class
Result
,
class
PPFPs
,
class
Msg
>
Result
unroll_expr
(
PPFPs
&
,
minus1l
,
Msg
&
)
{
// end of recursion
return
none
;
}
template
<
class
Result
,
class
PPFPs
,
long
N
,
class
Msg
>
Result
unroll_expr
(
PPFPs
&
fs
,
long_constant
<
N
>
,
Msg
&
msg
)
{
{
// recursively evaluate sub expressions
Result
res
=
unroll_expr
<
Result
>
(
fs
,
long_constant
<
N
-
1
>
{},
msg
);
if
(
!
get
<
none_t
>
(
&
res
))
{
return
res
;
}
template
<
class
Result
>
struct
unroll_expr
{
Result
operator
()(
message
&
)
const
{
// end of recursion
return
none
;
}
auto
&
f
=
get
<
N
>
(
fs
);
using
ft
=
typename
std
::
decay
<
decltype
(
f
)
>::
type
;
meta_elements
<
typename
ft
::
pattern
>
ms
;
typename
ft
::
intermediate_tuple
targs
;
if
((
ft
::
has_wildcard
||
ft
::
type_token
==
msg
.
type_token
())
&&
try_match
(
msg
,
ms
.
arr
.
data
(),
ms
.
arr
.
size
(),
targs
.
data
))
{
auto
is
=
detail
::
get_indices
(
targs
);
auto
res
=
detail
::
apply_args
(
f
,
is
,
deduce_const
(
msg
,
targs
));
if
(
unroll_expr_result_valid
(
res
))
{
return
std
::
move
(
unroll_expr_result_unbox
(
res
));
template
<
class
F
,
class
...
Fs
>
Result
operator
()(
message
&
msg
,
F
&
f
,
Fs
&
...
fs
)
const
{
meta_elements
<
typename
F
::
pattern
>
ms
;
typename
F
::
intermediate_tuple
targs
;
if
((
F
::
has_wildcard
||
F
::
type_token
==
msg
.
type_token
())
&&
try_match
(
msg
,
ms
.
arr
.
data
(),
ms
.
arr
.
size
(),
targs
.
data
))
{
auto
is
=
detail
::
get_indices
(
targs
);
auto
res
=
detail
::
apply_args
(
f
,
is
,
deduce_const
(
msg
,
targs
));
if
(
res
)
{
return
std
::
move
(
unroll_expr_result_unbox
(
res
));
}
}
return
(
*
this
)(
msg
,
fs
...);
}
return
none
;
}
};
template
<
bool
IsManipulator
,
typename
T0
,
typename
T1
>
struct
mexpr_fwd_
{
...
...
@@ -269,20 +241,12 @@ struct mexpr_fwd {
>::
type
;
};
// detach_if_needed(message tup, bool do_detach)
inline
message
&
detach_if_needed
(
message
&
tup
,
std
::
true_type
)
{
tup
.
force_detach
();
return
tup
;
}
inline
message
detach_if_needed
(
const
message
&
tup
,
std
::
true_type
)
{
message
cpy
{
tup
};
cpy
.
force_detach
();
return
cpy
;
inline
void
detach_if_needed
(
message
&
msg
,
std
::
true_type
)
{
msg
.
force_detach
();
}
inline
const
message
&
detach_if_needed
(
const
message
&
tup
,
std
::
false_type
)
{
return
tup
;
inline
void
detach_if_needed
(
const
message
&
,
std
::
false_type
)
{
// nop
}
inline
void
*
fetch_native_data
(
message
&
msg
,
std
::
true_type
)
{
...
...
@@ -298,14 +262,12 @@ struct is_manipulator_case {
// static constexpr bool value = T::second_type::manipulates_args;
using
arg_types
=
typename
T
::
arg_types
;
static
constexpr
bool
value
=
tl_exists
<
arg_types
,
is_mutable_ref
>::
value
;
};
template
<
class
T
>
struct
get_case_result
{
// using type = typename T::second_type::result_type;
using
type
=
typename
T
::
result_type
;
};
}
// namespace detail
...
...
@@ -319,7 +281,6 @@ struct match_result_from_type_list;
template
<
class
...
Ts
>
struct
match_result_from_type_list
<
detail
::
type_list
<
Ts
...
>>
{
using
type
=
variant
<
none_t
,
typename
lift_void
<
Ts
>::
type
...
>
;
};
/**
...
...
@@ -343,11 +304,6 @@ class match_expr {
>::
type
>::
type
;
static
constexpr
bool
has_manipulator
=
detail
::
tl_exists
<
cases_list
,
detail
::
is_manipulator_case
>::
value
;
using
idx_token_type
=
detail
::
long_constant
<
sizeof
...(
Cs
)
-
1l
>
;
template
<
class
T
,
class
...
Ts
>
match_expr
(
T
v
,
Ts
&&
...
vs
)
:
m_cases
(
std
::
move
(
v
),
std
::
forward
<
Ts
>
(
vs
)...)
{
// nop
...
...
@@ -357,17 +313,16 @@ class match_expr {
match_expr
(
const
match_expr
&
)
=
default
;
result_type
operator
()(
const
message
&
tup
)
{
return
apply
(
tup
);
}
result_type
operator
()(
message
&
tup
)
{
return
apply
(
tup
);
}
result_type
operator
()(
message
&&
tup
)
{
message
tmp
{
tup
};
return
apply
(
tmp
);
result_type
operator
()(
message
&
msg
)
{
using
mutator_token
=
std
::
integral_constant
<
bool
,
detail
::
tl_exists
<
cases_list
,
detail
::
is_manipulator_case
>::
value
>
;
detail
::
detach_if_needed
(
msg
,
mutator_token
{});
auto
indices
=
detail
::
get_indices
(
m_cases
);
detail
::
unroll_expr
<
result_type
>
f
;
return
detail
::
apply_args_prefixed
(
f
,
indices
,
m_cases
,
msg
);
}
template
<
class
...
Ds
>
...
...
@@ -395,20 +350,6 @@ class match_expr {
// std::tuple<type_list<...>, ...>,
// ...>
std
::
tuple
<
Cs
...
>
m_cases
;
static
constexpr
size_t
cache_size
=
10
;
using
cache_element
=
std
::
pair
<
const
std
::
type_info
*
,
uint64_t
>
;
template
<
class
Msg
>
result_type
apply
(
Msg
&
msg
)
{
idx_token_type
idx_token
;
std
::
integral_constant
<
bool
,
has_manipulator
>
mutator_token
;
// returns either a reference or a new object
using
detached
=
decltype
(
detail
::
detach_if_needed
(
msg
,
mutator_token
));
detached
mref
=
detail
::
detach_if_needed
(
msg
,
mutator_token
);
return
detail
::
unroll_expr
<
result_type
>
(
m_cases
,
idx_token
,
mref
);
}
};
template
<
class
T
>
...
...
@@ -507,22 +448,26 @@ behavior_impl_ptr match_expr_concat(const T0& arg0, const T1& arg1,
// some more convenience functions
template
<
class
F
,
class
E
=
typename
std
::
enable_if
<
is_callable
<
F
>
::
value
>::
type
>
match_expr
<
typename
get_case
<
false
,
F
,
type_list
<>
,
type_list
<>>::
type
>
lift_to_match_expr
(
F
fun
)
{
template
<
class
T
,
class
E
=
typename
std
::
enable_if
<
is_callable
<
T
>
::
value
&&
!
is_match_expr
<
T
>::
value
>::
type
>
match_expr
<
typename
get_case
<
false
,
T
,
type_list
<>
,
type_list
<>>::
type
>
lift_to_match_expr
(
T
arg
)
{
using
result_type
=
typename
get_case
<
false
,
F
,
T
,
detail
::
empty_type_list
,
detail
::
empty_type_list
>::
type
;
return
result_type
{
std
::
move
(
fun
)};
return
result_type
{
std
::
move
(
arg
)};
}
template
<
class
T
,
class
E
=
typename
std
::
enable_if
<!
is_callable
<
T
>
::
value
>::
type
>
class
E
=
typename
std
::
enable_if
<
!
is_callable
<
T
>
::
value
||
is_match_expr
<
T
>::
value
>::
type
>
T
lift_to_match_expr
(
T
arg
)
{
return
arg
;
}
...
...
libcaf_core/caf/policy/invoke_policy.hpp
View file @
57ca0479
...
...
@@ -160,7 +160,7 @@ class invoke_policy {
if
(
ref_opt
)
{
auto
fhdl
=
fetch_response_promise
(
self
,
hdl
);
behavior
inner
=
*
ref_opt
;
*
ref_opt
=
behavior
{
ref_opt
->
assign
(
others
()
>>
[
=
]
{
// inner is const inside this lambda and mutable a C++14 feature
behavior
cpy
=
inner
;
...
...
@@ -169,7 +169,7 @@ class invoke_policy {
fhdl
.
deliver
(
*
inner_res
);
}
}
}
;
)
;
}
}
else
{
// respond by using the result of 'fun'
...
...
libcaf_core/caf/variant.hpp
View file @
57ca0479
...
...
@@ -24,9 +24,10 @@
#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_CASE(x) \
case x: \
return visitor(from.get( \
std::integral_constant<int, (x < max_type_id ? x : max_type_id)>()))
namespace
caf
{
...
...
@@ -36,7 +37,7 @@ struct variant_assign_helper {
T
&
lhs
;
variant_assign_helper
(
T
&
lhs_ref
)
:
lhs
(
lhs_ref
)
{
}
template
<
class
U
>
inline
void
operator
()(
const
U
&
rhs
)
const
{
void
operator
()(
const
U
&
rhs
)
const
{
lhs
=
rhs
;
}
};
...
...
@@ -47,17 +48,18 @@ struct variant_move_helper {
T
&
lhs
;
variant_move_helper
(
T
&
lhs_ref
)
:
lhs
(
lhs_ref
)
{
}
template
<
class
U
>
inline
void
operator
()(
U
&
rhs
)
const
{
void
operator
()(
U
&
rhs
)
const
{
lhs
=
std
::
move
(
rhs
);
}
};
template
<
class
T
,
typename
U
,
bool
Enable
=
std
::
is_integral
<
T
>
::
value
&&
std
::
is_integral
<
U
>::
value
>
template
<
class
T
,
class
U
,
bool
Enable
=
std
::
is_integral
<
T
>
::
value
&&
std
::
is_integral
<
U
>::
value
>
struct
is_equal_int_type
{
static
constexpr
bool
value
=
sizeof
(
T
)
==
sizeof
(
U
)
&&
std
::
is_signed
<
T
>::
value
==
std
::
is_signed
<
U
>::
value
;
static
constexpr
bool
value
=
sizeof
(
T
)
==
sizeof
(
U
)
&&
std
::
is_signed
<
T
>::
value
==
std
::
is_signed
<
U
>::
value
;
};
template
<
class
T
,
typename
U
>
...
...
@@ -70,26 +72,25 @@ struct is_equal_int_type<T, U, false> : std::false_type { };
* `uint8_t != unsigned char on some compilers.
*/
template
<
class
T
,
typename
U
>
struct
is_same_ish
:
std
::
conditional
<
std
::
is_same
<
T
,
U
>::
value
,
std
::
true_type
,
is_equal_int_type
<
T
,
U
>
>::
type
{
};
struct
is_same_ish
:
std
::
conditional
<
std
::
is_same
<
T
,
U
>::
value
,
std
::
true_type
,
is_equal_int_type
<
T
,
U
>
>::
type
{
};
/**
* A variant represents always a valid value of one of the types `Ts...`.
*/
template
<
class
...
Ts
>
class
variant
{
public:
using
types
=
detail
::
type_list
<
Ts
...
>
;
static
constexpr
int
max_type_id
=
sizeof
...(
Ts
)
-
1
;
static_assert
(
!
detail
::
tl_exists
<
types
,
std
::
is_reference
>::
value
,
"Cannot create a variant of references"
);
"Cannot create a variant of references"
);
variant
&
operator
=
(
const
variant
&
other
)
{
variant_assign_helper
<
variant
>
helper
{
*
this
};
...
...
@@ -134,20 +135,19 @@ class variant {
}
/** @cond PRIVATE */
template
<
int
Pos
>
inline
bool
is
(
std
::
integral_constant
<
int
,
Pos
>
)
const
{
bool
is
(
std
::
integral_constant
<
int
,
Pos
>
)
const
{
return
m_type
==
Pos
;
}
template
<
int
Pos
>
inline
const
typename
detail
::
tl_at
<
types
,
Pos
>::
type
&
const
typename
detail
::
tl_at
<
types
,
Pos
>::
type
&
get
(
std
::
integral_constant
<
int
,
Pos
>
token
)
const
{
return
m_data
.
get
(
token
);
}
template
<
int
Pos
>
inline
typename
detail
::
tl_at
<
types
,
Pos
>::
type
&
typename
detail
::
tl_at
<
types
,
Pos
>::
type
&
get
(
std
::
integral_constant
<
int
,
Pos
>
token
)
{
return
m_data
.
get
(
token
);
}
...
...
@@ -161,11 +161,9 @@ class variant {
typename
Visitor
::
result_type
apply
(
Visitor
&
visitor
)
{
return
apply_impl
(
*
this
,
visitor
);
}
/** @endcond */
private:
template
<
class
Self
,
typename
Visitor
>
static
typename
Visitor
::
result_type
apply_impl
(
Self
&
from
,
Visitor
&
visitor
)
{
switch
(
from
.
m_type
)
{
...
...
@@ -222,30 +220,29 @@ class variant {
}
template
<
class
...
Us
>
inline
void
set
(
const
variant
<
Us
...
>&
other
)
{
void
set
(
const
variant
<
Us
...
>&
other
)
{
using
namespace
detail
;
static_assert
(
tl_is_strict_subset
<
type_list
<
Us
...
>
,
types
>::
value
,
"cannot set variant of type A to variant of type B "
"unless the element types of A are a strict subset of "
"the element types of B"
);
"cannot set variant of type A to variant of type B "
"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
);
}
template
<
class
...
Us
>
inline
void
set
(
variant
<
Us
...
>&&
other
)
{
void
set
(
variant
<
Us
...
>&&
other
)
{
using
namespace
detail
;
static_assert
(
tl_is_strict_subset
<
type_list
<
Us
...
>
,
types
>::
value
,
"cannot set variant of type A to variant of type B "
"unless the element types of A are a strict subset of "
"the element types of B"
);
"cannot set variant of type A to variant of type B "
"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
);
}
int
m_type
;
detail
::
variant_data
<
typename
lift_void
<
Ts
>::
type
...
>
m_data
;
};
/**
...
...
@@ -254,9 +251,10 @@ class variant {
template
<
class
T
,
class
...
Us
>
T
&
get
(
variant
<
Us
...
>&
value
)
{
using
namespace
detail
;
constexpr
int
type_id
=
tl_find_if
<
type_list
<
Us
...
>
,
tbind
<
is_same_ish
,
T
>::
template
type
>
::
value
;
constexpr
int
type_id
=
tl_find_if
<
type_list
<
Us
...
>
,
tbind
<
is_same_ish
,
T
>::
template
type
>
::
value
;
std
::
integral_constant
<
int
,
type_id
>
token
;
// silence compiler error about "binding to unrelated types" such as
// 'signed char' to 'char' (which is obvious bullshit)
...
...
@@ -278,11 +276,14 @@ const T& get(const variant<Us...>& value) {
template
<
class
T
,
class
...
Us
>
T
*
get
(
variant
<
Us
...
>*
value
)
{
using
namespace
detail
;
constexpr
int
type_id
=
tl_find_if
<
type_list
<
Us
...
>
,
tbind
<
is_same_ish
,
T
>::
template
type
>
::
value
;
constexpr
int
type_id
=
tl_find_if
<
type_list
<
Us
...
>
,
tbind
<
is_same_ish
,
T
>::
template
type
>
::
value
;
std
::
integral_constant
<
int
,
type_id
>
token
;
if
(
value
->
is
(
token
))
return
&
get
<
T
>
(
*
value
);
if
(
value
->
is
(
token
))
{
return
&
get
<
T
>
(
*
value
);
}
return
nullptr
;
}
...
...
libcaf_core/src/behavior_impl.cpp
View file @
57ca0479
...
...
@@ -30,14 +30,7 @@ class combinator : public behavior_impl {
public:
bhvr_invoke_result
invoke
(
message
&
arg
)
{
auto
res
=
first
->
invoke
(
arg
);
if
(
!
res
)
return
second
->
invoke
(
arg
);
return
res
;
}
bhvr_invoke_result
invoke
(
const
message
&
arg
)
{
auto
res
=
first
->
invoke
(
arg
);
if
(
!
res
)
return
second
->
invoke
(
arg
);
return
res
;
return
res
?
res
:
second
->
invoke
(
arg
);
}
void
handle_timeout
()
{
...
...
@@ -78,9 +71,8 @@ behavior_impl::pointer behavior_impl::or_else(const pointer& other) {
}
behavior_impl
*
new_default_behavior
(
duration
d
,
std
::
function
<
void
()
>
fun
)
{
using
impl
=
default_behavior_impl
<
dummy_match_expr
,
std
::
function
<
void
()
>>
;
dummy_match_expr
nop
;
return
new
impl
(
nop
,
d
,
std
::
move
(
fun
));
return
new
default_behavior_impl
<
dummy_match_expr
>
(
nop
,
d
,
std
::
move
(
fun
));
}
}
// namespace detail
...
...
libcaf_core/src/message_data.cpp
View file @
57ca0479
...
...
@@ -74,6 +74,7 @@ message_data* message_data::ptr::get_detached() {
if
(
!
p
->
unique
())
{
auto
np
=
p
->
copy
();
m_ptr
.
reset
(
np
);
CAF_REQUIRE
(
np
->
unique
());
return
np
;
}
return
p
;
...
...
libcaf_core/src/ref_counted.cpp
View file @
57ca0479
...
...
@@ -25,7 +25,7 @@ ref_counted::~ref_counted() {
// nop
}
ref_counted
::
ref_counted
(
const
ref_counted
&
)
{
ref_counted
::
ref_counted
(
const
ref_counted
&
)
:
m_rc
(
0
)
{
// nop; don't copy reference count
}
...
...
unit_testing/CMakeLists.txt
View file @
57ca0479
...
...
@@ -35,6 +35,7 @@ add_unit_test(constructor_attach)
add_unit_test
(
custom_exception_handler
)
add_unit_test
(
typed_spawn
)
add_unit_test
(
actor_lifetime
)
add_unit_test
(
message_lifetime
)
add_unit_test
(
local_group
)
add_unit_test
(
sync_send
)
add_unit_test
(
broker
)
...
...
unit_testing/test_message_lifetime.cpp
0 → 100644
View file @
57ca0479
#include <atomic>
#include <iostream>
#include "test.hpp"
#include "caf/all.hpp"
using
std
::
cout
;
using
std
::
endl
;
using
namespace
caf
;
class
testee
:
public
event_based_actor
{
public:
testee
();
~
testee
();
behavior
make_behavior
()
override
;
};
testee
::
testee
()
{
// nop
}
testee
::~
testee
()
{
// nop
}
behavior
testee
::
make_behavior
()
{
return
{
others
()
>>
[
=
]
{
CAF_CHECK_EQUAL
(
last_dequeued
().
cvals
()
->
get_reference_count
(),
2
);
quit
();
return
last_dequeued
();
}
};
}
class
tester
:
public
event_based_actor
{
public:
tester
(
actor
aut
);
~
tester
();
behavior
make_behavior
()
override
;
private:
actor
m_aut
;
message
m_msg
;
};
tester
::
tester
(
actor
aut
)
:
m_aut
(
std
::
move
(
aut
)),
m_msg
(
make_message
(
1
,
2
,
3
))
{
// nop
}
tester
::~
tester
()
{
// nop
}
behavior
tester
::
make_behavior
()
{
monitor
(
m_aut
);
send
(
m_aut
,
m_msg
);
return
{
on
(
1
,
2
,
3
)
>>
[
=
]
{
CAF_CHECK_EQUAL
(
last_dequeued
().
cvals
()
->
get_reference_count
(),
2
);
CAF_CHECK
(
last_dequeued
().
cvals
().
get
()
==
m_msg
.
cvals
().
get
());
},
[
=
](
const
down_msg
&
dm
)
{
CAF_CHECK
(
dm
.
source
==
m_aut
);
CAF_CHECK_EQUAL
(
dm
.
reason
,
exit_reason
::
normal
);
CAF_CHECK_EQUAL
(
last_dequeued
().
cvals
()
->
get_reference_count
(),
1
);
quit
();
},
others
()
>>
CAF_UNEXPECTED_MSG_CB
(
this
)
};
}
void
test_message_lifetime_in_scoped_actor
()
{
auto
msg
=
make_message
(
1
,
2
,
3
);
scoped_actor
self
;
self
->
send
(
self
,
msg
);
self
->
receive
(
on
(
1
,
2
,
3
)
>>
[
&
]
{
CAF_CHECK_EQUAL
(
msg
.
cvals
()
->
get_reference_count
(),
2
);
CAF_CHECK_EQUAL
(
self
->
last_dequeued
().
cvals
()
->
get_reference_count
(),
2
);
CAF_CHECK
(
self
->
last_dequeued
().
cvals
().
get
()
==
msg
.
cvals
().
get
());
}
);
CAF_CHECK_EQUAL
(
msg
.
cvals
()
->
get_reference_count
(),
1
);
msg
=
make_message
(
42
);
self
->
send
(
self
,
msg
);
self
->
receive
(
[
&
](
int
&
value
)
{
CAF_CHECK_EQUAL
(
msg
.
cvals
()
->
get_reference_count
(),
1
);
CAF_CHECK_EQUAL
(
self
->
last_dequeued
().
cvals
()
->
get_reference_count
(),
1
);
CAF_CHECK
(
self
->
last_dequeued
().
cvals
().
get
()
!=
msg
.
cvals
().
get
());
value
=
10
;
}
);
CAF_CHECK_EQUAL
(
msg
.
get_as
<
int
>
(
0
),
42
);
}
void
test_message_lifetime
()
{
test_message_lifetime_in_scoped_actor
();
if
(
CAF_TEST_RESULT
()
!=
0
)
{
return
;
}
// put some preassure on the scheduler (check for thread safety)
for
(
size_t
i
=
0
;
i
<
100
;
++
i
)
{
spawn
<
tester
>
(
spawn
<
testee
>
());
}
}
int
main
()
{
CAF_TEST
(
test_message_lifetime
);
test_message_lifetime
();
await_all_actors_done
();
shutdown
();
return
CAF_TEST_RESULT
();
}
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