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
00fba105
Commit
00fba105
authored
Jan 08, 2016
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add third decorator for splitting requests
parent
a4e4c4ff
Changes
22
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
594 additions
and
101 deletions
+594
-101
libcaf_core/CMakeLists.txt
libcaf_core/CMakeLists.txt
+1
-0
libcaf_core/caf/actor.hpp
libcaf_core/caf/actor.hpp
+8
-0
libcaf_core/caf/check_typed_input.hpp
libcaf_core/caf/check_typed_input.hpp
+2
-2
libcaf_core/caf/data_processor.hpp
libcaf_core/caf/data_processor.hpp
+1
-1
libcaf_core/caf/decorator/splitter.hpp
libcaf_core/caf/decorator/splitter.hpp
+60
-0
libcaf_core/caf/detail/mpi_sequencer.hpp
libcaf_core/caf/detail/mpi_sequencer.hpp
+11
-11
libcaf_core/caf/detail/mpi_splice.hpp
libcaf_core/caf/detail/mpi_splice.hpp
+82
-0
libcaf_core/caf/detail/tbind.hpp
libcaf_core/caf/detail/tbind.hpp
+0
-1
libcaf_core/caf/detail/type_list.hpp
libcaf_core/caf/detail/type_list.hpp
+68
-33
libcaf_core/caf/detail/type_nr.hpp
libcaf_core/caf/detail/type_nr.hpp
+3
-3
libcaf_core/caf/detail/typed_actor_util.hpp
libcaf_core/caf/detail/typed_actor_util.hpp
+5
-5
libcaf_core/caf/match_case.hpp
libcaf_core/caf/match_case.hpp
+1
-1
libcaf_core/caf/message.hpp
libcaf_core/caf/message.hpp
+2
-0
libcaf_core/caf/typed_actor.hpp
libcaf_core/caf/typed_actor.hpp
+29
-3
libcaf_core/caf/variant.hpp
libcaf_core/caf/variant.hpp
+9
-10
libcaf_core/src/actor.cpp
libcaf_core/src/actor.cpp
+15
-0
libcaf_core/src/message.cpp
libcaf_core/src/message.cpp
+6
-0
libcaf_core/src/sequencer.cpp
libcaf_core/src/sequencer.cpp
+1
-2
libcaf_core/src/splitter.cpp
libcaf_core/src/splitter.cpp
+121
-0
libcaf_core/test/adapter.cpp
libcaf_core/test/adapter.cpp
+8
-8
libcaf_core/test/sequencer.cpp
libcaf_core/test/sequencer.cpp
+21
-21
libcaf_core/test/splitter.cpp
libcaf_core/test/splitter.cpp
+140
-0
No files found.
libcaf_core/CMakeLists.txt
View file @
00fba105
...
...
@@ -81,6 +81,7 @@ set (LIBCAF_CORE_SRCS
src/serializer.cpp
src/sequencer.cpp
src/shared_spinlock.cpp
src/splitter.cpp
src/sync_request_bouncer.cpp
src/try_match.cpp
src/type_erased_value.cpp
...
...
libcaf_core/caf/actor.hpp
View file @
00fba105
...
...
@@ -161,6 +161,8 @@ public:
return
compare
(
invalid_actor
);
}
static
actor
splice_impl
(
std
::
initializer_list
<
actor
>
xs
);
/// @endcond
private:
...
...
@@ -184,6 +186,12 @@ private:
/// Combine `f` and `g` so that `(f*g)(x) = f(g(x))`.
actor
operator
*
(
actor
f
,
actor
g
);
/// @relates actor
template
<
class
...
Ts
>
actor
splice
(
const
actor
&
x
,
const
actor
&
y
,
const
Ts
&
...
zs
)
{
return
actor
::
splice_impl
({
x
,
y
,
zs
...});
}
/// @relates actor
void
serialize
(
serializer
&
,
actor
&
,
const
unsigned
int
);
...
...
libcaf_core/caf/check_typed_input.hpp
View file @
00fba105
...
...
@@ -32,13 +32,13 @@ namespace caf {
template
<
class
...
Sigs
,
class
...
Ts
>
void
check_typed_input
(
const
typed_actor
<
Sigs
...
>&
,
const
detail
::
type_list
<
Ts
...
>&
)
{
static_assert
(
detail
::
tl_
find
<
static_assert
(
detail
::
tl_
index_of
<
detail
::
type_list
<
Ts
...
>
,
atom_value
>::
value
==
-
1
,
"atom(...) notation is not sufficient for static type "
"checking, please use atom_constant instead in this context"
);
static_assert
(
detail
::
tl_
find_if
<
static_assert
(
detail
::
tl_
exists
<
detail
::
type_list
<
Sigs
...
>
,
detail
::
input_is
<
detail
::
type_list
<
Ts
...
>>::
template
eval
>
::
value
>=
0
,
...
...
libcaf_core/caf/data_processor.hpp
View file @
00fba105
...
...
@@ -113,7 +113,7 @@ public:
template
<
class
T
>
typename
std
::
enable_if
<
std
::
is_arithmetic
<
T
>::
value
>::
type
apply
(
T
&
x
)
{
apply_builtin
(
static_cast
<
builtin
>
(
detail
::
tl_
find
<
builtin_t
,
T
>::
value
),
apply_builtin
(
static_cast
<
builtin
>
(
detail
::
tl_
index_of
<
builtin_t
,
T
>::
value
),
&
x
);
}
...
...
libcaf_core/caf/decorator/splitter.hpp
0 → 100644
View file @
00fba105
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2015 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_DECORATOR_SPLITTER_HPP
#define CAF_DECORATOR_SPLITTER_HPP
#include <vector>
#include "caf/actor_addr.hpp"
#include "caf/mailbox_element.hpp"
#include "caf/monitorable_actor.hpp"
namespace
caf
{
namespace
decorator
{
/// An actor decorator implementing "dot operator"-like compositions,
/// i.e., `f.g(x) = f(g(x))`. Composed actors are hidden actors.
/// A composed actor exits when either of its constituent actors exits;
/// Constituent actors have no dependency on the composed actor
/// by default, and exit of a composed actor has no effect on its
/// constituent actors. A composed actor is hosted on the same actor
/// system and node as `g`, the first actor on the forwarding chain.
class
splitter
:
public
monitorable_actor
{
public:
using
message_types_set
=
std
::
set
<
std
::
string
>
;
splitter
(
std
::
vector
<
actor_addr
>
workers
,
message_types_set
msg_types
);
// non-system messages are processed and then forwarded;
// system messages are handled and consumed on the spot;
// in either case, the processing is done synchronously
void
enqueue
(
mailbox_element_ptr
what
,
execution_unit
*
host
)
override
;
message_types_set
message_types
()
const
override
;
private:
std
::
vector
<
actor_addr
>
workers_
;
message_types_set
msg_types_
;
};
}
// namespace decorator
}
// namespace caf
#endif // CAF_DECORATOR_SPLITTER_HPP
libcaf_core/caf/detail/mpi_
composition
.hpp
→
libcaf_core/caf/detail/mpi_
sequencer
.hpp
View file @
00fba105
...
...
@@ -17,8 +17,8 @@
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_DETAIL_MPI_
COMPOSITION
_HPP
#define CAF_DETAIL_MPI_
COMPOSITION
_HPP
#ifndef CAF_DETAIL_MPI_
SEQUENCER
_HPP
#define CAF_DETAIL_MPI_
SEQUENCER
_HPP
#include "caf/replies_to.hpp"
...
...
@@ -28,30 +28,30 @@ namespace caf {
namespace
detail
{
template
<
class
X
,
class
Y
>
struct
mpi_
composition
_one
{
struct
mpi_
sequencer
_one
{
using
type
=
void
;
};
template
<
class
...
Xs
,
class
...
Ys
,
class
...
Zs
>
struct
mpi_
composition
_one
<
typed_mpi
<
type_list
<
Xs
...
>
,
type_list
<
Ys
...
>>
,
typed_mpi
<
type_list
<
Ys
...
>
,
type_list
<
Zs
...
>>>
{
struct
mpi_
sequencer
_one
<
typed_mpi
<
type_list
<
Xs
...
>
,
type_list
<
Ys
...
>>
,
typed_mpi
<
type_list
<
Ys
...
>
,
type_list
<
Zs
...
>>>
{
using
type
=
typed_mpi
<
type_list
<
Xs
...
>
,
type_list
<
Zs
...
>>
;
};
template
<
class
X
,
class
Y
>
struct
mpi_
composition
_all
;
struct
mpi_
sequencer
_all
;
template
<
class
X
,
class
...
Ys
>
struct
mpi_
composition
_all
<
X
,
type_list
<
Ys
...
>>
{
using
type
=
type_list
<
typename
mpi_
composition
_one
<
X
,
Ys
>::
type
...
>
;
struct
mpi_
sequencer
_all
<
X
,
type_list
<
Ys
...
>>
{
using
type
=
type_list
<
typename
mpi_
sequencer
_one
<
X
,
Ys
>::
type
...
>
;
};
template
<
template
<
class
...
>
class
Target
,
class
Ys
,
class
...
Xs
>
struct
mpi_
composition
{
struct
mpi_
sequencer
{
// combine each X with all Ys
using
all
=
typename
tl_concat
<
typename
mpi_
composition
_all
<
Xs
,
Ys
>::
type
...
typename
mpi_
sequencer
_all
<
Xs
,
Ys
>::
type
...
>::
type
;
// drop all mismatches (void results)
using
filtered
=
typename
tl_filter_not_type
<
all
,
void
>::
type
;
...
...
@@ -66,4 +66,4 @@ struct mpi_composition {
}
// namespace detail
}
// namespace caf
#endif // CAF_DETAIL_MPI_
COMPOSITION
_HPP
#endif // CAF_DETAIL_MPI_
SEQUENCER
_HPP
libcaf_core/caf/detail/mpi_splice.hpp
0 → 100644
View file @
00fba105
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2015 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_DETAIL_MPI_SPLICE_HPP
#define CAF_DETAIL_MPI_SPLICE_HPP
#include <type_traits>
#include "caf/replies_to.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/detail/typed_actor_util.hpp"
namespace
caf
{
namespace
detail
{
template
<
class
X
,
class
...
Ts
>
struct
mpi_splice_one
;
template
<
class
X
>
struct
mpi_splice_one
<
X
>
{
using
type
=
X
;
};
template
<
class
X
,
class
...
Ts
>
struct
mpi_splice_one
<
X
,
none_t
,
Ts
...
>
{
using
type
=
none_t
;
};
template
<
class
...
Xs
,
class
...
Ys
,
class
...
Zs
,
class
...
Ts
>
struct
mpi_splice_one
<
typed_mpi
<
type_list
<
Xs
...
>
,
type_list
<
Ys
...
>>
,
typed_mpi
<
type_list
<
Xs
...
>
,
type_list
<
Zs
...
>>
,
Ts
...
>
:
mpi_splice_one
<
typed_mpi
<
type_list
<
Xs
...
>
,
type_list
<
Ys
...,
Zs
...
>>
,
Ts
...
>
{
// nop
};
template
<
template
<
class
...
>
class
Target
,
class
List
,
class
...
Lists
>
struct
mpi_splice
;
template
<
template
<
class
...
>
class
Target
,
class
...
Ts
,
class
...
Lists
>
struct
mpi_splice
<
Target
,
type_list
<
Ts
...
>
,
Lists
...
>
{
using
spliced_list
=
type_list
<
typename
mpi_splice_one
<
Ts
,
typename
tl_find
<
Lists
,
input_is
<
typename
Ts
::
input_types
>::
template
eval
>
::
type
...
>::
type
...
>
;
using
filtered_list
=
typename
tl_filter_not_type
<
spliced_list
,
none_t
>::
type
;
static_assert
(
tl_size
<
filtered_list
>::
value
>
0
,
"cannot splice incompatible actor handles"
);
using
type
=
typename
tl_apply
<
filtered_list
,
Target
>::
type
;
};
}
// namespace detail
}
// namespace caf
#endif // CAF_DETAIL_MPI_SPLICE_HPP
libcaf_core/caf/detail/tbind.hpp
View file @
00fba105
...
...
@@ -28,7 +28,6 @@ struct tbind {
template
<
class
Arg2
>
struct
type
{
static
constexpr
bool
value
=
Tpl
<
Arg1
,
Arg2
>::
value
;
};
};
...
...
libcaf_core/caf/detail/type_list.hpp
View file @
00fba105
...
...
@@ -25,6 +25,7 @@
#include <type_traits>
#include "caf/unit.hpp"
#include "caf/none.hpp"
#include "caf/detail/tbind.hpp"
#include "caf/detail/type_pair.hpp"
...
...
@@ -302,16 +303,57 @@ struct tl_unzip<type_list<Elements...>> {
// int index_of(list, type)
template
<
class
List
,
typename
T
>
struct
tl_index_of
{
static
constexpr
size_t
value
=
tl_index_of
<
typename
tl_tail
<
List
>::
type
,
T
>::
value
;
/// Finds the first element of type `What` beginning at index `Pos`.
template
<
int
Pos
,
class
X
,
class
...
Ts
>
struct
tl_index_of_impl
;
template
<
int
Pos
,
class
X
>
struct
tl_index_of_impl
<
Pos
,
X
>
{
static
constexpr
int
value
=
-
1
;
};
template
<
int
Pos
,
class
X
,
class
...
Ts
>
struct
tl_index_of_impl
<
Pos
,
X
,
X
,
Ts
...
>
{
static
constexpr
int
value
=
Pos
;
};
template
<
int
Pos
,
class
X
,
class
T
,
class
...
Ts
>
struct
tl_index_of_impl
<
Pos
,
X
,
T
,
Ts
...
>
{
static
constexpr
int
value
=
tl_index_of_impl
<
Pos
+
1
,
X
,
Ts
...
>::
value
;
};
/// Finds the first element satisfying `Pred` beginning at index `Pos`.
template
<
class
List
,
class
T
>
struct
tl_index_of
;
template
<
class
...
Ts
,
class
T
>
struct
tl_index_of
<
type_list
<
Ts
...
>
,
T
>
{
static
constexpr
int
value
=
tl_index_of_impl
<
0
,
T
,
Ts
...
>::
value
;
};
template
<
size_t
N
,
typename
T
,
class
...
Ts
>
struct
tl_index_of
<
type_list
<
type_pair
<
std
::
integral_constant
<
size_t
,
N
>
,
T
>
,
Ts
...
>
,
T
>
{
static
constexpr
size_t
value
=
N
;
// int index_of(list, predicate)
template
<
int
Pos
,
template
<
class
>
class
Pred
,
class
...
Ts
>
struct
tl_index_where_impl
;
template
<
int
Pos
,
template
<
class
>
class
Pred
>
struct
tl_index_where_impl
<
Pos
,
Pred
>
{
static
constexpr
int
value
=
-
1
;
};
template
<
int
Pos
,
template
<
class
>
class
Pred
,
class
T
,
class
...
Ts
>
struct
tl_index_where_impl
<
Pos
,
Pred
,
T
,
Ts
...
>
{
static
constexpr
int
value
=
Pred
<
T
>::
value
?
Pos
:
tl_index_where_impl
<
Pos
+
1
,
Pred
,
Ts
...
>::
value
;
};
/// Finds the first element satisfying a given predicate.
template
<
class
List
,
template
<
class
>
class
Pred
>
struct
tl_index_where
;
template
<
class
...
Ts
,
template
<
class
>
class
Pred
>
struct
tl_index_where
<
type_list
<
Ts
...
>
,
Pred
>
{
static
constexpr
int
value
=
tl_index_where_impl
<
0
,
Pred
,
Ts
...
>::
value
;
};
// list reverse()
...
...
@@ -338,38 +380,31 @@ struct tl_reverse {
// bool find(list, type)
/// Finds the first element of type `What` beginning at index `Pos`.
template
<
class
List
,
template
<
class
>
class
Pred
,
int
Pos
=
0
>
template
<
template
<
class
>
class
Pred
,
class
...
Ts
>
struct
tl_find_impl
;
template
<
template
<
class
>
class
Pred
,
int
Pos
>
struct
tl_find_impl
<
type_list
<>
,
Pred
,
Pos
>
{
static
constexpr
int
value
=
-
1
;
template
<
template
<
class
>
class
Pred
>
struct
tl_find_impl
<
Pred
>
{
using
type
=
none_t
;
};
template
<
template
<
class
>
class
Pred
,
int
Pos
,
class
T0
,
class
...
Ts
>
struct
tl_find_impl
<
type_list
<
T0
,
Ts
...
>
,
Pred
,
Pos
>
{
// always use type_list for recursive calls to minimize instantiation costs
static
constexpr
int
value
=
Pred
<
T0
>::
value
?
Pos
:
tl_find_impl
<
type_list
<
Ts
...
>
,
Pred
,
Pos
+
1
>::
value
;
template
<
template
<
class
>
class
Pred
,
class
T
,
class
...
Ts
>
struct
tl_find_impl
<
Pred
,
T
,
Ts
...
>
{
using
type
=
typename
std
::
conditional
<
Pred
<
T
>::
value
,
T
,
typename
tl_find_impl
<
Pred
,
Ts
...
>::
type
>::
type
;
};
/// Finds the first element satisfying `Pred` beginning at
/// index `Pos`.
template
<
class
List
,
template
<
class
>
class
Pred
,
int
Pos
=
0
>
struct
tl_find_if
{
static
constexpr
int
value
=
tl_find_impl
<
List
,
Pred
,
Pos
>::
value
;
};
/// Finds the first element satisfying `Pred` beginning at index `Pos`.
template
<
class
List
,
template
<
class
>
class
Pred
>
struct
tl_find
;
/// Finds the first element of type `What` beginning at
/// index `Pos`.
template
<
class
List
,
class
What
,
int
Pos
=
0
>
struct
tl_find
{
static
constexpr
int
value
=
tl_find_impl
<
List
,
tbind
<
std
::
is_same
,
What
>::
template
type
,
Pos
>
::
value
;
template
<
class
...
Ts
,
template
<
class
>
class
Pred
>
struct
tl_find
<
type_list
<
Ts
...
>
,
Pred
>
{
using
type
=
typename
tl_find_impl
<
Pred
,
Ts
...
>::
type
;
};
// bool forall(predicate)
...
...
libcaf_core/caf/detail/type_nr.hpp
View file @
00fba105
...
...
@@ -94,7 +94,7 @@ using int_types_by_size =
template
<
class
T
,
bool
IsIntegral
=
std
::
is_integral
<
T
>
::
value
>
struct
type_nr
{
static
constexpr
uint16_t
value
=
static_cast
<
uint16_t
>
(
tl_
find
<
sorted_builtin_types
,
T
>::
value
+
1
);
static_cast
<
uint16_t
>
(
tl_
index_of
<
sorted_builtin_types
,
T
>::
value
+
1
);
};
template
<
class
T
>
...
...
@@ -107,13 +107,13 @@ struct type_nr<T, true> {
typename
tpair
::
second
>::
type
;
static
constexpr
uint16_t
value
=
static_cast
<
uint16_t
>
(
tl_
find
<
sorted_builtin_types
,
type
>::
value
+
1
);
static_cast
<
uint16_t
>
(
tl_
index_of
<
sorted_builtin_types
,
type
>::
value
+
1
);
};
template
<
>
struct
type_nr
<
bool
,
true
>
{
static
constexpr
uint16_t
value
=
static_cast
<
uint16_t
>
(
tl_
find
<
sorted_builtin_types
,
bool
>::
value
+
1
);
static_cast
<
uint16_t
>
(
tl_
index_of
<
sorted_builtin_types
,
bool
>::
value
+
1
);
};
template
<
atom_value
V
>
...
...
libcaf_core/caf/detail/typed_actor_util.hpp
View file @
00fba105
...
...
@@ -178,13 +178,13 @@ struct deduce_lifted_output_type<type_list<typed_continue_helper<R>>> {
template
<
class
Signatures
,
class
InputTypes
>
struct
deduce_output_type
{
static
constexpr
int
input_pos
=
t
l_find_if
<
using
signature
=
t
ypename
tl_find
<
Signatures
,
input_is
<
InputTypes
>::
template
eval
>
::
valu
e
;
static_assert
(
input_pos
!=
-
1
,
"typed actor does not support given input"
);
using
signature
=
typename
tl_at
<
Signatures
,
input_pos
>::
type
;
>
::
typ
e
;
static_assert
(
!
std
::
is_same
<
signature
,
none_t
>::
value
,
"typed actor does not support given input"
)
;
using
type
=
typename
signature
::
output_types
;
// generates the appropriate `delegated<...>` type from given signatures
using
delegated_type
=
typename
detail
::
tl_apply
<
type
,
delegated
>::
type
;
...
...
libcaf_core/caf/match_case.hpp
View file @
00fba105
...
...
@@ -326,7 +326,7 @@ protected:
template
<
class
Pattern
>
struct
pattern_has_wildcard
{
static
constexpr
bool
value
=
detail
::
tl_
find
<
detail
::
tl_
index_of
<
Pattern
,
anything
>::
value
!=
-
1
;
...
...
libcaf_core/caf/message.hpp
View file @
00fba105
...
...
@@ -267,6 +267,8 @@ public:
return
size
()
==
sizeof
...(
Ts
)
&&
match_elements_impl
(
p0
,
tlist
);
}
message
&
operator
+=
(
const
message
&
x
);
/// @cond PRIVATE
using
raw_ptr
=
detail
::
message_data
*
;
...
...
libcaf_core/caf/typed_actor.hpp
View file @
00fba105
...
...
@@ -31,10 +31,12 @@
#include "caf/typed_response_promise.hpp"
#include "caf/decorator/adapter.hpp"
#include "caf/decorator/splitter.hpp"
#include "caf/decorator/sequencer.hpp"
#include "caf/detail/mpi_bind.hpp"
#include "caf/detail/mpi_composition.hpp"
#include "caf/detail/mpi_splice.hpp"
#include "caf/detail/mpi_sequencer.hpp"
namespace
caf
{
...
...
@@ -287,24 +289,48 @@ bool operator!=(const typed_actor<Xs...>& x,
/// Returns a new actor that implements the composition `f.g(x) = f(g(x))`.
/// @relates typed_actor
template
<
class
...
Xs
,
class
...
Ys
>
typename
detail
::
mpi_
composition
<
typename
detail
::
mpi_
sequencer
<
typed_actor
,
detail
::
type_list
<
Xs
...
>
,
Ys
...
>::
type
operator
*
(
typed_actor
<
Xs
...
>
f
,
typed_actor
<
Ys
...
>
g
)
{
using
result
=
typename
detail
::
mpi_
composition
<
typename
detail
::
mpi_
sequencer
<
typed_actor
,
detail
::
type_list
<
Xs
...
>
,
Ys
...
>::
type
;
if
(
!
f
||
!
g
)
return
invalid_actor
;
auto
mts
=
g
->
home_system
().
message_types
(
result
{});
auto
ptr
=
make_counted
<
decorator
::
sequencer
>
(
f
.
address
(),
g
.
address
(),
std
::
move
(
mts
));
return
actor_cast
<
result
>
(
std
::
move
(
ptr
));
}
template
<
class
...
Xs
,
class
...
Ts
>
typename
detail
::
mpi_splice
<
typed_actor
,
detail
::
type_list
<
Xs
...
>
,
typename
Ts
::
signatures
...
>::
type
splice
(
const
typed_actor
<
Xs
...
>&
x
,
const
Ts
&
...
xs
)
{
using
result
=
typename
detail
::
mpi_splice
<
typed_actor
,
detail
::
type_list
<
Xs
...
>
,
typename
Ts
::
signatures
...
>::
type
;
std
::
vector
<
actor_addr
>
tmp
{
x
.
address
(),
xs
.
address
()...};
for
(
auto
&
addr
:
tmp
)
if
(
!
addr
)
return
invalid_actor
;
auto
mts
=
x
->
home_system
().
message_types
(
result
{});
auto
ptr
=
make_counted
<
decorator
::
splitter
>
(
std
::
move
(
tmp
),
std
::
move
(
mts
));
return
actor_cast
<
result
>
(
std
::
move
(
ptr
));
}
/// @relates typed_actor
template
<
class
T
,
class
...
Ts
>
typename
std
::
enable_if
<
T
::
is_saving
::
value
>::
type
...
...
libcaf_core/caf/variant.hpp
View file @
00fba105
...
...
@@ -200,12 +200,11 @@ private:
template
<
class
U
>
void
set
(
U
&&
arg
)
{
using
type
=
typename
std
::
decay
<
U
>::
type
;
static
constexpr
int
type_id
=
detail
::
tl_find_if
<
types
,
detail
::
tbind
<
is_same_ish
,
type
>::
template
type
>
::
value
;
static
constexpr
int
type_id
=
detail
::
tl_index_where
<
types
,
detail
::
tbind
<
is_same_ish
,
type
>::
template
type
>
::
value
;
static_assert
(
type_id
>=
0
,
"invalid type for variant"
);
std
::
integral_constant
<
int
,
type_id
>
token
;
if
(
type_
!=
type_id
)
{
...
...
@@ -248,8 +247,8 @@ private:
template
<
class
T
,
class
...
Us
>
T
&
get
(
variant
<
Us
...
>&
value
)
{
using
namespace
detail
;
int_token
<
tl_
find_if
<
type_list
<
Us
...
>
,
tbind
<
is_same_ish
,
T
>::
template
type
>
::
value
>
token
;
int_token
<
tl_
index_where
<
type_list
<
Us
...
>
,
tbind
<
is_same_ish
,
T
>::
template
type
>
::
value
>
token
;
// silence compiler error about "binding to unrelated types" such as
// 'signed char' to 'char' (which is obvious bullshit)
return
reinterpret_cast
<
T
&>
(
value
.
get
(
token
));
...
...
@@ -266,8 +265,8 @@ const T& get(const variant<Us...>& value) {
template
<
class
T
,
class
...
Us
>
T
*
get
(
variant
<
Us
...
>*
value
)
{
using
namespace
detail
;
int_token
<
tl_
find_if
<
type_list
<
Us
...
>
,
tbind
<
is_same_ish
,
T
>::
template
type
>
::
value
>
token
;
int_token
<
tl_
index_where
<
type_list
<
Us
...
>
,
tbind
<
is_same_ish
,
T
>::
template
type
>
::
value
>
token
;
if
(
value
->
is
(
token
))
return
&
get
<
T
>
(
*
value
);
return
nullptr
;
...
...
libcaf_core/src/actor.cpp
View file @
00fba105
...
...
@@ -31,6 +31,7 @@
#include "caf/event_based_actor.hpp"
#include "caf/decorator/adapter.hpp"
#include "caf/decorator/splitter.hpp"
#include "caf/decorator/sequencer.hpp"
namespace
caf
{
...
...
@@ -106,4 +107,18 @@ std::string to_string(const actor& x) {
return
to_string
(
x
.
address
());
}
actor
actor
::
splice_impl
(
std
::
initializer_list
<
actor
>
xs
)
{
if
(
xs
.
size
()
<
2
)
return
invalid_actor
;
std
::
vector
<
actor_addr
>
tmp
;
for
(
auto
&
x
:
xs
)
if
(
x
)
tmp
.
push_back
(
x
.
address
());
else
return
invalid_actor
;
auto
ptr
=
make_counted
<
decorator
::
splitter
>
(
std
::
move
(
tmp
),
std
::
set
<
std
::
string
>
{});
return
actor_cast
<
actor
>
(
std
::
move
(
ptr
));
}
}
// namespace caf
libcaf_core/src/message.cpp
View file @
00fba105
...
...
@@ -69,6 +69,12 @@ bool message::match_element(size_t pos, uint16_t typenr,
return
vals_
->
match_element
(
pos
,
typenr
,
rtti
);
}
message
&
message
::
operator
+=
(
const
message
&
x
)
{
auto
tmp
=
*
this
+
x
;
swap
(
tmp
);
return
*
this
;
}
bool
message
::
equals
(
const
message
&
other
)
const
{
if
(
empty
())
return
other
.
empty
();
...
...
libcaf_core/src/sequencer.cpp
View file @
00fba105
...
...
@@ -44,8 +44,7 @@ sequencer::sequencer(actor_addr f, actor_addr g, message_types_set msg_types)
g_
->
attach
(
default_attachable
::
make_monitor
(
address
()));
}
void
sequencer
::
enqueue
(
mailbox_element_ptr
what
,
execution_unit
*
context
)
{
void
sequencer
::
enqueue
(
mailbox_element_ptr
what
,
execution_unit
*
context
)
{
if
(
!
what
)
return
;
// not even an empty message
auto
reason
=
exit_reason_
.
load
();
...
...
libcaf_core/src/splitter.cpp
0 → 100644
View file @
00fba105
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2015 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/decorator/splitter.hpp"
#include "caf/actor_system.hpp"
#include "caf/stateful_actor.hpp"
#include "caf/response_promise.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/default_attachable.hpp"
#include "caf/detail/disposer.hpp"
#include "caf/detail/sync_request_bouncer.hpp"
namespace
caf
{
namespace
decorator
{
namespace
{
struct
splitter_state
{
response_promise
rp
;
message
result
;
size_t
pending
;
};
behavior
fan_out_fan_in
(
stateful_actor
<
splitter_state
>*
self
,
const
std
::
vector
<
actor_addr
>&
workers
)
{
return
{
others
>>
[
=
]
{
self
->
state
.
rp
=
self
->
make_response_promise
();
self
->
state
.
pending
=
workers
.
size
();
// request().await() has LIFO ordering
for
(
auto
i
=
workers
.
rbegin
();
i
!=
workers
.
rend
();
++
i
)
self
->
request
(
actor_cast
<
actor
>
(
*
i
),
self
->
current_message
()).
generic_await
(
[
=
](
const
message
&
tmp
)
{
self
->
state
.
result
+=
tmp
;
if
(
--
self
->
state
.
pending
==
0
)
self
->
state
.
rp
.
deliver
(
std
::
move
(
self
->
state
.
result
));
},
[
=
](
const
error
&
err
)
{
self
->
state
.
rp
.
deliver
(
err
);
self
->
quit
();
}
);
self
->
unbecome
();
}
};
}
}
// namespace <anonymous>
splitter
::
splitter
(
std
::
vector
<
actor_addr
>
workers
,
message_types_set
msg_types
)
:
monitorable_actor
(
&
workers
.
front
()
->
home_system
(),
workers
.
front
()
->
home_system
().
next_actor_id
(),
workers
.
front
()
->
node
(),
is_abstract_actor_flag
|
is_actor_dot_decorator_flag
),
workers_
(
std
::
move
(
workers
)),
msg_types_
(
std
::
move
(
msg_types
))
{
// composed actor has dependency on constituent actors by default;
// if either constituent actor is already dead upon establishing
// the dependency, the actor is spawned dead
auto
addr
=
address
();
for
(
auto
&
worker
:
workers_
)
worker
->
attach
(
default_attachable
::
make_monitor
(
addr
));
}
void
splitter
::
enqueue
(
mailbox_element_ptr
what
,
execution_unit
*
context
)
{
if
(
!
what
)
return
;
// not even an empty message
auto
reason
=
exit_reason_
.
load
();
if
(
reason
!=
exit_reason
::
not_exited
)
{
// actor has exited
auto
&
mid
=
what
->
mid
;
if
(
mid
.
is_request
())
{
// make sure that a request always gets a response;
// the exit reason reflects the first actor on the
// forwarding chain that is out of service
detail
::
sync_request_bouncer
rb
{
reason
};
rb
(
what
->
sender
,
mid
);
}
return
;
}
auto
down_msg_handler
=
[
&
](
const
down_msg
&
dm
)
{
// quit if either `f` or `g` are no longer available
auto
pred
=
[
&
](
const
actor_addr
&
x
)
{
return
x
==
dm
.
source
;
};
if
(
std
::
any_of
(
workers_
.
begin
(),
workers_
.
end
(),
pred
))
monitorable_actor
::
cleanup
(
dm
.
reason
,
context
);
};
// handle and consume the system message;
// the only effect that MAY result from handling a system message
// is to exit the actor if it hasn't exited already;
// `handle_system_message()` is thread-safe, and if the actor
// has already exited upon the invocation, nothing is done
if
(
handle_system_message
(
*
what
,
context
,
false
,
down_msg_handler
))
return
;
auto
helper
=
context
->
system
().
spawn
(
fan_out_fan_in
,
workers_
);
helper
->
enqueue
(
std
::
move
(
what
),
context
);
}
splitter
::
message_types_set
splitter
::
message_types
()
const
{
return
msg_types_
;
}
}
// namespace decorator
}
// namespace caf
libcaf_core/test/adapter.cpp
View file @
00fba105
...
...
@@ -28,7 +28,7 @@ using namespace caf;
namespace
{
behavior
dbl_bhvr
(
event_based_actor
*
self
)
{
behavior
testee
(
event_based_actor
*
self
)
{
return
{
[](
int
v
)
{
return
2
*
v
;
...
...
@@ -65,7 +65,7 @@ struct fixture {
CAF_TEST_FIXTURE_SCOPE
(
adapter_tests
,
fixture
)
CAF_TEST
(
identity
)
{
auto
dbl
=
system
.
spawn
(
dbl_bhvr
);
auto
dbl
=
system
.
spawn
(
testee
);
CAF_CHECK
(
system
.
registry
().
running
()
==
1
);
auto
bound
=
dbl
.
bind
(
1
);
CAF_CHECK
(
system
.
registry
().
running
()
==
1
);
...
...
@@ -80,7 +80,7 @@ CAF_TEST(identity) {
// bound actor spawned dead if decorated
// actor is already dead upon spawning
CAF_TEST
(
lifetime_1
)
{
auto
dbl
=
system
.
spawn
(
dbl_bhvr
);
auto
dbl
=
system
.
spawn
(
testee
);
self
->
monitor
(
dbl
);
anon_send_exit
(
dbl
,
exit_reason
::
kill
);
wait_until_exited
();
...
...
@@ -90,7 +90,7 @@ CAF_TEST(lifetime_1) {
// bound actor exits when decorated actor exits
CAF_TEST
(
lifetime_2
)
{
auto
dbl
=
system
.
spawn
(
dbl_bhvr
);
auto
dbl
=
system
.
spawn
(
testee
);
auto
bound
=
dbl
.
bind
(
1
);
self
->
monitor
(
bound
);
anon_send
(
dbl
,
message
{});
...
...
@@ -101,13 +101,13 @@ CAF_TEST(lifetime_2) {
// 2) exits by receiving an exit message
// 3) exit has no effect on decorated actor
CAF_TEST
(
lifetime_3
)
{
auto
dbl
=
system
.
spawn
(
dbl_bhvr
);
auto
dbl
=
system
.
spawn
(
testee
);
auto
bound
=
dbl
.
bind
(
1
);
anon_send
(
bound
,
down_msg
{
self
->
address
(),
exit_reason
::
kill
});
CAF_CHECK
(
!
exited
(
bound
));
self
->
monitor
(
bound
);
auto
em_sender
=
system
.
spawn
(
dbl_bhvr
);
auto
em_sender
=
system
.
spawn
(
testee
);
em_sender
->
link_to
(
bound
->
address
());
anon_send_exit
(
em_sender
,
exit_reason
::
kill
);
wait_until_exited
();
...
...
@@ -123,7 +123,7 @@ CAF_TEST(lifetime_3) {
}
CAF_TEST
(
request_response_promise
)
{
auto
dbl
=
system
.
spawn
(
dbl_bhvr
);
auto
dbl
=
system
.
spawn
(
testee
);
auto
bound
=
dbl
.
bind
(
1
);
anon_send_exit
(
bound
,
exit_reason
::
kill
);
CAF_CHECK
(
exited
(
bound
));
...
...
@@ -171,7 +171,7 @@ CAF_TEST(partial_currying) {
}
CAF_TEST
(
full_currying
)
{
auto
dbl_actor
=
system
.
spawn
(
dbl_bhvr
);
auto
dbl_actor
=
system
.
spawn
(
testee
);
auto
bound
=
dbl_actor
.
bind
(
1
);
self
->
request
(
bound
,
message
{}).
receive
(
[](
int
v
)
{
...
...
libcaf_core/test/sequencer.cpp
View file @
00fba105
...
...
@@ -28,7 +28,7 @@ using namespace caf;
namespace
{
behavior
dbl_bhvr
(
event_based_actor
*
self
)
{
behavior
testee
(
event_based_actor
*
self
)
{
return
{
[](
int
v
)
{
return
2
*
v
;
...
...
@@ -42,13 +42,13 @@ behavior dbl_bhvr(event_based_actor* self) {
using
first_stage
=
typed_actor
<
replies_to
<
int
>::
with
<
double
,
double
>>
;
using
second_stage
=
typed_actor
<
replies_to
<
double
,
double
>::
with
<
double
>>
;
first_stage
::
behavior_type
first_stage_impl
()
{
first_stage
::
behavior_type
typed_first_stage
()
{
return
[](
int
i
)
{
return
std
::
make_tuple
(
i
*
2.0
,
i
*
4.0
);
};
};
second_stage
::
behavior_type
second_stage_impl
()
{
second_stage
::
behavior_type
typed_second_stage
()
{
return
[](
double
x
,
double
y
)
{
return
x
*
y
;
};
...
...
@@ -82,8 +82,8 @@ CAF_TEST_FIXTURE_SCOPE(sequencer_tests, fixture)
CAF_TEST
(
identity
)
{
actor_system
system_of_g
;
actor_system
system_of_f
;
auto
g
=
system_of_g
.
spawn
(
first_stage_impl
);
auto
f
=
system_of_f
.
spawn
(
second_stage_impl
);
auto
g
=
system_of_g
.
spawn
(
typed_first_stage
);
auto
f
=
system_of_f
.
spawn
(
typed_second_stage
);
CAF_CHECK
(
system_of_g
.
registry
().
running
()
==
1
);
auto
h
=
f
*
g
;
CAF_CHECK
(
system_of_g
.
registry
().
running
()
==
1
);
...
...
@@ -99,8 +99,8 @@ CAF_TEST(identity) {
// spawned dead if `g` is already dead upon spawning
CAF_TEST
(
lifetime_1a
)
{
auto
g
=
system
.
spawn
(
dbl_bhvr
);
auto
f
=
system
.
spawn
(
dbl_bhvr
);
auto
g
=
system
.
spawn
(
testee
);
auto
f
=
system
.
spawn
(
testee
);
self
->
monitor
(
g
);
anon_send_exit
(
g
,
exit_reason
::
kill
);
wait_until_exited
();
...
...
@@ -111,8 +111,8 @@ CAF_TEST(lifetime_1a) {
// spawned dead if `f` is already dead upon spawning
CAF_TEST
(
lifetime_1b
)
{
auto
g
=
system
.
spawn
(
dbl_bhvr
);
auto
f
=
system
.
spawn
(
dbl_bhvr
);
auto
g
=
system
.
spawn
(
testee
);
auto
f
=
system
.
spawn
(
testee
);
self
->
monitor
(
f
);
anon_send_exit
(
f
,
exit_reason
::
kill
);
wait_until_exited
();
...
...
@@ -123,8 +123,8 @@ CAF_TEST(lifetime_1b) {
// `f.g` exits when `g` exits
CAF_TEST
(
lifetime_2a
)
{
auto
g
=
system
.
spawn
(
dbl_bhvr
);
auto
f
=
system
.
spawn
(
dbl_bhvr
);
auto
g
=
system
.
spawn
(
testee
);
auto
f
=
system
.
spawn
(
testee
);
auto
h
=
f
*
g
;
self
->
monitor
(
h
);
anon_send
(
g
,
message
{});
...
...
@@ -134,8 +134,8 @@ CAF_TEST(lifetime_2a) {
// `f.g` exits when `f` exits
CAF_TEST
(
lifetime_2b
)
{
auto
g
=
system
.
spawn
(
dbl_bhvr
);
auto
f
=
system
.
spawn
(
dbl_bhvr
);
auto
g
=
system
.
spawn
(
testee
);
auto
f
=
system
.
spawn
(
testee
);
auto
h
=
f
*
g
;
self
->
monitor
(
h
);
anon_send
(
f
,
message
{});
...
...
@@ -147,13 +147,13 @@ CAF_TEST(lifetime_2b) {
// 2) exits by receiving an exit message
// 3) exit has no effect on constituent actors
CAF_TEST
(
lifetime_3
)
{
auto
g
=
system
.
spawn
(
dbl_bhvr
);
auto
f
=
system
.
spawn
(
dbl_bhvr
);
auto
g
=
system
.
spawn
(
testee
);
auto
f
=
system
.
spawn
(
testee
);
auto
h
=
f
*
g
;
self
->
monitor
(
h
);
anon_send
(
h
,
down_msg
{
self
->
address
(),
exit_reason
::
kill
});
CAF_CHECK
(
!
exited
(
h
));
auto
em_sender
=
system
.
spawn
(
dbl_bhvr
);
auto
em_sender
=
system
.
spawn
(
testee
);
em_sender
->
link_to
(
h
.
address
());
anon_send_exit
(
em_sender
,
exit_reason
::
kill
);
wait_until_exited
();
...
...
@@ -178,8 +178,8 @@ CAF_TEST(lifetime_3) {
}
CAF_TEST
(
request_response_promise
)
{
auto
g
=
system
.
spawn
(
dbl_bhvr
);
auto
f
=
system
.
spawn
(
dbl_bhvr
);
auto
g
=
system
.
spawn
(
testee
);
auto
f
=
system
.
spawn
(
testee
);
auto
h
=
f
*
g
;
anon_send_exit
(
h
,
exit_reason
::
kill
);
CAF_CHECK
(
exited
(
h
));
...
...
@@ -197,8 +197,8 @@ CAF_TEST(request_response_promise) {
// single composition of distinct actors
CAF_TEST
(
dot_composition_1
)
{
auto
first
=
system
.
spawn
(
first_stage_impl
);
auto
second
=
system
.
spawn
(
second_stage_impl
);
auto
first
=
system
.
spawn
(
typed_first_stage
);
auto
second
=
system
.
spawn
(
typed_second_stage
);
auto
first_then_second
=
second
*
first
;
self
->
request
(
first_then_second
,
42
).
receive
(
[](
double
res
)
{
...
...
@@ -211,7 +211,7 @@ CAF_TEST(dot_composition_1) {
// multiple self composition
CAF_TEST
(
dot_composition_2
)
{
auto
dbl_actor
=
system
.
spawn
(
dbl_bhvr
);
auto
dbl_actor
=
system
.
spawn
(
testee
);
auto
dbl_x4_actor
=
dbl_actor
*
dbl_actor
*
dbl_actor
*
dbl_actor
;
self
->
request
(
dbl_x4_actor
,
1
).
receive
(
...
...
libcaf_core/test/splitter.cpp
0 → 100644
View file @
00fba105
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2015 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/config.hpp"
#define CAF_SUITE splitter
#include "caf/test/unit_test.hpp"
#include "caf/all.hpp"
using
namespace
caf
;
namespace
{
using
first_stage
=
typed_actor
<
replies_to
<
double
>::
with
<
double
,
double
>>
;
using
second_stage
=
typed_actor
<
replies_to
<
double
,
double
>::
with
<
double
>>
;
first_stage
::
behavior_type
typed_first_stage
()
{
return
[](
double
x
)
{
return
std
::
make_tuple
(
x
*
2.0
,
x
*
4.0
);
};
};
second_stage
::
behavior_type
typed_second_stage
()
{
return
[](
double
x
,
double
y
)
{
return
x
*
y
;
};
}
behavior
untyped_first_stage
()
{
return
typed_first_stage
().
unbox
();
};
behavior
untyped_second_stage
()
{
return
typed_second_stage
().
unbox
();
}
struct
fixture
{
actor_system
system
;
scoped_actor
self
{
system
,
true
};
actor
first
;
actor
second
;
actor
first_and_second
;
~
fixture
()
{
anon_send_exit
(
first
,
exit_reason
::
kill
);
anon_send_exit
(
second
,
exit_reason
::
kill
);
}
void
init_untyped
()
{
using
namespace
std
::
placeholders
;
first
=
system
.
spawn
(
untyped_first_stage
);
second
=
system
.
spawn
(
untyped_second_stage
);
first_and_second
=
splice
(
first
,
second
.
bind
(
23.0
,
_1
));
}
void
await_down
(
const
actor
&
x
)
{
self
->
monitor
(
x
);
self
->
receive
(
[
&
](
const
down_msg
&
dm
)
->
maybe
<
skip_message_t
>
{
if
(
dm
.
source
!=
x
)
return
skip_message
();
return
none
;
}
);
}
};
}
// namespace <anonymous>
CAF_TEST_FIXTURE_SCOPE
(
sequencer_tests
,
fixture
)
CAF_TEST
(
identity
)
{
init_untyped
();
CAF_CHECK
(
first
!=
second
);
CAF_CHECK
(
first
!=
first_and_second
);
CAF_CHECK
(
second
!=
first_and_second
);
}
CAF_TEST
(
kill_first
)
{
init_untyped
();
anon_send_exit
(
first
,
exit_reason
::
kill
);
await_down
(
first_and_second
);
}
CAF_TEST
(
kill_second
)
{
init_untyped
();
anon_send_exit
(
second
,
exit_reason
::
kill
);
await_down
(
first_and_second
);
}
CAF_TEST
(
untyped_splicing
)
{
init_untyped
();
self
->
request
(
first_and_second
,
42.0
).
receive
(
[](
double
x
,
double
y
,
double
z
)
{
CAF_CHECK
(
x
==
(
42.0
*
2.0
));
CAF_CHECK
(
y
==
(
42.0
*
4.0
));
CAF_CHECK
(
z
==
(
23.0
*
42.0
));
}
);
}
CAF_TEST
(
typed_splicing
)
{
using
namespace
std
::
placeholders
;
auto
x
=
system
.
spawn
(
typed_first_stage
);
auto
y
=
system
.
spawn
(
typed_second_stage
);
auto
x_and_y
=
splice
(
x
,
y
.
bind
(
23.0
,
_1
));
using
expected_type
=
typed_actor
<
replies_to
<
double
>
::
with
<
double
,
double
,
double
>>
;
static_assert
(
std
::
is_same
<
decltype
(
x_and_y
),
expected_type
>::
value
,
"splice() did not compute the correct result"
);
self
->
request
(
x_and_y
,
42.0
).
receive
(
[](
double
x
,
double
y
,
double
z
)
{
CAF_CHECK
(
x
==
(
42.0
*
2.0
));
CAF_CHECK
(
y
==
(
42.0
*
4.0
));
CAF_CHECK
(
z
==
(
23.0
*
42.0
));
}
);
anon_send_exit
(
x
,
exit_reason
::
kill
);
anon_send_exit
(
y
,
exit_reason
::
kill
);
}
CAF_TEST_FIXTURE_SCOPE_END
()
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