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
b4db95d5
Commit
b4db95d5
authored
Apr 22, 2016
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Use new param-API for composable behaviors
parent
0d219a24
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
241 additions
and
58 deletions
+241
-58
libcaf_core/caf/abstract_composable_behavior.hpp
libcaf_core/caf/abstract_composable_behavior.hpp
+0
-22
libcaf_core/caf/all.hpp
libcaf_core/caf/all.hpp
+2
-3
libcaf_core/caf/atom.hpp
libcaf_core/caf/atom.hpp
+10
-0
libcaf_core/caf/composable_behavior.hpp
libcaf_core/caf/composable_behavior.hpp
+4
-3
libcaf_core/caf/composed_behavior.hpp
libcaf_core/caf/composed_behavior.hpp
+2
-2
libcaf_core/caf/detail/message_data.hpp
libcaf_core/caf/detail/message_data.hpp
+2
-0
libcaf_core/caf/detail/pseudo_tuple.hpp
libcaf_core/caf/detail/pseudo_tuple.hpp
+70
-12
libcaf_core/caf/match_case.hpp
libcaf_core/caf/match_case.hpp
+19
-8
libcaf_core/caf/message.hpp
libcaf_core/caf/message.hpp
+4
-0
libcaf_core/caf/param.hpp
libcaf_core/caf/param.hpp
+113
-0
libcaf_core/caf/type_erased_tuple.hpp
libcaf_core/caf/type_erased_tuple.hpp
+7
-0
libcaf_core/src/message_data.cpp
libcaf_core/src/message_data.cpp
+4
-0
libcaf_core/test/composable_behavior.cpp
libcaf_core/test/composable_behavior.cpp
+4
-8
No files found.
libcaf_core/caf/abstract_composable_behavior.hpp
View file @
b4db95d5
...
...
@@ -38,28 +38,6 @@ public:
virtual
~
abstract_composable_behavior
();
virtual
void
init_behavior
(
behavior
&
x
)
=
0
;
template
<
class
Derived
,
class
...
Ts
>
auto
invoke_mutable
(
Derived
*
thisptr
,
const
Ts
&
...)
->
decltype
(
std
::
declval
<
Derived
>
()(
std
::
declval
<
Ts
>
()...))
{
// re-dispatch on current message via lambda expression
auto
f
=
[
thisptr
](
Ts
&
...
xs
)
{
return
(
*
thisptr
)(
xs
...);
};
// reference to the current message
auto
&
msg
=
thisptr
->
self
->
current_message
();
if
(
!
msg
.
template
match_elements
<
Ts
...>())
return
sec
::
invalid_invoke_mutable
;
// make sure no other actor accesses the same data
msg
.
force_unshare
();
// fill a pseudo tuple with values and invoke f
detail
::
pseudo_tuple
<
Ts
...
>
buf
;
// msg is guaranteed to be detached, hence we don't need to
// check this condition over and over again via get_mutable
for
(
size_t
i
=
0
;
i
<
msg
.
size
();
++
i
)
buf
[
i
]
=
const_cast
<
void
*>
(
msg
.
at
(
i
));
return
detail
::
apply_args
(
f
,
detail
::
get_indices
(
buf
),
buf
);
}
};
}
// namespace caf
...
...
libcaf_core/caf/all.hpp
View file @
b4db95d5
...
...
@@ -57,13 +57,11 @@
#include "caf/skip_message.hpp"
#include "caf/actor_ostream.hpp"
#include "caf/function_view.hpp"
#include "caf/handler_input.hpp"
#include "caf/index_mapping.hpp"
#include "caf/spawn_options.hpp"
#include "caf/abstract_actor.hpp"
#include "caf/abstract_group.hpp"
#include "caf/blocking_actor.hpp"
#include "caf/composed_behavior.hpp"
#include "caf/deep_to_string.hpp"
#include "caf/execution_unit.hpp"
#include "caf/memory_managed.hpp"
...
...
@@ -78,16 +76,17 @@
#include "caf/response_handle.hpp"
#include "caf/system_messages.hpp"
#include "caf/abstract_channel.hpp"
#include "caf/composable_behavior.hpp"
#include "caf/may_have_timeout.hpp"
#include "caf/message_priority.hpp"
#include "caf/typed_actor_view.hpp"
#include "caf/binary_serializer.hpp"
#include "caf/composed_behavior.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/primitive_variant.hpp"
#include "caf/timeout_definition.hpp"
#include "caf/actor_system_config.hpp"
#include "caf/binary_deserializer.hpp"
#include "caf/composable_behavior.hpp"
#include "caf/typed_actor_pointer.hpp"
#include "caf/scoped_execution_unit.hpp"
#include "caf/typed_continue_helper.hpp"
...
...
libcaf_core/caf/atom.hpp
View file @
b4db95d5
...
...
@@ -62,6 +62,16 @@ struct atom_constant {
static
const
atom_constant
value
;
};
template
<
class
T
>
struct
is_atom_constant
{
static
constexpr
bool
value
=
false
;
};
template
<
atom_value
X
>
struct
is_atom_constant
<
atom_constant
<
X
>>
{
static
constexpr
bool
value
=
true
;
};
template
<
atom_value
V
>
std
::
string
to_string
(
const
atom_constant
<
V
>&
)
{
return
to_string
(
V
);
...
...
libcaf_core/caf/composable_behavior.hpp
View file @
b4db95d5
...
...
@@ -20,6 +20,7 @@
#ifndef CAF_COMPOSABLE_STATE_HPP
#define CAF_COMPOSABLE_STATE_HPP
#include "caf/param.hpp"
#include "caf/behavior.hpp"
#include "caf/replies_to.hpp"
#include "caf/typed_actor.hpp"
...
...
@@ -42,7 +43,7 @@ public:
// nop
}
virtual
result
<
Ys
...
>
operator
()(
handler_input
_t
<
Xs
>
...)
=
0
;
virtual
result
<
Ys
...
>
operator
()(
param
_t
<
Xs
>
...)
=
0
;
};
// this class works around compiler issues on GCC
...
...
@@ -74,8 +75,8 @@ void init_behavior_impl(T* thisptr,
detail
::
type_list
<
Ys
...
>>
,
Ts
...
>
,
behavior
&
storage
,
Fs
...
fs
)
{
auto
f
=
[
=
](
handler_input
_t
<
Xs
>
...
xs
)
{
return
(
*
thisptr
)(
xs
...);
auto
f
=
[
=
](
param
_t
<
Xs
>
...
xs
)
{
return
(
*
thisptr
)(
std
::
move
(
xs
)
...);
};
detail
::
type_list
<
Ts
...
>
token
;
init_behavior_impl
(
thisptr
,
token
,
storage
,
fs
...,
f
);
...
...
libcaf_core/caf/composed_behavior.hpp
View file @
b4db95d5
...
...
@@ -20,7 +20,7 @@
#ifndef CAF_COMPOSED_STATE_HPP
#define CAF_COMPOSED_STATE_HPP
#include "caf/
handler_input
.hpp"
#include "caf/
param
.hpp"
#include "caf/composable_behavior.hpp"
#include "caf/typed_actor_pointer.hpp"
...
...
@@ -71,7 +71,7 @@ public:
using
super
::
operator
();
virtual
result
<
Ys
...
>
operator
()(
handler_input
_t
<
Xs
>
...)
override
=
0
;
virtual
result
<
Ys
...
>
operator
()(
param
_t
<
Xs
>
...)
override
=
0
;
};
template
<
class
...
Ts
>
...
...
libcaf_core/caf/detail/message_data.hpp
View file @
b4db95d5
...
...
@@ -43,6 +43,8 @@ public:
~
message_data
();
bool
shared
()
const
override
;
// nested types
class
cow_ptr
{
...
...
libcaf_core/caf/detail/pseudo_tuple.hpp
View file @
b4db95d5
...
...
@@ -22,12 +22,15 @@
#include <cstddef>
#include "caf/config.hpp"
#include "caf/param.hpp"
#include "caf/detail/type_traits.hpp"
namespace
caf
{
namespace
detail
{
// tuple-like access to an array of void pointers
// tuple-like access to an array of void pointers that is
// also aware of the semantics of param<T>
template
<
class
...
T
>
struct
pseudo_tuple
{
using
pointer
=
void
*
;
...
...
@@ -35,29 +38,84 @@ struct pseudo_tuple {
pointer
data
[
sizeof
...(
T
)
>
0
?
sizeof
...(
T
)
:
1
];
inline
const_pointer
at
(
size_t
p
)
const
{
return
data
[
p
];
}
bool
shared_access
;
inline
pointer
get_mutable
(
size_t
p
)
{
return
data
[
p
];
}
pseudo_tuple
(
bool
is_shared
)
:
shared_access
(
is_shared
)
{
// nop
}
inline
pointer
&
operator
[](
size_t
p
)
{
return
data
[
p
];
}
inline
const_pointer
at
(
size_t
p
)
const
{
return
data
[
p
];
}
inline
pointer
get_mutable
(
size_t
p
)
{
return
data
[
p
];
}
inline
pointer
&
operator
[](
size_t
p
)
{
return
data
[
p
];
}
};
template
<
class
T
>
struct
pseudo_tuple_access
{
using
result_type
=
T
&
;
template
<
class
Tuple
>
static
T
&
get
(
Tuple
&
xs
,
size_t
pos
)
{
auto
vp
=
xs
.
get_mutable
(
pos
);
CAF_ASSERT
(
vp
!=
nullptr
);
return
*
reinterpret_cast
<
T
*>
(
vp
);
}
};
template
<
class
T
>
struct
pseudo_tuple_access
<
const
T
>
{
using
result_type
=
const
T
&
;
template
<
class
Tuple
>
static
const
T
&
get
(
const
Tuple
&
xs
,
size_t
pos
)
{
auto
vp
=
xs
.
at
(
pos
);
CAF_ASSERT
(
vp
!=
nullptr
);
return
*
reinterpret_cast
<
const
T
*>
(
vp
);
}
};
template
<
class
T
>
struct
pseudo_tuple_access
<
param
<
T
>>
{
using
result_type
=
param
<
T
>
;
template
<
class
Tuple
>
static
result_type
get
(
const
Tuple
&
xs
,
size_t
pos
)
{
auto
vp
=
xs
.
at
(
pos
);
CAF_ASSERT
(
vp
!=
nullptr
);
return
{
vp
,
xs
.
shared_access
};
}
};
template
<
class
T
>
struct
pseudo_tuple_access
<
const
param
<
T
>>
:
pseudo_tuple_access
<
param
<
T
>>
{
// nop
};
template
<
size_t
N
,
class
...
Ts
>
const
typename
detail
::
type_at
<
N
,
Ts
...
>::
type
&
typename
pseudo_tuple_access
<
const
typename
detail
::
type_at
<
N
,
Ts
...
>::
type
>::
result_type
get
(
const
detail
::
pseudo_tuple
<
Ts
...
>&
tv
)
{
static_assert
(
N
<
sizeof
...(
Ts
),
"N >= tv.size()"
);
auto
vp
=
tv
.
at
(
N
);
CAF_ASSERT
(
vp
!=
nullptr
);
return
*
reinterpret_cast
<
const
typename
detail
::
type_at
<
N
,
Ts
...
>::
type
*>
(
vp
);
pseudo_tuple_access
<
const
typename
detail
::
type_at
<
N
,
Ts
...
>::
type
>
f
;
return
f
.
get
(
tv
,
N
);
}
template
<
size_t
N
,
class
...
Ts
>
typename
detail
::
type_at
<
N
,
Ts
...
>::
type
&
get
(
detail
::
pseudo_tuple
<
Ts
...
>&
tv
)
{
typename
pseudo_tuple_access
<
typename
detail
::
type_at
<
N
,
Ts
...
>::
type
>::
result_type
get
(
detail
::
pseudo_tuple
<
Ts
...
>&
tv
)
{
static_assert
(
N
<
sizeof
...(
Ts
),
"N >= tv.size()"
);
auto
vp
=
tv
.
get_mutable
(
N
);
CAF_ASSERT
(
vp
!=
nullptr
);
return
*
reinterpret_cast
<
typename
detail
::
type_at
<
N
,
Ts
...
>::
type
*>
(
vp
);
pseudo_tuple_access
<
typename
detail
::
type_at
<
N
,
Ts
...
>::
type
>
f
;
return
f
.
get
(
tv
,
N
);
}
}
// namespace detail
...
...
libcaf_core/caf/match_case.hpp
View file @
b4db95d5
...
...
@@ -20,11 +20,13 @@
#ifndef CAF_MATCH_CASE_HPP
#define CAF_MATCH_CASE_HPP
#include <type_traits>
#include "caf/none.hpp"
#include "caf/param.hpp"
#include "caf/optional.hpp"
#include "caf/skip_message.hpp"
#include "caf/match_case.hpp"
#include "caf/skip_message.hpp"
#include "caf/detail/int_list.hpp"
#include "caf/detail/try_match.hpp"
...
...
@@ -75,6 +77,12 @@ struct match_case_zipper {
}
};
template
<
class
T
>
T
&&
unopt
(
T
&&
v
,
typename
std
::
enable_if
<
std
::
is_rvalue_reference
<
T
&&>::
value
>::
type
*
=
0
)
{
return
std
::
move
(
v
);
}
template
<
class
T
>
T
&
unopt
(
T
&
v
)
{
return
v
;
...
...
@@ -159,12 +167,15 @@ public:
using
pattern
=
typename
detail
::
tl_map
<
arg_types
,
std
::
decay
param_
decay
>::
type
;
using
intermediate_tuple
=
typename
detail
::
tl_apply
<
pattern
,
typename
detail
::
tl_map
<
arg_types
,
std
::
decay
>::
type
,
detail
::
pseudo_tuple
>::
type
;
...
...
@@ -178,15 +189,15 @@ public:
}
match_case
::
result
invoke
(
detail
::
invoke_result_visitor
&
f
,
message
&
msg
)
override
{
intermediate_tuple
it
;
intermediate_tuple
it
{
msg
.
shared
()}
;
detail
::
meta_elements
<
pattern
>
ms
;
// check if try_match() reports success
if
(
!
detail
::
try_match
(
msg
,
ms
.
arr
.
data
(),
ms
.
arr
.
size
(),
it
.
data
))
{
if
(
!
detail
::
try_match
(
msg
,
ms
.
arr
.
data
(),
ms
.
arr
.
size
(),
it
.
data
))
return
match_case
::
no_match
;
}
// detach msg before invoking fun_ if needed
if
(
is_manipulator
)
{
if
(
is_manipulator
&&
it
.
shared_access
)
{
msg
.
force_unshare
();
it
.
shared_access
=
false
;
// update pointers in our intermediate tuple
for
(
size_t
i
=
0
;
i
<
msg
.
size
();
++
i
)
{
// msg is guaranteed to be detached, hence we don't need to
...
...
libcaf_core/caf/message.hpp
View file @
b4db95d5
...
...
@@ -298,6 +298,10 @@ public:
vals_
.
unshare
();
}
inline
bool
shared
()
const
{
return
vals_
?
vals_
->
shared
()
:
false
;
}
void
reset
(
raw_ptr
new_ptr
=
nullptr
,
bool
add_ref
=
true
);
void
swap
(
message
&
other
);
...
...
libcaf_core/caf/
handler_input
.hpp
→
libcaf_core/caf/
param
.hpp
View file @
b4db95d5
...
...
@@ -17,35 +17,97 @@
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_
HANDLER_INPUT
_HPP
#define CAF_
HANDLER_INPUT
_HPP
#ifndef CAF_
PARAM
_HPP
#define CAF_
PARAM
_HPP
#include <type_traits>
#include "caf/atom.hpp"
#include "caf/type_erased_tuple.hpp"
namespace
caf
{
/// Defines `type` as `const T&` unless `T` is an arithmetic type. In the
/// latter case, `type` is an alias for `T`.
template
<
class
T
,
bool
IsArithmetic
=
std
::
is_arithmetic
<
T
>
::
value
>
struct
handler_input
{
using
type
=
const
T
&
;
/// Represents a message handler parameter of type `T` and
/// guarantees copy-on-write semantics.
template
<
class
T
>
class
param
{
public:
enum
flag
{
shared_access
,
// x_ lives in a shared type_erased_tuple
exclusive_access
,
// x_ lives in an unshared type_erased_tuple
private_access
// x_ is a copy of the original value
};
param
(
const
void
*
ptr
,
bool
is_shared
)
:
x_
(
reinterpret_cast
<
T
*>
(
const_cast
<
void
*>
(
ptr
)))
{
flag_
=
is_shared
?
shared_access
:
exclusive_access
;
}
param
(
const
param
&
other
)
=
delete
;
param
&
operator
=
(
const
param
&
other
)
=
delete
;
param
(
param
&&
other
)
:
x_
(
other
.
x_
),
flag_
(
other
.
flag_
)
{
other
.
x_
=
nullptr
;
}
~
param
()
{
if
(
flag_
==
private_access
)
delete
x_
;
}
const
T
&
get
()
const
{
return
*
x_
;
}
operator
const
T
&
()
const
{
return
*
x_
;
}
T
&
get_mutable
()
{
if
(
flag_
==
shared_access
)
{
auto
cpy
=
new
T
(
get
());
x_
=
cpy
;
flag_
=
private_access
;
}
return
*
x_
;
}
T
&&
move
()
{
return
std
::
move
(
get_mutable
());
}
private:
T
*
x_
;
flag
flag_
;
};
/// Convenience alias that wraps `T` into `param<T>`
/// unless `T` is arithmetic or an atom constant.
template
<
class
T
>
using
param_t
=
typename
std
::
conditional
<
std
::
is_arithmetic
<
T
>::
value
||
is_atom_constant
<
T
>::
value
,
T
,
param
<
T
>
>::
type
;
/// Unpacks `param<T>` to `T`.
template
<
class
T
>
struct
handler_input
<
T
,
true
>
{
struct
remove_param
{
using
type
=
T
;
};
template
<
atom_value
X
>
struct
handler_input
<
atom_constant
<
X
>
,
false
>
{
using
type
=
atom_constant
<
X
>
;
template
<
class
T
>
struct
remove_param
<
param
<
T
>
>
{
using
type
=
T
;
};
/// Convenience struct for `remove_param<std::decay<T>>`.
template
<
class
T
>
using
handler_input_t
=
typename
handler_input
<
T
>::
type
;
struct
param_decay
{
using
type
=
typename
remove_param
<
typename
std
::
decay
<
T
>::
type
>::
type
;
};
}
// namespace caf
#endif // CAF_
HANDLER_INPUT
_HPP
#endif // CAF_
PARAM
_HPP
libcaf_core/caf/type_erased_tuple.hpp
View file @
b4db95d5
...
...
@@ -61,6 +61,9 @@ public:
/// Returns the size of this tuple.
virtual
size_t
size
()
const
=
0
;
/// Returns whether multiple references to this tuple exist.
virtual
bool
shared
()
const
=
0
;
/// Returns a type hint for the element types.
virtual
uint32_t
type_token
()
const
=
0
;
...
...
@@ -158,6 +161,10 @@ public:
return
sizeof
...(
Ts
);
}
bool
shared
()
const
override
{
return
false
;
}
uint32_t
type_token
()
const
override
{
return
detail
::
make_type_token
<
Ts
...
>
();
}
...
...
libcaf_core/src/message_data.cpp
View file @
b4db95d5
...
...
@@ -28,6 +28,10 @@ message_data::~message_data() {
// nop
}
bool
message_data
::
shared
()
const
{
return
!
unique
();
}
message_data
*
message_data
::
cow_ptr
::
get_unshared
()
{
auto
p
=
ptr_
.
get
();
if
(
!
p
->
unique
())
{
...
...
libcaf_core/test/composable_behavior.cpp
View file @
b4db95d5
...
...
@@ -92,20 +92,16 @@ public:
return
"dictionary"
;
}
result
<
std
::
string
>
operator
()(
get_atom
,
const
std
::
string
&
key
)
override
{
result
<
std
::
string
>
operator
()(
get_atom
,
param
<
std
::
string
>
key
)
override
{
auto
i
=
values_
.
find
(
key
);
if
(
i
==
values_
.
end
())
return
""
;
return
i
->
second
;
}
result
<
void
>
operator
()(
put_atom
put
,
const
std
::
string
&
key
,
const
std
::
string
&
value
)
override
{
return
invoke_mutable
(
this
,
put
,
key
,
value
);
}
result
<
void
>
operator
()(
put_atom
,
std
::
string
&
key
,
std
::
string
&
value
)
{
values_
.
emplace
(
std
::
move
(
key
),
std
::
move
(
value
));
result
<
void
>
operator
()(
put_atom
,
param
<
std
::
string
>
key
,
param
<
std
::
string
>
value
)
override
{
values_
.
emplace
(
key
.
move
(),
value
.
move
());
return
unit
;
}
...
...
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