Commit 317f90b5 authored by Dominik Charousset's avatar Dominik Charousset

Introduce type numbers, refactor matching

Instead of offering access to a `uniform_type_info` for each element, messages
now offer a `match_element` member function. This function is being used by the
new `try_match` implementation. To increase the performance for match
operations, type tokens are being used. The tokens are 32-bit integers, simply
concatenating the type number for each element. The token is not collision-free
(since all user-defined types are mapped to "0") but outrules many impossible
matches before `try_run` is called to increase overall performance.
parent aaa3715b
......@@ -37,19 +37,19 @@ namespace detail {
*/
template <class T>
class abstract_uniform_type_info : public uniform_type_info {
public:
bool equal_to(const std::type_info& tinfo) const override {
return typeid(T) == tinfo;
const char* name() const override {
return m_name.c_str();
}
const char* name() const { return m_name.c_str(); }
message as_message(void* instance) const override {
return make_message(deref(instance));
}
bool equal_to(const std::type_info& tinfo) const override {
return m_native == &tinfo || *m_native == tinfo;
}
bool equals(const void* lhs, const void* rhs) const override {
return eq(deref(lhs), deref(rhs));
}
......@@ -59,25 +59,30 @@ class abstract_uniform_type_info : public uniform_type_info {
}
protected:
abstract_uniform_type_info(std::string tname) : m_name(std::move(tname)) {
abstract_uniform_type_info(std::string tname)
: m_name(std::move(tname)),
m_native(&typeid(T)) {
// nop
}
static inline const T& deref(const void* ptr) {
static const T& deref(const void* ptr) {
return *reinterpret_cast<const T*>(ptr);
}
static inline T& deref(void* ptr) { return *reinterpret_cast<T*>(ptr); }
static T& deref(void* ptr) {
return *reinterpret_cast<T*>(ptr);
}
// can be overridden in subclasses to compare POD types
// by comparing each individual member
virtual bool pod_mems_equals(const T&, const T&) const { return false; }
virtual bool pod_mems_equals(const T&, const T&) const {
return false;
}
std::string m_name;
const std::type_info* m_native;
private:
template <class C>
typename std::enable_if<std::is_empty<C>::value, bool>::type
eq(const C&, const C&) const {
......@@ -99,7 +104,6 @@ class abstract_uniform_type_info : public uniform_type_info {
eq(const C& lhs, const C& rhs) const {
return pod_mems_equals(lhs, rhs);
}
};
} // namespace detail
......
......@@ -65,14 +65,22 @@ class decorated_tuple : public message_data {
const void* at(size_t pos) const override;
const uniform_type_info* type_at(size_t pos) const override;
bool match_element(size_t pos, uint16_t typenr,
const std::type_info* rtti) const override;
uint32_t type_token() const override;
const char* uniform_name_at(size_t pos) const override;
const std::string* tuple_type_names() const override;
uint16_t type_nr_at(size_t pos) const override;
private:
pointer m_decorated;
vector_type m_mapping;
uint32_t m_type_token;
void init();
......
......@@ -50,15 +50,32 @@ class message_data : public ref_counted {
// accessors
virtual size_t size() const = 0;
virtual message_data* copy() const = 0;
virtual const void* at(size_t pos) const = 0;
virtual const uniform_type_info* type_at(size_t pos) const = 0;
virtual const std::string* tuple_type_names() const = 0;
/**
* Tries to match element at position `pos` to given RTTI.
* @param pos Index of element in question.
* @param typenr Number of queried type or `0` for custom types.
* @param rtti Queried type or `nullptr` for builtin types.
*/
virtual bool match_element(size_t pos, uint16_t typenr,
const std::type_info* rtti) const = 0;
virtual uint32_t type_token() const = 0;
// returns either tdata<...> object or nullptr (default) if tuple
// is not a 'native' implementation
virtual const void* native_data() const;
virtual const char* uniform_name_at(size_t pos) const = 0;
virtual uint16_t type_nr_at(size_t pos) const = 0;
bool equals(const message_data& other) const;
using const_iterator = message_iterator;
......
......@@ -21,6 +21,7 @@
#define CAF_DETAIL_MESSAGE_ITERATOR_HPP
#include <cstddef>
#include <typeinfo>
#include "caf/fwd.hpp"
......@@ -78,7 +79,12 @@ class message_iterator {
const void* value() const;
const uniform_type_info* type() const;
bool match_element(uint16_t typenr, const std::type_info* rtti) const;
template <class T>
const T& value_as() const {
return *reinterpret_cast<const T*>(value());
}
inline message_iterator& operator*() {
return *this;
......
......@@ -26,45 +26,53 @@
#include "caf/atom.hpp"
#include "caf/message.hpp"
#include "caf/uniform_typeid.hpp"
#include "caf/wildcard_position.hpp"
#include "caf/detail/type_nr.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/detail/pseudo_tuple.hpp"
namespace caf {
namespace detail {
bool match_element(const atom_value&, const std::type_info* type,
const message_iterator& iter, void** storage);
bool match_atom_constant(const atom_value&, const std::type_info* type,
const message_iterator& iter, void** storage);
struct meta_element {
atom_value v;
uint16_t typenr;
const std::type_info* type;
bool (*fun)(const atom_value&, const std::type_info*,
const message_iterator&, void**);
bool (*fun)(const meta_element&, const message_iterator&, void**);
};
template <class T>
bool match_element(const meta_element&, const message_iterator&, void**);
bool match_atom_constant(const meta_element&, const message_iterator&, void**);
template <class T, uint16_t TN = detail::type_nr<T>::value>
struct meta_element_factory {
static meta_element create() {
return {static_cast<atom_value>(0), &typeid(T), match_element};
return {static_cast<atom_value>(0), TN, nullptr, match_element};
}
};
template <class T>
struct meta_element_factory<T, 0> {
static meta_element create() {
return {static_cast<atom_value>(0), 0, &typeid(T), match_element};
}
};
template <atom_value V>
struct meta_element_factory<atom_constant<V>> {
struct meta_element_factory<atom_constant<V>, 0> {
static meta_element create() {
return {V, &typeid(atom_value), match_atom_constant};
return {V, detail::type_nr<atom_value>::value,
nullptr, match_atom_constant};
}
};
template <>
struct meta_element_factory<anything> {
struct meta_element_factory<anything, 0> {
static meta_element create() {
return {static_cast<atom_value>(0), nullptr, nullptr};
return {static_cast<atom_value>(0), 0, nullptr, nullptr};
}
};
......
......@@ -52,15 +52,29 @@ struct tup_ptr_access<Pos, Max, false> {
}
};
using tuple_vals_rtti = std::pair<uint16_t, const std::type_info*>;
template <class T, uint16_t N = type_nr<T>::value>
struct tuple_vals_type_helper {
static tuple_vals_rtti get() {
return {N, nullptr};
}
};
template <class T>
struct tuple_vals_type_helper<T, 0> {
static tuple_vals_rtti get() {
return {0, &typeid(T)};
}
};
template <class... Ts>
class tuple_vals : public message_data {
public:
static_assert(sizeof...(Ts) > 0, "tuple_vals is not allowed to be empty");
using super = message_data;
public:
using data_type = std::tuple<Ts...>;
tuple_vals(const tuple_vals&) = default;
......@@ -68,55 +82,79 @@ class tuple_vals : public message_data {
template <class... Us>
tuple_vals(Us&&... args)
: m_data(std::forward<Us>(args)...),
m_types{{uniform_typeid<Ts>()...}} {
m_types{{tuple_vals_type_helper<Ts>::get()...}} {
// nop
}
const void* native_data() const { return &m_data; }
const void* native_data() const override {
return &m_data;
}
void* mutable_native_data() { return &m_data; }
void* mutable_native_data() override {
return &m_data;
}
inline data_type& data() { return m_data; }
data_type& data() {
return m_data;
}
inline const data_type& data() const { return m_data; }
const data_type& data() const {
return m_data;
}
size_t size() const { return sizeof...(Ts); }
size_t size() const override {
return sizeof...(Ts);
}
tuple_vals* copy() const { return new tuple_vals(*this); }
tuple_vals* copy() const override {
return new tuple_vals(*this);
}
const void* at(size_t pos) const {
const void* at(size_t pos) const override {
CAF_REQUIRE(pos < size());
return tup_ptr_access<0, sizeof...(Ts)>::get(pos, m_data);
}
void* mutable_at(size_t pos) {
void* mutable_at(size_t pos) override {
CAF_REQUIRE(pos < size());
return const_cast<void*>(at(pos));
}
const uniform_type_info* type_at(size_t pos) const {
const std::string* tuple_type_names() const override {
// produced name is equal for all instances
static std::string result = get_tuple_type_names(*this);
return &result;
}
bool match_element(size_t pos, uint16_t typenr,
const std::type_info* rtti) const override {
CAF_REQUIRE(pos < size());
return m_types[pos];
auto& et = m_types[pos];
if (et.first != typenr) {
return false;
}
return et.first != 0 || et.second == rtti || *et.second == *rtti;
}
uint32_t type_token() const override {
return make_type_token<Ts...>();
}
bool equals(const message_data& other) const {
if (size() != other.size()) return false;
const tuple_vals* o = dynamic_cast<const tuple_vals*>(&other);
if (o) {
return m_data == (o->m_data);
const char* uniform_name_at(size_t pos) const override {
auto& et = m_types[pos];
if (et.first != 0) {
return numbered_type_names[et.first - 1];
}
return message_data::equals(other);
return uniform_typeid(*et.second)->name();
}
const std::string* tuple_type_names() const override {
// produced name is equal for all instances
static std::string result = get_tuple_type_names(*this);
return &result;
uint16_t type_nr_at(size_t pos) const override {
return m_types[pos].first;
}
private:
data_type m_data;
std::array<const uniform_type_info*, sizeof...(Ts)> m_types;
std::array<tuple_vals_rtti, sizeof...(Ts)> m_types;
};
} // namespace detail
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2014 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_DETAIL_TYPE_NR_HPP
#define CAF_DETAIL_TYPE_NR_HPP
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdint>
#include "caf/fwd.hpp"
#include "caf/detail/type_list.hpp"
namespace caf {
namespace detail {
#define CAF_DETAIL_TYPE_NR(number, tname) \
template <> \
struct type_nr<tname> { \
static constexpr uint16_t value = number; \
};
template <class T,
bool IntegralConstant = std::is_integral<T>::value,
size_t = sizeof(T)>
struct type_nr_helper {
static constexpr uint16_t value = 0;
};
template <class T>
struct type_nr {
static constexpr uint16_t value = type_nr_helper<T>::value;
};
template <>
struct type_nr<void> {
static constexpr uint16_t value = 0;
};
using strmap = std::map<std::string, std::string>;
// WARNING: types are sorted by uniform name
CAF_DETAIL_TYPE_NR( 1, actor) // @actor
CAF_DETAIL_TYPE_NR( 2, actor_addr) // @addr
CAF_DETAIL_TYPE_NR( 3, atom_value) // @atom
CAF_DETAIL_TYPE_NR( 4, channel) // @channel
CAF_DETAIL_TYPE_NR( 5, std::vector<char>) // @charbuf
CAF_DETAIL_TYPE_NR( 6, down_msg) // @down
CAF_DETAIL_TYPE_NR( 7, duration) // @duration
CAF_DETAIL_TYPE_NR( 8, exit_msg) // @exit
CAF_DETAIL_TYPE_NR( 9, group) // @group
CAF_DETAIL_TYPE_NR(10, group_down_msg) // @group_down
CAF_DETAIL_TYPE_NR(11, int16_t) // @i16
CAF_DETAIL_TYPE_NR(12, int32_t) // @i32
CAF_DETAIL_TYPE_NR(13, int64_t) // @i64
CAF_DETAIL_TYPE_NR(14, int8_t) // @i8
CAF_DETAIL_TYPE_NR(15, long double) // @ldouble
CAF_DETAIL_TYPE_NR(16, message) // @message
CAF_DETAIL_TYPE_NR(17, message_id) // @message_id
CAF_DETAIL_TYPE_NR(18, node_id) // @node
CAF_DETAIL_TYPE_NR(19, std::string) // @str
CAF_DETAIL_TYPE_NR(20, strmap) // @strmap
CAF_DETAIL_TYPE_NR(21, std::set<std::string>) // @strset
CAF_DETAIL_TYPE_NR(22, std::vector<std::string>) // @strvec
CAF_DETAIL_TYPE_NR(23, sync_exited_msg) // @sync_exited
CAF_DETAIL_TYPE_NR(24, sync_timeout_msg) // @sync_timeout
CAF_DETAIL_TYPE_NR(25, timeout_msg) // @timeout
CAF_DETAIL_TYPE_NR(26, uint16_t) // @u16
CAF_DETAIL_TYPE_NR(27, std::u16string) // @u16_str
CAF_DETAIL_TYPE_NR(28, uint32_t) // @u32
CAF_DETAIL_TYPE_NR(29, std::u32string) // @u32_str
CAF_DETAIL_TYPE_NR(30, uint64_t) // @u64
CAF_DETAIL_TYPE_NR(31, uint8_t) // @u8
CAF_DETAIL_TYPE_NR(32, unit_t) // @unit
CAF_DETAIL_TYPE_NR(33, bool) // bool
CAF_DETAIL_TYPE_NR(34, double) // double
CAF_DETAIL_TYPE_NR(35, float) // float
static constexpr size_t type_nrs = 36;
extern const char* numbered_type_names[];
template <class T>
struct type_nr_helper<T, true, 1> {
static constexpr uint16_t value = std::is_signed<T>::value
? type_nr<int8_t>::value
: type_nr<uint8_t>::value;
};
template <class T>
struct type_nr_helper<T, true, 2> {
static constexpr uint16_t value = std::is_signed<T>::value
? type_nr<int16_t>::value
: type_nr<uint16_t>::value;
};
template <class T>
struct type_nr_helper<T, true, 4> {
static constexpr uint16_t value = std::is_signed<T>::value
? type_nr<int32_t>::value
: type_nr<uint32_t>::value;
};
template <class T>
struct type_nr_helper<T, true, 8> {
static constexpr uint16_t value = std::is_signed<T>::value
? type_nr<int64_t>::value
: type_nr<uint64_t>::value;
};
template <uint32_t R, uint16_t... Is>
struct type_token_helper;
template <uint32_t R>
struct type_token_helper<R> : std::integral_constant<uint32_t, R> {
// nop
};
template <uint32_t R, uint16_t I, uint16_t... Is>
struct type_token_helper<R, I, Is...> : type_token_helper<(R << 6) | I, Is...> {
// nop
};
template <class... Ts>
constexpr uint32_t make_type_token() {
return type_token_helper<0xFFFFFFFF, type_nr<Ts>::value...>::value;
}
template <class T>
struct make_type_token_from_list_helper;
template <class... Ts>
struct make_type_token_from_list_helper<type_list<Ts...>>
: type_token_helper<0xFFFFFFFF, type_nr<Ts>::value...> {
// nop
};
template <class T>
constexpr uint32_t make_type_token_from_list() {
return make_type_token_from_list_helper<T>::value;
}
} // namespace detail
} // namespace caf
#endif // CAF_DETAIL_TYPE_NR_HPP
......@@ -69,11 +69,13 @@ class uniform_type_info_map {
virtual pointer by_uniform_name(const std::string& name) = 0;
virtual pointer by_type_nr(uint16_t) const = 0;
virtual pointer by_rtti(const std::type_info& ti) const = 0;
virtual std::vector<pointer> get_all() const = 0;
virtual pointer insert(uniform_type_info_ptr uti) = 0;
virtual pointer insert(const std::type_info*, uniform_type_info_ptr) = 0;
static uniform_type_info_map* create_singleton();
......
......@@ -71,14 +71,20 @@ class match_expr_case : public get_lifted_fun<Expr, Projecs, Signature>::type {
using pattern = Pattern;
using filtered_pattern =
typename detail::tl_filter_not_type<
Pattern,
anything
>::type;
Pattern,
anything
>::type;
static constexpr bool has_wildcard =
!std::is_same<
pattern,
filtered_pattern
>::value;
static constexpr uint32_t type_token = make_type_token_from_list<pattern>();
using intermediate_tuple =
typename detail::tl_apply<
filtered_pattern,
detail::pseudo_tuple
>::type;
typename detail::tl_apply<
filtered_pattern,
detail::pseudo_tuple
>::type;
};
template <class Expr, class Transformers, class Pattern>
......@@ -225,7 +231,8 @@ Result unroll_expr(PPFPs& fs, long_constant<N>, Msg& msg) {
using ft = typename std::decay<decltype(f)>::type;
meta_elements<typename ft::pattern> ms;
typename ft::intermediate_tuple targs;
if (try_match(msg, ms.arr.data(), ms.arr.size(), targs.data)) {
if ((ft::has_wildcard || ft::type_token == msg.type_token())
&& try_match(msg, ms.arr.data(), ms.arr.size(), targs.data)) {
auto is = detail::get_indices(targs);
auto res = detail::apply_args(f, is, deduce_const(msg, targs));
if (unroll_expr_result_valid(res)) {
......@@ -235,23 +242,6 @@ Result unroll_expr(PPFPs& fs, long_constant<N>, Msg& msg) {
return none;
}
template <class PPFPs>
uint64_t calc_bitmask(PPFPs&, minus1l, const std::type_info&, const message&) {
return 0x00;
}
template <class Case, long N>
uint64_t calc_bitmask(Case& fs, long_constant<N>,
const std::type_info& tinf, const message& msg) {
auto& f = get<N>(fs);
using ft = typename std::decay<decltype(f)>::type;
meta_elements<typename ft::pattern> ms;
uint64_t result = try_match(msg, ms.arr.data(), ms.arr.size(), nullptr)
? (0x01 << N)
: 0x00;
return result | calc_bitmask(fs, long_constant<N - 1l>(), tinf, msg);
}
template <bool IsManipulator, typename T0, typename T1>
struct mexpr_fwd_ {
using type = T1;
......
......@@ -127,10 +127,15 @@ class message {
const void* at(size_t p) const;
/**
* Gets {@link uniform_type_info uniform type information}
* of the element at position @p p.
* Tries to match element at position `pos` to given RTTI.
* @param pos Index of element in question.
* @param typenr Number of queried type or `0` for custom types.
* @param rtti Queried type or `nullptr` for builtin types.
*/
const uniform_type_info* type_at(size_t p) const;
bool match_element(size_t pos, uint16_t typenr,
const std::type_info* rtti) const;
const char* uniform_name_at(size_t pos) const;
/**
* Returns @c true if `*this == other, otherwise false.
......@@ -149,7 +154,7 @@ class message {
*/
template <class T>
inline const T& get_as(size_t p) const {
CAF_REQUIRE(*(type_at(p)) == typeid(T));
CAF_REQUIRE(match_element(p, detail::type_nr<T>::value, &typeid(T)));
return *reinterpret_cast<const T*>(at(p));
}
......@@ -158,7 +163,7 @@ class message {
*/
template <class T>
inline T& get_as_mutable(size_t p) {
CAF_REQUIRE(*(type_at(p)) == typeid(T));
CAF_REQUIRE(match_element(p, detail::type_nr<T>::value, &typeid(T)));
return *reinterpret_cast<T*>(mutable_at(p));
}
......@@ -207,6 +212,10 @@ class message {
/** @cond PRIVATE */
inline uint32_t type_token() const {
return m_vals->type_token();
}
inline void force_detach() {
m_vals.detach();
}
......
......@@ -148,8 +148,8 @@ class invoke_policy {
} else {
CAF_LOGF_DEBUG("res = " << to_string(*res));
if (res->size() == 2
&& res->type_at(0) == uniform_typeid<atom_value>()
&& res->type_at(1) == uniform_typeid<uint64_t>()
&& res->match_element(0, detail::type_nr<atom_value>::value, nullptr)
&& res->match_element(1, detail::type_nr<uint64_t>::value, nullptr)
&& res->template get_as<atom_value>(0) == atom("MESSAGE_ID")) {
CAF_LOG_DEBUG("message handler returned a message id wrapper");
auto id = res->template get_as<uint64_t>(1);
......@@ -289,7 +289,7 @@ class invoke_policy {
const message& msg = node->msg;
auto mid = node->mid;
if (msg.size() == 1) {
if (msg.type_at(0)->equal_to(typeid(exit_msg))) {
if (msg.match_element(0, detail::type_nr<exit_msg>::value, nullptr)) {
auto& em = msg.get_as<exit_msg>(0);
CAF_REQUIRE(!mid.valid());
// make sure to get rid of attachables if they're no longer needed
......@@ -301,7 +301,7 @@ class invoke_policy {
}
return msg_type::normal_exit;
}
} else if (msg.type_at(0)->equal_to(typeid(timeout_msg))) {
} else if (msg.match_element(0, detail::type_nr<timeout_msg>::value, nullptr)) {
auto& tm = msg.get_as<timeout_msg>(0);
auto tid = tm.timeout_id;
CAF_REQUIRE(!mid.valid());
......@@ -310,8 +310,8 @@ class invoke_policy {
}
return self->waits_for_timeout(tid) ? msg_type::inactive_timeout
: msg_type::expired_timeout;
} else if (msg.type_at(0)->equal_to(typeid(sync_timeout_msg))
&& mid.is_response()) {
} else if (mid.is_response()
&& msg.match_element(0, detail::type_nr<sync_timeout_msg>::value, nullptr)) {
return msg_type::timeout_response;
}
}
......
......@@ -72,7 +72,7 @@ template <class T>
optional<T> from_string(const std::string& what) {
auto uti = uniform_typeid<T>();
auto uv = from_string_impl(what);
if (!uv || (*uv->ti) != typeid(T)) {
if (!uv || uv->ti != uti) {
// try again using the type name
std::string tmp = uti->name();
tmp += " ( ";
......@@ -80,7 +80,7 @@ optional<T> from_string(const std::string& what) {
tmp += " )";
uv = from_string_impl(tmp);
}
if (uv && (*uv->ti) == typeid(T)) {
if (uv && uv->ti == uti) {
return T{std::move(*reinterpret_cast<T*>(uv->val))};
}
return none;
......
......@@ -158,9 +158,9 @@ uniform_value make_uniform_value(const uniform_type_info* ti, Ts&&... args) {
* \@_::foo
*/
class uniform_type_info {
public:
friend bool operator==(const uniform_type_info& lhs,
const uniform_type_info& rhs);
const uniform_type_info& rhs);
// disable copy and move constructors
uniform_type_info(uniform_type_info&&) = delete;
......@@ -170,8 +170,6 @@ class uniform_type_info {
uniform_type_info& operator=(uniform_type_info&&) = delete;
uniform_type_info& operator=(const uniform_type_info&) = delete;
public:
virtual ~uniform_type_info();
/**
......@@ -254,9 +252,15 @@ class uniform_type_info {
*/
virtual message as_message(void* instance) const = 0;
protected:
/**
* Returns a unique number for builtin types or 0.
*/
uint16_t type_nr() const {
return m_type_nr;
}
uniform_type_info() = default;
protected:
uniform_type_info(uint16_t typenr = 0);
template <class T>
uniform_value create_impl(const uniform_value& other) const {
......@@ -268,6 +272,8 @@ class uniform_type_info {
return make_uniform_value<T>(this);
}
private:
uint16_t m_type_nr;
};
using uniform_type_info_ptr = std::unique_ptr<uniform_type_info>;
......@@ -294,38 +300,6 @@ inline bool operator!=(const uniform_type_info& lhs,
return !(lhs == rhs);
}
/**
* @relates uniform_type_info
*/
inline bool operator==(const uniform_type_info& lhs,
const std::type_info& rhs) {
return lhs.equal_to(rhs);
}
/**
* @relates uniform_type_info
*/
inline bool operator!=(const uniform_type_info& lhs,
const std::type_info& rhs) {
return !(lhs.equal_to(rhs));
}
/**
* @relates uniform_type_info
*/
inline bool operator==(const std::type_info& lhs,
const uniform_type_info& rhs) {
return rhs.equal_to(lhs);
}
/**
* @relates uniform_type_info
*/
inline bool operator!=(const std::type_info& lhs,
const uniform_type_info& rhs) {
return !(rhs.equal_to(lhs));
}
} // namespace caf
#endif // CAF_UNIFORM_TYPE_INFO_HPP
......@@ -22,16 +22,36 @@
#include <typeinfo>
#include "caf/detail/type_nr.hpp"
namespace caf {
class uniform_type_info;
/**
* Returns the uniform type info for the builtin type identified by `nr`.
* @pre `nr > 0 && nr < detail::type_nrs`
*/
const uniform_type_info* uniform_typeid_by_nr(uint16_t nr);
/**
* Returns the uniform type info for type `tinf`.
* @param allow_nullptr if set to true, this function returns `nullptr` instead
* of throwing an exception on error
*/
const uniform_type_info* uniform_typeid(const std::type_info& tinf,
bool allow_nullptr = false);
/**
* Returns the uniform type info for type `T`.
* @param allow_nullptr if set to true, this function returns `nullptr` instead
* of throwing an exception on error
*/
template <class T>
const uniform_type_info* uniform_typeid(bool allow_nullptr = false) {
return uniform_typeid(typeid(T), allow_nullptr);
auto nr = detail::type_nr<T>::value;
return (nr != 0) ? uniform_typeid_by_nr(nr)
: uniform_typeid(typeid(T), allow_nullptr);
}
} // namespace caf
......
......@@ -27,7 +27,9 @@ void* decorated_tuple::mutable_at(size_t pos) {
return m_decorated->mutable_at(m_mapping[pos]);
}
size_t decorated_tuple::size() const { return m_mapping.size(); }
size_t decorated_tuple::size() const {
return m_mapping.size();
}
decorated_tuple* decorated_tuple::copy() const {
return new decorated_tuple(*this);
......@@ -38,22 +40,39 @@ const void* decorated_tuple::at(size_t pos) const {
return m_decorated->at(m_mapping[pos]);
}
const uniform_type_info* decorated_tuple::type_at(size_t pos) const {
CAF_REQUIRE(pos < size());
return m_decorated->type_at(m_mapping[pos]);
bool decorated_tuple::match_element(size_t pos, uint16_t typenr,
const std::type_info* rtti) const {
return m_decorated->match_element(m_mapping[pos], typenr, rtti);
}
uint32_t decorated_tuple::type_token() const {
return m_type_token;
}
const char* decorated_tuple::uniform_name_at(size_t pos) const {
return m_decorated->uniform_name_at(m_mapping[pos]);
}
uint16_t decorated_tuple::type_nr_at(size_t pos) const {
return m_decorated->type_nr_at(m_mapping[pos]);
}
void decorated_tuple::init() {
CAF_REQUIRE(m_mapping.empty()
|| *(std::max_element(m_mapping.begin(), m_mapping.end()))
< static_cast<const pointer&>(m_decorated)->size());
// calculate type token
for (size_t i = 0; i < m_mapping.size(); ++i) {
m_type_token <<= 6;
m_type_token |= m_decorated->type_nr_at(m_mapping[i]);
}
}
void decorated_tuple::init(size_t offset) {
const pointer& dec = m_decorated;
if (offset < dec->size()) {
if (offset < m_decorated->size()) {
size_t i = offset;
m_mapping.resize(dec->size() - offset);
size_t new_size = m_decorated->size() - offset;
m_mapping.resize(new_size);
std::generate(m_mapping.begin(), m_mapping.end(), [&] { return i++; });
}
init();
......@@ -61,12 +80,14 @@ void decorated_tuple::init(size_t offset) {
decorated_tuple::decorated_tuple(pointer d, vector_type&& v)
: m_decorated(std::move(d)),
m_mapping(std::move(v)) {
m_mapping(std::move(v)),
m_type_token(0xFFFFFFFF) {
init();
}
decorated_tuple::decorated_tuple(pointer d, size_t offset)
: m_decorated(std::move(d)) {
: m_decorated(std::move(d)),
m_type_token(0xFFFFFFFF) {
init(offset);
}
......
......@@ -56,9 +56,13 @@ const void* message::at(size_t p) const {
return m_vals->at(p);
}
const uniform_type_info* message::type_at(size_t p) const {
CAF_REQUIRE(m_vals);
return m_vals->type_at(p);
bool message::match_element(size_t pos, uint16_t typenr,
const std::type_info* rtti) const {
return m_vals->match_element(pos, typenr, rtti);
}
const char* message::uniform_name_at(size_t pos) const {
return m_vals->uniform_name_at(pos);
}
bool message::equals(const message& other) const {
......
......@@ -31,19 +31,24 @@ class message_builder::dynamic_msg_data : public detail::message_data {
using message_data::const_iterator;
dynamic_msg_data() {
dynamic_msg_data() : m_type_token(0xFFFFFFFF) {
// nop
}
dynamic_msg_data(const dynamic_msg_data& other) {
dynamic_msg_data(const dynamic_msg_data& other)
: m_type_token(other.m_type_token) {
for (auto& d : other.m_elements) {
m_elements.push_back(d->copy());
}
}
dynamic_msg_data(std::vector<uniform_value>&& data)
: m_elements(std::move(data)) {
// nop
: m_elements(std::move(data)),
m_type_token(0xFFFFFFFF) {
for (auto& e : m_elements) {
m_type_token <<= 6;
m_type_token |= e->ti->type_nr();
}
}
~dynamic_msg_data();
......@@ -66,9 +71,23 @@ class message_builder::dynamic_msg_data : public detail::message_data {
return new dynamic_msg_data(*this);
}
const uniform_type_info* type_at(size_t pos) const override {
CAF_REQUIRE(pos < size());
return m_elements[pos]->ti;
bool match_element(size_t pos, uint16_t typenr,
const std::type_info* rtti) const override {
CAF_REQUIRE(typenr != 0 || rtti != nullptr);
auto uti = m_elements[pos]->ti;
return uti->type_nr() == typenr || uti->equal_to(*rtti);
}
const char* uniform_name_at(size_t pos) const override {
return m_elements[pos]->ti->name();
}
uint16_t type_nr_at(size_t pos) const override {
return m_elements[pos]->ti->type_nr();
}
uint32_t type_token() const override {
return m_type_token;
}
const std::string* tuple_type_names() const override {
......@@ -76,6 +95,7 @@ class message_builder::dynamic_msg_data : public detail::message_data {
}
std::vector<uniform_value> m_elements;
uint32_t m_type_token;
};
message_builder::dynamic_msg_data::~dynamic_msg_data() {
......
......@@ -27,13 +27,31 @@ message_data::message_data() {
}
bool message_data::equals(const message_data& other) const {
auto full_eq = [](const message_iterator& lhs, const message_iterator& rhs) {
return lhs.type() == rhs.type()
&& lhs.type()->equals(lhs.value(), rhs.value());
};
return this == &other
|| (size() == other.size()
&& std::equal(begin(), end(), other.begin(), full_eq));
if (this == &other) {
return true;
}
auto n = size();
if (n != other.size()) {
return false;
}
// step 1, get and compare type names
std::vector<const char*> type_names;
for (size_t i = 0; i < n; ++i) {
auto lhs = uniform_name_at(i);
auto rhs = other.uniform_name_at(i);
if (lhs != rhs && strcmp(lhs, rhs) != 0) {
return false; // type mismatch
}
type_names.push_back(lhs);
}
// step 2: compare each value individually
for (size_t i = 0; i < n; ++i) {
auto uti = uniform_type_info::from(type_names[i]);
if (!uti->equals(at(i), other.at(i))) {
return false;
}
}
return true;
}
const void* message_data::native_data() const {
......@@ -47,9 +65,8 @@ void* message_data::mutable_native_data() {
std::string get_tuple_type_names(const detail::message_data& tup) {
std::string result = "@<>";
for (size_t i = 0; i < tup.size(); ++i) {
auto uti = tup.type_at(i);
result += "+";
result += uti->name();
result += tup.uniform_name_at(i);
}
return result;
}
......
......@@ -34,8 +34,9 @@ const void* message_iterator::value() const {
return m_data->at(m_pos);
}
const uniform_type_info* message_iterator::type() const {
return m_data->type_at(m_pos);
bool message_iterator::match_element(uint16_t typenr,
const std::type_info* rtti) const {
return m_data->match_element(m_pos, typenr, rtti);
}
} // namespace detail
......
......@@ -25,12 +25,13 @@ namespace detail {
using pattern_iterator = const meta_element*;
bool is_wildcard(const meta_element& me) {
return me.type == nullptr;
return me.typenr == 0 && me.type == nullptr;
}
bool match_element(const atom_value&, const std::type_info* type,
const message_iterator& iter, void** storage) {
if (!iter.type()->equal_to(*type)) {
bool match_element(const meta_element& me, const message_iterator& iter,
void** storage) {
CAF_REQUIRE(me.typenr != 0 || me.type != nullptr);
if (!iter.match_element(me.typenr, me.type)) {
return false;
}
if (storage) {
......@@ -39,23 +40,23 @@ bool match_element(const atom_value&, const std::type_info* type,
return true;
}
bool match_atom_constant(const atom_value& value, const std::type_info* type,
const message_iterator& iter, void** storage) {
auto uti = iter.type();
if (!uti->equal_to(*type)) {
bool match_atom_constant(const meta_element& me, const message_iterator& iter,
void** storage) {
CAF_REQUIRE(me.typenr == detail::type_nr<atom_value>::value);
if (!iter.match_element(detail::type_nr<atom_value>::value, nullptr)) {
return false;
}
if (storage) {
if (!uti->equals(iter.value(), &value)) {
if (iter.value_as<atom_value>() != me.v) {
return false;
}
// This assignment casts `uniform_type_info*` to `atom_constant<V>*`.
// This assignment casts `atom_value` to `atom_constant<V>*`.
// This type violation could theoretically cause undefined behavior.
// However, `uti` does have an address that is guaranteed to be valid
// throughout the runtime of the program and the atom constant
// does not have any members. Hence, this is nonetheless safe since
// we are never actually going to dereference the pointer.
*storage = const_cast<void*>(reinterpret_cast<const void*>(uti));
*storage = const_cast<void*>(iter.value());
}
return true;
}
......@@ -113,7 +114,7 @@ bool try_match(message_iterator mbegin, message_iterator mend,
return false; // no submatch found
}
// inspect current element
if (!pbegin->fun(pbegin->v, pbegin->type, mbegin, storage.current())) {
if (!pbegin->fun(*pbegin, mbegin, storage.current())) {
// type mismatch
return false;
}
......
......@@ -58,9 +58,13 @@ uniform_value_t::~uniform_value_t() {
// nop
}
const uniform_type_info* announce(const std::type_info&,
uniform_type_info_ptr utype) {
return uti_map().insert(std::move(utype));
const uniform_type_info* announce(const std::type_info& ti,
uniform_type_info_ptr utype) {
return uti_map().insert(&ti, std::move(utype));
}
uniform_type_info::uniform_type_info(uint16_t typenr) : m_type_nr(typenr) {
// nop
}
uniform_type_info::~uniform_type_info() {
......@@ -97,6 +101,11 @@ std::vector<const uniform_type_info*> uniform_type_info::instances() {
return uti_map().get_all();
}
const uniform_type_info* uniform_typeid_by_nr(uint16_t nr) {
CAF_REQUIRE(nr > 0 && nr < detail::type_nrs);
return uti_map().by_type_nr(nr);
}
const uniform_type_info* uniform_typeid(const std::type_info& tinf,
bool allow_nullptr) {
auto result = uti_map().by_rtti(tinf);
......
......@@ -42,6 +42,7 @@
#include "caf/message_builder.hpp"
#include "caf/detail/logging.hpp"
#include "caf/detail/type_nr.hpp"
#include "caf/detail/safe_equal.hpp"
#include "caf/detail/singletons.hpp"
#include "caf/detail/scope_guard.hpp"
......@@ -52,82 +53,42 @@
namespace caf {
namespace detail {
namespace {
const char* mapped_type_names[] = {
"bool",
const char* numbered_type_names[] = {
"@actor",
"@addr",
"@atom",
"@channel",
"@charbuf",
"@down",
"@duration",
"@exit",
"@group",
"@group_down",
"@i16",
"@i32",
"@i64",
"@i8",
"@ldouble",
"@message",
"@message_id",
"@node",
"@str",
"@strmap",
"@strset",
"@strvec",
"@sync_exited",
"@sync_timeout",
"@timeout",
"@unit",
"double",
"float",
"@ldouble",
"@str",
"@u16",
"@u16str",
"@u32",
"@u32str",
"@strmap",
"@charbuf",
"@strvec",
"@strset"
};
// the order of this table must be *identical* to mapped_type_names
using static_type_table = type_list<bool,
actor,
actor_addr,
atom_value,
channel,
down_msg,
duration,
exit_msg,
group,
group_down_msg,
message,
message_id,
node_id,
sync_exited_msg,
sync_timeout_msg,
timeout_msg,
unit_t,
double,
float,
long double,
std::string,
std::u16string,
std::u32string,
std::map<std::string, std::string>,
std::vector<char>,
std::vector<std::string>,
std::set<std::string>>;
} // namespace <anonymous>
template <class T>
constexpr const char* mapped_name() {
return mapped_type_names[detail::tl_find<static_type_table, T>::value];
}
// maps sizeof(T) => {unsigned name, signed name}
/* extern */ const char* mapped_int_names[][2] = {
{nullptr, nullptr}, // no int type with 0 bytes
{"@u8", "@i8"},
{"@u16", "@i16"},
{nullptr, nullptr}, // no int type with 3 bytes
{"@u32", "@i32"},
{nullptr, nullptr}, // no int type with 5 bytes
{nullptr, nullptr}, // no int type with 6 bytes
{nullptr, nullptr}, // no int type with 7 bytes
{"@u64", "@i64"}
"@u64",
"@u8",
"@unit",
"bool",
"double",
"float"
};
namespace {
......@@ -289,7 +250,7 @@ void serialize_impl(const message& tup, serializer* sink) {
}
sink->begin_object(uti);
for (size_t i = 0; i < tup.size(); ++i) {
tup.type_at(i)->serialize(tup.at(i), sink);
uniform_type_info::from(tup.uniform_name_at(i))->serialize(tup.at(i), sink);
}
sink->end_object();
}
......@@ -432,39 +393,53 @@ deserialize_impl(T& iterable, deserializer* sink) {
sp(iterable, sink);
}
bool types_equal(const std::type_info* lhs, const std::type_info* rhs) {
// in some cases (when dealing with dynamic libraries),
// address can be different although types are equal
return lhs == rhs || *lhs == *rhs;
}
template <class T>
class uti_base : public uniform_type_info {
protected:
uti_base() : m_native(&typeid(T)) {
class uti_impl : public uniform_type_info {
public:
static_assert(detail::type_nr<T>::value > 0, "type_nr<T>::value == 0");
uti_impl() : uniform_type_info(detail::type_nr<T>::value) {
// nop
}
bool equal_to(const std::type_info& ti) const override {
return types_equal(m_native, &ti);
const char* name() const override {
return numbered_type_names[detail::type_nr<T>::value - 1];
}
bool equal_to(const std::type_info&) const override {
// CAF never compares builtin types using RTTI
return false;
}
bool equals(const void* lhs, const void* rhs) const override {
// return detail::safe_equal(deref(lhs), deref(rhs));
// return deref(lhs) == deref(rhs);
return eq(deref(lhs), deref(rhs));
}
uniform_value create(const uniform_value& other) const override {
return create_impl<T>(other);
}
message as_message(void* instance) const override {
return make_message(deref(instance));
}
static inline const T& deref(const void* ptr) {
return *reinterpret_cast<const T*>(ptr);
}
static inline T& deref(void* ptr) {
return *reinterpret_cast<T*>(ptr);
}
const std::type_info* m_native;
void serialize(const void* instance, serializer* sink) const override {
serialize_impl(deref(instance), sink);
}
void deserialize(void* instance, deserializer* source) const override {
deserialize_impl(deref(instance), source);
}
private:
template <class U>
......@@ -472,6 +447,7 @@ class uti_base : public uniform_type_info {
eq(const U& lhs, const U& rhs) const {
return detail::safe_equal(lhs, rhs);
}
template <class U>
typename std::enable_if<!std::is_floating_point<U>::value, bool>::type
eq(const U& lhs, const U& rhs) const {
......@@ -480,40 +456,11 @@ class uti_base : public uniform_type_info {
};
template <class T>
class uti_impl : public uti_base<T> {
class int_tinfo : public uniform_type_info {
public:
using super = uti_base<T>;
const char* name() const {
return mapped_name<T>();
}
protected:
void serialize(const void* instance, serializer* sink) const {
serialize_impl(super::deref(instance), sink);
}
void deserialize(void* instance, deserializer* source) const {
deserialize_impl(super::deref(instance), source);
}
};
class abstract_int_tinfo : public uniform_type_info {
public:
void add_native_type(const std::type_info& ti) {
// only push back if not already set
auto predicate = [&](const std::type_info* ptr) { return ptr == &ti; };
if (std::none_of(m_natives.begin(), m_natives.end(), predicate))
m_natives.push_back(&ti);
int_tinfo() : uniform_type_info(detail::type_nr<T>::value) {
// nop
}
protected:
std::vector<const std::type_info*> m_natives;
};
// unfortunately, one integer type can be mapped to multiple types
template <class T>
class int_tinfo : public abstract_int_tinfo {
public:
void serialize(const void* instance, serializer* sink) const override {
sink->write_value(deref(instance));
}
......@@ -528,12 +475,6 @@ class int_tinfo : public abstract_int_tinfo {
}
protected:
bool equal_to(const std::type_info& ti) const override {
auto tptr = &ti;
return std::any_of(
m_natives.begin(), m_natives.end(),
[tptr](const std::type_info* ptr) { return types_equal(ptr, tptr); });
}
bool equals(const void* lhs, const void* rhs) const override {
return deref(lhs) == deref(rhs);
}
......@@ -600,9 +541,11 @@ class default_meta_message : public uniform_type_info {
}
*cast(ptr) = mb.to_message();
}
bool equal_to(const std::type_info&) const override {
return false;
}
bool equals(const void* instance1, const void* instance2) const override {
return *cast(instance1) == *cast(instance2);
}
......@@ -618,17 +561,6 @@ class default_meta_message : public uniform_type_info {
std::vector<const uniform_type_info*> m_elements;
};
template <class T>
void push_native_type(abstract_int_tinfo* m[][2]) {
m[sizeof(T)][std::is_signed<T>::value ? 1 : 0]->add_native_type(typeid(T));
}
template <class T0, typename T1, class... Ts>
void push_native_type(abstract_int_tinfo* m[][2]) {
push_native_type<T0>(m);
push_native_type<T1, Ts...>(m);
}
template <class Iterator>
struct builtin_types_helper {
Iterator pos;
......@@ -643,10 +575,27 @@ struct builtin_types_helper {
}
};
class utim_impl : public uniform_type_info_map {
constexpr size_t builtins = detail::type_nrs - 1;
using builtins_t = std::integral_constant<size_t, builtins>;
using type_array = std::array<const uniform_type_info*, builtins>;
template <class T>
void fill_uti_arr(builtins_t, type_array&, const T&) {
// end of recursion
}
template <size_t N, class T>
void fill_uti_arr(std::integral_constant<size_t, N>, type_array& arr, const T& tup) {
arr[N] = &std::get<N>(tup);
fill_uti_arr(std::integral_constant<size_t, N+1>{}, arr, tup);
}
class utim_impl : public uniform_type_info_map {
public:
void initialize() {
/*
// maps sizeof(integer_type) to {signed_type, unsigned_type}
constexpr auto u8t = tl_find<builtin_types, int_tinfo<uint8_t>>::value;
constexpr auto i8t = tl_find<builtin_types, int_tinfo<int8_t>>::value;
......@@ -675,34 +624,36 @@ class utim_impl : public uniform_type_info_map {
unsigned long long, wchar_t, int8_t, uint8_t, int16_t,
uint16_t, int32_t, uint32_t, int64_t, uint64_t, char16_t,
char32_t, size_t, ptrdiff_t, intptr_t>(mapping);
// fill builtin types *in sorted order* (by uniform name)
auto i = m_builtin_types.begin();
builtin_types_helper<decltype(i)> h{i};
auto indices = detail::get_indices(m_storage);
detail::apply_args(h, indices, m_storage);
*/
fill_uti_arr(std::integral_constant<size_t, 0>{},
m_builtin_types, m_storage);
// make sure our builtin types are sorted
auto cmp = [](pointer lhs, pointer rhs) {
return strcmp(lhs->name(), rhs->name()) < 0;
};
std::sort(m_builtin_types.begin(), m_builtin_types.end(), cmp);
CAF_REQUIRE(std::is_sorted(m_builtin_types.begin(),
m_builtin_types.end(),
[](pointer lhs, pointer rhs) {
return strcmp(lhs->name(), rhs->name()) < 0;
}));
}
virtual pointer by_type_nr(uint16_t nr) const {
CAF_REQUIRE(nr > 0);
return m_builtin_types[nr - 1];
}
pointer by_rtti(const std::type_info& ti) const {
shared_lock<detail::shared_spinlock> guard(m_lock);
auto res = find_rtti(m_builtin_types, ti);
return (res) ? res : find_rtti(m_user_types, ti);
return find_rtti(ti);
}
pointer by_uniform_name(const std::string& name) {
pointer result = nullptr;
{ // lifetime scope of guard
pointer result = find_name(m_builtin_types, name);
if (!result) {
shared_lock<detail::shared_spinlock> guard(m_lock);
result = find_name(m_builtin_types, name);
result = (result) ? result : find_name(m_user_types, name);
result = find_name(m_user_types, name);
}
if (!result && name.compare(0, 3, "@<>") == 0) {
// create tuple UTI on-the-fly
result = insert(uniform_type_info_ptr{new default_meta_message(name)});
result = insert(nullptr, uniform_type_info_ptr{new default_meta_message(name)});
}
return result;
}
......@@ -716,15 +667,15 @@ class utim_impl : public uniform_type_info_map {
return res;
}
pointer insert(uniform_type_info_ptr uti) {
pointer insert(const std::type_info* ti, uniform_type_info_ptr uti) {
unique_lock<detail::shared_spinlock> guard(m_lock);
auto e = m_user_types.end();
auto i = std::lower_bound(m_user_types.begin(), e, uti.get(),
[](uniform_type_info* lhs, pointer rhs) {
[](pointer lhs, pointer rhs) {
return strcmp(lhs->name(), rhs->name()) < 0;
});
if (i == e) {
m_user_types.push_back(uti.release());
m_user_types.push_back(enriched_pointer{uti.release(), ti});
return m_user_types.back();
} else {
if (strcmp(uti->name(), (*i)->name()) == 0) {
......@@ -733,7 +684,7 @@ class utim_impl : public uniform_type_info_map {
}
// insert after lower bound (vector is always sorted)
auto new_pos = std::distance(m_user_types.begin(), i);
m_user_types.insert(i, uti.release());
m_user_types.insert(i, enriched_pointer{uti.release(), ti});
return m_user_types[static_cast<size_t>(new_pos)];
}
}
......@@ -752,65 +703,80 @@ class utim_impl : public uniform_type_info_map {
using strvec = std::vector<std::string>;
using builtin_types = std::tuple<uti_impl<node_id>,
using builtin_types = std::tuple<uti_impl<actor>,
uti_impl<actor_addr>,
uti_impl<atom_value>,
uti_impl<channel>,
uti_impl<charbuf>,
uti_impl<down_msg>,
uti_impl<duration>,
uti_impl<exit_msg>,
uti_impl<actor>,
uti_impl<actor_addr>,
uti_impl<group>,
uti_impl<group_down_msg>,
uti_impl<int16_t>,
uti_impl<int32_t>,
uti_impl<int64_t>,
uti_impl<int8_t>,
uti_impl<long double>,
uti_impl<message>,
uti_impl<message_id>,
uti_impl<duration>,
uti_impl<node_id>,
uti_impl<std::string>,
uti_impl<strmap>,
uti_impl<std::set<std::string>>,
uti_impl<strvec>,
uti_impl<sync_exited_msg>,
uti_impl<sync_timeout_msg>,
uti_impl<timeout_msg>,
uti_impl<unit_t>,
uti_impl<atom_value>,
uti_impl<std::string>,
uti_impl<uint16_t>,
uti_impl<std::u16string>,
uti_impl<uint32_t>,
uti_impl<std::u32string>,
uti_impl<strmap>,
uti_impl<uint64_t>,
uti_impl<uint8_t>,
uti_impl<unit_t>,
uti_impl<bool>,
uti_impl<float>,
uti_impl<double>,
uti_impl<long double>,
int_tinfo<int8_t>,
int_tinfo<uint8_t>,
int_tinfo<int16_t>,
int_tinfo<uint16_t>,
int_tinfo<int32_t>,
int_tinfo<uint32_t>,
int_tinfo<int64_t>,
int_tinfo<uint64_t>,
uti_impl<charbuf>,
uti_impl<strvec>,
uti_impl<std::set<std::string>>>;
uti_impl<float>>;
builtin_types m_storage;
// both containers are sorted by uniform name
struct enriched_pointer {
pointer first;
const std::type_info* second;
operator pointer() const {
return first;
}
pointer operator->() const {
return first;
}
};
using pointer_pair = std::pair<uniform_type_info*, std::type_info*>;
// bot containers are sorted by uniform name (m_user_types: second->name())
std::array<pointer, std::tuple_size<builtin_types>::value> m_builtin_types;
std::vector<uniform_type_info*> m_user_types;
std::vector<enriched_pointer> m_user_types;
mutable detail::shared_spinlock m_lock;
template <class Container>
pointer find_rtti(const Container& c, const std::type_info& ti) const {
auto e = c.end();
auto i = std::find_if(c.begin(), e,
[&](pointer p) { return p->equal_to(ti); });
return (i == e) ? nullptr : *i;
pointer find_rtti(const std::type_info& ti) const {
for (auto& utype : m_user_types) {
if (utype.second && (utype.second == &ti || *utype.second == ti)) {
return utype.first;
}
}
return nullptr;
}
template <class Container>
pointer find_name(const Container& c, const std::string& name) const {
auto e = c.end();
auto cmp = [](pointer lhs, const std::string& rhs) {
return lhs->name() < rhs;
};
// both containers are sorted
auto i = std::lower_bound(
c.begin(), e, name,
[](pointer p, const std::string& n) { return p->name() < n; });
return (i != e && (*i)->name() == name) ? *i : nullptr;
auto i = std::lower_bound(c.begin(), e, name, cmp);
return (i != e && name == (*i)->name()) ? *i : nullptr;
}
};
......
......@@ -273,7 +273,8 @@ void basp_broker::local_dispatch(const basp::header& hdr, message&& msg) {
CAF_REQUIRE(!dest || dest->node() == node());
// intercept message used for link signaling
if (dest && src == dest) {
if (msg.size() == 2 && typeid(actor_addr) == *msg.type_at(1)) {
if (msg.size() == 2
&& msg.match_element(1, detail::type_nr<actor_addr>::value, nullptr)) {
actor_addr other;
bool is_unlink = true;
// extract arguments
......
......@@ -116,54 +116,21 @@ deserialize_impl(T& dm, deserializer* source) {
}
template <class T>
class uti_impl : public uniform_type_info {
class uti_impl : public detail::abstract_uniform_type_info<T> {
public:
uti_impl(const char* tname) : m_native(&typeid(T)), m_name(tname) {
// nop
}
using super = detail::abstract_uniform_type_info<T>;
bool equal_to(const std::type_info& ti) const override {
// in some cases (when dealing with dynamic libraries),
// address can be different although types are equal
return m_native == &ti || *m_native == ti;
}
bool equals(const void* lhs, const void* rhs) const override {
return deref(lhs) == deref(rhs);
}
uniform_value create(const uniform_value& other) const override {
return this->create_impl<T>(other);
}
message as_message(void* instance) const override {
return make_message(deref(instance));
}
const char* name() const {
return m_name.c_str();
uti_impl(const char* tname) : super(tname) {
// nop
}
protected:
void serialize(const void* instance, serializer* sink) const {
serialize_impl(deref(instance), sink);
serialize_impl(super::deref(instance), sink);
}
void deserialize(void* instance, deserializer* source) const {
deserialize_impl(deref(instance), source);
}
private:
static inline T& deref(void* ptr) {
return *reinterpret_cast<T*>(ptr);
}
static inline const T& deref(const void* ptr) {
return *reinterpret_cast<const T*>(ptr);
deserialize_impl(super::deref(instance), source);
}
const std::type_info* m_native;
std::string m_name;
};
template <class T>
......
......@@ -18,6 +18,8 @@
#include "caf/all.hpp"
#include "caf/io/all.hpp"
#include "caf/detail/type_nr.hpp"
using std::cout;
using std::endl;
......@@ -106,8 +108,61 @@ T& append(T& storage, U&& u, Us&&... us) {
return append(storage, std::forward<Us>(us)...);
}
void check_builtin_type_nrs() {
std::map<std::string, uint16_t> nrs;
nrs["bool"] = detail::type_nr<bool>::value;
nrs["@i8"] = detail::type_nr<int8_t>::value;
nrs["@i16"] = detail::type_nr<int16_t>::value;
nrs["@i32"] = detail::type_nr<int32_t>::value;
nrs["@i64"] = detail::type_nr<int64_t>::value;
nrs["@u8"] = detail::type_nr<uint8_t>::value;
nrs["@u16"] = detail::type_nr<uint16_t>::value;
nrs["@u32"] = detail::type_nr<uint32_t>::value;
nrs["@u64"] = detail::type_nr<uint64_t>::value;
nrs["@str"] = detail::type_nr<std::string>::value;
nrs["@u16str"] = detail::type_nr<std::u16string>::value;
nrs["@u32str"] = detail::type_nr<std::u32string>::value;
nrs["float"] = detail::type_nr<float>::value;
nrs["double"] = detail::type_nr<double>::value;
nrs["@ldouble"] = detail::type_nr<long double>::value;
nrs["@unit"] = detail::type_nr<unit_t>::value;
nrs["@actor"] = detail::type_nr<actor>::value;
nrs["@addr"] = detail::type_nr<actor_addr>::value;
nrs["@atom"] = detail::type_nr<atom_value>::value;
nrs["@channel"] = detail::type_nr<channel>::value;
nrs["@charbuf"] = detail::type_nr<std::vector<char>>::value;
nrs["@down"] = detail::type_nr<down_msg>::value;
nrs["@duration"] = detail::type_nr<duration>::value;
nrs["@exit"] = detail::type_nr<exit_msg>::value;
nrs["@group"] = detail::type_nr<group>::value;
nrs["@group_down"] = detail::type_nr<group_down_msg>::value;
nrs["@message"] = detail::type_nr<message>::value;
nrs["@message_id"] = detail::type_nr<message_id>::value;
nrs["@node"] = detail::type_nr<node_id>::value;
nrs["@strmap"] = detail::type_nr<std::map<std::string, std::string>>::value;
nrs["@timeout"] = detail::type_nr<timeout_msg>::value;
nrs["@sync_exited"] = detail::type_nr<sync_exited_msg>::value;
nrs["@sync_timeout"] = detail::type_nr<sync_timeout_msg>::value;
nrs["@strvec"] = detail::type_nr<std::vector<std::string>>::value;
nrs["@strset"] = detail::type_nr<std::set<std::string>>::value;
auto types = uniform_type_info::instances();
for (auto tinfo : types) {
auto i = nrs.find(tinfo->name());
if (i == nrs.end()) {
CAF_FAILURE("could not find " << tinfo->name() << " in nrs map");
} else {
if (tinfo->type_nr() != i->second) {
CAF_FAILURE(tinfo->name() << " has wrong type nr, expected "
<< i->second << ", found " << tinfo->type_nr());
}
}
}
CAF_CHECKPOINT();
}
int main() {
CAF_TEST(test_uniform_type);
check_builtin_type_nrs();
auto announce1 = announce<foo>("foo", &foo::value);
auto announce2 = announce<foo>("foo", &foo::value);
auto announce3 = announce<foo>("foo", &foo::value);
......
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