Commit 6a058c4d authored by Dominik Charousset's avatar Dominik Charousset

Merge branch 'unstable' of github.com:Neverlord/libcppa into unstable

parents 8f79f160 9e7db021
...@@ -131,6 +131,7 @@ set(LIBCPPA_SRC ...@@ -131,6 +131,7 @@ set(LIBCPPA_SRC
src/uniform_type_info.cpp src/uniform_type_info.cpp
src/yield_interface.cpp src/yield_interface.cpp
src/context_switching_actor.cpp src/context_switching_actor.cpp
src/decorated_names_map.cpp
) )
set(boost_context third_party/boost_context) set(boost_context third_party/boost_context)
......
...@@ -272,3 +272,6 @@ examples/group_chat.cpp ...@@ -272,3 +272,6 @@ examples/group_chat.cpp
cppa/opt.hpp cppa/opt.hpp
src/opt.cpp src/opt.cpp
cppa/detail/opt_impls.hpp cppa/detail/opt_impls.hpp
examples/type_plugins.hpp
cppa/detail/decorated_names_map.hpp
src/decorated_names_map.cpp
...@@ -202,6 +202,11 @@ class actor : public channel { ...@@ -202,6 +202,11 @@ class actor : public channel {
*/ */
typedef intrusive_ptr<actor> actor_ptr; typedef intrusive_ptr<actor> actor_ptr;
class self_type;
bool operator==(const actor_ptr& lhs, const self_type& rhs);
bool operator!=(const self_type& lhs, const actor_ptr& rhs);
/****************************************************************************** /******************************************************************************
* inline and template member function implementations * * inline and template member function implementations *
******************************************************************************/ ******************************************************************************/
......
...@@ -751,9 +751,11 @@ inline void await_all_others_done() { ...@@ -751,9 +751,11 @@ inline void await_all_others_done() {
* The connection is automatically closed if the lifetime of @p whom ends. * The connection is automatically closed if the lifetime of @p whom ends.
* @param whom Actor that should be published at @p port. * @param whom Actor that should be published at @p port.
* @param port Unused TCP port. * @param port Unused TCP port.
* @param addr The IP address to listen to, or @p INADDR_ANY if @p addr is
* @p nullptr.
* @throws bind_failure * @throws bind_failure
*/ */
void publish(actor_ptr whom, std::uint16_t port); void publish(actor_ptr whom, std::uint16_t port, const char* addr = nullptr);
/** /**
* @brief Publishes @p whom using @p acceptor to handle incoming connections. * @brief Publishes @p whom using @p acceptor to handle incoming connections.
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011, 2012 *
* 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 3 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>
namespace cppa { namespace detail {
class decorated_names_map {
public:
decorated_names_map();
// 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:
std::map<std::string, std::string> m_map;
};
} } // namespace cppa::detail
#endif // DECORATED_NAMES_MAP_HPP
...@@ -319,10 +319,7 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T ...@@ -319,10 +319,7 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T
} }
void deserialize(void* obj, deserializer* d) const { void deserialize(void* obj, deserializer* d) const {
std::string cname = d->seek_object(); this->assert_type_name(d);
if (cname != this->name()) {
throw std::logic_error("wrong type name found");
}
d->begin_object(this->name()); d->begin_object(this->name());
for (auto& m : m_members) { for (auto& m : m_members) {
m.deserialize(obj, d); m.deserialize(obj, d);
......
...@@ -42,7 +42,8 @@ class ipv4_acceptor : public util::acceptor { ...@@ -42,7 +42,8 @@ class ipv4_acceptor : public util::acceptor {
public: public:
static std::unique_ptr<util::acceptor> create(std::uint16_t port); static std::unique_ptr<util::acceptor> create(std::uint16_t port,
const char* addr);
~ipv4_acceptor(); ~ipv4_acceptor();
......
...@@ -36,24 +36,24 @@ ...@@ -36,24 +36,24 @@
#include "cppa/serializer.hpp" #include "cppa/serializer.hpp"
#include "cppa/deserializer.hpp" #include "cppa/deserializer.hpp"
#include "cppa/primitive_variant.hpp" #include "cppa/primitive_variant.hpp"
#include "cppa/detail/type_to_ptype.hpp"
#include "cppa/util/is_builtin.hpp"
#include "cppa/util/is_primitive.hpp"
#include "cppa/util/abstract_uniform_type_info.hpp" #include "cppa/util/abstract_uniform_type_info.hpp"
#include "cppa/detail/types_array.hpp"
#include "cppa/detail/type_to_ptype.hpp"
namespace cppa { namespace detail { namespace cppa { namespace detail {
template<typename T1, typename T2> template<typename T1, typename T2, bool PrimitiveTypes> // default: true
class pair_member : public util::abstract_uniform_type_info<std::pair<T1,T2>> { struct pair_member_impl {
static constexpr primitive_type ptype1 = type_to_ptype<T1>::ptype; static constexpr primitive_type ptype1 = type_to_ptype<T1>::ptype;
static constexpr primitive_type ptype2 = type_to_ptype<T2>::ptype; static constexpr primitive_type ptype2 = type_to_ptype<T2>::ptype;
static_assert(ptype1 != pt_null, "T1 is not a primitive type");
static_assert(ptype2 != pt_null, "T2 is not a primitive type");
typedef std::pair<T1, T2> pair_type; typedef std::pair<T1, T2> pair_type;
public:
void serialize(const void* obj, serializer* s) const { void serialize(const void* obj, serializer* s) const {
auto& p = *reinterpret_cast<const pair_type*>(obj); auto& p = *reinterpret_cast<const pair_type*>(obj);
primitive_variant values[2] = { p.first, p.second }; primitive_variant values[2] = { p.first, p.second };
...@@ -71,6 +71,51 @@ class pair_member : public util::abstract_uniform_type_info<std::pair<T1,T2>> { ...@@ -71,6 +71,51 @@ class pair_member : public util::abstract_uniform_type_info<std::pair<T1,T2>> {
}; };
template<typename T1, typename T2>
struct pair_member_impl<T1, T2, false> {
typedef std::pair<T1, T2> pair_type;
void serialize(const void* obj, serializer* s) const {
auto& arr = static_types_array<T1, T2>::arr;
auto& p = *reinterpret_cast<const pair_type*>(obj);
arr[0]->serialize(&p.first, s);
arr[1]->serialize(&p.second, s);
}
void deserialize(void* obj, deserializer* d) const {
auto& arr = static_types_array<T1, T2>::arr;
auto& p = *reinterpret_cast<pair_type*>(obj);
arr[0]->deserialize(&p.first, d);
arr[1]->deserialize(&p.second, d);
}
};
template<typename T1, typename T2>
class pair_member : public util::abstract_uniform_type_info<std::pair<T1,T2>> {
static_assert(util::is_builtin<T1>::value, "T1 is not a builtin type");
static_assert(util::is_builtin<T1>::value, "T2 is not a builtin type");
public:
void serialize(const void* obj, serializer* s) const {
impl.serialize(obj, s);
}
void deserialize(void* obj, deserializer* d) const {
impl.deserialize(obj, d);
}
private:
pair_member_impl<T1, T2, util::is_primitive<T1>::value
&& util::is_primitive<T2>::value> impl;
};
} } // namespace cppa::detail } } // namespace cppa::detail
#endif // CPPA_PAIR_MEMBER_HPP #endif // CPPA_PAIR_MEMBER_HPP
...@@ -45,6 +45,7 @@ class group_manager; ...@@ -45,6 +45,7 @@ class group_manager;
class abstract_tuple; class abstract_tuple;
class actor_registry; class actor_registry;
class network_manager; class network_manager;
class decorated_names_map;
class uniform_type_info_map; class uniform_type_info_map;
class singleton_manager { class singleton_manager {
...@@ -70,6 +71,8 @@ class singleton_manager { ...@@ -70,6 +71,8 @@ class singleton_manager {
static empty_tuple* get_empty_tuple(); static empty_tuple* get_empty_tuple();
static decorated_names_map* get_decorated_names_map();
}; };
} } // namespace cppa::detail } } // namespace cppa::detail
......
...@@ -195,11 +195,12 @@ class group : public channel { ...@@ -195,11 +195,12 @@ class group : public channel {
typedef intrusive_ptr<group> group_ptr; typedef intrusive_ptr<group> group_ptr;
/** /**
* @brief Makes *all* local groups accessible via network on @p port. * @brief Makes *all* local groups accessible via network on address @p addr
* and @p port.
* @throws bind_failure * @throws bind_failure
* @throws network_error * @throws network_error
*/ */
void publish_local_groups_at(std::uint16_t port); void publish_local_groups_at(std::uint16_t port, const char* addr = nullptr);
} // namespace cppa } // namespace cppa
......
...@@ -234,8 +234,22 @@ class uniform_type_info { ...@@ -234,8 +234,22 @@ class uniform_type_info {
*/ */
virtual void deserialize(void* instance, deserializer* source) const = 0; 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: 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(const std::string& uniform_name);
/** /**
......
...@@ -100,18 +100,13 @@ class tree_type_info : public util::abstract_uniform_type_info<tree> { ...@@ -100,18 +100,13 @@ class tree_type_info : public util::abstract_uniform_type_info<tree> {
} }
void deserialize(void* ptr, deserializer* source) const { void deserialize(void* ptr, deserializer* source) const {
// seek_object() gets the uniform name of the next object in the // throws an exception if the next object in source is not a tree
// stream without modifying the deserializer assert_type_name(source);
std::string cname = source->seek_object();
// this name has to be our type name
if (cname != name()) {
throw std::logic_error("wrong type name found");
}
// 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() // workflow is analogous to serialize: begin_object() ... end_object()
source->begin_object(cname); 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(); source->end_object();
......
#include <set> #include <set>
#include <map> #include <map>
#include <vector> #include <vector>
#include <dlfcn.h>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <time.h> #include <time.h>
#include <cstdlib> #include <cstdlib>
#include "cppa/opt.hpp"
#include "cppa/cppa.hpp" #include "cppa/cppa.hpp"
#include "type_plugins.hpp"
using namespace std; using namespace std;
using namespace cppa; using namespace cppa;
using namespace cppa::placeholders;
auto on_opt(char short_opt, const char* long_opt) -> decltype(on("", val<string>) || on(function<option<string> (const string&)>())) { struct line { string str; };
const char short_flag_arr[] = {'-', short_opt, '\0' };
const char* lhs_str = short_flag_arr; istream& operator>>(istream& is, line& l) {
string prefix = "--"; getline(is, l.str);
prefix += long_opt; return is;
prefix += "=";
function<option<string> (const string&)> kvp = [prefix](const string& input) -> option<string> {
if ( input.compare(0, prefix.size(), prefix) == 0
// accept '-key=' as well
|| input.compare(1, prefix.size(), prefix) == 0) {
return input.substr(prefix.size());
}
return {};
};
return on(lhs_str, val<string>) || on(kvp);
} }
auto on_void_opt(char short_opt, const char* long_opt) -> decltype(on<string>().when(cppa::placeholders::_x1.in(vector<string>()))) { any_tuple s_last_line;
const char short_flag_arr[] = {'-', short_opt, '\0' };
vector<string> opt_strs = { short_flag_arr }; any_tuple split_line(const line& l) {
opt_strs.push_back(string("-") + long_opt); vector<string> result;
string str = "-"; stringstream strs(l.str);
str += opt_strs.back(); string tmp;
opt_strs.push_back(std::move(str)); while (getline(strs, tmp, ' ')) {
return on<string>().when(cppa::placeholders::_x1.in(opt_strs)); if (!tmp.empty()) result.push_back(std::move(tmp));
}
s_last_line = any_tuple::view(std::move(result));
return s_last_line;
} }
class client : public event_based_actor { class client : public event_based_actor {
string m_username; public:
actor_ptr m_printer;
client(const string& name, actor_ptr printer)
: m_name(name), m_printer(printer) { }
protected:
void init() { void init() {
become ( become (
// local commands
on(atom("broadcast"), arg_match) >> [=](const string& message) { on(atom("broadcast"), arg_match) >> [=](const string& message) {
for(auto& dest : joined_groups()) { for(auto& dest : joined_groups()) {
send(dest, m_username + ": " + message); send(dest, m_name + ": " + message);
} }
}, },
on(atom("join"), arg_match) >> [=](const group_ptr& what) { on(atom("join"), arg_match) >> [=](const group_ptr& what) {
...@@ -62,6 +62,7 @@ class client : public event_based_actor { ...@@ -62,6 +62,7 @@ class client : public event_based_actor {
} }
}, },
on(atom("quit")) >> [=] { on(atom("quit")) >> [=] {
// ignore quit messages from remote actors
auto s = self->last_sender(); auto s = self->last_sender();
if (s->is_proxy()) { if (s->is_proxy()) {
reply("nice try"); reply("nice try");
...@@ -75,14 +76,16 @@ class client : public event_based_actor { ...@@ -75,14 +76,16 @@ class client : public event_based_actor {
if (last_sender() != this) forward_to(m_printer); if (last_sender() != this) forward_to(m_printer);
}, },
others() >> [=]() { others() >> [=]() {
send(m_printer, string("[!!!] unexpected message: '") + to_string(last_dequeued())); send(m_printer,
"*** unexpected message: '" + to_string(last_dequeued()));
} }
); );
} }
public: private:
client(const string& username, actor_ptr printer) : m_username(username), m_printer(printer) { } string m_name;
actor_ptr m_printer;
}; };
...@@ -93,141 +96,93 @@ class print_actor : public event_based_actor { ...@@ -93,141 +96,93 @@ class print_actor : public event_based_actor {
self->quit(); self->quit();
}, },
on_arg_match >> [](const string& str) { on_arg_match >> [](const string& str) {
cout << (str + "\n"); cout << str << endl;
} }
); );
} }
}; };
inline vector<std::string> split(const string& str, char delim) {
vector<std::string> result;
stringstream strs{str};
string tmp;
while (std::getline(strs, tmp, delim)) result.push_back(tmp);
return result;
}
template<typename Iterator>
inline std::string join(Iterator first, Iterator last, char delim) {
std::string result;
if (first != last) {
result += *first++;
for (; first != last; ++first) {
result += delim;
result += *first++;
}
}
return result;
}
inline std::string join(const vector<string>& vec, char delim) {
return join(begin(vec), end(vec), delim);
}
template<typename T>
auto conv(const string& str) -> option<T> {
T result;
if (istringstream(str) >> result) return result;
return {};
}
void print_usage(actor_ptr printer) {
send(printer, "Usage: group_chat --type=<server|client>\n --type, -t\t\tcan be: server, s, client, c\n --name, -n\t\tusername (only needed for client)\n --host, -h\t\thostname (only needed for client)\n --port, -p\t\tport for server/client");
}
std::function<option<string> (const string&)> get_extractor(const string& identifier) {
auto tmp = [&](const string& kvp) -> option<string> {
auto vec = split(kvp, '=');
if (vec.size() == 2) {
if (vec.front() == "--"+identifier) {
return vec.back();
}
}
return {};
};
return tmp;
}
auto main(int argc, char* argv[]) -> int { auto main(int argc, char* argv[]) -> int {
cout.unsetf(std::ios_base::unitbuf); // enables this client to print user-defined types
// without changing this source code
auto printer = spawn<print_actor>(); exec_plugin();
string name; string name;
vector<string> group_ids;
bool args_valid = match_stream<string>(argv + 1, argv + argc) ( options_description desc;
on_opt('n', "name") >> [&](const string& input) -> bool { bool args_valid = argc > 1 && match_stream<string>(argv + 1, argv + argc) (
if (!name.empty()) { on_opt('n', "name", &desc, "set name") >> rd_arg(name),
cout << "name already set to " << name << endl; on_opt('g', "group", &desc, "join group <arg>") >> add_arg(group_ids),
return false; on_vopt('h', "help", &desc, "print help") >> print_desc_and_exit(&desc)
}
name = input;
return true;
}
); );
if(!args_valid) { if(!args_valid) print_desc_and_exit(&desc)();
print_usage(printer);
send(printer, atom("quit")); auto printer = spawn<print_actor>();
await_all_others_done();
shutdown();
return 0;
}
while (name.empty()) { while (name.empty()) {
send(printer, "So what is your name for chatting?"); send(printer, "*** what is your name for chatting?");
if (!getline(cin, name)) return 1; if (!getline(cin, name)) return 1;
} }
send(printer, "Starting client."); send(printer, "*** starting client.");
auto client_actor = spawn<client>(name, printer); auto client_actor = spawn<client>(name, printer);
auto get_command = [&]() -> bool { // evaluate group parameters
string input; for (auto& gid : group_ids) {
bool done = false; auto p = gid.find(':');
getline(cin, input); if (p == std::string::npos) {
if (input.size() > 0) { cerr << "*** error parsing argument " << gid
if (input.front() == '/') { << ", expected format: <module_name>:<group_id>";
input.erase(input.begin()); }
vector<string> values = split(input, ' '); else {
match (values) ( try {
on("send", val<string>, any_vals) >> [&](const string& groupname) { auto g = group::get(gid.substr(0, p),
if (values.size() < 3) { gid.substr(p + 1));
send(printer, "no message to send"); send(client_actor, atom("join"), g);
}
else {
send(client_actor, atom("send"), groupname, join(begin(values) + 2, end(values), ' '));
}
},
on("join", arg_match) >> [&](const string& mod, const string& id) {
group_ptr g;
try {
g = group::get(mod, id);
send(client_actor, atom("join"), g);
}
catch (exception& e) {
send(printer, string("exception: ") + e.what());
}
},
on("quit") >> [&] {
done = true;
},
others() >> [&] {
send(printer, "available commands:\n /connect HOST PORT\n /join GROUPNAME\n /join hamcast URI\n /send GROUPNAME MESSAGE\n /quit");
}
);
} }
else { catch (exception& e) {
send(client_actor, atom("broadcast"), input); ostringstream err;
err << "*** exception: group::get(\"" << gid.substr(0, p)
<< "\", \"" << gid.substr(p + 1) << "\") failed, what = "
<< e.what() << endl;
send(printer, err.str());
} }
} }
return !done; }
};
while (get_command()) { }
send(client_actor, atom("quit"));
istream_iterator<line> lines(cin);
istream_iterator<line> eof;
match_each(lines, eof, split_line) (
on("/join", arg_match) >> [&](const string& mod, const string& id) {
try {
send(client_actor, atom("join"), group::get(mod, id));
}
catch (exception& e) {
send(printer, string("*** exception: ") + e.what());
}
},
on("/quit") >> [&] {
close(0); // close STDIN
},
on<string, anything>().when(_x1.starts_with("/")) >> [&] {
send(printer, "*** available commands:\n "
"/join MODULE GROUP\n "
"/quit");
},
others() >> [&] {
if (s_last_line.size() > 0) {
string msg = s_last_line.get_as<string>(0);
for (size_t i = 1; i < s_last_line.size(); ++i) {
msg += " ";
msg += s_last_line.get_as<string>(i);
}
send(client_actor, atom("broadcast"), msg);
}
}
);
send(client_actor, atom("quit"));
send(printer, atom("quit")); send(printer, atom("quit"));
await_all_others_done(); await_all_others_done();
shutdown(); shutdown();
......
#include <string> #include <string>
#include <dlfcn.h>
#include <sstream> #include <sstream>
#include <iostream> #include <iostream>
#include "cppa/opt.hpp"
#include "cppa/cppa.hpp" #include "cppa/cppa.hpp"
#include "type_plugins.hpp"
using namespace std; using namespace std;
using namespace cppa; using namespace cppa;
auto on_opt(char short_opt, const char* long_opt) -> decltype(on("", val<string>) || on(function<option<string> (const string&)>())) {
const char short_flag_arr[] = {'-', short_opt, '\0' };
const char* lhs_str = short_flag_arr;
string prefix = "--";
prefix += long_opt;
prefix += "=";
function<option<string> (const string&)> kvp = [prefix](const string& input) -> option<string> {
if ( input.compare(0, prefix.size(), prefix) == 0
// accept '-key=' as well
|| input.compare(1, prefix.size(), prefix) == 0) {
return input.substr(prefix.size());
}
return {};
};
return on(lhs_str, val<string>) || on(kvp);
}
auto on_void_opt(char short_opt, const char* long_opt) -> decltype(on<string>().when(cppa::placeholders::_x1.in(vector<string>()))) {
const char short_flag_arr[] = {'-', short_opt, '\0' };
vector<string> opt_strs = { short_flag_arr };
opt_strs.push_back(string("-") + long_opt);
string str = "-";
str += opt_strs.back();
opt_strs.push_back(std::move(str));
return on<string>().when(cppa::placeholders::_x1.in(opt_strs));
}
int main(int argc, char** argv) { int main(int argc, char** argv) {
uint16_t port; // enables this server to be used with user-defined types
// without changing this source code
exec_plugin();
uint16_t port = 0;
options_description desc;
bool args_valid = argc > 1 && match_stream<string>(argv + 1, argv + argc) ( bool args_valid = argc > 1 && match_stream<string>(argv + 1, argv + argc) (
on_opt('p', "port") >> [&](const string& arg) -> bool { on_opt('p', "port", &desc, "set port") >> rd_arg(port),
if (!(istringstream(arg) >> port)) { on_vopt('h', "help", &desc, "print help") >> print_desc_and_exit(&desc)
cout << "\"" << arg << "\" is not a valid port" << endl;
return false;
}
return true;
}
); );
if (port <= 1024) { if (port <= 1024) {
cout << "no port > 1024 given" << endl; cout << "no port > 1024 given" << endl;
...@@ -54,9 +30,8 @@ int main(int argc, char** argv) { ...@@ -54,9 +30,8 @@ int main(int argc, char** argv) {
string line; string line;
while (getline(cin, line)) { while (getline(cin, line)) {
if (line == "quit") return 0; if (line == "quit") return 0;
else { else cout << "illegal command" << endl;
cout << "illegal command" << endl;
}
} }
shutdown();
return 0; return 0;
} }
#ifndef TYPE_PLUGINS_HPP
#define TYPE_PLUGINS_HPP
#include <dlfcn.h>
#include <iostream>
#include "cppa/cppa.hpp"
inline void exec_plugin() {
using namespace std;
using namespace cppa;
// user-defined types can be announced by a plugin
void* handle = dlopen("plugin.dylib", RTLD_NOW); // macos
if (!handle) handle = dlopen("plugin.so", RTLD_NOW); // linux
if (handle) {
auto before = uniform_type_info::instances();
cout << "found a plugin, call exec_plugin()" << endl;
auto fun = (void (*)()) dlsym(handle, "exec_plugin");
if (fun) {
fun();
cout << "the plugin announced the following types:" << endl;
for (auto inf : uniform_type_info::instances()) {
if (count(begin(before), end(before), inf) == 0) {
cout << inf->name() << endl;
}
}
}
}
}
#endif // TYPE_PLUGINS_HPP
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011, 2012 *
* 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 3 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::detail::addressed_message", "@msg" },
{ "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::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
...@@ -107,10 +107,10 @@ struct group_nameserver : event_based_actor { ...@@ -107,10 +107,10 @@ struct group_nameserver : event_based_actor {
} }
}; };
void publish_local_groups_at(std::uint16_t port) { void publish_local_groups_at(std::uint16_t port, const char* addr) {
auto gn = spawn_hidden<group_nameserver>(); auto gn = spawn_hidden<group_nameserver>();
try { try {
publish(gn, port); publish(gn, port, addr);
} }
catch (std::exception&) { catch (std::exception&) {
gn->enqueue(nullptr, make_any_tuple(atom("SHUTDOWN"))); gn->enqueue(nullptr, make_any_tuple(atom("SHUTDOWN")));
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#else #else
# include <netdb.h> # include <netdb.h>
# include <unistd.h> # include <unistd.h>
# include <arpa/inet.h>
# include <sys/types.h> # include <sys/types.h>
# include <sys/socket.h> # include <sys/socket.h>
# include <netinet/in.h> # include <netinet/in.h>
...@@ -97,7 +98,8 @@ bool accept_impl(util::io_stream_ptr_pair& result, native_socket_type fd, bool n ...@@ -97,7 +98,8 @@ bool accept_impl(util::io_stream_ptr_pair& result, native_socket_type fd, bool n
ipv4_acceptor::ipv4_acceptor(native_socket_type fd, bool nonblocking) ipv4_acceptor::ipv4_acceptor(native_socket_type fd, bool nonblocking)
: m_fd(fd), m_is_nonblocking(nonblocking) { } : m_fd(fd), m_is_nonblocking(nonblocking) { }
std::unique_ptr<util::acceptor> ipv4_acceptor::create(std::uint16_t port) { std::unique_ptr<util::acceptor> ipv4_acceptor::create(std::uint16_t port,
const char* addr) {
native_socket_type sockfd; native_socket_type sockfd;
sockfd = socket(AF_INET, SOCK_STREAM, 0); sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == invalid_socket) { if (sockfd == invalid_socket) {
...@@ -112,7 +114,13 @@ std::unique_ptr<util::acceptor> ipv4_acceptor::create(std::uint16_t port) { ...@@ -112,7 +114,13 @@ std::unique_ptr<util::acceptor> ipv4_acceptor::create(std::uint16_t port) {
struct sockaddr_in serv_addr; struct sockaddr_in serv_addr;
memset((char*) &serv_addr, 0, sizeof(serv_addr)); memset((char*) &serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET; serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY; if (! addr) {
serv_addr.sin_addr.s_addr = INADDR_ANY;
}
else if (inet_pton(AF_INET, addr, &serv_addr.sin_addr) <= 0) {
throw network_error("invalid IPv4 address");
}
serv_addr.sin_port = htons(port); serv_addr.sin_port = htons(port);
if (bind(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0) { if (bind(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0) {
throw bind_failure(errno); throw bind_failure(errno);
......
...@@ -58,6 +58,9 @@ ...@@ -58,6 +58,9 @@
using namespace std; using namespace std;
//#define VERBOSE_MIDDLEMAN
#ifdef VERBOSE_MIDDLEMAN
#define DEBUG(arg) { \ #define DEBUG(arg) { \
ostringstream oss; \ ostringstream oss; \
oss << "[process id: " \ oss << "[process id: " \
...@@ -65,9 +68,9 @@ using namespace std; ...@@ -65,9 +68,9 @@ using namespace std;
<< "] " << arg << endl; \ << "] " << arg << endl; \
cout << oss.str(); \ cout << oss.str(); \
} (void) 0 } (void) 0
#else
#undef DEBUG
#define DEBUG(unused) ((void) 0) #define DEBUG(unused) ((void) 0)
#endif
namespace cppa { namespace detail { namespace cppa { namespace detail {
...@@ -235,13 +238,15 @@ class peer_connection : public network_channel { ...@@ -235,13 +238,15 @@ class peer_connection : public network_channel {
bool continue_reading(); bool continue_reading();
bool continue_writing() { bool continue_writing() {
DEBUG("peer_connection::continue_writing"); DEBUG("peer_connection::continue_writing, try to write "
<< m_wr_buf.size() << " bytes");
if (has_unwritten_data()) { if (has_unwritten_data()) {
size_t written; size_t written;
written = m_ostream->write_some(m_wr_buf.data(), written = m_ostream->write_some(m_wr_buf.data(),
m_wr_buf.size()); m_wr_buf.size());
if (written != m_wr_buf.size()) { if (written != m_wr_buf.size()) {
m_wr_buf.erase_leading(written); m_wr_buf.erase_leading(written);
DEBUG("only " << written << " bytes written");
} }
else { else {
m_wr_buf.reset(); m_wr_buf.reset();
...@@ -257,17 +262,20 @@ class peer_connection : public network_channel { ...@@ -257,17 +262,20 @@ class peer_connection : public network_channel {
auto before = m_wr_buf.size(); auto before = m_wr_buf.size();
m_wr_buf.write(sizeof(std::uint32_t), &size, util::grow_if_needed); m_wr_buf.write(sizeof(std::uint32_t), &size, util::grow_if_needed);
bs << msg; bs << msg;
size = m_wr_buf.size() - sizeof(std::uint32_t); size = (m_wr_buf.size() - before) - sizeof(std::uint32_t);
// update size in buffer // update size in buffer
memcpy(m_wr_buf.data() + before, &size, sizeof(std::uint32_t)); memcpy(m_wr_buf.data() + before, &size, sizeof(std::uint32_t));
if (!has_unwritten_data()) { if (!has_unwritten_data()) {
size_t written = m_ostream->write_some(m_wr_buf.data(), size_t written = m_ostream->write_some(m_wr_buf.data(),
m_wr_buf.size()); m_wr_buf.size());
if (written != m_wr_buf.size()) { if (written != m_wr_buf.size()) {
DEBUG("tried to write " << m_wr_buf.size()
<< " bytes, only " << written << " bytes written");
m_wr_buf.erase_leading(written); m_wr_buf.erase_leading(written);
has_unwritten_data(true); has_unwritten_data(true);
} }
else { else {
DEBUG(written << " bytes written");
m_wr_buf.reset(); m_wr_buf.reset();
} }
} }
...@@ -398,6 +406,16 @@ bool peer_connection::continue_reading() { ...@@ -398,6 +406,16 @@ bool peer_connection::continue_reading() {
memcpy(node_id.data(), m_rd_buf.data() + sizeof(uint32_t), memcpy(node_id.data(), m_rd_buf.data() + sizeof(uint32_t),
process_information::node_id_size); process_information::node_id_size);
m_peer.reset(new process_information(process_id, node_id)); m_peer.reset(new process_information(process_id, node_id));
if (*(parent()->pself()) == *m_peer) {
# ifdef VERBOSE_MIDDLEMAN
DEBUG("incoming connection from self");
# elif defined(CPPA_DEBUG)
std::cerr << "*** middleman warning: "
"incoming connection from self"
<< std::endl;
# endif
throw std::ios_base::failure("refused connection from self");
}
parent()->add_peer(*m_peer, this); parent()->add_peer(*m_peer, this);
// initialization done // initialization done
m_rd_state = wait_for_msg_size; m_rd_state = wait_for_msg_size;
...@@ -698,6 +716,17 @@ void middleman::operator()(int pipe_fd, middleman_queue& queue) { ...@@ -698,6 +716,17 @@ void middleman::operator()(int pipe_fd, middleman_queue& queue) {
maxfd = max(maxfd, fd); maxfd = max(maxfd, fd);
FD_SET(fd, &rdset); FD_SET(fd, &rdset);
} }
// check consistency of m_peers_with_unwritten_data
if (!m_peers_with_unwritten_data.empty()) {
auto i = m_peers_with_unwritten_data.begin();
auto e = m_peers_with_unwritten_data.end();
while (i != e) {
if ((*i)->has_unwritten_data() == false) {
i = m_peers_with_unwritten_data.erase(i);
}
else ++i;
}
}
if (m_peers_with_unwritten_data.empty()) { if (m_peers_with_unwritten_data.empty()) {
if (wrset_ptr) wrset_ptr = nullptr; if (wrset_ptr) wrset_ptr = nullptr;
} }
...@@ -714,8 +743,17 @@ void middleman::operator()(int pipe_fd, middleman_queue& queue) { ...@@ -714,8 +743,17 @@ void middleman::operator()(int pipe_fd, middleman_queue& queue) {
auto continue_reading = [&](const network_channel_ptr& ch) { auto continue_reading = [&](const network_channel_ptr& ch) {
bool erase_channel = false; bool erase_channel = false;
try { erase_channel = !ch->continue_reading(); } try { erase_channel = !ch->continue_reading(); }
catch (ios_base::failure& e) {
DEBUG(demangle(typeid(e)) << ": " << e.what());
erase_channel = true;
}
catch (runtime_error& e) {
// thrown whenever serialize/deserialize fails
cerr << "*** runtime_error in middleman: " << e.what() << endl;
erase_channel = true;
}
catch (exception& e) { catch (exception& e) {
DEBUG(demangle(typeid(e).name()) << ": " << e.what()); DEBUG(demangle(typeid(e)) << ": " << e.what());
erase_channel = true; erase_channel = true;
} }
if (erase_channel) { if (erase_channel) {
...@@ -725,7 +763,9 @@ void middleman::operator()(int pipe_fd, middleman_queue& queue) { ...@@ -725,7 +763,9 @@ void middleman::operator()(int pipe_fd, middleman_queue& queue) {
}; };
auto continue_writing = [&](const peer_connection_ptr& peer) { auto continue_writing = [&](const peer_connection_ptr& peer) {
bool erase_channel = false; bool erase_channel = false;
try { erase_channel = !peer->continue_writing(); } try {
erase_channel = !peer->continue_writing();
}
catch (exception& e) { catch (exception& e) {
DEBUG(demangle(typeid(e).name()) << ": " << e.what()); DEBUG(demangle(typeid(e).name()) << ": " << e.what());
erase_channel = true; erase_channel = true;
......
...@@ -100,6 +100,14 @@ void tss_reset(local_actor* ptr, bool inc_ref_count = true) { ...@@ -100,6 +100,14 @@ void tss_reset(local_actor* ptr, bool inc_ref_count = true) {
} // namespace <anonymous> } // namespace <anonymous>
bool operator==(const actor_ptr& lhs, const self_type& rhs) {
return lhs.get() == rhs.get();
}
bool operator!=(const self_type& lhs, const actor_ptr& rhs) {
return lhs.get() != rhs.get();
}
void self_type::cleanup_fun(cppa::local_actor* what) { void self_type::cleanup_fun(cppa::local_actor* what) {
if (what) { if (what) {
auto ptr = dynamic_cast<thread_mapped_actor*>(what); auto ptr = dynamic_cast<thread_mapped_actor*>(what);
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#include "cppa/detail/actor_registry.hpp" #include "cppa/detail/actor_registry.hpp"
#include "cppa/detail/network_manager.hpp" #include "cppa/detail/network_manager.hpp"
#include "cppa/detail/singleton_manager.hpp" #include "cppa/detail/singleton_manager.hpp"
#include "cppa/detail/decorated_names_map.hpp"
#include "cppa/detail/thread_pool_scheduler.hpp" #include "cppa/detail/thread_pool_scheduler.hpp"
#include "cppa/detail/uniform_type_info_map.hpp" #include "cppa/detail/uniform_type_info_map.hpp"
...@@ -57,6 +58,7 @@ using namespace cppa::detail; ...@@ -57,6 +58,7 @@ using namespace cppa::detail;
//volatile uniform_type_info_map* s_uniform_type_info_map = 0; //volatile uniform_type_info_map* s_uniform_type_info_map = 0;
std::atomic<uniform_type_info_map*> s_uniform_type_info_map; std::atomic<uniform_type_info_map*> s_uniform_type_info_map;
std::atomic<decorated_names_map*> s_decorated_names_map;
std::atomic<network_manager*> s_network_manager; std::atomic<network_manager*> s_network_manager;
std::atomic<actor_registry*> s_actor_registry; std::atomic<actor_registry*> s_actor_registry;
std::atomic<group_manager*> s_group_manager; std::atomic<group_manager*> s_group_manager;
...@@ -121,6 +123,8 @@ void shutdown() { ...@@ -121,6 +123,8 @@ void shutdown() {
s_empty_tuple = nullptr; s_empty_tuple = nullptr;
delete s_uniform_type_info_map.load(); delete s_uniform_type_info_map.load();
s_uniform_type_info_map = nullptr; s_uniform_type_info_map = nullptr;
delete s_decorated_names_map.load();
s_decorated_names_map = nullptr;
} }
} // namespace cppa } // namespace cppa
...@@ -143,6 +147,10 @@ scheduler* singleton_manager::get_scheduler() { ...@@ -143,6 +147,10 @@ scheduler* singleton_manager::get_scheduler() {
return s_scheduler.load(); return s_scheduler.load();
} }
decorated_names_map* singleton_manager::get_decorated_names_map() {
return lazy_get(s_decorated_names_map);
}
bool singleton_manager::set_scheduler(scheduler* ptr) { bool singleton_manager::set_scheduler(scheduler* ptr) {
scheduler* expected = nullptr; scheduler* expected = nullptr;
if (s_scheduler.compare_exchange_weak(expected, ptr)) { if (s_scheduler.compare_exchange_weak(expected, ptr)) {
......
...@@ -29,7 +29,9 @@ ...@@ -29,7 +29,9 @@
#include <stack> #include <stack>
#include <cctype>
#include <sstream> #include <sstream>
#include <iomanip>
#include <algorithm> #include <algorithm>
#include "cppa/atom.hpp" #include "cppa/atom.hpp"
...@@ -41,26 +43,28 @@ ...@@ -41,26 +43,28 @@
#include "cppa/primitive_variant.hpp" #include "cppa/primitive_variant.hpp"
#include "cppa/uniform_type_info.hpp" #include "cppa/uniform_type_info.hpp"
using namespace std;
namespace cppa { namespace cppa {
namespace { namespace {
class string_serializer : public serializer { class string_serializer : public serializer {
std::ostream& out; ostream& out;
struct pt_writer { struct pt_writer {
std::ostream& out; ostream& out;
pt_writer(std::ostream& mout) : out(mout) { } pt_writer(ostream& mout) : out(mout) { }
template<typename T> template<typename T>
void operator()(const T& value) { void operator()(const T& value) {
out << value; out << value;
} }
void operator()(const std::string& str) { void operator()(const string& str) {
out << "\"";// << str << "\""; out << "\"";// << str << "\"";
for (char c : str) { for (char c : str) {
if (c == '"') out << "\\\""; if (c == '"') out << "\\\"";
...@@ -69,15 +73,15 @@ class string_serializer : public serializer { ...@@ -69,15 +73,15 @@ class string_serializer : public serializer {
out << '"'; out << '"';
} }
void operator()(const std::u16string&) { } void operator()(const u16string&) { }
void operator()(const std::u32string&) { } void operator()(const u32string&) { }
}; };
bool m_after_value; bool m_after_value;
bool m_obj_just_opened; bool m_obj_just_opened;
std::stack<std::string> m_open_objects; stack<string> m_open_objects;
inline void clear() { inline void clear() {
if (m_after_value) { if (m_after_value) {
...@@ -92,11 +96,11 @@ class string_serializer : public serializer { ...@@ -92,11 +96,11 @@ class string_serializer : public serializer {
public: public:
string_serializer(std::ostream& mout) string_serializer(ostream& mout)
: out(mout), m_after_value(false), m_obj_just_opened(false) { : out(mout), m_after_value(false), m_obj_just_opened(false) {
} }
void begin_object(const std::string& type_name) { void begin_object(const string& type_name) {
clear(); clear();
m_open_objects.push(type_name); m_open_objects.push(type_name);
out << type_name;// << " ( "; out << type_name;// << " ( ";
...@@ -129,14 +133,14 @@ class string_serializer : public serializer { ...@@ -129,14 +133,14 @@ class string_serializer : public serializer {
void write_value(const primitive_variant& value) { void write_value(const primitive_variant& value) {
clear(); clear();
if (m_open_objects.empty()) { if (m_open_objects.empty()) {
throw std::runtime_error("write_value(): m_open_objects.empty()"); throw runtime_error("write_value(): m_open_objects.empty()");
} }
if (m_open_objects.top() == "@atom") { if (m_open_objects.top() == "@atom") {
if (value.ptype() != pt_uint64) { if (value.ptype() != pt_uint64) {
throw std::runtime_error("expected uint64 value after @atom"); throw runtime_error("expected uint64 value after @atom");
} }
// write atoms as strings instead of integer values // write atoms as strings instead of integer values
auto av = static_cast<atom_value>(get<std::uint64_t>(value)); auto av = static_cast<atom_value>(get<uint64_t>(value));
(pt_writer(out))(to_string(av)); (pt_writer(out))(to_string(av));
} }
else { else {
...@@ -155,33 +159,41 @@ class string_serializer : public serializer { ...@@ -155,33 +159,41 @@ class string_serializer : public serializer {
out << (m_after_value ? " }" : "}"); out << (m_after_value ? " }" : "}");
} }
void write_raw(size_t, const void*) { void write_raw(size_t num_bytes, const void* buf) {
throw std::runtime_error("string_serializer::write_raw: " clear();
"not implemented yet"); auto first = reinterpret_cast<const unsigned char*>(buf);
auto last = first + num_bytes;
out << hex;
out << setfill('0');
for (; first != last; ++first) {
out << setw(2) << static_cast<size_t>(*first);
}
out << dec;
m_after_value = true;
} }
}; };
class string_deserializer : public deserializer { class string_deserializer : public deserializer {
std::string m_str; string m_str;
std::string::iterator m_pos; string::iterator m_pos;
//size_t m_obj_count; //size_t m_obj_count;
std::stack<bool> m_obj_had_left_parenthesis; stack<bool> m_obj_had_left_parenthesis;
std::stack<std::string> m_open_objects; stack<string> m_open_objects;
void skip_space_and_comma() { void skip_space_and_comma() {
while (*m_pos == ' ' || *m_pos == ',') ++m_pos; while (*m_pos == ' ' || *m_pos == ',') ++m_pos;
} }
void throw_malformed(const std::string& error_msg) { void throw_malformed(const string& error_msg) {
throw std::logic_error("malformed string: " + error_msg); throw logic_error("malformed string: " + error_msg);
} }
void consume(char c) { void consume(char c) {
skip_space_and_comma(); skip_space_and_comma();
if (*m_pos != c) { if (*m_pos != c) {
std::string error; string error;
error += "expected '"; error += "expected '";
error += c; error += c;
error += "' found '"; error += "' found '";
...@@ -205,8 +217,8 @@ class string_deserializer : public deserializer { ...@@ -205,8 +217,8 @@ class string_deserializer : public deserializer {
return false; return false;
} }
inline std::string::iterator next_delimiter() { inline string::iterator next_delimiter() {
return std::find_if(m_pos, m_str.end(), [] (char c) -> bool { return find_if(m_pos, m_str.end(), [] (char c) -> bool {
switch (c) { switch (c) {
case '(': case '(':
case ')': case ')':
...@@ -235,33 +247,33 @@ class string_deserializer : public deserializer { ...@@ -235,33 +247,33 @@ class string_deserializer : public deserializer {
public: public:
string_deserializer(const std::string& str) : m_str(str) { string_deserializer(const string& str) : m_str(str) {
m_pos = m_str.begin(); m_pos = m_str.begin();
} }
string_deserializer(std::string&& str) : m_str(std::move(str)) { string_deserializer(string&& str) : m_str(move(str)) {
m_pos = m_str.begin(); m_pos = m_str.begin();
} }
std::string seek_object() { string seek_object() {
skip_space_and_comma(); skip_space_and_comma();
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");
} }
std::string result(m_pos, substr_end); string result(m_pos, substr_end);
m_pos = substr_end; m_pos = substr_end;
return result; return result;
} }
std::string peek_object() { string peek_object() {
std::string result = seek_object(); string result = seek_object();
// restore position in stream // restore position in stream
m_pos -= result.size(); m_pos -= result.size();
return result; return result;
} }
void begin_object(const std::string& type_name) { 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();
...@@ -280,7 +292,7 @@ class string_deserializer : public deserializer { ...@@ -280,7 +292,7 @@ class string_deserializer : public deserializer {
m_obj_had_left_parenthesis.pop(); m_obj_had_left_parenthesis.pop();
} }
if (m_open_objects.empty()) { if (m_open_objects.empty()) {
throw std::runtime_error("no object to end"); throw runtime_error("no object to end");
} }
m_open_objects.pop(); m_open_objects.pop();
if (m_open_objects.empty()) { if (m_open_objects.empty()) {
...@@ -294,7 +306,7 @@ class string_deserializer : public deserializer { ...@@ -294,7 +306,7 @@ class string_deserializer : public deserializer {
size_t begin_sequence() { size_t begin_sequence() {
integrity_check(); integrity_check();
consume('{'); consume('{');
return std::count(m_pos, std::find(m_pos, m_str.end(), '}'), ',') + 1; return count(m_pos, find(m_pos, m_str.end(), '}'), ',') + 1;
} }
void end_sequence() { void end_sequence() {
...@@ -303,18 +315,18 @@ class string_deserializer : public deserializer { ...@@ -303,18 +315,18 @@ class string_deserializer : public deserializer {
} }
struct from_string { struct from_string {
const std::string& str; const string& str;
from_string(const std::string& s) : str(s) { } from_string(const string& s) : str(s) { }
template<typename T> template<typename T>
void operator()(T& what) { void operator()(T& what) {
std::istringstream s(str); istringstream s(str);
s >> what; s >> what;
} }
void operator()(std::string& what) { void operator()(string& what) {
what = str; what = str;
} }
void operator()(std::u16string&) { } void operator()(u16string&) { }
void operator()(std::u32string&) { } void operator()(u32string&) { }
}; };
primitive_variant read_value(primitive_type ptype) { primitive_variant read_value(primitive_type ptype) {
...@@ -323,14 +335,14 @@ class string_deserializer : public deserializer { ...@@ -323,14 +335,14 @@ class string_deserializer : public deserializer {
if (ptype != pt_uint64) { if (ptype != pt_uint64) {
throw_malformed("expected read of pt_uint64 after @atom"); throw_malformed("expected read of pt_uint64 after @atom");
} }
auto str_val = get<std::string>(read_value(pt_u8string)); auto str_val = get<string>(read_value(pt_u8string));
if (str_val.size() > 10) { if (str_val.size() > 10) {
throw_malformed("atom string size > 10"); throw_malformed("atom string size > 10");
} }
return detail::atom_val(str_val.c_str()); return detail::atom_val(str_val.c_str());
} }
skip_space_and_comma(); skip_space_and_comma();
std::string::iterator substr_end; string::iterator substr_end;
auto find_if_cond = [] (char c) -> bool { auto find_if_cond = [] (char c) -> bool {
switch (c) { switch (c) {
case ')': case ')':
...@@ -352,28 +364,28 @@ class string_deserializer : public deserializer { ...@@ -352,28 +364,28 @@ class string_deserializer : public deserializer {
last_char = c; last_char = c;
return false; return false;
}; };
substr_end = std::find_if(m_pos, m_str.end(), find_if_str_cond); substr_end = find_if(m_pos, m_str.end(), find_if_str_cond);
} }
else { else {
substr_end = std::find_if(m_pos, m_str.end(), find_if_cond); substr_end = find_if(m_pos, m_str.end(), find_if_cond);
} }
} }
else { else {
substr_end = std::find_if(m_pos, m_str.end(), find_if_cond); substr_end = find_if(m_pos, m_str.end(), find_if_cond);
} }
if (substr_end == m_str.end()) { if (substr_end == m_str.end()) {
throw std::logic_error("malformed string (unterminated value)"); throw logic_error("malformed string (unterminated value)");
} }
std::string substr(m_pos, substr_end); string substr(m_pos, substr_end);
m_pos += substr.size(); m_pos += substr.size();
if (ptype == pt_u8string) { if (ptype == pt_u8string) {
// skip trailing " // skip trailing "
if (*m_pos != '"') { if (*m_pos != '"') {
std::string error_msg; string error_msg;
error_msg = "malformed string, expected '\"' found '"; error_msg = "malformed string, expected '\"' found '";
error_msg += *m_pos; error_msg += *m_pos;
error_msg += "'"; error_msg += "'";
throw std::logic_error(error_msg); throw logic_error(error_msg);
} }
++m_pos; ++m_pos;
// replace '\"' by '"' // replace '\"' by '"'
...@@ -385,12 +397,12 @@ class string_deserializer : public deserializer { ...@@ -385,12 +397,12 @@ class string_deserializer : public deserializer {
last_char = c; last_char = c;
return false; return false;
}; };
std::string tmp; string tmp;
auto sbegin = substr.begin(); auto sbegin = substr.begin();
auto send = substr.end(); auto send = substr.end();
for (auto i = std::find_if(sbegin, send, cond); for (auto i = find_if(sbegin, send, cond);
i != send; i != send;
i = std::find_if(i, send, cond)) { i = find_if(i, send, cond)) {
--i; --i;
tmp.append(sbegin, i); tmp.append(sbegin, i);
tmp += '"'; tmp += '"';
...@@ -401,7 +413,7 @@ class string_deserializer : public deserializer { ...@@ -401,7 +413,7 @@ class string_deserializer : public deserializer {
tmp.append(sbegin, send); tmp.append(sbegin, send);
} }
if (!tmp.empty()) { if (!tmp.empty()) {
substr = std::move(tmp); substr = move(tmp);
} }
} }
primitive_variant result(ptype); primitive_variant result(ptype);
...@@ -416,35 +428,50 @@ class string_deserializer : public deserializer { ...@@ -416,35 +428,50 @@ class string_deserializer : public deserializer {
consume('{'); consume('{');
const primitive_type* end = begin + size; const primitive_type* end = begin + size;
for ( ; begin != end; ++begin) { for ( ; begin != end; ++begin) {
*storage = std::move(read_value(*begin)); *storage = move(read_value(*begin));
++storage; ++storage;
} }
consume('}'); consume('}');
} }
void read_raw(size_t, void*) { void read_raw(size_t buf_size, void* vbuf) {
throw std::runtime_error("string_deserializer::read_raw: " auto buf = reinterpret_cast<unsigned char*>(vbuf);
"not implemented yet"); integrity_check();
skip_space_and_comma();
auto next_nibble = [&]() -> size_t {
if (*m_pos == '\0') {
throw_malformed("unexpected end-of-string");
}
char c = *m_pos++;
if (!isxdigit(c)) {
throw_malformed("unexpected character, expected [0-9a-f]");
}
return static_cast<size_t>(isdigit(c) ? c - '0' : (c - 'a' + 10));
};
for (size_t i = 0; i < buf_size; ++i) {
auto nibble = next_nibble();
*buf++ = static_cast<unsigned char>((nibble << 4) | next_nibble());
}
} }
}; };
} // namespace <anonymous> } // namespace <anonymous>
object from_string(const std::string& what) { object from_string(const string& what) {
string_deserializer strd(what); string_deserializer strd(what);
std::string uname = strd.peek_object(); string uname = strd.peek_object();
auto utype = uniform_type_info::from(uname); auto utype = uniform_type_info::from(uname);
if (utype == nullptr) { if (utype == nullptr) {
throw std::logic_error(uname + " is not announced"); throw logic_error(uname + " is not announced");
} }
return utype->deserialize(&strd); return utype->deserialize(&strd);
} }
namespace detail { namespace detail {
std::string to_string_impl(const void *what, const uniform_type_info *utype) { string to_string_impl(const void *what, const uniform_type_info *utype) {
std::ostringstream osstr; ostringstream osstr;
string_serializer strs(osstr); string_serializer strs(osstr);
utype->serialize(what, &strs); utype->serialize(what, &strs);
return osstr.str(); return osstr.str();
......
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
namespace cppa { namespace cppa {
thread_mapped_actor::thread_mapped_actor() : m_initialized(false) { } thread_mapped_actor::thread_mapped_actor() : m_initialized(true) { }
thread_mapped_actor::thread_mapped_actor(std::function<void()> fun) thread_mapped_actor::thread_mapped_actor(std::function<void()> fun)
: super(std::move(fun)), m_initialized(false) { } : super(std::move(fun)), m_initialized(false) { }
......
...@@ -48,6 +48,8 @@ ...@@ -48,6 +48,8 @@
#include "cppa/detail/demangle.hpp" #include "cppa/detail/demangle.hpp"
#include "cppa/detail/to_uniform_name.hpp" #include "cppa/detail/to_uniform_name.hpp"
#include "cppa/detail/addressed_message.hpp" #include "cppa/detail/addressed_message.hpp"
#include "cppa/detail/singleton_manager.hpp"
#include "cppa/detail/decorated_names_map.hpp"
namespace { namespace {
...@@ -55,171 +57,157 @@ using namespace std; ...@@ -55,171 +57,157 @@ using namespace std;
using namespace cppa; using namespace cppa;
using namespace detail; using namespace 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> class parse_tree {
inline string demangled() {
return demangle(typeid(T));
}
template<typename T> public:
constexpr const char* mapped_int_name() {
return mapped_int_names[sizeof(T)][sign_index<T>()];
}
template<typename Iterator> string compile() const {
string to_uniform_name_impl(Iterator begin, Iterator end, string result;
bool first_run = false) { if (m_volatile) result += "volatile ";
// all integer type names as uniform representation if (m_const) result += "const ";
static map<string, string> mapped_demangled_names = { if (!m_template) {
// integer types result += dmm->decorate(m_name);
{ 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>() },
// string types
{ demangled<string>(), "@str" },
{ demangled<u16string>(), "@u16str" },
{ demangled<u32string>(), "@u32str" },
// cppa types
{ demangled<atom_value>(), "@atom" },
{ demangled<util::void_type>(), "@0" },
{ demangled<any_tuple>(), "@<>" },
{ demangled<actor_ptr>(), "@actor" },
{ demangled<group_ptr>(), "@group" },
{ demangled<channel_ptr>(), "@channel" },
{ demangled<addressed_message>(), "@msg" },
{ demangled< intrusive_ptr<process_information> >(), "@process_info" }
};
// check if we could find the whole string in our lookup map
if (first_run) {
string tmp(begin, end);
auto i = mapped_demangled_names.find(tmp);
if (i != mapped_demangled_names.end()) {
return i->second;
} }
else {
string full_name = m_name;
full_name += "<";
for (auto& tparam : m_template_parameters) {
// decorate each single template parameter
if (full_name.back() != '<') full_name += ",";
full_name += tparam.compile();
}
full_name += ">";
// decorate full name
result += dmm->decorate(full_name);
}
if (m_pointer) result += "*";
if (m_lvalue_ref) result += "&";
if (m_rvalue_ref) result += "&&";
return result;
} }
// does [begin, end) represents an empty string? template<typename Iterator>
if (begin == end) return ""; static vector<parse_tree> parse_tpl_args(Iterator first, Iterator last);
// derived reverse_iterator type
typedef reverse_iterator<Iterator> reverse_iterator;
// a subsequence [begin', end') within [begin, end)
typedef pair<Iterator, Iterator> subseq;
vector<subseq> substrings;
// explode string if we got a list of types
int open_brackets = 0; // counts "open" '<'
// denotes the begin of a possible subsequence
Iterator anchor = begin;
for (Iterator i = begin; i != end; /* i is incemented in the loop */) {
switch (*i) {
case '<': template<typename Iterator>
++open_brackets; static parse_tree parse(Iterator first, Iterator last) {
++i; typedef reverse_iterator<Iterator> rev_iter;
break; auto sub_first = find(first, last, '<');
auto sub_last = find(rev_iter(last), rev_iter(first), '>').base() - 1;
case '>': if (sub_last < sub_first) {
if (--open_brackets < 0) { sub_first = sub_last = last;
throw runtime_error("malformed string"); }
} auto islegal = [](char c) { return isalnum(c) || c == ':' || c == '_'; };
++i; vector<string> tokens;
break; tokens.push_back("");
for (auto i = first; i != last;) {
case ',': if (i == sub_first) {
if (open_brackets == 0) { tokens.push_back("");
substrings.push_back(make_pair(anchor, i)); i = sub_last;
++i;
anchor = i;
} }
else { else {
char c = *i;
if (islegal(c)) {
if (!tokens.back().empty() && !islegal(tokens.back().back())) {
tokens.push_back("");
}
tokens.back() += c;
}
else if (c == ' ') {
tokens.push_back("");
}
else if (c == '&') {
if (tokens.back().empty() || tokens.back().back() == '&') {
tokens.back() += c;
}
else {
tokens.push_back("&");
}
}
else if (c == '*') {
tokens.push_back("*");
}
++i; ++i;
} }
break;
default:
++i;
break;
} }
} parse_tree result;
// call recursively for each list argument if (sub_first != sub_last) {
if (!substrings.empty()) { result.m_template = true;
string result; result.m_template_parameters = parse_tpl_args(sub_first + 1, sub_last);
substrings.push_back(make_pair(anchor, end)); }
for (const subseq& sstr : substrings) { for (auto& token: tokens) {
if (!result.empty()) result += ","; if (token == "const") {
result += to_uniform_name_impl(sstr.first, sstr.second); result.m_const = true;
}
else if (token == "volatile") {
result.m_volatile = true;
}
else if (token == "&") {
result.m_lvalue_ref = true;
}
else if (token == "&&") {
result.m_rvalue_ref = true;
}
else if (token == "*") {
result.m_pointer = true;
}
else if (token == "class" || token == "struct") {
// ignored (created by visual c++ compilers)
}
else if (!token.empty()) {
if (!result.m_name.empty()) result.m_name += " ";
result.m_name += token;
}
} }
return result; return result;
} }
// we didn't got a list, compute unify name
else { private:
// is [begin, end) a template?
Iterator substr_begin = find(begin, end, '<'); parse_tree()
if (substr_begin == end) { : m_const(false), m_pointer(false), m_volatile(false), m_template(false)
// not a template, return mapping , m_lvalue_ref(false), m_rvalue_ref(false) {
string arg(begin, end); dmm = singleton_manager::get_decorated_names_map();
auto mapped = mapped_demangled_names.find(arg); }
return (mapped == mapped_demangled_names.end()) ? arg : mapped->second;
} bool m_const;
// skip leading '<' bool m_pointer;
++substr_begin; bool m_volatile;
// find trailing '>' bool m_template;
Iterator substr_end = find(reverse_iterator(end), bool m_lvalue_ref;
reverse_iterator(substr_begin), bool m_rvalue_ref;
'>') const decorated_names_map* dmm;
// get as an Iterator
.base(); string m_name;
// skip trailing '>' vector<parse_tree> m_template_parameters;
--substr_end;
if (substr_end == substr_begin) { };
throw runtime_error("substr_end == substr_begin");
template<typename Iterator>
vector<parse_tree> parse_tree::parse_tpl_args(Iterator first, Iterator last) {
vector<parse_tree> result;
long open_brackets = 0;
auto i0 = first;
for (; first != last; ++first) {
switch (*first) {
case '<':
++open_brackets;
break;
case '>':
--open_brackets;
break;
case ',':
if (open_brackets == 0) {
result.push_back(parse(i0, first));
i0 = first + 1;
}
break;
default: break;
} }
string result;
// template name (part before leading '<')
result.append(begin, substr_begin);
// get mappings of all template parameter(s)
result += to_uniform_name_impl(substr_begin, substr_end);
result.append(substr_end, end);
return result;
} }
result.push_back(parse(i0, first));
return result;
} }
template<size_t RawSize> template<size_t RawSize>
...@@ -232,11 +220,7 @@ void replace_all(string& str, const char (&before)[RawSize], const char* after) ...@@ -232,11 +220,7 @@ void replace_all(string& str, const char (&before)[RawSize], const char* after)
} }
} }
const char s_rawstr[] = const char s_rawan[] = "anonymous namespace";
"std::basic_string<@i8,std::char_traits<@i8>,std::allocator<@i8>>";
const char s_str[] = "@str";
const char s_rawan[] = "(anonymous namespace)";
const char s_an[] = "@_"; const char s_an[] = "@_";
} // namespace <anonymous> } // namespace <anonymous>
...@@ -244,8 +228,8 @@ const char s_an[] = "@_"; ...@@ -244,8 +228,8 @@ const char s_an[] = "@_";
namespace cppa { namespace detail { namespace cppa { namespace detail {
std::string to_uniform_name(const std::string& dname) { std::string to_uniform_name(const std::string& dname) {
auto r = to_uniform_name_impl(dname.begin(), dname.end(), true); auto r = parse_tree::parse(begin(dname), end(dname)).compile();
replace_all(r, s_rawstr, s_str); // replace compiler-dependent "anonmyous namespace" with "@_"
replace_all(r, s_rawan, s_an); replace_all(r, s_rawan, s_an);
return r; return r;
} }
......
...@@ -57,10 +57,6 @@ ...@@ -57,10 +57,6 @@
#include "cppa/detail/actor_proxy_cache.hpp" #include "cppa/detail/actor_proxy_cache.hpp"
#include "cppa/detail/singleton_manager.hpp" #include "cppa/detail/singleton_manager.hpp"
using std::cout;
using std::endl;
namespace cppa { namespace cppa {
void publish(actor_ptr whom, std::unique_ptr<util::acceptor> acceptor) { void publish(actor_ptr whom, std::unique_ptr<util::acceptor> acceptor) {
...@@ -82,6 +78,14 @@ actor_ptr remote_actor(util::io_stream_ptr_pair peer) { ...@@ -82,6 +78,14 @@ actor_ptr remote_actor(util::io_stream_ptr_pair peer) {
peer.first->read(&peer_pid, sizeof(std::uint32_t)); peer.first->read(&peer_pid, sizeof(std::uint32_t));
peer.first->read(peer_node_id.data(), peer_node_id.size()); peer.first->read(peer_node_id.data(), peer_node_id.size());
process_information_ptr pinfptr(new process_information(peer_pid, peer_node_id)); process_information_ptr pinfptr(new process_information(peer_pid, peer_node_id));
if (*pinf == *pinfptr) {
// dude, this is not a remote actor, it's a local actor!
# ifdef CPPA_DEBUG
std::cerr << "*** warning: remote_actor() called to access a local actor\n"
<< std::flush;
# endif
return detail::singleton_manager::get_actor_registry()->get(remote_actor_id);
}
//auto key = std::make_tuple(remote_actor_id, pinfptr->process_id(), pinfptr->node_id()); //auto key = std::make_tuple(remote_actor_id, pinfptr->process_id(), pinfptr->node_id());
detail::middleman_add_peer(peer, pinfptr); detail::middleman_add_peer(peer, pinfptr);
return detail::get_actor_proxy_cache().get_or_put(remote_actor_id, return detail::get_actor_proxy_cache().get_or_put(remote_actor_id,
...@@ -89,8 +93,8 @@ actor_ptr remote_actor(util::io_stream_ptr_pair peer) { ...@@ -89,8 +93,8 @@ actor_ptr remote_actor(util::io_stream_ptr_pair peer) {
pinfptr->node_id()); pinfptr->node_id());
} }
void publish(actor_ptr whom, std::uint16_t port) { void publish(actor_ptr whom, std::uint16_t port, const char* addr) {
if (whom) publish(whom, detail::ipv4_acceptor::create(port)); if (whom) publish(whom, detail::ipv4_acceptor::create(port, addr));
} }
actor_ptr remote_actor(const char* host, std::uint16_t port) { actor_ptr remote_actor(const char* host, std::uint16_t port) {
......
...@@ -66,11 +66,13 @@ namespace cppa { namespace detail { ...@@ -66,11 +66,13 @@ namespace cppa { namespace detail {
namespace { namespace {
using namespace std;
inline uniform_type_info_map& uti_map() { inline uniform_type_info_map& uti_map() {
return *singleton_manager::get_uniform_type_info_map(); return *singleton_manager::get_uniform_type_info_map();
} }
inline const char* raw_name(const std::type_info& tinfo) { inline const char* raw_name(const type_info& tinfo) {
#ifdef CPPA_WINDOWS #ifdef CPPA_WINDOWS
return tinfo.raw_name(); return tinfo.raw_name();
#else #else
...@@ -78,25 +80,21 @@ inline const char* raw_name(const std::type_info& tinfo) { ...@@ -78,25 +80,21 @@ inline const char* raw_name(const std::type_info& tinfo) {
#endif #endif
} }
template<typename T>
struct is_signed :
std::integral_constant<bool, std::numeric_limits<T>::is_signed> { };
template<typename T> template<typename T>
inline const char* raw_name() { inline const char* raw_name() {
return raw_name(typeid(T)); return raw_name(typeid(T));
} }
typedef std::set<std::string> string_set; typedef set<string> string_set;
typedef std::map<int, std::pair<string_set, string_set> > int_name_mapping; typedef map<int, pair<string_set, string_set> > int_name_mapping;
template<typename Int> template<typename Int>
inline void push_impl(int_name_mapping& ints, std::true_type) { inline void push_impl(int_name_mapping& ints, true_type) {
ints[sizeof(Int)].first.insert(raw_name<Int>()); // signed version ints[sizeof(Int)].first.insert(raw_name<Int>()); // signed version
} }
template<typename Int> template<typename Int>
inline void push_impl(int_name_mapping& ints, std::false_type) { inline void push_impl(int_name_mapping& ints, false_type) {
ints[sizeof(Int)].second.insert(raw_name<Int>()); // unsigned version ints[sizeof(Int)].second.insert(raw_name<Int>()); // unsigned version
} }
...@@ -111,7 +109,7 @@ inline void push(int_name_mapping& ints) { ...@@ -111,7 +109,7 @@ inline void push(int_name_mapping& ints) {
push<Int1, Ints...>(ints); push<Int1, Ints...>(ints);
} }
const std::string s_nullptr_type_name{"@0"}; const char s_nullptr_type_name[] = "@0";
void serialize_nullptr(serializer* sink) { void serialize_nullptr(serializer* sink) {
sink->begin_object(s_nullptr_type_name); sink->begin_object(s_nullptr_type_name);
...@@ -131,7 +129,7 @@ class void_type_tinfo : public uniform_type_info { ...@@ -131,7 +129,7 @@ class void_type_tinfo : public uniform_type_info {
void_type_tinfo() : uniform_type_info(to_uniform_name<util::void_type>()) {} void_type_tinfo() : uniform_type_info(to_uniform_name<util::void_type>()) {}
bool equals(const std::type_info &tinfo) const { bool equals(const type_info &tinfo) const {
return typeid(util::void_type) == tinfo; return typeid(util::void_type) == tinfo;
} }
...@@ -142,9 +140,9 @@ class void_type_tinfo : public uniform_type_info { ...@@ -142,9 +140,9 @@ class void_type_tinfo : public uniform_type_info {
} }
void deserialize(void*, deserializer* source) const { void deserialize(void*, deserializer* source) const {
std::string cname = source->seek_object(); string cname = source->seek_object();
if (cname != name()) { if (cname != name()) {
throw std::logic_error("wrong type name found"); throw logic_error("wrong type name found");
} }
deserialize_nullptr(source); deserialize_nullptr(source);
} }
...@@ -176,7 +174,7 @@ class actor_ptr_tinfo : public util::abstract_uniform_type_info<actor_ptr> { ...@@ -176,7 +174,7 @@ class actor_ptr_tinfo : public util::abstract_uniform_type_info<actor_ptr> {
static void s_serialize(const actor_ptr& ptr, static void s_serialize(const actor_ptr& ptr,
serializer* sink, serializer* sink,
const std::string& name) { const string& name) {
if (ptr == nullptr) { if (ptr == nullptr) {
serialize_nullptr(sink); serialize_nullptr(sink);
} }
...@@ -196,16 +194,14 @@ class actor_ptr_tinfo : public util::abstract_uniform_type_info<actor_ptr> { ...@@ -196,16 +194,14 @@ class actor_ptr_tinfo : public util::abstract_uniform_type_info<actor_ptr> {
static void s_deserialize(actor_ptr& ptrref, static void s_deserialize(actor_ptr& ptrref,
deserializer* source, deserializer* source,
const std::string& name) { const string& name) {
std::string cname = source->seek_object(); auto cname = source->seek_object();
if (cname != name) { if (cname != name) {
if (cname == s_nullptr_type_name) { if (cname == s_nullptr_type_name) {
deserialize_nullptr(source); deserialize_nullptr(source);
ptrref.reset(); ptrref.reset();
} }
else { else assert_type_name(source, name); // throws
throw std::logic_error("wrong type name found");
}
} }
else { else {
primitive_variant ptup[3]; primitive_variant ptup[3];
...@@ -213,28 +209,28 @@ class actor_ptr_tinfo : public util::abstract_uniform_type_info<actor_ptr> { ...@@ -213,28 +209,28 @@ class actor_ptr_tinfo : public util::abstract_uniform_type_info<actor_ptr> {
source->begin_object(cname); source->begin_object(cname);
source->read_tuple(3, ptypes, ptup); source->read_tuple(3, ptypes, ptup);
source->end_object(); source->end_object();
const std::string& nstr = get<std::string>(ptup[2]); const string& nstr = get<string>(ptup[2]);
// local actor? // local actor?
auto pinf = process_information::get(); auto pinf = process_information::get();
if ( pinf->process_id() == get<std::uint32_t>(ptup[1]) if ( pinf->process_id() == get<uint32_t>(ptup[1])
&& cppa::equal(nstr, pinf->node_id())) { && cppa::equal(nstr, pinf->node_id())) {
auto id = get<std::uint32_t>(ptup[0]); auto id = get<uint32_t>(ptup[0]);
ptrref = singleton_manager::get_actor_registry()->get(id); ptrref = singleton_manager::get_actor_registry()->get(id);
//ptrref = actor::by_id(get<std::uint32_t>(ptup[0])); //ptrref = actor::by_id(get<uint32_t>(ptup[0]));
} }
else { else {
/* /*
actor_proxy_cache::key_tuple key; actor_proxy_cache::key_tuple key;
std::get<0>(key) = get<std::uint32_t>(ptup[0]); get<0>(key) = get<uint32_t>(ptup[0]);
std::get<1>(key) = get<std::uint32_t>(ptup[1]); get<1>(key) = get<uint32_t>(ptup[1]);
node_id_from_string(nstr, std::get<2>(key)); node_id_from_string(nstr, get<2>(key));
ptrref = detail::get_actor_proxy_cache().get(key); ptrref = detail::get_actor_proxy_cache().get(key);
*/ */
process_information::node_id_type nid; process_information::node_id_type nid;
node_id_from_string(nstr, nid); node_id_from_string(nstr, nid);
auto& cache = detail::get_actor_proxy_cache(); auto& cache = detail::get_actor_proxy_cache();
ptrref = cache.get_or_put(get<std::uint32_t>(ptup[0]), ptrref = cache.get_or_put(get<uint32_t>(ptup[0]),
get<std::uint32_t>(ptup[1]), get<uint32_t>(ptup[1]),
nid); nid);
} }
} }
...@@ -258,7 +254,7 @@ class group_ptr_tinfo : public util::abstract_uniform_type_info<group_ptr> { ...@@ -258,7 +254,7 @@ class group_ptr_tinfo : public util::abstract_uniform_type_info<group_ptr> {
static void s_serialize(const group_ptr& ptr, static void s_serialize(const group_ptr& ptr,
serializer* sink, serializer* sink,
const std::string& name) { const string& name) {
if (ptr == nullptr) { if (ptr == nullptr) {
serialize_nullptr(sink); serialize_nullptr(sink);
} }
...@@ -272,21 +268,19 @@ class group_ptr_tinfo : public util::abstract_uniform_type_info<group_ptr> { ...@@ -272,21 +268,19 @@ class group_ptr_tinfo : public util::abstract_uniform_type_info<group_ptr> {
static void s_deserialize(group_ptr& ptrref, static void s_deserialize(group_ptr& ptrref,
deserializer* source, deserializer* source,
const std::string& name) { const string& name) {
std::string cname = source->seek_object(); auto cname = source->seek_object();
if (cname != name) { if (cname != name) {
if (cname == s_nullptr_type_name) { if (cname == s_nullptr_type_name) {
deserialize_nullptr(source); deserialize_nullptr(source);
ptrref.reset(); ptrref.reset();
} }
else { else assert_type_name(source, name); // throws
throw std::logic_error("wrong type name found");
}
} }
else { else {
source->begin_object(name); source->begin_object(name);
auto modname = source->read_value(pt_u8string); auto modname = source->read_value(pt_u8string);
ptrref = group::get_module(get<std::string>(modname)) ptrref = group::get_module(get<string>(modname))
->deserialize(source); ->deserialize(source);
source->end_object(); source->end_object();
} }
...@@ -308,16 +302,16 @@ class group_ptr_tinfo : public util::abstract_uniform_type_info<group_ptr> { ...@@ -308,16 +302,16 @@ class group_ptr_tinfo : public util::abstract_uniform_type_info<group_ptr> {
class channel_ptr_tinfo : public util::abstract_uniform_type_info<channel_ptr> { class channel_ptr_tinfo : public util::abstract_uniform_type_info<channel_ptr> {
std::string group_ptr_name; string group_ptr_name;
std::string actor_ptr_name; string actor_ptr_name;
public: public:
static void s_serialize(const channel_ptr& ptr, static void s_serialize(const channel_ptr& ptr,
serializer* sink, serializer* sink,
const std::string& channel_type_name, const string& channel_type_name,
const std::string& actor_ptr_type_name, const string& actor_ptr_type_name,
const std::string& group_ptr_type_name) { const string& group_ptr_type_name) {
sink->begin_object(channel_type_name); sink->begin_object(channel_type_name);
if (ptr == nullptr) { if (ptr == nullptr) {
serialize_nullptr(sink); serialize_nullptr(sink);
...@@ -332,7 +326,7 @@ class channel_ptr_tinfo : public util::abstract_uniform_type_info<channel_ptr> { ...@@ -332,7 +326,7 @@ class channel_ptr_tinfo : public util::abstract_uniform_type_info<channel_ptr> {
group_ptr_tinfo::s_serialize(gptr, sink, group_ptr_type_name); group_ptr_tinfo::s_serialize(gptr, sink, group_ptr_type_name);
} }
else { else {
throw std::logic_error("channel is neither " throw logic_error("channel is neither "
"an actor nor a group"); "an actor nor a group");
} }
} }
...@@ -341,15 +335,12 @@ class channel_ptr_tinfo : public util::abstract_uniform_type_info<channel_ptr> { ...@@ -341,15 +335,12 @@ class channel_ptr_tinfo : public util::abstract_uniform_type_info<channel_ptr> {
static void s_deserialize(channel_ptr& ptrref, static void s_deserialize(channel_ptr& ptrref,
deserializer* source, deserializer* source,
const std::string& name, const string& name,
const std::string& actor_ptr_type_name, const string& actor_ptr_type_name,
const std::string& group_ptr_type_name) { const string& group_ptr_type_name) {
std::string cname = source->seek_object(); assert_type_name(source, name);
if (cname != name) { source->begin_object(name);
throw std::logic_error("wrong type name found"); string subobj = source->peek_object();
}
source->begin_object(cname);
std::string subobj = source->peek_object();
if (subobj == actor_ptr_type_name) { if (subobj == actor_ptr_type_name) {
actor_ptr tmp; actor_ptr tmp;
actor_ptr_tinfo::s_deserialize(tmp, source, actor_ptr_type_name); actor_ptr_tinfo::s_deserialize(tmp, source, actor_ptr_type_name);
...@@ -365,7 +356,7 @@ class channel_ptr_tinfo : public util::abstract_uniform_type_info<channel_ptr> { ...@@ -365,7 +356,7 @@ class channel_ptr_tinfo : public util::abstract_uniform_type_info<channel_ptr> {
ptrref.reset(); ptrref.reset();
} }
else { else {
throw std::logic_error("unexpected type name: " + subobj); throw logic_error("unexpected type name: " + subobj);
} }
source->end_object(); source->end_object();
} }
...@@ -401,7 +392,7 @@ class any_tuple_tinfo : public util::abstract_uniform_type_info<any_tuple> { ...@@ -401,7 +392,7 @@ class any_tuple_tinfo : public util::abstract_uniform_type_info<any_tuple> {
static void s_serialize(const any_tuple& atup, static void s_serialize(const any_tuple& atup,
serializer* sink, serializer* sink,
const std::string& name) { const string& name) {
sink->begin_object(name); sink->begin_object(name);
sink->begin_sequence(atup.size()); sink->begin_sequence(atup.size());
for (size_t i = 0; i < atup.size(); ++i) { for (size_t i = 0; i < atup.size(); ++i) {
...@@ -413,11 +404,10 @@ class any_tuple_tinfo : public util::abstract_uniform_type_info<any_tuple> { ...@@ -413,11 +404,10 @@ class any_tuple_tinfo : public util::abstract_uniform_type_info<any_tuple> {
static void s_deserialize(any_tuple& atref, static void s_deserialize(any_tuple& atref,
deserializer* source, deserializer* source,
const std::string& name) { const string& name) {
uniform_type_info::assert_type_name(source, name);
auto result = new detail::object_array; auto result = new detail::object_array;
auto str = source->seek_object(); source->begin_object(name);
if (str != name) throw std::logic_error("invalid type found: " + str);
source->begin_object(str);
size_t tuple_size = source->begin_sequence(); size_t tuple_size = source->begin_sequence();
for (size_t i = 0; i < tuple_size; ++i) { for (size_t i = 0; i < tuple_size; ++i) {
auto tname = source->peek_object(); auto tname = source->peek_object();
...@@ -443,10 +433,10 @@ class any_tuple_tinfo : public util::abstract_uniform_type_info<any_tuple> { ...@@ -443,10 +433,10 @@ class any_tuple_tinfo : public util::abstract_uniform_type_info<any_tuple> {
class addr_msg_tinfo : public util::abstract_uniform_type_info<addressed_message> { class addr_msg_tinfo : public util::abstract_uniform_type_info<addressed_message> {
std::string any_tuple_name; string any_tuple_name;
std::string actor_ptr_name; string actor_ptr_name;
std::string group_ptr_name; string group_ptr_name;
std::string channel_ptr_name; string channel_ptr_name;
public: public:
...@@ -466,9 +456,8 @@ class addr_msg_tinfo : public util::abstract_uniform_type_info<addressed_message ...@@ -466,9 +456,8 @@ class addr_msg_tinfo : public util::abstract_uniform_type_info<addressed_message
} }
virtual void deserialize(void* instance, deserializer* source) const { virtual void deserialize(void* instance, deserializer* source) const {
auto tname = source->seek_object(); assert_type_name(source);
if (tname != name()) throw 42; source->begin_object(name());
source->begin_object(tname);
auto& msg = *reinterpret_cast<addressed_message*>(instance); auto& msg = *reinterpret_cast<addressed_message*>(instance);
actor_ptr_tinfo::s_deserialize(msg.sender(), source, actor_ptr_name); actor_ptr_tinfo::s_deserialize(msg.sender(), source, actor_ptr_name);
channel_ptr_tinfo::s_deserialize(msg.receiver(), channel_ptr_tinfo::s_deserialize(msg.receiver(),
...@@ -512,15 +501,13 @@ class process_info_ptr_tinfo : public util::abstract_uniform_type_info<process_i ...@@ -512,15 +501,13 @@ class process_info_ptr_tinfo : public util::abstract_uniform_type_info<process_i
virtual void deserialize(void* instance, deserializer* source) const { virtual void deserialize(void* instance, deserializer* source) const {
auto& ptrref = *reinterpret_cast<ptr_type*>(instance); auto& ptrref = *reinterpret_cast<ptr_type*>(instance);
std::string cname = source->seek_object(); auto cname = source->seek_object();
if (cname != name()) { if (cname != name()) {
if (cname == s_nullptr_type_name) { if (cname == s_nullptr_type_name) {
deserialize_nullptr(source); deserialize_nullptr(source);
ptrref.reset(); ptrref.reset();
} }
else { else assert_type_name(source); // throws
throw std::logic_error("wrong type name found");
}
} }
else { else {
primitive_variant ptup[2]; primitive_variant ptup[2];
...@@ -529,8 +516,8 @@ class process_info_ptr_tinfo : public util::abstract_uniform_type_info<process_i ...@@ -529,8 +516,8 @@ class process_info_ptr_tinfo : public util::abstract_uniform_type_info<process_i
source->read_tuple(2, ptypes, ptup); source->read_tuple(2, ptypes, ptup);
source->end_object(); source->end_object();
process_information::node_id_type nid; process_information::node_id_type nid;
node_id_from_string(get<std::string>(ptup[1]), nid); node_id_from_string(get<string>(ptup[1]), nid);
ptrref.reset(new process_information{get<std::uint32_t>(ptup[0]), nid}); ptrref.reset(new process_information{get<uint32_t>(ptup[0]), nid});
} }
} }
...@@ -543,18 +530,17 @@ class atom_value_tinfo : public util::abstract_uniform_type_info<atom_value> { ...@@ -543,18 +530,17 @@ class atom_value_tinfo : public util::abstract_uniform_type_info<atom_value> {
virtual void serialize(const void* instance, serializer* sink) const { virtual void serialize(const void* instance, serializer* sink) const {
auto val = reinterpret_cast<const atom_value*>(instance); auto val = reinterpret_cast<const atom_value*>(instance);
sink->begin_object(name()); sink->begin_object(name());
sink->write_value(static_cast<std::uint64_t>(*val)); sink->write_value(static_cast<uint64_t>(*val));
sink->end_object(); sink->end_object();
} }
virtual void deserialize(void* instance, deserializer* source) const { virtual void deserialize(void* instance, deserializer* source) const {
assert_type_name(source);
auto val = reinterpret_cast<atom_value*>(instance); auto val = reinterpret_cast<atom_value*>(instance);
auto tname = source->seek_object(); source->begin_object(name());
if (tname != name()) throw 42;
source->begin_object(tname);
auto ptval = source->read_value(pt_uint64); auto ptval = source->read_value(pt_uint64);
source->end_object(); source->end_object();
*val = static_cast<atom_value>(get<std::uint64_t>(ptval)); *val = static_cast<atom_value>(get<uint64_t>(ptval));
} }
}; };
...@@ -564,20 +550,19 @@ class duration_tinfo : public util::abstract_uniform_type_info<util::duration> { ...@@ -564,20 +550,19 @@ class duration_tinfo : public util::abstract_uniform_type_info<util::duration> {
virtual void serialize(const void* instance, serializer* sink) const { virtual void serialize(const void* instance, serializer* sink) const {
auto val = reinterpret_cast<const util::duration*>(instance); auto val = reinterpret_cast<const util::duration*>(instance);
sink->begin_object(name()); sink->begin_object(name());
sink->write_value(static_cast<std::uint32_t>(val->unit)); sink->write_value(static_cast<uint32_t>(val->unit));
sink->write_value(val->count); sink->write_value(val->count);
sink->end_object(); sink->end_object();
} }
virtual void deserialize(void* instance, deserializer* source) const { virtual void deserialize(void* instance, deserializer* source) const {
assert_type_name(source);
source->begin_object(name());
auto val = reinterpret_cast<util::duration*>(instance); auto val = reinterpret_cast<util::duration*>(instance);
auto tname = source->seek_object();
if (tname != name()) throw 42;
source->begin_object(tname);
auto unit_val = source->read_value(pt_uint32); auto unit_val = source->read_value(pt_uint32);
auto count_val = source->read_value(pt_uint32); auto count_val = source->read_value(pt_uint32);
source->end_object(); source->end_object();
switch (get<std::uint32_t>(unit_val)) { switch (get<uint32_t>(unit_val)) {
case 1: case 1:
val->unit = util::time_unit::seconds; val->unit = util::time_unit::seconds;
break; break;
...@@ -594,7 +579,7 @@ class duration_tinfo : public util::abstract_uniform_type_info<util::duration> { ...@@ -594,7 +579,7 @@ class duration_tinfo : public util::abstract_uniform_type_info<util::duration> {
val->unit = util::time_unit::none; val->unit = util::time_unit::none;
break; break;
} }
val->count = get<std::uint32_t>(count_val); val->count = get<uint32_t>(count_val);
} }
}; };
...@@ -604,14 +589,14 @@ class int_tinfo : public detail::default_uniform_type_info_impl<T> { ...@@ -604,14 +589,14 @@ class int_tinfo : public detail::default_uniform_type_info_impl<T> {
public: public:
bool equals(const std::type_info& tinfo) const { bool equals(const type_info& tinfo) const {
// TODO: string comparsion sucks & is slow; find a nicer solution // TODO: string comparsion sucks & is slow; find a nicer solution
auto map_iter = uti_map().int_names().find(sizeof(T)); auto map_iter = uti_map().int_names().find(sizeof(T));
const string_set& st = is_signed<T>::value ? map_iter->second.first const string_set& st = is_signed<T>::value ? map_iter->second.first
: map_iter->second.second; : map_iter->second.second;
auto x = raw_name(tinfo); auto x = raw_name(tinfo);
return std::any_of(st.begin(), st.end(), return any_of(st.begin(), st.end(),
[&x](const std::string& y) { return x == y; }); [&x](const string& y) { return x == y; });
} }
}; };
...@@ -623,14 +608,13 @@ class bool_tinfo : public util::abstract_uniform_type_info<bool> { ...@@ -623,14 +608,13 @@ class bool_tinfo : public util::abstract_uniform_type_info<bool> {
virtual void serialize(const void* instance, serializer* sink) const { virtual void serialize(const void* instance, serializer* sink) const {
auto val = *reinterpret_cast<const bool*>(instance); auto val = *reinterpret_cast<const bool*>(instance);
sink->begin_object(name()); sink->begin_object(name());
sink->write_value(static_cast<std::uint8_t>(val ? 1 : 0)); sink->write_value(static_cast<uint8_t>(val ? 1 : 0));
sink->end_object(); sink->end_object();
} }
virtual void deserialize(void* instance, deserializer* source) const { virtual void deserialize(void* instance, deserializer* source) const {
auto tname = source->seek_object(); assert_type_name(source);
if (tname != name()) throw 42; source->begin_object(name());
source->begin_object(tname);
auto ptval = source->read_value(pt_uint8); auto ptval = source->read_value(pt_uint8);
source->end_object(); source->end_object();
*reinterpret_cast<bool*>(instance) = (get<pt_uint8>(ptval) != 0); *reinterpret_cast<bool*>(instance) = (get<pt_uint8>(ptval) != 0);
...@@ -726,18 +710,12 @@ uniform_type_info_map::~uniform_type_info_map() { ...@@ -726,18 +710,12 @@ uniform_type_info_map::~uniform_type_info_map() {
const uniform_type_info* uniform_type_info_map::by_raw_name(const std::string& name) const { const uniform_type_info* uniform_type_info_map::by_raw_name(const std::string& name) const {
auto i = m_by_rname.find(name); auto i = m_by_rname.find(name);
if (i != m_by_rname.end()) { return (i != m_by_rname.end()) ? i->second : nullptr;
return i->second;
}
return nullptr;
} }
const uniform_type_info* uniform_type_info_map::by_uniform_name(const std::string& name) const { const uniform_type_info* uniform_type_info_map::by_uniform_name(const std::string& name) const {
auto i = m_by_uname.find(name); auto i = m_by_uname.find(name);
if (i != m_by_uname.end()) { return (i != m_by_uname.end()) ? i->second : nullptr;
return i->second;
}
return nullptr;
} }
bool uniform_type_info_map::insert(const std::set<std::string>& raw_names, bool uniform_type_info_map::insert(const std::set<std::string>& raw_names,
...@@ -776,7 +754,23 @@ bool announce(const std::type_info& tinfo, uniform_type_info* utype) { ...@@ -776,7 +754,23 @@ bool announce(const std::type_info& tinfo, uniform_type_info* utype) {
uniform_type_info::uniform_type_info(const std::string& str) : m_name(str) { } uniform_type_info::uniform_type_info(const std::string& str) : m_name(str) { }
uniform_type_info::~uniform_type_info() { uniform_type_info::~uniform_type_info() { }
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));
}
}
void uniform_type_info::assert_type_name(deserializer* source) const {
assert_type_name(source, name());
} }
object uniform_type_info::create() const { object uniform_type_info::create() const {
......
...@@ -236,7 +236,7 @@ int main(int argc, char** argv) { ...@@ -236,7 +236,7 @@ int main(int argc, char** argv) {
bool success = false; bool success = false;
do { do {
try { try {
publish(self, port); publish(self, port, "127.0.0.1");
success = true; success = true;
} }
catch (bind_failure&) { catch (bind_failure&) {
......
...@@ -50,17 +50,14 @@ ...@@ -50,17 +50,14 @@
#include "cppa/detail/ptype_to_type.hpp" #include "cppa/detail/ptype_to_type.hpp"
#include "cppa/detail/default_uniform_type_info_impl.hpp" #include "cppa/detail/default_uniform_type_info_impl.hpp"
using std::cout; using namespace std;
using std::cerr;
using std::endl;
using namespace cppa; using namespace cppa;
using namespace cppa::util; using namespace cppa::util;
using cppa::detail::type_to_ptype; using cppa::detail::type_to_ptype;
using cppa::detail::ptype_to_type; using cppa::detail::ptype_to_type;
namespace { const size_t ui32size = sizeof(std::uint32_t); } namespace { const size_t ui32size = sizeof(uint32_t); }
struct struct_a { struct struct_a {
int x; int x;
...@@ -78,7 +75,7 @@ bool operator!=(const struct_a& lhs, const struct_a& rhs) { ...@@ -78,7 +75,7 @@ bool operator!=(const struct_a& lhs, const struct_a& rhs) {
struct struct_b { struct struct_b {
struct_a a; struct_a a;
int z; int z;
std::list<int> ints; list<int> ints;
}; };
bool operator==(const struct_b& lhs, const struct_b& rhs) { bool operator==(const struct_b& lhs, const struct_b& rhs) {
...@@ -89,11 +86,11 @@ bool operator!=(const struct_b& lhs, const struct_b& rhs) { ...@@ -89,11 +86,11 @@ bool operator!=(const struct_b& lhs, const struct_b& rhs) {
return !(lhs == rhs); return !(lhs == rhs);
} }
typedef std::map<std::string, std::u16string> strmap; typedef map<string, u16string> strmap;
struct struct_c { struct struct_c {
strmap strings; strmap strings;
std::set<int> ints; set<int> ints;
}; };
bool operator==(const struct_c& lhs, const struct_c& rhs) { bool operator==(const struct_c& lhs, const struct_c& rhs) {
...@@ -106,36 +103,97 @@ bool operator!=(const struct_c& lhs, const struct_c& rhs) { ...@@ -106,36 +103,97 @@ bool operator!=(const struct_c& lhs, const struct_c& rhs) {
static const char* msg1str = u8R"__(@<> ( { @i32 ( 42 ), @str ( "Hello \"World\"!" ) } ))__"; static const char* msg1str = u8R"__(@<> ( { @i32 ( 42 ), @str ( "Hello \"World\"!" ) } ))__";
struct raw_struct {
string str;
};
bool operator==(const raw_struct& lhs, const raw_struct& rhs) {
return lhs.str == rhs.str;
}
bool operator!=(const raw_struct& lhs, const raw_struct& rhs) {
return lhs.str != rhs.str;
}
struct raw_struct_type_info : util::abstract_uniform_type_info<raw_struct> {
void serialize(const void* ptr, serializer* sink) const {
auto rs = reinterpret_cast<const raw_struct*>(ptr);
sink->begin_object(name());
sink->write_value(static_cast<uint32_t>(rs->str.size()));
sink->write_raw(rs->str.size(), rs->str.data());
sink->end_object();
}
void deserialize(void* ptr, deserializer* source) const {
assert_type_name(source);
source->begin_object(name());
auto rs = reinterpret_cast<raw_struct*>(ptr);
rs->str.clear();
auto size = get<std::uint32_t>(source->read_value(pt_uint32));
rs->str.resize(size);
source->read_raw(size, &(rs->str[0]));
source->end_object();
}
};
int main() { int main() {
CPPA_TEST(test__serialization); CPPA_TEST(test__serialization);
announce(typeid(raw_struct), new raw_struct_type_info);
auto oarr = new detail::object_array; auto oarr = new detail::object_array;
oarr->push_back(object::from(static_cast<std::uint32_t>(42))); oarr->push_back(object::from(static_cast<uint32_t>(42)));
oarr->push_back(object::from("foo" )); oarr->push_back(object::from("foo" ));
any_tuple atuple1(oarr); any_tuple atuple1(oarr);
try { try {
auto opt = tuple_cast<std::uint32_t, std::string>(atuple1); auto opt = tuple_cast<uint32_t, string>(atuple1);
CPPA_CHECK(opt.valid()); CPPA_CHECK(opt.valid());
if (opt) { if (opt) {
auto& tup = *opt; auto& tup = *opt;
CPPA_CHECK_EQUAL(tup.size(), static_cast<size_t>(2)); CPPA_CHECK_EQUAL(tup.size(), static_cast<size_t>(2));
CPPA_CHECK_EQUAL(get<0>(tup), static_cast<std::uint32_t>(42)); CPPA_CHECK_EQUAL(get<0>(tup), static_cast<uint32_t>(42));
CPPA_CHECK_EQUAL(get<1>(tup), "foo"); CPPA_CHECK_EQUAL(get<1>(tup), "foo");
} }
} }
catch (std::exception& e) { catch (exception& e) {
CPPA_ERROR("exception: " << e.what()); CPPA_ERROR("exception: " << e.what());
} }
try {
// test raw_type in both binary and string serialization
raw_struct rs;
rs.str = "Lorem ipsum dolor sit amet.";
util::buffer wr_buf;
binary_serializer bs(&wr_buf);
bs << rs;
binary_deserializer bd(wr_buf.data(), wr_buf.size());
raw_struct rs2;
uniform_typeid<raw_struct>()->deserialize(&rs2, &bd);
CPPA_CHECK_EQUAL(rs.str, rs2.str);
auto rsstr = cppa::to_string(rs);
rs2.str = "foobar";
cout << "rs as string: " << rsstr << endl;
rs2 = from_string<raw_struct>(rsstr);
CPPA_CHECK_EQUAL(rs.str, rs2.str);
}
catch (exception& e) {
CPPA_ERROR("exception: " << e.what());
}
{ {
any_tuple ttup = make_cow_tuple(1, 2, actor_ptr(self)); any_tuple ttup = make_cow_tuple(1, 2, actor_ptr(self));
util::buffer wr_buf; util::buffer wr_buf;
binary_serializer bs(&wr_buf); binary_serializer bs(&wr_buf);
bs << ttup; bs << ttup;
bs << ttup;
binary_deserializer bd(wr_buf.data(), wr_buf.size()); binary_deserializer bd(wr_buf.data(), wr_buf.size());
any_tuple ttup2; any_tuple ttup2;
any_tuple ttup3;
uniform_typeid<any_tuple>()->deserialize(&ttup2, &bd); uniform_typeid<any_tuple>()->deserialize(&ttup2, &bd);
CPPA_CHECK(ttup == ttup2); uniform_typeid<any_tuple>()->deserialize(&ttup3, &bd);
CPPA_CHECK(ttup == ttup2);
CPPA_CHECK(ttup == ttup3);
CPPA_CHECK(ttup2 == ttup3);
} }
{ {
// serialize b1 to buf // serialize b1 to buf
...@@ -147,7 +205,7 @@ int main() { ...@@ -147,7 +205,7 @@ int main() {
any_tuple atuple2; any_tuple atuple2;
uniform_typeid<any_tuple>()->deserialize(&atuple2, &bd); uniform_typeid<any_tuple>()->deserialize(&atuple2, &bd);
try { try {
auto opt = tuple_cast<std::uint32_t, std::string>(atuple2); auto opt = tuple_cast<uint32_t, string>(atuple2);
CPPA_CHECK(opt.valid()); CPPA_CHECK(opt.valid());
if (opt.valid()) { if (opt.valid()) {
auto& tup = *opt; auto& tup = *opt;
...@@ -156,12 +214,12 @@ int main() { ...@@ -156,12 +214,12 @@ int main() {
CPPA_CHECK_EQUAL(get<1>(tup), "foo"); CPPA_CHECK_EQUAL(get<1>(tup), "foo");
} }
} }
catch (std::exception& e) { catch (exception& e) {
CPPA_ERROR("exception: " << e.what()); CPPA_ERROR("exception: " << e.what());
} }
} }
{ {
any_tuple msg1 = cppa::make_cow_tuple(42, std::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) {
CPPA_ERROR("msg1str != to_string(msg1)"); CPPA_ERROR("msg1str != to_string(msg1)");
...@@ -178,8 +236,8 @@ int main() { ...@@ -178,8 +236,8 @@ int main() {
if (typeid(any_tuple) == *(obj1.type()) && obj2.type() == obj1.type()) { if (typeid(any_tuple) == *(obj1.type()) && obj2.type() == obj1.type()) {
auto& content1 = get<any_tuple>(obj1); auto& content1 = get<any_tuple>(obj1);
auto& content2 = get<any_tuple>(obj2); auto& content2 = get<any_tuple>(obj2);
auto opt1 = tuple_cast<decltype(42), std::string>(content1); auto opt1 = tuple_cast<decltype(42), string>(content1);
auto opt2 = tuple_cast<decltype(42), std::string>(content2); auto opt2 = tuple_cast<decltype(42), string>(content2);
CPPA_CHECK(opt1.valid() && opt2.valid()); CPPA_CHECK(opt1.valid() && opt2.valid());
if (opt1.valid() && opt2.valid()) { if (opt1.valid() && opt2.valid()) {
auto& tup1 = *opt1; auto& tup1 = *opt1;
...@@ -198,18 +256,18 @@ int main() { ...@@ -198,18 +256,18 @@ int main() {
} }
CPPA_CHECK((is_iterable<int>::value) == false); CPPA_CHECK((is_iterable<int>::value) == false);
// std::string is primitive and thus not identified by is_iterable // string is primitive and thus not identified by is_iterable
CPPA_CHECK((is_iterable<std::string>::value) == false); CPPA_CHECK((is_iterable<string>::value) == false);
CPPA_CHECK((is_iterable<std::list<int>>::value) == true); CPPA_CHECK((is_iterable<list<int>>::value) == true);
CPPA_CHECK((is_iterable<std::map<int,int>>::value) == true); CPPA_CHECK((is_iterable<map<int,int>>::value) == true);
{ // test meta_object implementation for primitive types { // test meta_object implementation for primitive types
auto meta_int = uniform_typeid<std::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) {
auto o = meta_int->create(); auto o = meta_int->create();
get_ref<std::uint32_t>(o) = 42; get_ref<uint32_t>(o) = 42;
auto str = to_string(get<std::uint32_t>(o)); auto str = cppa::to_string(get<uint32_t>(o));
CPPA_CHECK_EQUAL(str, "@u32 ( 42 )"); CPPA_CHECK_EQUAL( "@u32 ( 42 )", str);
} }
} }
{ // test serializers / deserializers with struct_b { // test serializers / deserializers with struct_b
...@@ -220,7 +278,7 @@ int main() { ...@@ -220,7 +278,7 @@ int main() {
&struct_b::z, &struct_b::z,
&struct_b::ints); &struct_b::ints);
// testees // testees
struct_b b1 = { { 1, 2 }, 3, std::list<int>{ 4, 5, 6, 7, 8, 9, 10 } }; struct_b b1 = { { 1, 2 }, 3, list<int>{ 4, 5, 6, 7, 8, 9, 10 } };
struct_b b2; struct_b b2;
struct_b b3; struct_b b3;
// expected result of to_string(&b1, meta_b) // expected result of to_string(&b1, meta_b)
...@@ -253,7 +311,7 @@ int main() { ...@@ -253,7 +311,7 @@ int main() {
// get meta type of struct_c and "announce" // 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" }}, std::set<int>{9, 4, 5}}; struct_c c1{strmap{{"abc", u"cba" }, { "x", u"y" }}, set<int>{9, 4, 5}};
struct_c c2; { struct_c c2; {
// serialize c1 to buf // serialize c1 to buf
util::buffer wr_buf; util::buffer wr_buf;
......
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