Commit 488ca971 authored by Dominik Charousset's avatar Dominik Charousset

refactored type name mapping

type names are now mapped using a static lookup table; all built-in types
information instances are now members of uniform_type_info_map to get rid
of as much heap allocations as possible
parent 31699f7f
......@@ -102,7 +102,6 @@ set(LIBCPPA_SRC
src/context_switching_actor.cpp
src/continuable_reader.cpp
src/continuable_writer.cpp
src/decorated_names_map.cpp
src/default_actor_addressing.cpp
src/default_actor_proxy.cpp
src/default_peer.cpp
......@@ -154,6 +153,7 @@ set(LIBCPPA_SRC
src/to_uniform_name.cpp
src/unicast_network.cpp
src/uniform_type_info.cpp
src/uniform_type_info_map.cpp
src/weak_ptr_anchor.cpp
src/yield_interface.cpp)
......
......@@ -25,7 +25,6 @@ cppa/detail/behavior_impl.hpp
cppa/detail/behavior_stack.hpp
cppa/detail/boxed.hpp
cppa/detail/container_tuple_view.hpp
cppa/detail/decorated_names_map.hpp
cppa/detail/decorated_tuple.hpp
cppa/detail/default_uniform_type_info_impl.hpp
cppa/detail/demangle.hpp
......@@ -122,6 +121,7 @@ cppa/option.hpp
cppa/partial_function.hpp
cppa/primitive_type.hpp
cppa/primitive_variant.hpp
cppa/prioritizing.hpp
cppa/process_information.hpp
cppa/qtsupport/actor_widget_mixin.hpp
cppa/receive.hpp
......@@ -131,6 +131,7 @@ cppa/sb_actor.hpp
cppa/scheduled_actor.hpp
cppa/scheduler.hpp
cppa/self.hpp
cppa/send.hpp
cppa/serializer.hpp
cppa/singletons.hpp
cppa/spawn_options.hpp
......@@ -227,7 +228,6 @@ src/channel.cpp
src/context_switching_actor.cpp
src/continuable_reader.cpp
src/continuable_writer.cpp
src/decorated_names_map.cpp
src/default_actor_addressing.cpp
src/default_actor_proxy.cpp
src/default_peer.cpp
......@@ -283,6 +283,7 @@ src/thread_pool_scheduler.cpp
src/to_uniform_name.cpp
src/unicast_network.cpp
src/uniform_type_info.cpp
src/uniform_type_info_map.cpp
src/weak_ptr_anchor.cpp
src/yield_interface.cpp
unit_testing/ping_pong.cpp
......@@ -306,5 +307,3 @@ unit_testing/test_sync_send.cpp
unit_testing/test_tuple.cpp
unit_testing/test_uniform_type.cpp
unit_testing/test_yield_interface.cpp
cppa/prioritizing.hpp
cppa/send.hpp
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_DECORATED_NAMES_MAP_HPP
#define CPPA_DECORATED_NAMES_MAP_HPP
#include <map>
#include <string>
#include "cppa/detail/singleton_mixin.hpp"
namespace cppa { namespace detail {
class decorated_names_map : public singleton_mixin<decorated_names_map> {
friend class singleton_mixin<decorated_names_map>;
public:
// returns either a decorated version of @p demangled_name or
// @p demangled_name itself
const std::string& decorate(const std::string& demangled_name) const;
private:
decorated_names_map();
std::map<std::string, std::string> m_map;
};
} } // namespace cppa::detail
#endif // DECORATED_NAMES_MAP_HPP
......@@ -50,7 +50,6 @@ class empty_tuple;
class group_manager;
class abstract_tuple;
class actor_registry;
class decorated_names_map;
class uniform_type_info_map;
class singleton_manager {
......@@ -79,8 +78,6 @@ class singleton_manager {
static empty_tuple* get_empty_tuple();
static decorated_names_map* get_decorated_names_map();
static opencl::command_dispatcher* get_command_dispatcher();
private:
......
......@@ -32,57 +32,93 @@
#define CPPA_UNIFORM_TYPE_INFO_MAP_HPP
#include <set>
#include <map>
#include <string>
#include <utility> // std::pair
#include <utility>
#include <type_traits>
#include "cppa/cppa_fwd.hpp"
#include "cppa/util/duration.hpp"
#include "cppa/util/type_list.hpp"
#include "cppa/detail/singleton_mixin.hpp"
#include "cppa/detail/default_uniform_type_info_impl.hpp"
namespace cppa { class uniform_type_info; }
namespace cppa { namespace detail {
using mapped_type_list = util::type_list<
bool,
any_tuple,
atom_value,
actor_ptr,
channel_ptr,
group_ptr,
process_information_ptr,
message_header,
std::nullptr_t,
util::duration,
util::void_type,
double,
float,
long double,
std::string,
std::u16string,
std::u32string,
std::map<std::string,std::string>
>;
using zipped_type_list = util::tl_zip_with_index<mapped_type_list>::type;
// lookup table for built-in types
extern const char* mapped_type_names[][2];
template<typename T>
constexpr const char* mapped_name() {
return mapped_type_names[util::tl_index_of<zipped_type_list,T>::value][1];
}
const char* mapped_name_by_decorated_name(const char* decorated_type_name);
// lookup table for integer types
extern const char* mapped_int_names[][2];
template<typename T>
constexpr const char* mapped_int_name() {
return mapped_int_names[sizeof(T)][std::is_signed<T>::value ? 1 : 0];
}
class uniform_type_info_map_helper;
// note: this class is implemented in uniform_type_info.cpp
class uniform_type_info_map : public singleton_mixin<uniform_type_info_map> {
class uniform_type_info_map {
friend class uniform_type_info_map_helper;
friend class singleton_mixin<uniform_type_info_map>;
public:
typedef std::set<std::string> set_type;
typedef std::map<std::string, uniform_type_info*> uti_map_type;
typedef std::map<int, std::pair<set_type, set_type> > int_map_type;
typedef const uniform_type_info* pointer;
inline const int_map_type& int_names() const {
return m_ints;
}
virtual ~uniform_type_info_map();
const uniform_type_info* by_raw_name(const std::string& name) const;
virtual pointer by_uniform_name(const std::string& name) const = 0;
const uniform_type_info* by_uniform_name(const std::string& name) const;
virtual pointer by_rtti(const std::type_info& ti) const = 0;
std::vector<const uniform_type_info*> get_all() const;
virtual std::vector<pointer> get_all() const = 0;
// NOT thread safe!
bool insert(const std::set<std::string>& raw_names, uniform_type_info* uti);
private:
// maps raw typeid names to uniform type informations
uti_map_type m_by_rname;
virtual bool insert(uniform_type_info* uti) = 0;
// maps uniform names to uniform type informations
uti_map_type m_by_uname;
static uniform_type_info_map* create_singleton();
// maps sizeof(-integer_type-) to { signed-names-set, unsigned-names-set }
int_map_type m_ints;
inline void dispose() { delete this; }
uniform_type_info_map();
inline void destroy() { delete this; }
~uniform_type_info_map();
virtual void initialize() = 0;
};
......
......@@ -67,10 +67,6 @@ inline detail::empty_tuple* get_empty_tuple() {
return detail::singleton_manager::get_empty_tuple();
}
inline detail::decorated_names_map* get_decorated_names_map() {
return detail::singleton_manager::get_decorated_names_map();
}
} // namespace cppa
#endif // CPPA_SINGLETONS_HPP
......@@ -186,12 +186,6 @@ class uniform_type_info {
*/
static std::vector<const uniform_type_info*> instances();
/**
* @brief Get the internal @p libcppa name for this type.
* @returns A string describing the @p libcppa internal type name.
*/
inline const std::string& name() const { return m_name; }
/**
* @brief Creates an object of this type.
*/
......@@ -202,6 +196,12 @@ class uniform_type_info {
*/
object deserialize(deserializer* source) const;
/**
* @brief Get the internal @p libcppa name for this type.
* @returns A string describing the @p libcppa internal type name.
*/
virtual const char* name() const = 0;
/**
* @brief Determines if this uniform_type_info describes the same
* type than @p tinfo.
......@@ -234,23 +234,9 @@ class uniform_type_info {
*/
virtual void deserialize(void* instance, deserializer* source) const = 0;
/**
* @brief Checks wheter <tt>src->seek_object()</tt>
* returns @p tname and throws an exception if not.
* @throws std::logic_error
*/
static void assert_type_name(deserializer* src, const std::string& tname);
protected:
/**
* @brief Checks wheter <tt>src->seek_object()</tt>
* returns {@link name()} and throws an exception if not.
* @throws std::logic_error
*/
void assert_type_name(deserializer* src) const;
uniform_type_info(const std::string& uniform_name);
uniform_type_info() = default;
/**
* @brief Casts @p instance to the native type and deletes it.
......@@ -270,10 +256,6 @@ class uniform_type_info {
*/
virtual void* new_instance(const void* instance = nullptr) const = 0;
private:
std::string m_name;
};
/**
......
......@@ -31,8 +31,11 @@
#ifndef CPPA_ABSTRACT_UNIFORM_TYPE_INFO_HPP
#define CPPA_ABSTRACT_UNIFORM_TYPE_INFO_HPP
#include "cppa/deserializer.hpp"
#include "cppa/uniform_type_info.hpp"
#include "cppa/detail/to_uniform_name.hpp"
#include "cppa/detail/uniform_type_info_map.hpp"
namespace cppa { namespace util {
......@@ -43,19 +46,23 @@ namespace cppa { namespace util {
template<typename T>
class abstract_uniform_type_info : public uniform_type_info {
inline static const T& deref(const void* ptr) {
return *reinterpret_cast<const T*>(ptr);
public:
bool equals(const std::type_info& tinfo) const {
return typeid(T) == tinfo;
}
inline static T& deref(void* ptr) {
return *reinterpret_cast<T*>(ptr);
const char* name() const {
return m_name.c_str();
}
protected:
abstract_uniform_type_info(const std::string& uname
= detail::to_uniform_name(typeid(T)))
: uniform_type_info(uname) {
abstract_uniform_type_info() {
auto uname = detail::to_uniform_name<T>();
auto cname = detail::mapped_name_by_decorated_name(uname.c_str());
if (cname == uname.c_str()) m_name = std::move(uname);
else m_name = cname;
}
bool equals(const void* lhs, const void* rhs) const {
......@@ -70,14 +77,32 @@ class abstract_uniform_type_info : public uniform_type_info {
delete reinterpret_cast<T*>(instance);
}
public:
void assert_type_name(deserializer* source) const {
auto tname = source->seek_object();
if (tname != name()) {
std::string error_msg = "wrong type name found; expected \"";
error_msg += name();
error_msg += "\", found \"";
error_msg += tname;
error_msg += "\"";
throw std::logic_error(std::move(error_msg));
}
}
bool equals(const std::type_info& tinfo) const {
return typeid(T) == tinfo;
private:
static inline const T& deref(const void* ptr) {
return *reinterpret_cast<const T*>(ptr);
}
static inline T& deref(void* ptr) {
return *reinterpret_cast<T*>(ptr);
}
std::string m_name;
};
} }
} } // namespace cppa::util
#endif // CPPA_ABSTRACT_UNIFORM_TYPE_INFO_HPP
......@@ -340,6 +340,18 @@ struct tl_zip_with_index<empty_type_list> {
typedef empty_type_list type;
};
// int index_of(list, type)
template<class List, typename T>
struct tl_index_of {
static constexpr size_t value = tl_index_of<typename tl_tail<List>::type,T>::value;
};
template<size_t N, typename T, typename... Ts>
struct tl_index_of<type_list<type_pair<std::integral_constant<size_t,N>,T>,Ts...>,T> {
static constexpr size_t value = N;
};
// list reverse()
template<class From, typename... Elements>
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#include <limits>
#include "cppa/detail/demangle.hpp"
#include "cppa/detail/decorated_names_map.hpp"
using namespace std;
namespace {
using namespace cppa;
using namespace cppa::detail;
constexpr const char* mapped_int_names[][2] = {
{ nullptr, nullptr }, // sizeof 0-> invalid
{ "@i8", "@u8" }, // sizeof 1 -> signed / unsigned int8
{ "@i16", "@u16" }, // sizeof 2 -> signed / unsigned int16
{ nullptr, nullptr }, // sizeof 3-> invalid
{ "@i32", "@u32" }, // sizeof 4 -> signed / unsigned int32
{ nullptr, nullptr }, // sizeof 5-> invalid
{ nullptr, nullptr }, // sizeof 6-> invalid
{ nullptr, nullptr }, // sizeof 7-> invalid
{ "@i64", "@u64" } // sizeof 8 -> signed / unsigned int64
};
template<typename T>
constexpr size_t sign_index() {
static_assert(numeric_limits<T>::is_integer, "T is not an integer");
return numeric_limits<T>::is_signed ? 0 : 1;
}
template<typename T>
inline string demangled() {
return demangle(typeid(T));
}
template<typename T>
constexpr const char* mapped_int_name() {
return mapped_int_names[sizeof(T)][sign_index<T>()];
}
template<typename T>
struct is_signed : integral_constant<bool, numeric_limits<T>::is_signed> { };
} // namespace <anonymous>
namespace cppa { namespace detail {
decorated_names_map::decorated_names_map() {
map<string, string> tmp = {
// integer types
{ demangled<char>(), mapped_int_name<char>() },
{ demangled<signed char>(), mapped_int_name<signed char>() },
{ demangled<unsigned char>(), mapped_int_name<unsigned char>() },
{ demangled<short>(), mapped_int_name<short>() },
{ demangled<signed short>(), mapped_int_name<signed short>() },
{ demangled<unsigned short>(), mapped_int_name<unsigned short>() },
{ demangled<short int>(), mapped_int_name<short int>() },
{ demangled<signed short int>(), mapped_int_name<signed short int>() },
{ demangled<unsigned short int>(), mapped_int_name<unsigned short int>()},
{ demangled<int>(), mapped_int_name<int>() },
{ demangled<signed int>(), mapped_int_name<signed int>() },
{ demangled<unsigned int>(), mapped_int_name<unsigned int>() },
{ demangled<long int>(), mapped_int_name<long int>() },
{ demangled<signed long int>(), mapped_int_name<signed long int>() },
{ demangled<unsigned long int>(), mapped_int_name<unsigned long int>() },
{ demangled<long>(), mapped_int_name<long>() },
{ demangled<signed long>(), mapped_int_name<signed long>() },
{ demangled<unsigned long>(), mapped_int_name<unsigned long>() },
{ demangled<long long>(), mapped_int_name<long long>() },
{ demangled<signed long long>(), mapped_int_name<signed long long>() },
{ demangled<unsigned long long>(), mapped_int_name<unsigned long long>()},
{ demangled<char16_t>(), mapped_int_name<char16_t>() },
{ demangled<char32_t>(), mapped_int_name<char32_t>() },
{ "cppa::atom_value", "@atom" },
{ "cppa::any_tuple", "@<>" },
{ "cppa::message_header", "@hdr" },
{ "cppa::intrusive_ptr<cppa::actor>", "@actor" },
{ "cppa::intrusive_ptr<cppa::group>" ,"@group" },
{ "cppa::intrusive_ptr<cppa::channel>", "@channel" },
{ "cppa::intrusive_ptr<cppa::process_information>", "@process_info" },
{ "std::basic_string<@i8,std::char_traits<@i8>,std::allocator<@i8>>", "@str" },
{ "std::basic_string<@u16,std::char_traits<@u16>,std::allocator<@u16>>", "@u16str" },
{ "std::basic_string<@u32,std::char_traits<@u32>,std::allocator<@u32>>", "@u32str"},
{ "std::map<@str,@str,std::less<@str>,std::allocator<std::pair<const @str,@str>>>", "@strmap" },
{ "std::string", "@str" }, // GCC
{ "cppa::util::void_type", "@0" }
};
m_map = move(tmp);
}
const string& decorated_names_map::decorate(const string& what) const {
auto i = m_map.find(what);
return (i != m_map.end()) ? i->second : what;
}
} } // namespace cppa::detail
......@@ -44,7 +44,6 @@
#include "cppa/detail/group_manager.hpp"
#include "cppa/detail/actor_registry.hpp"
#include "cppa/detail/singleton_manager.hpp"
#include "cppa/detail/decorated_names_map.hpp"
#include "cppa/detail/thread_pool_scheduler.hpp"
#include "cppa/detail/uniform_type_info_map.hpp"
......@@ -66,7 +65,6 @@ namespace {
std::atomic<opencl::command_dispatcher*> s_command_dispatcher;
std::atomic<uniform_type_info_map*> s_uniform_type_info_map;
std::atomic<decorated_names_map*> s_decorated_names_map;
std::atomic<network::middleman*> s_middleman;
std::atomic<actor_registry*> s_actor_registry;
std::atomic<group_manager*> s_group_manager;
......@@ -100,8 +98,6 @@ void singleton_manager::shutdown() {
destroy(s_empty_tuple);
CPPA_LOGF(CPPA_DEBUG, nullptr, "clear type info map");
destroy(s_uniform_type_info_map);
CPPA_LOGF(CPPA_DEBUG, nullptr, "clear decorated names log");
destroy(s_decorated_names_map);
destroy(s_logger);
}
......@@ -130,10 +126,6 @@ scheduler* singleton_manager::get_scheduler() {
return lazy_get(s_scheduler);
}
decorated_names_map* singleton_manager::get_decorated_names_map() {
return lazy_get(s_decorated_names_map);
}
logging* singleton_manager::get_logger() {
return lazy_get(s_logger);
}
......
......@@ -53,7 +53,7 @@ namespace cppa {
namespace {
bool isbuiltin(const string& type_name) {
return type_name == "@str" || type_name == "@atom" || type_name == "@<>";
return type_name == "@str" || type_name == "@atom" || type_name == "@tuple";
}
// serializes types as type_name(...) except:
......@@ -284,7 +284,7 @@ class string_deserializer : public deserializer {
return "@atom";
}
else if (*m_pos == '{') {
return "@<>";
return "@tuple";
}
// default case
auto substr_end = next_delimiter();
......
......@@ -32,6 +32,7 @@
#include <cwchar>
#include <limits>
#include <vector>
#include <cstring>
#include <typeinfo>
#include <stdexcept>
#include <algorithm>
......@@ -42,14 +43,14 @@
#include "cppa/channel.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/message_header.hpp"
#include "cppa/util/void_type.hpp"
#include "cppa/detail/demangle.hpp"
#include "cppa/detail/to_uniform_name.hpp"
#include "cppa/message_header.hpp"
#include "cppa/detail/singleton_manager.hpp"
#include "cppa/detail/decorated_names_map.hpp"
#include "cppa/detail/uniform_type_info_map.hpp"
namespace {
......@@ -57,6 +58,47 @@ using namespace std;
using namespace cppa;
using namespace detail;
struct platform_int_mapping { const char* name; size_t size; bool is_signed; };
// WARNING: this list is sorted and searched with std::lower_bound;
// keep ordered when adding elements!
platform_int_mapping platform_dependent_sizes[] = {
{"char", sizeof(char), true},
{"char16_t", sizeof(char16_t), true},
{"char32_t", sizeof(char32_t), true},
{"int", sizeof(int), true},
{"long", sizeof(long), true},
{"long int", sizeof(long int), true},
{"long long", sizeof(long long), true},
{"short", sizeof(short), true},
{"short int", sizeof(short int), true},
{"signed char", sizeof(signed char), true},
{"signed int", sizeof(signed int), true},
{"signed long", sizeof(signed long), true},
{"signed long int", sizeof(signed long int), true},
{"signed long long", sizeof(signed long long), true},
{"signed short", sizeof(signed short), true},
{"signed short int", sizeof(signed short int), true},
{"unsigned char", sizeof(unsigned char), false},
{"unsigned int", sizeof(unsigned int), false},
{"unsigned long", sizeof(unsigned long), false},
{"unsigned long int", sizeof(unsigned long int), false},
{"unsigned long long", sizeof(unsigned long long), false},
{"unsigned short", sizeof(unsigned short), false},
{"unsigned short int", sizeof(unsigned short int), false}
};
string map2decorated(const char* name) {
auto cmp = [](const platform_int_mapping& pim, const char* name) {
return strcmp(pim.name, name) < 0;
};
auto e = end(platform_dependent_sizes);
auto i = lower_bound(begin(platform_dependent_sizes), e, name, cmp);
if (i != e && strcmp(i->name, name) == 0) {
return mapped_int_names[i->size][i->is_signed ? 1 : 0];
}
return mapped_name_by_decorated_name(name);
}
class parse_tree {
......@@ -67,7 +109,7 @@ class parse_tree {
if (m_volatile) result += "volatile ";
if (m_const) result += "const ";
if (!m_template) {
result += dmm->decorate(m_name);
result += map2decorated(m_name.c_str());
}
else {
string full_name = m_name;
......@@ -79,7 +121,7 @@ class parse_tree {
}
full_name += ">";
// decorate full name
result += dmm->decorate(full_name);
result += map2decorated(full_name.c_str());
}
if (m_pointer) result += "*";
if (m_lvalue_ref) result += "&";
......@@ -167,9 +209,7 @@ class parse_tree {
parse_tree()
: m_const(false), m_pointer(false), m_volatile(false), m_template(false)
, m_lvalue_ref(false), m_rvalue_ref(false) {
dmm = singleton_manager::get_decorated_names_map();
}
, m_lvalue_ref(false), m_rvalue_ref(false) { }
bool m_const;
bool m_pointer;
......@@ -177,7 +217,6 @@ class parse_tree {
bool m_template;
bool m_lvalue_ref;
bool m_rvalue_ref;
const decorated_names_map* dmm;
string m_name;
vector<parse_tree> m_template_parameters;
......@@ -221,7 +260,7 @@ void replace_all(string& str, const char (&before)[RawSize], const char* after)
}
const char s_rawan[] = "anonymous namespace";
const char s_an[] = "@_";
const char s_an[] = "$";
} // namespace <anonymous>
......
......@@ -64,614 +64,24 @@
#include "cppa/message_header.hpp"
namespace cppa { namespace detail {
namespace {
// see 'to_uniform_names.cpp' for a list of all type names
std::string actor_ptr_tname = "@actor";
std::string group_ptr_tname = "@group";
std::string channel_ptr_tname = "@channel";
std::string any_tuple_tname = "@<>";
using namespace std;
inline uniform_type_info_map& uti_map() {
return *singleton_manager::get_uniform_type_info_map();
}
inline const char* raw_name(const type_info& tinfo) {
#ifdef CPPA_WINDOWS
return tinfo.raw_name();
#else
return tinfo.name();
#endif
}
template<typename T>
inline const char* raw_name() {
return raw_name(typeid(T));
}
typedef set<string> string_set;
typedef map<int, pair<string_set, string_set> > int_name_mapping;
template<typename Int>
inline void push_impl(int_name_mapping& ints, true_type) {
ints[sizeof(Int)].first.insert(raw_name<Int>()); // signed version
}
template<typename Int>
inline void push_impl(int_name_mapping& ints, false_type) {
ints[sizeof(Int)].second.insert(raw_name<Int>()); // unsigned version
}
template<typename Int>
inline void push(int_name_mapping& ints) {
push_impl<Int>(ints, is_signed<Int>{});
}
template<typename Int0, typename Int1, typename... Ints>
inline void push(int_name_mapping& ints) {
push_impl<Int0>(ints, is_signed<Int0>{});
push<Int1, Ints...>(ints);
}
const char s_nullptr_type_name[] = "@0";
void serialize_nullptr(serializer* sink) {
sink->begin_object(s_nullptr_type_name);
sink->end_object();
}
void deserialize_nullptr(deserializer* source) {
source->begin_object(s_nullptr_type_name);
source->end_object();
}
} // namespace <anonymous>
class void_type_tinfo : public uniform_type_info {
public:
void_type_tinfo() : uniform_type_info(to_uniform_name<util::void_type>()) {}
bool equals(const type_info &tinfo) const {
return typeid(util::void_type) == tinfo;
}
protected:
void serialize(const void*, serializer* sink) const {
serialize_nullptr(sink);
}
void deserialize(void*, deserializer* source) const {
string cname = source->seek_object();
if (cname != name()) {
throw logic_error("wrong type name found");
}
deserialize_nullptr(source);
}
bool equals(const void*, const void*) const {
return true;
}
void* new_instance(const void*) const {
// const_cast cannot cause any harm, because void_type is immutable
return const_cast<void*>(static_cast<const void*>(&m_value));
}
void delete_instance(void* instance) const {
CPPA_REQUIRE(instance == &m_value);
// keep compiler happy (suppress unused argument warning)
static_cast<void>(instance);
}
private:
util::void_type m_value;
};
class actor_ptr_tinfo : public util::abstract_uniform_type_info<actor_ptr> {
public:
static void s_serialize(const actor_ptr& ptr, serializer* sink) {
auto impl = sink->addressing();
if (impl) impl->write(sink, ptr);
else throw std::runtime_error("unable to serialize actor_ptr: "
"no actor addressing defined");
}
static void s_deserialize(actor_ptr& ptrref, deserializer* source) {
auto impl = source->addressing();
if (impl) ptrref = impl->read(source);
else throw std::runtime_error("unable to deserialize actor_ptr: "
"no actor addressing defined");
}
protected:
void serialize(const void* ptr, serializer* sink) const {
s_serialize(*reinterpret_cast<const actor_ptr*>(ptr), sink);
}
void deserialize(void* ptr, deserializer* source) const {
s_deserialize(*reinterpret_cast<actor_ptr*>(ptr), source);
}
};
class group_ptr_tinfo : public util::abstract_uniform_type_info<group_ptr> {
public:
static void s_serialize(const group_ptr& ptr, serializer* sink) {
if (ptr == nullptr) {
serialize_nullptr(sink);
}
else {
sink->begin_object(group_ptr_tname);
sink->write_value(ptr->module_name());
ptr->serialize(sink);
sink->end_object();
}
}
static void s_deserialize(group_ptr& ptrref, deserializer* source) {
auto cname = source->seek_object();
if (cname != group_ptr_tname) {
if (cname == s_nullptr_type_name) {
deserialize_nullptr(source);
ptrref.reset();
}
else assert_type_name(source, group_ptr_tname); // throws
}
else {
source->begin_object(group_ptr_tname);
auto modname = source->read<string>();
ptrref = group::get_module(modname)
->deserialize(source);
source->end_object();
}
}
protected:
void serialize(const void* ptr, serializer* sink) const {
s_serialize(*reinterpret_cast<const group_ptr*>(ptr), sink);
}
void deserialize(void* ptr, deserializer* source) const {
s_deserialize(*reinterpret_cast<group_ptr*>(ptr), source);
}
};
class channel_ptr_tinfo : public util::abstract_uniform_type_info<channel_ptr> {
public:
static void s_serialize(const channel_ptr& ptr, serializer* sink) {
sink->begin_object(channel_ptr_tname);
if (ptr == nullptr) serialize_nullptr(sink);
else {
auto aptr = ptr.downcast<actor>();
if (aptr) actor_ptr_tinfo::s_serialize(aptr, sink);
else {
auto gptr = ptr.downcast<group>();
if (gptr) group_ptr_tinfo::s_serialize(gptr, sink);
else throw logic_error("channel is neither "
"an actor nor a group");
}
}
sink->end_object();
}
static void s_deserialize(channel_ptr& ptrref, deserializer* source) {
assert_type_name(source, channel_ptr_tname);
source->begin_object(channel_ptr_tname);
string subobj = source->peek_object();
if (subobj == actor_ptr_tname) {
actor_ptr tmp;
actor_ptr_tinfo::s_deserialize(tmp, source);
ptrref = tmp;
}
else if (subobj == group_ptr_tname) {
group_ptr tmp;
group_ptr_tinfo::s_deserialize(tmp, source);
ptrref = tmp;
}
else if (subobj == s_nullptr_type_name) { (void) source->seek_object();
deserialize_nullptr(source);
ptrref.reset();
}
else {
throw logic_error("unexpected type name: " + subobj);
}
source->end_object();
}
protected:
void serialize(const void* instance, serializer* sink) const {
s_serialize(*reinterpret_cast<const channel_ptr*>(instance), sink);
}
void deserialize(void* instance, deserializer* source) const {
s_deserialize(*reinterpret_cast<channel_ptr*>(instance), source);
}
};
class any_tuple_tinfo : public util::abstract_uniform_type_info<any_tuple> {
public:
static void s_serialize(const any_tuple& atup, serializer* sink) {
sink->begin_object(any_tuple_tname);
sink->begin_sequence(atup.size());
for (size_t i = 0; i < atup.size(); ++i) {
atup.type_at(i)->serialize(atup.at(i), sink);
}
sink->end_sequence();
sink->end_object();
}
static void s_deserialize(any_tuple& atref, deserializer* source) {
uniform_type_info::assert_type_name(source, any_tuple_tname);
auto result = new detail::object_array;
source->begin_object(any_tuple_tname);
size_t tuple_size = source->begin_sequence();
for (size_t i = 0; i < tuple_size; ++i) {
auto tname = source->peek_object();
auto utype = uniform_type_info::from(tname);
result->push_back(utype->deserialize(source));
}
source->end_sequence();
source->end_object();
atref = any_tuple{result};
}
protected:
void serialize(const void* instance, serializer* sink) const {
s_serialize(*reinterpret_cast<const any_tuple*>(instance), sink);
}
void deserialize(void* instance, deserializer* source) const {
s_deserialize(*reinterpret_cast<any_tuple*>(instance), source);
}
};
class msg_hdr_tinfo : public util::abstract_uniform_type_info<message_header> {
public:
virtual void serialize(const void* instance, serializer* sink) const {
auto& hdr = *reinterpret_cast<const message_header*>(instance);
sink->begin_object(name());
actor_ptr_tinfo::s_serialize(hdr.sender, sink);
channel_ptr_tinfo::s_serialize(hdr.receiver, sink);
sink->write_value(hdr.id.integer_value());
sink->end_object();
}
virtual void deserialize(void* instance, deserializer* source) const {
assert_type_name(source);
source->begin_object(name());
auto& msg = *reinterpret_cast<message_header*>(instance);
actor_ptr_tinfo::s_deserialize(msg.sender, source);
channel_ptr_tinfo::s_deserialize(msg.receiver, source);
auto msg_id = source->read<std::uint64_t>();
msg.id = message_id::from_integer_value(msg_id);
source->end_object();
}
};
class process_info_ptr_tinfo : public util::abstract_uniform_type_info<process_information_ptr> {
typedef process_information_ptr ptr_type;
public:
virtual void serialize(const void* instance, serializer* sink) const {
auto& ptr = *reinterpret_cast<const ptr_type*>(instance);
if (ptr == nullptr) {
serialize_nullptr(sink);
}
else {
sink->begin_object(name());
sink->write_value(ptr->process_id());
sink->write_raw(ptr->node_id().size(), ptr->node_id().data());
sink->end_object();
}
}
virtual void deserialize(void* instance, deserializer* source) const {
auto& ptrref = *reinterpret_cast<ptr_type*>(instance);
auto cname = source->seek_object();
if (cname != name()) {
if (cname == s_nullptr_type_name) {
deserialize_nullptr(source);
ptrref.reset();
}
else assert_type_name(source); // throws
}
else {
source->begin_object(cname);
auto id = source->read<uint32_t>();
process_information::node_id_type nid;
source->read_raw(nid.size(), nid.data());
source->end_object();
ptrref.reset(new process_information{id, nid});
}
}
};
class atom_value_tinfo : public util::abstract_uniform_type_info<atom_value> {
public:
virtual void serialize(const void* instance, serializer* sink) const {
auto val = reinterpret_cast<const atom_value*>(instance);
sink->begin_object(name());
sink->write_value(static_cast<uint64_t>(*val));
sink->end_object();
}
virtual void deserialize(void* instance, deserializer* source) const {
assert_type_name(source);
auto val = reinterpret_cast<atom_value*>(instance);
source->begin_object(name());
*val = static_cast<atom_value>(source->read<uint64_t>());
source->end_object();
}
};
class duration_tinfo : public util::abstract_uniform_type_info<util::duration> {
virtual void serialize(const void* instance, serializer* sink) const {
auto val = reinterpret_cast<const util::duration*>(instance);
sink->begin_object(name());
sink->write_value(static_cast<uint32_t>(val->unit));
sink->write_value(val->count);
sink->end_object();
}
virtual void deserialize(void* instance, deserializer* source) const {
assert_type_name(source);
source->begin_object(name());
auto val = reinterpret_cast<util::duration*>(instance);
auto unit_val = source->read<uint32_t>();
auto count_val = source->read<uint32_t>();
source->end_object();
switch (unit_val) {
case 1:
val->unit = util::time_unit::seconds;
break;
case 1000:
val->unit = util::time_unit::milliseconds;
break;
case 1000000:
val->unit = util::time_unit::microseconds;
break;
default:
val->unit = util::time_unit::none;
break;
}
val->count = count_val;
}
};
template<typename T>
class int_tinfo : public detail::default_uniform_type_info_impl<T> {
public:
bool equals(const type_info& tinfo) const {
// TODO: string comparsion sucks & is slow; find a nicer solution
auto map_iter = uti_map().int_names().find(sizeof(T));
const string_set& st = is_signed<T>::value ? map_iter->second.first
: map_iter->second.second;
auto x = raw_name(tinfo);
return any_of(st.begin(), st.end(),
[&x](const string& y) { return x == y; });
}
};
class bool_tinfo : public util::abstract_uniform_type_info<bool> {
public:
virtual void serialize(const void* instance, serializer* sink) const {
auto val = *reinterpret_cast<const bool*>(instance);
sink->begin_object(name());
sink->write_value(static_cast<uint8_t>(val ? 1 : 0));
sink->end_object();
}
virtual void deserialize(void* instance, deserializer* source) const {
assert_type_name(source);
source->begin_object(name());
*reinterpret_cast<bool*>(instance) = source->read<uint8_t>() != 0;
source->end_object();
}
};
class uniform_type_info_map_helper {
public:
uniform_type_info_map_helper(uniform_type_info_map* umap) : d(umap) { }
template<typename T>
inline void insert_int() {
d->insert(d->m_ints[sizeof(T)].first, new int_tinfo<T>);
}
template<typename T>
inline void insert_uint() {
d->insert(d->m_ints[sizeof(T)].second, new int_tinfo<T>);
}
template<typename T>
inline void insert_builtin() {
d->insert({raw_name<T>()}, new default_uniform_type_info_impl<T>);
}
private:
uniform_type_info_map* d;
};
uniform_type_info_map::uniform_type_info_map() {
// inserts all compiler generated raw-names to m_ings
push<char, signed char,
unsigned char, short,
signed short, unsigned short,
short int, signed short int,
unsigned short int, int,
signed int, unsigned int,
long int, signed long int,
unsigned long int, long,
signed long, unsigned long,
long long, signed long long,
unsigned long long, wchar_t,
std::int8_t, std::uint8_t,
std::int16_t, std::uint16_t,
std::int32_t, std::uint32_t,
std::int64_t, std::uint64_t,
char16_t, char32_t,
size_t, ptrdiff_t,
intptr_t >(m_ints);
uniform_type_info_map_helper helper{this};
// inserts integer type infos
helper.insert_int<std::int8_t>();
helper.insert_int<std::int16_t>();
helper.insert_int<std::int32_t>();
helper.insert_int<std::int64_t>();
helper.insert_uint<std::uint8_t>();
helper.insert_uint<std::uint16_t>();
helper.insert_uint<std::uint32_t>();
helper.insert_uint<std::uint64_t>();
// insert type infos for "built-in" types
helper.insert_builtin<float>();
helper.insert_builtin<double>();
helper.insert_builtin<long double>();
helper.insert_builtin<std::string>();
helper.insert_builtin<std::u16string>();
helper.insert_builtin<std::u32string>();
// bool needs some special handling, because it hasn't a guaranteed size
insert({raw_name<bool>()}, new bool_tinfo);
// insert cppa types
insert({raw_name<util::duration>()}, new duration_tinfo);
insert({raw_name<any_tuple>()}, new any_tuple_tinfo);
insert({raw_name<actor_ptr>()}, new actor_ptr_tinfo);
insert({raw_name<group_ptr>()}, new group_ptr_tinfo);
insert({raw_name<channel_ptr>()}, new channel_ptr_tinfo);
insert({raw_name<atom_value>()}, new atom_value_tinfo);
insert({raw_name<message_header>()}, new msg_hdr_tinfo);
insert({raw_name<util::void_type>()}, new void_type_tinfo);
insert({raw_name<process_information_ptr>()}, new process_info_ptr_tinfo);
insert({raw_name<map<string,string>>()}, new default_uniform_type_info_impl<map<string,string>>);
}
uniform_type_info_map::~uniform_type_info_map() {
m_by_rname.clear();
for (auto& kvp : m_by_uname) {
delete kvp.second;
kvp.second = nullptr;
}
m_by_uname.clear();
}
const uniform_type_info* uniform_type_info_map::by_raw_name(const std::string& name) const {
auto i = m_by_rname.find(name);
return (i != m_by_rname.end()) ? i->second : nullptr;
}
const uniform_type_info* uniform_type_info_map::by_uniform_name(const std::string& name) const {
auto i = m_by_uname.find(name);
return (i != m_by_uname.end()) ? i->second : nullptr;
}
bool uniform_type_info_map::insert(const std::set<std::string>& raw_names,
uniform_type_info* what) {
if (m_by_uname.count(what->name()) > 0) {
delete what;
return false;
}
m_by_uname.insert(std::make_pair(what->name(), what));
for (auto& plain_name : raw_names) {
if (!m_by_rname.insert(std::make_pair(plain_name, what)).second) {
std::string error_str = plain_name;
error_str += " already mapped to an uniform_type_info";
throw std::runtime_error(error_str);
}
}
return true;
}
std::vector<const uniform_type_info*> uniform_type_info_map::get_all() const {
std::vector<const uniform_type_info*> result;
result.reserve(m_by_uname.size());
for (const uti_map_type::value_type& i : m_by_uname) {
result.push_back(i.second);
}
return std::move(result);
}
} } // namespace cppa::detail
namespace cppa {
bool announce(const std::type_info& tinfo, uniform_type_info* utype) {
return detail::uti_map().insert({detail::raw_name(tinfo)}, utype);
}
uniform_type_info::uniform_type_info(const std::string& str) : m_name(str) { }
uniform_type_info::~uniform_type_info() { }
namespace { inline detail::uniform_type_info_map& uti_map() {
return *detail::singleton_manager::get_uniform_type_info_map();
} } // namespace <anonymous>
void uniform_type_info::assert_type_name(deserializer* source,
const std::string& expected_name) {
auto tname = source->seek_object();
if (tname != expected_name) {
std::string error_msg = "wrong type name found; expected \"";
error_msg += expected_name;
error_msg += "\", found \"";
error_msg += tname;
error_msg += "\"";
throw std::logic_error(std::move(error_msg));
}
bool announce(const std::type_info&, uniform_type_info* utype) {
return uti_map().insert(utype);
}
void uniform_type_info::assert_type_name(deserializer* source) const {
assert_type_name(source, name());
}
uniform_type_info::~uniform_type_info() { }
object uniform_type_info::create() const {
return {new_instance(), this};
}
const uniform_type_info* uniform_type_info::from(const std::type_info& tinf) {
auto result = detail::uti_map().by_raw_name(detail::raw_name(tinf));
auto result = uti_map().by_rtti(tinf);
if (result == nullptr) {
std::string error = "uniform_type_info::by_type_info(): ";
error += detail::to_uniform_name(tinf);
......@@ -683,7 +93,7 @@ const uniform_type_info* uniform_type_info::from(const std::type_info& tinf) {
}
const uniform_type_info* uniform_type_info::from(const std::string& name) {
auto result = detail::uti_map().by_uniform_name(name);
auto result = uti_map().by_uniform_name(name);
if (result == nullptr) {
throw std::runtime_error(name + " is an unknown typeid name");
}
......@@ -697,7 +107,7 @@ object uniform_type_info::deserialize(deserializer* from) const {
}
std::vector<const uniform_type_info*> uniform_type_info::instances() {
return detail::uti_map().get_all();
return uti_map().get_all();
}
const uniform_type_info* uniform_typeid(const std::type_info& tinfo) {
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#include <array>
#include <string>
#include <vector>
#include <cstring>
#include <algorithm>
#include "cppa/any_tuple.hpp"
#include "cppa/message_header.hpp"
#include "cppa/actor_addressing.hpp"
#include "cppa/util/duration.hpp"
#include "cppa/util/limited_vector.hpp"
#include "cppa/detail/uniform_type_info_map.hpp"
#include "cppa/detail/default_uniform_type_info_impl.hpp"
namespace cppa { namespace detail {
// maps demangled names to libcppa names
// WARNING: this map is sorted, insert new elements *in sorted order* as well!
/* extern */ const char* mapped_type_names[][2] = {
{ "bool", "bool" },
{ "cppa::any_tuple", "@tuple" },
{ "cppa::atom_value", "@atom" },
{ "cppa::intrusive_ptr<cppa::actor>", "@actor" },
{ "cppa::intrusive_ptr<cppa::channel>", "@channel" },
{ "cppa::intrusive_ptr<cppa::group>", "@group" },
{ "cppa::intrusive_ptr<cppa::process_information>", "@proc"},
{ "cppa::message_header", "@header" },
{ "cppa::nullptr_t", "@null" },
{ "cppa::util::duration", "@duration" },
{ "cppa::util::void_type", "@0" },
{ "double", "double" },
{ "float", "float" },
{ "long double", "@ldouble" },
{ "std::basic_string<@i8,std::char_traits<@i8>,std::allocator<@i8>>", "@str" },
{ "std::basic_string<@u16,std::char_traits<@u16>,std::allocator<@u16>>", "@u16str" },
{ "std::basic_string<@u32,std::char_traits<@u32>,std::allocator<@u32>>", "@u32str" },
{ "std::map<@str,@str,std::less<@str>,std::allocator<std::pair<const @str,@str>>>", "@strmap" }
};
// 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"}
};
const char* mapped_name_by_decorated_name(const char* cstr) {
using namespace std;
auto cmp = [](const char** lhs, const char* rhs) {
return strcmp(lhs[0], rhs) < 0;
};
auto e = end(mapped_type_names);
auto i = lower_bound(begin(mapped_type_names), e, cstr, cmp);
if (i != e && strcmp(cstr, (*i)[0]) == 0) return (*i)[1];
# if defined(__GNUC__) && !defined(__clang__)
// for some reason, GCC returns "std::string" as RTTI type name
// instead of std::basic_string<...>
if (strcmp("std::string", cstr) == 0) return mapped_name<std::string>();
# endif
return cstr;
}
namespace {
inline bool operator==(const util::void_type&, const util::void_type&) {
return true;
}
template<typename T> struct type_token { };
void serialize_nullptr(serializer* sink) {
sink->begin_object(mapped_name<std::nullptr_t>());
sink->end_object();
}
void deserialize_nullptr(deserializer* source) {
source->begin_object(mapped_name<std::nullptr_t>());
source->end_object();
}
void assert_type_name(const char* expected_name, deserializer* source) {
auto tname = source->seek_object();
if (tname != expected_name) {
std::string error_msg = "wrong type name found; expected \"";
error_msg += expected_name;
error_msg += "\", found \"";
error_msg += tname;
error_msg += "\"";
throw std::logic_error(std::move(error_msg));
}
}
template<typename T>
void serialize_impl(const T& val, serializer* sink) {
sink->begin_object(mapped_name<T>());
sink->write_value(val);
sink->end_object();
}
template<typename T>
void deserialize_impl(T& val, deserializer* source) {
assert_type_name(mapped_name<T>(), source);
source->begin_object(mapped_name<T>());
val = source->read<T>();
source->end_object();
}
void serialize_impl(const util::void_type&, serializer* sink) {
sink->begin_object(mapped_name<util::void_type>());
sink->end_object();
}
void deserialize_impl(util::void_type&, deserializer* source) {
auto tname = mapped_name<util::void_type>();
assert_type_name(tname, source);
source->begin_object(tname);
source->end_object();
}
void serialize_impl(const actor_ptr& ptr, serializer* sink) {
auto impl = sink->addressing();
if (impl) impl->write(sink, ptr);
else throw std::runtime_error("unable to serialize actor_ptr: "
"no actor addressing defined");
}
void deserialize_impl(actor_ptr& ptrref, deserializer* source) {
auto impl = source->addressing();
if (impl) ptrref = impl->read(source);
else throw std::runtime_error("unable to deserialize actor_ptr: "
"no actor addressing defined");
}
void serialize_impl(const group_ptr& ptr, serializer* sink) {
if (ptr == nullptr) serialize_nullptr(sink);
else {
sink->begin_object(mapped_name<group_ptr>());
sink->write_value(ptr->module_name());
ptr->serialize(sink);
sink->end_object();
}
}
void deserialize_impl(group_ptr& ptrref, deserializer* source) {
auto tname = mapped_name<group_ptr>();
auto cname = source->seek_object();
if (cname != tname) {
if (cname == mapped_name<std::nullptr_t>()) {
deserialize_nullptr(source);
ptrref.reset();
}
else assert_type_name(tname, source); // throws
}
else {
source->begin_object(tname);
auto modname = source->read<std::string>();
ptrref = group::get_module(modname)
->deserialize(source);
source->end_object();
}
}
void serialize_impl(const channel_ptr& ptr, serializer* sink) {
auto tname = mapped_name<channel_ptr>();
sink->begin_object(tname);
if (ptr == nullptr) serialize_nullptr(sink);
else {
auto aptr = ptr.downcast<actor>();
if (aptr) serialize_impl(aptr, sink);
else {
auto gptr = ptr.downcast<group>();
if (gptr) serialize_impl(gptr, sink);
else throw std::logic_error("channel is neither "
"an actor nor a group");
}
}
sink->end_object();
}
void deserialize_impl(channel_ptr& ptrref, deserializer* source) {
auto tname = mapped_name<channel_ptr>();
assert_type_name(tname, source);
source->begin_object(tname);
auto subobj = source->peek_object();
if (subobj == mapped_name<actor_ptr>()) {
actor_ptr tmp;
deserialize_impl(tmp, source);
ptrref = tmp;
}
else if (subobj == mapped_name<group_ptr>()) {
group_ptr tmp;
deserialize_impl(tmp, source);
ptrref = tmp;
}
else if (subobj == mapped_name<std::nullptr_t>()) {
static_cast<void>(source->seek_object());
deserialize_nullptr(source);
ptrref.reset();
}
else throw std::logic_error("unexpected type name: " + subobj);
source->end_object();
}
void serialize_impl(const any_tuple& tup, serializer* sink) {
auto tname = mapped_name<any_tuple>();
sink->begin_object(tname);
sink->begin_sequence(tup.size());
for (size_t i = 0; i < tup.size(); ++i) {
tup.type_at(i)->serialize(tup.at(i), sink);
}
sink->end_sequence();
sink->end_object();
}
void deserialize_impl(any_tuple& atref, deserializer* source) {
auto tname = mapped_name<any_tuple>();
assert_type_name(tname, source);
auto result = new detail::object_array;
source->begin_object(tname);
size_t tuple_size = source->begin_sequence();
for (size_t i = 0; i < tuple_size; ++i) {
auto uname = source->peek_object();
auto utype = uniform_type_info::from(uname);
result->push_back(utype->deserialize(source));
}
source->end_sequence();
source->end_object();
atref = any_tuple{result};
}
void serialize_impl(const message_header& hdr, serializer* sink) {
auto tname = mapped_name<message_header>();
sink->begin_object(tname);
serialize_impl(hdr.sender, sink);
serialize_impl(hdr.receiver, sink);
sink->write_value(hdr.id.integer_value());
sink->end_object();
}
void deserialize_impl(message_header& hdr, deserializer* source) {
auto tname = mapped_name<message_header>();
assert_type_name(tname, source);
source->begin_object(tname);
deserialize_impl(hdr.sender, source);
deserialize_impl(hdr.receiver, source);
auto msg_id = source->read<std::uint64_t>();
hdr.id = message_id::from_integer_value(msg_id);
source->end_object();
}
void serialize_impl(const process_information_ptr& ptr, serializer* sink) {
if (ptr == nullptr) serialize_nullptr(sink);
else {
auto tname = mapped_name<process_information_ptr>();
sink->begin_object(tname);
sink->write_value(ptr->process_id());
sink->write_raw(ptr->node_id().size(), ptr->node_id().data());
sink->end_object();
}
}
void deserialize_impl(process_information_ptr& ptr, deserializer* source) {
auto tname = mapped_name<process_information_ptr>();
auto cname = source->seek_object();
if (cname != tname) {
if (cname == mapped_name<std::nullptr_t>()) {
deserialize_nullptr(source);
ptr.reset();
}
else assert_type_name(tname, source); // throws
}
else {
source->begin_object(tname);
auto id = source->read<uint32_t>();
process_information::node_id_type nid;
source->read_raw(nid.size(), nid.data());
source->end_object();
ptr.reset(new process_information{id, nid});
}
}
void serialize_impl(const atom_value& val, serializer* sink) {
sink->begin_object(mapped_name<atom_value>());
sink->write_value(static_cast<uint64_t>(val));
sink->end_object();
}
void deserialize_impl(atom_value& val, deserializer* source) {
auto tname = mapped_name<atom_value>();
assert_type_name(tname, source);
source->begin_object(tname);
val = static_cast<atom_value>(source->read<uint64_t>());
source->end_object();
}
void serialize_impl(const util::duration& val, serializer* sink) {
auto tname = mapped_name<util::duration>();
sink->begin_object(tname);
sink->write_value(static_cast<uint32_t>(val.unit));
sink->write_value(val.count);
sink->end_object();
}
void deserialize_impl(util::duration& val, deserializer* source) {
auto tname = mapped_name<util::duration>();
assert_type_name(tname, source);
source->begin_object(tname);
auto unit_val = source->read<uint32_t>();
auto count_val = source->read<uint32_t>();
source->end_object();
switch (unit_val) {
case 1:
val.unit = util::time_unit::seconds;
break;
case 1000:
val.unit = util::time_unit::milliseconds;
break;
case 1000000:
val.unit = util::time_unit::microseconds;
break;
default:
val.unit = util::time_unit::none;
break;
}
val.count = count_val;
}
void serialize_impl(bool val, serializer* sink) {
sink->begin_object(mapped_name<bool>());
sink->write_value(static_cast<uint8_t>(val ? 1 : 0));
sink->end_object();
}
void deserialize_impl(bool& val, deserializer* source) {
auto tname = mapped_name<bool>();
assert_type_name(tname, source);
source->begin_object(tname);
val = source->read<uint8_t>() != 0;
source->end_object();
}
inline 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<typename T>
class uti_base : public uniform_type_info {
protected:
uti_base() : m_native(&typeid(T)) { }
bool equals(const std::type_info& ti) const {
return types_equal(m_native, &ti);
}
bool equals(const void* lhs, const void* rhs) const {
return deref(lhs) == deref(rhs);
}
void* new_instance(const void* ptr) const {
return (ptr) ? new T(deref(ptr)) : new T;
}
void delete_instance(void* instance) const {
delete reinterpret_cast<T*>(instance);
}
static inline const T& deref(const void* ptr) {
return *reinterpret_cast<const T*>(ptr);
}
static inline T& deref(void* ptr) {
return *reinterpret_cast<T*>(ptr);
}
const std::type_info* m_native;
};
template<typename T>
class uti_impl : public uti_base<T> {
typedef uti_base<T> super;
public:
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<typename T>
class int_tinfo : public abstract_int_tinfo {
public:
void serialize(const void* instance, serializer* sink) const {
auto& val = deref(instance);
sink->begin_object(static_name());
sink->write_value(val);
sink->end_object();
}
void deserialize(void* instance, deserializer* source) const {
assert_type_name(static_name(), source);
auto& ref = deref(instance);
source->begin_object(static_name());
ref = source->read<T>();
source->end_object();
}
const char* name() const {
return static_name();
}
protected:
bool equals(const std::type_info& ti) const {
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 {
return deref(lhs) == deref(rhs);
}
void* new_instance(const void* ptr) const {
return (ptr) ? new T(deref(ptr)) : new T;
}
void delete_instance(void* instance) const {
delete reinterpret_cast<T*>(instance);
}
private:
inline static const T& deref(const void* ptr) {
return *reinterpret_cast<const T*>(ptr);
}
inline static T& deref(void* ptr) {
return *reinterpret_cast<T*>(ptr);
}
static inline const char* static_name() {
return mapped_int_name<T>();
}
};
template<typename 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<typename T0, typename T1, typename... Ts>
void push_native_type(abstract_int_tinfo* m [][2]) {
push_native_type<T0>(m);
push_native_type<T1,Ts...>(m);
}
class utim_impl : public uniform_type_info_map {
public:
void initialize() {
// maps sizeof(integer_type) to {signed_type, unsigned_type}
abstract_int_tinfo* mapping[][2] = {
{nullptr, nullptr}, // no integer type for sizeof(T) == 0
{&m_type_u8, &m_type_i8},
{&m_type_u16, &m_type_i16},
{nullptr, nullptr}, // no integer type for sizeof(T) == 3
{&m_type_u32, &m_type_i32},
{nullptr, nullptr}, // no integer type for sizeof(T) == 5
{nullptr, nullptr}, // no integer type for sizeof(T) == 6
{nullptr, nullptr}, // no integer type for sizeof(T) == 7
{&m_type_u64, &m_type_i64}
};
push_native_type<char, signed char,
unsigned char, short,
signed short, unsigned short,
short int, signed short int,
unsigned short int, int,
signed int, unsigned int,
long int, signed long int,
unsigned long int, long,
signed long, unsigned long,
long long, signed long long,
unsigned long long, wchar_t,
std::int8_t, std::uint8_t,
std::int16_t, std::uint16_t,
std::int32_t, std::uint32_t,
std::int64_t, std::uint64_t,
char16_t, char32_t,
size_t, ptrdiff_t,
intptr_t >(mapping);
// fill builtin types *in sorted order* (by uniform name)
size_t i = 0;
m_builtin_types[i++] = &m_type_void;
m_builtin_types[i++] = &m_type_actor;
m_builtin_types[i++] = &m_type_atom;
m_builtin_types[i++] = &m_type_channel;
m_builtin_types[i++] = &m_type_duration;
m_builtin_types[i++] = &m_type_group;
m_builtin_types[i++] = &m_type_header;
m_builtin_types[i++] = &m_type_i16;
m_builtin_types[i++] = &m_type_i32;
m_builtin_types[i++] = &m_type_i64;
m_builtin_types[i++] = &m_type_i8;
m_builtin_types[i++] = &m_type_long_double;
m_builtin_types[i++] = &m_type_proc;
m_builtin_types[i++] = &m_type_str;
m_builtin_types[i++] = &m_type_strmap;
m_builtin_types[i++] = &m_type_tuple;
m_builtin_types[i++] = &m_type_u16;
m_builtin_types[i++] = &m_type_u16str;
m_builtin_types[i++] = &m_type_u32;
m_builtin_types[i++] = &m_type_u32str;
m_builtin_types[i++] = &m_type_u64;
m_builtin_types[i++] = &m_type_u8;
m_builtin_types[i++] = &m_type_bool;
m_builtin_types[i++] = &m_type_double;
m_builtin_types[i++] = &m_type_float;
CPPA_REQUIRE(i == m_builtin_types.size());
# if CPPA_DEBUG_MODE
auto cmp = [](pointer lhs, pointer rhs) {
return strcmp(lhs->name(), rhs->name()) < 0;
};
if (!std::is_sorted(m_builtin_types.begin(), m_builtin_types.end(), cmp)) {
std::cerr << "FATAL: uniform type map not sorted" << std::endl;
std::cerr << "order is:" << std::endl;
for (auto ptr : m_builtin_types) std::cerr << ptr->name() << std::endl;
std::sort(m_builtin_types.begin(), m_builtin_types.end(), cmp);
std::cerr << "\norder should be:" << std::endl;
for (auto ptr : m_builtin_types) std::cerr << ptr->name() << std::endl;
abort();
}
auto cmp2 = [](const char** lhs, const char** rhs) {
return strcmp(lhs[0], rhs[0]) < 0;
};
if (!std::is_sorted(std::begin(mapped_type_names), std::end(mapped_type_names), cmp2)) {
std::cerr << "FATAL: mapped_type_names not sorted" << std::endl;
abort();
}
# endif
}
pointer by_rtti(const std::type_info& ti) const {
auto res = find_rtti(m_builtin_types, ti);
return (res) ? res : find_rtti(m_user_types, ti);
}
pointer by_uniform_name(const std::string& name) const {
auto res = find_name(m_builtin_types, name);
return (res) ? res : find_name(m_user_types, name);
}
std::vector<pointer> get_all() const {
std::vector<pointer> res;
res.reserve(m_builtin_types.size() + m_user_types.size());
res.insert(res.end(), m_builtin_types.begin(), m_builtin_types.end());
res.insert(res.end(), m_user_types.begin(), m_user_types.end());
return std::move(res);
}
bool insert(uniform_type_info* uti) {
auto e = m_user_types.end();
auto i = std::lower_bound(m_user_types.begin(), e, uti, [](uniform_type_info* lhs, pointer rhs) {
return strcmp(lhs->name(), rhs->name()) < 0;
});
if (i == e) m_user_types.push_back(uti);
else {
if (strcmp(uti->name(), (*i)->name()) == 0) {
// type already known
return false;
}
// insert after lower bound (vector is always sorted)
m_user_types.insert(i, uti);
}
return true;
}
~utim_impl() {
for (auto ptr : m_user_types) delete ptr;
m_user_types.clear();
}
private:
typedef std::map<std::string,std::string> strmap;
uti_impl<process_information_ptr> m_type_proc;
uti_impl<channel_ptr> m_type_channel;
uti_impl<actor_ptr> m_type_actor;
uti_impl<group_ptr> m_type_group;
uti_impl<any_tuple> m_type_tuple;
uti_impl<util::duration> m_type_duration;
uti_impl<message_header> m_type_header;
uti_impl<util::void_type> m_type_void;
uti_impl<atom_value> m_type_atom;
uti_impl<std::string> m_type_str;
uti_impl<std::u16string> m_type_u16str;
uti_impl<std::u32string> m_type_u32str;
default_uniform_type_info_impl<strmap> m_type_strmap;
uti_impl<bool> m_type_bool;
uti_impl<float> m_type_float;
uti_impl<double> m_type_double;
uti_impl<long double> m_type_long_double;
int_tinfo<std::int8_t> m_type_i8;
int_tinfo<std::uint8_t> m_type_u8;
int_tinfo<std::int16_t> m_type_i16;
int_tinfo<std::uint16_t> m_type_u16;
int_tinfo<std::int32_t> m_type_i32;
int_tinfo<std::uint32_t> m_type_u32;
int_tinfo<std::int64_t> m_type_i64;
int_tinfo<std::uint64_t> m_type_u64;
// both containers are sorted by uniform name
std::array<pointer,25> m_builtin_types;
std::vector<uniform_type_info*> m_user_types;
template<typename Container>
pointer find_rtti(const Container& c, const std::type_info& ti) const {
auto e = c.end();
auto i = std::find_if(c.begin(), e, [&](pointer p) {
return p->equals(ti);
});
return (i == e) ? nullptr : *i;
}
template<typename Container>
pointer find_name(const Container& c, const std::string& name) const {
auto e = c.end();
// both containers are sorted
auto i = std::lower_bound(c.begin(), e, name, [](pointer p, const std::string& n) {
return p->name() < n;
});
return (i != e && (*i)->name() == name) ? *i : nullptr;
}
};
} // namespace <anonymous>
uniform_type_info_map* uniform_type_info_map::create_singleton() {
return new utim_impl;
}
uniform_type_info_map::~uniform_type_info_map() { }
} } // namespace cppa::detail
......@@ -3,6 +3,7 @@
#include <vector>
#include <string>
#include <cstring>
#include <cstddef>
#include <sstream>
#include <iostream>
......@@ -43,7 +44,9 @@ struct both_integral {
};
template<bool V, typename T1, typename T2>
struct enable_integral : std::enable_if<both_integral<T1,T2>::value == V> { };
struct enable_integral : std::enable_if< both_integral<T1,T2>::value == V
&& not std::is_pointer<T1>::value
&& not std::is_pointer<T2>::value> { };
template<typename T>
const T& cppa_stream_arg(const T& value) {
......@@ -73,6 +76,15 @@ inline void cppa_failed(const V1& v1,
cppa_inc_error_count();
}
inline void cppa_check_value(const std::string& v1,
const std::string& v2,
const char* fname,
int line,
bool expected = true) {
if ((v1 == v2) == expected) cppa_passed(fname, line);
else cppa_failed(v1, v2, fname, line);
}
template<typename V1, typename V2>
inline void cppa_check_value(const V1& v1,
const V2& v2,
......
......@@ -229,6 +229,7 @@ int main() {
if (msg1str != msg1_tostring) {
CPPA_FAILURE("msg1str != to_string(msg1)");
cerr << "to_string(msg1) = " << msg1_tostring << endl;
cerr << "to_string(msg1str) = " << msg1str << endl;
}
util::buffer wr_buf;
binary_serializer bs(&wr_buf, &addressing);
......
......@@ -222,13 +222,13 @@ void check_guards() {
CPPA_CHECK_EQUAL(f09_any_val.get_as<int>(1), 9);
f09_any_val.get_as_mutable<int>(1) = 666;
any_tuple f09_any_val_copy{f09_any_val};
CPPA_CHECK_EQUAL(f09_any_val.at(0), f09_any_val_copy.at(0));
CPPA_CHECK(f09_any_val.at(0) == f09_any_val_copy.at(0));
// detaches f09_any_val from f09_any_val_copy
CPPA_CHECK(f09.invoke(f09_any_val));
CPPA_CHECK_EQUAL(f09_any_val.get_as<int>(1), 9);
CPPA_CHECK_EQUAL(f09_any_val_copy.get_as<int>(1), 666);
// no longer the same data
CPPA_CHECK_NOT_EQUAL(f09_any_val.at(0), f09_any_val_copy.at(0));
CPPA_CHECK(f09_any_val.at(0) != f09_any_val_copy.at(0));
auto f10 = (
on<int>().when(_x1 < 10) >> [&]() { invoked = "f10.0"; },
......@@ -351,11 +351,11 @@ void check_wildcards() {
CPPA_CHECK_EQUAL(get<0>(v0), "1");
CPPA_CHECK_EQUAL(get<0>(t0), get<0>(v0));
// check cow semantics
CPPA_CHECK_EQUAL(&get<0>(t0), &get<0>(v0)); // point to the same
CPPA_CHECK(&get<0>(t0) == &get<0>(v0)); // point to the same
get_ref<0>(t0) = "hello world"; // detaches t0 from v0
CPPA_CHECK_EQUAL(get<0>(t0), "hello world"); // t0 contains new value
CPPA_CHECK_EQUAL(get<0>(v0), "1"); // v0 contains old value
CPPA_CHECK_NOT_EQUAL(&get<0>(t0), &get<0>(v0)); // no longer the same
CPPA_CHECK(&get<0>(t0) != &get<0>(v0)); // no longer the same
// check operator==
auto lhs = make_cow_tuple(1,2,3,4);
auto rhs = make_cow_tuple(static_cast<std::uint8_t>(1), 2.0, 3, 4);
......@@ -368,24 +368,24 @@ void check_wildcards() {
CPPA_CHECK(opt0);
if (opt0) {
CPPA_CHECK((*opt0 == make_cow_tuple("one", 2, 3.f, 4.0)));
CPPA_CHECK_EQUAL(&get<0>(*opt0), at1.at(0));
CPPA_CHECK_EQUAL(&get<1>(*opt0), at1.at(1));
CPPA_CHECK_EQUAL(&get<2>(*opt0), at1.at(2));
CPPA_CHECK_EQUAL(&get<3>(*opt0), at1.at(3));
CPPA_CHECK(&get<0>(*opt0) == at1.at(0));
CPPA_CHECK(&get<1>(*opt0) == at1.at(1));
CPPA_CHECK(&get<2>(*opt0) == at1.at(2));
CPPA_CHECK(&get<3>(*opt0) == at1.at(3));
}
// leading wildcard
auto opt1 = tuple_cast<anything, double>(at1);
CPPA_CHECK(opt1);
if (opt1) {
CPPA_CHECK_EQUAL(get<0>(*opt1), 4.0);
CPPA_CHECK_EQUAL(&get<0>(*opt1), at1.at(3));
CPPA_CHECK(&get<0>(*opt1) == at1.at(3));
}
// trailing wildcard
auto opt2 = tuple_cast<std::string, anything>(at1);
CPPA_CHECK(opt2);
if (opt2) {
CPPA_CHECK_EQUAL(get<0>(*opt2), "one");
CPPA_CHECK_EQUAL(&get<0>(*opt2), at1.at(0));
CPPA_CHECK(&get<0>(*opt2) == at1.at(0));
}
// wildcard in between
auto opt3 = tuple_cast<std::string, anything, double>(at1);
......@@ -394,8 +394,8 @@ void check_wildcards() {
CPPA_CHECK((*opt3 == make_cow_tuple("one", 4.0)));
CPPA_CHECK_EQUAL(get<0>(*opt3), "one");
CPPA_CHECK_EQUAL(get<1>(*opt3), 4.0);
CPPA_CHECK_EQUAL(&get<0>(*opt3), at1.at(0));
CPPA_CHECK_EQUAL(&get<1>(*opt3), at1.at(3));
CPPA_CHECK(&get<0>(*opt3) == at1.at(0));
CPPA_CHECK(&get<1>(*opt3) == at1.at(3));
}
}
}
......
......@@ -70,22 +70,22 @@ int main() {
// the uniform_type_info implementation is correct
std::set<std::string> expected = {
"bool",
"@_::foo", // <anonymous namespace>::foo
"$::foo", // <anonymous namespace>::foo
"@i8", "@i16", "@i32", "@i64", // signed integer names
"@u8", "@u16", "@u32", "@u64", // unsigned integer names
"@str", "@u16str", "@u32str", // strings
"@strmap", // string containers
"float", "double", "long double", // floating points
"float", "double", "@ldouble", // floating points
"@0", // cppa::util::void_type
// default announced cppa types
"@atom", // cppa::atom_value
"@<>", // cppa::any_tuple
"@hdr", // cppa::detail::addressed_message
"@tuple", // cppa::any_tuple
"@header", // cppa::message_header
"@actor", // cppa::actor_ptr
"@group", // cppa::group_ptr
"@channel", // cppa::channel_ptr
"@process_info", // cppa::intrusive_ptr<cppa::process_information>
"cppa::util::duration"
"@proc", // cppa::intrusive_ptr<cppa::process_information>
"@duration" // cppa::util::duration
};
// holds the type names we see at runtime
std::set<std::string> found;
......
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