Commit 2b4734b9 authored by Dominik Charousset's avatar Dominik Charousset Committed by Joseph Noir

Handle `optional<T>` members in `announce()`

parent 0a86b71c
...@@ -30,9 +30,9 @@ ...@@ -30,9 +30,9 @@
#include "caf/deserializer.hpp" #include "caf/deserializer.hpp"
#include "caf/detail/type_traits.hpp" #include "caf/detail/type_traits.hpp"
#include "caf/detail/types_array.hpp"
#include "caf/detail/abstract_uniform_type_info.hpp" #include "caf/detail/abstract_uniform_type_info.hpp"
#include "caf/detail/types_array.hpp"
namespace caf { namespace caf {
namespace detail { namespace detail {
...@@ -42,62 +42,66 @@ using uniform_type_info_ptr = uniform_type_info_ptr; ...@@ -42,62 +42,66 @@ using uniform_type_info_ptr = uniform_type_info_ptr;
// check if there's a 'push_back' that takes a C::value_type // check if there's a 'push_back' that takes a C::value_type
template <class T> template <class T>
char sfinae_has_push_back(T* ptr, typename T::value_type* val = nullptr, char sfinae_has_push_back(T* ptr, typename T::value_type* val = nullptr,
decltype(ptr->push_back(*val)) * = nullptr); decltype(ptr->push_back(*val)) * = nullptr);
long sfinae_has_push_back(void*); // SFNINAE default long sfinae_has_push_back(void*); // SFNINAE default
template <class T> template <class T>
struct is_stl_compliant_list { struct is_stl_compliant_list {
static constexpr bool value = static constexpr bool value =
detail::is_iterable<T>::value && detail::is_iterable<T>::value
sizeof(sfinae_has_push_back(static_cast<T*>(nullptr))) == sizeof(char); && sizeof(sfinae_has_push_back(static_cast<T*>(nullptr))) == sizeof(char);
}; };
// check if there's an 'insert' that takes a C::value_type // check if there's an 'insert' that takes a C::value_type
template <class T> template <class T>
char sfinae_has_insert(T* ptr, typename T::value_type* val = nullptr, char sfinae_has_insert(T* ptr, typename T::value_type* val = nullptr,
decltype(ptr->insert(*val)) * = nullptr); decltype(ptr->insert(*val)) * = nullptr);
long sfinae_has_insert(void*); // SFNINAE default long sfinae_has_insert(void*); // SFNINAE default
template <class T> template <class T>
struct is_stl_compliant_map { struct is_stl_compliant_map {
static constexpr bool value = static constexpr bool value =
detail::is_iterable<T>::value && detail::is_iterable<T>::value
sizeof(sfinae_has_insert(static_cast<T*>(nullptr))) == sizeof(char); && sizeof(sfinae_has_insert(static_cast<T*>(nullptr))) == sizeof(char);
}; };
template <class T> template <class T>
struct is_stl_pair : std::false_type {}; struct is_stl_pair : std::false_type {
// no members
};
template <class F, typename S> template <class F, typename S>
struct is_stl_pair<std::pair<F, S>> : std::true_type {}; struct is_stl_pair<std::pair<F, S>> : std::true_type {
// no members
};
using primitive_impl = std::integral_constant<int, 0>; using primitive_impl = std::integral_constant<int, 0>;
using list_impl = std::integral_constant<int, 1>; using list_impl = std::integral_constant<int, 1>;
using map_impl = std::integral_constant<int, 2>; using map_impl = std::integral_constant<int, 2>;
using pair_impl = std::integral_constant<int, 3>; using pair_impl = std::integral_constant<int, 3>;
using opt_impl = std::integral_constant<int, 4>;
using recursive_impl = std::integral_constant<int, 9>; using recursive_impl = std::integral_constant<int, 9>;
template <class T> template <class T>
constexpr int impl_id() { constexpr int impl_id() {
return detail::is_primitive<T>::value ? return detail::is_primitive<T>::value
0 : ? 0
(is_stl_compliant_list<T>::value ? : (is_stl_compliant_list<T>::value
1 : ? 1
(is_stl_compliant_map<T>::value ? : (is_stl_compliant_map<T>::value
2 : ? 2
(is_stl_pair<T>::value ? 3 : 9))); : (is_stl_pair<T>::value
? 3
: (detail::is_optional<T>::value
? 4
: 9))));
} }
template <class T> template <class T>
struct deconst_pair { struct deconst_pair {
using type = T; using type = T;
}; };
template <class K, typename V> template <class K, typename V>
...@@ -105,13 +109,10 @@ struct deconst_pair<std::pair<K, V>> { ...@@ -105,13 +109,10 @@ struct deconst_pair<std::pair<K, V>> {
using first_type = typename std::remove_const<K>::type; using first_type = typename std::remove_const<K>::type;
using second_type = typename std::remove_const<V>::type; using second_type = typename std::remove_const<V>::type;
using type = std::pair<first_type, second_type>; using type = std::pair<first_type, second_type>;
}; };
class default_serialize_policy { class default_serialize_policy {
public: public:
template <class T> template <class T>
void operator()(const T& val, serializer* s) const { void operator()(const T& val, serializer* s) const {
std::integral_constant<int, impl_id<T>()> token; std::integral_constant<int, impl_id<T>()> token;
...@@ -122,11 +123,9 @@ class default_serialize_policy { ...@@ -122,11 +123,9 @@ class default_serialize_policy {
void operator()(T& val, deserializer* d) const { void operator()(T& val, deserializer* d) const {
std::integral_constant<int, impl_id<T>()> token; std::integral_constant<int, impl_id<T>()> token;
dimpl(val, d, token); dimpl(val, d, token);
// static_types_array<T>::arr[0]->deserialize(&val, d);
} }
private: private:
template <class T> template <class T>
void simpl(const T& val, serializer* s, primitive_impl) const { void simpl(const T& val, serializer* s, primitive_impl) const {
s->write_value(val); s->write_value(val);
...@@ -154,6 +153,15 @@ class default_serialize_policy { ...@@ -154,6 +153,15 @@ class default_serialize_policy {
(*this)(val.second, s); (*this)(val.second, s);
} }
template <class T>
void simpl(const optional<T>& val, serializer* s, opt_impl) const {
uint8_t flag = val ? 1 : 0;
s->write_value(flag);
if (val) {
(*this)(*val, s);
}
}
template <class T> template <class T>
void simpl(const T& val, serializer* s, recursive_impl) const { void simpl(const T& val, serializer* s, recursive_impl) const {
static_types_array<T>::arr[0]->serialize(&val, s); static_types_array<T>::arr[0]->serialize(&val, s);
...@@ -195,19 +203,30 @@ class default_serialize_policy { ...@@ -195,19 +203,30 @@ class default_serialize_policy {
(*this)(storage.second, d); (*this)(storage.second, d);
} }
template <class T>
void dimpl(optional<T>& val, deserializer* d, opt_impl) const {
auto flag = d->read<uint8_t>();
if (flag != 0) {
T tmp;
(*this)(tmp, d);
val = std::move(tmp);
} else {
val = none;
}
}
template <class T> template <class T>
void dimpl(T& storage, deserializer* d, recursive_impl) const { void dimpl(T& storage, deserializer* d, recursive_impl) const {
static_types_array<T>::arr[0]->deserialize(&storage, d); static_types_array<T>::arr[0]->deserialize(&storage, d);
} }
}; };
class forwarding_serialize_policy { class forwarding_serialize_policy {
public: public:
inline forwarding_serialize_policy(uniform_type_info_ptr uti) inline forwarding_serialize_policy(uniform_type_info_ptr uti)
: m_uti(std::move(uti)) {} : m_uti(std::move(uti)) {
// nop
}
template <class T> template <class T>
void operator()(const T& val, serializer* s) const { void operator()(const T& val, serializer* s) const {
...@@ -220,25 +239,25 @@ class forwarding_serialize_policy { ...@@ -220,25 +239,25 @@ class forwarding_serialize_policy {
} }
private: private:
uniform_type_info_ptr m_uti; uniform_type_info_ptr m_uti;
}; };
template <class T, class AccessPolicy, template <class T, class AccessPolicy,
class SerializePolicy = default_serialize_policy, class SerializePolicy = default_serialize_policy,
bool IsEnum = std::is_enum<T>::value, bool IsEnum = std::is_enum<T>::value,
bool IsEmptyType = std::is_class<T>::value&& std::is_empty<T>::value> bool IsEmptyType = std::is_class<T>::value&& std::is_empty<T>::value>
class member_tinfo : public detail::abstract_uniform_type_info<T> { class member_tinfo : public detail::abstract_uniform_type_info<T> {
public: public:
member_tinfo(AccessPolicy apol, SerializePolicy spol) member_tinfo(AccessPolicy apol, SerializePolicy spol)
: m_apol(std::move(apol)), m_spol(std::move(spol)) {} : m_apol(std::move(apol)), m_spol(std::move(spol)) {
// nop
}
member_tinfo(AccessPolicy apol) : m_apol(std::move(apol)) {} member_tinfo(AccessPolicy apol) : m_apol(std::move(apol)) {
// nop
}
member_tinfo() {} member_tinfo() = default;
void serialize(const void* vptr, serializer* s) const override { void serialize(const void* vptr, serializer* s) const override {
m_spol(m_apol(vptr), s); m_spol(m_apol(vptr), s);
...@@ -278,9 +297,7 @@ class member_tinfo<T, A, S, false, true> ...@@ -278,9 +297,7 @@ class member_tinfo<T, A, S, false, true>
// nop // nop
} }
member_tinfo() { member_tinfo() = default;
// nop
}
void serialize(const void*, serializer*) const override { void serialize(const void*, serializer*) const override {
// nop // nop
...@@ -294,16 +311,15 @@ class member_tinfo<T, A, S, false, true> ...@@ -294,16 +311,15 @@ class member_tinfo<T, A, S, false, true>
template <class T, class AccessPolicy, class SerializePolicy> template <class T, class AccessPolicy, class SerializePolicy>
class member_tinfo<T, AccessPolicy, SerializePolicy, true, false> class member_tinfo<T, AccessPolicy, SerializePolicy, true, false>
: public detail::abstract_uniform_type_info<T> { : public detail::abstract_uniform_type_info<T> {
public:
using value_type = typename std::underlying_type<T>::type; using value_type = typename std::underlying_type<T>::type;
public:
member_tinfo(AccessPolicy apol, SerializePolicy spol) member_tinfo(AccessPolicy apol, SerializePolicy spol)
: m_apol(std::move(apol)), m_spol(std::move(spol)) {} : m_apol(std::move(apol)), m_spol(std::move(spol)) {}
member_tinfo(AccessPolicy apol) : m_apol(std::move(apol)) {} member_tinfo(AccessPolicy apol) : m_apol(std::move(apol)) {}
member_tinfo() {} member_tinfo() = default;
void serialize(const void* p, serializer* s) const override { void serialize(const void* p, serializer* s) const override {
auto val = m_apol(p); auto val = m_apol(p);
...@@ -319,18 +335,17 @@ class member_tinfo<T, AccessPolicy, SerializePolicy, true, false> ...@@ -319,18 +335,17 @@ class member_tinfo<T, AccessPolicy, SerializePolicy, true, false>
private: private:
AccessPolicy m_apol; AccessPolicy m_apol;
SerializePolicy m_spol; SerializePolicy m_spol;
}; };
template <class T, class C> template <class T, class C>
class memptr_access_policy { class memptr_access_policy {
public: public:
inline memptr_access_policy(T C::*memptr) : m_memptr(memptr) {
// nop
}
memptr_access_policy(const memptr_access_policy&) = default; memptr_access_policy(const memptr_access_policy&) = default;
memptr_access_policy& operator=(const memptr_access_policy&) = default; memptr_access_policy& operator=(const memptr_access_policy&) = default;
inline memptr_access_policy(T C::*memptr) : m_memptr(memptr) {}
inline T& operator()(void* vptr) const { inline T& operator()(void* vptr) const {
auto ptr = reinterpret_cast<C*>(vptr); auto ptr = reinterpret_cast<C*>(vptr);
return *ptr.*m_memptr; return *ptr.*m_memptr;
...@@ -355,7 +370,6 @@ class memptr_access_policy { ...@@ -355,7 +370,6 @@ class memptr_access_policy {
template <class C, typename GRes, typename SRes, typename SArg> template <class C, typename GRes, typename SRes, typename SArg>
class getter_setter_access_policy { class getter_setter_access_policy {
public: public:
using getter = GRes (C::*)() const; using getter = GRes (C::*)() const;
...@@ -377,15 +391,12 @@ class getter_setter_access_policy { ...@@ -377,15 +391,12 @@ class getter_setter_access_policy {
static constexpr bool grants_mutable_access = false; static constexpr bool grants_mutable_access = false;
private: private:
getter m_get; getter m_get;
setter m_set; setter m_set;
}; };
template <class T> template <class T>
struct fake_access_policy { struct fake_access_policy {
inline T& operator()(void* vptr) const { inline T& operator()(void* vptr) const {
return *reinterpret_cast<T*>(vptr); return *reinterpret_cast<T*>(vptr);
} }
...@@ -400,7 +411,6 @@ struct fake_access_policy { ...@@ -400,7 +411,6 @@ struct fake_access_policy {
} }
static constexpr bool grants_mutable_access = true; static constexpr bool grants_mutable_access = true;
}; };
template <class T, class C> template <class T, class C>
...@@ -436,15 +446,13 @@ uniform_type_info_ptr new_member_tinfo(GRes (C::*getter)() const, ...@@ -436,15 +446,13 @@ uniform_type_info_ptr new_member_tinfo(GRes (C::*getter)() const,
using value_type = typename detail::rm_const_and_ref<GRes>::type; using value_type = typename detail::rm_const_and_ref<GRes>::type;
using tinfo = member_tinfo<value_type, access_policy, using tinfo = member_tinfo<value_type, access_policy,
forwarding_serialize_policy>; forwarding_serialize_policy>;
return uniform_type_info_ptr( return uniform_type_info_ptr(new tinfo(access_policy(getter, setter),
new tinfo(access_policy(getter, setter), std::move(meminf))); std::move(meminf)));
} }
template <class T> template <class T>
class default_uniform_type_info : public detail::abstract_uniform_type_info<T> { class default_uniform_type_info : public detail::abstract_uniform_type_info<T> {
public: public:
template <class... Ts> template <class... Ts>
default_uniform_type_info(Ts&&... args) { default_uniform_type_info(Ts&&... args) {
push_back(std::forward<Ts>(args)...); push_back(std::forward<Ts>(args)...);
...@@ -457,22 +465,24 @@ class default_uniform_type_info : public detail::abstract_uniform_type_info<T> { ...@@ -457,22 +465,24 @@ class default_uniform_type_info : public detail::abstract_uniform_type_info<T> {
void serialize(const void* obj, serializer* s) const override { void serialize(const void* obj, serializer* s) const override {
// serialize each member // serialize each member
for (auto& m : m_members) m->serialize(obj, s); for (auto& m : m_members) {
m->serialize(obj, s);
}
} }
void deserialize(void* obj, deserializer* d) const override { void deserialize(void* obj, deserializer* d) const override {
// deserialize each member // deserialize each member
for (auto& m : m_members) m->deserialize(obj, d); for (auto& m : m_members) {
m->deserialize(obj, d);
}
} }
protected: protected:
bool pod_mems_equals(const T& lhs, const T& rhs) const override { bool pod_mems_equals(const T& lhs, const T& rhs) const override {
return pod_eq(lhs, rhs); return pod_eq(lhs, rhs);
} }
private: private:
template <class C> template <class C>
typename std::enable_if<std::is_pod<C>::value, bool>::type typename std::enable_if<std::is_pod<C>::value, bool>::type
pod_eq(const C& lhs, const C& rhs) const { pod_eq(const C& lhs, const C& rhs) const {
...@@ -488,8 +498,9 @@ class default_uniform_type_info : public detail::abstract_uniform_type_info<T> { ...@@ -488,8 +498,9 @@ class default_uniform_type_info : public detail::abstract_uniform_type_info<T> {
return false; return false;
} }
// terminates recursion inline void push_back() {
inline void push_back() {} // terminate recursion
}
template <class R, class C, class... Ts> template <class R, class C, class... Ts>
void push_back(R C::*memptr, Ts&&... args) { void push_back(R C::*memptr, Ts&&... args) {
...@@ -535,18 +546,17 @@ class default_uniform_type_info : public detail::abstract_uniform_type_info<T> { ...@@ -535,18 +546,17 @@ class default_uniform_type_info : public detail::abstract_uniform_type_info<T> {
} }
std::vector<uniform_type_info_ptr> m_members; std::vector<uniform_type_info_ptr> m_members;
}; };
template <class... Rs> template <class... Rs>
class default_uniform_type_info<typed_actor< class default_uniform_type_info<typed_actor<Rs...>> :
Rs...>> : public detail::abstract_uniform_type_info<typed_actor<Rs...>> { public detail::abstract_uniform_type_info<typed_actor<Rs...>> {
public: public:
using handle_type = typed_actor<Rs...>; using handle_type = typed_actor<Rs...>;
default_uniform_type_info() { sub_uti = uniform_typeid<actor>(); } default_uniform_type_info() {
sub_uti = uniform_typeid<actor>();
}
void serialize(const void* obj, serializer* s) const override { void serialize(const void* obj, serializer* s) const override {
auto tmp = actor_cast<actor>(deref(obj).address()); auto tmp = actor_cast<actor>(deref(obj).address());
...@@ -560,17 +570,13 @@ class default_uniform_type_info<typed_actor< ...@@ -560,17 +570,13 @@ class default_uniform_type_info<typed_actor<
} }
private: private:
const uniform_type_info* sub_uti;
static handle_type& deref(void* ptr) { static handle_type& deref(void* ptr) {
return *reinterpret_cast<handle_type*>(ptr); return *reinterpret_cast<handle_type*>(ptr);
} }
static const handle_type& deref(const void* ptr) { static const handle_type& deref(const void* ptr) {
return *reinterpret_cast<const handle_type*>(ptr); return *reinterpret_cast<const handle_type*>(ptr);
} }
const uniform_type_info* sub_uti;
}; };
} // namespace detail } // namespace detail
......
...@@ -479,6 +479,16 @@ struct type_at<0, T0, Ts...> { ...@@ -479,6 +479,16 @@ struct type_at<0, T0, Ts...> {
using type = T0; using type = T0;
}; };
template <class T>
struct is_optional : std::false_type {
// no members
};
template <class T>
struct is_optional<optional<T>> : std::true_type {
// no members
};
} // namespace detail } // namespace detail
} // namespace caf } // namespace caf
......
...@@ -335,28 +335,23 @@ struct to_guard<anything, false> { ...@@ -335,28 +335,23 @@ struct to_guard<anything, false> {
template <class T> template <class T>
struct to_guard<detail::wrapped<T>, false> : to_guard<anything> {}; struct to_guard<detail::wrapped<T>, false> : to_guard<anything> {};
template <class T>
struct is_optional : std::false_type {};
template <class T>
struct is_optional<optional<T>> : std::true_type {};
template <class T> template <class T>
struct to_guard<T, true> { struct to_guard<T, true> {
using ct = typename detail::get_callable_trait<T>::type; using ct = typename detail::get_callable_trait<T>::type;
using arg_types = typename ct::arg_types; using arg_types = typename ct::arg_types;
static_assert(detail::tl_size<arg_types>::value == 1, static_assert(detail::tl_size<arg_types>::value == 1,
"projection/guard must take exactly one argument"); "projection/guard must take exactly one argument");
static_assert(is_optional<typename ct::result_type>::value, static_assert(detail::is_optional<typename ct::result_type>::value,
"projection/guard must return an optional value"); "projection/guard must return an optional value");
using value_type = using value_type =
typename std::conditional< typename std::conditional<
std::is_function<T>::value, std::is_function<T>::value,
T*, T*,
T T
>::type; >::type;
static value_type _(value_type val) { return val; } static value_type _(value_type val) {
return val;
}
}; };
template <class T> template <class T>
......
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