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
d19ca0d6
Commit
d19ca0d6
authored
Mar 18, 2020
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Enable states with non-default constructor
parent
99212ecc
Changes
11
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
168 additions
and
113 deletions
+168
-113
CHANGELOG.md
CHANGELOG.md
+9
-0
examples/message_passing/fan_out_request.cpp
examples/message_passing/fan_out_request.cpp
+0
-1
libcaf_core/caf/composable_behavior_based_actor.hpp
libcaf_core/caf/composable_behavior_based_actor.hpp
+3
-1
libcaf_core/caf/detail/type_traits.hpp
libcaf_core/caf/detail/type_traits.hpp
+1
-0
libcaf_core/caf/infer_handle.hpp
libcaf_core/caf/infer_handle.hpp
+0
-1
libcaf_core/caf/stateful_actor.hpp
libcaf_core/caf/stateful_actor.hpp
+63
-62
libcaf_core/caf/type_nr.hpp
libcaf_core/caf/type_nr.hpp
+6
-0
libcaf_core/src/actor_registry.cpp
libcaf_core/src/actor_registry.cpp
+0
-1
libcaf_core/src/actor_system.cpp
libcaf_core/src/actor_system.cpp
+1
-0
libcaf_core/test/stateful_actor.cpp
libcaf_core/test/stateful_actor.cpp
+80
-43
libcaf_test/caf/test/dsl.hpp
libcaf_test/caf/test/dsl.hpp
+5
-4
No files found.
CHANGELOG.md
View file @
d19ca0d6
...
@@ -68,6 +68,15 @@ is based on [Keep a Changelog](https://keepachangelog.com).
...
@@ -68,6 +68,15 @@ is based on [Keep a Changelog](https://keepachangelog.com).
-
Our manual now uses
`reStructuredText`
instead of
`LaTeX`
. We hope this makes
-
Our manual now uses
`reStructuredText`
instead of
`LaTeX`
. We hope this makes
extending the manual easier and lowers the barrier to entry for new
extending the manual easier and lowers the barrier to entry for new
contributors.
contributors.
-
A
`stateful_actor`
now forwards excess arguments to the
`State`
rather than to
the
`Base`
. This enables states with non-default constructors. When using
`stateful_actor<State>`
as pointer type in function-based actors, nothing
changes (i.e. the new API is backwards compatible for this case). However,
calling
`spawn<stateful_actor<State>>(xs...)`
now initializes the
`State`
with
the argument pack
`xs...`
(plus optionally a
`self`
pointer as first
argument). Furthermore, the state class can now provide a
`make_behavior`
member function to initialize the actor (this has no effect for function-based
actors).
### Removed
### Removed
...
...
examples/message_passing/fan_out_request.cpp
View file @
d19ca0d6
...
@@ -16,7 +16,6 @@
...
@@ -16,7 +16,6 @@
#include "caf/function_view.hpp"
#include "caf/function_view.hpp"
#include "caf/policy/select_all.hpp"
#include "caf/policy/select_all.hpp"
#include "caf/scoped_actor.hpp"
#include "caf/scoped_actor.hpp"
#include "caf/stateful_actor.hpp"
#include "caf/typed_actor.hpp"
#include "caf/typed_actor.hpp"
#include "caf/typed_event_based_actor.hpp"
#include "caf/typed_event_based_actor.hpp"
...
...
libcaf_core/caf/composable_behavior_based_actor.hpp
View file @
d19ca0d6
...
@@ -33,7 +33,9 @@ public:
...
@@ -33,7 +33,9 @@ public:
using
super
=
stateful_actor
<
State
,
Base
>
;
using
super
=
stateful_actor
<
State
,
Base
>
;
composable_behavior_based_actor
(
actor_config
&
cfg
)
:
super
(
cfg
)
{
template
<
class
...
Ts
>
explicit
composable_behavior_based_actor
(
actor_config
&
cfg
,
Ts
&&
...
xs
)
:
super
(
cfg
,
std
::
forward
<
Ts
>
(
xs
)...)
{
// nop
// nop
}
}
...
...
libcaf_core/caf/detail/type_traits.hpp
View file @
d19ca0d6
...
@@ -437,6 +437,7 @@ public:
...
@@ -437,6 +437,7 @@ public:
CAF_HAS_MEMBER_TRAIT
(
size
);
CAF_HAS_MEMBER_TRAIT
(
size
);
CAF_HAS_MEMBER_TRAIT
(
data
);
CAF_HAS_MEMBER_TRAIT
(
data
);
CAF_HAS_MEMBER_TRAIT
(
make_behavior
);
/// Checks whether F is convertible to either `std::function<void (T&)>`
/// Checks whether F is convertible to either `std::function<void (T&)>`
/// or `std::function<void (const T&)>`.
/// or `std::function<void (const T&)>`.
...
...
libcaf_core/caf/infer_handle.hpp
View file @
d19ca0d6
...
@@ -21,7 +21,6 @@
...
@@ -21,7 +21,6 @@
#include "caf/abstract_composable_behavior.hpp"
#include "caf/abstract_composable_behavior.hpp"
#include "caf/actor.hpp"
#include "caf/actor.hpp"
#include "caf/actor_addr.hpp"
#include "caf/actor_addr.hpp"
#include "caf/stateful_actor.hpp"
#include "caf/typed_behavior.hpp"
#include "caf/typed_behavior.hpp"
namespace
caf
{
namespace
caf
{
...
...
libcaf_core/caf/stateful_actor.hpp
View file @
d19ca0d6
...
@@ -24,88 +24,89 @@
...
@@ -24,88 +24,89 @@
#include "caf/fwd.hpp"
#include "caf/fwd.hpp"
#include "caf/sec.hpp"
#include "caf/sec.hpp"
#include "caf/logger.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/detail/type_traits.hpp"
namespace
caf
{
namespace
caf
::
detail
{
/// An event-based actor with managed state. The state is constructed
/// Conditional base type for `stateful_actor` that overrides `make_behavior` if
/// before `make_behavior` will get called and destroyed after the
/// `State::make_behavior()` exists.
/// actor called `quit`. This state management brakes cycles and
template
<
class
State
,
class
Base
>
/// allows actors to automatically release resources as soon
class
stateful_actor_base
:
public
Base
{
/// as possible.
template
<
class
State
,
class
Base
/* = event_based_actor (see fwd.hpp) */
>
class
stateful_actor
:
public
Base
{
public:
public:
template
<
class
...
Ts
>
using
Base
::
Base
;
explicit
stateful_actor
(
actor_config
&
cfg
,
Ts
&&
...
xs
)
:
Base
(
cfg
,
std
::
forward
<
Ts
>
(
xs
)...),
state
(
state_
)
{
cr_state
(
this
);
}
~
stateful_actor
()
override
{
typename
Base
::
behavior_type
make_behavior
()
override
;
// nop
};
}
/// Destroys the state of this actor (no further overriding allowed).
void
on_exit
()
final
{
CAF_LOG_TRACE
(
""
);
state_
.
~
State
();
}
const
char
*
name
()
const
final
{
return
get_name
(
state_
);
}
/// A reference to the actor's state.
/// Evaluates to either `stateful_actor_base<State, Base> `or `Base`, depending
State
&
state
;
/// on whether `State::make_behavior()` exists.
template
<
class
State
,
class
Base
>
using
stateful_actor_base_t
=
std
::
conditional_t
<
has_make_behavior_member
<
State
>::
value
,
stateful_actor_base
<
State
,
Base
>
,
Base
>
;
/// @cond PRIVATE
}
// namespace caf::detail
void
initialize
()
override
{
namespace
caf
{
Base
::
initialize
();
}
/// @endcond
private:
/// An event-based actor with managed state. The state is constructed with the
template
<
class
T
>
/// actor, but destroyed when the actor calls `quit`. This state management
typename
std
::
enable_if
<
std
::
is_constructible
<
State
,
T
>::
value
>::
type
/// brakes cycles and allows actors to automatically release resources as soon
cr_state
(
T
arg
)
{
/// as possible.
new
(
&
state_
)
State
(
arg
);
template
<
class
State
,
class
Base
/* = event_based_actor (see fwd.hpp) */
>
}
class
stateful_actor
:
public
detail
::
stateful_actor_base_t
<
State
,
Base
>
{
public:
using
super
=
detail
::
stateful_actor_base_t
<
State
,
Base
>
;
template
<
class
T
>
template
<
class
...
Ts
>
typename
std
::
enable_if
<!
std
::
is_constructible
<
State
,
T
>::
value
>::
type
explicit
stateful_actor
(
actor_config
&
cfg
,
Ts
&&
...
xs
)
:
super
(
cfg
)
{
cr_state
(
T
)
{
using
pointer
=
stateful_actor
*
;
new
(
&
state_
)
State
();
if
constexpr
(
std
::
is_constructible
<
State
,
pointer
,
Ts
&&
...
>::
value
)
{
new
(
&
state
)
State
(
this
,
std
::
forward
<
Ts
>
(
xs
)...);
}
else
{
new
(
&
state
)
State
(
std
::
forward
<
Ts
>
(
xs
)...);
}
}
static
const
char
*
unbox_str
(
const
char
*
str
)
{
return
str
;
}
}
template
<
class
U
>
~
stateful_actor
()
override
{
static
const
char
*
unbox_str
(
const
U
&
str
)
{
// nop
return
str
.
c_str
();
}
}
template
<
class
U
>
/// @copydoc local_actor::on_exit
typename
std
::
enable_if
<
detail
::
has_name
<
U
>::
value
,
const
char
*>::
type
/// @note when overriding this member function, make sure to call
get_name
(
const
U
&
st
)
const
{
/// `super::on_exit()` in order to clean up the state.
return
unbox_str
(
st
.
name
);
void
on_exit
()
override
{
state
.
~
State
();
}
}
template
<
class
U
>
const
char
*
name
()
const
override
{
typename
std
::
enable_if
<!
detail
::
has_name
<
U
>::
value
,
const
char
*>::
type
if
constexpr
(
detail
::
has_name
<
State
>::
value
)
{
get_name
(
const
U
&
)
const
{
if
constexpr
(
std
::
is_convertible
<
decltype
(
state
.
name
),
const
char
*>::
value
)
return
state
.
name
;
else
return
state
.
name
.
c_str
();
}
else
{
return
Base
::
name
();
return
Base
::
name
();
}
}
}
union
{
union
{
State
state_
;
/// The actor's state. This member lives inside a union since its lifetime
/// ends when the actor terminates while the actual actor object lives until
/// its reference count drops to zero.
State
state
;
};
};
};
};
}
// namespace caf
}
// namespace caf
namespace
caf
::
detail
{
template
<
class
State
,
class
Base
>
typename
Base
::
behavior_type
stateful_actor_base
<
State
,
Base
>::
make_behavior
()
{
auto
dptr
=
static_cast
<
stateful_actor
<
State
,
Base
>*>
(
this
);
return
dptr
->
state
.
make_behavior
();
}
}
// namespace caf::detail
libcaf_core/caf/type_nr.hpp
View file @
d19ca0d6
...
@@ -36,6 +36,12 @@
...
@@ -36,6 +36,12 @@
#define CAF_MSG_TYPE_ADD_ATOM(name) \
#define CAF_MSG_TYPE_ADD_ATOM(name) \
struct name {}; \
struct name {}; \
[[maybe_unused]] constexpr bool operator==(name, name) { \
return true; \
} \
[[maybe_unused]] constexpr bool operator!=(name, name) { \
return false; \
} \
template <class Inspector> \
template <class Inspector> \
auto inspect(Inspector& f, name&) { \
auto inspect(Inspector& f, name&) { \
return f(meta::type_name("caf::" #name)); \
return f(meta::type_name("caf::" #name)); \
...
...
libcaf_core/src/actor_registry.cpp
View file @
d19ca0d6
...
@@ -31,7 +31,6 @@
...
@@ -31,7 +31,6 @@
#include "caf/exit_reason.hpp"
#include "caf/exit_reason.hpp"
#include "caf/actor_system.hpp"
#include "caf/actor_system.hpp"
#include "caf/scoped_actor.hpp"
#include "caf/scoped_actor.hpp"
#include "caf/stateful_actor.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/uniform_type_info_map.hpp"
#include "caf/uniform_type_info_map.hpp"
...
...
libcaf_core/src/actor_system.cpp
View file @
d19ca0d6
...
@@ -32,6 +32,7 @@
...
@@ -32,6 +32,7 @@
#include "caf/scheduler/coordinator.hpp"
#include "caf/scheduler/coordinator.hpp"
#include "caf/scheduler/test_coordinator.hpp"
#include "caf/scheduler/test_coordinator.hpp"
#include "caf/send.hpp"
#include "caf/send.hpp"
#include "caf/stateful_actor.hpp"
#include "caf/to_string.hpp"
#include "caf/to_string.hpp"
namespace
caf
{
namespace
caf
{
...
...
libcaf_core/test/stateful_actor.cpp
View file @
d19ca0d6
...
@@ -16,18 +16,18 @@
...
@@ -16,18 +16,18 @@
* http://www.boost.org/LICENSE_1_0.txt. *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
******************************************************************************/
#include "caf/config.hpp"
#define CAF_SUITE stateful_actor
#define CAF_SUITE stateful_actor
#include "caf/test/unit_test.hpp"
#include "caf/all.hpp"
#include "caf/stateful_actor.hpp"
#include "caf/test/dsl.hpp"
#
define ERROR_HANDLER [&](error& err) { CAF_FAIL(system.render(err)); }
#
include "caf/event_based_actor.hpp"
using
namespace
std
;
using
namespace
caf
;
using
namespace
caf
;
using
namespace
std
::
string_literals
;
namespace
{
namespace
{
using
typed_adder_actor
using
typed_adder_actor
...
@@ -35,7 +35,6 @@ using typed_adder_actor
...
@@ -35,7 +35,6 @@ using typed_adder_actor
struct
counter
{
struct
counter
{
int
value
=
0
;
int
value
=
0
;
local_actor
*
self_
;
};
};
behavior
adder
(
stateful_actor
<
counter
>*
self
)
{
behavior
adder
(
stateful_actor
<
counter
>*
self
)
{
...
@@ -77,36 +76,32 @@ public:
...
@@ -77,36 +76,32 @@ public:
}
}
};
};
struct
fixture
{
struct
fixture
:
test_coordinator_fixture
<>
{
actor_system_config
cfg
;
fixture
()
{
actor_system
system
;
fixture
()
:
system
(
cfg
)
{
// nop
// nop
}
}
template
<
class
ActorUnderTest
>
template
<
class
ActorUnderTest
>
void
test_adder
(
ActorUnderTest
aut
)
{
void
test_adder
(
ActorUnderTest
aut
)
{
scoped_actor
self
{
system
};
inject
((
add_atom
,
int
),
from
(
self
).
to
(
aut
).
with
(
add_atom_v
,
7
));
self
->
send
(
aut
,
add_atom_v
,
7
);
inject
((
add_atom
,
int
),
from
(
self
).
to
(
aut
).
with
(
add_atom_v
,
4
));
self
->
send
(
aut
,
add_atom_v
,
4
);
inject
((
add_atom
,
int
),
from
(
self
).
to
(
aut
).
with
(
add_atom_v
,
9
));
self
->
send
(
aut
,
add_atom_v
,
9
);
inject
((
get_atom
),
from
(
self
).
to
(
aut
).
with
(
get_atom_v
));
self
->
request
(
aut
,
infinite
,
get_atom_v
)
expect
((
int
),
from
(
aut
).
to
(
self
).
with
(
20
));
.
receive
([](
int
x
)
{
CAF_CHECK_EQUAL
(
x
,
20
);
},
ERROR_HANDLER
);
}
}
template
<
class
State
>
template
<
class
State
>
void
test_name
(
const
char
*
expected
)
{
void
test_name
(
const
char
*
expected
)
{
auto
aut
=
system
.
spawn
([](
stateful_actor
<
State
>*
self
)
->
behavior
{
auto
aut
=
sys
.
spawn
([](
stateful_actor
<
State
>*
self
)
->
behavior
{
return
[
=
](
get_atom
)
{
return
{
[
=
](
get_atom
)
{
self
->
quit
();
self
->
quit
();
return
self
->
name
();
return
self
->
name
();
},
};
};
});
});
scoped_actor
self
{
system
};
inject
((
get_atom
),
from
(
self
).
to
(
aut
).
with
(
get_atom_v
));
self
->
request
(
aut
,
infinite
,
get_atom_v
)
expect
((
std
::
string
),
from
(
aut
).
to
(
self
).
with
(
expected
));
.
receive
([
&
](
const
string
&
str
)
{
CAF_CHECK_EQUAL
(
str
,
expected
);
},
ERROR_HANDLER
);
}
}
};
};
...
@@ -114,42 +109,84 @@ struct fixture {
...
@@ -114,42 +109,84 @@ struct fixture {
CAF_TEST_FIXTURE_SCOPE
(
dynamic_stateful_actor_tests
,
fixture
)
CAF_TEST_FIXTURE_SCOPE
(
dynamic_stateful_actor_tests
,
fixture
)
CAF_TEST
(
dynamic_stateful_actor
)
{
CAF_TEST
(
stateful
actors
can
be
dynamically
typed
)
{
CAF_REQUIRE
(
monitored
+
monitored
==
monitored
);
test_adder
(
sys
.
spawn
(
adder
));
test_adder
(
system
.
spawn
(
adder
));
test_adder
(
sys
.
spawn
<
typed_adder_class
>
());
}
CAF_TEST
(
typed_stateful_actor
)
{
test_adder
(
system
.
spawn
(
typed_adder
));
}
}
CAF_TEST
(
dynamic_stateful_actor_class
)
{
CAF_TEST
(
stateful
actors
can
be
statically
typed
)
{
test_adder
(
system
.
spawn
<
adder_class
>
());
test_adder
(
sys
.
spawn
(
typed_adder
));
test_adder
(
sys
.
spawn
<
adder_class
>
());
}
}
CAF_TEST
(
typed_stateful_actor_class
)
{
CAF_TEST
(
stateful
actors
without
explicit
name
use
the
name
of
the
parent
)
{
test_adder
(
system
.
spawn
<
typed_adder_class
>
());
}
CAF_TEST
(
no_name
)
{
struct
state
{
struct
state
{
// empty
// empty
};
};
test_name
<
state
>
(
"scheduled_actor"
);
test_name
<
state
>
(
"scheduled_actor"
);
}
}
CAF_TEST
(
char_
name
)
{
CAF_TEST
(
states
with
C
string
names
override
the
default
name
)
{
struct
state
{
struct
state
{
const
char
*
name
=
"testee"
;
const
char
*
name
=
"testee"
;
};
};
test_name
<
state
>
(
"testee"
);
test_name
<
state
>
(
"testee"
);
}
}
CAF_TEST
(
st
ring_
name
)
{
CAF_TEST
(
st
ates
with
STL
string
names
override
the
default
name
)
{
struct
state
{
struct
state
{
string
name
=
"testee2"
;
st
d
::
st
ring
name
=
"testee2"
;
};
};
test_name
<
state
>
(
"testee2"
);
test_name
<
state
>
(
"testee2"
);
}
}
CAF_TEST
(
states
can
accept
constructor
arguments
and
provide
a
behavior
)
{
struct
state_type
{
int
x
;
int
y
;
state_type
(
int
x
,
int
y
)
:
x
(
x
),
y
(
y
)
{
// nop
}
behavior
make_behavior
()
{
return
{
[
=
](
int
x
,
int
y
)
{
this
->
x
=
x
;
this
->
y
=
y
;
},
};
}
};
using
actor_type
=
stateful_actor
<
state_type
>
;
auto
testee
=
sys
.
spawn
<
actor_type
>
(
10
,
20
);
auto
&
state
=
deref
<
actor_type
>
(
testee
).
state
;
CAF_CHECK_EQUAL
(
state
.
x
,
10
);
CAF_CHECK_EQUAL
(
state
.
y
,
20
);
inject
((
int
,
int
),
to
(
testee
).
with
(
1
,
2
));
CAF_CHECK_EQUAL
(
state
.
x
,
1
);
CAF_CHECK_EQUAL
(
state
.
y
,
2
);
}
CAF_TEST
(
states
optionally
take
the
self
pointer
as
first
argument
)
{
struct
state_type
{
event_based_actor
*
self
;
int
x
;
const
char
*
name
=
"testee"
;
state_type
(
event_based_actor
*
self
,
int
x
)
:
self
(
self
),
x
(
x
)
{
// nop
}
behavior
make_behavior
()
{
return
{
[
=
](
get_atom
)
{
return
self
->
name
();
},
};
}
};
using
actor_type
=
stateful_actor
<
state_type
>
;
auto
testee
=
sys
.
spawn
<
actor_type
>
(
10
);
auto
&
state
=
deref
<
actor_type
>
(
testee
).
state
;
CAF_CHECK
(
state
.
self
==
&
deref
<
actor_type
>
(
testee
));
CAF_CHECK_EQUAL
(
state
.
x
,
10
);
inject
((
get_atom
),
from
(
self
).
to
(
testee
).
with
(
get_atom_v
));
expect
((
std
::
string
),
from
(
testee
).
to
(
self
).
with
(
"testee"
s
));
}
CAF_TEST_FIXTURE_SCOPE_END
()
CAF_TEST_FIXTURE_SCOPE_END
()
libcaf_test/caf/test/dsl.hpp
View file @
d19ca0d6
...
@@ -458,10 +458,11 @@ public:
...
@@ -458,10 +458,11 @@ public:
}
}
void
with
(
Ts
...
xs
)
{
void
with
(
Ts
...
xs
)
{
if
(
src_
==
nullptr
)
CAF_FAIL
(
"missing .from() in inject() statement"
);
if
(
dest_
==
nullptr
)
if
(
dest_
==
nullptr
)
CAF_FAIL
(
"missing .to() in inject() statement"
);
CAF_FAIL
(
"missing .to() in inject() statement"
);
if
(
src_
==
nullptr
)
caf
::
anon_send
(
caf
::
actor_cast
<
caf
::
actor
>
(
dest_
),
xs
...);
else
caf
::
send_as
(
caf
::
actor_cast
<
caf
::
actor
>
(
src_
),
caf
::
send_as
(
caf
::
actor_cast
<
caf
::
actor
>
(
src_
),
caf
::
actor_cast
<
caf
::
actor
>
(
dest_
),
xs
...);
caf
::
actor_cast
<
caf
::
actor
>
(
dest_
),
xs
...);
CAF_REQUIRE
(
sched_
.
prioritize
(
dest_
));
CAF_REQUIRE
(
sched_
.
prioritize
(
dest_
));
...
...
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