Commit e19adfa8 authored by Dominik Charousset's avatar Dominik Charousset

optimization in serialization layer

this patch removes redundancies and reduces string comparisons by
using session-dependent type IDs rather than sending type names
parent 12d3bf01
...@@ -166,6 +166,7 @@ set(LIBCPPA_SRC ...@@ -166,6 +166,7 @@ set(LIBCPPA_SRC
src/thread_mapped_actor.cpp src/thread_mapped_actor.cpp
src/thread_pool_scheduler.cpp src/thread_pool_scheduler.cpp
src/to_uniform_name.cpp src/to_uniform_name.cpp
src/type_lookup_table.cpp
src/unicast_network.cpp src/unicast_network.cpp
src/uniform_type_info.cpp src/uniform_type_info.cpp
src/uniform_type_info_map.cpp src/uniform_type_info_map.cpp
......
...@@ -310,3 +310,6 @@ cppa/io/accept_handle.hpp ...@@ -310,3 +310,6 @@ cppa/io/accept_handle.hpp
unit_testing/test_broker.cpp unit_testing/test_broker.cpp
cppa/io/buffered_writing.hpp cppa/io/buffered_writing.hpp
cppa/detail/handle.hpp cppa/detail/handle.hpp
cppa/add_tuple_hint.hpp
cppa/type_lookup_table.hpp
src/type_lookup_table.cpp
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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 ADD_TUPLE_HINT_HPP
#define ADD_TUPLE_HINT_HPP
#include "cppa/config.hpp"
#include "cppa/cow_tuple.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/singletons.hpp"
#include "cppa/serializer.hpp"
#include "cppa/deserializer.hpp"
#include "cppa/util/algorithm.hpp"
#include "cppa/detail/uniform_type_info_map.hpp"
namespace cppa {
namespace detail {
template<long Pos, typename Tuple, typename T>
typename std::enable_if<util::is_primitive<T>::value>::type
serialze_single(serializer* sink, const Tuple&, const T& value) {
sink->write_value(value);
}
template<long Pos, typename Tuple, typename T>
typename std::enable_if<not util::is_primitive<T>::value>::type
serialze_single(serializer* sink, const Tuple& tup, const T& value) {
tup.type_at(Pos)->serialize(&value, sink);
}
// end of recursion
template<typename Tuple>
void do_serialize(serializer*, const Tuple&, util::int_list<>) { }
// end of recursion
template<typename Tuple, long I, long... Is>
void do_serialize(serializer* sink, const Tuple& tup, util::int_list<I, Is...>) {
serialze_single<I>(sink, tup, get<I>(tup));
do_serialize(sink, tup, util::int_list<Is...>{});
}
template<long Pos, typename Tuple, typename T>
typename std::enable_if<util::is_primitive<T>::value>::type
deserialze_single(deserializer* source, Tuple&, T& value) {
value = source->read<T>();
}
template<long Pos, typename Tuple, typename T>
typename std::enable_if<not util::is_primitive<T>::value>::type
deserialze_single(deserializer* source, Tuple& tup, T& value) {
tup.type_at(Pos)->deserialize(&value, source);
}
// end of recursion
template<typename Tuple>
void do_deserialize(deserializer*, const Tuple&, util::int_list<>) { }
// end of recursion
template<typename Tuple, long I, long... Is>
void do_deserialize(deserializer* source, Tuple& tup, util::int_list<I, Is...>) {
deserialze_single<I>(source, tup, get_ref<I>(tup));
do_deserialize(source, tup, util::int_list<Is...>{});
}
template<typename T, typename... Ts>
class meta_cow_tuple : public uniform_type_info {
public:
typedef cow_tuple<T, Ts...> tuple_type;
meta_cow_tuple() {
m_name = "@<>+";
m_name += detail::to_uniform_name<T>();
util::splice(m_name, "+", detail::to_uniform_name<Ts>()...);
}
const char* name() const override {
return m_name.c_str();
}
void serialize(const void* instance, serializer* sink) const override {
auto& ref = *cast(instance);
do_serialize(sink, ref, util::get_indices(ref));
}
void deserialize(void* instance, deserializer* source) const override {
auto& ref = *cast(instance);
do_deserialize(source, ref, util::get_indices(ref));
}
void* new_instance(const void* other = nullptr) const override {
return (other) ? new tuple_type{*cast(other)} : new tuple_type;
}
void delete_instance(void* instance) const override {
delete cast(instance);
}
any_tuple as_any_tuple(void* instance) const override {
return (instance) ? any_tuple{*cast(instance)} : any_tuple{};
}
bool equals(const std::type_info& tinfo) const {
return typeid(tuple_type) == tinfo;
}
bool equals(const void* instance1, const void* instance2) const {
return *cast(instance1) == *cast(instance2);
}
private:
inline tuple_type* cast(void* ptr) const {
return reinterpret_cast<tuple_type*>(ptr);
}
inline const tuple_type* cast(const void* ptr) const {
return reinterpret_cast<const tuple_type*>(ptr);
}
std::string m_name;
};
} // namespace detail
/**
* @addtogroup TypeSystem
* @{
*/
/**
* @brief Adds a hint to the type system of libcppa. This type hint can
* significantly increase the network performance, because libcppa
* can use the hint to create tuples with full static type information
* rather than using fully dynamically typed tuples.
*/
template<typename T, typename... Ts>
inline void add_tuple_hint() {
typedef detail::meta_cow_tuple<T, Ts...> meta_type;
get_uniform_type_info_map()->insert(create_unique<meta_type>());
}
/**
* @}
*/
} // namespace cppa
#endif // ADD_TUPLE_HINT_HPP
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#ifndef CPPA_ANNOUNCE_HPP #ifndef CPPA_ANNOUNCE_HPP
#define CPPA_ANNOUNCE_HPP #define CPPA_ANNOUNCE_HPP
#include <memory>
#include <typeinfo> #include <typeinfo>
#include "cppa/uniform_type_info.hpp" #include "cppa/uniform_type_info.hpp"
...@@ -98,7 +99,8 @@ namespace cppa { ...@@ -98,7 +99,8 @@ namespace cppa {
* instance (mapped to @p plain_type); otherwise @c false * instance (mapped to @p plain_type); otherwise @c false
* is returned and @p uniform_type was deleted. * is returned and @p uniform_type was deleted.
*/ */
bool announce(const std::type_info& tinfo, uniform_type_info* utype); const uniform_type_info* announce(const std::type_info& tinfo,
std::unique_ptr<uniform_type_info> utype);
// deals with member pointer // deals with member pointer
/** /**
...@@ -154,13 +156,12 @@ compound_member(const std::pair<GRes (Parent::*)() const, ...@@ -154,13 +156,12 @@ compound_member(const std::pair<GRes (Parent::*)() const,
/** /**
* @brief Adds a new type mapping for @p T to the libcppa type system. * @brief Adds a new type mapping for @p T to the libcppa type system.
* @param args Members of @p T. * @param args Members of @p T.
* @returns @c true if @p T was added to the libcppa type system, * @warning @p announce is <b>not</b> thead safe!
* @c false otherwise.
*/ */
template<typename T, typename... Ts> template<typename T, typename... Ts>
inline bool announce(const Ts&... args) { inline const uniform_type_info* announce(const Ts&... args) {
auto ptr = new detail::default_uniform_type_info_impl<T>(args...); auto ptr = new detail::default_uniform_type_info_impl<T>(args...);
return announce(typeid(T), ptr); return announce(typeid(T), std::unique_ptr<uniform_type_info>{ptr});
} }
/** /**
......
...@@ -206,7 +206,7 @@ class any_tuple { ...@@ -206,7 +206,7 @@ class any_tuple {
/** /**
* @brief Checks whether this tuple is dynamically typed, i.e., * @brief Checks whether this tuple is dynamically typed, i.e.,
* its types were not known during compile time. * its types were not known at compile time.
*/ */
inline bool dynamically_typed() const; inline bool dynamically_typed() const;
...@@ -221,6 +221,8 @@ class any_tuple { ...@@ -221,6 +221,8 @@ class any_tuple {
explicit any_tuple(raw_ptr); explicit any_tuple(raw_ptr);
inline const std::string* tuple_type_names() const;
/** @endcond */ /** @endcond */
private: private:
...@@ -330,6 +332,11 @@ inline void any_tuple::force_detach() { ...@@ -330,6 +332,11 @@ inline void any_tuple::force_detach() {
m_vals.detach(); m_vals.detach();
} }
inline const std::string* any_tuple::tuple_type_names() const {
return m_vals->tuple_type_names();
}
inline size_t any_tuple::size() const { inline size_t any_tuple::size() const {
return m_vals->size(); return m_vals->size();
} }
......
...@@ -46,22 +46,20 @@ class binary_deserializer : public deserializer { ...@@ -46,22 +46,20 @@ class binary_deserializer : public deserializer {
public: public:
binary_deserializer(const void* buf, size_t buf_size, binary_deserializer(const void* buf, size_t buf_size,
actor_addressing* addressing = nullptr); actor_addressing* addressing = nullptr,
type_lookup_table* table = nullptr);
binary_deserializer(const void* begin, const void* m_end, binary_deserializer(const void* begin, const void* m_end,
actor_addressing* addressing = nullptr); actor_addressing* addressing = nullptr,
type_lookup_table* table = nullptr);
std::string seek_object(); const uniform_type_info* begin_object() override;
std::string peek_object(); void end_object() override;
void begin_object(const std::string& type_name); size_t begin_sequence() override;
void end_object(); void end_sequence() override;
size_t begin_sequence(); primitive_variant read_value(primitive_type ptype) override;
void end_sequence(); void read_tuple(size_t, const primitive_type*, primitive_variant*) override;
primitive_variant read_value(primitive_type ptype); void read_raw(size_t num_bytes, void* storage) override;
void read_tuple(size_t size,
const primitive_type* ptypes,
primitive_variant* storage);
void read_raw(size_t num_bytes, void* storage);
private: private:
......
...@@ -54,21 +54,23 @@ class binary_serializer : public serializer { ...@@ -54,21 +54,23 @@ class binary_serializer : public serializer {
* @brief Creates a binary serializer writing to @p write_buffer. * @brief Creates a binary serializer writing to @p write_buffer.
* @warning @p write_buffer must be guaranteed to outlive @p this * @warning @p write_buffer must be guaranteed to outlive @p this
*/ */
binary_serializer(util::buffer* write_buffer, actor_addressing* ptr = 0); binary_serializer(util::buffer* write_buffer,
actor_addressing* addressing = nullptr,
type_lookup_table* lookup_table = nullptr);
void begin_object(const std::string& tname); void begin_object(const uniform_type_info*) override;
void end_object(); void end_object() override;
void begin_sequence(size_t list_size); void begin_sequence(size_t list_size) override;
void end_sequence(); void end_sequence() override;
void write_value(const primitive_variant& value); void write_value(const primitive_variant& value) override;
void write_tuple(size_t size, const primitive_variant* values); void write_tuple(size_t size, const primitive_variant* values) override;
void write_raw(size_t num_bytes, const void* data); void write_raw(size_t num_bytes, const void* data) override;
private: private:
......
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
# error Plattform and/or compiler not supportet # error Plattform and/or compiler not supportet
#endif #endif
#include <memory>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
...@@ -88,6 +89,15 @@ ...@@ -88,6 +89,15 @@
namespace cppa { namespace cppa {
/**
* @brief An alternative for the 'missing' @p std::make_unqiue.
*/
template<typename T, typename... Args>
std::unique_ptr<T> create_unique(Args&&... args) {
return std::unique_ptr<T>{new T(std::forward<Args>(args)...)};
}
#ifdef CPPA_WINDOWS #ifdef CPPA_WINDOWS
typedef SOCKET native_socket_type; typedef SOCKET native_socket_type;
typedef const char* socket_send_ptr; typedef const char* socket_send_ptr;
......
...@@ -62,6 +62,7 @@ ...@@ -62,6 +62,7 @@
#include "cppa/prioritizing.hpp" #include "cppa/prioritizing.hpp"
#include "cppa/spawn_options.hpp" #include "cppa/spawn_options.hpp"
#include "cppa/message_future.hpp" #include "cppa/message_future.hpp"
#include "cppa/add_tuple_hint.hpp"
#include "cppa/response_handle.hpp" #include "cppa/response_handle.hpp"
#include "cppa/scheduled_actor.hpp" #include "cppa/scheduled_actor.hpp"
#include "cppa/event_based_actor.hpp" #include "cppa/event_based_actor.hpp"
......
...@@ -41,6 +41,7 @@ namespace cppa { ...@@ -41,6 +41,7 @@ namespace cppa {
class object; class object;
class actor_addressing; class actor_addressing;
class type_lookup_table;
namespace util { class buffer; } namespace util { class buffer; }
...@@ -55,7 +56,8 @@ class deserializer { ...@@ -55,7 +56,8 @@ class deserializer {
public: public:
deserializer(actor_addressing* addressing = nullptr); deserializer(actor_addressing* addressing = nullptr,
type_lookup_table* incoming_types = nullptr);
virtual ~deserializer(); virtual ~deserializer();
...@@ -63,19 +65,13 @@ class deserializer { ...@@ -63,19 +65,13 @@ class deserializer {
* @brief Seeks the beginning of the next object and return * @brief Seeks the beginning of the next object and return
* its uniform type name. * its uniform type name.
*/ */
virtual std::string seek_object() = 0; //virtual std::string seek_object() = 0;
/**
* @brief Equal to {@link seek_object()} but doesn't
* modify the internal in-stream position.
*/
virtual std::string peek_object() = 0;
/** /**
* @brief Begins deserialization of an object of type @p type_name. * @brief Begins deserialization of an object of type @p type_name.
* @param type_name The platform-independent @p libcppa type name. * @param type_name The platform-independent @p libcppa type name.
*/ */
virtual void begin_object(const std::string& type_name) = 0; virtual const uniform_type_info* begin_object() = 0;
/** /**
* @brief Ends deserialization of an object. * @brief Ends deserialization of an object.
...@@ -127,26 +123,23 @@ class deserializer { ...@@ -127,26 +123,23 @@ class deserializer {
*/ */
virtual void read_raw(size_t num_bytes, void* storage) = 0; virtual void read_raw(size_t num_bytes, void* storage) = 0;
inline actor_addressing* addressing() { return m_addressing; } inline actor_addressing* addressing() {
return m_addressing;
}
void read_raw(size_t num_bytes, util::buffer& storage); inline type_lookup_table* incoming_types() {
return m_incoming_types;
}
void read_raw(size_t num_bytes, util::buffer& storage);
private: private:
actor_addressing* m_addressing; actor_addressing* m_addressing;
type_lookup_table* m_incoming_types;
}; };
/**
* @brief Deserializes a value and stores the result in @p storage.
* @param d A valid deserializer.
* @param storage An that should contain the deserialized value.
* @returns @p d
* @relates deserializer
*/
deserializer& operator>>(deserializer& d, object& storage);
} // namespace cppa } // namespace cppa
#endif // CPPA_DESERIALIZER_HPP #endif // CPPA_DESERIALIZER_HPP
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#ifndef CPPA_ABSTRACT_TUPLE_HPP #ifndef CPPA_ABSTRACT_TUPLE_HPP
#define CPPA_ABSTRACT_TUPLE_HPP #define CPPA_ABSTRACT_TUPLE_HPP
#include <string>
#include <iterator> #include <iterator>
#include <typeinfo> #include <typeinfo>
...@@ -60,6 +61,7 @@ class abstract_tuple : public ref_counted { ...@@ -60,6 +61,7 @@ class abstract_tuple : public ref_counted {
virtual abstract_tuple* copy() const = 0; virtual abstract_tuple* 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 uniform_type_info* type_at(size_t pos) const = 0;
virtual const std::string* tuple_type_names() 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
...@@ -121,6 +123,8 @@ constexpr full_eq_type full_eq; ...@@ -121,6 +123,8 @@ constexpr full_eq_type full_eq;
constexpr types_only_eq_type types_only_eq; constexpr types_only_eq_type types_only_eq;
} // namespace <anonymous> } // namespace <anonymous>
std::string get_tuple_type_names(const detail::abstract_tuple&);
} } // namespace cppa::detail } } // namespace cppa::detail
#endif // CPPA_ABSTRACT_TUPLE_HPP #endif // CPPA_ABSTRACT_TUPLE_HPP
...@@ -81,6 +81,11 @@ class container_tuple_view : public abstract_tuple { ...@@ -81,6 +81,11 @@ class container_tuple_view : public abstract_tuple {
return static_types_array<value_type>::arr[0]; return static_types_array<value_type>::arr[0];
} }
const std::string* tuple_type_names() const {
static std::string result = demangle<value_type>();
return &result;
}
private: private:
std::unique_ptr<Container, disablable_delete> m_ptr; std::unique_ptr<Container, disablable_delete> m_ptr;
......
...@@ -81,15 +81,17 @@ class decorated_tuple : public abstract_tuple { ...@@ -81,15 +81,17 @@ class decorated_tuple : public abstract_tuple {
return pointer{new decorated_tuple(std::move(d), ti, offset)}; return pointer{new decorated_tuple(std::move(d), ti, offset)};
} }
virtual void* mutable_at(size_t pos) override; void* mutable_at(size_t pos) override;
virtual size_t size() const override; size_t size() const override;
virtual decorated_tuple* copy() const override; decorated_tuple* copy() const override;
virtual const void* at(size_t pos) const override; const void* at(size_t pos) const override;
virtual const uniform_type_info* type_at(size_t pos) const override; const uniform_type_info* type_at(size_t pos) const override;
const std::string* tuple_type_names() const override;
rtti type_token() const override; rtti type_token() const override;
......
...@@ -458,20 +458,11 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T ...@@ -458,20 +458,11 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T
} }
void serialize(const void* obj, serializer* s) const { void serialize(const void* obj, serializer* s) const {
s->begin_object(this->name()); for (auto& m : m_members) m->serialize(obj, s);
for (auto& m : m_members) {
m->serialize(obj, s);
}
s->end_object();
} }
void deserialize(void* obj, deserializer* d) const { void deserialize(void* obj, deserializer* d) const {
this->assert_type_name(d); for (auto& m : m_members) m->deserialize(obj, d);
d->begin_object(this->name());
for (auto& m : m_members) {
m->deserialize(obj, d);
}
d->end_object();
} }
}; };
......
...@@ -43,6 +43,10 @@ class disablable_delete { ...@@ -43,6 +43,10 @@ class disablable_delete {
m_enabled = false; m_enabled = false;
} }
inline void enable() {
m_enabled = true;
}
template<typename T> template<typename T>
inline void operator()(T* ptr) { inline void operator()(T* ptr) {
if (m_enabled) delete ptr; if (m_enabled) delete ptr;
......
...@@ -54,6 +54,7 @@ class empty_tuple : public singleton_mixin<empty_tuple, abstract_tuple> { ...@@ -54,6 +54,7 @@ class empty_tuple : public singleton_mixin<empty_tuple, abstract_tuple> {
bool equals(const abstract_tuple& other) const; bool equals(const abstract_tuple& other) const;
const uniform_type_info* type_at(size_t) const; const uniform_type_info* type_at(size_t) const;
const std::type_info* type_token() const; const std::type_info* type_token() const;
const std::string* tuple_type_names() const;
private: private:
......
...@@ -66,6 +66,8 @@ class object_array : public abstract_tuple { ...@@ -66,6 +66,8 @@ class object_array : public abstract_tuple {
const uniform_type_info* type_at(size_t pos) const; const uniform_type_info* type_at(size_t pos) const;
const std::string* tuple_type_names() const;
private: private:
std::vector<object> m_elements; std::vector<object> m_elements;
......
...@@ -113,6 +113,12 @@ class tuple_vals : public abstract_tuple { ...@@ -113,6 +113,12 @@ class tuple_vals : public abstract_tuple {
return detail::static_type_list<Ts...>::list; return detail::static_type_list<Ts...>::list;
} }
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;
}
private: private:
data_type m_data; data_type m_data;
......
...@@ -116,14 +116,13 @@ class uniform_type_info_map { ...@@ -116,14 +116,13 @@ class uniform_type_info_map {
virtual ~uniform_type_info_map(); virtual ~uniform_type_info_map();
virtual pointer by_uniform_name(const std::string& name) const = 0; virtual pointer by_uniform_name(const std::string& name) = 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;
// NOT thread safe! virtual pointer insert(std::unique_ptr<uniform_type_info> uti) = 0;
virtual bool insert(uniform_type_info* uti) = 0;
static uniform_type_info_map* create_singleton(); static uniform_type_info_map* create_singleton();
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "cppa/extend.hpp" #include "cppa/extend.hpp"
#include "cppa/actor_proxy.hpp" #include "cppa/actor_proxy.hpp"
#include "cppa/partial_function.hpp" #include "cppa/partial_function.hpp"
#include "cppa/type_lookup_table.hpp"
#include "cppa/weak_intrusive_ptr.hpp" #include "cppa/weak_intrusive_ptr.hpp"
#include "cppa/process_information.hpp" #include "cppa/process_information.hpp"
...@@ -120,6 +121,9 @@ class default_peer : public extend<continuable>::with<buffered_writing> { ...@@ -120,6 +121,9 @@ class default_peer : public extend<continuable>::with<buffered_writing> {
partial_function m_content_handler; partial_function m_content_handler;
type_lookup_table m_incoming_types;
type_lookup_table m_outgoing_types;
void monitor(const actor_ptr& sender, const process_information_ptr& node, actor_id aid); void monitor(const actor_ptr& sender, const process_information_ptr& node, actor_id aid);
void kill_proxy(const actor_ptr& sender, const process_information_ptr& node, actor_id aid, std::uint32_t reason); void kill_proxy(const actor_ptr& sender, const process_information_ptr& node, actor_id aid, std::uint32_t reason);
...@@ -136,6 +140,8 @@ class default_peer : public extend<continuable>::with<buffered_writing> { ...@@ -136,6 +140,8 @@ class default_peer : public extend<continuable>::with<buffered_writing> {
void enqueue_impl(const message_header& hdr, const any_tuple& msg); void enqueue_impl(const message_header& hdr, const any_tuple& msg);
void add_type_if_needed(const std::string& tname);
}; };
} } // namespace cppa::network } } // namespace cppa::network
......
...@@ -41,6 +41,8 @@ ...@@ -41,6 +41,8 @@
namespace cppa { namespace cppa {
class serializer;
/** /**
* @brief Identifies a process. * @brief Identifies a process.
*/ */
...@@ -99,9 +101,15 @@ class process_information : public ref_counted ...@@ -99,9 +101,15 @@ class process_information : public ref_counted
*/ */
static const intrusive_ptr<process_information>& get(); static const intrusive_ptr<process_information>& get();
/** @cond PRIVATE */
// "inherited" from comparable<process_information> // "inherited" from comparable<process_information>
int compare(const process_information& other) const; int compare(const process_information& other) const;
static void serialize_invalid(serializer*);
/** @endcond */
private: private:
std::uint32_t m_process_id; std::uint32_t m_process_id;
......
...@@ -41,6 +41,7 @@ namespace cppa { ...@@ -41,6 +41,7 @@ namespace cppa {
class actor_addressing; class actor_addressing;
class primitive_variant; class primitive_variant;
class type_lookup_table;
/** /**
* @ingroup TypeSystem * @ingroup TypeSystem
...@@ -53,7 +54,11 @@ class serializer { ...@@ -53,7 +54,11 @@ class serializer {
public: public:
serializer(actor_addressing* addressing = nullptr); /**
* @note @p addressing must be guaranteed to outlive the serializer
*/
serializer(actor_addressing* addressing = nullptr,
type_lookup_table* outgoing_types = nullptr);
virtual ~serializer(); virtual ~serializer();
...@@ -62,7 +67,7 @@ class serializer { ...@@ -62,7 +67,7 @@ class serializer {
* named @p type_name. * named @p type_name.
* @param type_name The platform-independent @p libcppa type name. * @param type_name The platform-independent @p libcppa type name.
*/ */
virtual void begin_object(const std::string& type_name) = 0; virtual void begin_object(const uniform_type_info*) = 0;
/** /**
* @brief Ends serialization of an object. * @brief Ends serialization of an object.
...@@ -99,11 +104,18 @@ class serializer { ...@@ -99,11 +104,18 @@ class serializer {
*/ */
virtual void write_tuple(size_t num, const primitive_variant* values) = 0; virtual void write_tuple(size_t num, const primitive_variant* values) = 0;
inline actor_addressing* addressing() { return m_addressing; } inline actor_addressing* addressing() {
return m_addressing;
}
inline type_lookup_table* outgoing_types() {
return m_outgoing_types;
}
private: private:
actor_addressing* m_addressing; actor_addressing* m_addressing;
type_lookup_table* m_outgoing_types;
}; };
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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_TYPE_LOOKUP_TABLE_HPP
#define CPPA_TYPE_LOOKUP_TABLE_HPP
#include <vector>
#include <memory>
#include <utility>
#include "cppa/uniform_type_info.hpp"
namespace cppa {
/**
*
* Default types are:
*
* 1: {atom_value}
* 2: {atom_value, uint32_t}
* 3: {atom_value, process_information}
* 4: {atom_value, process_information, uint32_t}
* 5: {atom_value, process_information, uint32_t, uint32_t}
* 6: {atom_value, actor_ptr}
* 7: {atom_value, uint32_t, string}
*
*/
class type_lookup_table {
public:
typedef const uniform_type_info* pointer;
type_lookup_table();
pointer by_id(std::uint32_t id) const;
pointer by_name(const std::string& name) const;
std::uint32_t id_of(const std::string& name) const;
std::uint32_t id_of(pointer uti) const;
void emplace(std::uint32_t id, pointer instance);
std::uint32_t max_id() const;
private:
typedef std::vector<std::pair<std::uint32_t, pointer>> container;
typedef container::value_type value_type;
typedef container::iterator iterator;
typedef container::const_iterator const_iterator;
container m_data;
const_iterator find(std::uint32_t) const;
iterator find(std::uint32_t);
};
} // namespace cppa
#endif // CPPA_TYPE_LOOKUP_TABLE_HPP
...@@ -234,10 +234,6 @@ class uniform_type_info { ...@@ -234,10 +234,6 @@ class uniform_type_info {
*/ */
virtual void deserialize(void* instance, deserializer* source) const = 0; virtual void deserialize(void* instance, deserializer* source) const = 0;
protected:
uniform_type_info() = default;
/** /**
* @brief Casts @p instance to the native type and deletes it. * @brief Casts @p instance to the native type and deletes it.
* @param instance Instance of this type. * @param instance Instance of this type.
...@@ -256,6 +252,15 @@ class uniform_type_info { ...@@ -256,6 +252,15 @@ class uniform_type_info {
*/ */
virtual void* new_instance(const void* instance = nullptr) const = 0; virtual void* new_instance(const void* instance = nullptr) const = 0;
/**
* @brief Returns @p instance encapsulated as an @p any_tuple.
*/
virtual any_tuple as_any_tuple(void* instance) const = 0;
protected:
uniform_type_info() = default;
}; };
/** /**
......
...@@ -56,6 +56,10 @@ class abstract_uniform_type_info : public uniform_type_info { ...@@ -56,6 +56,10 @@ class abstract_uniform_type_info : public uniform_type_info {
return m_name.c_str(); return m_name.c_str();
} }
any_tuple as_any_tuple(void* instance) const override {
return make_any_tuple(deref(instance));
}
protected: protected:
abstract_uniform_type_info() { abstract_uniform_type_info() {
...@@ -77,18 +81,6 @@ class abstract_uniform_type_info : public uniform_type_info { ...@@ -77,18 +81,6 @@ class abstract_uniform_type_info : public uniform_type_info {
delete reinterpret_cast<T*>(instance); delete reinterpret_cast<T*>(instance);
} }
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));
}
}
private: private:
static inline const T& deref(const void* ptr) { static inline const T& deref(const void* ptr) {
......
...@@ -61,6 +61,16 @@ join(const Container& c, const std::string& glue = "") { ...@@ -61,6 +61,16 @@ join(const Container& c, const std::string& glue = "") {
return join(c.begin(), c.end(), glue); return join(c.begin(), c.end(), glue);
} }
// end of recursion
inline void splice(std::string&, const std::string&) { }
template<typename T, typename... Ts>
void splice(std::string& str, const std::string& glue, T&& arg, Ts&&... args) {
str += glue;
str += std::forward<T>(arg);
splice(str, glue, std::forward<Ts>(args)...);
}
} } // namespace cppa::util } } // namespace cppa::util
#endif // CPPA_UTIL_SPLIT_HPP #endif // CPPA_UTIL_SPLIT_HPP
...@@ -77,11 +77,11 @@ int main(int, char**) { ...@@ -77,11 +77,11 @@ int main(int, char**) {
// announces foo to the libcppa type system; // announces foo to the libcppa type system;
// the function expects member pointers to all elements of foo // the function expects member pointers to all elements of foo
assert(announce<foo>(&foo::a, &foo::b) == true); announce<foo>(&foo::a, &foo::b);
// announce foo2 to the libcppa type system, // announce foo2 to the libcppa type system,
// note that recursive containers are managed automatically by libcppa // note that recursive containers are managed automatically by libcppa
assert(announce<foo2>(&foo2::a, &foo2::b) == true); announce<foo2>(&foo2::a, &foo2::b);
foo2 vd; foo2 vd;
vd.a = 5; vd.a = 5;
...@@ -100,12 +100,12 @@ int main(int, char**) { ...@@ -100,12 +100,12 @@ int main(int, char**) {
// announce std::pair<int, int> to the type system; // announce std::pair<int, int> to the type system;
// NOTE: foo_pair is NOT distinguishable from foo_pair2! // NOTE: foo_pair is NOT distinguishable from foo_pair2!
assert(announce<foo_pair>(&foo_pair::first, &foo_pair::second) == true); auto uti = announce<foo_pair>(&foo_pair::first, &foo_pair::second);
// since foo_pair and foo_pair2 are not distinguishable since typedefs // since foo_pair and foo_pair2 are not distinguishable since typedefs
// do not 'create' an own type, this announce fails, since // do not 'create' an own type, this announce fails, since
// std::pair<int, int> is already announced // std::pair<int, int> is already announced
assert(announce<foo_pair2>(&foo_pair2::first, &foo_pair2::second) == false); assert(announce<foo_pair2>(&foo_pair2::first, &foo_pair2::second) == uti);
// libcppa returns the same uniform_type_info // libcppa returns the same uniform_type_info
// instance for foo_pair and foo_pair2 // instance for foo_pair and foo_pair2
......
...@@ -90,26 +90,16 @@ class tree_type_info : public util::abstract_uniform_type_info<tree> { ...@@ -90,26 +90,16 @@ class tree_type_info : public util::abstract_uniform_type_info<tree> {
void serialize(const void* ptr, serializer* sink) const { void serialize(const void* ptr, serializer* sink) const {
// ptr is guaranteed to be a pointer of type tree // ptr is guaranteed to be a pointer of type tree
auto tree_ptr = reinterpret_cast<const tree*>(ptr); auto tree_ptr = reinterpret_cast<const tree*>(ptr);
// serialization always begins with begin_object(name())
// and ends with end_object();
// name() returns the uniform type name of tree
sink->begin_object(name());
// recursively serialize nodes, beginning with root // recursively serialize nodes, beginning with root
serialize_node(tree_ptr->root, sink); serialize_node(tree_ptr->root, sink);
sink->end_object();
} }
void deserialize(void* ptr, deserializer* source) const { void deserialize(void* ptr, deserializer* source) const {
// throws an exception if the next object in source is not a tree
assert_type_name(source);
// ptr is guaranteed to be a pointer of type tree // ptr is guaranteed to be a pointer of type tree
auto tree_ptr = reinterpret_cast<tree*>(ptr); auto tree_ptr = reinterpret_cast<tree*>(ptr);
tree_ptr->root.children.clear(); tree_ptr->root.children.clear();
// workflow is analogous to serialize: begin_object() ... end_object()
source->begin_object(name());
// recursively deserialize nodes, beginning with root // recursively deserialize nodes, beginning with root
deserialize_node(tree_ptr->root, source); deserialize_node(tree_ptr->root, source);
source->end_object();
} }
private: private:
...@@ -176,7 +166,7 @@ void testee(size_t remaining) { ...@@ -176,7 +166,7 @@ void testee(size_t remaining) {
int main() { int main() {
// the tree_type_info is owned by libcppa after this function call // the tree_type_info is owned by libcppa after this function call
announce(typeid(tree), new tree_type_info); announce(typeid(tree), std::unique_ptr<uniform_type_info>{new tree_type_info});
tree t0; // create a tree and fill it with some data tree t0; // create a tree and fill it with some data
......
...@@ -55,4 +55,14 @@ void* abstract_tuple::mutable_native_data() { ...@@ -55,4 +55,14 @@ void* abstract_tuple::mutable_native_data() {
return nullptr; return nullptr;
} }
std::string get_tuple_type_names(const detail::abstract_tuple& tup) {
std::string result = "@<>";
for (size_t i = 0; i < tup.size(); ++i) {
auto uti = tup.type_at(i);
result += "+";
result += uti->name();
}
return result;
}
} } // namespace cppa::detail } } // namespace cppa::detail
...@@ -40,8 +40,11 @@ ...@@ -40,8 +40,11 @@
#include "cppa/self.hpp" #include "cppa/self.hpp"
#include "cppa/logging.hpp" #include "cppa/logging.hpp"
#include "cppa/type_lookup_table.hpp"
#include "cppa/binary_deserializer.hpp" #include "cppa/binary_deserializer.hpp"
#include "cppa/detail/uniform_type_info_map.hpp"
using namespace std; using namespace std;
namespace cppa { namespace cppa {
...@@ -138,27 +141,46 @@ struct pt_reader { ...@@ -138,27 +141,46 @@ struct pt_reader {
} // namespace <anonmyous> } // namespace <anonmyous>
binary_deserializer::binary_deserializer(const void* buf, size_t buf_size, binary_deserializer::binary_deserializer(const void* buf, size_t buf_size,
actor_addressing* addressing) actor_addressing* addressing,
: super(addressing), m_pos(buf), m_end(advanced(buf, buf_size)) { } type_lookup_table* tbl)
: super(addressing, tbl), m_pos(buf), m_end(advanced(buf, buf_size)) { }
binary_deserializer::binary_deserializer(const void* bbegin, const void* bend, binary_deserializer::binary_deserializer(const void* bbegin, const void* bend,
actor_addressing* addressing) actor_addressing* addressing,
: super(addressing), m_pos(bbegin), m_end(bend) { } type_lookup_table* tbl)
: super(addressing, tbl), m_pos(bbegin), m_end(bend) { }
string binary_deserializer::seek_object() {
string result; const uniform_type_info* binary_deserializer::begin_object() {
m_pos = read_range(m_pos, m_end, result); std::uint8_t flag;
return result; m_pos = read_range(m_pos, m_end, flag);
} if (flag == 1) {
string tname;
string binary_deserializer::peek_object() { m_pos = read_range(m_pos, m_end, tname);
string result; auto uti = get_uniform_type_info_map()->by_uniform_name(tname);
read_range(m_pos, m_end, result); if (!uti) {
return result; std::string err = "received type name \"";
err += tname;
err += "\" but no such type is known";
throw std::runtime_error(err);
}
return uti;
}
else {
std::uint32_t type_id;
m_pos = read_range(m_pos, m_end, type_id);
auto it = incoming_types();
if (!it) {
std::string err = "received type ID ";
err += std::to_string(type_id);
err += " but incoming_types() == nullptr";
throw std::runtime_error(err);
}
auto uti = it->by_id(type_id);
if (!uti) throw std::runtime_error("received unknown type id");
return uti;
}
} }
void binary_deserializer::begin_object(const string&) { }
void binary_deserializer::end_object() { } void binary_deserializer::end_object() { }
size_t binary_deserializer::begin_sequence() { size_t binary_deserializer::begin_sequence() {
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "cppa/primitive_variant.hpp" #include "cppa/primitive_variant.hpp"
#include "cppa/binary_serializer.hpp" #include "cppa/binary_serializer.hpp"
#include "cppa/type_lookup_table.hpp"
using std::enable_if; using std::enable_if;
...@@ -110,11 +111,19 @@ class binary_writer { ...@@ -110,11 +111,19 @@ class binary_writer {
} // namespace <anonymous> } // namespace <anonymous>
binary_serializer::binary_serializer(util::buffer* buf, actor_addressing* ptr) binary_serializer::binary_serializer(util::buffer* buf,
: super(ptr), m_sink(buf) { } actor_addressing* aa,
type_lookup_table* tbl)
void binary_serializer::begin_object(const std::string& tname) { : super(aa, tbl), m_sink(buf) { }
binary_writer::write_string(m_sink, tname);
void binary_serializer::begin_object(const uniform_type_info* uti) {
CPPA_REQUIRE(uti != nullptr);
auto ot = outgoing_types();
std::uint32_t id = (ot) ? ot->id_of(uti) : 0;
std::uint8_t flag = (id == 0) ? 1 : 0;
binary_writer::write_int(m_sink, flag);
if (flag == 1) binary_writer::write_string(m_sink, uti->name());
else binary_writer::write_int(m_sink, id);
} }
void binary_serializer::end_object() { } void binary_serializer::end_object() { }
......
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
#include <iostream> #include <iostream>
#include "cppa/config.hpp"
#include "cppa/cppa.hpp" #include "cppa/cppa.hpp"
#include "cppa/singletons.hpp" #include "cppa/singletons.hpp"
...@@ -53,11 +55,6 @@ namespace { ...@@ -53,11 +55,6 @@ namespace {
constexpr size_t default_max_buffer_size = 65535; constexpr size_t default_max_buffer_size = 65535;
template<typename T, typename... Ts>
std::unique_ptr<T> make_unique(Ts&&... args) {
return std::unique_ptr<T>(new T{std::forward<Ts>(args)...});
}
} // namespace <anonymous> } // namespace <anonymous>
class default_broker : public broker { class default_broker : public broker {
...@@ -442,14 +439,14 @@ void broker::erase_acceptor(int id) { ...@@ -442,14 +439,14 @@ void broker::erase_acceptor(int id) {
connection_handle broker::add_scribe(input_stream_ptr in, output_stream_ptr out) { connection_handle broker::add_scribe(input_stream_ptr in, output_stream_ptr out) {
using namespace std; using namespace std;
auto id = connection_handle::from_int(in->read_handle()); auto id = connection_handle::from_int(in->read_handle());
m_io.insert(make_pair(id, make_unique<scribe>(this, move(in), move(out)))); m_io.insert(make_pair(id, create_unique<scribe>(this, move(in), move(out))));
return id; return id;
} }
accept_handle broker::add_doorman(acceptor_uptr ptr) { accept_handle broker::add_doorman(acceptor_uptr ptr) {
using namespace std; using namespace std;
auto id = accept_handle::from_int(ptr->file_handle()); auto id = accept_handle::from_int(ptr->file_handle());
m_accept.insert(make_pair(id, make_unique<doorman>(this, move(ptr)))); m_accept.insert(make_pair(id, create_unique<doorman>(this, move(ptr))));
return id; return id;
} }
......
...@@ -95,4 +95,10 @@ decorated_tuple::decorated_tuple(pointer d, rtti ti, size_t offset) ...@@ -95,4 +95,10 @@ decorated_tuple::decorated_tuple(pointer d, rtti ti, size_t offset)
init(offset); init(offset);
} }
const std::string* decorated_tuple::tuple_type_names() const {
// produced name is equal for all instances
static std::string result = get_tuple_type_names(*this);
return &result;
}
} } // namespace cppa::detail } } // namespace cppa::detail
...@@ -56,9 +56,9 @@ atom_value default_actor_addressing::technology_id() const { ...@@ -56,9 +56,9 @@ atom_value default_actor_addressing::technology_id() const {
void default_actor_addressing::write(serializer* sink, const actor_ptr& ptr) { void default_actor_addressing::write(serializer* sink, const actor_ptr& ptr) {
CPPA_REQUIRE(sink != nullptr); CPPA_REQUIRE(sink != nullptr);
if (ptr == nullptr) { if (ptr == nullptr) {
CPPA_LOGMF(CPPA_DEBUG, self, "serialized nullptr"); CPPA_LOG_DEBUG("serialize nullptr");
sink->begin_object("@0"); sink->write_value(static_cast<actor_id>(0));
sink->end_object(); process_information::serialize_invalid(sink);
} }
else { else {
// local actor? // local actor?
...@@ -69,45 +69,33 @@ void default_actor_addressing::write(serializer* sink, const actor_ptr& ptr) { ...@@ -69,45 +69,33 @@ void default_actor_addressing::write(serializer* sink, const actor_ptr& ptr) {
if (ptr->is_proxy()) { if (ptr->is_proxy()) {
auto dptr = ptr.downcast<default_actor_proxy>(); auto dptr = ptr.downcast<default_actor_proxy>();
if (dptr) pinf = dptr->process_info(); if (dptr) pinf = dptr->process_info();
else CPPA_LOGMF(CPPA_ERROR, self, "downcast failed"); else CPPA_LOG_ERROR("downcast failed");
} }
sink->begin_object("@actor");
sink->write_value(ptr->id()); sink->write_value(ptr->id());
sink->write_value(pinf->process_id()); sink->write_value(pinf->process_id());
sink->write_raw(process_information::node_id_size, sink->write_raw(process_information::node_id_size,
pinf->node_id().data()); pinf->node_id().data());
sink->end_object();
} }
} }
actor_ptr default_actor_addressing::read(deserializer* source) { actor_ptr default_actor_addressing::read(deserializer* source) {
CPPA_REQUIRE(source != nullptr); CPPA_REQUIRE(source != nullptr);
auto cname = source->seek_object(); process_information::node_id_type nid;
if (cname == "@0") { auto aid = source->read<uint32_t>();
CPPA_LOGMF(CPPA_DEBUG, self, "deserialized nullptr"); auto pid = source->read<uint32_t>();
source->begin_object("@0"); source->read_raw(process_information::node_id_size, nid.data());
source->end_object(); // local actor?
auto pinf = process_information::get();
if (aid == 0 && pid == 0) {
return nullptr; return nullptr;
} }
else if (cname == "@actor") { else if (pid == pinf->process_id() && nid == pinf->node_id()) {
process_information::node_id_type nid; return get_actor_registry()->get(aid);
source->begin_object(cname); }
auto aid = source->read<uint32_t>(); else {
auto pid = source->read<uint32_t>(); process_information tmp{pid, nid};
source->read_raw(process_information::node_id_size, nid.data()); return get_or_put(tmp, aid);
source->end_object();
// local actor?
auto pinf = process_information::get();
if (pid == pinf->process_id() && nid == pinf->node_id()) {
return get_actor_registry()->get(aid);
}
else {
process_information tmp(pid, nid);
return get_or_put(tmp, aid);
}
} }
else throw runtime_error("expected type name \"@0\" or \"@actor\"; "
"found: " + cname);
} }
size_t default_actor_addressing::count_proxies(const process_information& inf) { size_t default_actor_addressing::count_proxies(const process_information& inf) {
...@@ -148,16 +136,20 @@ void default_actor_addressing::put(const process_information& node, ...@@ -148,16 +136,20 @@ void default_actor_addressing::put(const process_information& node,
} }
} }
actor_ptr default_actor_addressing::get_or_put(const process_information& inf, actor_ptr default_actor_addressing::get_or_put(const process_information& inf,
actor_id aid) { actor_id aid) {
auto result = get(inf, aid); auto result = get(inf, aid);
if (result == nullptr) { if (result == nullptr) {
CPPA_LOGMF(CPPA_INFO, self, "created new proxy instance; " CPPA_LOGMF(CPPA_INFO, self, "created new proxy instance; "
<< CPPA_TARG(inf, to_string) << ", " << CPPA_ARG(aid)); << CPPA_TARG(inf, to_string) << ", " << CPPA_ARG(aid));
auto ptr = make_counted<default_actor_proxy>(aid, new process_information(inf), m_parent); if (m_parent == nullptr) {
put(inf, aid, ptr); CPPA_LOG_ERROR("m_parent == nullptr (cannot create proxy without MM)");
result = ptr; }
else {
auto ptr = make_counted<default_actor_proxy>(aid, new process_information(inf), m_parent);
put(inf, aid, ptr);
result = ptr;
}
} }
return result; return result;
} }
......
...@@ -40,16 +40,20 @@ ...@@ -40,16 +40,20 @@
#include "cppa/singletons.hpp" #include "cppa/singletons.hpp"
#include "cppa/exit_reason.hpp" #include "cppa/exit_reason.hpp"
#include "cppa/actor_proxy.hpp" #include "cppa/actor_proxy.hpp"
#include "cppa/message_header.hpp"
#include "cppa/binary_serializer.hpp" #include "cppa/binary_serializer.hpp"
#include "cppa/binary_deserializer.hpp" #include "cppa/binary_deserializer.hpp"
#include "cppa/util/algorithm.hpp"
#include "cppa/detail/demangle.hpp" #include "cppa/detail/demangle.hpp"
#include "cppa/detail/object_array.hpp"
#include "cppa/detail/actor_registry.hpp" #include "cppa/detail/actor_registry.hpp"
#include "cppa/detail/singleton_manager.hpp" #include "cppa/detail/singleton_manager.hpp"
#include "cppa/detail/uniform_type_info_map.hpp"
#include "cppa/io/middleman.hpp" #include "cppa/io/middleman.hpp"
#include "cppa/io/default_peer.hpp" #include "cppa/io/default_peer.hpp"
#include "cppa/message_header.hpp"
#include "cppa/io/default_protocol.hpp" #include "cppa/io/default_protocol.hpp"
using namespace std; using namespace std;
...@@ -113,7 +117,7 @@ continue_reading_result default_peer::continue_reading() { ...@@ -113,7 +117,7 @@ continue_reading_result default_peer::continue_reading() {
<< std::endl; << std::endl;
return read_failure; return read_failure;
} }
CPPA_LOGMF(CPPA_DEBUG, self, "read process info: " << to_string(*m_node)); CPPA_LOG_DEBUG("read process info: " << to_string(*m_node));
m_parent->register_peer(*m_node, this); m_parent->register_peer(*m_node, this);
// initialization done // initialization done
m_state = wait_for_msg_size; m_state = wait_for_msg_size;
...@@ -135,7 +139,7 @@ continue_reading_result default_peer::continue_reading() { ...@@ -135,7 +139,7 @@ continue_reading_result default_peer::continue_reading() {
message_header hdr; message_header hdr;
any_tuple msg; any_tuple msg;
binary_deserializer bd(m_rd_buf.data(), m_rd_buf.size(), binary_deserializer bd(m_rd_buf.data(), m_rd_buf.size(),
m_parent->addressing()); m_parent->addressing(), &m_incoming_types);
try { try {
m_meta_hdr->deserialize(&hdr, &bd); m_meta_hdr->deserialize(&hdr, &bd);
m_meta_msg->deserialize(&msg, &bd); m_meta_msg->deserialize(&msg, &bd);
...@@ -146,8 +150,7 @@ continue_reading_result default_peer::continue_reading() { ...@@ -146,8 +150,7 @@ continue_reading_result default_peer::continue_reading() {
<< ", what(): " << e.what()); << ", what(): " << e.what());
return read_failure; return read_failure;
} }
CPPA_LOGMF(CPPA_DEBUG, self, "deserialized: " << to_string(hdr) << " " << to_string(msg)); CPPA_LOG_DEBUG("deserialized: " << to_string(hdr) << " " << to_string(msg));
//DEBUG("<-- " << to_string(msg));
match(msg) ( match(msg) (
// monitor messages are sent automatically whenever // monitor messages are sent automatically whenever
// actor_proxy_cache creates a new proxy // actor_proxy_cache creates a new proxy
...@@ -164,6 +167,11 @@ continue_reading_result default_peer::continue_reading() { ...@@ -164,6 +167,11 @@ continue_reading_result default_peer::continue_reading() {
on(atom("UNLINK"), arg_match) >> [&](const actor_ptr& ptr) { on(atom("UNLINK"), arg_match) >> [&](const actor_ptr& ptr) {
unlink(hdr.sender, ptr); unlink(hdr.sender, ptr);
}, },
on(atom("ADD_TYPE"), arg_match) >> [&](std::uint32_t id, const std::string& name) {
auto imap = get_uniform_type_info_map();
auto uti = imap->by_uniform_name(name);
m_incoming_types.emplace(id, uti);
},
others() >> [&] { others() >> [&] {
deliver(hdr, move(msg)); deliver(hdr, move(msg));
} }
...@@ -314,12 +322,24 @@ continue_writing_result default_peer::continue_writing() { ...@@ -314,12 +322,24 @@ continue_writing_result default_peer::continue_writing() {
return result; return result;
} }
void default_peer::add_type_if_needed(const std::string& tname) {
if (m_outgoing_types.id_of(tname) == 0) {
auto id = m_outgoing_types.max_id() + 1;
auto imap = get_uniform_type_info_map();
auto uti = imap->by_uniform_name(tname);
m_outgoing_types.emplace(id, uti);
enqueue_impl({nullptr}, make_any_tuple(atom("ADD_TYPE"), id, tname));
}
}
void default_peer::enqueue_impl(const message_header& hdr, const any_tuple& msg) { void default_peer::enqueue_impl(const message_header& hdr, const any_tuple& msg) {
CPPA_LOG_TRACE(""); CPPA_LOG_TRACE("");
auto tname = msg.tuple_type_names();
add_type_if_needed((tname) ? *tname : detail::get_tuple_type_names(*msg.vals()));
uint32_t size = 0; uint32_t size = 0;
auto& wbuf = write_buffer(); auto& wbuf = write_buffer();
auto before = wbuf.size(); auto before = wbuf.size();
binary_serializer bs(&wbuf, m_parent->addressing()); binary_serializer bs(&wbuf, m_parent->addressing(), &m_outgoing_types);
wbuf.write(sizeof(uint32_t), &size); wbuf.write(sizeof(uint32_t), &size);
try { bs << hdr << msg; } try { bs << hdr << msg; }
catch (exception& e) { catch (exception& e) {
......
...@@ -40,7 +40,8 @@ ...@@ -40,7 +40,8 @@
namespace cppa { namespace cppa {
deserializer::deserializer(actor_addressing* aa) : m_addressing(aa) { } deserializer::deserializer(actor_addressing* aa, type_lookup_table* ot)
: m_addressing{aa}, m_incoming_types{ot} { }
deserializer::~deserializer() { } deserializer::~deserializer() { }
...@@ -50,14 +51,4 @@ void deserializer::read_raw(size_t num_bytes, util::buffer& storage) { ...@@ -50,14 +51,4 @@ void deserializer::read_raw(size_t num_bytes, util::buffer& storage) {
storage.inc_size(num_bytes); storage.inc_size(num_bytes);
} }
deserializer& operator>>(deserializer& d, object& what) {
std::string tname = d.peek_object();
auto mtype = uniform_type_info::from(tname);
if (mtype == nullptr) {
throw std::logic_error("no uniform type info found for " + tname);
}
what = std::move(mtype->deserialize(&d));
return d;
}
} // namespace cppa } // namespace cppa
...@@ -63,4 +63,9 @@ const std::type_info* empty_tuple::type_token() const { ...@@ -63,4 +63,9 @@ const std::type_info* empty_tuple::type_token() const {
return &typeid(util::empty_type_list); return &typeid(util::empty_type_list);
} }
const std::string* empty_tuple::tuple_type_names() const {
static std::string result = "";
return &result;
}
} } // namespace cppa::detail } } // namespace cppa::detail
...@@ -62,4 +62,8 @@ const uniform_type_info* object_array::type_at(size_t pos) const { ...@@ -62,4 +62,8 @@ const uniform_type_info* object_array::type_at(size_t pos) const {
return m_elements[pos].type(); return m_elements[pos].type();
} }
const std::string* object_array::tuple_type_names() const {
return nullptr; // get_tuple_type_names(*this);
}
} } // namespace cppa::detail } } // namespace cppa::detail
...@@ -28,9 +28,6 @@ ...@@ -28,9 +28,6 @@
\******************************************************************************/ \******************************************************************************/
#include "cppa/config.hpp"
#include "cppa/process_information.hpp"
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#include <sstream> #include <sstream>
...@@ -38,6 +35,11 @@ ...@@ -38,6 +35,11 @@
#include <unistd.h> #include <unistd.h>
#include <sys/types.h> #include <sys/types.h>
#include "cppa/config.hpp"
#include "cppa/serializer.hpp"
#include "cppa/primitive_variant.hpp"
#include "cppa/process_information.hpp"
#include "cppa/util/algorithm.hpp" #include "cppa/util/algorithm.hpp"
#include "cppa/util/ripemd_160.hpp" #include "cppa/util/ripemd_160.hpp"
#include "cppa/util/get_root_uuid.hpp" #include "cppa/util/get_root_uuid.hpp"
...@@ -123,17 +125,15 @@ bool equal(const std::string& hash, ...@@ -123,17 +125,15 @@ bool equal(const std::string& hash,
} }
process_information::process_information(const process_information& other) process_information::process_information(const process_information& other)
: super(), m_process_id(other.process_id()), m_node_id(other.node_id()) { : super(), m_process_id(other.process_id()), m_node_id(other.node_id()) { }
}
process_information::process_information(std::uint32_t a, const std::string& b) process_information::process_information(std::uint32_t a, const std::string& b)
: m_process_id(a) { : m_process_id(a) {
node_id_from_string(b, m_node_id); node_id_from_string(b, m_node_id);
} }
process_information::process_information(std::uint32_t a, const node_id_type& b) process_information::process_information(std::uint32_t a, const node_id_type& b)
: m_process_id(a), m_node_id(b) { : m_process_id(a), m_node_id(b) { }
}
std::string to_string(const process_information::node_id_type& node_id) { std::string to_string(const process_information::node_id_type& node_id) {
std::ostringstream oss; std::ostringstream oss;
...@@ -162,6 +162,13 @@ int process_information::compare(const process_information& other) const { ...@@ -162,6 +162,13 @@ int process_information::compare(const process_information& other) const {
return tmp; return tmp;
} }
void process_information::serialize_invalid(serializer* sink) {
sink->write_value(static_cast<uint32_t>(0));
process_information::node_id_type zero;
std::fill(zero.begin(), zero.end(), 0);
sink->write_raw(process_information::node_id_size, zero.data());
}
std::string to_string(const process_information& what) { std::string to_string(const process_information& what) {
std::ostringstream oss; std::ostringstream oss;
oss << what.process_id() << "@" << to_string(what.node_id()); oss << what.process_id() << "@" << to_string(what.node_id());
......
...@@ -32,7 +32,8 @@ ...@@ -32,7 +32,8 @@
namespace cppa { namespace cppa {
serializer::serializer(actor_addressing* aa) : m_addressing(aa) { } serializer::serializer(actor_addressing* aa, type_lookup_table* it)
: m_addressing{aa}, m_outgoing_types{it} { }
serializer::~serializer() { } serializer::~serializer() { }
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include "cppa/object.hpp" #include "cppa/object.hpp"
#include "cppa/to_string.hpp" #include "cppa/to_string.hpp"
#include "cppa/serializer.hpp" #include "cppa/serializer.hpp"
#include "cppa/singletons.hpp"
#include "cppa/from_string.hpp" #include "cppa/from_string.hpp"
#include "cppa/deserializer.hpp" #include "cppa/deserializer.hpp"
#include "cppa/primitive_variant.hpp" #include "cppa/primitive_variant.hpp"
...@@ -46,6 +47,8 @@ ...@@ -46,6 +47,8 @@
#include "cppa/io/default_actor_addressing.hpp" #include "cppa/io/default_actor_addressing.hpp"
#include "cppa/detail/uniform_type_info_map.hpp"
using namespace std; using namespace std;
namespace cppa { namespace cppa {
...@@ -115,11 +118,12 @@ class string_serializer : public serializer { ...@@ -115,11 +118,12 @@ class string_serializer : public serializer {
string_serializer(ostream& mout) string_serializer(ostream& mout)
: super(&m_addressing), out(mout), m_after_value(false), m_obj_just_opened(false) { } : super(&m_addressing), out(mout), m_after_value(false), m_obj_just_opened(false) { }
void begin_object(const string& type_name) { void begin_object(const uniform_type_info* uti) {
clear(); clear();
m_open_objects.push(type_name); std::string tname = uti->name();
m_open_objects.push(tname);
// do not print type names for strings and atoms // do not print type names for strings and atoms
if (!isbuiltin(type_name)) out << type_name; if (!isbuiltin(tname)) out << tname;
m_obj_just_opened = true; m_obj_just_opened = true;
} }
...@@ -274,43 +278,34 @@ class string_deserializer : public deserializer { ...@@ -274,43 +278,34 @@ class string_deserializer : public deserializer {
m_pos = m_str.begin(); m_pos = m_str.begin();
} }
string seek_object() { const uniform_type_info* begin_object() override {
skip_space_and_comma(); skip_space_and_comma();
string type_name;
// shortcuts for builtin types // shortcuts for builtin types
if (*m_pos == '"') { if (*m_pos == '"') {
return "@str"; type_name = "@str";
} }
else if (*m_pos == '\'') { else if (*m_pos == '\'') {
return "@atom"; type_name = "@atom";
} }
else if (*m_pos == '{') { else if (*m_pos == '{') {
return "@tuple"; type_name = "@tuple";
} }
// default case else {
auto substr_end = next_delimiter(); auto substr_end = next_delimiter();
if (m_pos == substr_end) { if (m_pos == substr_end) {
throw_malformed("could not seek object type name"); throw_malformed("could not seek object type name");
}
type_name = string(m_pos, substr_end);
m_pos = substr_end;
} }
string result(m_pos, substr_end);
m_pos = substr_end;
return result;
}
string peek_object() {
auto pos = m_pos;
string result = seek_object();
// restore position in stream
m_pos = pos;
return result;
}
void begin_object(const string& type_name) {
m_open_objects.push(type_name); m_open_objects.push(type_name);
//++m_obj_count; //++m_obj_count;
skip_space_and_comma(); skip_space_and_comma();
// suppress leading parenthesis for builtin types // suppress leading parenthesis for builtin types
m_obj_had_left_parenthesis.push(try_consume('(')); m_obj_had_left_parenthesis.push(try_consume('('));
//consume('('); //consume('(');
return get_uniform_type_info_map()->by_uniform_name(type_name);
} }
void end_object() { void end_object() {
...@@ -493,12 +488,10 @@ class string_deserializer : public deserializer { ...@@ -493,12 +488,10 @@ class string_deserializer : public deserializer {
object from_string(const string& what) { object from_string(const string& what) {
string_deserializer strd(what); string_deserializer strd(what);
string uname = strd.peek_object(); auto utype = strd.begin_object();
auto utype = uniform_type_info::from(uname); auto result = utype->deserialize(&strd);
if (utype == nullptr) { strd.end_object();
throw logic_error(uname + " is not announced"); return result;
}
return utype->deserialize(&strd);
} }
namespace detail { namespace detail {
...@@ -506,7 +499,9 @@ namespace detail { ...@@ -506,7 +499,9 @@ namespace detail {
string to_string_impl(const void *what, const uniform_type_info *utype) { string to_string_impl(const void *what, const uniform_type_info *utype) {
ostringstream osstr; ostringstream osstr;
string_serializer strs(osstr); string_serializer strs(osstr);
strs.begin_object(utype);
utype->serialize(what, &strs); utype->serialize(what, &strs);
strs.end_object();
return osstr.str(); return osstr.str();
} }
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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 <algorithm>
#include "cppa/singletons.hpp"
#include "cppa/type_lookup_table.hpp"
#include "cppa/detail/uniform_type_info_map.hpp"
namespace cppa {
type_lookup_table::type_lookup_table() {
auto uti_map = get_uniform_type_info_map();
auto get = [=](const char* cstr) {
return uti_map->by_uniform_name(cstr);
};
emplace(1, get("@<>+@atom"));
emplace(2, get("@<>+@atom+@u32"));
emplace(3, get("@<>+@atom+@proc"));
emplace(4, get("@<>+@atom+@proc+@u32"));
emplace(5, get("@<>+@atom+@proc+@u32+@u32"));
emplace(6, get("@<>+@atom+@actor"));
emplace(7, get("@<>+@atom+@u32+@str"));
}
auto type_lookup_table::by_id(std::uint32_t id) const -> pointer {
auto i = find(id);
return (i == m_data.end() || i->first != id) ? nullptr : i->second;
}
auto type_lookup_table::by_name(const std::string& name) const -> pointer {
auto e = m_data.end();
auto i = std::find_if(m_data.begin(), e, [&](const value_type& val) {
return val.second->name() == name;
});
return (i != e) ? i->second : nullptr;
}
std::uint32_t type_lookup_table::id_of(const std::string& name) const {
auto e = m_data.end();
auto i = std::find_if(m_data.begin(), e, [&](const value_type& val) {
return val.second->name() == name;
});
return (i != e) ? i->first : 0;
}
std::uint32_t type_lookup_table::id_of(pointer uti) const {
auto e = m_data.end();
auto i = std::find_if(m_data.begin(), e, [&](const value_type& val) {
return val.second == uti;
});
return (i != e) ? i->first : 0;
}
void type_lookup_table::emplace(std::uint32_t id, pointer instance) {
CPPA_REQUIRE(instance);
value_type kvp{id, instance};
auto i = find(id);
if (i == m_data.end()) m_data.push_back(std::move(kvp));
else if (i->first == id) throw std::runtime_error("key already defined");
else m_data.insert(i, std::move(kvp));
}
auto type_lookup_table::find(std::uint32_t arg) const -> const_iterator {
return std::lower_bound(m_data.begin(), m_data.end(), arg, [](const value_type& lhs, std::uint32_t id) {
return lhs.first < id;
});
}
auto type_lookup_table::find(std::uint32_t arg) -> iterator {
return std::lower_bound(m_data.begin(), m_data.end(), arg, [](const value_type& lhs, std::uint32_t id) {
return lhs.first < id;
});
}
std::uint32_t type_lookup_table::max_id() const {
return m_data.empty() ? 0 : m_data.back().first;
}
} // namespace cppa
...@@ -69,8 +69,9 @@ namespace { inline detail::uniform_type_info_map& uti_map() { ...@@ -69,8 +69,9 @@ namespace { inline detail::uniform_type_info_map& uti_map() {
return *detail::singleton_manager::get_uniform_type_info_map(); return *detail::singleton_manager::get_uniform_type_info_map();
} } // namespace <anonymous> } } // namespace <anonymous>
bool announce(const std::type_info&, uniform_type_info* utype) { const uniform_type_info* announce(const std::type_info&,
return uti_map().insert(utype); std::unique_ptr<uniform_type_info> utype) {
return uti_map().insert(std::move(utype));
} }
uniform_type_info::~uniform_type_info() { } uniform_type_info::~uniform_type_info() { }
......
This diff is collapsed.
...@@ -28,7 +28,7 @@ void cppa_unexpected_timeout(const char* fname, size_t line_num); ...@@ -28,7 +28,7 @@ void cppa_unexpected_timeout(const char* fname, size_t line_num);
cppa_strip_path(fname) << ":" << cppa_fill4(line) << " " << message cppa_strip_path(fname) << ":" << cppa_fill4(line) << " " << message
#define CPPA_PRINTC(filename, linenum, message) \ #define CPPA_PRINTC(filename, linenum, message) \
CPPA_LOGF_INFO(CPPA_STREAMIFY(filename, linenum, message)); \ CPPA_LOGF_INFO(CPPA_STREAMIFY(filename, linenum, message)); \
std::cout << CPPA_STREAMIFY(filename, linenum, message) << std::endl std::cout << CPPA_STREAMIFY(filename, linenum, message) << std::endl
#define CPPA_PRINT(message) CPPA_PRINTC(__FILE__, __LINE__, message) #define CPPA_PRINT(message) CPPA_PRINTC(__FILE__, __LINE__, message)
...@@ -144,7 +144,7 @@ inline void cppa_check_value(V1 v1, ...@@ -144,7 +144,7 @@ inline void cppa_check_value(V1 v1,
#define CPPA_CHECK_NOT_EQUAL(rhs_loc, lhs_loc) \ #define CPPA_CHECK_NOT_EQUAL(rhs_loc, lhs_loc) \
cppa_check_value((lhs_loc), (rhs_loc), __FILE__, __LINE__, false) cppa_check_value((lhs_loc), (rhs_loc), __FILE__, __LINE__, false)
#define CPPA_FAILURE(err_msg) { \ #define CPPA_FAILURE(err_msg) { \
CPPA_PRINTERR("ERROR: " << err_msg); \ CPPA_PRINTERR("ERROR: " << err_msg); \
cppa_inc_error_count(); \ cppa_inc_error_count(); \
} ((void) 0) } ((void) 0)
......
...@@ -102,12 +102,61 @@ void example() { ...@@ -102,12 +102,61 @@ void example() {
} }
} }
template<typename T>
struct type_token { typedef T type; };
template<typename... Ts>
struct variant;
template<typename T>
struct variant<T> {
T& get(type_token<T>) { return m_value; }
T m_value;
};
template<typename T0, typename T1>
struct variant<T0, T1> {
public:
T0& get(type_token<T0>) { return m_v0; }
T1& get(type_token<T1>) { return m_v1; }
variant() : m_type{0}, m_v0{} { }
~variant() {
switch (m_type) {
case 0: m_v0.~T0(); break;
case 1: m_v1.~T1(); break;
}
}
private:
size_t m_type;
union { T0 m_v0; T1 m_v1; };
};
template<typename T, typename... Ts>
T& get(variant<Ts...>& v) {
return v.get(type_token<T>{});
}
int main() { int main() {
CPPA_TEST(test_match); CPPA_TEST(test_match);
using namespace std::placeholders; using namespace std::placeholders;
using namespace cppa::placeholders; using namespace cppa::placeholders;
variant<int, double> rofl;
get<int>(rofl) = 42;
cout << "rofl = " << get<int>(rofl) << endl;
auto ascending = [](int a, int b, int c) -> bool { auto ascending = [](int a, int b, int c) -> bool {
return a < b && b < c; return a < b && b < c;
}; };
......
...@@ -311,6 +311,9 @@ class server : public event_based_actor { ...@@ -311,6 +311,9 @@ class server : public event_based_actor {
int main(int argc, char** argv) { int main(int argc, char** argv) {
announce<actor_vector>(); announce<actor_vector>();
add_tuple_hint<atom_value>();
add_tuple_hint<atom_value, actor_ptr>();
add_tuple_hint<atom_value, atom_value, int>();
string app_path = argv[0]; string app_path = argv[0];
bool run_remote_actor = true; bool run_remote_actor = true;
if (argc > 1) { if (argc > 1) {
......
...@@ -44,6 +44,8 @@ ...@@ -44,6 +44,8 @@
#include "cppa/util/get_mac_addresses.hpp" #include "cppa/util/get_mac_addresses.hpp"
#include "cppa/util/pt_token.hpp" #include "cppa/util/pt_token.hpp"
#include "cppa/util/int_list.hpp"
#include "cppa/util/algorithm.hpp"
#include "cppa/util/type_traits.hpp" #include "cppa/util/type_traits.hpp"
#include "cppa/util/abstract_uniform_type_info.hpp" #include "cppa/util/abstract_uniform_type_info.hpp"
...@@ -126,20 +128,15 @@ bool operator!=(const raw_struct& lhs, const raw_struct& rhs) { ...@@ -126,20 +128,15 @@ bool operator!=(const raw_struct& lhs, const raw_struct& rhs) {
struct raw_struct_type_info : util::abstract_uniform_type_info<raw_struct> { struct raw_struct_type_info : util::abstract_uniform_type_info<raw_struct> {
void serialize(const void* ptr, serializer* sink) const { void serialize(const void* ptr, serializer* sink) const {
auto rs = reinterpret_cast<const raw_struct*>(ptr); auto rs = reinterpret_cast<const raw_struct*>(ptr);
sink->begin_object(name());
sink->write_value(static_cast<uint32_t>(rs->str.size())); sink->write_value(static_cast<uint32_t>(rs->str.size()));
sink->write_raw(rs->str.size(), rs->str.data()); sink->write_raw(rs->str.size(), rs->str.data());
sink->end_object();
} }
void deserialize(void* ptr, deserializer* source) const { void deserialize(void* ptr, deserializer* source) const {
assert_type_name(source);
source->begin_object(name());
auto rs = reinterpret_cast<raw_struct*>(ptr); auto rs = reinterpret_cast<raw_struct*>(ptr);
rs->str.clear(); rs->str.clear();
auto size = source->read<std::uint32_t>(); auto size = source->read<std::uint32_t>();
rs->str.resize(size); rs->str.resize(size);
source->read_raw(size, &(rs->str[0])); source->read_raw(size, &(rs->str[0]));
source->end_object();
} }
}; };
...@@ -154,7 +151,7 @@ int main() { ...@@ -154,7 +151,7 @@ int main() {
CPPA_CHECK_EQUAL(detail::impl_id<strmap>(), 2); CPPA_CHECK_EQUAL(detail::impl_id<strmap>(), 2);
CPPA_CHECK_EQUAL(token::value, 2); CPPA_CHECK_EQUAL(token::value, 2);
announce(typeid(raw_struct), new raw_struct_type_info); announce(typeid(raw_struct), create_unique<raw_struct_type_info>());
io::default_actor_addressing addressing; io::default_actor_addressing addressing;
...@@ -177,6 +174,24 @@ int main() { ...@@ -177,6 +174,24 @@ int main() {
} }
catch (exception& e) { CPPA_FAILURE(to_verbose_string(e)); } catch (exception& e) { CPPA_FAILURE(to_verbose_string(e)); }
detail::meta_cow_tuple<int,int> mct;
try {
auto tup0 = make_cow_tuple(1, 2);
util::buffer wr_buf;
binary_serializer bs(&wr_buf, &addressing);
mct.serialize(&tup0, &bs);
binary_deserializer bd(wr_buf.data(), wr_buf.size(), &addressing);
auto ptr = mct.new_instance();
auto ptr_guard = make_scope_guard([&] {
mct.delete_instance(ptr);
});
mct.deserialize(ptr, &bd);
auto& tref = *reinterpret_cast<cow_tuple<int, int>*>(ptr);
CPPA_CHECK_EQUAL(get<0>(tup0), get<0>(tref));
CPPA_CHECK_EQUAL(get<1>(tup0), get<1>(tref));
}
catch (exception& e) { CPPA_FAILURE(to_verbose_string(e)); }
try { try {
// test raw_type in both binary and string serialization // test raw_type in both binary and string serialization
raw_struct rs; raw_struct rs;
...@@ -196,6 +211,18 @@ int main() { ...@@ -196,6 +211,18 @@ int main() {
} }
catch (exception& e) { CPPA_FAILURE(to_verbose_string(e)); } catch (exception& e) { CPPA_FAILURE(to_verbose_string(e)); }
try {
auto ttup = make_any_tuple(1, 2, actor_ptr(self));
util::buffer wr_buf;
binary_serializer bs(&wr_buf, &addressing);
bs << ttup;
binary_deserializer bd(wr_buf.data(), wr_buf.size(), &addressing);
any_tuple ttup2;
uniform_typeid<any_tuple>()->deserialize(&ttup2, &bd);
CPPA_CHECK(ttup == ttup2);
}
catch (exception& e) { CPPA_FAILURE(to_verbose_string(e)); }
try { try {
auto ttup = make_any_tuple(1, 2, actor_ptr(self)); auto ttup = make_any_tuple(1, 2, actor_ptr(self));
util::buffer wr_buf; util::buffer wr_buf;
...@@ -234,6 +261,7 @@ int main() { ...@@ -234,6 +261,7 @@ int main() {
catch (exception& e) { CPPA_FAILURE(to_verbose_string(e)); } catch (exception& e) { CPPA_FAILURE(to_verbose_string(e)); }
try { try {
/*
any_tuple msg1 = cppa::make_cow_tuple(42, string("Hello \"World\"!")); any_tuple msg1 = cppa::make_cow_tuple(42, string("Hello \"World\"!"));
auto msg1_tostring = to_string(msg1); auto msg1_tostring = to_string(msg1);
if (msg1str != msg1_tostring) { if (msg1str != msg1_tostring) {
...@@ -269,6 +297,7 @@ int main() { ...@@ -269,6 +297,7 @@ int main() {
else { else {
CPPA_FAILURE("obj.type() != typeid(message)"); CPPA_FAILURE("obj.type() != typeid(message)");
} }
*/
} }
catch (exception& e) { CPPA_FAILURE(to_verbose_string(e)); } catch (exception& e) { CPPA_FAILURE(to_verbose_string(e)); }
...@@ -277,7 +306,7 @@ int main() { ...@@ -277,7 +306,7 @@ int main() {
CPPA_CHECK((is_iterable<string>::value) == false); CPPA_CHECK((is_iterable<string>::value) == false);
CPPA_CHECK((is_iterable<list<int>>::value) == true); CPPA_CHECK((is_iterable<list<int>>::value) == true);
CPPA_CHECK((is_iterable<map<int, int>>::value) == true); CPPA_CHECK((is_iterable<map<int, int>>::value) == true);
{ // test meta_object implementation for primitive types try { // test meta_object implementation for primitive types
auto meta_int = uniform_typeid<uint32_t>(); auto meta_int = uniform_typeid<uint32_t>();
CPPA_CHECK(meta_int != nullptr); CPPA_CHECK(meta_int != nullptr);
if (meta_int) { if (meta_int) {
...@@ -287,8 +316,12 @@ int main() { ...@@ -287,8 +316,12 @@ int main() {
CPPA_CHECK_EQUAL( "@u32 ( 42 )", str); CPPA_CHECK_EQUAL( "@u32 ( 42 )", str);
} }
} }
{ // test serializers / deserializers with struct_b catch (exception& e) { CPPA_FAILURE(to_verbose_string(e)); }
try
{ // test serializers / deserializers with struct_b
// get meta object for struct_b // get meta object for struct_b
/*
announce<struct_b>(compound_member(&struct_b::a, announce<struct_b>(compound_member(&struct_b::a,
&struct_a::x, &struct_a::x,
&struct_a::y), &struct_a::y),
...@@ -323,9 +356,13 @@ int main() { ...@@ -323,9 +356,13 @@ int main() {
b3 = get<struct_b>(res); b3 = get<struct_b>(res);
} }
CPPA_CHECK(b1 == b3); CPPA_CHECK(b1 == b3);
*/
} }
{ // test serializers / deserializers with struct_c catch (exception& e) { CPPA_FAILURE(to_verbose_string(e)); }
// get meta type of struct_c and "announce"
try { // test serializers / deserializers with struct_c
// get meta type of struct_c and "announce"
/*
announce<struct_c>(&struct_c::strings, &struct_c::ints); announce<struct_c>(&struct_c::strings, &struct_c::ints);
// testees // testees
struct_c c1{strmap{{"abc", u"cba" }, { "x", u"y" }}, set<int>{9, 4, 5}}; struct_c c1{strmap{{"abc", u"cba" }, { "x", u"y" }}, set<int>{9, 4, 5}};
...@@ -343,6 +380,9 @@ int main() { ...@@ -343,6 +380,9 @@ int main() {
} }
// verify result of serialization / deserialization // verify result of serialization / deserialization
CPPA_CHECK(c1 == c2); CPPA_CHECK(c1 == c2);
*/
} }
catch (exception& e) { CPPA_FAILURE(to_verbose_string(e)); }
return CPPA_TEST_RESULT(); return CPPA_TEST_RESULT();
} }
...@@ -46,10 +46,14 @@ using namespace cppa; ...@@ -46,10 +46,14 @@ using namespace cppa;
int main() { int main() {
CPPA_TEST(test_uniform_type); CPPA_TEST(test_uniform_type);
bool announce1 = announce<foo>(&foo::value); auto announce1 = announce<foo>(&foo::value);
bool announce2 = announce<foo>(&foo::value); auto announce2 = announce<foo>(&foo::value);
bool announce3 = announce<foo>(&foo::value); auto announce3 = announce<foo>(&foo::value);
bool announce4 = announce<foo>(&foo::value); auto announce4 = announce<foo>(&foo::value);
CPPA_CHECK(announce1 == announce2);
CPPA_CHECK(announce1 == announce3);
CPPA_CHECK(announce1 == announce4);
CPPA_CHECK_EQUAL(announce1->name(), "$::foo");
{ {
//bar.create_object(); //bar.create_object();
object obj1 = uniform_typeid<foo>()->create(); object obj1 = uniform_typeid<foo>()->create();
...@@ -60,12 +64,6 @@ int main() { ...@@ -60,12 +64,6 @@ int main() {
CPPA_CHECK_EQUAL(get<foo>(obj1).value, 42); CPPA_CHECK_EQUAL(get<foo>(obj1).value, 42);
CPPA_CHECK_EQUAL(get<foo>(obj2).value, 0); CPPA_CHECK_EQUAL(get<foo>(obj2).value, 0);
} }
auto int_val = [](bool val) { return val ? 1 : 0; };
int successful_announces = int_val(announce1)
+ int_val(announce2)
+ int_val(announce3)
+ int_val(announce4);
CPPA_CHECK_EQUAL(1, successful_announces);
// these types (and only those) are present if // these types (and only those) are present if
// the uniform_type_info implementation is correct // the uniform_type_info implementation is correct
std::set<std::string> expected = { std::set<std::string> expected = {
...@@ -78,6 +76,8 @@ int main() { ...@@ -78,6 +76,8 @@ int main() {
"float", "double", "@ldouble", // floating points "float", "double", "@ldouble", // floating points
"@0", // cppa::util::void_type "@0", // cppa::util::void_type
// default announced cppa types // default announced cppa types
"@ac_hdl", // cppa::io::accept_handle
"@cn_hdl", // cppa::io::connection_handle
"@atom", // cppa::atom_value "@atom", // cppa::atom_value
"@tuple", // cppa::any_tuple "@tuple", // cppa::any_tuple
"@header", // cppa::message_header "@header", // cppa::message_header
......
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