Commit 4d42b255 authored by Dominik Charousset's avatar Dominik Charousset

Implement stateful actors, relates #293

parent f4516192
......@@ -20,15 +20,55 @@
#ifndef CAF_EXPERIMENTAL_STATEFUL_ACTOR_HPP
#define CAF_EXPERIMENTAL_STATEFUL_ACTOR_HPP
#include "caf/event_based_actor.hpp"
#include <new>
#include <type_traits>
#include "caf/fwd.hpp"
namespace caf {
namespace experimental {
template <class State>
class stateful_actor : public event_based_actor {
template <class State, class Base = event_based_actor>
class stateful_actor : public Base {
public:
stateful_actor() {
// nop
}
~stateful_actor() {
// nop
}
void initialize() override {
cr_state(this);
Base::initialize();
}
void on_exit() override final {
state_.~State();
}
State& state() {
return state_;
}
private:
template <class T>
typename std::enable_if<std::is_constructible<State, T>::value>::type
cr_state(T arg) {
new (&state_) State(arg);
}
template <class T>
typename std::enable_if<! std::is_constructible<State, T>::value>::type
cr_state(T) {
new (&state_) State();
}
union { State state_; };
};
} // namespace experimental
} // namespace caf
#endif // CAF_EXPERIMENTAL_STATEFUL_ACTOR_HPP
......@@ -199,17 +199,23 @@ actor spawn_in_group(const group& grp, Ts&&... xs) {
/// Infers the appropriate base class for a functor-based typed actor
/// from the result and the first argument of the functor.
template <class Result, class FirstArg>
template <class Result,
class FirstArg,
bool FirstArgPtr = std::is_pointer<FirstArg>::value
&& std::is_base_of<
local_actor,
typename std::remove_pointer<FirstArg>::type
>::value>
struct infer_typed_actor_base;
template <class... Sigs, class FirstArg>
struct infer_typed_actor_base<typed_behavior<Sigs...>, FirstArg> {
struct infer_typed_actor_base<typed_behavior<Sigs...>, FirstArg, false> {
using type = typed_event_based_actor<Sigs...>;
};
template <class... Sigs>
struct infer_typed_actor_base<void, typed_event_based_actor<Sigs...>*> {
using type = typed_event_based_actor<Sigs...>;
template <class Result, class T>
struct infer_typed_actor_base<Result, T*, true> {
using type = T;
};
/// Returns a new typed actor of type `C` using `xs...` as
......
......@@ -29,6 +29,8 @@
#include "caf/typed_behavior.hpp"
#include "caf/typed_response_promise.hpp"
#include "caf/experimental/stateful_actor.hpp"
namespace caf {
class actor_addr;
......@@ -92,6 +94,14 @@ class typed_actor : detail::comparable<typed_actor<Sigs...>>,
/// Stores the template parameter pack.
using signatures = detail::type_list<Sigs...>;
/// Identifies the base class for this kind of actor with actor.
template <class State>
using stateful_base = experimental::stateful_actor<State, base>;
/// Identifies the base class for this kind of actor with actor.
template <class State>
using stateful_pointer = experimental::stateful_actor<State, base>*;
typed_actor() = default;
typed_actor(typed_actor&&) = default;
typed_actor(const typed_actor&) = default;
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2015 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/config.hpp"
#define CAF_SUITE stateful_actor
#include "caf/test/unit_test.hpp"
#include "caf/all.hpp"
#include "caf/experimental/stateful_actor.hpp"
using namespace std;
using namespace caf;
using namespace caf::experimental;
namespace {
using typed_adder_actor = typed_actor<reacts_to<add_atom, int>,
replies_to<get_atom>::with<int>>;
struct counter {
int value = 0;
local_actor* self_;
};
behavior adder(stateful_actor<counter>* self) {
return {
[=](add_atom, int x) {
self->state().value += x;
},
[=](get_atom) {
return self->state().value;
}
};
}
class adder_class : public stateful_actor<counter> {
public:
behavior make_behavior() override {
return adder(this);
}
};
typed_adder_actor::behavior_type
typed_adder(typed_adder_actor::stateful_pointer<counter> self) {
return {
[=](add_atom, int x) {
self->state().value += x;
},
[=](get_atom) {
return self->state().value;
}
};
}
class typed_adder_class : public typed_adder_actor::stateful_base<counter> {
public:
behavior_type make_behavior() override {
return typed_adder(this);
}
};
struct fixture {
~fixture() {
await_all_actors_done();
shutdown();
}
};
template <class ActorUnderTest>
void test_adder(ActorUnderTest aut) {
scoped_actor self;
self->send(aut, add_atom::value, 7);
self->send(aut, add_atom::value, 4);
self->send(aut, add_atom::value, 9);
self->sync_send(aut, get_atom::value).await(
[](int x) {
CAF_CHECK_EQUAL(x, 20);
}
);
anon_send_exit(aut, exit_reason::kill);
}
} // namespace <anonymous>
CAF_TEST_FIXTURE_SCOPE(dynamic_stateful_actor_tests, fixture)
CAF_TEST(dynamic_stateful_actor) {
test_adder(spawn(adder));
}
CAF_TEST(typed_stateful_actor) {
test_adder(spawn_typed(typed_adder));
}
CAF_TEST(dynamic_stateful_actor_class) {
test_adder(spawn<adder_class>());
}
CAF_TEST(typed_stateful_actor_class) {
test_adder(spawn_typed<typed_adder_class>());
}
CAF_TEST_FIXTURE_SCOPE_END()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment