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);
......
This diff is collapsed.
......@@ -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