Commit 1028e5b6 authored by Dominik Charousset's avatar Dominik Charousset

Fix doxygen, harmonize actor handles, use noexcept

parent e6cb9172
......@@ -38,7 +38,9 @@ namespace caf {
class scoped_actor;
struct invalid_actor_t {
constexpr invalid_actor_t() {}
constexpr invalid_actor_t() {
// nop
}
};
/// Identifies an invalid {@link actor}.
......@@ -59,36 +61,40 @@ class actor : detail::comparable<actor>,
detail::comparable<actor, actor_addr>,
detail::comparable<actor, invalid_actor_t>,
detail::comparable<actor, invalid_actor_addr_t> {
public:
// grant access to private ctor
friend class local_actor;
// allow conversion via actor_cast
template <class T, typename U>
friend T actor_cast(const U&);
public:
actor() = default;
actor(actor&&) = default;
actor(const actor&) = default;
actor& operator=(actor&&) = default;
actor& operator=(const actor&) = default;
template <class T>
actor(intrusive_ptr<T> ptr,
typename std::enable_if<is_convertible_to_actor<T>::value>::type* = 0)
: ptr_(std::move(ptr)) {}
template <class T,
class Enable =
typename std::enable_if<
is_convertible_to_actor<T>::value
>::type>
actor(intrusive_ptr<T> ptr) : ptr_(std::move(ptr)) {
// nop
}
template <class T>
actor(T* ptr,
typename std::enable_if<is_convertible_to_actor<T>::value>::type* = 0)
: ptr_(ptr) {}
template <class T,
class Enable =
typename std::enable_if<
is_convertible_to_actor<T>::value
>::type>
actor(T* ptr) : ptr_(ptr) {
// nop
}
actor(const invalid_actor_t&);
actor& operator=(actor&&) = default;
actor& operator=(const actor&) = default;
template <class T>
typename std::enable_if<is_convertible_to_actor<T>::value, actor&>::type
operator=(intrusive_ptr<T> ptr) {
......@@ -107,55 +113,56 @@ public:
actor& operator=(const invalid_actor_t&);
inline operator bool() const {
/// Returns the address of the stored actor.
actor_addr address() const noexcept;
/// Returns `*this != invalid_actor`.
inline operator bool() const noexcept {
return static_cast<bool>(ptr_);
}
inline bool operator!() const {
/// Returns `*this == invalid_actor`.
inline bool operator!() const noexcept {
return ! ptr_;
}
/// Returns a handle that grants access to actor operations such as enqueue.
inline abstract_actor* operator->() const {
return ptr_.get();
}
/// Returns whether this is an handle to a remote actor.
bool is_remote() const noexcept;
/// Returns the ID of this actor.
actor_id id() const noexcept;
/// Exchange content of `*this` and `other`.
void swap(actor& other) noexcept;
/// @cond PRIVATE
inline abstract_actor& operator*() const {
return *ptr_;
inline abstract_actor* operator->() const noexcept {
return ptr_.get();
}
intptr_t compare(const actor& other) const;
intptr_t compare(const actor&) const noexcept;
intptr_t compare(const actor_addr&) const;
intptr_t compare(const actor_addr&) const noexcept;
inline intptr_t compare(const invalid_actor_t&) const {
inline intptr_t compare(const invalid_actor_t&) const noexcept {
return ptr_ ? 1 : 0;
}
inline intptr_t compare(const invalid_actor_addr_t&) const {
inline intptr_t compare(const invalid_actor_addr_t&) const noexcept {
return compare(invalid_actor);
}
/// Returns the address of the stored actor.
actor_addr address() const;
/// Returns whether this is an handle to a remote actor.
bool is_remote() const;
actor_id id() const;
void swap(actor& other);
/// @endcond
private:
inline abstract_actor* get() const {
inline abstract_actor* get() const noexcept {
return ptr_.get();
}
actor(abstract_actor*);
abstract_actor_ptr ptr_;
};
} // namespace caf
......
......@@ -45,62 +45,73 @@ constexpr invalid_actor_addr_t invalid_actor_addr = invalid_actor_addr_t{};
/// Stores the address of typed as well as untyped actors.
class actor_addr : detail::comparable<actor_addr>,
detail::comparable<actor_addr, abstract_actor*>,
detail::comparable<actor_addr, abstract_actor_ptr> {
detail::comparable<actor_addr, abstract_actor*>,
detail::comparable<actor_addr, abstract_actor_ptr> {
public:
// grant access to private ctor
friend class actor;
friend class abstract_actor;
template <class T, typename U>
friend T actor_cast(const U&);
public:
actor_addr() = default;
actor_addr(actor_addr&&) = default;
actor_addr(const actor_addr&) = default;
actor_addr& operator=(actor_addr&&) = default;
actor_addr& operator=(const actor_addr&) = default;
actor_addr(const invalid_actor_addr_t&);
actor_addr operator=(const invalid_actor_addr_t&);
inline explicit operator bool() const { return static_cast<bool>(ptr_); }
/// Returns `*this != invalid_actor_addr`.
inline explicit operator bool() const noexcept {
return static_cast<bool>(ptr_);
}
/// Returns `*this == invalid_actor_addr`.
inline bool operator!() const noexcept {
return !ptr_;
}
inline bool operator!() const { return ! ptr_; }
/// Returns whether this is an handle to a remote actor.
bool is_remote() const noexcept;
intptr_t compare(const actor_addr& other) const;
/// Returns the ID of this actor.
actor_id id() const noexcept;
intptr_t compare(const abstract_actor* other) const;
/// Returns the origin node of this actor.
node_id node() const noexcept;
inline intptr_t compare(const abstract_actor_ptr& other) const {
return compare(other.get());
/// Exchange content of `*this` and `other`.
void swap(actor_addr& other) noexcept;
/// @cond PRIVATE
inline abstract_actor* operator->() const noexcept {
return ptr_.get();
}
actor_id id() const;
intptr_t compare(const actor_addr& other) const noexcept;
node_id node() const;
intptr_t compare(const abstract_actor* other) const noexcept;
/// Returns whether this is an address of a remote actor.
bool is_remote() const;
inline intptr_t compare(const abstract_actor_ptr& other) const noexcept {
return compare(other.get());
}
/// Returns the set of accepted messages types as strings or
/// an empty set if this actor is untyped.
std::set<std::string> message_types() const;
/// @endcond
private:
inline abstract_actor* get() const { return ptr_.get(); }
inline abstract_actor* get() const noexcept {
return ptr_.get();
}
explicit actor_addr(abstract_actor*);
abstract_actor_ptr ptr_;
};
} // namespace caf
......
......@@ -51,7 +51,7 @@ public:
~blocking_actor();
/**************************************************************************
* utility stuff and receive() member function family *
* utility stuff and receive() member function family *
**************************************************************************/
using timeout_type = std::chrono::high_resolution_clock::time_point;
......
......@@ -38,17 +38,12 @@
#define CAF_VERSION 1400
/// Defined to the major version number of CAF.
///*/
#define CAF_MAJOR_VERSION (CAF_VERSION / 10000)
/**
/// Defined to the minor version number of CAF.
///*/
#define CAF_MINOR_VERSION ((CAF_VERSION / 100) % 100)
/**
/// Defined to the patch version number of CAF.
///*/
#define CAF_PATCH_VERSION (CAF_VERSION % 100)
// This compiler-specific block defines:
......
......@@ -31,84 +31,80 @@ namespace detail {
/// - `x == 0` if `*this == other`
template <class Subclass, class T = Subclass>
class comparable {
friend bool operator==(const Subclass& lhs, const T& rhs) {
friend bool operator==(const Subclass& lhs, const T& rhs) noexcept {
return lhs.compare(rhs) == 0;
}
friend bool operator==(const T& lhs, const Subclass& rhs) {
friend bool operator==(const T& lhs, const Subclass& rhs) noexcept {
return rhs.compare(lhs) == 0;
}
friend bool operator!=(const Subclass& lhs, const T& rhs) {
friend bool operator!=(const Subclass& lhs, const T& rhs) noexcept {
return lhs.compare(rhs) != 0;
}
friend bool operator!=(const T& lhs, const Subclass& rhs) {
friend bool operator!=(const T& lhs, const Subclass& rhs) noexcept {
return rhs.compare(lhs) != 0;
}
friend bool operator<(const Subclass& lhs, const T& rhs) {
friend bool operator<(const Subclass& lhs, const T& rhs) noexcept {
return lhs.compare(rhs) < 0;
}
friend bool operator>(const Subclass& lhs, const T& rhs) {
friend bool operator>(const Subclass& lhs, const T& rhs) noexcept {
return lhs.compare(rhs) > 0;
}
friend bool operator<(const T& lhs, const Subclass& rhs) {
friend bool operator<(const T& lhs, const Subclass& rhs) noexcept {
return rhs > lhs;
}
friend bool operator>(const T& lhs, const Subclass& rhs) {
friend bool operator>(const T& lhs, const Subclass& rhs) noexcept {
return rhs < lhs;
}
friend bool operator<=(const Subclass& lhs, const T& rhs) {
friend bool operator<=(const Subclass& lhs, const T& rhs) noexcept {
return lhs.compare(rhs) <= 0;
}
friend bool operator>=(const Subclass& lhs, const T& rhs) {
friend bool operator>=(const Subclass& lhs, const T& rhs) noexcept {
return lhs.compare(rhs) >= 0;
}
friend bool operator<=(const T& lhs, const Subclass& rhs) {
friend bool operator<=(const T& lhs, const Subclass& rhs) noexcept {
return rhs >= lhs;
}
friend bool operator>=(const T& lhs, const Subclass& rhs) {
friend bool operator>=(const T& lhs, const Subclass& rhs) noexcept {
return rhs <= lhs;
}
};
template <class Subclass>
class comparable<Subclass, Subclass> {
friend bool operator==(const Subclass& lhs, const Subclass& rhs) {
friend bool operator==(const Subclass& lhs, const Subclass& rhs) noexcept {
return lhs.compare(rhs) == 0;
}
friend bool operator!=(const Subclass& lhs, const Subclass& rhs) {
friend bool operator!=(const Subclass& lhs, const Subclass& rhs) noexcept {
return lhs.compare(rhs) != 0;
}
friend bool operator<(const Subclass& lhs, const Subclass& rhs) {
friend bool operator<(const Subclass& lhs, const Subclass& rhs) noexcept {
return lhs.compare(rhs) < 0;
}
friend bool operator<=(const Subclass& lhs, const Subclass& rhs) {
friend bool operator<=(const Subclass& lhs, const Subclass& rhs) noexcept {
return lhs.compare(rhs) <= 0;
}
friend bool operator>(const Subclass& lhs, const Subclass& rhs) {
friend bool operator>(const Subclass& lhs, const Subclass& rhs) noexcept {
return lhs.compare(rhs) > 0;
}
friend bool operator>=(const Subclass& lhs, const Subclass& rhs) {
friend bool operator>=(const Subclass& lhs, const Subclass& rhs) noexcept {
return lhs.compare(rhs) >= 0;
}
};
} // namespace details
......
......@@ -71,13 +71,13 @@ public:
}
}
void swap(intrusive_ptr& other) {
void swap(intrusive_ptr& other) noexcept {
std::swap(ptr_, other.ptr_);
}
/// Returns the raw pointer without modifying reference
/// count and sets this to `nullptr`.
pointer release() {
pointer release() noexcept {
auto result = ptr_;
ptr_ = nullptr;
return result;
......
......@@ -54,9 +54,11 @@ class typed_broker;
template <class... Sigs>
class typed_actor : detail::comparable<typed_actor<Sigs...>>,
detail::comparable<typed_actor<Sigs...>, actor_addr>,
detail::comparable<typed_actor<Sigs...>, invalid_actor_t>,
detail::comparable<typed_actor<Sigs...>,
invalid_actor_addr_t> {
public:
// grant access to private ctor
friend class local_actor;
// friend with all possible instantiations
......@@ -97,55 +99,85 @@ class typed_actor : detail::comparable<typed_actor<Sigs...>>,
typed_actor& operator=(const typed_actor&) = default;
template <class TypedActor,
class Enable = typename std::enable_if<
detail::tlf_is_subset(signatures{},
typename TypedActor::signatures{})
>::type>
class Enable =
typename std::enable_if<
detail::tlf_is_subset(signatures(),
typename TypedActor::signatures())
>::type>
typed_actor(const TypedActor& other) : ptr_(other.ptr_) {
// nop
}
template <class TypedActor,
class Enable = typename std::enable_if<
detail::tlf_is_subset(signatures{},
typename TypedActor::signatures{})
>::type>
class Enable =
typename std::enable_if<
detail::tlf_is_subset(signatures(),
typename TypedActor::signatures())
>::type>
typed_actor& operator=(const TypedActor& other) {
ptr_ = other.ptr_;
return *this;
}
template <class Impl,
class Enable = typename std::enable_if<
detail::tlf_is_subset(signatures{},
typename Impl::signatures{})
>::type>
class Enable =
typename std::enable_if<
detail::tlf_is_subset(signatures(),
typename Impl::signatures())
>::type>
typed_actor(intrusive_ptr<Impl> other) : ptr_(std::move(other)) {
// nop
}
abstract_actor* operator->() const {
return ptr_.get();
/// Queries the address of the stored actor.
actor_addr address() const noexcept {
return ptr_ ? ptr_->address() : actor_addr();
}
abstract_actor& operator*() const {
return *ptr_.get();
/// Returns `*this != invalid_actor`.
explicit operator bool() const noexcept {
return static_cast<bool>(ptr_);
}
/// Queries the address of the stored actor.
actor_addr address() const {
return ptr_ ? ptr_->address() : actor_addr{};
/// Returns `*this == invalid_actor`.
bool operator!() const noexcept {
return !ptr_;
}
/// Returns whether this is an handle to a remote actor.
bool is_remote() const noexcept {
return ptr_ ? ptr_->is_remote() : false;
}
/// Returns the ID of this actor.
actor_id id() const noexcept {
return ptr_ ? ptr_->id() : invalid_actor_id;
}
/// Exchange content of `*this` and `other`.
void swap(actor& other) noexcept {
ptr_.swap(other.ptr_);
}
intptr_t compare(const actor_addr& rhs) const {
/// @cond PRIVATE
abstract_actor* operator->() const noexcept {
return ptr_.get();
}
abstract_actor& operator*() const noexcept {
return *ptr_.get();
}
intptr_t compare(const actor_addr& rhs) const noexcept {
return address().compare(rhs);
}
intptr_t compare(const typed_actor& other) const {
intptr_t compare(const typed_actor& other) const noexcept {
return compare(other.address());
}
intptr_t compare(const invalid_actor_addr_t&) const {
intptr_t compare(const invalid_actor_addr_t&) const noexcept {
return ptr_ ? 1 : 0;
}
......@@ -153,13 +185,7 @@ class typed_actor : detail::comparable<typed_actor<Sigs...>>,
return {Sigs::static_type_name()...};
}
explicit operator bool() const {
return static_cast<bool>(ptr_);
}
bool operator!() const {
return !ptr_;
}
/// @endcond
private:
abstract_actor* get() const {
......
......@@ -84,85 +84,62 @@ uniform_value make_uniform_value(const uniform_type_info* uti, Ts&&... xs) {
/// Unfortunately, this is not possible using the C++ RTTI system.
///
/// Since it is not possible to extend `std::type_info, `libcaf`
/// uses its own type abstraction:
/// {@link caf::uniform_type_info uniform_type_info}.
/// uses its own type abstraction: `uniform_type_info`.
///
/// Unlike `std::type_info::name(),
/// {@link caf::uniform_type_info::name() uniform_type_info::name()}
/// Unlike `std::type_info::name()`, `uniform_type_info::name()`
/// is guaranteed to return the same name on all supported platforms.
/// Furthermore, it allows to create an instance of a type by name:
///
/// @code
/// // creates a signed, 32 bit integer
/// caf::object i = caf::uniform_type_info::by_name("@i32")->create();
/// uniform_value i = caf::uniform_type_info::by_name("@i32")->create();
/// @endcode
///
/// However, you should rarely if ever need to use {@link caf::object object}
/// or {@link caf::uniform_type_info uniform_type_info}.
/// However, you should rarely if ever need to use `uniform_value`
/// or `uniform_type_info`.
///
/// There is one exception, though, where you need to care about
/// the type system: using custom data types in messages.
/// The source code below compiles fine, but crashes with an exception during
/// runtime.
///
/// @code
/// ~~~
/// #include "caf/all.hpp"
/// using namespace caf;
///
/// struct foo { int a; int b; };
///
/// int main()
/// {
/// int main() {
/// send(self, foo{1, 2});
/// return 0;
/// }
/// @endcode
///
/// Depending on your platform, the error message looks somewhat like this:
///
/// <tt>
/// terminate called after throwing an instance of std::runtime_error
/// <br>
/// what(): uniform_type_info::by_type_info(): foo is an unknown typeid name
/// </tt>
/// ~~~
///
/// The user-defined struct `foo` is not known by the type system.
/// Thus, `foo` cannot be serialized and is rejected.
///
/// Fortunately, there is an easy way to add `foo` the type system,
/// without needing to implement serialize/deserialize by yourself:
///
/// @code
/// caf::announce<foo>(&foo::a, &foo::b);
/// @endcode
/// Thus, `foo` cannot be serialized and the code above code above will
/// throw a `std::runtime_error`.
///
/// {@link caf::announce announce()} takes the class as template
/// parameter and pointers to all members (or getter/setter pairs)
/// as arguments. This works for all primitive data types and STL compliant
/// containers. See the announce {@link announce_example_1.cpp example 1},
/// {@link announce_example_2.cpp example 2},
/// {@link announce_example_3.cpp example 3} and
/// {@link announce_example_4.cpp example 4} for more details.
/// Fortunately, there is an easy way to add simple data structures like
/// `foo` the type system without implementing serialize/deserialize yourself:
/// `caf::announce<foo>("foo", &foo::a, &foo::b)`.
///
/// Obviously, there are limitations. If your class does implement
/// an unsupported data structure, you have to implement serialize/deserialize
/// by yourself. {@link announce_example_5.cpp Example 5} shows, how to
/// announce a tree data structure to the type system.
/// The function `announce()` takes the class as template
/// parameter. The name of the announced type is the first argument, followed
/// by pointers to all members (or getter/setter pairs). This works for all
/// primitive data types and STL compliant containers. See the announce example
/// for more details. Complex data structures usually require a custom
/// serializer class.
/// @ingroup TypeSystem
/// Provides a platform independent type name and a (very primitive)
/// kind of reflection in combination with {@link caf::object object}.
/// The platform independent name is equal to the "in-sourcecode-name"
/// with a few exceptions:
/// kind of reflection in combination with `uniform_value`.
/// CAF uses abbvreviate type names for brevity:
/// - std::string is named \@str
/// - std::u16string is named \@u16str
/// - std::u32string is named \@u32str
/// - integers are named `\@(i|u)$size\n
/// e.g.: \@i32 is a 32 bit signed integer; \@u16
/// is a 16 bit unsigned integer
/// - the <em>anonymous namespace</em> is named \@_ \n
/// e.g.: `namespace { class foo { }; } is mapped to
/// \@_::foo
class uniform_type_info {
public:
friend bool operator==(const uniform_type_info& lhs,
......@@ -190,8 +167,7 @@ public:
/// @throws std::runtime_error if `tinfo` is not an announced type.
static const uniform_type_info* from(const std::type_info& tinfo);
/// Get all instances.
/// @returns A vector with all known (announced) instances.
/// Returns a vector with all known (announced) types.
static std::vector<const uniform_type_info*> instances();
/// Creates a copy of `other`.
......
......@@ -42,28 +42,28 @@ actor& actor::operator=(const invalid_actor_t&) {
return *this;
}
intptr_t actor::compare(const actor& other) const {
intptr_t actor::compare(const actor& other) const noexcept {
return channel::compare(ptr_.get(), other.ptr_.get());
}
intptr_t actor::compare(const actor_addr& other) const {
intptr_t actor::compare(const actor_addr& other) const noexcept {
return static_cast<ptrdiff_t>(ptr_.get() - other.ptr_.get());
}
void actor::swap(actor& other) {
void actor::swap(actor& other) noexcept {
ptr_.swap(other.ptr_);
}
actor_addr actor::address() const {
actor_addr actor::address() const noexcept {
return ptr_ ? ptr_->address() : actor_addr{};
}
bool actor::is_remote() const {
bool actor::is_remote() const noexcept {
return ptr_ ? ptr_->is_remote() : false;
}
actor_id actor::id() const {
return (ptr_) ? ptr_->id() : 0;
actor_id actor::id() const noexcept {
return ptr_ ? ptr_->id() : invalid_actor_id;
}
} // namespace caf
......@@ -41,33 +41,33 @@ actor_addr::actor_addr(abstract_actor* ptr) : ptr_(ptr) {
// nop
}
intptr_t actor_addr::compare(const actor_addr& other) const {
actor_addr actor_addr::operator=(const invalid_actor_addr_t&) {
ptr_.reset();
return *this;
}
intptr_t actor_addr::compare(const actor_addr& other) const noexcept {
return compare_impl(ptr_.get(), other.ptr_.get());
}
intptr_t actor_addr::compare(const abstract_actor* other) const {
intptr_t actor_addr::compare(const abstract_actor* other) const noexcept {
return compare_impl(ptr_.get(), other);
}
actor_addr actor_addr::operator=(const invalid_actor_addr_t&) {
ptr_.reset();
return *this;
}
actor_id actor_addr::id() const {
actor_id actor_addr::id() const noexcept {
return (ptr_) ? ptr_->id() : 0;
}
node_id actor_addr::node() const {
node_id actor_addr::node() const noexcept {
return ptr_ ? ptr_->node() : detail::singletons::get_node_id();
}
bool actor_addr::is_remote() const {
bool actor_addr::is_remote() const noexcept {
return ptr_ ? ptr_->is_remote() : false;
}
std::set<std::string> actor_addr::message_types() const {
return ! ptr_ ? std::set<std::string>{} : ptr_->message_types();
void actor_addr::swap(actor_addr& other) noexcept {
ptr_.swap(other.ptr_);
}
} // namespace caf
......@@ -779,7 +779,9 @@ void basp_broker::init_handshake_as_server(connection_context& ctx,
if (addr != invalid_actor_addr) {
auto writer = make_payload_writer([&](binary_serializer& sink) {
sink << addr.id();
auto sigs = addr.message_types();
// TODO: this always exposes the "real" type of an actor,
// which prohibits users from announcing sub-types
auto sigs = addr->message_types();
sink << static_cast<uint32_t>(sigs.size());
for (auto& sig : sigs) {
sink << sig;
......
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