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
b877c738
Unverified
Commit
b877c738
authored
Sep 17, 2019
by
Joseph Noir
Committed by
GitHub
Sep 17, 2019
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #909
Support streaming in composable behaviors
parents
94a262f9
e24ad712
Changes
32
Hide whitespace changes
Inline
Side-by-side
Showing
32 changed files
with
1379 additions
and
888 deletions
+1379
-888
doc/tex/Streaming.tex
doc/tex/Streaming.tex
+8
-8
examples/streaming/integer_stream.cpp
examples/streaming/integer_stream.cpp
+83
-96
libcaf_core/caf/all.hpp
libcaf_core/caf/all.hpp
+74
-69
libcaf_core/caf/attach_continuous_stream_source.hpp
libcaf_core/caf/attach_continuous_stream_source.hpp
+85
-0
libcaf_core/caf/attach_continuous_stream_stage.hpp
libcaf_core/caf/attach_continuous_stream_stage.hpp
+81
-0
libcaf_core/caf/attach_stream_sink.hpp
libcaf_core/caf/attach_stream_sink.hpp
+62
-0
libcaf_core/caf/attach_stream_source.hpp
libcaf_core/caf/attach_stream_source.hpp
+170
-0
libcaf_core/caf/attach_stream_stage.hpp
libcaf_core/caf/attach_stream_stage.hpp
+109
-0
libcaf_core/caf/composable_behavior.hpp
libcaf_core/caf/composable_behavior.hpp
+9
-14
libcaf_core/caf/composed_type.hpp
libcaf_core/caf/composed_type.hpp
+39
-90
libcaf_core/caf/deduce_mpi.hpp
libcaf_core/caf/deduce_mpi.hpp
+0
-8
libcaf_core/caf/detail/invoke_result_visitor.hpp
libcaf_core/caf/detail/invoke_result_visitor.hpp
+0
-6
libcaf_core/caf/detail/type_traits.hpp
libcaf_core/caf/detail/type_traits.hpp
+45
-0
libcaf_core/caf/fwd.hpp
libcaf_core/caf/fwd.hpp
+0
-4
libcaf_core/caf/make_sink_result.hpp
libcaf_core/caf/make_sink_result.hpp
+5
-7
libcaf_core/caf/make_source_result.hpp
libcaf_core/caf/make_source_result.hpp
+16
-14
libcaf_core/caf/make_stage_result.hpp
libcaf_core/caf/make_stage_result.hpp
+15
-15
libcaf_core/caf/param.hpp
libcaf_core/caf/param.hpp
+20
-9
libcaf_core/caf/replies_to.hpp
libcaf_core/caf/replies_to.hpp
+0
-12
libcaf_core/caf/result.hpp
libcaf_core/caf/result.hpp
+22
-23
libcaf_core/caf/scheduled_actor.hpp
libcaf_core/caf/scheduled_actor.hpp
+14
-27
libcaf_core/caf/stream_manager.hpp
libcaf_core/caf/stream_manager.hpp
+0
-1
libcaf_core/caf/stream_slot.hpp
libcaf_core/caf/stream_slot.hpp
+12
-13
libcaf_core/caf/typed_actor_pointer.hpp
libcaf_core/caf/typed_actor_pointer.hpp
+5
-1
libcaf_core/caf/typed_actor_view.hpp
libcaf_core/caf/typed_actor_view.hpp
+8
-5
libcaf_core/test/composable_behavior.cpp
libcaf_core/test/composable_behavior.cpp
+183
-127
libcaf_core/test/continuous_streaming.cpp
libcaf_core/test/continuous_streaming.cpp
+58
-67
libcaf_core/test/fused_downstream_manager.cpp
libcaf_core/test/fused_downstream_manager.cpp
+29
-33
libcaf_core/test/metaprogramming.cpp
libcaf_core/test/metaprogramming.cpp
+0
-28
libcaf_core/test/pipeline_streaming.cpp
libcaf_core/test/pipeline_streaming.cpp
+88
-128
libcaf_core/test/selective_streaming.cpp
libcaf_core/test/selective_streaming.cpp
+65
-81
libcaf_test/caf/test/dsl.hpp
libcaf_test/caf/test/dsl.hpp
+74
-2
No files found.
doc/tex/Streaming.tex
View file @
b877c738
...
@@ -56,18 +56,18 @@ data to the next available worker.
...
@@ -56,18 +56,18 @@ data to the next available worker.
\subsection
{
Defining Sources
}
\subsection
{
Defining Sources
}
\cppexample
[17-
52
]
{
streaming/integer
_
stream
}
\cppexample
[17-
46
]
{
streaming/integer
_
stream
}
The simplest way to defining a source is to use the
\lstinline
^
make
_
source
^
The simplest way to defining a source is to use the
function and pass it three arguments:
\emph
{
initializer
}
for the state,
\lstinline
^
attach
_
stream
_
source
^
function and pass it four arguments: a pointer
\emph
{
generator
}
for producing values, and
\emph
{
predicate
}
for signaling the
to
\emph
{
self
}
,
\emph
{
initializer
}
for the state,
\emph
{
generator
}
for
end of the stream.
producing values, and
\emph
{
predicate
}
for signaling the
end of the stream.
\clearpage
\clearpage
\subsection
{
Defining Stages
}
\subsection
{
Defining Stages
}
\cppexample
[
54-87
]
{
streaming/integer
_
stream
}
\cppexample
[
48-78
]
{
streaming/integer
_
stream
}
The function
\lstinline
^
make
_
stage
^
also takes three lambdas but additionally
The function
\lstinline
^
make
_
stage
^
also takes three lambdas but additionally
the received input stream handshake as first argument. Instead of a predicate,
the received input stream handshake as first argument. Instead of a predicate,
...
@@ -78,7 +78,7 @@ data on its own and a stream terminates if no more sources exist.
...
@@ -78,7 +78,7 @@ data on its own and a stream terminates if no more sources exist.
\subsection
{
Defining Sinks
}
\subsection
{
Defining Sinks
}
\cppexample
[8
9-120
]
{
streaming/integer
_
stream
}
\cppexample
[8
0-106
]
{
streaming/integer
_
stream
}
The function
\lstinline
^
make
_
sink
^
is similar to
\lstinline
^
make
_
stage
^
, except
The function
\lstinline
^
make
_
sink
^
is similar to
\lstinline
^
make
_
stage
^
, except
that is does not produce outputs.
that is does not produce outputs.
...
@@ -87,7 +87,7 @@ that is does not produce outputs.
...
@@ -87,7 +87,7 @@ that is does not produce outputs.
\subsection
{
Initiating Streams
}
\subsection
{
Initiating Streams
}
\cppexample
[1
33-139
]
{
streaming/integer
_
stream
}
\cppexample
[1
21-125
]
{
streaming/integer
_
stream
}
In our example, we always have a source
\lstinline
^
int
_
source
^
and a sink
In our example, we always have a source
\lstinline
^
int
_
source
^
and a sink
\lstinline
^
int
_
sink
^
with an optional stage
\lstinline
^
int
_
selector
^
. Sending
\lstinline
^
int
_
sink
^
with an optional stage
\lstinline
^
int
_
selector
^
. Sending
...
...
examples/streaming/integer_stream.cpp
View file @
b877c738
...
@@ -2,7 +2,7 @@
...
@@ -2,7 +2,7 @@
* Basic, non-interactive streaming example for processing integers. *
* Basic, non-interactive streaming example for processing integers. *
******************************************************************************/
******************************************************************************/
// Manual refs: lines 17-
52, 54-87, 89-120, 133-139
(Streaming)
// Manual refs: lines 17-
46, 48-78, 80-107, 121-125
(Streaming)
#include <iostream>
#include <iostream>
#include <vector>
#include <vector>
...
@@ -16,114 +16,101 @@ namespace {
...
@@ -16,114 +16,101 @@ namespace {
// Simple source for generating a stream of integers from [0, n).
// Simple source for generating a stream of integers from [0, n).
behavior
int_source
(
event_based_actor
*
self
)
{
behavior
int_source
(
event_based_actor
*
self
)
{
return
{
return
{[
=
](
open_atom
,
int
n
)
{
[
=
](
open_atom
,
int
n
)
{
// Produce at least one value.
// Produce at least one value.
if
(
n
<=
0
)
if
(
n
<=
0
)
n
=
1
;
n
=
1
;
// Create a stream manager for implementing a stream source. The
// Create a stream manager for implementing a stream source. The
// streaming logic requires three functions: initializer, generator, and
// streaming logic requires three functions: initializer, generator, and
// predicate.
// predicate.
return
attach_stream_source
(
return
self
->
make_source
(
self
,
// Initializer. The type of the first argument (state) is freely
// Initializer. The type of the first argument (state) is freely
// chosen. If no state is required, `caf::unit_t` can be used here.
// chosen. If no state is required, `caf::unit_t` can be used here.
[](
int
&
x
)
{
[](
int
&
x
)
{
x
=
0
;
},
x
=
0
;
// Generator. This function is called by CAF to produce new stream
},
// elements for downstream actors. The `x` argument is our state again
// Generator. This function is called by CAF to produce new stream
// (with our freely chosen type). The second argument `out` points to
// elements for downstream actors. The `x` argument is our state again
// the output buffer. The template argument (here: int) determines what
// (with our freely chosen type). The second argument `out` points to
// elements downstream actors receive in this stream. Finally, `num` is
// the output buffer. The template argument (here: int) determines what
// a hint from CAF how many elements we should ideally insert into
// elements downstream actors receive in this stream. Finally, `num` is
// `out`. We can always insert fewer or more items.
// a hint from CAF how many elements we should ideally insert into
[
n
](
int
&
x
,
downstream
<
int
>&
out
,
size_t
num
)
{
// `out`. We can always insert fewer or more items.
auto
max_x
=
std
::
min
(
x
+
static_cast
<
int
>
(
num
),
n
);
[
n
](
int
&
x
,
downstream
<
int
>&
out
,
size_t
num
)
{
for
(;
x
<
max_x
;
++
x
)
auto
max_x
=
std
::
min
(
x
+
static_cast
<
int
>
(
num
),
n
);
out
.
push
(
x
);
for
(;
x
<
max_x
;
++
x
)
},
out
.
push
(
x
);
// Predicate. This function tells CAF when we reached the end.
},
[
n
](
const
int
&
x
)
{
return
x
==
n
;
});
// Predicate. This function tells CAF when we reached the end.
}};
[
n
](
const
int
&
x
)
{
return
x
==
n
;
}
);
}
};
}
}
// Simple stage that only selects even numbers.
// Simple stage that only selects even numbers.
behavior
int_selector
(
event_based_actor
*
self
)
{
behavior
int_selector
(
event_based_actor
*
self
)
{
return
{
return
{[
=
](
stream
<
int
>
in
)
{
[
=
](
stream
<
int
>
in
)
{
// Create a stream manager for implementing a stream stage. Similar to
// Create a stream manager for implementing a stream stage. Similar to
// `make_source`, we need three functions: initialzer, processor, and
// `make_source`, we need three functions: initialzer, processor, and
// finalizer.
// finalizer.
return
attach_stream_stage
(
return
self
->
make_stage
(
self
,
// Our input source.
// Our input source.
in
,
in
,
// Initializer. Here, we don't need any state and simply use unit_t.
// Initializer. Here, we don't need any state and simply use unit_t.
[](
unit_t
&
)
{
[](
unit_t
&
)
{
// nop
// nop
},
},
// Processor. This function takes individual input elements as `val`
// Processor. This function takes individual input elements as `val`
// and forwards even integers to `out`.
// and forwards even integers to `out`.
[](
unit_t
&
,
downstream
<
int
>&
out
,
int
val
)
{
[](
unit_t
&
,
downstream
<
int
>&
out
,
int
val
)
{
if
(
val
%
2
==
0
)
if
(
val
%
2
==
0
)
out
.
push
(
val
);
out
.
push
(
val
);
},
},
// Finalizer. Allows us to run cleanup code once the stream terminates.
// Finalizer. Allows us to run cleanup code once the stream terminates.
[
=
](
unit_t
&
,
const
error
&
err
)
{
[
=
](
unit_t
&
,
const
error
&
err
)
{
if
(
err
)
{
if
(
err
)
{
aout
(
self
)
<<
"int_selector aborted with error: "
<<
err
aout
(
self
)
<<
"int_selector aborted with error: "
<<
err
<<
std
::
endl
;
<<
std
::
endl
;
}
else
{
}
else
{
aout
(
self
)
<<
"int_selector finalized"
<<
std
::
endl
;
aout
(
self
)
<<
"int_selector finalized"
<<
std
::
endl
;
}
// else: regular stream shutdown
}
}
);
// else: regular stream shutdown
}
});
};
}
}
;
}
}
behavior
int_sink
(
event_based_actor
*
self
)
{
behavior
int_sink
(
event_based_actor
*
self
)
{
return
{
return
{[
=
](
stream
<
int
>
in
)
{
[
=
](
stream
<
int
>
in
)
{
// Create a stream manager for implementing a stream sink. Once more, we
// Create a stream manager for implementing a stream sink. Once more, we
// have to provide three functions: Initializer, Consumer, Finalizer.
// have to provide three functions: Initializer, Consumer, Finalizer.
return
attach_stream_sink
(
return
self
->
make_sink
(
self
,
// Our input source.
// Our input source.
in
,
in
,
// Initializer. Here, we store all values we receive. Note that streams
// Initializer. Here, we store all values we receive. Note that streams
// are potentially unbound, so this is usually a bad idea outside small
// are potentially unbound, so this is usually a bad idea outside small
// examples like this one.
// examples like this one.
[](
std
::
vector
<
int
>&
)
{
[](
std
::
vector
<
int
>&
)
{
// nop
// nop
},
},
// Consumer. Takes individual input elements as `val` and stores them
// Consumer. Takes individual input elements as `val` and stores them
// in our history.
// in our history.
[](
std
::
vector
<
int
>&
xs
,
int
val
)
{
[](
std
::
vector
<
int
>&
xs
,
int
val
)
{
xs
.
emplace_back
(
val
);
},
xs
.
emplace_back
(
val
);
// Finalizer. Allows us to run cleanup code once the stream terminates.
},
[
=
](
std
::
vector
<
int
>&
xs
,
const
error
&
err
)
{
// Finalizer. Allows us to run cleanup code once the stream terminates.
if
(
err
)
{
[
=
](
std
::
vector
<
int
>&
xs
,
const
error
&
err
)
{
aout
(
self
)
<<
"int_sink aborted with error: "
<<
err
<<
std
::
endl
;
if
(
err
)
{
}
else
{
aout
(
self
)
<<
"int_sink aborted with error: "
<<
err
<<
std
::
endl
;
aout
(
self
)
<<
"int_sink finalized after receiving: "
<<
xs
}
else
{
<<
std
::
endl
;
aout
(
self
)
<<
"int_sink finalized after receiving: "
<<
xs
<<
std
::
endl
;
}
}
}
);
});
}
}};
};
}
}
struct
config
:
actor_system_config
{
struct
config
:
actor_system_config
{
config
()
{
config
()
{
opt_group
{
custom_options_
,
"global"
}
opt_group
{
custom_options_
,
"global"
}
.
add
(
with_stage
,
"with-stage,s"
,
"use a stage for filtering odd numbers"
)
.
add
(
with_stage
,
"with-stage,s"
,
"use a stage for filtering odd numbers"
)
.
add
(
n
,
"num-values,n"
,
"number of values produced by the source"
);
.
add
(
n
,
"num-values,n"
,
"number of values produced by the source"
);
}
}
bool
with_stage
=
false
;
bool
with_stage
=
false
;
...
@@ -138,6 +125,6 @@ void caf_main(actor_system& sys, const config& cfg) {
...
@@ -138,6 +125,6 @@ void caf_main(actor_system& sys, const config& cfg) {
anon_send
(
pipeline
,
open_atom
::
value
,
cfg
.
n
);
anon_send
(
pipeline
,
open_atom
::
value
,
cfg
.
n
);
}
}
}
// namespace
<anonymous>
}
// namespace
CAF_MAIN
()
CAF_MAIN
()
libcaf_core/caf/all.hpp
View file @
b877c738
...
@@ -20,93 +20,98 @@
...
@@ -20,93 +20,98 @@
#include "caf/config.hpp"
#include "caf/config.hpp"
#include "caf/sec.hpp"
#include "caf/abstract_actor.hpp"
#include "caf/atom.hpp"
#include "caf/abstract_channel.hpp"
#include "caf/send.hpp"
#include "caf/abstract_composable_behavior.hpp"
#include "caf/skip.hpp"
#include "caf/abstract_group.hpp"
#include "caf/unit.hpp"
#include "caf/term.hpp"
#include "caf/actor.hpp"
#include "caf/actor.hpp"
#include "caf/after.hpp"
#include "caf/error.hpp"
#include "caf/group.hpp"
#include "caf/extend.hpp"
#include "caf/logger.hpp"
#include "caf/others.hpp"
#include "caf/result.hpp"
#include "caf/stream.hpp"
#include "caf/message.hpp"
#include "caf/node_id.hpp"
#include "caf/behavior.hpp"
#include "caf/defaults.hpp"
#include "caf/duration.hpp"
#include "caf/expected.hpp"
#include "caf/exec_main.hpp"
#include "caf/resumable.hpp"
#include "caf/streambuf.hpp"
#include "caf/to_string.hpp"
#include "caf/actor_addr.hpp"
#include "caf/actor_addr.hpp"
#include "caf/actor_pool.hpp"
#include "caf/attachable.hpp"
#include "caf/message_id.hpp"
#include "caf/replies_to.hpp"
#include "caf/serializer.hpp"
#include "caf/actor_clock.hpp"
#include "caf/actor_clock.hpp"
#include "caf/actor_ostream.hpp"
#include "caf/actor_pool.hpp"
#include "caf/actor_proxy.hpp"
#include "caf/actor_proxy.hpp"
#include "caf/exit_reason.hpp"
#include "caf/local_actor.hpp"
#include "caf/raise_error.hpp"
#include "caf/ref_counted.hpp"
#include "caf/stream_slot.hpp"
#include "caf/thread_hook.hpp"
#include "caf/typed_actor.hpp"
#include "caf/actor_system.hpp"
#include "caf/actor_system.hpp"
#include "caf/actor_system_config.hpp"
#include "caf/after.hpp"
#include "caf/atom.hpp"
#include "caf/attach_continuous_stream_source.hpp"
#include "caf/attach_continuous_stream_stage.hpp"
#include "caf/attach_stream_sink.hpp"
#include "caf/attach_stream_source.hpp"
#include "caf/attach_stream_stage.hpp"
#include "caf/attachable.hpp"
#include "caf/behavior.hpp"
#include "caf/behavior_policy.hpp"
#include "caf/binary_deserializer.hpp"
#include "caf/binary_serializer.hpp"
#include "caf/blocking_actor.hpp"
#include "caf/composable_behavior.hpp"
#include "caf/composed_behavior.hpp"
#include "caf/config_option.hpp"
#include "caf/config_option_adder.hpp"
#include "caf/config_value.hpp"
#include "caf/config_value.hpp"
#include "caf/deep_to_string.hpp"
#include "caf/defaults.hpp"
#include "caf/deserializer.hpp"
#include "caf/deserializer.hpp"
#include "caf/scoped_actor.hpp"
#include "caf/downstream_msg.hpp"
#include "caf/upstream_msg.hpp"
#include "caf/duration.hpp"
#include "caf/actor_ostream.hpp"
#include "caf/error.hpp"
#include "caf/config_option.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/exec_main.hpp"
#include "caf/execution_unit.hpp"
#include "caf/exit_reason.hpp"
#include "caf/expected.hpp"
#include "caf/extend.hpp"
#include "caf/function_view.hpp"
#include "caf/function_view.hpp"
#include "caf/fused_downstream_manager.hpp"
#include "caf/group.hpp"
#include "caf/index_mapping.hpp"
#include "caf/index_mapping.hpp"
#include "caf/spawn_options.hpp"
#include "caf/local_actor.hpp"
#include "caf/abstract_actor.hpp"
#include "caf/logger.hpp"
#include "caf/abstract_group.hpp"
#include "caf/make_config_option.hpp"
#include "caf/blocking_actor.hpp"
#include "caf/may_have_timeout.hpp"
#include "caf/deep_to_string.hpp"
#include "caf/execution_unit.hpp"
#include "caf/memory_managed.hpp"
#include "caf/memory_managed.hpp"
#include "caf/stateful_actor.hpp"
#include "caf/message.hpp"
#include "caf/typed_behavior.hpp"
#include "caf/proxy_registry.hpp"
#include "caf/downstream_msg.hpp"
#include "caf/behavior_policy.hpp"
#include "caf/message_builder.hpp"
#include "caf/message_builder.hpp"
#include "caf/message_handler.hpp"
#include "caf/message_handler.hpp"
#include "caf/response_handle.hpp"
#include "caf/message_id.hpp"
#include "caf/system_messages.hpp"
#include "caf/abstract_channel.hpp"
#include "caf/may_have_timeout.hpp"
#include "caf/message_priority.hpp"
#include "caf/message_priority.hpp"
#include "caf/typed_actor_view.hpp"
#include "caf/node_id.hpp"
#include "caf/binary_serializer.hpp"
#include "caf/others.hpp"
#include "caf/composed_behavior.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/primitive_variant.hpp"
#include "caf/primitive_variant.hpp"
#include "caf/proxy_registry.hpp"
#include "caf/raise_error.hpp"
#include "caf/ref_counted.hpp"
#include "caf/replies_to.hpp"
#include "caf/response_handle.hpp"
#include "caf/result.hpp"
#include "caf/resumable.hpp"
#include "caf/scoped_actor.hpp"
#include "caf/scoped_execution_unit.hpp"
#include "caf/sec.hpp"
#include "caf/send.hpp"
#include "caf/serializer.hpp"
#include "caf/skip.hpp"
#include "caf/spawn_options.hpp"
#include "caf/stateful_actor.hpp"
#include "caf/stream.hpp"
#include "caf/stream_deserializer.hpp"
#include "caf/stream_serializer.hpp"
#include "caf/stream_serializer.hpp"
#include "caf/make_config_option.hpp"
#include "caf/stream_slot.hpp"
#include "caf/streambuf.hpp"
#include "caf/system_messages.hpp"
#include "caf/term.hpp"
#include "caf/thread_hook.hpp"
#include "caf/timeout_definition.hpp"
#include "caf/timeout_definition.hpp"
#include "caf/actor_system_config.hpp"
#include "caf/to_string.hpp"
#include "caf/binary_deserializer.hpp"
#include "caf/typed_actor.hpp"
#include "caf/composable_behavior.hpp"
#include "caf/config_option_adder.hpp"
#include "caf/stream_deserializer.hpp"
#include "caf/typed_actor_pointer.hpp"
#include "caf/typed_actor_pointer.hpp"
#include "caf/
scoped_execution_unit
.hpp"
#include "caf/
typed_actor_view
.hpp"
#include "caf/typed_
response_promise
.hpp"
#include "caf/typed_
behavior
.hpp"
#include "caf/typed_event_based_actor.hpp"
#include "caf/typed_event_based_actor.hpp"
#include "caf/fused_downstream_manager.hpp"
#include "caf/typed_response_promise.hpp"
#include "caf/abstract_composable_behavior.hpp"
#include "caf/unit.hpp"
#include "caf/upstream_msg.hpp"
#include "caf/decorator/sequencer.hpp"
#include "caf/decorator/sequencer.hpp"
...
...
libcaf_core/caf/attach_continuous_stream_source.hpp
0 → 100644
View file @
b877c738
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* *
* 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. *
******************************************************************************/
#pragma once
#include "caf/broadcast_downstream_manager.hpp"
#include "caf/detail/stream_source_driver_impl.hpp"
#include "caf/detail/stream_source_impl.hpp"
#include "caf/fwd.hpp"
#include "caf/policy/arg.hpp"
#include "caf/stream_source.hpp"
#include "caf/stream_source_driver.hpp"
#include "caf/stream_source_trait.hpp"
namespace
caf
{
/// Creates a new continuous stream source by instantiating the default source
/// implementation with `Driver`. The returned manager is not connected to any
/// slot and thus not stored by the actor automatically.
/// @param self Points to the hosting actor.
/// @param init Function object for initializing the state of the source.
/// @param pull Generator function object for producing downstream messages.
/// @param done Predicate returning `true` when generator is done.
/// @param fin Cleanup handler.
/// @returns The new `stream_manager`.
template
<
class
Driver
,
class
...
Ts
>
typename
Driver
::
source_ptr_type
attach_continuous_stream_source
(
scheduled_actor
*
self
,
Ts
&&
...
xs
)
{
using
detail
::
make_stream_source
;
auto
mgr
=
make_stream_source
<
Driver
>
(
self
,
std
::
forward
<
Ts
>
(
xs
)...);
mgr
->
continuous
(
true
);
return
mgr
;
}
/// Creates a new continuous stream source by instantiating the default source
/// implementation with `Driver`. The returned manager is not connected to any
/// slot and thus not stored by the actor automatically.
/// @param self Points to the hosting actor.
/// @param init Function object for initializing the state of the source.
/// @param pull Generator function object for producing downstream messages.
/// @param done Predicate returning `true` when generator is done.
/// @param fin Cleanup handler.
/// @returns The new `stream_manager`.
template
<
class
Init
,
class
Pull
,
class
Done
,
class
Finalize
=
unit_t
,
class
Trait
=
stream_source_trait_t
<
Pull
>,
class
DownstreamManager
=
broadcast_downstream_manager
<
typename
Trait
::
output
>>
stream_source_ptr
<
DownstreamManager
>
attach_continuous_stream_source
(
scheduled_actor
*
self
,
Init
init
,
Pull
pull
,
Done
done
,
Finalize
fin
=
{},
policy
::
arg
<
DownstreamManager
>
=
{})
{
using
state_type
=
typename
Trait
::
state
;
static_assert
(
std
::
is_same
<
void
(
state_type
&
),
typename
detail
::
get_callable_trait
<
Init
>::
fun_sig
>::
value
,
"Expected signature `void (State&)` for init function"
);
static_assert
(
std
::
is_same
<
bool
(
const
state_type
&
),
typename
detail
::
get_callable_trait
<
Done
>::
fun_sig
>::
value
,
"Expected signature `bool (const State&)` "
"for done predicate function"
);
using
driver
=
detail
::
stream_source_driver_impl
<
DownstreamManager
,
Pull
,
Done
,
Finalize
>
;
return
attach_continuous_stream_source
<
driver
>
(
self
,
std
::
move
(
init
),
std
::
move
(
pull
),
std
::
move
(
done
),
std
::
move
(
fin
));
}
}
// namespace caf
libcaf_core/caf/attach_continuous_stream_stage.hpp
0 → 100644
View file @
b877c738
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* *
* 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. *
******************************************************************************/
#pragma once
#include "caf/default_downstream_manager.hpp"
#include "caf/detail/stream_stage_driver_impl.hpp"
#include "caf/detail/stream_stage_impl.hpp"
#include "caf/downstream_manager.hpp"
#include "caf/fwd.hpp"
#include "caf/make_stage_result.hpp"
#include "caf/policy/arg.hpp"
#include "caf/stream.hpp"
#include "caf/stream_stage.hpp"
#include "caf/unit.hpp"
namespace
caf
{
/// Returns a stream manager (implementing a continuous stage) without in- or
/// outbound path. The returned manager is not connected to any slot and thus
/// not stored by the actor automatically.
/// @param self Points to the hosting actor.
/// @param xs User-defined arguments for the downstream handshake.
/// @returns The new `stream_manager`.
template
<
class
Driver
,
class
...
Ts
>
typename
Driver
::
stage_ptr_type
attach_continuous_stream_stage
(
scheduled_actor
*
self
,
Ts
&&
...
xs
)
{
auto
ptr
=
detail
::
make_stream_stage
<
Driver
>
(
self
,
std
::
forward
<
Ts
>
(
xs
)...);
ptr
->
continuous
(
true
);
return
ptr
;
}
/// @param self Points to the hosting actor.
/// @param init Function object for initializing the state of the stage.
/// @param fun Processing function.
/// @param fin Optional cleanup handler.
/// @param token Policy token for selecting a downstream manager
/// implementation.
template
<
class
Init
,
class
Fun
,
class
Finalize
=
unit_t
,
class
DownstreamManager
=
default_downstream_manager_t
<
Fun
>,
class
Trait
=
stream_stage_trait_t
<
Fun
>>
stream_stage_ptr
<
typename
Trait
::
input
,
DownstreamManager
>
attach_continuous_stream_stage
(
scheduled_actor
*
self
,
Init
init
,
Fun
fun
,
Finalize
fin
=
{},
policy
::
arg
<
DownstreamManager
>
token
=
{})
{
CAF_IGNORE_UNUSED
(
token
);
using
input_type
=
typename
Trait
::
input
;
using
output_type
=
typename
Trait
::
output
;
using
state_type
=
typename
Trait
::
state
;
static_assert
(
std
::
is_same
<
void
(
state_type
&
),
typename
detail
::
get_callable_trait
<
Init
>::
fun_sig
>::
value
,
"Expected signature `void (State&)` for init function"
);
static_assert
(
std
::
is_same
<
void
(
state_type
&
,
downstream
<
output_type
>&
,
input_type
),
typename
detail
::
get_callable_trait
<
Fun
>::
fun_sig
>::
value
,
"Expected signature `void (State&, downstream<Out>&, In)` "
"for consume function"
);
using
detail
::
stream_stage_driver_impl
;
using
driver
=
stream_stage_driver_impl
<
typename
Trait
::
input
,
DownstreamManager
,
Fun
,
Finalize
>
;
return
attach_continuous_stream_stage
<
driver
>
(
self
,
std
::
move
(
init
),
std
::
move
(
fun
),
std
::
move
(
fin
));
}
}
// namespace caf
libcaf_core/caf/
output_stream
.hpp
→
libcaf_core/caf/
attach_stream_sink
.hpp
View file @
b877c738
...
@@ -5,7 +5,7 @@
...
@@ -5,7 +5,7 @@
* | |___ / ___ \| _| Framework *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* \____/_/ \_|_| *
* *
* *
* Copyright 2011-201
8
Dominik Charousset *
* Copyright 2011-201
9
Dominik Charousset *
* *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* 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 *
* (at your option) under the terms and conditions of the Boost Software *
...
@@ -18,14 +18,45 @@
...
@@ -18,14 +18,45 @@
#pragma once
#pragma once
#include "caf/detail/stream_sink_driver_impl.hpp"
#include "caf/detail/stream_sink_impl.hpp"
#include "caf/fwd.hpp"
#include "caf/make_sink_result.hpp"
#include "caf/policy/arg.hpp"
#include "caf/stream.hpp"
#include "caf/stream_sink.hpp"
namespace
caf
{
namespace
caf
{
/// Empty marker type for type-checking of stream sources and stages.
/// Attaches a new stream sink to `self` by creating a default stream sink /
template
<
class
T
,
class
...
Ts
>
/// manager from given callbacks.
class
output_stream
{
/// @param self Points to the hosting actor.
public:
/// @param xs Additional constructor arguments for `Driver`.
using
value_type
=
T
;
/// @returns The new `stream_manager`, an inbound slot, and an outbound slot.
};
template
<
class
Driver
,
class
...
Ts
>
make_sink_result
<
typename
Driver
::
input_type
>
attach_stream_sink
(
scheduled_actor
*
self
,
stream
<
typename
Driver
::
input_type
>
in
,
Ts
&&
...
xs
)
{
auto
mgr
=
detail
::
make_stream_sink
<
Driver
>
(
self
,
std
::
forward
<
Ts
>
(
xs
)...);
auto
slot
=
mgr
->
add_inbound_path
(
in
);
return
{
slot
,
std
::
move
(
mgr
)};
}
}
// namespace caf
/// Attaches a new stream sink to `self` by creating a default stream sink
/// manager from given callbacks.
/// @param self Points to the hosting actor.
/// @param in Stream handshake from upstream path.
/// @param init Function object for initializing the state of the sink.
/// @param fun Processing function.
/// @param fin Optional cleanup handler.
/// @returns The new `stream_manager` and the inbound slot.
template
<
class
In
,
class
Init
,
class
Fun
,
class
Finalize
=
unit_t
,
class
Trait
=
stream_sink_trait_t
<
Fun
>
>
make_sink_result
<
In
>
attach_stream_sink
(
scheduled_actor
*
self
,
stream
<
In
>
in
,
Init
init
,
Fun
fun
,
Finalize
fin
=
{})
{
using
driver
=
detail
::
stream_sink_driver_impl
<
In
,
Fun
,
Finalize
>
;
return
attach_stream_sink
<
driver
>
(
self
,
in
,
std
::
move
(
init
),
std
::
move
(
fun
),
std
::
move
(
fin
));
}
}
// namespace caf
libcaf_core/caf/attach_stream_source.hpp
0 → 100644
View file @
b877c738
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* *
* 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. *
******************************************************************************/
#pragma once
#include <tuple>
#include "caf/broadcast_downstream_manager.hpp"
#include "caf/default_downstream_manager.hpp"
#include "caf/detail/stream_source_driver_impl.hpp"
#include "caf/detail/stream_source_impl.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/downstream_manager.hpp"
#include "caf/fwd.hpp"
#include "caf/is_actor_handle.hpp"
#include "caf/make_source_result.hpp"
#include "caf/policy/arg.hpp"
#include "caf/response_type.hpp"
#include "caf/stream_source.hpp"
namespace
caf
{
/// Attaches a new stream source to `self` by creating a default stream source
/// manager with `Driver`.
/// @param self Points to the hosting actor.
/// @param xs User-defined arguments for the stream handshake.
/// @param init Function object for initializing the state of the source.
/// @param pull Function object for generating downstream messages.
/// @param done Predicate returning `true` when generator is done.
/// @param fin Optional cleanup handler.
/// @returns The allocated `stream_manager` and the output slot.
template
<
class
Driver
,
class
...
Ts
,
class
...
CtorArgs
>
make_source_result_t
<
typename
Driver
::
downstream_manager_type
,
Ts
...
>
attach_stream_source
(
scheduled_actor
*
self
,
std
::
tuple
<
Ts
...
>
xs
,
CtorArgs
&&
...
ctor_args
)
{
using
namespace
detail
;
auto
mgr
=
make_stream_source
<
Driver
>
(
self
,
std
::
forward
<
CtorArgs
>
(
ctor_args
)...);
auto
slot
=
mgr
->
add_outbound_path
(
std
::
move
(
xs
));
return
{
slot
,
std
::
move
(
mgr
)};
}
/// Attaches a new stream source to `self` by creating a default stream source
/// manager with the default driver.
/// @param self Points to the hosting actor.
/// @param xs User-defined arguments for the stream handshake.
/// @param init Function object for initializing the state of the source.
/// @param pull Generator function object for producing downstream messages.
/// @param done Predicate returning `true` when generator is done.
/// @param fin Cleanup handler.
/// @returns The allocated `stream_manager` and the output slot.
template
<
class
...
Ts
,
class
Init
,
class
Pull
,
class
Done
,
class
Finalize
=
unit_t
,
class
Trait
=
stream_source_trait_t
<
Pull
>,
class
DownstreamManager
=
broadcast_downstream_manager
<
typename
Trait
::
output
>>
make_source_result_t
<
DownstreamManager
,
Ts
...
>
attach_stream_source
(
scheduled_actor
*
self
,
std
::
tuple
<
Ts
...
>
xs
,
Init
init
,
Pull
pull
,
Done
done
,
Finalize
fin
=
{},
policy
::
arg
<
DownstreamManager
>
=
{})
{
using
state_type
=
typename
Trait
::
state
;
static_assert
(
std
::
is_same
<
void
(
state_type
&
),
typename
detail
::
get_callable_trait
<
Init
>::
fun_sig
>::
value
,
"Expected signature `void (State&)` for init function"
);
static_assert
(
std
::
is_same
<
bool
(
const
state_type
&
),
typename
detail
::
get_callable_trait
<
Done
>::
fun_sig
>::
value
,
"Expected signature `bool (const State&)` "
"for done predicate function"
);
using
driver
=
detail
::
stream_source_driver_impl
<
DownstreamManager
,
Pull
,
Done
,
Finalize
>
;
return
attach_stream_source
<
driver
>
(
self
,
std
::
move
(
xs
),
std
::
move
(
init
),
std
::
move
(
pull
),
std
::
move
(
done
),
std
::
move
(
fin
));
}
/// Attaches a new stream source to `self` by creating a default stream source
/// manager with the default driver.
/// @param self Points to the hosting actor.
/// @param init Function object for initializing the state of the source.
/// @param pull Generator function object for producing downstream messages.
/// @param done Predicate returning `true` when generator is done.
/// @param fin Cleanup handler.
/// @returns The allocated `stream_manager` and the output slot.
template
<
class
Init
,
class
Pull
,
class
Done
,
class
Finalize
=
unit_t
,
class
DownstreamManager
=
default_downstream_manager_t
<
Pull
>,
class
Trait
=
stream_source_trait_t
<
Pull
>>
detail
::
enable_if_t
<!
is_actor_handle
<
Init
>::
value
&&
Trait
::
valid
,
make_source_result_t
<
DownstreamManager
>>
attach_stream_source
(
scheduled_actor
*
self
,
Init
init
,
Pull
pull
,
Done
done
,
Finalize
finalize
=
{},
policy
::
arg
<
DownstreamManager
>
token
=
{})
{
return
attach_stream_source
(
self
,
std
::
make_tuple
(),
init
,
pull
,
done
,
finalize
,
token
);
}
/// Attaches a new stream source to `self` by creating a default stream source
/// manager with the default driver and starts sending to `dest` immediately.
/// @param self Points to the hosting actor.
/// @param dest Handle to the next stage in the pipeline.
/// @param xs User-defined arguments for the stream handshake.
/// @param init Function object for initializing the state of the source.
/// @param pull Generator function object for producing downstream messages.
/// @param done Predicate returning `true` when generator is done.
/// @param fin Cleanup handler.
/// @returns The allocated `stream_manager` and the output slot.
template
<
class
ActorHandle
,
class
...
Ts
,
class
Init
,
class
Pull
,
class
Done
,
class
Finalize
=
unit_t
,
class
DownstreamManager
=
default_downstream_manager_t
<
Pull
>,
class
Trait
=
stream_source_trait_t
<
Pull
>>
detail
::
enable_if_t
<
is_actor_handle
<
ActorHandle
>::
value
,
make_source_result_t
<
DownstreamManager
>>
attach_stream_source
(
scheduled_actor
*
self
,
const
ActorHandle
&
dest
,
std
::
tuple
<
Ts
...
>
xs
,
Init
init
,
Pull
pull
,
Done
done
,
Finalize
fin
=
{},
policy
::
arg
<
DownstreamManager
>
=
{})
{
using
namespace
detail
;
using
token
=
type_list
<
stream
<
typename
DownstreamManager
::
output_type
>
,
strip_and_convert_t
<
Ts
>
...
>
;
static_assert
(
response_type_unbox
<
signatures_of_t
<
ActorHandle
>
,
token
>::
valid
,
"receiver does not accept the stream handshake"
);
using
driver
=
detail
::
stream_source_driver_impl
<
DownstreamManager
,
Pull
,
Done
,
Finalize
>
;
auto
mgr
=
detail
::
make_stream_source
<
driver
>
(
self
,
std
::
move
(
init
),
std
::
move
(
pull
),
std
::
move
(
done
),
std
::
move
(
fin
));
auto
slot
=
mgr
->
add_outbound_path
(
dest
,
std
::
move
(
xs
));
return
{
slot
,
std
::
move
(
mgr
)};
}
/// Attaches a new stream source to `self` by creating a default stream source
/// manager with the default driver and starts sending to `dest` immediately.
/// @param self Points to the hosting actor.
/// @param dest Handle to the next stage in the pipeline.
/// @param init Function object for initializing the state of the source.
/// @param pull Generator function object for producing downstream messages.
/// @param done Predicate returning `true` when generator is done.
/// @param fin Cleanup handler.
/// @returns The allocated `stream_manager` and the output slot.
template
<
class
ActorHandle
,
class
Init
,
class
Pull
,
class
Done
,
class
Finalize
=
unit_t
,
class
DownstreamManager
=
default_downstream_manager_t
<
Pull
>,
class
Trait
=
stream_source_trait_t
<
Pull
>>
detail
::
enable_if_t
<
is_actor_handle
<
ActorHandle
>::
value
&&
Trait
::
valid
,
make_source_result_t
<
DownstreamManager
>>
attach_stream_source
(
scheduled_actor
*
self
,
const
ActorHandle
&
dest
,
Init
init
,
Pull
pull
,
Done
done
,
Finalize
fin
=
{},
policy
::
arg
<
DownstreamManager
>
token
=
{})
{
return
attach_stream_source
(
self
,
dest
,
std
::
make_tuple
(),
std
::
move
(
init
),
std
::
move
(
pull
),
std
::
move
(
done
),
std
::
move
(
fin
),
token
);
}
}
// namespace caf
libcaf_core/caf/attach_stream_stage.hpp
0 → 100644
View file @
b877c738
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* *
* 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. *
******************************************************************************/
#pragma once
#include "caf/default_downstream_manager.hpp"
#include "caf/detail/stream_stage_driver_impl.hpp"
#include "caf/detail/stream_stage_impl.hpp"
#include "caf/downstream_manager.hpp"
#include "caf/fwd.hpp"
#include "caf/make_stage_result.hpp"
#include "caf/policy/arg.hpp"
#include "caf/stream.hpp"
#include "caf/stream_stage.hpp"
#include "caf/unit.hpp"
namespace
caf
{
/// Attaches a new stream stage to `self` by creating a default stream stage
/// manager with `Driver`.
/// @param self Points to the hosting actor.
/// @param in Stream handshake from upstream path.
/// @param xs User-defined arguments for the downstream handshake.
/// @param ys Additional constructor arguments for `Driver`.
/// @returns The new `stream_manager`, an inbound slot, and an outbound slot.
template
<
class
Driver
,
class
In
,
class
...
Ts
,
class
...
Us
>
make_stage_result_t
<
In
,
typename
Driver
::
downstream_manager_type
,
Ts
...
>
attach_stream_stage
(
scheduled_actor
*
self
,
const
stream
<
In
>&
in
,
std
::
tuple
<
Ts
...
>
xs
,
Us
&&
...
ys
)
{
using
detail
::
make_stream_stage
;
auto
mgr
=
make_stream_stage
<
Driver
>
(
self
,
std
::
forward
<
Us
>
(
ys
)...);
auto
islot
=
mgr
->
add_inbound_path
(
in
);
auto
oslot
=
mgr
->
add_outbound_path
(
std
::
move
(
xs
));
return
{
islot
,
oslot
,
std
::
move
(
mgr
)};
}
/// Attaches a new stream stage to `self` by creating a default stream stage
/// manager from given callbacks.
/// @param self Points to the hosting actor.
/// @param in Stream handshake from upstream path.
/// @param xs User-defined arguments for the downstream handshake.
/// @param init Function object for initializing the state of the stage.
/// @param fun Processing function.
/// @param fin Optional cleanup handler.
/// @param token Policy token for selecting a downstream manager
/// implementation.
/// @returns The new `stream_manager`, an inbound slot, and an outbound slot.
template
<
class
In
,
class
...
Ts
,
class
Init
,
class
Fun
,
class
Finalize
=
unit_t
,
class
DownstreamManager
=
default_downstream_manager_t
<
Fun
>,
class
Trait
=
stream_stage_trait_t
<
Fun
>>
make_stage_result_t
<
In
,
DownstreamManager
,
Ts
...
>
attach_stream_stage
(
scheduled_actor
*
self
,
const
stream
<
In
>&
in
,
std
::
tuple
<
Ts
...
>
xs
,
Init
init
,
Fun
fun
,
Finalize
fin
=
{},
policy
::
arg
<
DownstreamManager
>
token
=
{})
{
CAF_IGNORE_UNUSED
(
token
);
using
output_type
=
typename
stream_stage_trait_t
<
Fun
>::
output
;
using
state_type
=
typename
stream_stage_trait_t
<
Fun
>::
state
;
static_assert
(
std
::
is_same
<
void
(
state_type
&
),
typename
detail
::
get_callable_trait
<
Init
>::
fun_sig
>::
value
,
"Expected signature `void (State&)` for init function"
);
static_assert
(
std
::
is_same
<
void
(
state_type
&
,
downstream
<
output_type
>&
,
In
),
typename
detail
::
get_callable_trait
<
Fun
>::
fun_sig
>::
value
,
"Expected signature `void (State&, downstream<Out>&, In)` "
"for consume function"
);
using
driver
=
detail
::
stream_stage_driver_impl
<
typename
Trait
::
input
,
DownstreamManager
,
Fun
,
Finalize
>
;
return
attach_stream_stage
<
driver
>
(
self
,
in
,
std
::
move
(
xs
),
std
::
move
(
init
),
std
::
move
(
fun
),
std
::
move
(
fin
));
}
/// Attaches a new stream stage to `self` by creating a default stream stage
/// manager from given callbacks.
/// @param self Points to the hosting actor.
/// @param in Stream handshake from upstream path.
/// @param init Function object for initializing the state of the stage.
/// @param fun Processing function.
/// @param fin Optional cleanup handler.
/// @param token Policy token for selecting a downstream manager
/// implementation.
/// @returns The new `stream_manager`, an inbound slot, and an outbound slot.
template
<
class
In
,
class
Init
,
class
Fun
,
class
Finalize
=
unit_t
,
class
DownstreamManager
=
default_downstream_manager_t
<
Fun
>,
class
Trait
=
stream_stage_trait_t
<
Fun
>>
make_stage_result_t
<
In
,
DownstreamManager
>
attach_stream_stage
(
scheduled_actor
*
self
,
const
stream
<
In
>&
in
,
Init
init
,
Fun
fun
,
Finalize
fin
=
{},
policy
::
arg
<
DownstreamManager
>
token
=
{})
{
return
attach_stream_stage
(
self
,
in
,
std
::
make_tuple
(),
std
::
move
(
init
),
std
::
move
(
fun
),
std
::
move
(
fin
),
token
);
}
}
// namespace caf
libcaf_core/caf/composable_behavior.hpp
View file @
b877c738
...
@@ -18,12 +18,12 @@
...
@@ -18,12 +18,12 @@
#pragma once
#pragma once
#include "caf/
param
.hpp"
#include "caf/
abstract_composable_behavior
.hpp"
#include "caf/behavior.hpp"
#include "caf/behavior.hpp"
#include "caf/param.hpp"
#include "caf/replies_to.hpp"
#include "caf/replies_to.hpp"
#include "caf/typed_actor.hpp"
#include "caf/typed_actor.hpp"
#include "caf/typed_actor_pointer.hpp"
#include "caf/typed_actor_pointer.hpp"
#include "caf/abstract_composable_behavior.hpp"
namespace
caf
{
namespace
caf
{
...
@@ -34,8 +34,8 @@ template <class MPI>
...
@@ -34,8 +34,8 @@ template <class MPI>
class
composable_behavior_base
;
class
composable_behavior_base
;
template
<
class
...
Xs
,
class
...
Ys
>
template
<
class
...
Xs
,
class
...
Ys
>
class
composable_behavior_base
<
typed_mpi
<
detail
::
type_list
<
Xs
...
>
,
class
composable_behavior_base
<
output_tuple
<
Ys
...
>>>
{
typed_mpi
<
detail
::
type_list
<
Xs
...
>
,
output_tuple
<
Ys
...
>>>
{
public:
public:
virtual
~
composable_behavior_base
()
noexcept
{
virtual
~
composable_behavior_base
()
noexcept
{
// nop
// nop
...
@@ -44,16 +44,16 @@ public:
...
@@ -44,16 +44,16 @@ public:
virtual
result
<
Ys
...
>
operator
()(
param_t
<
Xs
>
...)
=
0
;
virtual
result
<
Ys
...
>
operator
()(
param_t
<
Xs
>
...)
=
0
;
// C++14 and later
// C++14 and later
#
if __cplusplus > 201103L
#if __cplusplus > 201103L
auto
make_callback
()
{
auto
make_callback
()
{
return
[
=
](
param_t
<
Xs
>
...
xs
)
{
return
(
*
this
)(
std
::
move
(
xs
)...);
};
return
[
=
](
param_t
<
Xs
>
...
xs
)
{
return
(
*
this
)(
std
::
move
(
xs
)...);
};
}
}
#
else
#else
// C++11
// C++11
std
::
function
<
result
<
Ys
...
>
(
param_t
<
Xs
>
...)
>
make_callback
()
{
std
::
function
<
result
<
Ys
...
>
(
param_t
<
Xs
>
...)
>
make_callback
()
{
return
[
=
](
param_t
<
Xs
>
...
xs
)
{
return
(
*
this
)(
std
::
move
(
xs
)...);
};
return
[
=
](
param_t
<
Xs
>
...
xs
)
{
return
(
*
this
)(
std
::
move
(
xs
)...);
};
}
}
#
endif
#endif
};
};
/// Base type for composable actor states.
/// Base type for composable actor states.
...
@@ -67,11 +67,7 @@ class composable_behavior<typed_actor<Clauses...>>
...
@@ -67,11 +67,7 @@ class composable_behavior<typed_actor<Clauses...>>
public:
public:
using
signatures
=
detail
::
type_list
<
Clauses
...
>
;
using
signatures
=
detail
::
type_list
<
Clauses
...
>
;
using
handle_type
=
using
handle_type
=
typename
detail
::
tl_apply
<
signatures
,
typed_actor
>::
type
;
typename
detail
::
tl_apply
<
signatures
,
typed_actor
>::
type
;
using
actor_base
=
typename
handle_type
::
base
;
using
actor_base
=
typename
handle_type
::
base
;
...
@@ -106,4 +102,3 @@ public:
...
@@ -106,4 +102,3 @@ public:
};
};
}
// namespace caf
}
// namespace caf
libcaf_core/caf/composed_type.hpp
View file @
b877c738
...
@@ -18,122 +18,71 @@
...
@@ -18,122 +18,71 @@
#pragma once
#pragma once
#include "caf/detail/type_list.hpp"
#include "caf/fwd.hpp"
#include "caf/fwd.hpp"
#include "caf/replies_to.hpp"
#include "caf/replies_to.hpp"
#include "caf/detail/type_list.hpp"
namespace
caf
{
namespace
caf
{
/// Computes the type for f*g (actor composition).
/// Computes the type for f*g (actor composition).
///
///
/// ~~~
/// This metaprogramming function implements the following pseudo-code (with
/// let output_type x = case x of Stream y -> y ; Single y -> y
/// `f` and `g` modelled as pairs where the first element is the input type and
/// the second type is the output type).
///
///
/// let propagate_stream from to = case from of
/// ~~~
/// Stream _ -> Stream (output_type to)
/// Single _ -> to
/// let composed_type f g =
/// let composed_type f g =
/// [(fst x,
propagate_stream (snd x) (snd y)
) | x <- g, y <- f,
/// [(fst x,
snd y
) | x <- g, y <- f,
///
output_type (snd x)
== fst y]
///
snd x
== fst y]
/// ~~~
/// ~~~
///
///
/// This class implements the list comprehension above in a
/// This class implements the list comprehension above in a single shot with
/// single shot with worst case n*m template instantiations using an
/// worst case n*m template instantiations using an inner and outer loop, where
/// inner and outer loop, where n is the size
/// n is the size of `Xs` and m the size of `Ys`. `Zs` is a helper that models
/// of Xs and m the size of Ys. Zs is a helper that models the
/// the "inner loop variable" for generating the cross product of `Xs` and
/// "inner loop variable" for generating the cross product of Xs and Ys.
/// `Ys`. `Rs` collects the results.
/// The helper function propagate_stream is integrated into the loop with
/// four cases for the matching case. Rs collects the results.
template
<
class
Xs
,
class
Ys
,
class
Zs
,
class
Rs
>
template
<
class
Xs
,
class
Ys
,
class
Zs
,
class
Rs
>
struct
composed_type
;
struct
composed_type
;
//
end of outer loop over Xs
//
End of outer loop over Xs.
template
<
class
Ys
,
class
Zs
,
class
...
Rs
>
template
<
class
Ys
,
class
Zs
,
class
...
Rs
>
struct
composed_type
<
detail
::
type_list
<>
,
Ys
,
Zs
,
detail
::
type_list
<
Rs
...
>>
{
struct
composed_type
<
detail
::
type_list
<>
,
Ys
,
Zs
,
detail
::
type_list
<
Rs
...
>>
{
using
type
=
typed_actor
<
Rs
...
>
;
using
type
=
typed_actor
<
Rs
...
>
;
};
};
//
end of inner loop Ys (Zs)
//
End of inner loop Ys (Zs).
template
<
class
X
,
class
...
Xs
,
class
Ys
,
class
Rs
>
template
<
class
X
,
class
...
Xs
,
class
Ys
,
class
Rs
>
struct
composed_type
<
detail
::
type_list
<
X
,
Xs
...
>
,
Ys
,
detail
::
type_list
<>
,
Rs
>
struct
composed_type
<
detail
::
type_list
<
X
,
Xs
...
>
,
Ys
,
detail
::
type_list
<>
,
Rs
>
:
composed_type
<
detail
::
type_list
<
Xs
...
>
,
Ys
,
Ys
,
Rs
>
{};
:
composed_type
<
detail
::
type_list
<
Xs
...
>
,
Ys
,
Ys
,
Rs
>
{};
// case #1
// Output type matches the input type of the next actor.
template
<
class
...
In
,
class
...
Out
,
class
...
Xs
,
class
Ys
,
template
<
class
...
In
,
class
...
Out
,
class
...
Xs
,
class
Ys
,
class
...
MapsTo
,
class
...
MapsTo
,
class
...
Zs
,
class
...
Rs
>
class
...
Zs
,
class
...
Rs
>
struct
composed_type
<
detail
::
type_list
<
typed_mpi
<
detail
::
type_list
<
In
...
>
,
struct
composed_type
<
output_tuple
<
Out
...
>>
,
Xs
...
>
,
detail
::
type_list
<
typed_mpi
<
detail
::
type_list
<
In
...
>
,
output_tuple
<
Out
...
>>
,
Ys
,
Xs
...
>
,
detail
::
type_list
<
typed_mpi
<
detail
::
type_list
<
Out
...
>
,
Ys
,
output_tuple
<
MapsTo
...
>>
,
Zs
...
>
,
detail
::
type_list
<
detail
::
type_list
<
Rs
...
>>
typed_mpi
<
detail
::
type_list
<
Out
...
>
,
output_tuple
<
MapsTo
...
>>
,
Zs
...
>
,
:
composed_type
<
detail
::
type_list
<
Xs
...
>
,
Ys
,
Ys
,
detail
::
type_list
<
Rs
...
>>
detail
::
type_list
<
Rs
...,
typed_mpi
<
detail
::
type_list
<
In
...
>
,
:
composed_type
<
output_tuple
<
MapsTo
...
>>>>
{};
detail
::
type_list
<
Xs
...
>
,
Ys
,
Ys
,
detail
::
type_list
<
// case #2
Rs
...,
typed_mpi
<
detail
::
type_list
<
In
...
>
,
output_tuple
<
MapsTo
...
>>>>
{
template
<
class
...
In
,
class
...
Out
,
class
...
Xs
,
class
Ys
,
class
M
,
class
...
Ms
,
class
...
Zs
,
class
...
Rs
>
struct
composed_type
<
detail
::
type_list
<
typed_mpi
<
detail
::
type_list
<
In
...
>
,
output_tuple
<
Out
...
>>
,
Xs
...
>
,
Ys
,
detail
::
type_list
<
typed_mpi
<
detail
::
type_list
<
Out
...
>
,
output_stream
<
M
,
Ms
...
>>
,
Zs
...
>
,
detail
::
type_list
<
Rs
...
>>
:
composed_type
<
detail
::
type_list
<
Xs
...
>
,
Ys
,
Ys
,
detail
::
type_list
<
Rs
...,
typed_mpi
<
detail
::
type_list
<
In
...
>
,
output_stream
<
M
,
Ms
...
>>>>
{
};
// case #3
template
<
class
...
In
,
class
O
,
class
...
Out
,
class
...
Xs
,
class
Ys
,
class
M
,
class
...
Ms
,
class
...
Zs
,
class
...
Rs
>
struct
composed_type
<
detail
::
type_list
<
typed_mpi
<
detail
::
type_list
<
In
...
>
,
output_stream
<
O
,
Out
...
>>
,
Xs
...
>
,
Ys
,
detail
::
type_list
<
typed_mpi
<
detail
::
type_list
<
O
,
Out
...
>
,
output_tuple
<
M
,
Ms
...
>>
,
Zs
...
>
,
detail
::
type_list
<
Rs
...
>>
:
composed_type
<
detail
::
type_list
<
Xs
...
>
,
Ys
,
Ys
,
detail
::
type_list
<
Rs
...,
typed_mpi
<
detail
::
type_list
<
In
...
>
,
output_stream
<
M
,
Ms
...
>>>>
{
};
};
// case #4
// No match, recurse over Zs.
template
<
class
...
In
,
class
O
,
class
...
Out
,
class
...
Xs
,
class
Ys
,
template
<
class
In
,
class
Out
,
class
...
Xs
,
class
Ys
,
class
Unrelated
,
class
M
,
class
...
Ms
,
class
...
Zs
,
class
...
Rs
>
class
MapsTo
,
class
...
Zs
,
class
Rs
>
struct
composed_type
<
detail
::
type_list
<
typed_mpi
<
detail
::
type_list
<
In
...
>
,
struct
composed_type
<
detail
::
type_list
<
typed_mpi
<
In
,
Out
>
,
Xs
...
>
,
Ys
,
output_stream
<
O
,
Out
...
>>
,
Xs
...
>
,
detail
::
type_list
<
typed_mpi
<
Unrelated
,
MapsTo
>
,
Zs
...
>
,
Rs
>
Ys
,
:
composed_type
<
detail
::
type_list
<
typed_mpi
<
In
,
Out
>
,
Xs
...
>
,
Ys
,
detail
::
type_list
<
typed_mpi
<
detail
::
type_list
<
O
,
Out
...
>
,
detail
::
type_list
<
Zs
...
>
,
Rs
>
{};
output_stream
<
M
,
Ms
...
>>
,
Zs
...
>
,
detail
::
type_list
<
Rs
...
>>
:
composed_type
<
detail
::
type_list
<
Xs
...
>
,
Ys
,
Ys
,
detail
::
type_list
<
Rs
...,
typed_mpi
<
detail
::
type_list
<
In
...
>
,
output_stream
<
M
,
Ms
...
>>>>
{
};
// default case (recurse over Zs)
template
<
class
In
,
class
Out
,
class
...
Xs
,
class
Ys
,
class
Unrelated
,
class
MapsTo
,
class
...
Zs
,
class
Rs
>
struct
composed_type
<
detail
::
type_list
<
typed_mpi
<
In
,
Out
>
,
Xs
...
>
,
Ys
,
detail
::
type_list
<
typed_mpi
<
Unrelated
,
MapsTo
>
,
Zs
...
>
,
Rs
>
:
composed_type
<
detail
::
type_list
<
typed_mpi
<
In
,
Out
>
,
Xs
...
>
,
Ys
,
detail
::
type_list
<
Zs
...
>
,
Rs
>
{};
/// Convenience type alias.
/// Convenience type alias.
/// @relates composed_type
/// @relates composed_type
template
<
class
F
,
class
G
>
template
<
class
F
,
class
G
>
using
composed_type_t
=
using
composed_type_t
=
typename
composed_type
<
G
,
F
,
F
,
typename
composed_type
<
G
,
F
,
F
,
detail
::
type_list
<>>::
type
;
detail
::
type_list
<>>::
type
;
}
// namespace caf
}
// namespace caf
libcaf_core/caf/deduce_mpi.hpp
View file @
b877c738
...
@@ -79,14 +79,6 @@ struct dmi<optional<Y> (Xs...)> : dmi<Y (Xs...)> {};
...
@@ -79,14 +79,6 @@ struct dmi<optional<Y> (Xs...)> : dmi<Y (Xs...)> {};
template
<
class
Y
,
class
...
Xs
>
template
<
class
Y
,
class
...
Xs
>
struct
dmi
<
expected
<
Y
>
(
Xs
...)
>
:
dmi
<
Y
(
Xs
...)
>
{};
struct
dmi
<
expected
<
Y
>
(
Xs
...)
>
:
dmi
<
Y
(
Xs
...)
>
{};
// case #5: function returning an output_stream<>
template
<
class
Y
,
class
...
Ys
,
class
P
,
class
...
Xs
>
struct
dmi
<
output_stream
<
Y
,
std
::
tuple
<
Ys
...
>
,
P
>
(
Xs
...)
>
:
dmi
<
Y
(
Xs
...)
>
{
using
type
=
typed_mpi
<
type_list
<
typename
param_decay
<
Xs
>::
type
...
>
,
output_tuple
<
stream
<
Y
>
,
strip_and_convert_t
<
Ys
>
...
>>
;
};
// -- dmfou = deduce_mpi_function_object_unboxing
// -- dmfou = deduce_mpi_function_object_unboxing
template
<
class
T
,
bool
isClass
=
std
::
is_class
<
T
>
::
value
>
template
<
class
T
,
bool
isClass
=
std
::
is_class
<
T
>
::
value
>
...
...
libcaf_core/caf/detail/invoke_result_visitor.hpp
View file @
b877c738
...
@@ -140,12 +140,6 @@ public:
...
@@ -140,12 +140,6 @@ public:
(
*
this
)();
(
*
this
)();
}
}
/// Calls `(*this)()`.
template
<
class
Out
,
class
...
Ts
>
void
operator
()(
output_stream
<
Out
,
Ts
...
>&
)
{
(
*
this
)();
}
/// Calls `(*this)()`.
/// Calls `(*this)()`.
template
<
class
Out
,
class
...
Ts
>
template
<
class
Out
,
class
...
Ts
>
void
operator
()(
outbound_stream_slot
<
Out
,
Ts
...
>&
)
{
void
operator
()(
outbound_stream_slot
<
Out
,
Ts
...
>&
)
{
...
...
libcaf_core/caf/detail/type_traits.hpp
View file @
b877c738
...
@@ -769,6 +769,19 @@ CAF_HAS_ALIAS_TRAIT(mapped_type);
...
@@ -769,6 +769,19 @@ CAF_HAS_ALIAS_TRAIT(mapped_type);
// -- constexpr functions for use in enable_if & friends -----------------------
// -- constexpr functions for use in enable_if & friends -----------------------
template
<
class
List1
,
class
List2
>
struct
all_constructible
:
std
::
false_type
{};
template
<
>
struct
all_constructible
<
type_list
<>
,
type_list
<>>
:
std
::
true_type
{};
template
<
class
T
,
class
...
Ts
,
class
U
,
class
...
Us
>
struct
all_constructible
<
type_list
<
T
,
Ts
...
>
,
type_list
<
U
,
Us
...
>>
{
static
constexpr
bool
value
=
std
::
is_constructible
<
T
,
U
>::
value
&&
all_constructible
<
type_list
<
Ts
...
>
,
type_list
<
Us
...
>>::
value
;
};
/// Checks whether T behaves like `std::map`.
/// Checks whether T behaves like `std::map`.
template
<
class
T
>
template
<
class
T
>
struct
is_map_like
{
struct
is_map_like
{
...
@@ -785,6 +798,38 @@ struct is_list_like {
...
@@ -785,6 +798,38 @@ struct is_list_like {
&&
!
has_mapped_type_alias
<
T
>::
value
;
&&
!
has_mapped_type_alias
<
T
>::
value
;
};
};
template
<
class
F
,
class
...
Ts
>
struct
is_invocable
{
private:
template
<
class
U
>
static
auto
sfinae
(
U
*
f
)
->
decltype
((
*
f
)(
std
::
declval
<
Ts
>
()...),
std
::
true_type
());
template
<
class
U
>
static
auto
sfinae
(...)
->
std
::
false_type
;
using
sfinae_type
=
decltype
(
sfinae
<
F
>
(
nullptr
));
public:
static
constexpr
bool
value
=
sfinae_type
::
value
;
};
template
<
class
R
,
class
F
,
class
...
Ts
>
struct
is_invocable_r
{
private:
template
<
class
U
>
static
auto
sfinae
(
U
*
f
)
->
std
::
is_same
<
R
,
decltype
((
*
f
)(
std
::
declval
<
Ts
>
()...))
>
;
template
<
class
U
>
static
auto
sfinae
(...)
->
std
::
false_type
;
using
sfinae_type
=
decltype
(
sfinae
<
F
>
(
nullptr
));
public:
static
constexpr
bool
value
=
sfinae_type
::
value
;
};
}
// namespace detail
}
// namespace detail
}
// namespace caf
}
// namespace caf
...
...
libcaf_core/caf/fwd.hpp
View file @
b877c738
...
@@ -73,10 +73,6 @@ template <class...> class typed_event_based_actor;
...
@@ -73,10 +73,6 @@ template <class...> class typed_event_based_actor;
template
<
class
...
>
class
typed_response_promise
;
template
<
class
...
>
class
typed_response_promise
;
template
<
class
...
>
class
variant
;
template
<
class
...
>
class
variant
;
// -- variadic templates with fixed arguments ----------------------------------
//
template
<
class
,
class
...>
class
output_stream
;
// clang-format on
// clang-format on
// -- classes ------------------------------------------------------------------
// -- classes ------------------------------------------------------------------
...
...
libcaf_core/caf/make_sink_result.hpp
View file @
b877c738
...
@@ -18,6 +18,7 @@
...
@@ -18,6 +18,7 @@
#pragma once
#pragma once
#include "caf/delegated.hpp"
#include "caf/fwd.hpp"
#include "caf/fwd.hpp"
#include "caf/stream_sink.hpp"
#include "caf/stream_sink.hpp"
#include "caf/stream_slot.hpp"
#include "caf/stream_slot.hpp"
...
@@ -26,7 +27,7 @@ namespace caf {
...
@@ -26,7 +27,7 @@ namespace caf {
/// Returns a stream sink with the slot ID of its first inbound path.
/// Returns a stream sink with the slot ID of its first inbound path.
template
<
class
In
>
template
<
class
In
>
class
make_sink_result
{
class
make_sink_result
:
public
delegated
<
void
>
{
public:
public:
// -- member types -----------------------------------------------------------
// -- member types -----------------------------------------------------------
...
@@ -39,9 +40,6 @@ public:
...
@@ -39,9 +40,6 @@ public:
/// Pointer to a fully typed stream manager.
/// Pointer to a fully typed stream manager.
using
sink_ptr_type
=
intrusive_ptr
<
sink_type
>
;
using
sink_ptr_type
=
intrusive_ptr
<
sink_type
>
;
/// The return type for `scheduled_actor::make_sink`.
using
output_stream_type
=
stream
<
input_type
>
;
// -- constructors, destructors, and assignment operators --------------------
// -- constructors, destructors, and assignment operators --------------------
make_sink_result
()
noexcept
:
slot_
(
0
)
{
make_sink_result
()
noexcept
:
slot_
(
0
)
{
...
@@ -61,15 +59,15 @@ public:
...
@@ -61,15 +59,15 @@ public:
// -- properties -------------------------------------------------------------
// -- properties -------------------------------------------------------------
inline
stream_slot
inbound_slot
()
const
noexcept
{
stream_slot
inbound_slot
()
const
noexcept
{
return
slot_
;
return
slot_
;
}
}
inline
sink_ptr_type
&
ptr
()
noexcept
{
sink_ptr_type
&
ptr
()
noexcept
{
return
ptr_
;
return
ptr_
;
}
}
inline
const
sink_ptr_type
&
ptr
()
const
noexcept
{
const
sink_ptr_type
&
ptr
()
const
noexcept
{
return
ptr_
;
return
ptr_
;
}
}
...
...
libcaf_core/caf/make_source_result.hpp
View file @
b877c738
...
@@ -18,17 +18,22 @@
...
@@ -18,17 +18,22 @@
#pragma once
#pragma once
#include <tuple>
#include "caf/delegated.hpp"
#include "caf/detail/implicit_conversions.hpp"
#include "caf/fwd.hpp"
#include "caf/fwd.hpp"
#include "caf/stream.hpp"
#include "caf/stream_slot.hpp"
#include "caf/stream_slot.hpp"
#include "caf/stream_source.hpp"
#include "caf/stream_source.hpp"
#include "caf/detail/implicit_conversions.hpp"
namespace
caf
{
namespace
caf
{
/// Returns a stream source with the slot ID of its first outbound path.
/// Returns a stream source with the slot ID of its first outbound path.
template
<
class
DownstreamManager
,
class
...
Ts
>
template
<
class
DownstreamManager
,
class
...
Ts
>
struct
make_source_result
{
class
make_source_result
:
public
delegated
<
stream
<
typename
DownstreamManager
::
output_type
>
,
Ts
...
>
{
public:
// -- member types -----------------------------------------------------------
// -- member types -----------------------------------------------------------
/// Type of a single element.
/// Type of a single element.
...
@@ -40,8 +45,11 @@ struct make_source_result {
...
@@ -40,8 +45,11 @@ struct make_source_result {
/// Pointer to a fully typed stream manager.
/// Pointer to a fully typed stream manager.
using
source_ptr_type
=
intrusive_ptr
<
source_type
>
;
using
source_ptr_type
=
intrusive_ptr
<
source_type
>
;
/// The return type for `scheduled_actor::make_source`.
/// The return type for `scheduled_actor::make_stage`.
using
output_stream_type
=
output_stream
<
output_type
,
Ts
...
>
;
using
stream_type
=
stream
<
output_type
>
;
/// Type of user-defined handshake arguments.
using
handshake_arguments
=
std
::
tuple
<
Ts
...
>
;
// -- constructors, destructors, and assignment operators --------------------
// -- constructors, destructors, and assignment operators --------------------
...
@@ -60,23 +68,17 @@ struct make_source_result {
...
@@ -60,23 +68,17 @@ struct make_source_result {
make_source_result
&
operator
=
(
make_source_result
&&
)
=
default
;
make_source_result
&
operator
=
(
make_source_result
&&
)
=
default
;
make_source_result
&
operator
=
(
const
make_source_result
&
)
=
default
;
make_source_result
&
operator
=
(
const
make_source_result
&
)
=
default
;
// -- conversion operators ---------------------------------------------------
inline
operator
output_stream_type
()
const
noexcept
{
return
{};
}
// -- properties -------------------------------------------------------------
// -- properties -------------------------------------------------------------
inline
stream_slot
outbound_slot
()
const
noexcept
{
stream_slot
outbound_slot
()
const
noexcept
{
return
slot_
;
return
slot_
;
}
}
inline
source_ptr_type
&
ptr
()
noexcept
{
source_ptr_type
&
ptr
()
noexcept
{
return
ptr_
;
return
ptr_
;
}
}
inline
const
source_ptr_type
&
ptr
()
const
noexcept
{
const
source_ptr_type
&
ptr
()
const
noexcept
{
return
ptr_
;
return
ptr_
;
}
}
...
...
libcaf_core/caf/make_stage_result.hpp
View file @
b877c738
...
@@ -18,19 +18,22 @@
...
@@ -18,19 +18,22 @@
#pragma once
#pragma once
#include <tuple>
#include "caf/delegated.hpp"
#include "caf/detail/implicit_conversions.hpp"
#include "caf/fwd.hpp"
#include "caf/fwd.hpp"
#include "caf/
output_
stream.hpp"
#include "caf/stream.hpp"
#include "caf/stream_slot.hpp"
#include "caf/stream_slot.hpp"
#include "caf/stream_stage.hpp"
#include "caf/stream_stage.hpp"
#include "caf/detail/implicit_conversions.hpp"
namespace
caf
{
namespace
caf
{
/// Returns a stream stage with the slot IDs of its first in- and outbound
/// Returns a stream stage with the slot IDs of its first in- and outbound
/// paths.
/// paths.
template
<
class
In
,
class
DownstreamManager
,
class
...
Ts
>
template
<
class
In
,
class
DownstreamManager
,
class
...
Ts
>
class
make_stage_result
{
class
make_stage_result
:
public
delegated
<
stream
<
typename
DownstreamManager
::
output_type
>
,
Ts
...
>
{
public:
public:
// -- member types -----------------------------------------------------------
// -- member types -----------------------------------------------------------
...
@@ -47,7 +50,10 @@ public:
...
@@ -47,7 +50,10 @@ public:
using
stage_ptr_type
=
intrusive_ptr
<
stage_type
>
;
using
stage_ptr_type
=
intrusive_ptr
<
stage_type
>
;
/// The return type for `scheduled_actor::make_stage`.
/// The return type for `scheduled_actor::make_stage`.
using
output_stream_type
=
output_stream
<
output_type
,
Ts
...
>
;
using
stream_type
=
stream
<
output_type
>
;
/// Type of user-defined handshake arguments.
using
handshake_arguments
=
std
::
tuple
<
Ts
...
>
;
// -- constructors, destructors, and assignment operators --------------------
// -- constructors, destructors, and assignment operators --------------------
...
@@ -67,27 +73,21 @@ public:
...
@@ -67,27 +73,21 @@ public:
make_stage_result
&
operator
=
(
make_stage_result
&&
)
=
default
;
make_stage_result
&
operator
=
(
make_stage_result
&&
)
=
default
;
make_stage_result
&
operator
=
(
const
make_stage_result
&
)
=
default
;
make_stage_result
&
operator
=
(
const
make_stage_result
&
)
=
default
;
// -- conversion operators ---------------------------------------------------
inline
operator
output_stream_type
()
const
noexcept
{
return
{};
}
// -- properties -------------------------------------------------------------
// -- properties -------------------------------------------------------------
inline
stream_slot
inbound_slot
()
const
noexcept
{
stream_slot
inbound_slot
()
const
noexcept
{
return
inbound_slot_
;
return
inbound_slot_
;
}
}
inline
stream_slot
outbound_slot
()
const
noexcept
{
stream_slot
outbound_slot
()
const
noexcept
{
return
outbound_slot_
;
return
outbound_slot_
;
}
}
inline
stage_ptr_type
&
ptr
()
noexcept
{
stage_ptr_type
&
ptr
()
noexcept
{
return
ptr_
;
return
ptr_
;
}
}
inline
const
stage_ptr_type
&
ptr
()
const
noexcept
{
const
stage_ptr_type
&
ptr
()
const
noexcept
{
return
ptr_
;
return
ptr_
;
}
}
...
...
libcaf_core/caf/param.hpp
View file @
b877c738
...
@@ -84,15 +84,27 @@ private:
...
@@ -84,15 +84,27 @@ private:
flag
flag_
;
flag
flag_
;
};
};
/// Conve
nience alias that wraps `T` into `param<T>`
/// Conve
rts `T` to `param<T>` unless `T` is arithmetic, an atom constant, or
///
unless `T` is arithmetic or an atom constant
.
///
a stream handshake
.
template
<
class
T
>
template
<
class
T
>
using
param_t
=
struct
add_param
:
std
::
conditional
<
std
::
is_arithmetic
<
T
>::
value
,
T
,
param
<
T
>>
{
typename
std
::
conditional
<
// nop
std
::
is_arithmetic
<
T
>::
value
||
is_atom_constant
<
T
>::
value
,
};
T
,
param
<
T
>
template
<
atom_value
V
>
>::
type
;
struct
add_param
<
atom_constant
<
V
>>
{
using
type
=
atom_constant
<
V
>
;
};
template
<
class
T
>
struct
add_param
<
stream
<
T
>>
{
using
type
=
stream
<
T
>
;
};
/// Convenience alias that wraps `T` into `param<T>` unless `T` is arithmetic,
/// a stream handshake or an atom constant.
template
<
class
T
>
using
param_t
=
typename
add_param
<
T
>::
type
;
/// Unpacks `param<T>` to `T`.
/// Unpacks `param<T>` to `T`.
template
<
class
T
>
template
<
class
T
>
...
@@ -112,4 +124,3 @@ struct param_decay {
...
@@ -112,4 +124,3 @@ struct param_decay {
};
};
}
// namespace caf
}
// namespace caf
libcaf_core/caf/replies_to.hpp
View file @
b877c738
...
@@ -20,13 +20,7 @@
...
@@ -20,13 +20,7 @@
#include <string>
#include <string>
#include "caf/illegal_message_element.hpp"
#include "caf/output_stream.hpp"
#include "caf/stream.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/detail/type_pair.hpp"
#include "caf/detail/type_traits.hpp"
namespace
caf
{
namespace
caf
{
...
@@ -47,15 +41,9 @@ template <class... Is>
...
@@ -47,15 +41,9 @@ template <class... Is>
struct
replies_to
{
struct
replies_to
{
template
<
class
...
Os
>
template
<
class
...
Os
>
using
with
=
typed_mpi
<
detail
::
type_list
<
Is
...
>
,
output_tuple
<
Os
...
>>
;
using
with
=
typed_mpi
<
detail
::
type_list
<
Is
...
>
,
output_tuple
<
Os
...
>>
;
/// @private
template
<
class
O
,
class
...
Os
>
using
with_stream
=
typed_mpi
<
detail
::
type_list
<
Is
...
>
,
output_stream
<
O
,
Os
...
>>
;
};
};
template
<
class
...
Is
>
template
<
class
...
Is
>
using
reacts_to
=
typed_mpi
<
detail
::
type_list
<
Is
...
>
,
output_tuple
<
void
>>
;
using
reacts_to
=
typed_mpi
<
detail
::
type_list
<
Is
...
>
,
output_tuple
<
void
>>
;
}
// namespace caf
}
// namespace caf
libcaf_core/caf/result.hpp
View file @
b877c738
...
@@ -18,15 +18,17 @@
...
@@ -18,15 +18,17 @@
#pragma once
#pragma once
#include "caf/fwd.hpp"
#include <type_traits>
#include "caf/none.hpp"
#include "caf/skip.hpp"
#include "caf/delegated.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/error.hpp"
#include "caf/error.hpp"
#include "caf/expected.hpp"
#include "caf/expected.hpp"
#include "caf/fwd.hpp"
#include "caf/message.hpp"
#include "caf/message.hpp"
#include "caf/delegated.hpp"
#include "caf/none.hpp"
#include "caf/skip.hpp"
#include "caf/detail/type_list.hpp"
namespace
caf
{
namespace
caf
{
...
@@ -40,13 +42,15 @@ enum result_runtime_type {
...
@@ -40,13 +42,15 @@ enum result_runtime_type {
template
<
class
...
Ts
>
template
<
class
...
Ts
>
class
result
{
class
result
{
public:
public:
result
(
Ts
...
xs
)
:
flag
(
rt_value
),
value
(
make_message
(
std
::
move
(
xs
)...))
{
// clang-format off
// nop
template
<
class
...
Us
,
}
class
=
detail
::
enable_if_tt
<
detail
::
all_constructible
<
template
<
class
U
,
class
...
Us
>
detail
::
type_list
<
Ts
...>,
result
(
U
x
,
Us
...
xs
)
:
flag
(
rt_value
)
{
detail
::
type_list
<
detail
::
decay_t
<
Us
>
...
>>>>
init
(
std
::
move
(
x
),
std
::
move
(
xs
)...);
// clang-format on
result
(
Us
&&
...
xs
)
:
flag
(
rt_value
)
{
value
=
make_message
(
Ts
{
std
::
forward
<
Us
>
(
xs
)}...);
}
}
template
<
class
E
,
class
=
enable_if_has_make_error_t
<
E
>
>
template
<
class
E
,
class
=
enable_if_has_make_error_t
<
E
>
>
...
@@ -58,16 +62,11 @@ public:
...
@@ -58,16 +62,11 @@ public:
// nop
// nop
}
}
template
<
template
<
class
T
,
class
T
,
class
=
typename
std
::
enable_if
<
class
=
typename
std
::
enable_if
<
sizeof
...(
Ts
)
==
1
sizeof
...(
Ts
)
==
1
&&
std
::
is_convertible
<
&&
std
::
is_convertible
<
T
,
detail
::
tl_head_t
<
detail
::
type_list
<
Ts
...>
>>::
value
>::
type
>
T
,
detail
::
tl_head_t
<
detail
::
type_list
<
Ts
...>
>
>::
value
>::
type
>
result
(
expected
<
T
>
x
)
{
result
(
expected
<
T
>
x
)
{
if
(
x
)
{
if
(
x
)
{
flag
=
rt_value
;
flag
=
rt_value
;
...
...
libcaf_core/caf/scheduled_actor.hpp
View file @
b877c738
...
@@ -44,7 +44,6 @@
...
@@ -44,7 +44,6 @@
#include "caf/make_source_result.hpp"
#include "caf/make_source_result.hpp"
#include "caf/make_stage_result.hpp"
#include "caf/make_stage_result.hpp"
#include "caf/no_stages.hpp"
#include "caf/no_stages.hpp"
#include "caf/output_stream.hpp"
#include "caf/response_handle.hpp"
#include "caf/response_handle.hpp"
#include "caf/scheduled_actor.hpp"
#include "caf/scheduled_actor.hpp"
#include "caf/sec.hpp"
#include "caf/sec.hpp"
...
@@ -420,14 +419,7 @@ public:
...
@@ -420,14 +419,7 @@ public:
// -- stream management ------------------------------------------------------
// -- stream management ------------------------------------------------------
/// Creates a new stream source by instantiating the default source
/// @deprecated Please use `attach_stream_source` instead.
/// implementation with `Driver`.
/// @param xs User-defined handshake payload.
/// @param init Function object for initializing the state of the source.
/// @param pull Generator function object for producing downstream messages.
/// @param done Predicate returning `true` when generator is done.
/// @param fin Cleanup handler.
/// @returns The allocated `stream_manager` and the output slot.
template
<
class
Driver
,
class
...
Ts
,
class
Init
,
class
Pull
,
class
Done
,
template
<
class
Driver
,
class
...
Ts
,
class
Init
,
class
Pull
,
class
Done
,
class
Finalize
=
unit_t
>
class
Finalize
=
unit_t
>
make_source_result_t
<
typename
Driver
::
downstream_manager_type
,
Ts
...
>
make_source_result_t
<
typename
Driver
::
downstream_manager_type
,
Ts
...
>
...
@@ -441,13 +433,7 @@ public:
...
@@ -441,13 +433,7 @@ public:
return
{
slot
,
std
::
move
(
mgr
)};
return
{
slot
,
std
::
move
(
mgr
)};
}
}
/// Creates a new stream source from given arguments.
/// @deprecated Please use `attach_stream_source` instead.
/// @param xs User-defined handshake payload.
/// @param init Function object for initializing the state of the source.
/// @param pull Generator function object for producing downstream messages.
/// @param done Predicate returning `true` when generator is done.
/// @param fin Cleanup handler.
/// @returns The allocated `stream_manager` and the output slot.
template
<
class
...
Ts
,
class
Init
,
class
Pull
,
class
Done
,
template
<
class
...
Ts
,
class
Init
,
class
Pull
,
class
Done
,
class
Finalize
=
unit_t
,
class
Finalize
=
unit_t
,
class
DownstreamManager
=
broadcast_downstream_manager
<
class
DownstreamManager
=
broadcast_downstream_manager
<
...
@@ -461,6 +447,7 @@ public:
...
@@ -461,6 +447,7 @@ public:
std
::
move
(
done
),
std
::
move
(
fin
));
std
::
move
(
done
),
std
::
move
(
fin
));
}
}
/// @deprecated Please use `attach_stream_source` instead.
template
<
class
Init
,
class
Pull
,
class
Done
,
class
Finalize
=
unit_t
,
template
<
class
Init
,
class
Pull
,
class
Done
,
class
Finalize
=
unit_t
,
class
DownstreamManager
=
default_downstream_manager_t
<
Pull
>,
class
DownstreamManager
=
default_downstream_manager_t
<
Pull
>,
class
Trait
=
stream_source_trait_t
<
Pull
>>
class
Trait
=
stream_source_trait_t
<
Pull
>>
...
@@ -472,7 +459,7 @@ public:
...
@@ -472,7 +459,7 @@ public:
token
);
token
);
}
}
///
Creates a new stream source and adds `dest` as first outbound path to it
.
///
@deprecated Please use `attach_stream_source` instead
.
template
<
class
ActorHandle
,
class
...
Ts
,
class
Init
,
class
Pull
,
class
Done
,
template
<
class
ActorHandle
,
class
...
Ts
,
class
Init
,
class
Pull
,
class
Done
,
class
Finalize
=
unit_t
,
class
Finalize
=
unit_t
,
class
DownstreamManager
=
default_downstream_manager_t
<
Pull
>,
class
DownstreamManager
=
default_downstream_manager_t
<
Pull
>,
...
@@ -493,7 +480,7 @@ public:
...
@@ -493,7 +480,7 @@ public:
return
{
slot
,
std
::
move
(
mgr
)};
return
{
slot
,
std
::
move
(
mgr
)};
}
}
///
Creates a new stream source and adds `dest` as first outbound path to it
.
///
@deprecated Please use `attach_stream_source` instead
.
template
<
class
ActorHandle
,
class
Init
,
class
Pull
,
class
Done
,
template
<
class
ActorHandle
,
class
Init
,
class
Pull
,
class
Done
,
class
Finalize
=
unit_t
,
class
Finalize
=
unit_t
,
class
DownstreamManager
=
default_downstream_manager_t
<
Pull
>,
class
DownstreamManager
=
default_downstream_manager_t
<
Pull
>,
...
@@ -507,9 +494,7 @@ public:
...
@@ -507,9 +494,7 @@ public:
std
::
move
(
pull
),
std
::
move
(
done
),
std
::
move
(
fin
),
token
);
std
::
move
(
pull
),
std
::
move
(
done
),
std
::
move
(
fin
),
token
);
}
}
/// Creates a new continuous stream source by instantiating the default
/// @deprecated Please use `attach_continuous_stream_source` instead.
/// source implementation with `Driver. `The returned manager is not
/// connected to any slot and thus not stored by the actor automatically.
template
<
class
Driver
,
class
Init
,
class
Pull
,
class
Done
,
template
<
class
Driver
,
class
Init
,
class
Pull
,
class
Done
,
class
Finalize
=
unit_t
>
class
Finalize
=
unit_t
>
typename
Driver
::
source_ptr_type
typename
Driver
::
source_ptr_type
...
@@ -522,9 +507,7 @@ public:
...
@@ -522,9 +507,7 @@ public:
return
mgr
;
return
mgr
;
}
}
/// Creates a new continuous stream source by instantiating the default
/// @deprecated Please use `attach_continuous_stream_source` instead.
/// source implementation with `Driver. `The returned manager is not
/// connected to any slot and thus not stored by the actor automatically.
template
<
class
Init
,
class
Pull
,
class
Done
,
class
Finalize
=
unit_t
,
template
<
class
Init
,
class
Pull
,
class
Done
,
class
Finalize
=
unit_t
,
class
DownstreamManager
=
broadcast_downstream_manager
<
class
DownstreamManager
=
broadcast_downstream_manager
<
typename
stream_source_trait_t
<
Pull
>
::
output
>>
typename
stream_source_trait_t
<
Pull
>
::
output
>>
...
@@ -537,6 +520,7 @@ public:
...
@@ -537,6 +520,7 @@ public:
std
::
move
(
done
),
std
::
move
(
fin
));
std
::
move
(
done
),
std
::
move
(
fin
));
}
}
/// @deprecated Please use `attach_stream_sink` instead.
template
<
class
Driver
,
class
...
Ts
>
template
<
class
Driver
,
class
...
Ts
>
make_sink_result
<
typename
Driver
::
input_type
>
make_sink_result
<
typename
Driver
::
input_type
>
make_sink
(
const
stream
<
typename
Driver
::
input_type
>&
src
,
Ts
&&
...
xs
)
{
make_sink
(
const
stream
<
typename
Driver
::
input_type
>&
src
,
Ts
&&
...
xs
)
{
...
@@ -545,6 +529,7 @@ public:
...
@@ -545,6 +529,7 @@ public:
return
{
slot
,
std
::
move
(
mgr
)};
return
{
slot
,
std
::
move
(
mgr
)};
}
}
/// @deprecated Please use `attach_stream_sink` instead.
template
<
class
In
,
class
Init
,
class
Fun
,
class
Finalize
=
unit_t
,
template
<
class
In
,
class
Init
,
class
Fun
,
class
Finalize
=
unit_t
,
class
Trait
=
stream_sink_trait_t
<
Fun
>
>
class
Trait
=
stream_sink_trait_t
<
Fun
>
>
make_sink_result
<
In
>
make_sink
(
const
stream
<
In
>&
in
,
Init
init
,
Fun
fun
,
make_sink_result
<
In
>
make_sink
(
const
stream
<
In
>&
in
,
Init
init
,
Fun
fun
,
...
@@ -554,6 +539,7 @@ public:
...
@@ -554,6 +539,7 @@ public:
std
::
move
(
fin
));
std
::
move
(
fin
));
}
}
/// @deprecated Please use `attach_stream_stage` instead.
template
<
class
Driver
,
class
In
,
class
...
Ts
,
class
...
Us
>
template
<
class
Driver
,
class
In
,
class
...
Ts
,
class
...
Us
>
make_stage_result_t
<
In
,
typename
Driver
::
downstream_manager_type
,
Ts
...
>
make_stage_result_t
<
In
,
typename
Driver
::
downstream_manager_type
,
Ts
...
>
make_stage
(
const
stream
<
In
>&
src
,
std
::
tuple
<
Ts
...
>
xs
,
Us
&&
...
ys
)
{
make_stage
(
const
stream
<
In
>&
src
,
std
::
tuple
<
Ts
...
>
xs
,
Us
&&
...
ys
)
{
...
@@ -564,6 +550,7 @@ public:
...
@@ -564,6 +550,7 @@ public:
return
{
in
,
out
,
std
::
move
(
mgr
)};
return
{
in
,
out
,
std
::
move
(
mgr
)};
}
}
/// @deprecated Please use `attach_stream_stage` instead.
template
<
class
In
,
class
...
Ts
,
class
Init
,
class
Fun
,
template
<
class
In
,
class
...
Ts
,
class
Init
,
class
Fun
,
class
Finalize
=
unit_t
,
class
Finalize
=
unit_t
,
class
DownstreamManager
=
default_downstream_manager_t
<
Fun
>,
class
DownstreamManager
=
default_downstream_manager_t
<
Fun
>,
...
@@ -595,6 +582,7 @@ public:
...
@@ -595,6 +582,7 @@ public:
std
::
move
(
fun
),
std
::
move
(
fin
));
std
::
move
(
fun
),
std
::
move
(
fin
));
}
}
/// @deprecated Please use `attach_stream_stage` instead.
template
<
class
In
,
class
Init
,
class
Fun
,
class
Finalize
=
unit_t
,
template
<
class
In
,
class
Init
,
class
Fun
,
class
Finalize
=
unit_t
,
class
DownstreamManager
=
default_downstream_manager_t
<
Fun
>,
class
DownstreamManager
=
default_downstream_manager_t
<
Fun
>,
class
Trait
=
stream_stage_trait_t
<
Fun
>>
class
Trait
=
stream_stage_trait_t
<
Fun
>>
...
@@ -605,9 +593,7 @@ public:
...
@@ -605,9 +593,7 @@ public:
std
::
move
(
fin
),
token
);
std
::
move
(
fin
),
token
);
}
}
/// Returns a stream manager (implementing a continuous stage) without in- or
/// @deprecated Please use `attach_continuous_stream_stage` instead.
/// outbound path. The returned manager is not connected to any slot and thus
/// not stored by the actor automatically.
template
<
class
Driver
,
class
...
Ts
>
template
<
class
Driver
,
class
...
Ts
>
typename
Driver
::
stage_ptr_type
make_continuous_stage
(
Ts
&&
...
xs
)
{
typename
Driver
::
stage_ptr_type
make_continuous_stage
(
Ts
&&
...
xs
)
{
auto
ptr
=
detail
::
make_stream_stage
<
Driver
>
(
this
,
std
::
forward
<
Ts
>
(
xs
)...);
auto
ptr
=
detail
::
make_stream_stage
<
Driver
>
(
this
,
std
::
forward
<
Ts
>
(
xs
)...);
...
@@ -615,6 +601,7 @@ public:
...
@@ -615,6 +601,7 @@ public:
return
ptr
;
return
ptr
;
}
}
/// @deprecated Please use `attach_continuous_stream_stage` instead.
template
<
class
Init
,
class
Fun
,
class
Cleanup
,
template
<
class
Init
,
class
Fun
,
class
Cleanup
,
class
DownstreamManager
=
default_downstream_manager_t
<
Fun
>,
class
DownstreamManager
=
default_downstream_manager_t
<
Fun
>,
class
Trait
=
stream_stage_trait_t
<
Fun
>>
class
Trait
=
stream_stage_trait_t
<
Fun
>>
...
...
libcaf_core/caf/stream_manager.hpp
View file @
b877c738
...
@@ -31,7 +31,6 @@
...
@@ -31,7 +31,6 @@
#include "caf/mailbox_element.hpp"
#include "caf/mailbox_element.hpp"
#include "caf/make_message.hpp"
#include "caf/make_message.hpp"
#include "caf/message_builder.hpp"
#include "caf/message_builder.hpp"
#include "caf/output_stream.hpp"
#include "caf/ref_counted.hpp"
#include "caf/ref_counted.hpp"
#include "caf/stream.hpp"
#include "caf/stream.hpp"
#include "caf/stream_slot.hpp"
#include "caf/stream_slot.hpp"
...
...
libcaf_core/caf/stream_slot.hpp
View file @
b877c738
...
@@ -20,8 +20,6 @@
...
@@ -20,8 +20,6 @@
#include <cstdint>
#include <cstdint>
#include "caf/output_stream.hpp"
#include "caf/detail/comparable.hpp"
#include "caf/detail/comparable.hpp"
namespace
caf
{
namespace
caf
{
...
@@ -35,7 +33,7 @@ constexpr stream_slot invalid_stream_slot = 0;
...
@@ -35,7 +33,7 @@ constexpr stream_slot invalid_stream_slot = 0;
/// Maps two `stream_slot` values into a pair for storing sender and receiver
/// Maps two `stream_slot` values into a pair for storing sender and receiver
/// slot information.
/// slot information.
struct
stream_slots
:
detail
::
comparable
<
stream_slots
>
{
struct
stream_slots
:
detail
::
comparable
<
stream_slots
>
{
stream_slot
sender
;
stream_slot
sender
;
stream_slot
receiver
;
stream_slot
receiver
;
...
@@ -46,8 +44,7 @@ struct stream_slots : detail::comparable<stream_slots>{
...
@@ -46,8 +44,7 @@ struct stream_slots : detail::comparable<stream_slots>{
}
}
constexpr
stream_slots
(
stream_slot
sender_slot
,
stream_slot
receiver_slot
)
constexpr
stream_slots
(
stream_slot
sender_slot
,
stream_slot
receiver_slot
)
:
sender
(
sender_slot
),
:
sender
(
sender_slot
),
receiver
(
receiver_slot
)
{
receiver
(
receiver_slot
)
{
// nop
// nop
}
}
...
@@ -82,7 +79,7 @@ public:
...
@@ -82,7 +79,7 @@ public:
// -- constructors, destructors, and assignment operators --------------------
// -- constructors, destructors, and assignment operators --------------------
constexpr
inbound_stream_slot
(
stream_slot
value
=
0
)
:
value_
(
value
)
{
constexpr
inbound_stream_slot
(
stream_slot
value
=
0
)
:
value_
(
value
)
{
// nop
// nop
}
}
...
@@ -117,26 +114,28 @@ public:
...
@@ -117,26 +114,28 @@ public:
/// Type of a single element.
/// Type of a single element.
using
output_type
=
OutputType
;
using
output_type
=
OutputType
;
/// The return type for `scheduled_actor::make_source`.
/// Type of a stream over the elements.
using
output_stream_type
=
output_stream
<
output_type
,
HandshakeArgs
...
>
;
using
stream_type
=
stream
<
output_type
>
;
/// Type of user-defined handshake arguments.
using
handshake_arguments
=
std
::
tuple
<
HandshakeArgs
...
>
;
// -- constructors, destructors, and assignment operators --------------------
// -- constructors, destructors, and assignment operators --------------------
constexpr
outbound_stream_slot
(
stream_slot
value
=
0
)
:
value_
(
value
)
{
constexpr
outbound_stream_slot
(
stream_slot
value
=
0
)
:
value_
(
value
)
{
// nop
// nop
}
}
outbound_stream_slot
(
outbound_stream_slot
&&
)
=
default
;
outbound_stream_slot
(
outbound_stream_slot
&&
)
=
default
;
outbound_stream_slot
(
const
outbound_stream_slot
&
)
=
default
;
outbound_stream_slot
(
const
outbound_stream_slot
&
)
=
default
;
outbound_stream_slot
&
operator
=
(
outbound_stream_slot
&&
)
=
default
;
outbound_stream_slot
&
operator
=
(
outbound_stream_slot
&&
)
=
default
;
outbound_stream_slot
&
operator
=
(
const
outbound_stream_slot
&
)
=
default
;
outbound_stream_slot
&
operator
=
(
const
outbound_stream_slot
&
)
=
default
;
// -- conversion operators ---------------------------------------------------
// -- conversion operators ---------------------------------------------------
constexpr
operator
output_stream_type
()
const
noexcept
{
return
{};
}
constexpr
operator
stream_slot
()
const
noexcept
{
constexpr
operator
stream_slot
()
const
noexcept
{
return
value_
;
return
value_
;
}
}
...
...
libcaf_core/caf/typed_actor_pointer.hpp
View file @
b877c738
...
@@ -62,7 +62,11 @@ public:
...
@@ -62,7 +62,11 @@ public:
}
}
/// @private
/// @private
scheduled_actor
*
internal_ptr
()
const
{
scheduled_actor
*
internal_ptr
()
const
noexcept
{
return
view_
.
internal_ptr
();
}
operator
scheduled_actor
*
()
const
noexcept
{
return
view_
.
internal_ptr
();
return
view_
.
internal_ptr
();
}
}
...
...
libcaf_core/caf/typed_actor_view.hpp
View file @
b877c738
...
@@ -116,23 +116,27 @@ public:
...
@@ -116,23 +116,27 @@ public:
/// Returns a pointer to the sender of the current message.
/// Returns a pointer to the sender of the current message.
/// @pre `current_mailbox_element() != nullptr`
/// @pre `current_mailbox_element() != nullptr`
inline
strong_actor_ptr
&
current_sender
()
{
strong_actor_ptr
&
current_sender
()
{
return
self_
->
current_sender
();
return
self_
->
current_sender
();
}
}
/// Returns a pointer to the currently processed mailbox element.
/// Returns a pointer to the currently processed mailbox element.
inline
mailbox_element
*
current_mailbox_element
()
{
mailbox_element
*
current_mailbox_element
()
{
return
self_
->
current_mailbox_element
();
return
self_
->
current_mailbox_element
();
}
}
/// @private
/// @private
actor_control_block
*
ctrl
()
const
{
actor_control_block
*
ctrl
()
const
noexcept
{
CAF_ASSERT
(
self_
!=
nullptr
);
CAF_ASSERT
(
self_
!=
nullptr
);
return
actor_control_block
::
from
(
self_
);;
return
actor_control_block
::
from
(
self_
);;
}
}
/// @private
/// @private
scheduled_actor
*
internal_ptr
()
const
{
scheduled_actor
*
internal_ptr
()
const
noexcept
{
return
self_
;
}
operator
scheduled_actor
*
()
const
noexcept
{
return
self_
;
return
self_
;
}
}
...
@@ -141,4 +145,3 @@ private:
...
@@ -141,4 +145,3 @@ private:
};
};
}
// namespace caf
}
// namespace caf
libcaf_core/test/composable_behavior.cpp
View file @
b877c738
...
@@ -16,27 +16,36 @@
...
@@ -16,27 +16,36 @@
* http://www.boost.org/LICENSE_1_0.txt. *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
******************************************************************************/
#
include "caf/config.hpp"
#
define CAF_SUITE composable_behavior
#define CAF_SUITE composable_behaviors
#include "caf/composable_behavior.hpp"
#include "caf/test/unit_test.hpp"
#include "caf/
al
l.hpp"
#include "caf/
test/ds
l.hpp"
#define ERROR_HANDLER \
#include "caf/atom.hpp"
[&](error& err) { CAF_FAIL(system.render(err)); }
#include "caf/attach_stream_sink.hpp"
#include "caf/attach_stream_source.hpp"
#include "caf/attach_stream_stage.hpp"
#include "caf/typed_actor.hpp"
#define ERROR_HANDLER [&](error& err) { CAF_FAIL(system.render(err)); }
using
namespace
std
;
using
namespace
caf
;
using
namespace
caf
;
namespace
{
namespace
{
// -- composable behaviors using primitive data types
------------
--------------
// -- composable behaviors using primitive data types
and streams
--------------
using
i3_actor
=
typed_actor
<
replies_to
<
int
,
int
,
int
>::
with
<
int
>>
;
using
i3_actor
=
typed_actor
<
replies_to
<
int
,
int
,
int
>::
with
<
int
>>
;
using
d_actor
=
typed_actor
<
replies_to
<
double
>::
with
<
double
,
double
>>
;
using
d_actor
=
typed_actor
<
replies_to
<
double
>::
with
<
double
,
double
>>
;
using
source_actor
=
typed_actor
<
replies_to
<
open_atom
>::
with
<
stream
<
int
>>>
;
using
stage_actor
=
typed_actor
<
replies_to
<
stream
<
int
>>::
with
<
stream
<
int
>>>
;
using
sink_actor
=
typed_actor
<
reacts_to
<
stream
<
int
>>>
;
using
foo_actor
=
i3_actor
::
extend_with
<
d_actor
>
;
using
foo_actor
=
i3_actor
::
extend_with
<
d_actor
>
;
class
foo_actor_state
:
public
composable_behavior
<
foo_actor
>
{
class
foo_actor_state
:
public
composable_behavior
<
foo_actor
>
{
...
@@ -74,12 +83,56 @@ public:
...
@@ -74,12 +83,56 @@ public:
// checks whether CAF resolves "diamonds" properly by inheriting
// checks whether CAF resolves "diamonds" properly by inheriting
// from two behaviors that both implement i3_actor
// from two behaviors that both implement i3_actor
struct
foo_actor_state2
struct
foo_actor_state2
:
composed_behavior
<
i3_actor_state2
,
i3_actor_state
,
d_actor_state
>
{
:
composed_behavior
<
i3_actor_state2
,
i3_actor_state
,
d_actor_state
>
{
result
<
int
>
operator
()(
int
x
,
int
y
,
int
z
)
override
{
result
<
int
>
operator
()(
int
x
,
int
y
,
int
z
)
override
{
return
x
-
y
-
z
;
return
x
-
y
-
z
;
}
}
};
};
class
source_actor_state
:
public
composable_behavior
<
source_actor
>
{
public:
result
<
stream
<
int
>>
operator
()(
open_atom
)
override
{
return
attach_stream_source
(
self
,
[](
size_t
&
counter
)
{
counter
=
0
;
},
[](
size_t
&
counter
,
downstream
<
int
>&
out
,
size_t
hint
)
{
auto
n
=
std
::
min
(
static_cast
<
size_t
>
(
100
-
counter
),
hint
);
for
(
size_t
i
=
0
;
i
<
n
;
++
i
)
out
.
push
(
counter
++
);
},
[](
const
size_t
&
counter
)
{
return
counter
<
100
;
});
}
};
class
stage_actor_state
:
public
composable_behavior
<
stage_actor
>
{
public:
result
<
stream
<
int
>>
operator
()(
stream
<
int
>
in
)
override
{
return
attach_stream_stage
(
self
,
in
,
[](
unit_t
&
)
{
// nop
},
[](
unit_t
&
,
downstream
<
int
>&
out
,
int
x
)
{
if
(
x
%
2
==
0
)
out
.
push
(
x
);
});
}
};
class
sink_actor_state
:
public
composable_behavior
<
sink_actor
>
{
public:
std
::
vector
<
int
>
buf
;
result
<
void
>
operator
()(
stream
<
int
>
in
)
override
{
attach_stream_sink
(
self
,
in
,
[](
unit_t
&
)
{
// nop
},
[
=
](
unit_t
&
,
int
x
)
{
buf
.
emplace_back
(
x
);
});
return
unit
;
}
};
// -- composable behaviors using param<T> arguments ----------------------------
// -- composable behaviors using param<T> arguments ----------------------------
std
::
atomic
<
long
>
counting_strings_created
;
std
::
atomic
<
long
>
counting_strings_created
;
...
@@ -141,13 +194,13 @@ std::string to_string(const counting_string& ref) {
...
@@ -141,13 +194,13 @@ std::string to_string(const counting_string& ref) {
return
ref
.
str
();
return
ref
.
str
();
}
}
}
// namespace
<anonymous>
}
// namespace
namespace
std
{
namespace
std
{
template
<
>
template
<
>
struct
hash
<
counting_string
>
{
struct
hash
<
counting_string
>
{
inline
size_t
operator
()(
const
counting_string
&
ref
)
const
{
size_t
operator
()(
const
counting_string
&
ref
)
const
{
hash
<
string
>
f
;
hash
<
string
>
f
;
return
f
(
ref
.
str
());
return
f
(
ref
.
str
());
}
}
...
@@ -163,16 +216,14 @@ using ping_atom = atom_constant<atom("ping")>;
...
@@ -163,16 +216,14 @@ using ping_atom = atom_constant<atom("ping")>;
using
pong_atom
=
atom_constant
<
atom
(
"pong"
)
>
;
using
pong_atom
=
atom_constant
<
atom
(
"pong"
)
>
;
// "base" interface
// "base" interface
using
named_actor
=
using
named_actor
=
typed_actor
<
typed_actor
<
replies_to
<
get_name_atom
>::
with
<
counting_string
>
,
replies_to
<
get_name_atom
>::
with
<
counting_string
>
,
replies_to
<
ping_atom
>::
with
<
pong_atom
>>
;
replies_to
<
ping_atom
>::
with
<
pong_atom
>>
;
// a simple dictionary
// a simple dictionary
using
dict
=
using
dict
=
named_actor
::
extend
<
named_actor
::
extend
<
replies_to
<
get_atom
,
counting_string
>
replies_to
<
get_atom
,
counting_string
>::
with
<
counting_string
>
,
::
with
<
counting_string
>
,
replies_to
<
put_atom
,
counting_string
,
counting_string
>::
with
<
void
>>
;
replies_to
<
put_atom
,
counting_string
,
counting_string
>
::
with
<
void
>>
;
class
dict_state
:
public
composable_behavior
<
dict
>
{
class
dict_state
:
public
composable_behavior
<
dict
>
{
public:
public:
...
@@ -204,9 +255,8 @@ protected:
...
@@ -204,9 +255,8 @@ protected:
std
::
unordered_map
<
counting_string
,
counting_string
>
values_
;
std
::
unordered_map
<
counting_string
,
counting_string
>
values_
;
};
};
using
delayed_testee_actor
=
typed_actor
<
reacts_to
<
int
>
,
using
delayed_testee_actor
=
typed_actor
<
replies_to
<
bool
>::
with
<
int
>
,
reacts_to
<
int
>
,
replies_to
<
bool
>::
with
<
int
>
,
reacts_to
<
std
::
string
>>
;
reacts_to
<
std
::
string
>>
;
class
delayed_testee
:
public
composable_behavior
<
delayed_testee_actor
>
{
class
delayed_testee
:
public
composable_behavior
<
delayed_testee_actor
>
{
public:
public:
...
@@ -228,142 +278,148 @@ public:
...
@@ -228,142 +278,148 @@ public:
}
}
};
};
struct
fixture
{
struct
config
:
actor_system_config
{
fixture
()
:
system
(
cfg
)
{
config
()
{
// nop
using
foo_actor_impl
=
composable_behavior_based_actor
<
foo_actor_state
>
;
add_actor_type
<
foo_actor_impl
>
(
"foo_actor"
);
}
}
};
actor_system_config
cfg
;
struct
fixture
:
test_coordinator_fixture
<
config
>
{
actor_system
system
;
// nop
};
};
}
// namespace
<anonymous>
}
// namespace
CAF_TEST_FIXTURE_SCOPE
(
composable_behaviors_tests
,
fixture
)
CAF_TEST_FIXTURE_SCOPE
(
composable_behaviors_tests
,
fixture
)
CAF_TEST
(
composition
)
{
CAF_TEST
(
composition
)
{
// test foo_foo_actor_state
CAF_MESSAGE
(
"test foo_actor_state"
);
auto
f1
=
make_function_view
(
system
.
spawn
<
foo_actor_state
>
());
auto
f1
=
sys
.
spawn
<
foo_actor_state
>
();
CAF_CHECK_EQUAL
(
f1
(
1
,
2
,
4
),
7
);
inject
((
int
,
int
,
int
),
from
(
self
).
to
(
f1
).
with
(
1
,
2
,
4
));
CAF_CHECK_EQUAL
(
f1
(
42.0
),
std
::
make_tuple
(
42.0
,
42.0
));
expect
((
int
),
from
(
f1
).
to
(
self
).
with
(
7
));
// test on-the-fly composition of i3_actor_state and d_actor_state
inject
((
double
),
from
(
self
).
to
(
f1
).
with
(
42.0
));
f1
.
assign
(
system
.
spawn
<
composed_behavior
<
i3_actor_state
,
d_actor_state
>>
());
expect
((
double
,
double
),
from
(
f1
).
to
(
self
).
with
(
42.0
,
42.0
));
CAF_CHECK_EQUAL
(
f1
(
1
,
2
,
4
),
7
);
CAF_MESSAGE
(
"test composed_behavior<i3_actor_state, d_actor_state>"
);
CAF_CHECK_EQUAL
(
f1
(
42.0
),
std
::
make_tuple
(
42.0
,
42.0
));
f1
=
sys
.
spawn
<
composed_behavior
<
i3_actor_state
,
d_actor_state
>>
();
// test on-the-fly composition of i3_actor_state2 and d_actor_state
inject
((
int
,
int
,
int
),
from
(
self
).
to
(
f1
).
with
(
1
,
2
,
4
));
f1
.
assign
(
system
.
spawn
<
composed_behavior
<
i3_actor_state2
,
d_actor_state
>>
());
expect
((
int
),
from
(
f1
).
to
(
self
).
with
(
7
));
CAF_CHECK_EQUAL
(
f1
(
1
,
2
,
4
),
8
);
inject
((
double
),
from
(
self
).
to
(
f1
).
with
(
42.0
));
CAF_CHECK_EQUAL
(
f1
(
42.0
),
std
::
make_tuple
(
42.0
,
42.0
));
expect
((
double
,
double
),
from
(
f1
).
to
(
self
).
with
(
42.0
,
42.0
));
// test foo_actor_state2
CAF_MESSAGE
(
"test composed_behavior<i3_actor_state2, d_actor_state>"
);
f1
.
assign
(
system
.
spawn
<
foo_actor_state2
>
());
f1
=
sys
.
spawn
<
composed_behavior
<
i3_actor_state2
,
d_actor_state
>>
();
CAF_CHECK_EQUAL
(
f1
(
1
,
2
,
4
),
-
5
);
inject
((
int
,
int
,
int
),
from
(
self
).
to
(
f1
).
with
(
1
,
2
,
4
));
CAF_CHECK_EQUAL
(
f1
(
42.0
),
std
::
make_tuple
(
42.0
,
42.0
));
expect
((
int
),
from
(
f1
).
to
(
self
).
with
(
8
));
inject
((
double
),
from
(
self
).
to
(
f1
).
with
(
42.0
));
expect
((
double
,
double
),
from
(
f1
).
to
(
self
).
with
(
42.0
,
42.0
));
CAF_MESSAGE
(
"test foo_actor_state2"
);
f1
=
sys
.
spawn
<
foo_actor_state2
>
();
inject
((
int
,
int
,
int
),
from
(
self
).
to
(
f1
).
with
(
1
,
2
,
4
));
expect
((
int
),
from
(
f1
).
to
(
self
).
with
(
-
5
));
inject
((
double
),
from
(
self
).
to
(
f1
).
with
(
42.0
));
expect
((
double
,
double
),
from
(
f1
).
to
(
self
).
with
(
42.0
,
42.0
));
}
}
CAF_TEST
(
param_detaching
)
{
CAF_TEST
(
param_detaching
)
{
auto
dict
=
actor_cast
<
actor
>
(
system
.
spawn
<
dict_state
>
());
auto
dict
=
actor_cast
<
actor
>
(
sys
.
spawn
<
dict_state
>
());
scoped_actor
self
{
system
};
// this ping-pong makes sure that dict has cleaned up all state related
// to a test before moving to the second test; otherwise, reference counts
// can diverge from what we expect
auto
ping_pong
=
[
&
]
{
self
->
request
(
dict
,
infinite
,
ping_atom
::
value
).
receive
(
[](
pong_atom
)
{
// nop
},
[
&
](
error
&
err
)
{
CAF_FAIL
(
"error: "
<<
system
.
render
(
err
));
}
);
};
// Using CAF is the key to success!
// Using CAF is the key to success!
counting_string
key
=
"CAF"
;
counting_string
key
=
"CAF"
;
counting_string
value
=
"success"
;
counting_string
value
=
"success"
;
CAF_CHECK_EQUAL
(
counting_strings_created
.
load
(),
2
);
CAF_CHECK_EQUAL
(
counting_strings_created
.
load
(),
2
);
CAF_CHECK_EQUAL
(
counting_strings_moved
.
load
(),
0
);
CAF_CHECK_EQUAL
(
counting_strings_moved
.
load
(),
0
);
CAF_CHECK_EQUAL
(
counting_strings_destroyed
.
load
(),
0
);
CAF_CHECK_EQUAL
(
counting_strings_destroyed
.
load
(),
0
);
//
wrap two strings into messages
//
Wrap two strings into messages.
auto
put_msg
=
make_message
(
put_atom
::
value
,
key
,
value
);
auto
put_msg
=
make_message
(
put_atom
::
value
,
key
,
value
);
auto
get_msg
=
make_message
(
get_atom
::
value
,
key
);
auto
get_msg
=
make_message
(
get_atom
::
value
,
key
);
CAF_CHECK_EQUAL
(
counting_strings_created
.
load
(),
5
);
CAF_CHECK_EQUAL
(
counting_strings_created
.
load
(),
5
);
CAF_CHECK_EQUAL
(
counting_strings_moved
.
load
(),
0
);
CAF_CHECK_EQUAL
(
counting_strings_moved
.
load
(),
0
);
CAF_CHECK_EQUAL
(
counting_strings_destroyed
.
load
(),
0
);
CAF_CHECK_EQUAL
(
counting_strings_destroyed
.
load
(),
0
);
// send put message to dictionary
// Send put message to dictionary.
self
->
request
(
dict
,
infinite
,
put_msg
).
receive
(
self
->
send
(
dict
,
put_msg
);
[
&
]
{
sched
.
run
();
ping_pong
();
// The handler of put_atom calls .move() on key and value, both causing to
// the handler of put_atom calls .move() on key and value,
// detach + move into the map.
// both causing to detach + move into the map
CAF_CHECK_EQUAL
(
counting_strings_created
.
load
(),
9
);
CAF_CHECK_EQUAL
(
counting_strings_created
.
load
(),
9
);
CAF_CHECK_EQUAL
(
counting_strings_moved
.
load
(),
2
);
CAF_CHECK_EQUAL
(
counting_strings_moved
.
load
(),
2
);
CAF_CHECK_EQUAL
(
counting_strings_destroyed
.
load
(),
2
);
CAF_CHECK_EQUAL
(
counting_strings_destroyed
.
load
(),
2
);
// Send put message to dictionary again.
},
self
->
send
(
dict
,
put_msg
);
ERROR_HANDLER
sched
.
run
();
);
// The handler checks whether key already exists -> no copies.
// send put message to dictionary again
CAF_CHECK_EQUAL
(
counting_strings_created
.
load
(),
9
);
self
->
request
(
dict
,
infinite
,
put_msg
).
receive
(
CAF_CHECK_EQUAL
(
counting_strings_moved
.
load
(),
2
);
[
&
]
{
CAF_CHECK_EQUAL
(
counting_strings_destroyed
.
load
(),
2
);
ping_pong
();
// Alter our initial put, this time moving it to the dictionary.
// the handler checks whether key already exists -> no copies
CAF_CHECK_EQUAL
(
counting_strings_created
.
load
(),
9
);
CAF_CHECK_EQUAL
(
counting_strings_moved
.
load
(),
2
);
CAF_CHECK_EQUAL
(
counting_strings_destroyed
.
load
(),
2
);
},
ERROR_HANDLER
);
// alter our initial put, this time moving it to the dictionary
put_msg
.
get_mutable_as
<
counting_string
>
(
1
)
=
"neverlord"
;
put_msg
.
get_mutable_as
<
counting_string
>
(
1
)
=
"neverlord"
;
put_msg
.
get_mutable_as
<
counting_string
>
(
2
)
=
"CAF"
;
put_msg
.
get_mutable_as
<
counting_string
>
(
2
)
=
"CAF"
;
// send put message to dictionary
// Send new put message to dictionary.
self
->
request
(
dict
,
infinite
,
std
::
move
(
put_msg
)).
receive
(
self
->
send
(
dict
,
std
::
move
(
put_msg
));
[
&
]
{
sched
.
run
();
ping_pong
();
// The handler of put_atom calls .move() on key and value, but no detaching
// the handler of put_atom calls .move() on key and value,
// occurs this time (unique access) -> move into the map.
// but no detaching occurs this time (unique access) -> move into the map
CAF_CHECK_EQUAL
(
counting_strings_created
.
load
(),
11
);
CAF_CHECK_EQUAL
(
counting_strings_created
.
load
(),
11
);
CAF_CHECK_EQUAL
(
counting_strings_moved
.
load
(),
4
);
CAF_CHECK_EQUAL
(
counting_strings_moved
.
load
(),
4
);
CAF_CHECK_EQUAL
(
counting_strings_destroyed
.
load
(),
4
);
CAF_CHECK_EQUAL
(
counting_strings_destroyed
.
load
(),
4
);
// Finally, check for original key.
},
self
->
send
(
dict
,
std
::
move
(
get_msg
));
ERROR_HANDLER
sched
.
run
();
);
self
->
receive
([
&
](
const
counting_string
&
str
)
{
// finally, check for original key
// We receive a copy of the value, which is copied out of the map and then
self
->
request
(
dict
,
infinite
,
std
::
move
(
get_msg
)).
receive
(
// moved into the result message; the string from our get_msg is destroyed.
[
&
](
const
counting_string
&
str
)
{
CAF_CHECK_EQUAL
(
counting_strings_created
.
load
(),
13
);
ping_pong
();
CAF_CHECK_EQUAL
(
counting_strings_moved
.
load
(),
5
);
// we receive a copy of the value, which is copied out of the map and
CAF_CHECK_EQUAL
(
counting_strings_destroyed
.
load
(),
6
);
// then moved into the result message;
CAF_CHECK_EQUAL
(
str
,
"success"
);
// the string from our get_msg is destroyed
});
CAF_CHECK_EQUAL
(
counting_strings_created
.
load
(),
13
);
// Temporary of our handler is destroyed.
CAF_CHECK_EQUAL
(
counting_strings_moved
.
load
(),
5
);
CAF_CHECK_EQUAL
(
counting_strings_destroyed
.
load
(),
6
);
CAF_CHECK_EQUAL
(
str
,
"success"
);
},
ERROR_HANDLER
);
// temporary of our handler is destroyed
CAF_CHECK_EQUAL
(
counting_strings_destroyed
.
load
(),
7
);
CAF_CHECK_EQUAL
(
counting_strings_destroyed
.
load
(),
7
);
self
->
send_exit
(
dict
,
exit_reason
::
kill
);
self
->
send_exit
(
dict
,
exit_reason
::
user_shutdown
);
self
->
await_all_other_actors_done
();
sched
.
run
();
// only `key` and `value` from this scope remain
dict
=
nullptr
;
// Only `key` and `value` from this scope remain.
CAF_CHECK_EQUAL
(
counting_strings_destroyed
.
load
(),
11
);
CAF_CHECK_EQUAL
(
counting_strings_destroyed
.
load
(),
11
);
}
}
CAF_TEST
(
delayed_sends
)
{
CAF_TEST
(
delayed_sends
)
{
scoped_actor
self
{
system
};
auto
testee
=
self
->
spawn
<
delayed_testee
>
();
auto
testee
=
self
->
spawn
<
delayed_testee
>
();
self
->
send
(
testee
,
42
);
inject
((
int
),
from
(
self
).
to
(
testee
).
with
(
42
));
disallow
((
bool
),
from
(
_
).
to
(
testee
));
sched
.
trigger_timeouts
();
expect
((
bool
),
from
(
_
).
to
(
testee
));
disallow
((
std
::
string
),
from
(
testee
).
to
(
testee
).
with
(
"hello"
));
sched
.
trigger_timeouts
();
expect
((
std
::
string
),
from
(
testee
).
to
(
testee
).
with
(
"hello"
));
}
}
CAF_TEST_FIXTURE_SCOPE_END
()
CAF_TEST
(
dynamic_spawning
)
{
CAF_TEST
(
dynamic_spawning
)
{
using
impl
=
composable_behavior_based_actor
<
foo_actor_state
>
;
auto
testee
=
unbox
(
sys
.
spawn
<
foo_actor
>
(
"foo_actor"
,
make_message
()));
actor_system_config
cfg
;
inject
((
int
,
int
,
int
),
from
(
self
).
to
(
testee
).
with
(
1
,
2
,
4
));
cfg
.
add_actor_type
<
impl
>
(
"foo_actor"
);
expect
((
int
),
from
(
testee
).
to
(
self
).
with
(
7
));
actor_system
sys
{
cfg
};
inject
((
double
),
from
(
self
).
to
(
testee
).
with
(
42.0
));
auto
sr
=
sys
.
spawn
<
foo_actor
>
(
"foo_actor"
,
make_message
());
expect
((
double
,
double
),
from
(
testee
).
to
(
self
).
with
(
42.0
,
42.0
));
CAF_REQUIRE
(
sr
);
auto
f1
=
make_function_view
(
std
::
move
(
*
sr
));
CAF_CHECK_EQUAL
(
f1
(
1
,
2
,
4
),
7
);
CAF_CHECK_EQUAL
(
f1
(
42.0
),
std
::
make_tuple
(
42.0
,
42.0
));
}
}
CAF_TEST
(
streaming
)
{
auto
src
=
sys
.
spawn
<
source_actor_state
>
();
auto
stg
=
sys
.
spawn
<
stage_actor_state
>
();
auto
snk
=
sys
.
spawn
<
sink_actor_state
>
();
using
src_to_stg
=
typed_actor
<
replies_to
<
open_atom
>::
with
<
stream
<
int
>>>
;
using
stg_to_snk
=
typed_actor
<
reacts_to
<
stream
<
int
>>>
;
static_assert
(
std
::
is_same
<
decltype
(
stg
*
src
),
src_to_stg
>::
value
,
"stg * src produces the wrong type"
);
static_assert
(
std
::
is_same
<
decltype
(
snk
*
stg
),
stg_to_snk
>::
value
,
"stg * src produces the wrong type"
);
auto
pipeline
=
snk
*
stg
*
src
;
self
->
send
(
pipeline
,
open_atom
::
value
);
run
();
using
sink_actor
=
composable_behavior_based_actor
<
sink_actor_state
>
;
auto
&
st
=
deref
<
sink_actor
>
(
snk
).
state
;
CAF_CHECK_EQUAL
(
st
.
buf
.
size
(),
50u
);
auto
is_even
=
[](
int
x
)
{
return
x
%
2
==
0
;
};
CAF_CHECK
(
std
::
all_of
(
st
.
buf
.
begin
(),
st
.
buf
.
end
(),
is_even
));
anon_send_exit
(
src
,
exit_reason
::
user_shutdown
);
anon_send_exit
(
stg
,
exit_reason
::
user_shutdown
);
anon_send_exit
(
snk
,
exit_reason
::
user_shutdown
);
}
CAF_TEST_FIXTURE_SCOPE_END
()
libcaf_core/test/continuous_streaming.cpp
View file @
b877c738
...
@@ -25,6 +25,8 @@
...
@@ -25,6 +25,8 @@
#include "caf/actor_system.hpp"
#include "caf/actor_system.hpp"
#include "caf/actor_system_config.hpp"
#include "caf/actor_system_config.hpp"
#include "caf/attach_continuous_stream_stage.hpp"
#include "caf/attach_stream_sink.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/stateful_actor.hpp"
#include "caf/stateful_actor.hpp"
...
@@ -46,38 +48,37 @@ TESTEE_STATE(file_reader) {
...
@@ -46,38 +48,37 @@ TESTEE_STATE(file_reader) {
};
};
VARARGS_TESTEE
(
file_reader
,
size_t
buf_size
)
{
VARARGS_TESTEE
(
file_reader
,
size_t
buf_size
)
{
return
{
return
{[
=
](
string
&
fname
)
->
result
<
stream
<
int
>
,
string
>
{
[
=
](
string
&
fname
)
->
output_stream
<
int
,
string
>
{
CAF_CHECK_EQUAL
(
fname
,
"numbers.txt"
);
CAF_CHECK_EQUAL
(
fname
,
"numbers.txt"
);
CAF_CHECK_EQUAL
(
self
->
mailbox
().
empty
(),
true
);
CAF_CHECK_EQUAL
(
self
->
mailbox
().
empty
(),
true
);
return
attach_stream_source
(
return
self
->
make_source
(
self
,
// forward file name in handshake to next stage
// forward file name in handshake to next stage
std
::
forward_as_tuple
(
std
::
move
(
fname
)),
std
::
forward_as_tuple
(
std
::
move
(
fname
)),
// initialize state
// initialize state
[
=
](
unit_t
&
)
{
[
=
](
unit_t
&
)
{
auto
&
xs
=
self
->
state
.
buf
;
auto
&
xs
=
self
->
state
.
buf
;
xs
.
resize
(
buf_size
);
xs
.
resize
(
buf_size
);
std
::
iota
(
xs
.
begin
(),
xs
.
end
(),
1
);
std
::
iota
(
xs
.
begin
(),
xs
.
end
(),
1
);
},
},
// get next element
// get next element
[
=
](
unit_t
&
,
downstream
<
int
>&
out
,
size_t
num
)
{
[
=
](
unit_t
&
,
downstream
<
int
>&
out
,
size_t
num
)
{
auto
&
xs
=
self
->
state
.
buf
;
auto
&
xs
=
self
->
state
.
buf
;
CAF_MESSAGE
(
"push "
<<
num
<<
" messages downstream"
);
CAF_MESSAGE
(
"push "
<<
num
<<
" messages downstream"
);
auto
n
=
std
::
min
(
num
,
xs
.
size
());
auto
n
=
std
::
min
(
num
,
xs
.
size
());
for
(
size_t
i
=
0
;
i
<
n
;
++
i
)
for
(
size_t
i
=
0
;
i
<
n
;
++
i
)
out
.
push
(
xs
[
i
]);
out
.
push
(
xs
[
i
]);
xs
.
erase
(
xs
.
begin
(),
xs
.
begin
()
+
static_cast
<
ptrdiff_t
>
(
n
));
xs
.
erase
(
xs
.
begin
(),
xs
.
begin
()
+
static_cast
<
ptrdiff_t
>
(
n
));
},
},
// check whether we reached the end
// check whether we reached the end
[
=
](
const
unit_t
&
)
{
[
=
](
const
unit_t
&
)
{
if
(
self
->
state
.
buf
.
empty
())
{
if
(
self
->
state
.
buf
.
empty
())
{
CAF_MESSAGE
(
self
->
name
()
<<
" is done"
);
CAF_MESSAGE
(
self
->
name
()
<<
" is done"
);
return
true
;
return
true
;
}
}
return
false
;
return
false
;
});
});
}
}};
};
}
}
TESTEE_STATE
(
sum_up
)
{
TESTEE_STATE
(
sum_up
)
{
...
@@ -85,32 +86,26 @@ TESTEE_STATE(sum_up) {
...
@@ -85,32 +86,26 @@ TESTEE_STATE(sum_up) {
};
};
TESTEE
(
sum_up
)
{
TESTEE
(
sum_up
)
{
return
{
return
{[
=
](
stream
<
int
>&
in
,
const
string
&
fname
)
{
[
=
](
stream
<
int
>&
in
,
const
string
&
fname
)
{
CAF_CHECK_EQUAL
(
fname
,
"numbers.txt"
);
CAF_CHECK_EQUAL
(
fname
,
"numbers.txt"
);
using
int_ptr
=
int
*
;
using
int_ptr
=
int
*
;
return
attach_stream_sink
(
return
self
->
make_sink
(
self
,
// input stream
// input stream
in
,
in
,
// initialize state
// initialize state
[
=
](
int_ptr
&
x
)
{
[
=
](
int_ptr
&
x
)
{
x
=
&
self
->
state
.
x
;
},
x
=
&
self
->
state
.
x
;
// processing step
},
[](
int_ptr
&
x
,
int
y
)
{
*
x
+=
y
;
},
// processing step
// cleanup
[](
int_ptr
&
x
,
int
y
)
{
[
=
](
int_ptr
&
,
const
error
&
)
{
*
x
+=
y
;
CAF_MESSAGE
(
self
->
name
()
<<
" is done"
);
},
});
// cleanup
},
[
=
](
int_ptr
&
,
const
error
&
)
{
[
=
](
join_atom
atm
,
actor
src
)
{
CAF_MESSAGE
(
self
->
name
()
<<
" is done"
);
CAF_MESSAGE
(
self
->
name
()
<<
" joins a stream"
);
}
self
->
send
(
self
*
src
,
atm
);
);
}};
},
[
=
](
join_atom
atm
,
actor
src
)
{
CAF_MESSAGE
(
self
->
name
()
<<
" joins a stream"
);
self
->
send
(
self
*
src
,
atm
);
}
};
}
}
TESTEE_STATE
(
stream_multiplexer
)
{
TESTEE_STATE
(
stream_multiplexer
)
{
...
@@ -118,20 +113,16 @@ TESTEE_STATE(stream_multiplexer) {
...
@@ -118,20 +113,16 @@ TESTEE_STATE(stream_multiplexer) {
};
};
TESTEE
(
stream_multiplexer
)
{
TESTEE
(
stream_multiplexer
)
{
self
->
state
.
stage
=
self
->
make_continuous_stage
(
self
->
state
.
stage
=
attach_continuous_stream_stage
(
self
,
// initialize state
// initialize state
[](
unit_t
&
)
{
[](
unit_t
&
)
{
// nop
// nop
},
},
// processing step
// processing step
[](
unit_t
&
,
downstream
<
int
>&
out
,
int
x
)
{
[](
unit_t
&
,
downstream
<
int
>&
out
,
int
x
)
{
out
.
push
(
x
);
},
out
.
push
(
x
);
},
// cleanup
// cleanup
[
=
](
unit_t
&
,
const
error
&
)
{
[
=
](
unit_t
&
,
const
error
&
)
{
CAF_MESSAGE
(
self
->
name
()
<<
" is done"
);
});
CAF_MESSAGE
(
self
->
name
()
<<
" is done"
);
}
);
return
{
return
{
[
=
](
join_atom
)
{
[
=
](
join_atom
)
{
CAF_MESSAGE
(
"received 'join' request"
);
CAF_MESSAGE
(
"received 'join' request"
);
...
@@ -151,7 +142,7 @@ TESTEE(stream_multiplexer) {
...
@@ -151,7 +142,7 @@ TESTEE(stream_multiplexer) {
using
fixture
=
test_coordinator_fixture
<>
;
using
fixture
=
test_coordinator_fixture
<>
;
}
// namespace
<anonymous>
}
// namespace
// -- unit tests ---------------------------------------------------------------
// -- unit tests ---------------------------------------------------------------
...
...
libcaf_core/test/fused_
streaming
.cpp
→
libcaf_core/test/fused_
downstream_manager
.cpp
View file @
b877c738
...
@@ -16,7 +16,9 @@
...
@@ -16,7 +16,9 @@
* http://www.boost.org/LICENSE_1_0.txt. *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
******************************************************************************/
#define CAF_SUITE fused_streaming
#define CAF_SUITE fused_downstream_manager
#include "caf/fused_downstream_manager.hpp"
#include "caf/test/dsl.hpp"
#include "caf/test/dsl.hpp"
...
@@ -25,8 +27,8 @@
...
@@ -25,8 +27,8 @@
#include "caf/actor_system.hpp"
#include "caf/actor_system.hpp"
#include "caf/actor_system_config.hpp"
#include "caf/actor_system_config.hpp"
#include "caf/attach_stream_sink.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/fused_downstream_manager.hpp"
#include "caf/stateful_actor.hpp"
#include "caf/stateful_actor.hpp"
using
std
::
string
;
using
std
::
string
;
...
@@ -57,9 +59,10 @@ void push(std::deque<T>& xs, downstream<T>& out, size_t num) {
...
@@ -57,9 +59,10 @@ void push(std::deque<T>& xs, downstream<T>& out, size_t num) {
VARARGS_TESTEE
(
int_file_reader
,
size_t
buf_size
)
{
VARARGS_TESTEE
(
int_file_reader
,
size_t
buf_size
)
{
using
buf
=
std
::
deque
<
int32_t
>
;
using
buf
=
std
::
deque
<
int32_t
>
;
return
{
return
{
[
=
](
string
&
fname
)
->
output_stream
<
int32_t
>
{
[
=
](
string
&
fname
)
->
result
<
stream
<
int32_t
>
>
{
CAF_CHECK_EQUAL
(
fname
,
"numbers.txt"
);
CAF_CHECK_EQUAL
(
fname
,
"numbers.txt"
);
return
self
->
make_source
(
return
attach_stream_source
(
self
,
// initialize state
// initialize state
[
=
](
buf
&
xs
)
{
[
=
](
buf
&
xs
)
{
xs
.
resize
(
buf_size
);
xs
.
resize
(
buf_size
);
...
@@ -70,19 +73,18 @@ VARARGS_TESTEE(int_file_reader, size_t buf_size) {
...
@@ -70,19 +73,18 @@ VARARGS_TESTEE(int_file_reader, size_t buf_size) {
push
(
xs
,
out
,
num
);
push
(
xs
,
out
,
num
);
},
},
// check whether we reached the end
// check whether we reached the end
[
=
](
const
buf
&
xs
)
{
[
=
](
const
buf
&
xs
)
{
return
xs
.
empty
();
});
return
xs
.
empty
();
},
});
}
};
};
}
}
VARARGS_TESTEE
(
string_file_reader
,
size_t
buf_size
)
{
VARARGS_TESTEE
(
string_file_reader
,
size_t
buf_size
)
{
using
buf
=
std
::
deque
<
string
>
;
using
buf
=
std
::
deque
<
string
>
;
return
{
return
{
[
=
](
string
&
fname
)
->
output_stream
<
string
>
{
[
=
](
string
&
fname
)
->
result
<
stream
<
string
>
>
{
CAF_CHECK_EQUAL
(
fname
,
"strings.txt"
);
CAF_CHECK_EQUAL
(
fname
,
"strings.txt"
);
return
self
->
make_source
(
return
attach_stream_source
(
self
,
// initialize state
// initialize state
[
=
](
buf
&
xs
)
{
[
=
](
buf
&
xs
)
{
for
(
size_t
i
=
0
;
i
<
buf_size
;
++
i
)
for
(
size_t
i
=
0
;
i
<
buf_size
;
++
i
)
...
@@ -93,10 +95,8 @@ VARARGS_TESTEE(string_file_reader, size_t buf_size) {
...
@@ -93,10 +95,8 @@ VARARGS_TESTEE(string_file_reader, size_t buf_size) {
push
(
xs
,
out
,
num
);
push
(
xs
,
out
,
num
);
},
},
// check whether we reached the end
// check whether we reached the end
[
=
](
const
buf
&
xs
)
{
[
=
](
const
buf
&
xs
)
{
return
xs
.
empty
();
});
return
xs
.
empty
();
},
});
}
};
};
}
}
...
@@ -108,27 +108,23 @@ TESTEE(sum_up) {
...
@@ -108,27 +108,23 @@ TESTEE(sum_up) {
using
intptr
=
int
*
;
using
intptr
=
int
*
;
return
{
return
{
[
=
](
stream
<
int32_t
>&
in
)
{
[
=
](
stream
<
int32_t
>&
in
)
{
return
self
->
make_sink
(
return
attach_stream_sink
(
self
,
// input stream
// input stream
in
,
in
,
// initialize state
// initialize state
[
=
](
intptr
&
x
)
{
[
=
](
intptr
&
x
)
{
x
=
&
self
->
state
.
x
;
},
x
=
&
self
->
state
.
x
;
},
// processing step
// processing step
[](
intptr
&
x
,
int32_t
y
)
{
[](
intptr
&
x
,
int32_t
y
)
{
*
x
+=
y
;
},
*
x
+=
y
;
},
// cleanup and produce result message
// cleanup and produce result message
[
=
](
intptr
&
,
const
error
&
)
{
[
=
](
intptr
&
,
const
error
&
)
{
CAF_MESSAGE
(
self
->
name
()
<<
" is done"
);
CAF_MESSAGE
(
self
->
name
()
<<
" is done"
);
}
});
);
},
},
[
=
](
join_atom
,
actor
src
)
{
[
=
](
join_atom
,
actor
src
)
{
CAF_MESSAGE
(
self
->
name
()
<<
" joins a stream"
);
CAF_MESSAGE
(
self
->
name
()
<<
" joins a stream"
);
self
->
send
(
self
*
src
,
join_atom
::
value
,
ints_atom
::
value
);
self
->
send
(
self
*
src
,
join_atom
::
value
,
ints_atom
::
value
);
}
}
,
};
};
}
}
...
@@ -139,7 +135,8 @@ TESTEE_STATE(collect) {
...
@@ -139,7 +135,8 @@ TESTEE_STATE(collect) {
TESTEE
(
collect
)
{
TESTEE
(
collect
)
{
return
{
return
{
[
=
](
stream
<
string
>&
in
)
{
[
=
](
stream
<
string
>&
in
)
{
return
self
->
make_sink
(
return
attach_stream_sink
(
self
,
// input stream
// input stream
in
,
in
,
// initialize state
// initialize state
...
@@ -153,13 +150,12 @@ TESTEE(collect) {
...
@@ -153,13 +150,12 @@ TESTEE(collect) {
// cleanup and produce result message
// cleanup and produce result message
[
=
](
unit_t
&
,
const
error
&
)
{
[
=
](
unit_t
&
,
const
error
&
)
{
CAF_MESSAGE
(
self
->
name
()
<<
" is done"
);
CAF_MESSAGE
(
self
->
name
()
<<
" is done"
);
}
});
);
},
},
[
=
](
join_atom
,
actor
src
)
{
[
=
](
join_atom
,
actor
src
)
{
CAF_MESSAGE
(
self
->
name
()
<<
" joins a stream"
);
CAF_MESSAGE
(
self
->
name
()
<<
" joins a stream"
);
self
->
send
(
self
*
src
,
join_atom
::
value
,
strings_atom
::
value
);
self
->
send
(
self
*
src
,
join_atom
::
value
,
strings_atom
::
value
);
}
}
,
};
};
}
}
...
@@ -167,8 +163,8 @@ using int_downstream_manager = broadcast_downstream_manager<int>;
...
@@ -167,8 +163,8 @@ using int_downstream_manager = broadcast_downstream_manager<int>;
using
string_downstream_manager
=
broadcast_downstream_manager
<
string
>
;
using
string_downstream_manager
=
broadcast_downstream_manager
<
string
>
;
using
fused_manager
=
using
fused_manager
=
fused_downstream_manager
<
int_downstream_manager
,
fused_downstream_manager
<
int_downstream_manager
,
string_downstream_manager
>
;
string_downstream_manager
>
;
class
fused_stage
:
public
stream_manager
{
class
fused_stage
:
public
stream_manager
{
public:
public:
...
@@ -248,7 +244,7 @@ TESTEE(stream_multiplexer) {
...
@@ -248,7 +244,7 @@ TESTEE(stream_multiplexer) {
[
=
](
const
stream
<
string
>&
in
)
{
[
=
](
const
stream
<
string
>&
in
)
{
CAF_MESSAGE
(
"received handshake for strings"
);
CAF_MESSAGE
(
"received handshake for strings"
);
return
self
->
state
.
stage
->
add_unchecked_inbound_path
(
in
);
return
self
->
state
.
stage
->
add_unchecked_inbound_path
(
in
);
}
}
,
};
};
}
}
...
@@ -260,11 +256,11 @@ struct config : actor_system_config {
...
@@ -260,11 +256,11 @@ struct config : actor_system_config {
using
fixture
=
test_coordinator_fixture
<>
;
using
fixture
=
test_coordinator_fixture
<>
;
}
// namespace
<anonymous>
}
// namespace
// -- unit tests ---------------------------------------------------------------
// -- unit tests ---------------------------------------------------------------
CAF_TEST_FIXTURE_SCOPE
(
fused_
streaming
_tests
,
fixture
)
CAF_TEST_FIXTURE_SCOPE
(
fused_
downstream_manager
_tests
,
fixture
)
CAF_TEST
(
depth_3_pipeline_with_fork
)
{
CAF_TEST
(
depth_3_pipeline_with_fork
)
{
auto
src1
=
sys
.
spawn
(
int_file_reader
,
50u
);
auto
src1
=
sys
.
spawn
(
int_file_reader
,
50u
);
...
...
libcaf_core/test/metaprogramming.cpp
View file @
b877c738
...
@@ -253,34 +253,6 @@ CAF_TEST(typed_behavior_assignment) {
...
@@ -253,34 +253,6 @@ CAF_TEST(typed_behavior_assignment) {
h5
,
h6
,
h7
,
h8
));
h5
,
h6
,
h7
,
h8
));
}
}
CAF_TEST
(
composed_types
)
{
// message type for test message #1
auto
msg_1
=
tk
<
type_list
<
int
>>
();
// message type for test message #1
auto
msg_2
=
tk
<
type_list
<
double
>>
();
// interface type a
auto
if_a
=
tk
<
type_list
<
replies_to
<
int
>::
with
<
double
>
,
replies_to
<
double
,
double
>::
with
<
int
,
int
>>>
();
// interface type b
auto
if_b
=
tk
<
type_list
<
replies_to
<
double
>::
with
<
std
::
string
>>>
();
// interface type c
auto
if_c
=
tk
<
type_list
<
replies_to
<
int
>::
with_stream
<
double
>>>
();
// interface type b . a
auto
if_ba
=
tk
<
typed_actor
<
replies_to
<
int
>::
with
<
std
::
string
>>>
();
// interface type b . c
auto
if_bc
=
tk
<
typed_actor
<
replies_to
<
int
>::
with_stream
<
std
::
string
>>>
();
CAF_MESSAGE
(
"check whether actors return the correct types"
);
auto
nil
=
tk
<
none_t
>
();
auto
dbl
=
tk
<
type_list
<
double
>>
();
//auto dbl_stream = tk<output_stream<double>>();
CAF_CHECK_EQUAL
(
res
(
if_a
,
msg_1
),
dbl
);
CAF_CHECK_EQUAL
(
res
(
if_a
,
msg_2
),
nil
);
//CAF_CHECK_EQUAL(res(if_c, msg_1), dbl_stream);
CAF_MESSAGE
(
"check types of actor compositions"
);
CAF_CHECK_EQUAL
(
dot_op
(
if_b
,
if_a
),
if_ba
);
CAF_CHECK_EQUAL
(
dot_op
(
if_b
,
if_c
),
if_bc
);
}
struct
foo
{};
struct
foo
{};
struct
bar
{};
struct
bar
{};
bool
operator
==
(
const
bar
&
,
const
bar
&
);
bool
operator
==
(
const
bar
&
,
const
bar
&
);
...
...
libcaf_core/test/pipeline_streaming.cpp
View file @
b877c738
...
@@ -25,6 +25,8 @@
...
@@ -25,6 +25,8 @@
#include "caf/actor_system.hpp"
#include "caf/actor_system.hpp"
#include "caf/actor_system_config.hpp"
#include "caf/actor_system_config.hpp"
#include "caf/attach_stream_sink.hpp"
#include "caf/attach_stream_stage.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/stateful_actor.hpp"
#include "caf/stateful_actor.hpp"
...
@@ -64,7 +66,7 @@ std::function<bool(const buf&)> is_done(scheduled_actor* self) {
...
@@ -64,7 +66,7 @@ std::function<bool(const buf&)> is_done(scheduled_actor* self) {
}
}
template
<
class
T
>
template
<
class
T
>
std
::
function
<
void
(
T
&
,
const
error
&
)
>
fin
(
scheduled_actor
*
self
)
{
std
::
function
<
void
(
T
&
,
const
error
&
)
>
fin
(
scheduled_actor
*
self
)
{
return
[
=
](
T
&
,
const
error
&
err
)
{
return
[
=
](
T
&
,
const
error
&
err
)
{
if
(
err
==
none
)
{
if
(
err
==
none
)
{
CAF_MESSAGE
(
self
->
name
()
<<
" is done"
);
CAF_MESSAGE
(
self
->
name
()
<<
" is done"
);
...
@@ -75,51 +77,32 @@ std::function<void (T&, const error&)> fin(scheduled_actor* self) {
...
@@ -75,51 +77,32 @@ std::function<void (T&, const error&)> fin(scheduled_actor* self) {
}
}
TESTEE
(
infinite_source
)
{
TESTEE
(
infinite_source
)
{
return
{
return
{[
=
](
string
&
fname
)
->
result
<
stream
<
int
>>
{
[
=
](
string
&
fname
)
->
output_stream
<
int
>
{
CAF_CHECK_EQUAL
(
fname
,
"numbers.txt"
);
CAF_CHECK_EQUAL
(
fname
,
"numbers.txt"
);
CAF_CHECK_EQUAL
(
self
->
mailbox
().
empty
(),
true
);
CAF_CHECK_EQUAL
(
self
->
mailbox
().
empty
(),
true
);
return
attach_stream_source
(
return
self
->
make_source
(
self
,
[](
int
&
x
)
{
x
=
0
;
},
[](
int
&
x
)
{
[](
int
&
x
,
downstream
<
int
>&
out
,
size_t
num
)
{
x
=
0
;
for
(
size_t
i
=
0
;
i
<
num
;
++
i
)
},
out
.
push
(
x
++
);
[](
int
&
x
,
downstream
<
int
>&
out
,
size_t
num
)
{
},
for
(
size_t
i
=
0
;
i
<
num
;
++
i
)
[](
const
int
&
)
{
return
false
;
},
fin
<
int
>
(
self
));
out
.
push
(
x
++
);
}};
},
[](
const
int
&
)
{
return
false
;
},
fin
<
int
>
(
self
)
);
}
};
}
}
VARARGS_TESTEE
(
file_reader
,
size_t
buf_size
)
{
VARARGS_TESTEE
(
file_reader
,
size_t
buf_size
)
{
return
{
return
{[
=
](
string
&
fname
)
->
result
<
stream
<
int
>>
{
[
=
](
string
&
fname
)
->
output_stream
<
int
>
{
CAF_CHECK_EQUAL
(
fname
,
"numbers.txt"
);
CAF_CHECK_EQUAL
(
fname
,
"numbers.txt"
);
CAF_CHECK_EQUAL
(
self
->
mailbox
().
empty
(),
true
);
CAF_CHECK_EQUAL
(
self
->
mailbox
().
empty
(),
true
);
return
attach_stream_source
(
self
,
init
(
buf_size
),
push_from_buf
,
return
self
->
make_source
(
is_done
(
self
),
fin
<
buf
>
(
self
));
init
(
buf_size
),
},
push_from_buf
,
[
=
](
string
&
fname
,
actor
next
)
{
is_done
(
self
),
CAF_CHECK_EQUAL
(
fname
,
"numbers.txt"
);
fin
<
buf
>
(
self
)
CAF_CHECK_EQUAL
(
self
->
mailbox
().
empty
(),
true
);
);
attach_stream_source
(
self
,
next
,
init
(
buf_size
),
push_from_buf
,
},
is_done
(
self
),
fin
<
buf
>
(
self
));
[
=
](
string
&
fname
,
actor
next
)
{
}};
CAF_CHECK_EQUAL
(
fname
,
"numbers.txt"
);
CAF_CHECK_EQUAL
(
self
->
mailbox
().
empty
(),
true
);
self
->
make_source
(
next
,
init
(
buf_size
),
push_from_buf
,
is_done
(
self
),
fin
<
buf
>
(
self
)
);
}
};
}
}
TESTEE_STATE
(
sum_up
)
{
TESTEE_STATE
(
sum_up
)
{
...
@@ -128,23 +111,16 @@ TESTEE_STATE(sum_up) {
...
@@ -128,23 +111,16 @@ TESTEE_STATE(sum_up) {
TESTEE
(
sum_up
)
{
TESTEE
(
sum_up
)
{
using
intptr
=
int
*
;
using
intptr
=
int
*
;
return
{
return
{[
=
](
stream
<
int
>&
in
)
{
[
=
](
stream
<
int
>&
in
)
{
return
attach_stream_sink
(
return
self
->
make_sink
(
self
,
// input stream
// input stream
in
,
in
,
// initialize state
// initialize state
[
=
](
intptr
&
x
)
{
[
=
](
intptr
&
x
)
{
x
=
&
self
->
state
.
x
;
},
x
=
&
self
->
state
.
x
;
// processing step
},
[](
intptr
&
x
,
int
y
)
{
*
x
+=
y
;
},
fin
<
intptr
>
(
self
));
// processing step
}};
[](
intptr
&
x
,
int
y
)
{
*
x
+=
y
;
},
fin
<
intptr
>
(
self
)
);
}
};
}
}
TESTEE_STATE
(
delayed_sum_up
)
{
TESTEE_STATE
(
delayed_sum_up
)
{
...
@@ -154,83 +130,67 @@ TESTEE_STATE(delayed_sum_up) {
...
@@ -154,83 +130,67 @@ TESTEE_STATE(delayed_sum_up) {
TESTEE
(
delayed_sum_up
)
{
TESTEE
(
delayed_sum_up
)
{
using
intptr
=
int
*
;
using
intptr
=
int
*
;
self
->
set_default_handler
(
skip
);
self
->
set_default_handler
(
skip
);
return
{
return
{[
=
](
ok_atom
)
{
[
=
](
ok_atom
)
{
self
->
become
([
=
](
stream
<
int
>&
in
)
{
self
->
become
(
self
->
set_default_handler
(
print_and_drop
);
[
=
](
stream
<
int
>&
in
)
{
return
attach_stream_sink
(
self
->
set_default_handler
(
print_and_drop
);
self
,
return
self
->
make_sink
(
// input stream
// input stream
in
,
in
,
// initialize state
// initialize state
[
=
](
intptr
&
x
)
{
x
=
&
self
->
state
.
x
;
},
[
=
](
intptr
&
x
)
{
// processing step
x
=
&
self
->
state
.
x
;
[](
intptr
&
x
,
int
y
)
{
*
x
+=
y
;
},
},
// cleanup
// processing step
fin
<
intptr
>
(
self
));
[](
intptr
&
x
,
int
y
)
{
});
*
x
+=
y
;
}};
},
// cleanup
fin
<
intptr
>
(
self
)
);
}
);
}
};
}
}
TESTEE
(
broken_sink
)
{
TESTEE
(
broken_sink
)
{
CAF_IGNORE_UNUSED
(
self
);
CAF_IGNORE_UNUSED
(
self
);
return
{
return
{[
=
](
stream
<
int
>&
,
const
actor
&
)
{
[
=
](
stream
<
int
>&
,
const
actor
&
)
{
// nop
// nop
}};
}
};
}
}
TESTEE
(
filter
)
{
TESTEE
(
filter
)
{
CAF_IGNORE_UNUSED
(
self
);
CAF_IGNORE_UNUSED
(
self
);
return
{
return
{[
=
](
stream
<
int
>&
in
)
{
[
=
](
stream
<
int
>&
in
)
{
return
attach_stream_stage
(
return
self
->
make_stage
(
self
,
// input stream
// input stream
in
,
in
,
// initialize state
// initialize state
[](
unit_t
&
)
{
[](
unit_t
&
)
{
// nop
// nop
},
},
// processing step
// processing step
[](
unit_t
&
,
downstream
<
int
>&
out
,
int
x
)
{
[](
unit_t
&
,
downstream
<
int
>&
out
,
int
x
)
{
if
((
x
&
0x01
)
!=
0
)
if
((
x
&
0x01
)
!=
0
)
out
.
push
(
x
);
out
.
push
(
x
);
},
},
// cleanup
// cleanup
fin
<
unit_t
>
(
self
)
fin
<
unit_t
>
(
self
));
);
}};
}
};
}
}
TESTEE
(
doubler
)
{
TESTEE
(
doubler
)
{
CAF_IGNORE_UNUSED
(
self
);
CAF_IGNORE_UNUSED
(
self
);
return
{
return
{[
=
](
stream
<
int
>&
in
)
{
[
=
](
stream
<
int
>&
in
)
{
return
attach_stream_stage
(
return
self
->
make_stage
(
self
,
// input stream
// input stream
in
,
in
,
// initialize state
// initialize state
[](
unit_t
&
)
{
[](
unit_t
&
)
{
// nop
// nop
},
},
// processing step
// processing step
[](
unit_t
&
,
downstream
<
int
>&
out
,
int
x
)
{
[](
unit_t
&
,
downstream
<
int
>&
out
,
int
x
)
{
out
.
push
(
x
*
2
);
},
out
.
push
(
x
*
2
);
// cleanup
},
fin
<
unit_t
>
(
self
));
// cleanup
}};
fin
<
unit_t
>
(
self
)
);
}
};
}
}
struct
fixture
:
test_coordinator_fixture
<>
{
struct
fixture
:
test_coordinator_fixture
<>
{
...
@@ -245,7 +205,7 @@ struct fixture : test_coordinator_fixture<> {
...
@@ -245,7 +205,7 @@ struct fixture : test_coordinator_fixture<> {
}
}
};
};
}
// namespace
<anonymous>
}
// namespace
// -- unit tests ---------------------------------------------------------------
// -- unit tests ---------------------------------------------------------------
...
@@ -426,8 +386,8 @@ CAF_TEST(depth_4_pipeline_500_items) {
...
@@ -426,8 +386,8 @@ CAF_TEST(depth_4_pipeline_500_items) {
auto
stg1
=
sys
.
spawn
(
filter
);
auto
stg1
=
sys
.
spawn
(
filter
);
auto
stg2
=
sys
.
spawn
(
doubler
);
auto
stg2
=
sys
.
spawn
(
doubler
);
auto
snk
=
sys
.
spawn
(
sum_up
);
auto
snk
=
sys
.
spawn
(
sum_up
);
CAF_MESSAGE
(
CAF_ARG
(
self
)
<<
CAF_ARG
(
src
)
<<
CAF_ARG
(
stg1
)
CAF_MESSAGE
(
CAF_ARG
(
self
)
<<
CAF_ARG
(
src
)
<<
CAF_ARG
(
stg1
)
<<
CAF_ARG
(
stg2
)
<<
CAF_ARG
(
stg2
)
<<
CAF_ARG
(
snk
));
<<
CAF_ARG
(
snk
));
CAF_MESSAGE
(
"initiate stream handshake"
);
CAF_MESSAGE
(
"initiate stream handshake"
);
self
->
send
(
snk
*
stg2
*
stg1
*
src
,
"numbers.txt"
);
self
->
send
(
snk
*
stg2
*
stg1
*
src
,
"numbers.txt"
);
expect
((
string
),
from
(
self
).
to
(
src
).
with
(
"numbers.txt"
));
expect
((
string
),
from
(
self
).
to
(
src
).
with
(
"numbers.txt"
));
...
...
libcaf_core/test/selective_streaming.cpp
View file @
b877c738
...
@@ -26,6 +26,9 @@
...
@@ -26,6 +26,9 @@
#include "caf/actor_system.hpp"
#include "caf/actor_system.hpp"
#include "caf/actor_system_config.hpp"
#include "caf/actor_system_config.hpp"
#include "caf/atom.hpp"
#include "caf/atom.hpp"
#include "caf/attach_continuous_stream_stage.hpp"
#include "caf/attach_stream_sink.hpp"
#include "caf/attach_stream_source.hpp"
#include "caf/broadcast_downstream_manager.hpp"
#include "caf/broadcast_downstream_manager.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/stateful_actor.hpp"
#include "caf/stateful_actor.hpp"
...
@@ -36,13 +39,7 @@ using namespace caf;
...
@@ -36,13 +39,7 @@ using namespace caf;
namespace
{
namespace
{
enum
class
level
{
enum
class
level
{
all
,
trace
,
debug
,
warning
,
error
};
all
,
trace
,
debug
,
warning
,
error
};
using
value_type
=
std
::
pair
<
level
,
string
>
;
using
value_type
=
std
::
pair
<
level
,
string
>
;
...
@@ -55,7 +52,7 @@ struct select {
...
@@ -55,7 +52,7 @@ struct select {
}
}
};
};
using
downstream_manager
=
broadcast_downstream_manager
<
value_type
,
level
,
select
>
;
using
manager_type
=
broadcast_downstream_manager
<
value_type
,
level
,
select
>
;
using
buf
=
std
::
vector
<
value_type
>
;
using
buf
=
std
::
vector
<
value_type
>
;
...
@@ -76,47 +73,43 @@ buf make_log(level lvl) {
...
@@ -76,47 +73,43 @@ buf make_log(level lvl) {
TESTEE_SETUP
();
TESTEE_SETUP
();
TESTEE
(
log_producer
)
{
TESTEE
(
log_producer
)
{
return
{
return
{[
=
](
level
lvl
)
->
result
<
stream
<
value_type
>>
{
[
=
](
level
lvl
)
->
output_stream
<
value_type
>
{
auto
res
=
attach_stream_source
(
auto
res
=
self
->
make_source
(
self
,
// initialize state
// initialize state
[
=
](
buf
&
xs
)
{
[
=
](
buf
&
xs
)
{
xs
=
make_log
(
lvl
);
},
xs
=
make_log
(
lvl
);
// get next element
},
[](
buf
&
xs
,
downstream
<
value_type
>&
out
,
size_t
num
)
{
// get next element
CAF_MESSAGE
(
"push "
<<
num
<<
" messages downstream"
);
[](
buf
&
xs
,
downstream
<
value_type
>&
out
,
size_t
num
)
{
auto
n
=
std
::
min
(
num
,
xs
.
size
());
CAF_MESSAGE
(
"push "
<<
num
<<
" messages downstream"
);
for
(
size_t
i
=
0
;
i
<
n
;
++
i
)
auto
n
=
std
::
min
(
num
,
xs
.
size
());
out
.
push
(
xs
[
i
]);
for
(
size_t
i
=
0
;
i
<
n
;
++
i
)
xs
.
erase
(
xs
.
begin
(),
xs
.
begin
()
+
static_cast
<
ptrdiff_t
>
(
n
));
out
.
push
(
xs
[
i
]);
},
xs
.
erase
(
xs
.
begin
(),
xs
.
begin
()
+
static_cast
<
ptrdiff_t
>
(
n
));
// check whether we reached the end
},
[
=
](
const
buf
&
xs
)
{
// check whether we reached the end
if
(
xs
.
empty
())
{
[
=
](
const
buf
&
xs
)
{
CAF_MESSAGE
(
self
->
name
()
<<
" is done"
);
if
(
xs
.
empty
())
{
return
true
;
CAF_MESSAGE
(
self
->
name
()
<<
" is done"
);
}
return
true
;
return
false
;
}
},
return
false
;
unit
,
policy
::
arg
<
manager_type
>::
value
);
},
auto
&
out
=
res
.
ptr
()
->
out
();
unit
,
static_assert
(
std
::
is_same
<
decltype
(
out
),
manager_type
&>::
value
,
policy
::
arg
<
downstream_manager
>::
value
"source has wrong manager_type type"
);
);
out
.
set_filter
(
res
.
outbound_slot
(),
lvl
);
auto
&
out
=
res
.
ptr
()
->
out
();
return
res
;
static_assert
(
std
::
is_same
<
decltype
(
out
),
downstream_manager
&>::
value
,
}};
"source has wrong downstream_manager type"
);
out
.
set_filter
(
res
.
outbound_slot
(),
lvl
);
return
res
;
}
};
}
}
TESTEE_STATE
(
log_dispatcher
)
{
TESTEE_STATE
(
log_dispatcher
)
{
stream_stage_ptr
<
value_type
,
downstream_manager
>
stage
;
stream_stage_ptr
<
value_type
,
manager_type
>
stage
;
};
};
TESTEE
(
log_dispatcher
)
{
TESTEE
(
log_dispatcher
)
{
self
->
state
.
stage
=
self
->
make_continuous_stage
(
self
->
state
.
stage
=
attach_continuous_stream_stage
(
self
,
// initialize state
// initialize state
[](
unit_t
&
)
{
[](
unit_t
&
)
{
// nop
// nop
...
@@ -126,23 +119,18 @@ TESTEE(log_dispatcher) {
...
@@ -126,23 +119,18 @@ TESTEE(log_dispatcher) {
out
.
push
(
std
::
move
(
x
));
out
.
push
(
std
::
move
(
x
));
},
},
// cleanup
// cleanup
[
=
](
unit_t
&
,
const
error
&
)
{
[
=
](
unit_t
&
,
const
error
&
)
{
CAF_MESSAGE
(
self
->
name
()
<<
" is done"
);
},
CAF_MESSAGE
(
self
->
name
()
<<
" is done"
);
policy
::
arg
<
manager_type
>::
value
);
},
return
{[
=
](
join_atom
,
level
lvl
)
{
policy
::
arg
<
downstream_manager
>::
value
auto
&
stg
=
self
->
state
.
stage
;
);
CAF_MESSAGE
(
"received 'join' request"
);
return
{
auto
result
=
stg
->
add_outbound_path
();
[
=
](
join_atom
,
level
lvl
)
{
stg
->
out
().
set_filter
(
result
,
lvl
);
auto
&
stg
=
self
->
state
.
stage
;
return
result
;
CAF_MESSAGE
(
"received 'join' request"
);
},
auto
result
=
stg
->
add_outbound_path
();
[
=
](
const
stream
<
value_type
>&
in
)
{
stg
->
out
().
set_filter
(
result
,
lvl
);
self
->
state
.
stage
->
add_inbound_path
(
in
);
return
result
;
}};
},
[
=
](
const
stream
<
value_type
>&
in
)
{
self
->
state
.
stage
->
add_inbound_path
(
in
);
}
};
}
}
TESTEE_STATE
(
log_consumer
)
{
TESTEE_STATE
(
log_consumer
)
{
...
@@ -150,26 +138,22 @@ TESTEE_STATE(log_consumer) {
...
@@ -150,26 +138,22 @@ TESTEE_STATE(log_consumer) {
};
};
TESTEE
(
log_consumer
)
{
TESTEE
(
log_consumer
)
{
return
{
return
{[
=
](
stream
<
value_type
>&
in
)
{
[
=
](
stream
<
value_type
>&
in
)
{
return
attach_stream_sink
(
return
self
->
make_sink
(
self
,
// input stream
// input stream
in
,
in
,
// initialize state
// initialize state
[
=
](
unit_t
&
)
{
[
=
](
unit_t
&
)
{
// nop
// nop
},
},
// processing step
// processing step
[
=
](
unit_t
&
,
value_type
x
)
{
[
=
](
unit_t
&
,
value_type
x
)
{
self
->
state
.
log
.
emplace_back
(
std
::
move
(
x
));
self
->
state
.
log
.
emplace_back
(
std
::
move
(
x
));
},
},
// cleanup and produce result message
// cleanup and produce result message
[
=
](
unit_t
&
,
const
error
&
)
{
[
=
](
unit_t
&
,
const
error
&
)
{
CAF_MESSAGE
(
self
->
name
()
<<
" is done"
);
});
CAF_MESSAGE
(
self
->
name
()
<<
" is done"
);
}};
}
);
}
};
}
}
struct
config
:
actor_system_config
{
struct
config
:
actor_system_config
{
...
@@ -180,7 +164,7 @@ struct config : actor_system_config {
...
@@ -180,7 +164,7 @@ struct config : actor_system_config {
using
fixture
=
test_coordinator_fixture
<
config
>
;
using
fixture
=
test_coordinator_fixture
<
config
>
;
}
// namespace
<anonymous>
}
// namespace
// -- unit tests ---------------------------------------------------------------
// -- unit tests ---------------------------------------------------------------
...
...
libcaf_test/caf/test/dsl.hpp
View file @
b877c738
...
@@ -18,13 +18,14 @@
...
@@ -18,13 +18,14 @@
#pragma once
#pragma once
#include <type_traits>
#include "caf/all.hpp"
#include "caf/all.hpp"
#include "caf/config.hpp"
#include "caf/config.hpp"
#include "caf/detail/gcd.hpp"
#include "caf/meta/annotation.hpp"
#include "caf/meta/annotation.hpp"
#include "caf/test/unit_test.hpp"
#include "caf/test/unit_test.hpp"
#include "caf/detail/gcd.hpp"
CAF_PUSH_WARNINGS
CAF_PUSH_WARNINGS
/// The type of `_`.
/// The type of `_`.
...
@@ -375,6 +376,71 @@ protected:
...
@@ -375,6 +376,71 @@ protected:
std
::
function
<
void
()
>
peek_
;
std
::
function
<
void
()
>
peek_
;
};
};
template
<
class
...
Ts
>
class
inject_clause
{
public:
inject_clause
(
caf
::
scheduler
::
test_coordinator
&
sched
)
:
sched_
(
sched
),
dest_
(
nullptr
)
{
// nop
}
inject_clause
(
inject_clause
&&
other
)
=
default
;
template
<
class
Handle
>
inject_clause
&
from
(
const
Handle
&
whom
)
{
src_
=
caf
::
actor_cast
<
caf
::
strong_actor_ptr
>
(
whom
);
return
*
this
;
}
template
<
class
Handle
>
inject_clause
&
to
(
const
Handle
&
whom
)
{
dest_
=
caf
::
actor_cast
<
caf
::
strong_actor_ptr
>
(
whom
);
return
*
this
;
}
inject_clause
&
to
(
const
caf
::
scoped_actor
&
whom
)
{
dest_
=
whom
.
ptr
();
return
*
this
;
}
void
with
(
Ts
...
xs
)
{
if
(
src_
==
nullptr
)
CAF_FAIL
(
"missing .from() in inject() statement"
);
if
(
dest_
==
nullptr
)
CAF_FAIL
(
"missing .to() in inject() statement"
);
caf
::
send_as
(
caf
::
actor_cast
<
caf
::
actor
>
(
src_
),
caf
::
actor_cast
<
caf
::
actor
>
(
dest_
),
xs
...);
CAF_REQUIRE
(
sched_
.
prioritize
(
dest_
));
auto
dest_ptr
=
&
sched_
.
next_job
<
caf
::
abstract_actor
>
();
auto
ptr
=
dest_ptr
->
peek_at_next_mailbox_element
();
CAF_REQUIRE
(
ptr
!=
nullptr
);
CAF_REQUIRE_EQUAL
(
ptr
->
sender
,
src_
);
// TODO: replace this workaround with the make_tuple() line when dropping
// support for GCC 4.8.
std
::
tuple
<
Ts
...
>
tmp
{
std
::
move
(
xs
)...};
using
namespace
caf
::
detail
;
elementwise_compare_inspector
<
decltype
(
tmp
)
>
inspector
{
tmp
};
auto
ys
=
extract
<
Ts
...
>
(
dest_
);
auto
ys_indices
=
get_indices
(
ys
);
CAF_REQUIRE
(
apply_args
(
inspector
,
ys_indices
,
ys
));
run_once
();
}
protected:
void
run_once
()
{
auto
ptr
=
caf
::
actor_cast
<
caf
::
abstract_actor
*>
(
dest_
);
auto
dptr
=
dynamic_cast
<
caf
::
blocking_actor
*>
(
ptr
);
if
(
dptr
==
nullptr
)
sched_
.
run_once
();
else
dptr
->
dequeue
();
// Drop message.
}
caf
::
scheduler
::
test_coordinator
&
sched_
;
caf
::
strong_actor_ptr
src_
;
caf
::
strong_actor_ptr
dest_
;
};
template
<
class
...
Ts
>
template
<
class
...
Ts
>
class
allow_clause
{
class
allow_clause
{
public:
public:
...
@@ -797,6 +863,12 @@ T unbox(T* x) {
...
@@ -797,6 +863,12 @@ T unbox(T* x) {
expect_clause<CAF_EXPAND(CAF_DSL_LIST types)>{sched}.fields; \
expect_clause<CAF_EXPAND(CAF_DSL_LIST types)>{sched}.fields; \
} while (false)
} while (false)
#define inject(types, fields) \
do { \
CAF_MESSAGE("inject" << #types << "." << #fields); \
inject_clause<CAF_EXPAND(CAF_DSL_LIST types)>{sched}.fields; \
} while (false)
/// Convenience macro for defining allow clauses.
/// Convenience macro for defining allow clauses.
#define allow(types, fields) \
#define allow(types, fields) \
([&] { \
([&] { \
...
...
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