Commit ce263b17 authored by Dominik Charousset's avatar Dominik Charousset

Allow const T& and T&& for saving data processors

parent 29ab096a
// Showcases how to add custom POD message types.
// Manual refs: 23-26, 29-33, 87-90, 93-96 (ConfiguringActorApplications)
// Manual refs: 24-27, 30-34, 75-78, 81-84 (ConfiguringActorApplications)
// 23-33 (TypeInspection)
#include <string>
#include <vector>
......
// Showcases custom message types that cannot provide
// friend access to the inspect() function.
// Manual refs: 57-59, 64-66 (ConfiguringActorApplications)
// Manual refs: 20-49, 51-76 (TypeInspection)
#include <utility>
#include <iostream>
......@@ -16,8 +16,8 @@ using namespace caf;
namespace {
// identical to our second custom type example,
// but without friend declarations
// identical to our second custom type example, but
// no friend access for `inspect`
class foo {
public:
foo(int a0 = 0, int b0 = 0) : a_(a0), b_(b0) {
......@@ -49,17 +49,30 @@ private:
};
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, foo& x) {
// store current state into temporaries, then give the inspector references
// to temporaries that are written back only when the inspector is saving
auto a = x.a();
auto b = x.b();
auto save = [&]() -> error {
x.set_a(a);
x.set_b(b);
return none;
};
return f(meta::type_name("foo"), a, b, meta::save_callback(save));
typename std::enable_if<Inspector::is_saving::value,
typename Inspector::result_type>::type
inspect(Inspector& f, foo& x) {
return f(meta::type_name("foo"), x.a(), x.b());
}
template <class Inspector>
typename std::enable_if<Inspector::is_loading::value,
typename Inspector::result_type>::type
inspect(Inspector& f, foo& x) {
struct tmp_t {
tmp_t(foo& ref) : x_(ref) {
// nop
}
~tmp_t() {
// write back to x at scope exit
x_.set_a(a);
x_.set_b(b);
}
foo& x_;
int a;
int b;
} tmp{x};
return f(meta::type_name("foo"), tmp.a, tmp.b);
}
behavior testee(event_based_actor* self) {
......
......@@ -18,7 +18,7 @@
******************************************************************************/
// This file is referenced in the manual, do not modify without updating refs!
// ConfiguringActorApplications: 36-40
// ConfiguringActorApplications: 50-54
#ifndef CAF_ALLOWED_UNSAFE_MESSAGE_TYPE_HPP
#define CAF_ALLOWED_UNSAFE_MESSAGE_TYPE_HPP
......@@ -27,10 +27,24 @@
namespace caf {
///
/// Template specializations can whitelist individual
/// types for unsafe message passing operations.
template <class T>
struct allowed_unsafe_message_type : std::false_type {};
template <class T>
struct is_allowed_unsafe_message_type : allowed_unsafe_message_type<T> {};
template <class T>
struct is_allowed_unsafe_message_type<T&> : allowed_unsafe_message_type<T> {};
template <class T>
struct is_allowed_unsafe_message_type<T&&> : allowed_unsafe_message_type<T> {};
template <class T>
struct is_allowed_unsafe_message_type<const T&>
: allowed_unsafe_message_type<T> {};
} // namespace caf
#define CAF_ALLOW_UNSAFE_MESSAGE_TYPE(type_name) \
......
......@@ -463,21 +463,27 @@ public:
template <class T, class... Ts>
typename std::enable_if<
allowed_unsafe_message_type<T>::value,
is_allowed_unsafe_message_type<T>::value,
error
>::type
operator()(T&, Ts&&... xs) {
operator()(const T&, Ts&&... xs) {
return (*this)(std::forward<Ts>(xs)...);
}
template <class T, class... Ts>
typename std::enable_if<
! meta::is_annotation<T>::value
&& ! allowed_unsafe_message_type<T>::value,
&& ! is_allowed_unsafe_message_type<T>::value,
error
>::type
operator()(T& x, Ts&&... xs) {
auto e = apply(x);
operator()(T&& x, Ts&&... xs) {
static_assert(Derived::is_saving::value
|| (! std::is_rvalue_reference<T&&>::value
&& ! std::is_const<
typename std::remove_reference<T>::type
>::value),
"a loading inspector requires mutable lvalue references");
auto e = apply(deconst(x));
return e ? e : (*this)(std::forward<Ts>(xs)...);
}
......@@ -486,6 +492,11 @@ protected:
virtual error apply_builtin(builtin in_out_type, void* in_out) = 0;
private:
template <class T>
T& deconst(const T& x) {
return const_cast<T&>(x);
}
template <class D, class T, class U, class F>
static typename std::enable_if<D::is_saving::value, error>::type
convert_apply(D& self, T& x, U& storage, F assign) {
......
......@@ -32,7 +32,6 @@
#include "caf/optional.hpp"
#include "caf/make_counted.hpp"
#include "caf/index_mapping.hpp"
#include "caf/allowed_unsafe_message_type.hpp"
#include "caf/detail/int_list.hpp"
#include "caf/detail/apply_args.hpp"
......
......@@ -37,6 +37,15 @@ struct is_annotation {
static constexpr bool value = std::is_base_of<annotation, T>::value;
};
template <class T>
struct is_annotation<T&> : is_annotation<T> {};
template <class T>
struct is_annotation<const T&> : is_annotation<T> {};
template <class T>
struct is_annotation<T&&> : is_annotation<T> {};
} // namespace meta
} // namespace caf
......
......@@ -31,7 +31,7 @@ struct hex_formatted_t : annotation {
}
};
/// Allows an inspector to omit the following data field if it is empty.
/// Advises the inspector to format the following data field in hex format.
constexpr hex_formatted_t hex_formatted() {
return {};
}
......
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