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 @@
#pragma once
#include <string>
#include <cstddef>
#include <cstdint>
#include <utility>
#include <string>
#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/actor_control_block.hpp"
#include "caf/actor_traits.hpp"
#include "caf/config.hpp"
#include "caf/detail/comparable.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/fwd.hpp"
#include "caf/message.hpp"
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
/// of `event_based_actor`, `blocking_actor`, and `actor_proxy`.
class actor : detail::comparable<actor>,
......@@ -82,24 +64,22 @@ public:
actor(const scoped_actor&);
template <class T,
class = typename std::enable_if<
std::is_base_of<dynamically_typed_actor_base, T>::value
>::type>
class = detail::enable_if_t<actor_traits<T>::is_dynamically_typed>>
actor(T* ptr) : ptr_(ptr->ctrl()) {
CAF_ASSERT(ptr != nullptr);
}
template <class T>
typename std::enable_if<is_convertible_to_actor<T>::value, actor&>::type
operator=(intrusive_ptr<T> ptr) {
template <class T,
class = detail::enable_if_t<actor_traits<T>::is_dynamically_typed>>
actor& operator=(intrusive_ptr<T> ptr) {
actor tmp{std::move(ptr)};
swap(tmp);
return *this;
}
template <class T>
typename std::enable_if<is_convertible_to_actor<T>::value, actor&>::type
operator=(T* ptr) {
template <class T,
class = detail::enable_if_t<actor_traits<T>::is_dynamically_typed>>
actor& operator=(T* ptr) {
actor tmp{ptr};
swap(tmp);
return *this;
......
......@@ -32,9 +32,9 @@
#include "caf/actor_cast.hpp"
#include "caf/actor_clock.hpp"
#include "caf/actor_config.hpp"
#include "caf/actor_marker.hpp"
#include "caf/actor_profiler.hpp"
#include "caf/actor_registry.hpp"
#include "caf/actor_traits.hpp"
#include "caf/composable_behavior_based_actor.hpp"
#include "caf/detail/init_fun_factory.hpp"
#include "caf/detail/spawn_fwd.hpp"
......@@ -412,13 +412,13 @@ public:
F& fun, Ts&&... xs) {
using impl = infer_impl_from_fun_t<F>;
check_invariants<impl>();
static constexpr bool dynamically_typed = is_dynamically_typed<impl>::value;
static_assert(dynamically_typed,
using traits = actor_traits<impl>;
static_assert(traits::is_dynamically_typed,
"only dynamically-typed actors can join groups");
static constexpr bool spawnable = detail::spawnable<F, impl, Ts...>();
static_assert(spawnable,
"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);
cfg.groups = &irange;
return spawn_functor<Os>(detail::bool_token<enabled>{}, cfg, fun,
......
......@@ -5,7 +5,7 @@
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* 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 *
......@@ -18,33 +18,84 @@
#pragma once
#include <type_traits>
#include "caf/fwd.hpp"
namespace caf {
class statically_typed_actor_base {
// used as marker only
};
// Note: having marker types for blocking and non-blocking may seem redundant,
// 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 {
// used as marker only
};
/// Marker type for dynamically typed actors.
struct dynamically_typed_actor_base {};
template <class T>
struct actor_marker {
using type = statically_typed_actor_base;
};
/// Marker type for statically typed actors.
struct 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 <>
struct actor_marker<behavior> {
using type = dynamically_typed_actor_base;
static constexpr bool is_non_blocking = false;
static constexpr bool is_incomplete = true;
};
/// Default implementation of `actor_traits` for regular actors.
/// @relates actor_traits
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>
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
......@@ -32,6 +32,7 @@
#include "caf/actor_proxy.hpp"
#include "caf/actor_system.hpp"
#include "caf/actor_system_config.hpp"
#include "caf/actor_traits.hpp"
#include "caf/after.hpp"
#include "caf/atom.hpp"
#include "caf/attach_continuous_stream_source.hpp"
......
......@@ -23,7 +23,7 @@
#include <condition_variable>
#include "caf/actor_config.hpp"
#include "caf/actor_marker.hpp"
#include "caf/actor_traits.hpp"
#include "caf/after.hpp"
#include "caf/behavior.hpp"
#include "caf/extend.hpp"
......@@ -72,11 +72,14 @@ namespace caf {
/// receive rather than a behavior-stack based message processing.
/// @extends local_actor
class blocking_actor
// clang-format off
: public extend<local_actor, blocking_actor>::
with<mixin::requester,
mixin::sender,
mixin::subscriber>,
public dynamically_typed_actor_base {
public dynamically_typed_actor_base,
public blocking_actor_base {
// clang-format on
public:
// -- nested and member types ------------------------------------------------
......
......@@ -21,8 +21,8 @@
#include <string>
#include <type_traits>
#include "caf/actor_traits.hpp"
#include "caf/fwd.hpp"
#include "caf/actor_marker.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/detail/type_traits.hpp"
......
......@@ -29,11 +29,8 @@ namespace detail {
/// 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.
template <class T>
typename std::conditional<
is_convertible_to_actor<typename std::decay<T>::type>::value,
actor,
T&&
>::type
typename std::conditional<std::is_convertible<T, actor>::value, actor,
T&&>::type
spawn_fwd(typename std::remove_reference<T>::type& arg) noexcept {
return static_cast<T&&>(arg);
}
......@@ -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`
/// but simply forwards any other argument in the same way `std::forward` does.
template <class T>
typename std::conditional<
is_convertible_to_actor<typename std::decay<T>::type>::value,
actor,
T&&
>::type
typename std::conditional<std::is_convertible<T, actor>::value, actor,
T&&>::type
spawn_fwd(typename std::remove_reference<T>::type&& arg) noexcept {
static_assert(!std::is_lvalue_reference<T>::value,
"silently converting an lvalue to an rvalue");
......
......@@ -20,10 +20,10 @@
#include <type_traits>
#include "caf/fwd.hpp"
#include "caf/actor_traits.hpp"
#include "caf/extend.hpp"
#include "caf/fwd.hpp"
#include "caf/local_actor.hpp"
#include "caf/actor_marker.hpp"
#include "caf/response_handle.hpp"
#include "caf/scheduled_actor.hpp"
......
......@@ -19,17 +19,10 @@
#pragma once
#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/response_handle.hpp"
#include "caf/mixin/sender.hpp"
#include "caf/mixin/requester.hpp"
#include "caf/fwd.hpp"
namespace caf {
namespace mixin {
......@@ -64,19 +57,16 @@ public:
template <class T0, class T1, class... Ts>
typename std::enable_if<
!std::is_same<keep_behavior_t, typename std::decay<T0>::type>::value
>::type
!std::is_same<keep_behavior_t, typename std::decay<T0>::type>::value>::type
become(T0&& x0, T1&& x1, Ts&&... xs) {
behavior_type bhvr{std::forward<T0>(x0),
std::forward<T1>(x1),
behavior_type bhvr{std::forward<T0>(x0), std::forward<T1>(x1),
std::forward<Ts>(xs)...};
dptr()->do_become(std::move(bhvr.unbox()), true);
}
template <class T0, class T1, class... Ts>
void become(const keep_behavior_t&, T0&& x0, T1&& x1, Ts&&... xs) {
behavior_type bhvr{std::forward<T0>(x0),
std::forward<T1>(x1),
behavior_type bhvr{std::forward<T0>(x0), std::forward<T1>(x1),
std::forward<Ts>(xs)...};
dptr()->do_become(std::move(bhvr.unbox()), false);
}
......@@ -93,4 +83,3 @@ private:
} // namespace mixin
} // namespace caf
......@@ -29,7 +29,7 @@
#include <type_traits>
#include <unordered_map>
#include "caf/actor_marker.hpp"
#include "caf/actor_traits.hpp"
#include "caf/broadcast_downstream_manager.hpp"
#include "caf/default_downstream_manager.hpp"
#include "caf/error.hpp"
......@@ -106,7 +106,9 @@ result<message> drop(scheduled_actor*, message_view&);
/// A cooperatively scheduled, event-based actor implementation.
/// @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:
// -- nested enums -----------------------------------------------------------
......
......@@ -18,12 +18,11 @@
#pragma once
#include "caf/none.hpp"
#include "caf/actor_cast.hpp"
#include "caf/actor_system.hpp"
#include "caf/actor_storage.hpp"
#include "caf/intrusive_ptr.hpp"
#include "caf/actor_system.hpp"
#include "caf/blocking_actor.hpp"
#include "caf/none.hpp"
#include "caf/scoped_execution_unit.hpp"
namespace caf {
......@@ -83,7 +82,7 @@ private:
strong_actor_ptr self_;
};
/// @relates scoped_actor
std::string to_string(const scoped_actor& x);
} // namespace caf
......@@ -141,16 +141,11 @@ class typed_actor : detail::comparable<typed_actor<Sigs...>>,
}
// allow `handle_type{this}` for typed actors
template <class T>
typed_actor(T* ptr,
typename std::enable_if<
std::is_base_of<statically_typed_actor_base, T>::value
>::type* = 0)
: ptr_(ptr->ctrl()) {
static_assert(detail::tl_subset_of<
signatures,
typename T::signatures
>::value,
template <class T,
class = detail::enable_if_t<actor_traits<T>::is_statically_typed>>
typed_actor(T* ptr) : ptr_(ptr->ctrl()) {
static_assert(detail::tl_subset_of<signatures,
typename T::signatures>::value,
"Cannot assign T* to incompatible handle type");
CAF_ASSERT(ptr != nullptr);
}
......
......@@ -70,11 +70,14 @@ using accept_handler = typed_actor<reacts_to<new_connection_msg>,
/// components in the network.
/// @extends local_actor
template <class... Sigs>
class typed_broker : public extend<abstract_broker,
typed_broker<Sigs...>>::template
with<mixin::sender, mixin::requester,
class typed_broker
// clang-format off
: public extend<abstract_broker, typed_broker<Sigs...>>::template
with<mixin::sender,
mixin::requester,
mixin::behavior_changer>,
public statically_typed_actor_base {
// clang-format on
public:
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