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
1700bcf8
Commit
1700bcf8
authored
Dec 13, 2017
by
Dominik Charousset
Committed by
Dominik Charousset
Feb 06, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix copy-on-write semantic for messages
parent
8a47221b
Changes
11
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
347 additions
and
267 deletions
+347
-267
libcaf_core/caf/actor_factory.hpp
libcaf_core/caf/actor_factory.hpp
+2
-1
libcaf_core/caf/detail/message_data.hpp
libcaf_core/caf/detail/message_data.hpp
+17
-1
libcaf_core/caf/message.hpp
libcaf_core/caf/message.hpp
+68
-110
libcaf_core/caf/mixin/sender.hpp
libcaf_core/caf/mixin/sender.hpp
+2
-0
libcaf_core/caf/monitorable_actor.hpp
libcaf_core/caf/monitorable_actor.hpp
+2
-8
libcaf_core/caf/scheduled_actor.hpp
libcaf_core/caf/scheduled_actor.hpp
+2
-2
libcaf_core/caf/type_erased_tuple.hpp
libcaf_core/caf/type_erased_tuple.hpp
+16
-6
libcaf_core/src/mailbox_element.cpp
libcaf_core/src/mailbox_element.cpp
+1
-1
libcaf_core/src/message.cpp
libcaf_core/src/message.cpp
+196
-135
libcaf_core/test/mailbox_element.cpp
libcaf_core/test/mailbox_element.cpp
+3
-3
libcaf_core/test/message_lifetime.cpp
libcaf_core/test/message_lifetime.cpp
+38
-0
No files found.
libcaf_core/caf/actor_factory.hpp
View file @
1700bcf8
...
...
@@ -156,7 +156,8 @@ actor_factory make_actor_factory(F fun) {
typename
ctrait
::
arg_types
>
;
fd
f
{
fun
,
static_cast
<
impl
*>
(
x
)};
empty_type_erased_tuple
dummy_
;
auto
&
ct
=
msg
.
empty
()
?
dummy_
:
const_cast
<
message
&>
(
msg
).
content
();
auto
&
ct
=
msg
.
empty
()
?
dummy_
:
const_cast
<
message
&>
(
msg
).
content
();
auto
opt
=
ct
.
apply
(
f
);
if
(
!
opt
)
return
{};
...
...
libcaf_core/caf/detail/message_data.hpp
View file @
1700bcf8
...
...
@@ -122,7 +122,7 @@ public:
}
inline
explicit
operator
bool
()
const
noexcept
{
return
static_cast
<
bool
>
(
ptr_
)
;
return
ptr_
!=
nullptr
;
}
inline
message_data
*
get
()
const
noexcept
{
...
...
@@ -134,6 +134,22 @@ private:
intrusive_ptr
<
message_data
>
ptr_
;
};
inline
bool
operator
==
(
const
message_data
::
cow_ptr
&
x
,
std
::
nullptr_t
)
{
return
x
.
get
()
==
nullptr
;
}
inline
bool
operator
==
(
std
::
nullptr_t
,
const
message_data
::
cow_ptr
&
x
)
{
return
x
.
get
()
==
nullptr
;
}
inline
bool
operator
!=
(
const
message_data
::
cow_ptr
&
x
,
std
::
nullptr_t
)
{
return
x
.
get
()
!=
nullptr
;
}
inline
bool
operator
!=
(
std
::
nullptr_t
,
const
message_data
::
cow_ptr
&
x
)
{
return
x
.
get
()
!=
nullptr
;
}
}
// namespace detail
}
// namespace caf
...
...
libcaf_core/caf/message.hpp
View file @
1700bcf8
...
...
@@ -23,28 +23,29 @@
#include <sstream>
#include <type_traits>
#include "caf/fwd.hpp"
#include "caf/skip.hpp"
#include "caf/atom.hpp"
#include "caf/none.hpp"
#include "caf/config.hpp"
#include "caf/optional.hpp"
#include "caf/make_counted.hpp"
#include "caf/fwd.hpp"
#include "caf/index_mapping.hpp"
#include "caf/make_counted.hpp"
#include "caf/none.hpp"
#include "caf/optional.hpp"
#include "caf/skip.hpp"
#include "caf/type_nr.hpp"
#include "caf/detail/int_list.hpp"
#include "caf/detail/apply_args.hpp"
#include "caf/detail/comparable.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/detail/message_data.hpp"
#include "caf/detail/implicit_conversions.hpp"
#include "caf/detail/int_list.hpp"
#include "caf/detail/message_data.hpp"
#include "caf/detail/type_traits.hpp"
namespace
caf
{
class
message_handler
;
/// Describes a fixed-length, copy-on-write, type-erased
/// tuple with elements of any type.
class
message
{
class
message
:
public
type_erased_tuple
{
public:
// -- nested types -----------------------------------------------------------
...
...
@@ -74,7 +75,33 @@ public:
message
&
operator
=
(
message
&&
)
noexcept
;
explicit
message
(
data_ptr
ptr
)
noexcept
;
~
message
();
~
message
()
override
;
// -- implementation of type_erased_tuple ------------------------------------
void
*
get_mutable
(
size_t
p
)
override
;
error
load
(
size_t
pos
,
deserializer
&
source
)
override
;
size_t
size
()
const
noexcept
override
;
uint32_t
type_token
()
const
noexcept
override
;
rtti_pair
type
(
size_t
pos
)
const
noexcept
override
;
const
void
*
get
(
size_t
pos
)
const
noexcept
override
;
std
::
string
stringify
(
size_t
pos
)
const
override
;
type_erased_value_ptr
copy
(
size_t
pos
)
const
override
;
error
save
(
size_t
pos
,
serializer
&
sink
)
const
override
;
bool
shared
()
const
noexcept
override
;
error
load
(
deserializer
&
source
)
override
;
error
save
(
serializer
&
sink
)
const
override
;
// -- factories --------------------------------------------------------------
...
...
@@ -92,16 +119,6 @@ public:
/// Concatenates `*this` and `x`.
message
&
operator
+=
(
const
message
&
x
);
/// Returns a mutable pointer to the element at position `p`.
void
*
get_mutable
(
size_t
p
);
/// Returns the value at position `p` as mutable reference of type `T`.
template
<
class
T
>
T
&
get_mutable_as
(
size_t
p
)
{
CAF_ASSERT
(
match_element
(
p
,
type_nr
<
T
>::
value
,
&
typeid
(
T
)));
return
*
reinterpret_cast
<
T
*>
(
get_mutable
(
p
));
}
/// Returns `handler(*this)`.
optional
<
message
>
apply
(
message_handler
handler
);
...
...
@@ -212,7 +229,7 @@ public:
/// Returns a const pointer to the element at position `p`.
inline
const
void
*
at
(
size_t
p
)
const
noexcept
{
CAF_ASSERT
(
vals_
);
CAF_ASSERT
(
vals_
!=
nullptr
);
return
vals_
->
get
(
p
);
}
...
...
@@ -226,21 +243,7 @@ public:
return
vals_
;
}
/// Returns a type hint for the pattern matching engine.
inline
uint32_t
type_token
()
const
noexcept
{
return
vals_
?
vals_
->
type_token
()
:
0xFFFFFFFF
;
}
/// Returns whether there are more than one references to the content.
inline
bool
shared
()
const
noexcept
{
return
vals_
?
vals_
->
shared
()
:
false
;
}
/// Returns the size of this message.
inline
size_t
size
()
const
noexcept
{
return
vals_
?
vals_
->
size
()
:
0
;
}
/// Creates a new message from the first n values.
inline
message
take
(
size_t
n
)
const
{
return
n
>=
size
()
?
*
this
:
drop_right
(
size
()
-
n
);
...
...
@@ -251,71 +254,24 @@ public:
return
n
>=
size
()
?
*
this
:
drop
(
size
()
-
n
);
}
/// Returns true if `size() == 0, otherwise false.
inline
bool
empty
()
const
{
return
size
()
==
0
;
}
/// Returns the value at position `p` as const reference of type `T`.
template
<
class
T
>
const
T
&
get_as
(
size_t
p
)
const
{
CAF_ASSERT
(
match_element
(
p
,
type_nr
<
T
>::
value
,
&
typeid
(
T
)));
return
*
reinterpret_cast
<
const
T
*>
(
at
(
p
));
}
/// Queries whether the element at position `p` is of type `T`.
template
<
class
T
>
bool
match_element
(
size_t
p
)
const
noexcept
{
return
vals_
?
vals_
->
match_element
<
T
>
(
p
)
:
false
;
}
/// Queries whether the types of this message are `Ts...`.
template
<
class
...
Ts
>
bool
match_elements
()
const
noexcept
{
detail
::
type_list
<
Ts
...
>
token
;
return
match_elements
(
token
);
}
/// Queries the run-time type information for the element at position `pos`.
inline
std
::
pair
<
uint16_t
,
const
std
::
type_info
*>
type
(
size_t
pos
)
const
noexcept
{
CAF_ASSERT
(
vals_
&&
vals_
->
size
()
>
pos
);
return
vals_
->
type
(
pos
);
}
/// Checks whether the type of the stored value at position `pos`
/// matches type number `n` and run-time type information `p`.
bool
match_element
(
size_t
pos
,
uint16_t
n
,
const
std
::
type_info
*
p
)
const
noexcept
{
CAF_ASSERT
(
vals_
);
return
vals_
->
matches
(
pos
,
n
,
p
);
}
inline
bool
match_elements
(
detail
::
type_list
<>
)
const
noexcept
{
return
!
vals_
||
vals_
->
empty
();
}
template
<
class
T
,
class
...
Ts
>
bool
match_elements
(
detail
::
type_list
<
T
,
Ts
...
>
)
const
noexcept
{
return
vals_
?
vals_
->
match_elements
<
T
,
Ts
...
>
()
:
false
;
}
/// @cond PRIVATE
/// @pre `!empty()`
inline
type_erased_tuple
&
content
()
{
CAF_ASSERT
(
vals_
);
CAF_ASSERT
(
vals_
!=
nullptr
);
return
*
vals_
;
}
inline
const
type_erased_tuple
&
content
()
const
{
CAF_ASSERT
(
vals_
);
CAF_ASSERT
(
vals_
!=
nullptr
);
return
*
vals_
;
}
/// @endcond
private:
// -- private helpers --------------------------------------------------------
template
<
size_t
P
>
static
bool
match_elements_impl
(
std
::
integral_constant
<
size_t
,
P
>
,
detail
::
type_list
<>
)
noexcept
{
...
...
@@ -334,17 +290,24 @@ private:
static
message
concat_impl
(
std
::
initializer_list
<
data_ptr
>
xs
);
// -- member functions -------------------------------------------------------
data_ptr
vals_
;
};
/// @relates message
error
inspect
(
serializer
&
sink
,
message
&
msg
);
// -- nested types -------------------------------------------------------------
/// @relates message
error
inspect
(
deserializer
&
source
,
message
&
msg
);
/// @relates message
std
::
string
to_string
(
const
message
&
msg
);
/// Stores the result of `message::extract_opts`.
struct
message
::
cli_res
{
/// Stores the remaining (unmatched) arguments.
message
remainder
;
/// Stores the names of all active options.
std
::
set
<
std
::
string
>
opts
;
/// Stores the automatically generated help text.
std
::
string
helptext
;
/// Stores errors during option parsing.
std
::
string
error
;
};
/// Stores the name of a command line option ("<long name>[,<short name>]")
/// along with a description and a callback.
...
...
@@ -389,11 +352,7 @@ struct message::cli_arg {
/// Creates a CLI argument for converting from strings,
/// storing its matched argument in `dest`.
template
<
class
T
>
cli_arg
(
typename
std
::
enable_if
<
type_nr
<
T
>::
value
!=
0
,
std
::
string
>::
type
nstr
,
std
::
string
tstr
,
T
&
arg
)
cli_arg
(
std
::
string
nstr
,
std
::
string
tstr
,
T
&
arg
)
:
name
(
std
::
move
(
nstr
)),
text
(
std
::
move
(
tstr
)),
flag
(
nullptr
)
{
...
...
@@ -420,7 +379,7 @@ struct message::cli_arg {
flag
(
nullptr
)
{
fun
=
[
&
arg
](
const
std
::
string
&
str
)
->
bool
{
T
x
;
std
::
istringstream
iss
{
str
};
std
::
istringstream
iss
{
str
};
if
(
iss
>>
x
)
{
arg
.
emplace_back
(
std
::
move
(
x
));
return
true
;
...
...
@@ -430,17 +389,16 @@ struct message::cli_arg {
}
};
/// Stores the result of `message::extract_opts`.
struct
message
::
cli_res
{
/// Stores the remaining (unmatched) arguments.
message
remainder
;
/// Stores the names of all active options.
std
::
set
<
std
::
string
>
opts
;
/// Stores the automatically generated help text.
std
::
string
helptext
;
/// Stores errors during option parsing.
std
::
string
error
;
};
// -- related non-members ------------------------------------------------------
/// @relates message
error
inspect
(
serializer
&
sink
,
message
&
msg
);
/// @relates message
error
inspect
(
deserializer
&
source
,
message
&
msg
);
/// @relates message
std
::
string
to_string
(
const
message
&
msg
);
/// @relates message
inline
message
operator
+
(
const
message
&
lhs
,
const
message
&
rhs
)
{
...
...
libcaf_core/caf/mixin/sender.hpp
View file @
1700bcf8
...
...
@@ -36,6 +36,8 @@
#include "caf/response_handle.hpp"
#include "caf/response_type.hpp"
#include "caf/scheduler/abstract_coordinator.hpp"
namespace
caf
{
namespace
mixin
{
...
...
libcaf_core/caf/monitorable_actor.hpp
View file @
1700bcf8
...
...
@@ -138,14 +138,8 @@ protected:
template
<
class
F
>
bool
handle_system_message
(
mailbox_element
&
x
,
execution_unit
*
context
,
bool
trap_exit
,
F
&
down_msg_handler
)
{
auto
&
content
=
x
.
content
();
if
(
content
.
type_token
()
==
make_type_token
<
down_msg
>
())
{
if
(
content
.
shared
())
{
auto
vptr
=
content
.
copy
(
0
);
down_msg_handler
(
vptr
->
get_mutable_as
<
down_msg
>
());
}
else
{
down_msg_handler
(
content
.
get_mutable_as
<
down_msg
>
(
0
));
}
if
(
x
.
content
().
type_token
()
==
make_type_token
<
down_msg
>
())
{
down_msg_handler
(
x
.
content
().
get_mutable_as
<
down_msg
>
(
0
));
return
true
;
}
return
handle_system_message
(
x
,
context
,
trap_exit
);
...
...
libcaf_core/caf/scheduled_actor.hpp
View file @
1700bcf8
...
...
@@ -823,6 +823,8 @@ public:
}
*/
void
push_to_cache
(
mailbox_element_ptr
ptr
);
/// @endcond
/// Returns the queue for storing incoming messages.
...
...
@@ -865,8 +867,6 @@ protected:
bool
handle_stream_msg
(
mailbox_element
&
x
,
behavior
*
active_behavior
);
void
push_to_cache
(
mailbox_element_ptr
ptr
);
// -- Member Variables -------------------------------------------------------
// used by both event-based and blocking actors
...
...
libcaf_core/caf/type_erased_tuple.hpp
View file @
1700bcf8
...
...
@@ -60,7 +60,7 @@ public:
// -- modifiers --------------------------------------------------------------
/// Load the content for the tuple from `source`.
error
load
(
deserializer
&
source
);
virtual
error
load
(
deserializer
&
source
);
// -- pure virtual observers -------------------------------------------------
...
...
@@ -99,11 +99,12 @@ public:
std
::
string
stringify
()
const
;
/// Saves the content of the tuple to `sink`.
error
save
(
serializer
&
sink
)
const
;
virtual
error
save
(
serializer
&
sink
)
const
;
/// Checks whether the type of the stored value at position `pos`
/// matches type number `n` and run-time type information `p`.
bool
matches
(
size_t
pos
,
uint16_t
nr
,
const
std
::
type_info
*
ptr
)
const
noexcept
;
bool
matches
(
size_t
pos
,
uint16_t
nr
,
const
std
::
type_info
*
ptr
)
const
noexcept
;
// -- convenience functions --------------------------------------------------
...
...
@@ -175,9 +176,8 @@ public:
/// Returns `true` if the pattern `Ts...` matches the content of this tuple.
template
<
class
...
Ts
>
bool
match_elements
()
const
noexcept
{
detail
::
meta_elements
<
detail
::
type_list
<
Ts
...
>>
xs
;
return
xs
.
arr
.
empty
()
?
empty
()
:
detail
::
try_match
(
*
this
,
&
xs
.
arr
[
0
],
sizeof
...(
Ts
));
detail
::
type_list
<
Ts
...
>
tk
;
return
match_elements
(
tk
);
}
template
<
class
F
>
...
...
@@ -190,6 +190,16 @@ public:
}
private:
template
<
class
T
,
class
...
Ts
>
bool
match_elements
(
detail
::
type_list
<
T
,
Ts
...
>
)
const
noexcept
{
detail
::
meta_elements
<
detail
::
type_list
<
T
,
Ts
...
>>
xs
;
return
detail
::
try_match
(
*
this
,
&
xs
.
arr
[
0
],
1
+
sizeof
...(
Ts
));
}
inline
bool
match_elements
(
detail
::
type_list
<>
)
const
noexcept
{
return
empty
();
}
template
<
class
F
,
class
R
,
class
...
Ts
>
optional
<
R
>
apply
(
F
&
fun
,
detail
::
type_list
<
R
>
,
detail
::
type_list
<
Ts
...
>
tk
)
{
...
...
libcaf_core/src/mailbox_element.cpp
View file @
1700bcf8
...
...
@@ -50,7 +50,7 @@ public:
}
type_erased_tuple
&
content
()
override
{
return
msg_
.
content
()
;
return
msg_
;
}
const
type_erased_tuple
&
content
()
const
override
{
...
...
libcaf_core/src/message.cpp
View file @
1700bcf8
This diff is collapsed.
Click to expand it.
libcaf_core/test/mailbox_element.cpp
View file @
1700bcf8
...
...
@@ -37,19 +37,19 @@ using namespace caf;
namespace
{
template
<
class
...
Ts
>
optional
<
tuple
<
Ts
...
>>
fetch
(
type_erased_tuple
&
x
)
{
optional
<
tuple
<
Ts
...
>>
fetch
(
const
type_erased_tuple
&
x
)
{
if
(
!
x
.
match_elements
<
Ts
...
>
())
return
none
;
return
x
.
get_as_tuple
<
Ts
...
>
();
}
template
<
class
...
Ts
>
optional
<
tuple
<
Ts
...
>>
fetch
(
message
&
x
)
{
optional
<
tuple
<
Ts
...
>>
fetch
(
const
message
&
x
)
{
return
fetch
<
Ts
...
>
(
x
.
content
());
}
template
<
class
...
Ts
>
optional
<
tuple
<
Ts
...
>>
fetch
(
mailbox_element
&
x
)
{
optional
<
tuple
<
Ts
...
>>
fetch
(
const
mailbox_element
&
x
)
{
return
fetch
<
Ts
...
>
(
x
.
content
());
}
...
...
libcaf_core/test/message_lifetime.cpp
View file @
1700bcf8
...
...
@@ -86,10 +86,48 @@ struct fixture {
actor_system
system
{
cfg
};
};
struct
fail_on_copy
{
int
value
;
fail_on_copy
(
int
x
=
0
)
:
value
(
x
)
{
// nop
}
fail_on_copy
(
fail_on_copy
&&
)
=
default
;
fail_on_copy
&
operator
=
(
fail_on_copy
&&
)
=
default
;
fail_on_copy
(
const
fail_on_copy
&
)
{
CAF_FAIL
(
"fail_on_copy: copy constructor called"
);
}
fail_on_copy
&
operator
=
(
const
fail_on_copy
&
)
{
CAF_FAIL
(
"fail_on_copy: copy assign operator called"
);
}
};
template
<
class
Inspector
>
typename
Inspector
::
result_type
inspect
(
Inspector
&
f
,
fail_on_copy
&
x
)
{
return
f
(
x
.
value
);
}
}
// namespace <anonymous>
CAF_TEST_FIXTURE_SCOPE
(
message_lifetime_tests
,
fixture
)
CAF_TEST
(
nocopy_in_scoped_actor
)
{
auto
msg
=
make_message
(
fail_on_copy
{
1
});
scoped_actor
self
{
system
};
self
->
send
(
self
,
msg
);
self
->
receive
(
[
&
](
const
fail_on_copy
&
x
)
{
CAF_CHECK_EQUAL
(
x
.
value
,
1
);
CAF_CHECK_EQUAL
(
msg
.
cvals
()
->
get_reference_count
(),
2u
);
}
);
CAF_CHECK_EQUAL
(
msg
.
cvals
()
->
get_reference_count
(),
1u
);
}
CAF_TEST
(
message_lifetime_in_scoped_actor
)
{
auto
msg
=
make_message
(
1
,
2
,
3
);
scoped_actor
self
{
system
};
...
...
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