Commit f676aa81 authored by Dominik Charousset's avatar Dominik Charousset

Implement type-erased views

parent 37b1c2dc
...@@ -127,9 +127,9 @@ public: ...@@ -127,9 +127,9 @@ public:
"T must provide default and copy constructors"); "T must provide default and copy constructors");
static_assert(detail::is_serializable<T>::value, "T must be serializable"); static_assert(detail::is_serializable<T>::value, "T must be serializable");
type_names_by_rtti_.emplace(std::type_index(typeid(T)), name); type_names_by_rtti_.emplace(std::type_index(typeid(T)), name);
value_factories_by_name_.emplace(std::move(name), &make_type_erased<T>); value_factories_by_name_.emplace(std::move(name), &make_type_erased_value<T>);
value_factories_by_rtti_.emplace(std::type_index(typeid(T)), value_factories_by_rtti_.emplace(std::type_index(typeid(T)),
&make_type_erased<T>); &make_type_erased_value<T>);
return *this; return *this;
} }
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <tuple> #include <tuple>
#include <string> #include <string>
#include <utility> #include <utility>
#include <functional>
#include <type_traits> #include <type_traits>
#include "caf/atom.hpp" #include "caf/atom.hpp"
...@@ -38,6 +39,11 @@ public: ...@@ -38,6 +39,11 @@ public:
// nop // nop
} }
template <class T>
std::string operator()(const std::reference_wrapper<T>& x) const {
return (*this)(x.get());
}
std::string operator()(const char* cstr) const; std::string operator()(const char* cstr) const;
inline std::string operator()(char* cstr) const { inline std::string operator()(char* cstr) const {
......
...@@ -23,13 +23,13 @@ ...@@ -23,13 +23,13 @@
namespace caf { namespace caf {
namespace detail { namespace detail {
template <class Processor, class U> template <class Processor, class T>
auto try_serialize(Processor& proc, U* x) -> decltype(proc & *x) { auto try_serialize(Processor& proc, T* x) -> decltype(proc & *x) {
proc & *x; proc & *x;
} }
template <class Processor> template <class Processor>
void try_serialize(Processor&, const void*) { void try_serialize(Processor&, void*) {
// nop // nop
} }
......
...@@ -25,22 +25,26 @@ ...@@ -25,22 +25,26 @@
namespace caf { namespace caf {
// 1-class templates // -- 1 param templates --------------------------------------------------------
template <class> class maybe; template <class> class maybe;
template <class> class optional; template <class> class optional;
template <class> class intrusive_ptr; template <class> class intrusive_ptr;
template <class> class weak_intrusive_ptr; template <class> class weak_intrusive_ptr;
template <class> class typed_continue_helper; template <class> class typed_continue_helper;
// 2-class templates // -- 3 param templates --------------------------------------------------------
template <class, class, int> class actor_cast_access; template <class, class, int> class actor_cast_access;
// variadic templates // -- variadic templates -------------------------------------------------------
template <class...> class delegated; template <class...> class delegated;
template <class...> class typed_actor; template <class...> class typed_actor;
template <class...> class typed_response_promise; template <class...> class typed_response_promise;
// classes // -- classes ------------------------------------------------------------------
class actor; class actor;
class group; class group;
class error; class error;
...@@ -70,15 +74,18 @@ class continue_helper; ...@@ -70,15 +74,18 @@ class continue_helper;
class mailbox_element; class mailbox_element;
class message_handler; class message_handler;
class response_promise; class response_promise;
class event_based_actor;
class binary_serializer; class binary_serializer;
class event_based_actor;
class type_erased_tuple;
class type_erased_value;
class actor_control_block; class actor_control_block;
class binary_deserializer; class binary_deserializer;
class actor_system_config; class actor_system_config;
class uniform_type_info_map; class uniform_type_info_map;
class forwarding_actor_proxy; class forwarding_actor_proxy;
// structs // -- structs ------------------------------------------------------------------
struct unit_t; struct unit_t;
struct anything; struct anything;
struct exit_msg; struct exit_msg;
...@@ -90,12 +97,16 @@ struct invalid_actor_addr_t; ...@@ -90,12 +97,16 @@ struct invalid_actor_addr_t;
struct illegal_message_element; struct illegal_message_element;
struct prohibit_top_level_spawn_marker; struct prohibit_top_level_spawn_marker;
// enums // -- enums --------------------------------------------------------------------
enum class atom_value : uint64_t; enum class atom_value : uint64_t;
// aliases // -- aliases ------------------------------------------------------------------
using actor_id = uint64_t; using actor_id = uint64_t;
// -- I/O classes --------------------------------------------------------------
namespace io { namespace io {
class broker; class broker;
...@@ -109,18 +120,24 @@ struct header; ...@@ -109,18 +120,24 @@ struct header;
} // namespace io } // namespace io
// -- OpenCL classes -----------------------------------------------------------
namespace opencl { namespace opencl {
class manager; class manager;
} // namespace opencl } // namespace opencl
// -- RIAC classes -------------------------------------------------------------
namespace riac { namespace riac {
class probe; class probe;
} // namespace riac } // namespace riac
// -- scheduler classes --------------------------------------------------------
namespace scheduler { namespace scheduler {
class abstract_worker; class abstract_worker;
...@@ -128,6 +145,8 @@ class abstract_coordinator; ...@@ -128,6 +145,8 @@ class abstract_coordinator;
} // namespace scheduler } // namespace scheduler
// -- detail classes -----------------------------------------------------------
namespace detail { namespace detail {
class disposer; class disposer;
...@@ -137,8 +156,17 @@ class dynamic_message_data; ...@@ -137,8 +156,17 @@ class dynamic_message_data;
} // namespace detail } // namespace detail
using strong_actor_ptr = intrusive_ptr<actor_control_block>; // -- weak pointer aliases -----------------------------------------------------
using weak_actor_ptr = weak_intrusive_ptr<actor_control_block>; using weak_actor_ptr = weak_intrusive_ptr<actor_control_block>;
// -- intrusive pointer aliases ------------------------------------------------
using strong_actor_ptr = intrusive_ptr<actor_control_block>;
// -- unique pointer aliases ---------------------------------------------------
using type_erased_value_ptr = std::unique_ptr<type_erased_value>;
using mailbox_element_ptr = std::unique_ptr<mailbox_element, detail::disposer>; using mailbox_element_ptr = std::unique_ptr<mailbox_element, detail::disposer>;
} // namespace caf } // namespace caf
......
...@@ -62,7 +62,7 @@ public: ...@@ -62,7 +62,7 @@ public:
typename std::decay<T>::type typename std::decay<T>::type
>::type >::type
>::type; >::type;
return emplace(make_type_erased<type>(std::forward<T>(x))); return emplace(make_type_erased_value<type>(std::forward<T>(x)));
} }
/// Converts the buffer to an actual message object without /// Converts the buffer to an actual message object without
......
...@@ -20,49 +20,78 @@ ...@@ -20,49 +20,78 @@
#ifndef CAF_TYPE_ERASED_COLLECTION_HPP #ifndef CAF_TYPE_ERASED_COLLECTION_HPP
#define CAF_TYPE_ERASED_COLLECTION_HPP #define CAF_TYPE_ERASED_COLLECTION_HPP
#include <tuple>
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <typeinfo> #include <typeinfo>
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/type_erased_value.hpp"
#include "caf/detail/type_nr.hpp"
namespace caf { namespace caf {
/// Represents a tuple of type-erased values. /// Represents a tuple of type-erased values.
class type_erased_tuple { class type_erased_tuple {
public: public:
// -- member types -----------------------------------------------------------
using rtti_pair = std::pair<uint16_t, const std::type_info*>; using rtti_pair = std::pair<uint16_t, const std::type_info*>;
// -- constructors, destructors, and assignment operators --------------------
virtual ~type_erased_tuple(); virtual ~type_erased_tuple();
// pure virtual modifiers // -- pure virtual modifiers -------------------------------------------------
/// Returns a mutable pointer to the element at position `pos`.
virtual void* get_mutable(size_t pos) = 0; virtual void* get_mutable(size_t pos) = 0;
/// Load the content for the element at position `pos` from `source`.
virtual void load(size_t pos, deserializer& source) = 0; virtual void load(size_t pos, deserializer& source) = 0;
// pure virtual observers // -- modifiers --------------------------------------------------------------
/// Load the content for the tuple from `source`.
void load(deserializer& source);
// -- pure virtual observers -------------------------------------------------
/// Returns the size of this tuple.
virtual size_t size() const = 0; virtual size_t size() const = 0;
/// Returns a type hint for the element types.
virtual uint32_t type_token() const = 0; virtual uint32_t type_token() const = 0;
/// Returns the type number and `std::type_info` object for
/// the element at position `pos`.
virtual rtti_pair type(size_t pos) const = 0; virtual rtti_pair type(size_t pos) const = 0;
/// Returns the element at position `pos`.
virtual const void* get(size_t pos) const = 0; virtual const void* get(size_t pos) const = 0;
/// Returns a string representation of the element at position `pos`.
virtual std::string stringify(size_t pos) const = 0; virtual std::string stringify(size_t pos) const = 0;
/// Saves the element at position `pos` to `sink`.
virtual void save(size_t pos, serializer& sink) const = 0; virtual void save(size_t pos, serializer& sink) const = 0;
// observers // -- observers --------------------------------------------------------------
/// Returns a string representation of the tuple.
std::string stringify() const;
/// Saves the content of the tuple to `sink`.
void save(serializer& sink) const;
/// Checks whether the type of the stored value matches /// Checks whether the type of the stored value matches
/// the type nr and type info object. /// the type nr and type info object.
bool matches(size_t pos, uint16_t tnr, const std::type_info* tinf) const; bool matches(size_t pos, uint16_t tnr, const std::type_info* tinf) const;
// inline observers // -- inline observers -------------------------------------------------------
/// Returns the type number for the element at position `pos`.
inline uint16_t type_nr(size_t pos) const { inline uint16_t type_nr(size_t pos) const {
return type(pos).first; return type(pos).first;
} }
...@@ -73,6 +102,108 @@ public: ...@@ -73,6 +102,108 @@ public:
} }
}; };
/// @relates type_erased_tuple
template <class Processor>
typename std::enable_if<Processor::is_saving::value>::type
serialize(Processor& proc, type_erased_tuple& x) {
x.save(proc);
}
/// @relates type_erased_tuple
template <class Processor>
typename std::enable_if<Processor::is_loading::value>::type
serialize(Processor& proc, type_erased_tuple& x) {
x.load(proc);
}
/// @relates type_erased_tuple
inline std::string to_string(const type_erased_tuple& x) {
return x.stringify();
}
template <class... Ts>
class type_erased_tuple_view : public type_erased_tuple {
public:
// -- member types -----------------------------------------------------------
template <size_t X>
using num_token = std::integral_constant<size_t, X>;
// -- constructors, destructors, and assignment operators --------------------
type_erased_tuple_view(Ts&... xs) : xs_(xs...) {
init();
}
type_erased_tuple_view(const type_erased_tuple_view& other) : xs_(other.xs_) {
init();
}
// -- overridden modifiers ---------------------------------------------------
void* get_mutable(size_t pos) override {
return ptrs_[pos]->get_mutable();
}
void load(size_t pos, deserializer& source) override {
ptrs_[pos]->load(source);
}
// -- overridden observers ---------------------------------------------------
size_t size() const override {
return sizeof...(Ts);
}
uint32_t type_token() const override {
return detail::make_type_token<Ts...>();
}
rtti_pair type(size_t pos) const override {
return ptrs_[pos]->type();
}
const void* get(size_t pos) const override {
return ptrs_[pos]->get();
}
std::string stringify(size_t pos) const override {
return ptrs_[pos]->stringify();
}
void save(size_t pos, serializer& sink) const override {
return ptrs_[pos]->save(sink);
}
private:
// -- pointer "lookup table" utility -----------------------------------------
template <size_t N>
void init(num_token<N>, num_token<N>) {
// end of recursion
}
template <size_t P, size_t N>
void init(num_token<P>, num_token<N> last) {
ptrs_[P] = &std::get<P>(xs_);
init(num_token<P + 1>{}, last);
}
void init() {
init(num_token<0>{}, num_token<sizeof...(Ts)>{});
}
// -- data members -----------------------------------------------------------
std::tuple<type_erased_value_impl<std::reference_wrapper<Ts>>...> xs_;
type_erased_value* ptrs_[sizeof...(Ts)];
};
template <class... Ts>
type_erased_tuple_view<Ts...> make_type_erased_tuple_view(Ts&... xs) {
return {xs...};
}
} // namespace caf } // namespace caf
#endif // CAF_TYPE_ERASED_COLLECTION_HPP #endif // CAF_TYPE_ERASED_COLLECTION_HPP
...@@ -22,7 +22,9 @@ ...@@ -22,7 +22,9 @@
#include <cstdint> #include <cstdint>
#include <typeinfo> #include <typeinfo>
#include <functional>
#include "caf/fwd.hpp"
#include "caf/deep_to_string.hpp" #include "caf/deep_to_string.hpp"
#include "caf/detail/type_nr.hpp" #include "caf/detail/type_nr.hpp"
...@@ -31,18 +33,18 @@ ...@@ -31,18 +33,18 @@
namespace caf { namespace caf {
class type_erased_value;
using type_erased_value_ptr = std::unique_ptr<type_erased_value>;
/// Represents a single type-erased value. /// Represents a single type-erased value.
class type_erased_value { class type_erased_value {
public: public:
// -- member types -----------------------------------------------------------
using rtti_pair = std::pair<uint16_t, const std::type_info*>; using rtti_pair = std::pair<uint16_t, const std::type_info*>;
// -- constructors, destructors, and assignment operators --------------------
virtual ~type_erased_value(); virtual ~type_erased_value();
// pure virtual modifiers // -- pure virtual modifiers -------------------------------------------------
/// Returns a mutable pointer to the stored value. /// Returns a mutable pointer to the stored value.
virtual void* get_mutable() = 0; virtual void* get_mutable() = 0;
...@@ -50,7 +52,7 @@ public: ...@@ -50,7 +52,7 @@ public:
/// Load the content for the stored value from `source`. /// Load the content for the stored value from `source`.
virtual void load(deserializer& source) = 0; virtual void load(deserializer& source) = 0;
// pure virtual observers // -- pure virtual observers -------------------------------------------------
/// Returns the type number and type information object for the stored value. /// Returns the type number and type information object for the stored value.
virtual rtti_pair type() const = 0; virtual rtti_pair type() const = 0;
...@@ -67,13 +69,13 @@ public: ...@@ -67,13 +69,13 @@ public:
/// Returns a copy of the stored value. /// Returns a copy of the stored value.
virtual type_erased_value_ptr copy() const = 0; virtual type_erased_value_ptr copy() const = 0;
// observers // -- observers --------------------------------------------------------------
/// Checks whether the type of the stored value matches /// Checks whether the type of the stored value matches
/// the type nr and type info object. /// the type nr and type info object.
bool matches(uint16_t tnr, const std::type_info* tinf) const; bool matches(uint16_t tnr, const std::type_info* tinf) const;
// inline observers // -- inline observers -------------------------------------------------------
/// Returns the type number for the stored value. /// Returns the type number for the stored value.
inline uint16_t type_nr() const { inline uint16_t type_nr() const {
...@@ -86,162 +88,168 @@ public: ...@@ -86,162 +88,168 @@ public:
} }
}; };
/// @relates type_erased_value_impl
template <class Processor>
typename std::enable_if<Processor::is_saving::value>::type
serialize(Processor& proc, type_erased_value& x) {
x.save(proc);
}
/// @relates type_erased_value_impl
template <class Processor>
typename std::enable_if<Processor::is_loading::value>::type
serialize(Processor& proc, type_erased_value& x) {
x.load(proc);
}
/// @relates type_erased_value_impl
inline std::string to_string(const type_erased_value& x) {
return x.stringify();
}
/// @relates type_erased_value
/// Default implementation for single type-erased values.
template <class T> template <class T>
struct type_erased_value_impl : public type_erased_value { class type_erased_value_impl : public type_erased_value {
T x; public:
// -- constructors, destructors, and assignment operators --------------------
template <class... Ts> template <class... Ts>
type_erased_value_impl(Ts&&... xs) : x(std::forward<Ts>(xs)...) { type_erased_value_impl(Ts&&... xs) : x_(std::forward<Ts>(xs)...) {
// nop // nop
} }
type_erased_value_impl(const T& value) : x(value) { template <class U, size_t N,
// nop class = typename std::enable_if<std::is_same<T, U[N]>::value>::type>
type_erased_value_impl(const U (&ys)[N]) {
array_copy(x_, ys);
} }
void* get_mutable() override { template <class U, size_t N,
return &x; class = typename std::enable_if<std::is_same<T, U[N]>::value>::type>
type_erased_value_impl(const U (&&ys)[N]) {
array_copy(x_, ys);
} }
const void* get() const override { type_erased_value_impl(type_erased_value_impl&& other)
return &x; : type_erased_value_impl(std::move(other.x_)) {
// nop
} }
void save(serializer& sink) const override { type_erased_value_impl(const type_erased_value_impl& other)
detail::try_serialize(sink, const_cast<T*>(&x)); : type_erased_value_impl(other.x_) {
// nop
} }
void load(deserializer& source) override { // -- overridden modifiers ---------------------------------------------------
detail::try_serialize(source, &x);
}
std::string stringify() const override { void* get_mutable() override {
return deep_to_string(x); return addr_of(x_);
} }
type_erased_value_ptr copy() const override { void load(deserializer& source) override {
return type_erased_value_ptr{new type_erased_value_impl(x)}; detail::try_serialize(source, addr_of(x_));
} }
// -- overridden observers ---------------------------------------------------
rtti_pair type() const override { rtti_pair type() const override {
auto nr = detail::type_nr<T>::value; auto nr = detail::type_nr<T>::value;
return {nr, &typeid(T)}; return {nr, &typeid(T)};
} }
};
template <class T, size_t N>
struct type_erased_value_impl<T[N]> : public type_erased_value {
using array_type = T[N];
array_type xs;
type_erased_value_impl(const T (&ys)[N]) { const void* get() const override {
array_copy(xs, ys); // const is restored when returning from the function
return addr_of(const_cast<T&>(x_));
} }
type_erased_value_impl() { void save(serializer& sink) const override {
// nop detail::try_serialize(sink, addr_of(x_));
} }
void* get_mutable() override { std::string stringify() const override {
T* tmp = xs; return deep_to_string(x_);
return reinterpret_cast<void*>(tmp);
} }
const void* get() const override { type_erased_value_ptr copy() const override {
const T* tmp = xs; return type_erased_value_ptr{new type_erased_value_impl(x_)};
return reinterpret_cast<const void*>(tmp);
} }
void save(serializer& sink) const override { private:
array_serialize(sink, const_cast<array_type&>(xs)); // -- address-of-member utility ----------------------------------------------
}
void load(deserializer& source) override { template <class U>
array_serialize(source, xs); static inline U* addr_of(const U& x) {
return const_cast<U*>(&x);
} }
std::string stringify() const override { template <class U, size_t S>
return deep_to_string(xs); static inline U* addr_of(const U (&x)[S]) {
return const_cast<U*>(static_cast<const U*>(x));
} }
type_erased_value_ptr copy() const override { template <class U>
return new type_erased_value_impl(xs); static inline U* addr_of(std::reference_wrapper<U>& x) {
return &x.get();
} }
rtti_pair type() const override { template <class U>
auto nr = detail::type_nr<T>::value; static inline U* addr_of(const std::reference_wrapper<U>& x) {
return {nr, &typeid(T)}; return &x.get();
} }
template <class U, size_t Len> // -- typeid utility ---------------------------------------------------------
static bool array_cmp_impl(U (&lhs)[Len], const U (&rhs)[Len],
std::true_type) {
for (size_t i = 0; i < Len; ++i)
if (! array_cmp(lhs[i], rhs[i]))
return false;
return true;
}
template <class U, size_t Len> template <class U>
static bool array_cmp_impl(U (&lhs)[Len], const U (&rhs)[Len], static inline const std::type_info* typeid_of(U&) {
std::false_type) { return &typeid(U);
for (size_t i = 0; i < Len; ++i)
if (! detail::safe_equal(lhs[i], rhs[i]))
return false;
return true;
} }
template <class U, size_t Len> template <class U>
static bool array_cmp(U (&lhs)[Len], const U (&rhs)[Len]) { static inline const std::type_info* typeid_of(std::reference_wrapper<U>&) {
std::integral_constant<bool, std::is_array<U>::value> token; return &typeid(U);
return array_cmp_impl(lhs, rhs, token);
} }
// -- array copying utility --------------------------------------------------
template <class U, size_t Len> template <class U, size_t Len>
static void array_copy_impl(U (&lhs)[Len], const U (&rhs)[Len], static void array_copy_impl(U (&x)[Len], const U (&y)[Len], std::true_type) {
std::true_type) {
for (size_t i = 0; i < Len; ++i) for (size_t i = 0; i < Len; ++i)
array_copy(lhs[i], rhs[i]); array_copy(x[i], y[i]);
} }
template <class U, size_t Len> template <class U, size_t Len>
static void array_copy_impl(U (&lhs)[Len], const U (&rhs)[Len], static void array_copy_impl(U (&x)[Len], const U (&y)[Len], std::false_type) {
std::false_type) { std::copy(y, y + Len, x);
std::copy(rhs, rhs + Len, lhs);
} }
template <class U, size_t Len> template <class U, size_t Len>
static void array_copy(U (&lhs)[Len], const U (&rhs)[Len]) { static void array_copy(U (&x)[Len], const U (&y)[Len]) {
std::integral_constant<bool,std::is_array<U>::value> token; std::integral_constant<bool, std::is_array<U>::value> token;
array_copy_impl(lhs, rhs, token); array_copy_impl(x, y, token);
}
template <class P, class U, size_t Len>
static void array_serialize_impl(P& proc, U (&ys)[Len], std::true_type) {
for (auto& y : ys)
array_serialize(proc, y);
} }
template <class P, class U, size_t Len> // -- data members -----------------------------------------------------------
static void array_serialize_impl(P& proc, U (&ys)[Len], std::false_type) {
for (auto& y : ys)
proc & y;
}
template <class P, class U, size_t Len> T x_;
static void array_serialize(P& proc, U (&ys)[Len]) {
std::integral_constant<bool,std::is_array<U>::value> token;
array_serialize_impl(proc, ys, token);
}
}; };
/// @relates type_erased_value
/// Creates a type-erased value of type `T` from `xs`.
template <class T, class... Ts> template <class T, class... Ts>
type_erased_value_ptr make_type_erased(Ts&&... xs) { type_erased_value_ptr make_type_erased_value(Ts&&... xs) {
type_erased_value_ptr result; type_erased_value_ptr result;
result.reset(new type_erased_value_impl<T>(std::forward<Ts>(xs)...)); result.reset(new type_erased_value_impl<T>(std::forward<Ts>(xs)...));
return result; return result;
} }
/// @relates type_erased_value
/// Creates a type-erased view for `x`.
template <class T>
type_erased_value_impl<std::reference_wrapper<T>> make_type_erased_view(T& x) {
return {std::ref(x)};
}
} // namespace caf } // namespace caf
#endif // CAF_TYPE_ERASED_VALUE_HPP #endif // CAF_TYPE_ERASED_VALUE_HPP
...@@ -27,6 +27,29 @@ type_erased_tuple::~type_erased_tuple() { ...@@ -27,6 +27,29 @@ type_erased_tuple::~type_erased_tuple() {
// nop // nop
} }
void type_erased_tuple::load(deserializer& source) {
for (size_t i = 0; i < size(); ++i)
load(i, source);
}
std::string type_erased_tuple::stringify() const {
if (size() == 0)
return "()";
std::string result = "(";
result += stringify(0);
for (size_t i = 1; i < size(); ++i) {
result += ", ";
result += stringify(i);
}
result += ')';
return result;
}
void type_erased_tuple::save(serializer& sink) const {
for (size_t i = 0; i < size(); ++i)
save(i, sink);
}
bool type_erased_tuple::matches(size_t pos, uint16_t nr, bool type_erased_tuple::matches(size_t pos, uint16_t nr,
const std::type_info* ptr) const { const std::type_info* ptr) const {
CAF_ASSERT(pos < size()); CAF_ASSERT(pos < size());
......
...@@ -108,7 +108,7 @@ void fill_builtins(builtins& arr, List, size_t pos) { ...@@ -108,7 +108,7 @@ void fill_builtins(builtins& arr, List, size_t pos) {
using type = typename detail::tl_head<List>::type; using type = typename detail::tl_head<List>::type;
typename detail::tl_tail<List>::type next; typename detail::tl_tail<List>::type next;
arr[pos].first = detail::numbered_type_names[pos]; arr[pos].first = detail::numbered_type_names[pos];
arr[pos].second = &make_type_erased<type>; arr[pos].second = &make_type_erased_value<type>;
fill_builtins(arr, next, pos + 1); fill_builtins(arr, next, pos + 1);
} }
......
...@@ -49,8 +49,10 @@ ...@@ -49,8 +49,10 @@
#include "caf/serializer.hpp" #include "caf/serializer.hpp"
#include "caf/ref_counted.hpp" #include "caf/ref_counted.hpp"
#include "caf/deserializer.hpp" #include "caf/deserializer.hpp"
#include "caf/actor_system.hpp"
#include "caf/proxy_registry.hpp" #include "caf/proxy_registry.hpp"
#include "caf/message_handler.hpp" #include "caf/message_handler.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/primitive_variant.hpp" #include "caf/primitive_variant.hpp"
#include "caf/binary_serializer.hpp" #include "caf/binary_serializer.hpp"
#include "caf/binary_deserializer.hpp" #include "caf/binary_deserializer.hpp"
...@@ -141,6 +143,7 @@ struct fixture { ...@@ -141,6 +143,7 @@ struct fixture {
{4, 5, 6, 7} {4, 5, 6, 7}
}, },
}; };
int ra[3] = {1, 2, 3};
actor_system system; actor_system system;
scoped_execution_unit context; scoped_execution_unit context;
...@@ -171,6 +174,25 @@ struct fixture { ...@@ -171,6 +174,25 @@ struct fixture {
apply(bd, x, xs...); apply(bd, x, xs...);
} }
// serializes `x` and then deserializes and returns the serialized value
template <class T>
T roundtrip(const T& x) {
T result;
deserialize(serialize(x), result);
return result;
}
// converts `x` to a message, serialize it, then deserializes it, and
// finally returns unboxed value
template <class T>
T msg_roundtrip(const T& x) {
message result;
auto tmp = make_message(x);
deserialize(serialize(tmp), result);
CAF_REQUIRE(result.match_elements<T>());
return result.get_as<T>(0);
}
fixture() fixture()
: system(actor_system_config{} : system(actor_system_config{}
.add_message_type<test_enum>("test_enum") .add_message_type<test_enum>("test_enum")
...@@ -269,13 +291,19 @@ CAF_TEST(custom_struct) { ...@@ -269,13 +291,19 @@ CAF_TEST(custom_struct) {
CAF_TEST(atoms) { CAF_TEST(atoms) {
atom_value x; atom_value x;
auto foo = atom("foo"); auto foo = atom("foo");
CAF_CHECK(foo == roundtrip(foo));
CAF_CHECK(foo == msg_roundtrip(foo));
using bar_atom = atom_constant<atom("bar")>; using bar_atom = atom_constant<atom("bar")>;
auto buf = serialize(foo); CAF_CHECK(bar_atom::value == roundtrip(atom("bar")));
deserialize(buf, x); CAF_CHECK(bar_atom::value == msg_roundtrip(atom("bar")));
CAF_CHECK(x == foo); }
buf = serialize(bar_atom::value);
CAF_TEST(raw_arrays) {
auto buf = serialize(ra);
int x[3];
deserialize(buf, x); deserialize(buf, x);
CAF_CHECK(x == bar_atom::value); for (auto i = 0; i < 3; ++i)
CAF_CHECK(ra[i] == x[i]);
} }
CAF_TEST(arrays) { CAF_TEST(arrays) {
...@@ -292,18 +320,58 @@ CAF_TEST(arrays) { ...@@ -292,18 +320,58 @@ CAF_TEST(arrays) {
CAF_TEST(empty_non_pods) { CAF_TEST(empty_non_pods) {
test_empty_non_pod x; test_empty_non_pod x;
auto buf = serialize(x); auto buf = serialize(x);
CAF_REQUIRE(buf.empty());
deserialize(buf, x); deserialize(buf, x);
CAF_CHECK(true); }
std::string hexstr(const std::vector<char>& buf) {
using namespace std;
ostringstream oss;
oss << hex;
oss.fill('0');
for (auto& c : buf) {
oss.width(2);
oss << int{c};
}
return oss.str();
} }
CAF_TEST(messages) { CAF_TEST(messages) {
auto buf = serialize(msg); // serialize original message which uses tuple_vals internally and
// deserialize into a message which uses type_erased_value pointers
message x; message x;
deserialize(buf, x); auto buf1 = serialize(msg);
deserialize(buf1, x);
CAF_CHECK(to_string(msg) == to_string(x)); CAF_CHECK(to_string(msg) == to_string(x));
CAF_CHECK(is_message(x).equal(i32, te, str, rs)); CAF_CHECK(is_message(x).equal(i32, te, str, rs));
// serialize fully dynamic message again (do another roundtrip)
message y;
auto buf2 = serialize(x);
CAF_CHECK(buf1 == buf2);
deserialize(buf2, y);
CAF_CHECK(to_string(msg) == to_string(y));
CAF_CHECK(is_message(y).equal(i32, te, str, rs));
} }
/*
CAF_TEST(actor_addr_via_message) {
auto testee = system.spawn([] {});
auto addr = actor_cast<actor_addr>(testee);
auto addr_msg = make_message(addr);
// serialize original message which uses tuple_vals and
// deserialize into a message which uses message builder
message x;
deserialize(serialize(addr_msg), x);
CAF_CHECK(to_string(addr_msg) == to_string(x));
CAF_CHECK(is_message(x).equal(addr));
// serialize fully dynamic message again (do another roundtrip)
message y;
deserialize(serialize(x), y);
CAF_CHECK(to_string(addr_msg) == to_string(y));
CAF_CHECK(is_message(y).equal(addr));
}
*/
CAF_TEST(multiple_messages) { CAF_TEST(multiple_messages) {
auto m = make_message(rs, te); auto m = make_message(rs, te);
auto buf = serialize(te, m, msg); auto buf = serialize(te, m, msg);
...@@ -317,4 +385,34 @@ CAF_TEST(multiple_messages) { ...@@ -317,4 +385,34 @@ CAF_TEST(multiple_messages) {
CAF_CHECK(is_message(m2).equal(i32, te, str, rs)); CAF_CHECK(is_message(m2).equal(i32, te, str, rs));
} }
CAF_TEST(type_erased_value) {
auto buf = serialize(str);
type_erased_value_ptr ptr{new type_erased_value_impl<std::string>};
binary_deserializer bd{&context, buf.data(), buf.size()};
ptr->load(bd);
CAF_CHECK(str == *reinterpret_cast<const std::string*>(ptr->get()));
}
CAF_TEST(type_erased_view) {
auto str_view = make_type_erased_view(str);
auto buf = serialize(str_view);
std::string res;
deserialize(buf, res);
CAF_CHECK(str == res);
}
CAF_TEST(type_erased_tuple) {
auto tview = make_type_erased_tuple_view(str, i32);
CAF_CHECK(to_string(tview) == deep_to_string(std::make_tuple(str, i32)));
auto buf = serialize(tview);
CAF_REQUIRE(buf.size() > 0);
std::string tmp1;
int32_t tmp2;
deserialize(buf, tmp1, tmp2);
CAF_CHECK(tmp1 == str);
CAF_CHECK(tmp2 == i32);
deserialize(buf, tview);
CAF_CHECK(to_string(tview) == deep_to_string(std::make_tuple(str, i32)));
}
CAF_TEST_FIXTURE_SCOPE_END() 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