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 { ...@@ -37,19 +37,19 @@ namespace detail {
*/ */
template <class T> template <class T>
class abstract_uniform_type_info : public uniform_type_info { class abstract_uniform_type_info : public uniform_type_info {
public: public:
const char* name() const override {
bool equal_to(const std::type_info& tinfo) const override { return m_name.c_str();
return typeid(T) == tinfo;
} }
const char* name() const { return m_name.c_str(); }
message as_message(void* instance) const override { message as_message(void* instance) const override {
return make_message(deref(instance)); 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 { bool equals(const void* lhs, const void* rhs) const override {
return eq(deref(lhs), deref(rhs)); return eq(deref(lhs), deref(rhs));
} }
...@@ -59,25 +59,30 @@ class abstract_uniform_type_info : public uniform_type_info { ...@@ -59,25 +59,30 @@ class abstract_uniform_type_info : public uniform_type_info {
} }
protected: protected:
abstract_uniform_type_info(std::string tname)
abstract_uniform_type_info(std::string tname) : m_name(std::move(tname)) { : m_name(std::move(tname)),
m_native(&typeid(T)) {
// nop // nop
} }
static inline const T& deref(const void* ptr) { static const T& deref(const void* ptr) {
return *reinterpret_cast<const T*>(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 // can be overridden in subclasses to compare POD types
// by comparing each individual member // 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; std::string m_name;
const std::type_info* m_native;
private: private:
template <class C> template <class C>
typename std::enable_if<std::is_empty<C>::value, bool>::type typename std::enable_if<std::is_empty<C>::value, bool>::type
eq(const C&, const C&) const { eq(const C&, const C&) const {
...@@ -99,7 +104,6 @@ class abstract_uniform_type_info : public uniform_type_info { ...@@ -99,7 +104,6 @@ class abstract_uniform_type_info : public uniform_type_info {
eq(const C& lhs, const C& rhs) const { eq(const C& lhs, const C& rhs) const {
return pod_mems_equals(lhs, rhs); return pod_mems_equals(lhs, rhs);
} }
}; };
} // namespace detail } // namespace detail
......
...@@ -65,14 +65,22 @@ class decorated_tuple : public message_data { ...@@ -65,14 +65,22 @@ class decorated_tuple : public message_data {
const void* at(size_t pos) const override; 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; const std::string* tuple_type_names() const override;
uint16_t type_nr_at(size_t pos) const override;
private: private:
pointer m_decorated; pointer m_decorated;
vector_type m_mapping; vector_type m_mapping;
uint32_t m_type_token;
void init(); void init();
......
...@@ -50,15 +50,32 @@ class message_data : public ref_counted { ...@@ -50,15 +50,32 @@ class message_data : public ref_counted {
// accessors // accessors
virtual size_t size() const = 0; virtual size_t size() const = 0;
virtual message_data* copy() const = 0; virtual message_data* copy() const = 0;
virtual const void* at(size_t pos) 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; 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 // returns either tdata<...> object or nullptr (default) if tuple
// is not a 'native' implementation // is not a 'native' implementation
virtual const void* native_data() const; 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; bool equals(const message_data& other) const;
using const_iterator = message_iterator; using const_iterator = message_iterator;
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#define CAF_DETAIL_MESSAGE_ITERATOR_HPP #define CAF_DETAIL_MESSAGE_ITERATOR_HPP
#include <cstddef> #include <cstddef>
#include <typeinfo>
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
...@@ -78,7 +79,12 @@ class message_iterator { ...@@ -78,7 +79,12 @@ class message_iterator {
const void* value() const; 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*() { inline message_iterator& operator*() {
return *this; return *this;
......
...@@ -26,45 +26,53 @@ ...@@ -26,45 +26,53 @@
#include "caf/atom.hpp" #include "caf/atom.hpp"
#include "caf/message.hpp" #include "caf/message.hpp"
#include "caf/uniform_typeid.hpp"
#include "caf/wildcard_position.hpp" #include "caf/wildcard_position.hpp"
#include "caf/detail/type_nr.hpp"
#include "caf/detail/type_list.hpp" #include "caf/detail/type_list.hpp"
#include "caf/detail/pseudo_tuple.hpp" #include "caf/detail/pseudo_tuple.hpp"
namespace caf { namespace caf {
namespace detail { 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 { struct meta_element {
atom_value v; atom_value v;
uint16_t typenr;
const std::type_info* type; const std::type_info* type;
bool (*fun)(const atom_value&, const std::type_info*, bool (*fun)(const meta_element&, const message_iterator&, void**);
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 { struct meta_element_factory {
static meta_element create() { 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> template <atom_value V>
struct meta_element_factory<atom_constant<V>> { struct meta_element_factory<atom_constant<V>, 0> {
static meta_element create() { 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 <> template <>
struct meta_element_factory<anything> { struct meta_element_factory<anything, 0> {
static meta_element create() { 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> { ...@@ -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> template <class... Ts>
class tuple_vals : public message_data { class tuple_vals : public message_data {
public:
static_assert(sizeof...(Ts) > 0, "tuple_vals is not allowed to be empty"); static_assert(sizeof...(Ts) > 0, "tuple_vals is not allowed to be empty");
using super = message_data; using super = message_data;
public:
using data_type = std::tuple<Ts...>; using data_type = std::tuple<Ts...>;
tuple_vals(const tuple_vals&) = default; tuple_vals(const tuple_vals&) = default;
...@@ -68,55 +82,79 @@ class tuple_vals : public message_data { ...@@ -68,55 +82,79 @@ class tuple_vals : public message_data {
template <class... Us> template <class... Us>
tuple_vals(Us&&... args) tuple_vals(Us&&... args)
: m_data(std::forward<Us>(args)...), : m_data(std::forward<Us>(args)...),
m_types{{uniform_typeid<Ts>()...}} { m_types{{tuple_vals_type_helper<Ts>::get()...}} {
// nop // 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()); CAF_REQUIRE(pos < size());
return tup_ptr_access<0, sizeof...(Ts)>::get(pos, m_data); 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()); CAF_REQUIRE(pos < size());
return const_cast<void*>(at(pos)); 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()); 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 { const char* uniform_name_at(size_t pos) const override {
if (size() != other.size()) return false; auto& et = m_types[pos];
const tuple_vals* o = dynamic_cast<const tuple_vals*>(&other); if (et.first != 0) {
if (o) { return numbered_type_names[et.first - 1];
return m_data == (o->m_data);
} }
return message_data::equals(other); return uniform_typeid(*et.second)->name();
} }
const std::string* tuple_type_names() const override { uint16_t type_nr_at(size_t pos) const override {
// produced name is equal for all instances return m_types[pos].first;
static std::string result = get_tuple_type_names(*this);
return &result;
} }
private: private:
data_type m_data; 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 } // 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 { ...@@ -69,11 +69,13 @@ class uniform_type_info_map {
virtual pointer by_uniform_name(const std::string& name) = 0; 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 pointer by_rtti(const std::type_info& ti) const = 0;
virtual std::vector<pointer> get_all() 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(); static uniform_type_info_map* create_singleton();
......
...@@ -71,14 +71,20 @@ class match_expr_case : public get_lifted_fun<Expr, Projecs, Signature>::type { ...@@ -71,14 +71,20 @@ class match_expr_case : public get_lifted_fun<Expr, Projecs, Signature>::type {
using pattern = Pattern; using pattern = Pattern;
using filtered_pattern = using filtered_pattern =
typename detail::tl_filter_not_type< typename detail::tl_filter_not_type<
Pattern, Pattern,
anything anything
>::type; >::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 = using intermediate_tuple =
typename detail::tl_apply< typename detail::tl_apply<
filtered_pattern, filtered_pattern,
detail::pseudo_tuple detail::pseudo_tuple
>::type; >::type;
}; };
template <class Expr, class Transformers, class Pattern> template <class Expr, class Transformers, class Pattern>
...@@ -225,7 +231,8 @@ Result unroll_expr(PPFPs& fs, long_constant<N>, Msg& msg) { ...@@ -225,7 +231,8 @@ Result unroll_expr(PPFPs& fs, long_constant<N>, Msg& msg) {
using ft = typename std::decay<decltype(f)>::type; using ft = typename std::decay<decltype(f)>::type;
meta_elements<typename ft::pattern> ms; meta_elements<typename ft::pattern> ms;
typename ft::intermediate_tuple targs; 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 is = detail::get_indices(targs);
auto res = detail::apply_args(f, is, deduce_const(msg, targs)); auto res = detail::apply_args(f, is, deduce_const(msg, targs));
if (unroll_expr_result_valid(res)) { if (unroll_expr_result_valid(res)) {
...@@ -235,23 +242,6 @@ Result unroll_expr(PPFPs& fs, long_constant<N>, Msg& msg) { ...@@ -235,23 +242,6 @@ Result unroll_expr(PPFPs& fs, long_constant<N>, Msg& msg) {
return none; 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> template <bool IsManipulator, typename T0, typename T1>
struct mexpr_fwd_ { struct mexpr_fwd_ {
using type = T1; using type = T1;
......
...@@ -127,10 +127,15 @@ class message { ...@@ -127,10 +127,15 @@ class message {
const void* at(size_t p) const; const void* at(size_t p) const;
/** /**
* Gets {@link uniform_type_info uniform type information} * Tries to match element at position `pos` to given RTTI.
* of the element at position @p p. * @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. * Returns @c true if `*this == other, otherwise false.
...@@ -149,7 +154,7 @@ class message { ...@@ -149,7 +154,7 @@ class message {
*/ */
template <class T> template <class T>
inline const T& get_as(size_t p) const { 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)); return *reinterpret_cast<const T*>(at(p));
} }
...@@ -158,7 +163,7 @@ class message { ...@@ -158,7 +163,7 @@ class message {
*/ */
template <class T> template <class T>
inline T& get_as_mutable(size_t p) { 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)); return *reinterpret_cast<T*>(mutable_at(p));
} }
...@@ -207,6 +212,10 @@ class message { ...@@ -207,6 +212,10 @@ class message {
/** @cond PRIVATE */ /** @cond PRIVATE */
inline uint32_t type_token() const {
return m_vals->type_token();
}
inline void force_detach() { inline void force_detach() {
m_vals.detach(); m_vals.detach();
} }
......
...@@ -148,8 +148,8 @@ class invoke_policy { ...@@ -148,8 +148,8 @@ class invoke_policy {
} else { } else {
CAF_LOGF_DEBUG("res = " << to_string(*res)); CAF_LOGF_DEBUG("res = " << to_string(*res));
if (res->size() == 2 if (res->size() == 2
&& res->type_at(0) == uniform_typeid<atom_value>() && res->match_element(0, detail::type_nr<atom_value>::value, nullptr)
&& res->type_at(1) == uniform_typeid<uint64_t>() && res->match_element(1, detail::type_nr<uint64_t>::value, nullptr)
&& res->template get_as<atom_value>(0) == atom("MESSAGE_ID")) { && res->template get_as<atom_value>(0) == atom("MESSAGE_ID")) {
CAF_LOG_DEBUG("message handler returned a message id wrapper"); CAF_LOG_DEBUG("message handler returned a message id wrapper");
auto id = res->template get_as<uint64_t>(1); auto id = res->template get_as<uint64_t>(1);
...@@ -289,7 +289,7 @@ class invoke_policy { ...@@ -289,7 +289,7 @@ class invoke_policy {
const message& msg = node->msg; const message& msg = node->msg;
auto mid = node->mid; auto mid = node->mid;
if (msg.size() == 1) { 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); auto& em = msg.get_as<exit_msg>(0);
CAF_REQUIRE(!mid.valid()); CAF_REQUIRE(!mid.valid());
// make sure to get rid of attachables if they're no longer needed // make sure to get rid of attachables if they're no longer needed
...@@ -301,7 +301,7 @@ class invoke_policy { ...@@ -301,7 +301,7 @@ class invoke_policy {
} }
return msg_type::normal_exit; 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& tm = msg.get_as<timeout_msg>(0);
auto tid = tm.timeout_id; auto tid = tm.timeout_id;
CAF_REQUIRE(!mid.valid()); CAF_REQUIRE(!mid.valid());
...@@ -310,8 +310,8 @@ class invoke_policy { ...@@ -310,8 +310,8 @@ class invoke_policy {
} }
return self->waits_for_timeout(tid) ? msg_type::inactive_timeout return self->waits_for_timeout(tid) ? msg_type::inactive_timeout
: msg_type::expired_timeout; : msg_type::expired_timeout;
} else if (msg.type_at(0)->equal_to(typeid(sync_timeout_msg)) } else if (mid.is_response()
&& mid.is_response()) { && msg.match_element(0, detail::type_nr<sync_timeout_msg>::value, nullptr)) {
return msg_type::timeout_response; return msg_type::timeout_response;
} }
} }
......
...@@ -72,7 +72,7 @@ template <class T> ...@@ -72,7 +72,7 @@ template <class T>
optional<T> from_string(const std::string& what) { optional<T> from_string(const std::string& what) {
auto uti = uniform_typeid<T>(); auto uti = uniform_typeid<T>();
auto uv = from_string_impl(what); auto uv = from_string_impl(what);
if (!uv || (*uv->ti) != typeid(T)) { if (!uv || uv->ti != uti) {
// try again using the type name // try again using the type name
std::string tmp = uti->name(); std::string tmp = uti->name();
tmp += " ( "; tmp += " ( ";
...@@ -80,7 +80,7 @@ optional<T> from_string(const std::string& what) { ...@@ -80,7 +80,7 @@ optional<T> from_string(const std::string& what) {
tmp += " )"; tmp += " )";
uv = from_string_impl(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 T{std::move(*reinterpret_cast<T*>(uv->val))};
} }
return none; return none;
......
...@@ -158,9 +158,9 @@ uniform_value make_uniform_value(const uniform_type_info* ti, Ts&&... args) { ...@@ -158,9 +158,9 @@ uniform_value make_uniform_value(const uniform_type_info* ti, Ts&&... args) {
* \@_::foo * \@_::foo
*/ */
class uniform_type_info { class uniform_type_info {
public:
friend bool operator==(const uniform_type_info& lhs, friend bool operator==(const uniform_type_info& lhs,
const uniform_type_info& rhs); const uniform_type_info& rhs);
// disable copy and move constructors // disable copy and move constructors
uniform_type_info(uniform_type_info&&) = delete; uniform_type_info(uniform_type_info&&) = delete;
...@@ -170,8 +170,6 @@ class uniform_type_info { ...@@ -170,8 +170,6 @@ class uniform_type_info {
uniform_type_info& operator=(uniform_type_info&&) = delete; uniform_type_info& operator=(uniform_type_info&&) = delete;
uniform_type_info& operator=(const uniform_type_info&) = delete; uniform_type_info& operator=(const uniform_type_info&) = delete;
public:
virtual ~uniform_type_info(); virtual ~uniform_type_info();
/** /**
...@@ -254,9 +252,15 @@ class uniform_type_info { ...@@ -254,9 +252,15 @@ class uniform_type_info {
*/ */
virtual message as_message(void* instance) const = 0; 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> template <class T>
uniform_value create_impl(const uniform_value& other) const { uniform_value create_impl(const uniform_value& other) const {
...@@ -268,6 +272,8 @@ class uniform_type_info { ...@@ -268,6 +272,8 @@ class uniform_type_info {
return make_uniform_value<T>(this); return make_uniform_value<T>(this);
} }
private:
uint16_t m_type_nr;
}; };
using uniform_type_info_ptr = std::unique_ptr<uniform_type_info>; using uniform_type_info_ptr = std::unique_ptr<uniform_type_info>;
...@@ -294,38 +300,6 @@ inline bool operator!=(const uniform_type_info& lhs, ...@@ -294,38 +300,6 @@ inline bool operator!=(const uniform_type_info& lhs,
return !(lhs == rhs); 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 } // namespace caf
#endif // CAF_UNIFORM_TYPE_INFO_HPP #endif // CAF_UNIFORM_TYPE_INFO_HPP
...@@ -22,16 +22,36 @@ ...@@ -22,16 +22,36 @@
#include <typeinfo> #include <typeinfo>
#include "caf/detail/type_nr.hpp"
namespace caf { namespace caf {
class uniform_type_info; 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, const uniform_type_info* uniform_typeid(const std::type_info& tinf,
bool allow_nullptr = false); 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> template <class T>
const uniform_type_info* uniform_typeid(bool allow_nullptr = false) { 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 } // namespace caf
......
...@@ -27,7 +27,9 @@ void* decorated_tuple::mutable_at(size_t pos) { ...@@ -27,7 +27,9 @@ void* decorated_tuple::mutable_at(size_t pos) {
return m_decorated->mutable_at(m_mapping[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 { decorated_tuple* decorated_tuple::copy() const {
return new decorated_tuple(*this); return new decorated_tuple(*this);
...@@ -38,22 +40,39 @@ const void* decorated_tuple::at(size_t pos) const { ...@@ -38,22 +40,39 @@ const void* decorated_tuple::at(size_t pos) const {
return m_decorated->at(m_mapping[pos]); return m_decorated->at(m_mapping[pos]);
} }
const uniform_type_info* decorated_tuple::type_at(size_t pos) const { bool decorated_tuple::match_element(size_t pos, uint16_t typenr,
CAF_REQUIRE(pos < size()); const std::type_info* rtti) const {
return m_decorated->type_at(m_mapping[pos]); 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() { void decorated_tuple::init() {
CAF_REQUIRE(m_mapping.empty() CAF_REQUIRE(m_mapping.empty()
|| *(std::max_element(m_mapping.begin(), m_mapping.end())) || *(std::max_element(m_mapping.begin(), m_mapping.end()))
< static_cast<const pointer&>(m_decorated)->size()); < 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) { void decorated_tuple::init(size_t offset) {
const pointer& dec = m_decorated; if (offset < m_decorated->size()) {
if (offset < dec->size()) {
size_t i = offset; 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++; }); std::generate(m_mapping.begin(), m_mapping.end(), [&] { return i++; });
} }
init(); init();
...@@ -61,12 +80,14 @@ void decorated_tuple::init(size_t offset) { ...@@ -61,12 +80,14 @@ void decorated_tuple::init(size_t offset) {
decorated_tuple::decorated_tuple(pointer d, vector_type&& v) decorated_tuple::decorated_tuple(pointer d, vector_type&& v)
: m_decorated(std::move(d)), : m_decorated(std::move(d)),
m_mapping(std::move(v)) { m_mapping(std::move(v)),
m_type_token(0xFFFFFFFF) {
init(); init();
} }
decorated_tuple::decorated_tuple(pointer d, size_t offset) 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); init(offset);
} }
......
...@@ -56,9 +56,13 @@ const void* message::at(size_t p) const { ...@@ -56,9 +56,13 @@ const void* message::at(size_t p) const {
return m_vals->at(p); return m_vals->at(p);
} }
const uniform_type_info* message::type_at(size_t p) const { bool message::match_element(size_t pos, uint16_t typenr,
CAF_REQUIRE(m_vals); const std::type_info* rtti) const {
return m_vals->type_at(p); 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 { bool message::equals(const message& other) const {
......
...@@ -31,19 +31,24 @@ class message_builder::dynamic_msg_data : public detail::message_data { ...@@ -31,19 +31,24 @@ class message_builder::dynamic_msg_data : public detail::message_data {
using message_data::const_iterator; using message_data::const_iterator;
dynamic_msg_data() { dynamic_msg_data() : m_type_token(0xFFFFFFFF) {
// nop // 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) { for (auto& d : other.m_elements) {
m_elements.push_back(d->copy()); m_elements.push_back(d->copy());
} }
} }
dynamic_msg_data(std::vector<uniform_value>&& data) dynamic_msg_data(std::vector<uniform_value>&& data)
: m_elements(std::move(data)) { : m_elements(std::move(data)),
// nop m_type_token(0xFFFFFFFF) {
for (auto& e : m_elements) {
m_type_token <<= 6;
m_type_token |= e->ti->type_nr();
}
} }
~dynamic_msg_data(); ~dynamic_msg_data();
...@@ -66,9 +71,23 @@ class message_builder::dynamic_msg_data : public detail::message_data { ...@@ -66,9 +71,23 @@ class message_builder::dynamic_msg_data : public detail::message_data {
return new dynamic_msg_data(*this); return new dynamic_msg_data(*this);
} }
const uniform_type_info* type_at(size_t pos) const override { bool match_element(size_t pos, uint16_t typenr,
CAF_REQUIRE(pos < size()); const std::type_info* rtti) const override {
return m_elements[pos]->ti; 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 { const std::string* tuple_type_names() const override {
...@@ -76,6 +95,7 @@ class message_builder::dynamic_msg_data : public detail::message_data { ...@@ -76,6 +95,7 @@ class message_builder::dynamic_msg_data : public detail::message_data {
} }
std::vector<uniform_value> m_elements; std::vector<uniform_value> m_elements;
uint32_t m_type_token;
}; };
message_builder::dynamic_msg_data::~dynamic_msg_data() { message_builder::dynamic_msg_data::~dynamic_msg_data() {
......
...@@ -27,13 +27,31 @@ message_data::message_data() { ...@@ -27,13 +27,31 @@ message_data::message_data() {
} }
bool message_data::equals(const message_data& other) const { bool message_data::equals(const message_data& other) const {
auto full_eq = [](const message_iterator& lhs, const message_iterator& rhs) { if (this == &other) {
return lhs.type() == rhs.type() return true;
&& lhs.type()->equals(lhs.value(), rhs.value()); }
}; auto n = size();
return this == &other if (n != other.size()) {
|| (size() == other.size() return false;
&& std::equal(begin(), end(), other.begin(), full_eq)); }
// 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 { const void* message_data::native_data() const {
...@@ -47,9 +65,8 @@ void* message_data::mutable_native_data() { ...@@ -47,9 +65,8 @@ void* message_data::mutable_native_data() {
std::string get_tuple_type_names(const detail::message_data& tup) { std::string get_tuple_type_names(const detail::message_data& tup) {
std::string result = "@<>"; std::string result = "@<>";
for (size_t i = 0; i < tup.size(); ++i) { for (size_t i = 0; i < tup.size(); ++i) {
auto uti = tup.type_at(i);
result += "+"; result += "+";
result += uti->name(); result += tup.uniform_name_at(i);
} }
return result; return result;
} }
......
...@@ -34,8 +34,9 @@ const void* message_iterator::value() const { ...@@ -34,8 +34,9 @@ const void* message_iterator::value() const {
return m_data->at(m_pos); return m_data->at(m_pos);
} }
const uniform_type_info* message_iterator::type() const { bool message_iterator::match_element(uint16_t typenr,
return m_data->type_at(m_pos); const std::type_info* rtti) const {
return m_data->match_element(m_pos, typenr, rtti);
} }
} // namespace detail } // namespace detail
......
...@@ -25,12 +25,13 @@ namespace detail { ...@@ -25,12 +25,13 @@ namespace detail {
using pattern_iterator = const meta_element*; using pattern_iterator = const meta_element*;
bool is_wildcard(const meta_element& me) { 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, bool match_element(const meta_element& me, const message_iterator& iter,
const message_iterator& iter, void** storage) { void** storage) {
if (!iter.type()->equal_to(*type)) { CAF_REQUIRE(me.typenr != 0 || me.type != nullptr);
if (!iter.match_element(me.typenr, me.type)) {
return false; return false;
} }
if (storage) { if (storage) {
...@@ -39,23 +40,23 @@ bool match_element(const atom_value&, const std::type_info* type, ...@@ -39,23 +40,23 @@ bool match_element(const atom_value&, const std::type_info* type,
return true; return true;
} }
bool match_atom_constant(const atom_value& value, const std::type_info* type, bool match_atom_constant(const meta_element& me, const message_iterator& iter,
const message_iterator& iter, void** storage) { void** storage) {
auto uti = iter.type(); CAF_REQUIRE(me.typenr == detail::type_nr<atom_value>::value);
if (!uti->equal_to(*type)) { if (!iter.match_element(detail::type_nr<atom_value>::value, nullptr)) {
return false; return false;
} }
if (storage) { if (storage) {
if (!uti->equals(iter.value(), &value)) { if (iter.value_as<atom_value>() != me.v) {
return false; 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. // This type violation could theoretically cause undefined behavior.
// However, `uti` does have an address that is guaranteed to be valid // However, `uti` does have an address that is guaranteed to be valid
// throughout the runtime of the program and the atom constant // throughout the runtime of the program and the atom constant
// does not have any members. Hence, this is nonetheless safe since // does not have any members. Hence, this is nonetheless safe since
// we are never actually going to dereference the pointer. // 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; return true;
} }
...@@ -113,7 +114,7 @@ bool try_match(message_iterator mbegin, message_iterator mend, ...@@ -113,7 +114,7 @@ bool try_match(message_iterator mbegin, message_iterator mend,
return false; // no submatch found return false; // no submatch found
} }
// inspect current element // inspect current element
if (!pbegin->fun(pbegin->v, pbegin->type, mbegin, storage.current())) { if (!pbegin->fun(*pbegin, mbegin, storage.current())) {
// type mismatch // type mismatch
return false; return false;
} }
......
...@@ -58,9 +58,13 @@ uniform_value_t::~uniform_value_t() { ...@@ -58,9 +58,13 @@ uniform_value_t::~uniform_value_t() {
// nop // nop
} }
const uniform_type_info* announce(const std::type_info&, const uniform_type_info* announce(const std::type_info& ti,
uniform_type_info_ptr utype) { uniform_type_info_ptr utype) {
return uti_map().insert(std::move(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() { uniform_type_info::~uniform_type_info() {
...@@ -97,6 +101,11 @@ std::vector<const uniform_type_info*> uniform_type_info::instances() { ...@@ -97,6 +101,11 @@ std::vector<const uniform_type_info*> uniform_type_info::instances() {
return uti_map().get_all(); 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, const uniform_type_info* uniform_typeid(const std::type_info& tinf,
bool allow_nullptr) { bool allow_nullptr) {
auto result = uti_map().by_rtti(tinf); auto result = uti_map().by_rtti(tinf);
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include "caf/message_builder.hpp" #include "caf/message_builder.hpp"
#include "caf/detail/logging.hpp" #include "caf/detail/logging.hpp"
#include "caf/detail/type_nr.hpp"
#include "caf/detail/safe_equal.hpp" #include "caf/detail/safe_equal.hpp"
#include "caf/detail/singletons.hpp" #include "caf/detail/singletons.hpp"
#include "caf/detail/scope_guard.hpp" #include "caf/detail/scope_guard.hpp"
...@@ -52,82 +53,42 @@ ...@@ -52,82 +53,42 @@
namespace caf { namespace caf {
namespace detail { namespace detail {
namespace { const char* numbered_type_names[] = {
const char* mapped_type_names[] = {
"bool",
"@actor", "@actor",
"@addr", "@addr",
"@atom", "@atom",
"@channel", "@channel",
"@charbuf",
"@down", "@down",
"@duration", "@duration",
"@exit", "@exit",
"@group", "@group",
"@group_down", "@group_down",
"@i16",
"@i32",
"@i64",
"@i8",
"@ldouble",
"@message", "@message",
"@message_id", "@message_id",
"@node", "@node",
"@str",
"@strmap",
"@strset",
"@strvec",
"@sync_exited", "@sync_exited",
"@sync_timeout", "@sync_timeout",
"@timeout", "@timeout",
"@unit", "@u16",
"double",
"float",
"@ldouble",
"@str",
"@u16str", "@u16str",
"@u32",
"@u32str", "@u32str",
"@strmap", "@u64",
"@charbuf", "@u8",
"@strvec", "@unit",
"@strset" "bool",
}; "double",
// the order of this table must be *identical* to mapped_type_names "float"
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"}
}; };
namespace { namespace {
...@@ -289,7 +250,7 @@ void serialize_impl(const message& tup, serializer* sink) { ...@@ -289,7 +250,7 @@ void serialize_impl(const message& tup, serializer* sink) {
} }
sink->begin_object(uti); sink->begin_object(uti);
for (size_t i = 0; i < tup.size(); ++i) { 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(); sink->end_object();
} }
...@@ -432,39 +393,53 @@ deserialize_impl(T& iterable, deserializer* sink) { ...@@ -432,39 +393,53 @@ deserialize_impl(T& iterable, deserializer* sink) {
sp(iterable, 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> template <class T>
class uti_base : public uniform_type_info { class uti_impl : public uniform_type_info {
protected: public:
uti_base() : m_native(&typeid(T)) { static_assert(detail::type_nr<T>::value > 0, "type_nr<T>::value == 0");
uti_impl() : uniform_type_info(detail::type_nr<T>::value) {
// nop // 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 { bool equals(const void* lhs, const void* rhs) const override {
// return detail::safe_equal(deref(lhs), deref(rhs)); // return detail::safe_equal(deref(lhs), deref(rhs));
// return deref(lhs) == deref(rhs); // return deref(lhs) == deref(rhs);
return eq(deref(lhs), deref(rhs)); return eq(deref(lhs), deref(rhs));
} }
uniform_value create(const uniform_value& other) const override { uniform_value create(const uniform_value& other) const override {
return create_impl<T>(other); return create_impl<T>(other);
} }
message as_message(void* instance) const override { message as_message(void* instance) const override {
return make_message(deref(instance)); return make_message(deref(instance));
} }
static inline const T& deref(const void* ptr) { static inline const T& deref(const void* ptr) {
return *reinterpret_cast<const T*>(ptr); return *reinterpret_cast<const T*>(ptr);
} }
static inline T& deref(void* ptr) { static inline T& deref(void* ptr) {
return *reinterpret_cast<T*>(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: private:
template <class U> template <class U>
...@@ -472,6 +447,7 @@ class uti_base : public uniform_type_info { ...@@ -472,6 +447,7 @@ class uti_base : public uniform_type_info {
eq(const U& lhs, const U& rhs) const { eq(const U& lhs, const U& rhs) const {
return detail::safe_equal(lhs, rhs); return detail::safe_equal(lhs, rhs);
} }
template <class U> template <class U>
typename std::enable_if<!std::is_floating_point<U>::value, bool>::type typename std::enable_if<!std::is_floating_point<U>::value, bool>::type
eq(const U& lhs, const U& rhs) const { eq(const U& lhs, const U& rhs) const {
...@@ -480,40 +456,11 @@ class uti_base : public uniform_type_info { ...@@ -480,40 +456,11 @@ class uti_base : public uniform_type_info {
}; };
template <class T> template <class T>
class uti_impl : public uti_base<T> { class int_tinfo : public uniform_type_info {
public: public:
using super = uti_base<T>; int_tinfo() : uniform_type_info(detail::type_nr<T>::value) {
// nop
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);
} }
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 { void serialize(const void* instance, serializer* sink) const override {
sink->write_value(deref(instance)); sink->write_value(deref(instance));
} }
...@@ -528,12 +475,6 @@ class int_tinfo : public abstract_int_tinfo { ...@@ -528,12 +475,6 @@ class int_tinfo : public abstract_int_tinfo {
} }
protected: 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 { bool equals(const void* lhs, const void* rhs) const override {
return deref(lhs) == deref(rhs); return deref(lhs) == deref(rhs);
} }
...@@ -600,9 +541,11 @@ class default_meta_message : public uniform_type_info { ...@@ -600,9 +541,11 @@ class default_meta_message : public uniform_type_info {
} }
*cast(ptr) = mb.to_message(); *cast(ptr) = mb.to_message();
} }
bool equal_to(const std::type_info&) const override { bool equal_to(const std::type_info&) const override {
return false; return false;
} }
bool equals(const void* instance1, const void* instance2) const override { bool equals(const void* instance1, const void* instance2) const override {
return *cast(instance1) == *cast(instance2); return *cast(instance1) == *cast(instance2);
} }
...@@ -618,17 +561,6 @@ class default_meta_message : public uniform_type_info { ...@@ -618,17 +561,6 @@ class default_meta_message : public uniform_type_info {
std::vector<const uniform_type_info*> m_elements; 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> template <class Iterator>
struct builtin_types_helper { struct builtin_types_helper {
Iterator pos; Iterator pos;
...@@ -643,10 +575,27 @@ struct builtin_types_helper { ...@@ -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: public:
void initialize() { void initialize() {
/*
// maps sizeof(integer_type) to {signed_type, unsigned_type} // maps sizeof(integer_type) to {signed_type, unsigned_type}
constexpr auto u8t = tl_find<builtin_types, int_tinfo<uint8_t>>::value; constexpr auto u8t = tl_find<builtin_types, int_tinfo<uint8_t>>::value;
constexpr auto i8t = tl_find<builtin_types, int_tinfo<int8_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 { ...@@ -675,34 +624,36 @@ class utim_impl : public uniform_type_info_map {
unsigned long long, wchar_t, int8_t, uint8_t, int16_t, unsigned long long, wchar_t, int8_t, uint8_t, int16_t,
uint16_t, int32_t, uint32_t, int64_t, uint64_t, char16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t, char16_t,
char32_t, size_t, ptrdiff_t, intptr_t>(mapping); char32_t, size_t, ptrdiff_t, intptr_t>(mapping);
// fill builtin types *in sorted order* (by uniform name) */
auto i = m_builtin_types.begin(); fill_uti_arr(std::integral_constant<size_t, 0>{},
builtin_types_helper<decltype(i)> h{i}; m_builtin_types, m_storage);
auto indices = detail::get_indices(m_storage);
detail::apply_args(h, indices, m_storage);
// make sure our builtin types are sorted // make sure our builtin types are sorted
auto cmp = [](pointer lhs, pointer rhs) { CAF_REQUIRE(std::is_sorted(m_builtin_types.begin(),
return strcmp(lhs->name(), rhs->name()) < 0; m_builtin_types.end(),
}; [](pointer lhs, pointer rhs) {
std::sort(m_builtin_types.begin(), m_builtin_types.end(), cmp); 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 { pointer by_rtti(const std::type_info& ti) const {
shared_lock<detail::shared_spinlock> guard(m_lock); shared_lock<detail::shared_spinlock> guard(m_lock);
auto res = find_rtti(m_builtin_types, ti); return find_rtti(ti);
return (res) ? res : find_rtti(m_user_types, ti);
} }
pointer by_uniform_name(const std::string& name) { pointer by_uniform_name(const std::string& name) {
pointer result = nullptr; pointer result = find_name(m_builtin_types, name);
{ // lifetime scope of guard if (!result) {
shared_lock<detail::shared_spinlock> guard(m_lock); shared_lock<detail::shared_spinlock> guard(m_lock);
result = find_name(m_builtin_types, name); result = find_name(m_user_types, name);
result = (result) ? result : find_name(m_user_types, name);
} }
if (!result && name.compare(0, 3, "@<>") == 0) { if (!result && name.compare(0, 3, "@<>") == 0) {
// create tuple UTI on-the-fly // 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; return result;
} }
...@@ -716,15 +667,15 @@ class utim_impl : public uniform_type_info_map { ...@@ -716,15 +667,15 @@ class utim_impl : public uniform_type_info_map {
return res; 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); unique_lock<detail::shared_spinlock> guard(m_lock);
auto e = m_user_types.end(); auto e = m_user_types.end();
auto i = std::lower_bound(m_user_types.begin(), e, uti.get(), 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; return strcmp(lhs->name(), rhs->name()) < 0;
}); });
if (i == e) { 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(); return m_user_types.back();
} else { } else {
if (strcmp(uti->name(), (*i)->name()) == 0) { if (strcmp(uti->name(), (*i)->name()) == 0) {
...@@ -733,7 +684,7 @@ class utim_impl : public uniform_type_info_map { ...@@ -733,7 +684,7 @@ class utim_impl : public uniform_type_info_map {
} }
// insert after lower bound (vector is always sorted) // insert after lower bound (vector is always sorted)
auto new_pos = std::distance(m_user_types.begin(), i); 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)]; return m_user_types[static_cast<size_t>(new_pos)];
} }
} }
...@@ -752,65 +703,80 @@ class utim_impl : public uniform_type_info_map { ...@@ -752,65 +703,80 @@ class utim_impl : public uniform_type_info_map {
using strvec = std::vector<std::string>; 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<channel>,
uti_impl<charbuf>,
uti_impl<down_msg>, uti_impl<down_msg>,
uti_impl<duration>,
uti_impl<exit_msg>, uti_impl<exit_msg>,
uti_impl<actor>,
uti_impl<actor_addr>,
uti_impl<group>, uti_impl<group>,
uti_impl<group_down_msg>, 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>,
uti_impl<message_id>, 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_exited_msg>,
uti_impl<sync_timeout_msg>, uti_impl<sync_timeout_msg>,
uti_impl<timeout_msg>, uti_impl<timeout_msg>,
uti_impl<unit_t>, uti_impl<uint16_t>,
uti_impl<atom_value>,
uti_impl<std::string>,
uti_impl<std::u16string>, uti_impl<std::u16string>,
uti_impl<uint32_t>,
uti_impl<std::u32string>, uti_impl<std::u32string>,
uti_impl<strmap>, uti_impl<uint64_t>,
uti_impl<uint8_t>,
uti_impl<unit_t>,
uti_impl<bool>, uti_impl<bool>,
uti_impl<float>,
uti_impl<double>, uti_impl<double>,
uti_impl<long double>, uti_impl<float>>;
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>>>;
builtin_types m_storage; 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::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; mutable detail::shared_spinlock m_lock;
template <class Container> pointer find_rtti(const std::type_info& ti) const {
pointer find_rtti(const Container& c, const std::type_info& ti) const { for (auto& utype : m_user_types) {
auto e = c.end(); if (utype.second && (utype.second == &ti || *utype.second == ti)) {
auto i = std::find_if(c.begin(), e, return utype.first;
[&](pointer p) { return p->equal_to(ti); }); }
return (i == e) ? nullptr : *i; }
return nullptr;
} }
template <class Container> template <class Container>
pointer find_name(const Container& c, const std::string& name) const { pointer find_name(const Container& c, const std::string& name) const {
auto e = c.end(); auto e = c.end();
auto cmp = [](pointer lhs, const std::string& rhs) {
return lhs->name() < rhs;
};
// both containers are sorted // both containers are sorted
auto i = std::lower_bound( auto i = std::lower_bound(c.begin(), e, name, cmp);
c.begin(), e, name, return (i != e && name == (*i)->name()) ? *i : nullptr;
[](pointer p, const std::string& n) { return p->name() < n; });
return (i != e && (*i)->name() == name) ? *i : nullptr;
} }
}; };
......
...@@ -273,7 +273,8 @@ void basp_broker::local_dispatch(const basp::header& hdr, message&& msg) { ...@@ -273,7 +273,8 @@ void basp_broker::local_dispatch(const basp::header& hdr, message&& msg) {
CAF_REQUIRE(!dest || dest->node() == node()); CAF_REQUIRE(!dest || dest->node() == node());
// intercept message used for link signaling // intercept message used for link signaling
if (dest && src == dest) { 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; actor_addr other;
bool is_unlink = true; bool is_unlink = true;
// extract arguments // extract arguments
......
...@@ -116,54 +116,21 @@ deserialize_impl(T& dm, deserializer* source) { ...@@ -116,54 +116,21 @@ deserialize_impl(T& dm, deserializer* source) {
} }
template <class T> template <class T>
class uti_impl : public uniform_type_info { class uti_impl : public detail::abstract_uniform_type_info<T> {
public: public:
uti_impl(const char* tname) : m_native(&typeid(T)), m_name(tname) { using super = detail::abstract_uniform_type_info<T>;
// nop
}
bool equal_to(const std::type_info& ti) const override { uti_impl(const char* tname) : super(tname) {
// in some cases (when dealing with dynamic libraries), // nop
// 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();
} }
protected:
void serialize(const void* instance, serializer* sink) const { 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 { void deserialize(void* instance, deserializer* source) const {
deserialize_impl(deref(instance), source); deserialize_impl(super::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);
} }
const std::type_info* m_native;
std::string m_name;
}; };
template <class T> template <class T>
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
#include "caf/all.hpp" #include "caf/all.hpp"
#include "caf/io/all.hpp" #include "caf/io/all.hpp"
#include "caf/detail/type_nr.hpp"
using std::cout; using std::cout;
using std::endl; using std::endl;
...@@ -106,8 +108,61 @@ T& append(T& storage, U&& u, Us&&... us) { ...@@ -106,8 +108,61 @@ T& append(T& storage, U&& u, Us&&... us) {
return append(storage, std::forward<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() { int main() {
CAF_TEST(test_uniform_type); CAF_TEST(test_uniform_type);
check_builtin_type_nrs();
auto announce1 = announce<foo>("foo", &foo::value); auto announce1 = announce<foo>("foo", &foo::value);
auto announce2 = announce<foo>("foo", &foo::value); auto announce2 = announce<foo>("foo", &foo::value);
auto announce3 = 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