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. // 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 <string>
#include <vector> #include <vector>
......
// Showcases custom message types that cannot provide // Showcases custom message types that cannot provide
// friend access to the inspect() function. // friend access to the inspect() function.
// Manual refs: 57-59, 64-66 (ConfiguringActorApplications) // Manual refs: 20-49, 51-76 (TypeInspection)
#include <utility> #include <utility>
#include <iostream> #include <iostream>
...@@ -16,8 +16,8 @@ using namespace caf; ...@@ -16,8 +16,8 @@ using namespace caf;
namespace { namespace {
// identical to our second custom type example, // identical to our second custom type example, but
// but without friend declarations // no friend access for `inspect`
class foo { class foo {
public: public:
foo(int a0 = 0, int b0 = 0) : a_(a0), b_(b0) { foo(int a0 = 0, int b0 = 0) : a_(a0), b_(b0) {
...@@ -49,17 +49,30 @@ private: ...@@ -49,17 +49,30 @@ private:
}; };
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, foo& x) { typename std::enable_if<Inspector::is_saving::value,
// store current state into temporaries, then give the inspector references typename Inspector::result_type>::type
// to temporaries that are written back only when the inspector is saving inspect(Inspector& f, foo& x) {
auto a = x.a(); return f(meta::type_name("foo"), x.a(), x.b());
auto b = x.b(); }
auto save = [&]() -> error {
x.set_a(a); template <class Inspector>
x.set_b(b); typename std::enable_if<Inspector::is_loading::value,
return none; typename Inspector::result_type>::type
}; inspect(Inspector& f, foo& x) {
return f(meta::type_name("foo"), a, b, meta::save_callback(save)); 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) { behavior testee(event_based_actor* self) {
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
******************************************************************************/ ******************************************************************************/
// This file is referenced in the manual, do not modify without updating refs! // 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 #ifndef CAF_ALLOWED_UNSAFE_MESSAGE_TYPE_HPP
#define CAF_ALLOWED_UNSAFE_MESSAGE_TYPE_HPP #define CAF_ALLOWED_UNSAFE_MESSAGE_TYPE_HPP
...@@ -27,10 +27,24 @@ ...@@ -27,10 +27,24 @@
namespace caf { namespace caf {
/// /// Template specializations can whitelist individual
/// types for unsafe message passing operations.
template <class T> template <class T>
struct allowed_unsafe_message_type : std::false_type {}; 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 } // namespace caf
#define CAF_ALLOW_UNSAFE_MESSAGE_TYPE(type_name) \ #define CAF_ALLOW_UNSAFE_MESSAGE_TYPE(type_name) \
......
...@@ -463,21 +463,27 @@ public: ...@@ -463,21 +463,27 @@ public:
template <class T, class... Ts> template <class T, class... Ts>
typename std::enable_if< typename std::enable_if<
allowed_unsafe_message_type<T>::value, is_allowed_unsafe_message_type<T>::value,
error error
>::type >::type
operator()(T&, Ts&&... xs) { operator()(const T&, Ts&&... xs) {
return (*this)(std::forward<Ts>(xs)...); return (*this)(std::forward<Ts>(xs)...);
} }
template <class T, class... Ts> template <class T, class... Ts>
typename std::enable_if< typename std::enable_if<
! meta::is_annotation<T>::value ! meta::is_annotation<T>::value
&& ! allowed_unsafe_message_type<T>::value, && ! is_allowed_unsafe_message_type<T>::value,
error error
>::type >::type
operator()(T& x, Ts&&... xs) { operator()(T&& x, Ts&&... xs) {
auto e = apply(x); 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)...); return e ? e : (*this)(std::forward<Ts>(xs)...);
} }
...@@ -486,6 +492,11 @@ protected: ...@@ -486,6 +492,11 @@ protected:
virtual error apply_builtin(builtin in_out_type, void* in_out) = 0; virtual error apply_builtin(builtin in_out_type, void* in_out) = 0;
private: private:
template <class T>
T& deconst(const T& x) {
return const_cast<T&>(x);
}
template <class D, class T, class U, class F> template <class D, class T, class U, class F>
static typename std::enable_if<D::is_saving::value, error>::type static typename std::enable_if<D::is_saving::value, error>::type
convert_apply(D& self, T& x, U& storage, F assign) { convert_apply(D& self, T& x, U& storage, F assign) {
......
...@@ -32,7 +32,6 @@ ...@@ -32,7 +32,6 @@
#include "caf/optional.hpp" #include "caf/optional.hpp"
#include "caf/make_counted.hpp" #include "caf/make_counted.hpp"
#include "caf/index_mapping.hpp" #include "caf/index_mapping.hpp"
#include "caf/allowed_unsafe_message_type.hpp"
#include "caf/detail/int_list.hpp" #include "caf/detail/int_list.hpp"
#include "caf/detail/apply_args.hpp" #include "caf/detail/apply_args.hpp"
......
...@@ -37,6 +37,15 @@ struct is_annotation { ...@@ -37,6 +37,15 @@ struct is_annotation {
static constexpr bool value = std::is_base_of<annotation, T>::value; 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 meta
} // namespace caf } // namespace caf
......
...@@ -31,7 +31,7 @@ struct hex_formatted_t : annotation { ...@@ -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() { constexpr hex_formatted_t hex_formatted() {
return {}; 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