Unverified Commit 1b1aae99 authored by Joseph Noir's avatar Joseph Noir Committed by GitHub

Merge pull request #958

Provide uniform access to actor properties
parents d283fb2c 706d9c52
...@@ -18,41 +18,23 @@ ...@@ -18,41 +18,23 @@
#pragma once #pragma once
#include <string>
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <utility> #include <string>
#include <type_traits> #include <type_traits>
#include <utility>
#include "caf/config.hpp"
#include "caf/fwd.hpp"
#include "caf/message.hpp"
#include "caf/actor_marker.hpp"
#include "caf/abstract_actor.hpp" #include "caf/abstract_actor.hpp"
#include "caf/actor_control_block.hpp" #include "caf/actor_control_block.hpp"
#include "caf/actor_traits.hpp"
#include "caf/config.hpp"
#include "caf/detail/comparable.hpp" #include "caf/detail/comparable.hpp"
#include "caf/detail/type_traits.hpp" #include "caf/detail/type_traits.hpp"
#include "caf/fwd.hpp"
#include "caf/message.hpp"
namespace caf { namespace caf {
template <class T>
struct is_convertible_to_actor {
static constexpr bool value =
!std::is_base_of<statically_typed_actor_base, T>::value
&& (std::is_base_of<actor_proxy, T>::value
|| std::is_base_of<local_actor, T>::value);
};
template <>
struct is_convertible_to_actor<scoped_actor> : std::true_type {
// nop
};
template <class T>
struct is_convertible_to_actor<T*> : is_convertible_to_actor<T> {};
/// Identifies an untyped actor. Can be used with derived types /// Identifies an untyped actor. Can be used with derived types
/// of `event_based_actor`, `blocking_actor`, and `actor_proxy`. /// of `event_based_actor`, `blocking_actor`, and `actor_proxy`.
class actor : detail::comparable<actor>, class actor : detail::comparable<actor>,
...@@ -82,24 +64,22 @@ public: ...@@ -82,24 +64,22 @@ public:
actor(const scoped_actor&); actor(const scoped_actor&);
template <class T, template <class T,
class = typename std::enable_if< class = detail::enable_if_t<actor_traits<T>::is_dynamically_typed>>
std::is_base_of<dynamically_typed_actor_base, T>::value
>::type>
actor(T* ptr) : ptr_(ptr->ctrl()) { actor(T* ptr) : ptr_(ptr->ctrl()) {
CAF_ASSERT(ptr != nullptr); CAF_ASSERT(ptr != nullptr);
} }
template <class T> template <class T,
typename std::enable_if<is_convertible_to_actor<T>::value, actor&>::type class = detail::enable_if_t<actor_traits<T>::is_dynamically_typed>>
operator=(intrusive_ptr<T> ptr) { actor& operator=(intrusive_ptr<T> ptr) {
actor tmp{std::move(ptr)}; actor tmp{std::move(ptr)};
swap(tmp); swap(tmp);
return *this; return *this;
} }
template <class T> template <class T,
typename std::enable_if<is_convertible_to_actor<T>::value, actor&>::type class = detail::enable_if_t<actor_traits<T>::is_dynamically_typed>>
operator=(T* ptr) { actor& operator=(T* ptr) {
actor tmp{ptr}; actor tmp{ptr};
swap(tmp); swap(tmp);
return *this; return *this;
......
...@@ -32,9 +32,9 @@ ...@@ -32,9 +32,9 @@
#include "caf/actor_cast.hpp" #include "caf/actor_cast.hpp"
#include "caf/actor_clock.hpp" #include "caf/actor_clock.hpp"
#include "caf/actor_config.hpp" #include "caf/actor_config.hpp"
#include "caf/actor_marker.hpp"
#include "caf/actor_profiler.hpp" #include "caf/actor_profiler.hpp"
#include "caf/actor_registry.hpp" #include "caf/actor_registry.hpp"
#include "caf/actor_traits.hpp"
#include "caf/composable_behavior_based_actor.hpp" #include "caf/composable_behavior_based_actor.hpp"
#include "caf/detail/init_fun_factory.hpp" #include "caf/detail/init_fun_factory.hpp"
#include "caf/detail/spawn_fwd.hpp" #include "caf/detail/spawn_fwd.hpp"
...@@ -412,13 +412,13 @@ public: ...@@ -412,13 +412,13 @@ public:
F& fun, Ts&&... xs) { F& fun, Ts&&... xs) {
using impl = infer_impl_from_fun_t<F>; using impl = infer_impl_from_fun_t<F>;
check_invariants<impl>(); check_invariants<impl>();
static constexpr bool dynamically_typed = is_dynamically_typed<impl>::value; using traits = actor_traits<impl>;
static_assert(dynamically_typed, static_assert(traits::is_dynamically_typed,
"only dynamically-typed actors can join groups"); "only dynamically-typed actors can join groups");
static constexpr bool spawnable = detail::spawnable<F, impl, Ts...>(); static constexpr bool spawnable = detail::spawnable<F, impl, Ts...>();
static_assert(spawnable, static_assert(spawnable,
"cannot spawn function-based actor with given arguments"); "cannot spawn function-based actor with given arguments");
static constexpr bool enabled = dynamically_typed && spawnable; static constexpr bool enabled = traits::is_dynamically_typed && spawnable;
auto irange = make_input_range(first, second); auto irange = make_input_range(first, second);
cfg.groups = &irange; cfg.groups = &irange;
return spawn_functor<Os>(detail::bool_token<enabled>{}, cfg, fun, return spawn_functor<Os>(detail::bool_token<enabled>{}, cfg, fun,
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* | |___ / ___ \| _| Framework * * | |___ / ___ \| _| Framework *
* \____/_/ \_|_| * * \____/_/ \_|_| *
* * * *
* Copyright 2011-2018 Dominik Charousset * * Copyright 2011-2019 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,33 +18,84 @@ ...@@ -18,33 +18,84 @@
#pragma once #pragma once
#include <type_traits>
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
namespace caf { namespace caf {
class statically_typed_actor_base { // Note: having marker types for blocking and non-blocking may seem redundant,
// used as marker only // because an actor is either the one or the other. However, we cannot conclude
}; // that an actor is non-blocking if it does not have the blocking marker. Actor
// types such as `local_actor` have neither markers, because they are
// "incomplete", i.e., they serve as base type for both blocking and
// non-blocking actors. Hence, we need both markers even though they are
// mutually exclusive. The same reasoning applies to the dynamically vs.
// statically typed markers.
class dynamically_typed_actor_base { /// Marker type for dynamically typed actors.
// used as marker only struct dynamically_typed_actor_base {};
};
template <class T> /// Marker type for statically typed actors.
struct actor_marker { struct statically_typed_actor_base {};
using type = statically_typed_actor_base;
}; /// Marker type for blocking actors.
struct blocking_actor_base {};
/// Marker type for non-blocking actors.
struct non_blocking_actor_base {};
/// Default implementation of `actor_traits` for non-actors (SFINAE-friendly).
/// @relates actor_traits
template <class T, bool ExtendsAbstractActor>
struct default_actor_traits {
static constexpr bool is_dynamically_typed = false;
static constexpr bool is_statically_typed = false;
static constexpr bool is_blocking = false;
template <> static constexpr bool is_non_blocking = false;
struct actor_marker<behavior> {
using type = dynamically_typed_actor_base; static constexpr bool is_incomplete = true;
}; };
/// Default implementation of `actor_traits` for regular actors.
/// @relates actor_traits
template <class T> template <class T>
using is_statically_typed = std::is_base_of<statically_typed_actor_base, T>; struct default_actor_traits<T, true> {
/// Denotes whether `T` is dynamically typed.
static constexpr bool is_dynamically_typed = //
std::is_base_of<dynamically_typed_actor_base, T>::value;
/// Denotes whether `T` is statically typed.
static constexpr bool is_statically_typed = //
std::is_base_of<statically_typed_actor_base, T>::value;
/// Denotes whether `T` is a blocking actor type.
static constexpr bool is_blocking = //
std::is_base_of<blocking_actor_base, T>::value;
/// Denotes whether `T` is a non-blocking actor type.
static constexpr bool is_non_blocking = //
std::is_base_of<non_blocking_actor_base, T>::value;
/// Denotes whether `T` is an incomplete actor type that misses one or more
/// markers.
static constexpr bool is_incomplete = //
(!is_dynamically_typed && !is_statically_typed)
|| (!is_blocking && !is_non_blocking);
static_assert(!is_dynamically_typed || !is_statically_typed,
"an actor cannot be both statically and dynamically typed");
static_assert(!is_blocking || !is_non_blocking,
"an actor cannot be both blocking and non-blocking");
};
/// Provides uniform access to properties of actor types.
template <class T> template <class T>
using is_dynamically_typed = std::is_base_of<dynamically_typed_actor_base, T>; struct actor_traits
: default_actor_traits<T, std::is_base_of<abstract_actor, T>::value> {};
} // namespace caf } // namespace caf
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "caf/actor_proxy.hpp" #include "caf/actor_proxy.hpp"
#include "caf/actor_system.hpp" #include "caf/actor_system.hpp"
#include "caf/actor_system_config.hpp" #include "caf/actor_system_config.hpp"
#include "caf/actor_traits.hpp"
#include "caf/after.hpp" #include "caf/after.hpp"
#include "caf/atom.hpp" #include "caf/atom.hpp"
#include "caf/attach_continuous_stream_source.hpp" #include "caf/attach_continuous_stream_source.hpp"
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include <condition_variable> #include <condition_variable>
#include "caf/actor_config.hpp" #include "caf/actor_config.hpp"
#include "caf/actor_marker.hpp" #include "caf/actor_traits.hpp"
#include "caf/after.hpp" #include "caf/after.hpp"
#include "caf/behavior.hpp" #include "caf/behavior.hpp"
#include "caf/extend.hpp" #include "caf/extend.hpp"
...@@ -72,11 +72,14 @@ namespace caf { ...@@ -72,11 +72,14 @@ namespace caf {
/// receive rather than a behavior-stack based message processing. /// receive rather than a behavior-stack based message processing.
/// @extends local_actor /// @extends local_actor
class blocking_actor class blocking_actor
: public extend<local_actor, blocking_actor>:: // clang-format off
with<mixin::requester, : public extend<local_actor, blocking_actor>::
mixin::sender, with<mixin::requester,
mixin::subscriber>, mixin::sender,
public dynamically_typed_actor_base { mixin::subscriber>,
public dynamically_typed_actor_base,
public blocking_actor_base {
// clang-format on
public: public:
// -- nested and member types ------------------------------------------------ // -- nested and member types ------------------------------------------------
......
...@@ -21,8 +21,8 @@ ...@@ -21,8 +21,8 @@
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include "caf/actor_traits.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/actor_marker.hpp"
#include "caf/detail/type_list.hpp" #include "caf/detail/type_list.hpp"
#include "caf/detail/type_traits.hpp" #include "caf/detail/type_traits.hpp"
......
...@@ -29,11 +29,8 @@ namespace detail { ...@@ -29,11 +29,8 @@ namespace detail {
/// Converts `scoped_actor` and pointers to actors to handles of type `actor` /// Converts `scoped_actor` and pointers to actors to handles of type `actor`
/// but simply forwards any other argument in the same way `std::forward` does. /// but simply forwards any other argument in the same way `std::forward` does.
template <class T> template <class T>
typename std::conditional< typename std::conditional<std::is_convertible<T, actor>::value, actor,
is_convertible_to_actor<typename std::decay<T>::type>::value, T&&>::type
actor,
T&&
>::type
spawn_fwd(typename std::remove_reference<T>::type& arg) noexcept { spawn_fwd(typename std::remove_reference<T>::type& arg) noexcept {
return static_cast<T&&>(arg); return static_cast<T&&>(arg);
} }
...@@ -41,11 +38,8 @@ spawn_fwd(typename std::remove_reference<T>::type& arg) noexcept { ...@@ -41,11 +38,8 @@ spawn_fwd(typename std::remove_reference<T>::type& arg) noexcept {
/// Converts `scoped_actor` and pointers to actors to handles of type `actor` /// Converts `scoped_actor` and pointers to actors to handles of type `actor`
/// but simply forwards any other argument in the same way `std::forward` does. /// but simply forwards any other argument in the same way `std::forward` does.
template <class T> template <class T>
typename std::conditional< typename std::conditional<std::is_convertible<T, actor>::value, actor,
is_convertible_to_actor<typename std::decay<T>::type>::value, T&&>::type
actor,
T&&
>::type
spawn_fwd(typename std::remove_reference<T>::type&& arg) noexcept { spawn_fwd(typename std::remove_reference<T>::type&& arg) noexcept {
static_assert(!std::is_lvalue_reference<T>::value, static_assert(!std::is_lvalue_reference<T>::value,
"silently converting an lvalue to an rvalue"); "silently converting an lvalue to an rvalue");
......
...@@ -20,10 +20,10 @@ ...@@ -20,10 +20,10 @@
#include <type_traits> #include <type_traits>
#include "caf/fwd.hpp" #include "caf/actor_traits.hpp"
#include "caf/extend.hpp" #include "caf/extend.hpp"
#include "caf/fwd.hpp"
#include "caf/local_actor.hpp" #include "caf/local_actor.hpp"
#include "caf/actor_marker.hpp"
#include "caf/response_handle.hpp" #include "caf/response_handle.hpp"
#include "caf/scheduled_actor.hpp" #include "caf/scheduled_actor.hpp"
......
...@@ -19,17 +19,10 @@ ...@@ -19,17 +19,10 @@
#pragma once #pragma once
#include <type_traits> #include <type_traits>
#include <utility>
#include "caf/fwd.hpp"
#include "caf/message_id.hpp"
#include "caf/local_actor.hpp"
#include "caf/actor_marker.hpp"
#include "caf/typed_behavior.hpp"
#include "caf/behavior_policy.hpp" #include "caf/behavior_policy.hpp"
#include "caf/response_handle.hpp" #include "caf/fwd.hpp"
#include "caf/mixin/sender.hpp"
#include "caf/mixin/requester.hpp"
namespace caf { namespace caf {
namespace mixin { namespace mixin {
...@@ -64,19 +57,16 @@ public: ...@@ -64,19 +57,16 @@ public:
template <class T0, class T1, class... Ts> template <class T0, class T1, class... Ts>
typename std::enable_if< typename std::enable_if<
!std::is_same<keep_behavior_t, typename std::decay<T0>::type>::value !std::is_same<keep_behavior_t, typename std::decay<T0>::type>::value>::type
>::type
become(T0&& x0, T1&& x1, Ts&&... xs) { become(T0&& x0, T1&& x1, Ts&&... xs) {
behavior_type bhvr{std::forward<T0>(x0), behavior_type bhvr{std::forward<T0>(x0), std::forward<T1>(x1),
std::forward<T1>(x1),
std::forward<Ts>(xs)...}; std::forward<Ts>(xs)...};
dptr()->do_become(std::move(bhvr.unbox()), true); dptr()->do_become(std::move(bhvr.unbox()), true);
} }
template <class T0, class T1, class... Ts> template <class T0, class T1, class... Ts>
void become(const keep_behavior_t&, T0&& x0, T1&& x1, Ts&&... xs) { void become(const keep_behavior_t&, T0&& x0, T1&& x1, Ts&&... xs) {
behavior_type bhvr{std::forward<T0>(x0), behavior_type bhvr{std::forward<T0>(x0), std::forward<T1>(x1),
std::forward<T1>(x1),
std::forward<Ts>(xs)...}; std::forward<Ts>(xs)...};
dptr()->do_become(std::move(bhvr.unbox()), false); dptr()->do_become(std::move(bhvr.unbox()), false);
} }
...@@ -93,4 +83,3 @@ private: ...@@ -93,4 +83,3 @@ private:
} // namespace mixin } // namespace mixin
} // namespace caf } // namespace caf
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
#include <type_traits> #include <type_traits>
#include <unordered_map> #include <unordered_map>
#include "caf/actor_marker.hpp" #include "caf/actor_traits.hpp"
#include "caf/broadcast_downstream_manager.hpp" #include "caf/broadcast_downstream_manager.hpp"
#include "caf/default_downstream_manager.hpp" #include "caf/default_downstream_manager.hpp"
#include "caf/error.hpp" #include "caf/error.hpp"
...@@ -106,7 +106,9 @@ result<message> drop(scheduled_actor*, message_view&); ...@@ -106,7 +106,9 @@ result<message> drop(scheduled_actor*, message_view&);
/// A cooperatively scheduled, event-based actor implementation. /// A cooperatively scheduled, event-based actor implementation.
/// @extends local_actor /// @extends local_actor
class scheduled_actor : public local_actor, public resumable { class scheduled_actor : public local_actor,
public resumable,
public non_blocking_actor_base {
public: public:
// -- nested enums ----------------------------------------------------------- // -- nested enums -----------------------------------------------------------
......
...@@ -18,12 +18,11 @@ ...@@ -18,12 +18,11 @@
#pragma once #pragma once
#include "caf/none.hpp"
#include "caf/actor_cast.hpp" #include "caf/actor_cast.hpp"
#include "caf/actor_system.hpp"
#include "caf/actor_storage.hpp" #include "caf/actor_storage.hpp"
#include "caf/intrusive_ptr.hpp" #include "caf/actor_system.hpp"
#include "caf/blocking_actor.hpp" #include "caf/blocking_actor.hpp"
#include "caf/none.hpp"
#include "caf/scoped_execution_unit.hpp" #include "caf/scoped_execution_unit.hpp"
namespace caf { namespace caf {
...@@ -83,7 +82,7 @@ private: ...@@ -83,7 +82,7 @@ private:
strong_actor_ptr self_; strong_actor_ptr self_;
}; };
/// @relates scoped_actor
std::string to_string(const scoped_actor& x); std::string to_string(const scoped_actor& x);
} // namespace caf } // namespace caf
...@@ -141,16 +141,11 @@ class typed_actor : detail::comparable<typed_actor<Sigs...>>, ...@@ -141,16 +141,11 @@ class typed_actor : detail::comparable<typed_actor<Sigs...>>,
} }
// allow `handle_type{this}` for typed actors // allow `handle_type{this}` for typed actors
template <class T> template <class T,
typed_actor(T* ptr, class = detail::enable_if_t<actor_traits<T>::is_statically_typed>>
typename std::enable_if< typed_actor(T* ptr) : ptr_(ptr->ctrl()) {
std::is_base_of<statically_typed_actor_base, T>::value static_assert(detail::tl_subset_of<signatures,
>::type* = 0) typename T::signatures>::value,
: ptr_(ptr->ctrl()) {
static_assert(detail::tl_subset_of<
signatures,
typename T::signatures
>::value,
"Cannot assign T* to incompatible handle type"); "Cannot assign T* to incompatible handle type");
CAF_ASSERT(ptr != nullptr); CAF_ASSERT(ptr != nullptr);
} }
......
...@@ -70,11 +70,14 @@ using accept_handler = typed_actor<reacts_to<new_connection_msg>, ...@@ -70,11 +70,14 @@ using accept_handler = typed_actor<reacts_to<new_connection_msg>,
/// components in the network. /// components in the network.
/// @extends local_actor /// @extends local_actor
template <class... Sigs> template <class... Sigs>
class typed_broker : public extend<abstract_broker, class typed_broker
typed_broker<Sigs...>>::template // clang-format off
with<mixin::sender, mixin::requester, : public extend<abstract_broker, typed_broker<Sigs...>>::template
mixin::behavior_changer>, with<mixin::sender,
public statically_typed_actor_base { mixin::requester,
mixin::behavior_changer>,
public statically_typed_actor_base {
// clang-format on
public: public:
using signatures = detail::type_list<Sigs...>; using signatures = detail::type_list<Sigs...>;
......
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