Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

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

  • Loading branch information...
commit 6a058c4d1f7fe3240746dec681f3b14ccfad9b12 2 parents 8f79f16 + 9e7db02
@Neverlord Neverlord authored
View
1  CMakeLists.txt
@@ -131,6 +131,7 @@ set(LIBCPPA_SRC
src/uniform_type_info.cpp
src/yield_interface.cpp
src/context_switching_actor.cpp
+ src/decorated_names_map.cpp
)
set(boost_context third_party/boost_context)
View
3  cppa.files
@@ -272,3 +272,6 @@ examples/group_chat.cpp
cppa/opt.hpp
src/opt.cpp
cppa/detail/opt_impls.hpp
+examples/type_plugins.hpp
+cppa/detail/decorated_names_map.hpp
+src/decorated_names_map.cpp
View
5 cppa/actor.hpp
@@ -202,6 +202,11 @@ class actor : public channel {
*/
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 *
******************************************************************************/
View
4 cppa/cppa.hpp
@@ -751,9 +751,11 @@ inline void await_all_others_done() {
* The connection is automatically closed if the lifetime of @p whom ends.
* @param whom Actor that should be published at @p 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
*/
-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.
View
57 cppa/detail/decorated_names_map.hpp
@@ -0,0 +1,57 @@
+/******************************************************************************\
+ * ___ __ *
+ * /\_ \ __/\ \ *
+ * \//\ \ /\_\ \ \____ ___ _____ _____ __ *
+ * \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
+ * \_\ \_\ \ \ \ \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
View
5 cppa/detail/default_uniform_type_info_impl.hpp
@@ -319,10 +319,7 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T
}
void deserialize(void* obj, deserializer* d) const {
- std::string cname = d->seek_object();
- if (cname != this->name()) {
- throw std::logic_error("wrong type name found");
- }
+ this->assert_type_name(d);
d->begin_object(this->name());
for (auto& m : m_members) {
m.deserialize(obj, d);
View
3  cppa/detail/ipv4_acceptor.hpp
@@ -42,7 +42,8 @@ class ipv4_acceptor : public util::acceptor {
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();
View
61 cppa/detail/pair_member.hpp
@@ -36,24 +36,24 @@
#include "cppa/serializer.hpp"
#include "cppa/deserializer.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/detail/types_array.hpp"
+#include "cppa/detail/type_to_ptype.hpp"
+
namespace cppa { namespace detail {
-template<typename T1, typename T2>
-class pair_member : public util::abstract_uniform_type_info<std::pair<T1,T2>> {
+template<typename T1, typename T2, bool PrimitiveTypes> // default: true
+struct pair_member_impl {
static constexpr primitive_type ptype1 = type_to_ptype<T1>::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;
- public:
-
void serialize(const void* obj, serializer* s) const {
auto& p = *reinterpret_cast<const pair_type*>(obj);
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>> {
};
+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
#endif // CPPA_PAIR_MEMBER_HPP
View
3  cppa/detail/singleton_manager.hpp
@@ -45,6 +45,7 @@ class group_manager;
class abstract_tuple;
class actor_registry;
class network_manager;
+class decorated_names_map;
class uniform_type_info_map;
class singleton_manager {
@@ -70,6 +71,8 @@ class singleton_manager {
static empty_tuple* get_empty_tuple();
+ static decorated_names_map* get_decorated_names_map();
+
};
} } // namespace cppa::detail
View
5 cppa/group.hpp
@@ -195,11 +195,12 @@ class group : public channel {
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 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
View
14 cppa/uniform_type_info.hpp
@@ -234,8 +234,22 @@ class uniform_type_info {
*/
virtual void deserialize(void* instance, deserializer* source) const = 0;
+ /**
+ * @brief Checks wheter <tt>src->seek_object()</tt>
+ * returns @p tname and throws an exception if not.
+ * @throws std::logic_error
+ */
+ static void assert_type_name(deserializer* src, const std::string& tname);
+
protected:
+ /**
+ * @brief Checks wheter <tt>src->seek_object()</tt>
+ * returns {@link name()} and throws an exception if not.
+ * @throws std::logic_error
+ */
+ void assert_type_name(deserializer* src) const;
+
uniform_type_info(const std::string& uniform_name);
/**
View
11 examples/announce_example_5.cpp
@@ -100,18 +100,13 @@ class tree_type_info : public util::abstract_uniform_type_info<tree> {
}
void deserialize(void* ptr, deserializer* source) const {
- // seek_object() gets the uniform name of the next object in the
- // stream without modifying the deserializer
- 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");
- }
+ // throws an exception if the next object in source is not a tree
+ assert_type_name(source);
// ptr is guaranteed to be a pointer of type tree
auto tree_ptr = reinterpret_cast<tree*>(ptr);
tree_ptr->root.children.clear();
// workflow is analogous to serialize: begin_object() ... end_object()
- source->begin_object(cname);
+ source->begin_object(name());
// recursively deserialize nodes, beginning with root
deserialize_node(tree_ptr->root, source);
source->end_object();
View
241 examples/group_chat.cpp
@@ -1,54 +1,54 @@
#include <set>
#include <map>
#include <vector>
+#include <dlfcn.h>
#include <iostream>
#include <sstream>
#include <time.h>
#include <cstdlib>
+#include "cppa/opt.hpp"
#include "cppa/cppa.hpp"
+#include "type_plugins.hpp"
using namespace std;
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&)>())) {
- 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);
+struct line { string str; };
+
+istream& operator>>(istream& is, line& l) {
+ getline(is, l.str);
+ return is;
}
-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));
+any_tuple s_last_line;
+
+any_tuple split_line(const line& l) {
+ vector<string> result;
+ stringstream strs(l.str);
+ string tmp;
+ while (getline(strs, tmp, ' ')) {
+ 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 {
- string m_username;
- actor_ptr m_printer;
+ public:
+
+ client(const string& name, actor_ptr printer)
+ : m_name(name), m_printer(printer) { }
+
+ protected:
void init() {
become (
- // local commands
on(atom("broadcast"), arg_match) >> [=](const string& message) {
for(auto& dest : joined_groups()) {
- send(dest, m_username + ": " + message);
+ send(dest, m_name + ": " + message);
}
},
on(atom("join"), arg_match) >> [=](const group_ptr& what) {
@@ -62,6 +62,7 @@ class client : public event_based_actor {
}
},
on(atom("quit")) >> [=] {
+ // ignore quit messages from remote actors
auto s = self->last_sender();
if (s->is_proxy()) {
reply("nice try");
@@ -75,14 +76,16 @@ class client : public event_based_actor {
if (last_sender() != this) forward_to(m_printer);
},
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 {
self->quit();
},
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 {
- cout.unsetf(std::ios_base::unitbuf);
-
- auto printer = spawn<print_actor>();
+ // enables this client to print user-defined types
+ // without changing this source code
+ exec_plugin();
string name;
-
- bool args_valid = match_stream<string>(argv + 1, argv + argc) (
- on_opt('n', "name") >> [&](const string& input) -> bool {
- if (!name.empty()) {
- cout << "name already set to " << name << endl;
- return false;
- }
- name = input;
- return true;
- }
+ vector<string> group_ids;
+ options_description desc;
+ bool args_valid = argc > 1 && match_stream<string>(argv + 1, argv + argc) (
+ on_opt('n', "name", &desc, "set name") >> rd_arg(name),
+ on_opt('g', "group", &desc, "join group <arg>") >> add_arg(group_ids),
+ on_vopt('h', "help", &desc, "print help") >> print_desc_and_exit(&desc)
);
- if(!args_valid) {
- print_usage(printer);
- send(printer, atom("quit"));
- await_all_others_done();
- shutdown();
- return 0;
- }
+ if(!args_valid) print_desc_and_exit(&desc)();
+
+ auto printer = spawn<print_actor>();
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;
}
- send(printer, "Starting client.");
+ send(printer, "*** starting client.");
auto client_actor = spawn<client>(name, printer);
- auto get_command = [&]() -> bool {
- string input;
- bool done = false;
- getline(cin, input);
- if (input.size() > 0) {
- if (input.front() == '/') {
- input.erase(input.begin());
- vector<string> values = split(input, ' ');
- match (values) (
- on("send", val<string>, any_vals) >> [&](const string& groupname) {
- if (values.size() < 3) {
- send(printer, "no message to send");
- }
- 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");
- }
- );
+ // evaluate group parameters
+ for (auto& gid : group_ids) {
+ auto p = gid.find(':');
+ if (p == std::string::npos) {
+ cerr << "*** error parsing argument " << gid
+ << ", expected format: <module_name>:<group_id>";
+ }
+ else {
+ try {
+ auto g = group::get(gid.substr(0, p),
+ gid.substr(p + 1));
+ send(client_actor, atom("join"), g);
}
- else {
- send(client_actor, atom("broadcast"), input);
+ catch (exception& e) {
+ 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"));
await_all_others_done();
shutdown();
View
51 examples/group_server.cpp
@@ -1,48 +1,24 @@
#include <string>
+#include <dlfcn.h>
#include <sstream>
#include <iostream>
+
+#include "cppa/opt.hpp"
#include "cppa/cppa.hpp"
+#include "type_plugins.hpp"
using namespace std;
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) {
- 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) (
- on_opt('p', "port") >> [&](const string& arg) -> bool {
- if (!(istringstream(arg) >> port)) {
- cout << "\"" << arg << "\" is not a valid port" << endl;
- return false;
- }
- return true;
- }
+ on_opt('p', "port", &desc, "set port") >> rd_arg(port),
+ on_vopt('h', "help", &desc, "print help") >> print_desc_and_exit(&desc)
);
if (port <= 1024) {
cout << "no port > 1024 given" << endl;
@@ -54,9 +30,8 @@ int main(int argc, char** argv) {
string line;
while (getline(cin, line)) {
if (line == "quit") return 0;
- else {
- cout << "illegal command" << endl;
- }
+ else cout << "illegal command" << endl;
}
+ shutdown();
return 0;
}
View
30 examples/type_plugins.hpp
@@ -0,0 +1,30 @@
+#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
View
125 src/decorated_names_map.cpp
@@ -0,0 +1,125 @@
+/******************************************************************************\
+ * ___ __ *
+ * /\_ \ __/\ \ *
+ * \//\ \ /\_\ \ \____ ___ _____ _____ __ *
+ * \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
+ * \_\ \_\ \ \ \ \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
View
4 src/group.cpp
@@ -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>();
try {
- publish(gn, port);
+ publish(gn, port, addr);
}
catch (std::exception&) {
gn->enqueue(nullptr, make_any_tuple(atom("SHUTDOWN")));
View
12 src/ipv4_acceptor.cpp
@@ -42,6 +42,7 @@
#else
# include <netdb.h>
# include <unistd.h>
+# include <arpa/inet.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <netinet/in.h>
@@ -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)
: 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;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == invalid_socket) {
@@ -112,7 +114,13 @@ std::unique_ptr<util::acceptor> ipv4_acceptor::create(std::uint16_t port) {
struct sockaddr_in serv_addr;
memset((char*) &serv_addr, 0, sizeof(serv_addr));
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);
if (bind(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0) {
throw bind_failure(errno);
View
52 src/middleman.cpp
@@ -58,6 +58,9 @@
using namespace std;
+//#define VERBOSE_MIDDLEMAN
+
+#ifdef VERBOSE_MIDDLEMAN
#define DEBUG(arg) { \
ostringstream oss; \
oss << "[process id: " \
@@ -65,9 +68,9 @@ using namespace std;
<< "] " << arg << endl; \
cout << oss.str(); \
} (void) 0
-
-#undef DEBUG
+#else
#define DEBUG(unused) ((void) 0)
+#endif
namespace cppa { namespace detail {
@@ -235,13 +238,15 @@ class peer_connection : public network_channel {
bool continue_reading();
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()) {
size_t written;
written = m_ostream->write_some(m_wr_buf.data(),
m_wr_buf.size());
if (written != m_wr_buf.size()) {
m_wr_buf.erase_leading(written);
+ DEBUG("only " << written << " bytes written");
}
else {
m_wr_buf.reset();
@@ -257,17 +262,20 @@ class peer_connection : public network_channel {
auto before = m_wr_buf.size();
m_wr_buf.write(sizeof(std::uint32_t), &size, util::grow_if_needed);
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
memcpy(m_wr_buf.data() + before, &size, sizeof(std::uint32_t));
if (!has_unwritten_data()) {
size_t written = m_ostream->write_some(m_wr_buf.data(),
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);
has_unwritten_data(true);
}
else {
+ DEBUG(written << " bytes written");
m_wr_buf.reset();
}
}
@@ -398,6 +406,16 @@ bool peer_connection::continue_reading() {
memcpy(node_id.data(), m_rd_buf.data() + sizeof(uint32_t),
process_information::node_id_size);
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);
// initialization done
m_rd_state = wait_for_msg_size;
@@ -698,6 +716,17 @@ void middleman::operator()(int pipe_fd, middleman_queue& queue) {
maxfd = max(maxfd, fd);
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 (wrset_ptr) wrset_ptr = nullptr;
}
@@ -714,8 +743,17 @@ void middleman::operator()(int pipe_fd, middleman_queue& queue) {
auto continue_reading = [&](const network_channel_ptr& ch) {
bool erase_channel = false;
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) {
- DEBUG(demangle(typeid(e).name()) << ": " << e.what());
+ DEBUG(demangle(typeid(e)) << ": " << e.what());
erase_channel = true;
}
if (erase_channel) {
@@ -725,7 +763,9 @@ void middleman::operator()(int pipe_fd, middleman_queue& queue) {
};
auto continue_writing = [&](const peer_connection_ptr& peer) {
bool erase_channel = false;
- try { erase_channel = !peer->continue_writing(); }
+ try {
+ erase_channel = !peer->continue_writing();
+ }
catch (exception& e) {
DEBUG(demangle(typeid(e).name()) << ": " << e.what());
erase_channel = true;
View
8 src/self.cpp
@@ -100,6 +100,14 @@ void tss_reset(local_actor* ptr, bool inc_ref_count = true) {
} // 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) {
if (what) {
auto ptr = dynamic_cast<thread_mapped_actor*>(what);
View
8 src/singleton_manager.cpp
@@ -43,6 +43,7 @@
#include "cppa/detail/actor_registry.hpp"
#include "cppa/detail/network_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/uniform_type_info_map.hpp"
@@ -57,6 +58,7 @@ using namespace cppa::detail;
//volatile uniform_type_info_map* s_uniform_type_info_map = 0;
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<actor_registry*> s_actor_registry;
std::atomic<group_manager*> s_group_manager;
@@ -121,6 +123,8 @@ void shutdown() {
s_empty_tuple = nullptr;
delete s_uniform_type_info_map.load();
s_uniform_type_info_map = nullptr;
+ delete s_decorated_names_map.load();
+ s_decorated_names_map = nullptr;
}
} // namespace cppa
@@ -143,6 +147,10 @@ scheduler* singleton_manager::get_scheduler() {
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) {
scheduler* expected = nullptr;
if (s_scheduler.compare_exchange_weak(expected, ptr)) {
View
149 src/string_serialization.cpp
@@ -29,7 +29,9 @@
#include <stack>
+#include <cctype>
#include <sstream>
+#include <iomanip>
#include <algorithm>
#include "cppa/atom.hpp"
@@ -41,26 +43,28 @@
#include "cppa/primitive_variant.hpp"
#include "cppa/uniform_type_info.hpp"
+using namespace std;
+
namespace cppa {
namespace {
class string_serializer : public serializer {
- std::ostream& out;
+ ostream& out;
struct pt_writer {
- std::ostream& out;
+ ostream& out;
- pt_writer(std::ostream& mout) : out(mout) { }
+ pt_writer(ostream& mout) : out(mout) { }
template<typename T>
void operator()(const T& value) {
out << value;
}
- void operator()(const std::string& str) {
+ void operator()(const string& str) {
out << "\"";// << str << "\"";
for (char c : str) {
if (c == '"') out << "\\\"";
@@ -69,15 +73,15 @@ class string_serializer : public serializer {
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_obj_just_opened;
- std::stack<std::string> m_open_objects;
+ stack<string> m_open_objects;
inline void clear() {
if (m_after_value) {
@@ -92,11 +96,11 @@ class string_serializer : public serializer {
public:
- string_serializer(std::ostream& mout)
+ string_serializer(ostream& mout)
: 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();
m_open_objects.push(type_name);
out << type_name;// << " ( ";
@@ -129,14 +133,14 @@ class string_serializer : public serializer {
void write_value(const primitive_variant& value) {
clear();
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 (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
- 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));
}
else {
@@ -155,33 +159,41 @@ class string_serializer : public serializer {
out << (m_after_value ? " }" : "}");
}
- void write_raw(size_t, const void*) {
- throw std::runtime_error("string_serializer::write_raw: "
- "not implemented yet");
+ void write_raw(size_t num_bytes, const void* buf) {
+ clear();
+ 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 {
- std::string m_str;
- std::string::iterator m_pos;
+ string m_str;
+ string::iterator m_pos;
//size_t m_obj_count;
- std::stack<bool> m_obj_had_left_parenthesis;
- std::stack<std::string> m_open_objects;
+ stack<bool> m_obj_had_left_parenthesis;
+ stack<string> m_open_objects;
void skip_space_and_comma() {
while (*m_pos == ' ' || *m_pos == ',') ++m_pos;
}
- void throw_malformed(const std::string& error_msg) {
- throw std::logic_error("malformed string: " + error_msg);
+ void throw_malformed(const string& error_msg) {
+ throw logic_error("malformed string: " + error_msg);
}
void consume(char c) {
skip_space_and_comma();
if (*m_pos != c) {
- std::string error;
+ string error;
error += "expected '";
error += c;
error += "' found '";
@@ -205,8 +217,8 @@ class string_deserializer : public deserializer {
return false;
}
- inline std::string::iterator next_delimiter() {
- return std::find_if(m_pos, m_str.end(), [] (char c) -> bool {
+ inline string::iterator next_delimiter() {
+ return find_if(m_pos, m_str.end(), [] (char c) -> bool {
switch (c) {
case '(':
case ')':
@@ -235,33 +247,33 @@ class string_deserializer : public deserializer {
public:
- string_deserializer(const std::string& str) : m_str(str) {
+ string_deserializer(const string& str) : m_str(str) {
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();
}
- std::string seek_object() {
+ string seek_object() {
skip_space_and_comma();
auto substr_end = next_delimiter();
if (m_pos == substr_end) {
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;
return result;
}
- std::string peek_object() {
- std::string result = seek_object();
+ string peek_object() {
+ string result = seek_object();
// restore position in stream
m_pos -= result.size();
return result;
}
- void begin_object(const std::string& type_name) {
+ void begin_object(const string& type_name) {
m_open_objects.push(type_name);
//++m_obj_count;
skip_space_and_comma();
@@ -280,7 +292,7 @@ class string_deserializer : public deserializer {
m_obj_had_left_parenthesis.pop();
}
if (m_open_objects.empty()) {
- throw std::runtime_error("no object to end");
+ throw runtime_error("no object to end");
}
m_open_objects.pop();
if (m_open_objects.empty()) {
@@ -294,7 +306,7 @@ class string_deserializer : public deserializer {
size_t begin_sequence() {
integrity_check();
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() {
@@ -303,18 +315,18 @@ class string_deserializer : public deserializer {
}
struct from_string {
- const std::string& str;
- from_string(const std::string& s) : str(s) { }
+ const string& str;
+ from_string(const string& s) : str(s) { }
template<typename T>
void operator()(T& what) {
- std::istringstream s(str);
+ istringstream s(str);
s >> what;
}
- void operator()(std::string& what) {
+ void operator()(string& what) {
what = str;
}
- void operator()(std::u16string&) { }
- void operator()(std::u32string&) { }
+ void operator()(u16string&) { }
+ void operator()(u32string&) { }
};
primitive_variant read_value(primitive_type ptype) {
@@ -323,14 +335,14 @@ class string_deserializer : public deserializer {
if (ptype != pt_uint64) {
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) {
throw_malformed("atom string size > 10");
}
return detail::atom_val(str_val.c_str());
}
skip_space_and_comma();
- std::string::iterator substr_end;
+ string::iterator substr_end;
auto find_if_cond = [] (char c) -> bool {
switch (c) {
case ')':
@@ -352,28 +364,28 @@ class string_deserializer : public deserializer {
last_char = c;
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 {
- 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 {
- 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()) {
- 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();
if (ptype == pt_u8string) {
// skip trailing "
if (*m_pos != '"') {
- std::string error_msg;
+ string error_msg;
error_msg = "malformed string, expected '\"' found '";
error_msg += *m_pos;
error_msg += "'";
- throw std::logic_error(error_msg);
+ throw logic_error(error_msg);
}
++m_pos;
// replace '\"' by '"'
@@ -385,12 +397,12 @@ class string_deserializer : public deserializer {
last_char = c;
return false;
};
- std::string tmp;
+ string tmp;
auto sbegin = substr.begin();
auto send = substr.end();
- for (auto i = std::find_if(sbegin, send, cond);
+ for (auto i = find_if(sbegin, send, cond);
i != send;
- i = std::find_if(i, send, cond)) {
+ i = find_if(i, send, cond)) {
--i;
tmp.append(sbegin, i);
tmp += '"';
@@ -401,7 +413,7 @@ class string_deserializer : public deserializer {
tmp.append(sbegin, send);
}
if (!tmp.empty()) {
- substr = std::move(tmp);
+ substr = move(tmp);
}
}
primitive_variant result(ptype);
@@ -416,35 +428,50 @@ class string_deserializer : public deserializer {
consume('{');
const primitive_type* end = begin + size;
for ( ; begin != end; ++begin) {
- *storage = std::move(read_value(*begin));
+ *storage = move(read_value(*begin));
++storage;
}
consume('}');
}
- void read_raw(size_t, void*) {
- throw std::runtime_error("string_deserializer::read_raw: "
- "not implemented yet");
+ void read_raw(size_t buf_size, void* vbuf) {
+ auto buf = reinterpret_cast<unsigned char*>(vbuf);
+ 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>
-object from_string(const std::string& what) {
+object from_string(const string& what) {
string_deserializer strd(what);
- std::string uname = strd.peek_object();
+ string uname = strd.peek_object();
auto utype = uniform_type_info::from(uname);
if (utype == nullptr) {
- throw std::logic_error(uname + " is not announced");
+ throw logic_error(uname + " is not announced");
}
return utype->deserialize(&strd);
}
namespace detail {
-std::string to_string_impl(const void *what, const uniform_type_info *utype) {
- std::ostringstream osstr;
+string to_string_impl(const void *what, const uniform_type_info *utype) {
+ ostringstream osstr;
string_serializer strs(osstr);
utype->serialize(what, &strs);
return osstr.str();
View
2  src/thread_mapped_actor.cpp
@@ -43,7 +43,7 @@
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)
: super(std::move(fun)), m_initialized(false) { }
View
294 src/to_uniform_name.cpp
@@ -48,6 +48,8 @@
#include "cppa/detail/demangle.hpp"
#include "cppa/detail/to_uniform_name.hpp"
#include "cppa/detail/addressed_message.hpp"
+#include "cppa/detail/singleton_manager.hpp"
+#include "cppa/detail/decorated_names_map.hpp"
namespace {
@@ -55,171 +57,157 @@ using namespace std;
using namespace cppa;
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>
-inline string demangled() {
- return demangle(typeid(T));
-}
+class parse_tree {
-template<typename T>
-constexpr const char* mapped_int_name() {
- return mapped_int_names[sizeof(T)][sign_index<T>()];
-}
+ public:
-template<typename Iterator>
-string to_uniform_name_impl(Iterator begin, Iterator end,
- bool first_run = false) {
- // all integer type names as uniform representation
- static map<string, string> mapped_demangled_names = {
- // 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>() },
- // 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;
+ string compile() const {
+ string result;
+ if (m_volatile) result += "volatile ";
+ if (m_const) result += "const ";
+ if (!m_template) {
+ result += dmm->decorate(m_name);
}
+ 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?
- if (begin == end) return "";
- // 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) {
+ template<typename Iterator>
+ static vector<parse_tree> parse_tpl_args(Iterator first, Iterator last);
- case '<':
- ++open_brackets;
- ++i;
- break;
-
- case '>':
- if (--open_brackets < 0) {
- throw runtime_error("malformed string");
- }
- ++i;
- break;
-
- case ',':
- if (open_brackets == 0) {
- substrings.push_back(make_pair(anchor, i));
- ++i;
- anchor = i;
+ template<typename Iterator>
+ static parse_tree parse(Iterator first, Iterator last) {
+ typedef reverse_iterator<Iterator> rev_iter;
+ auto sub_first = find(first, last, '<');
+ auto sub_last = find(rev_iter(last), rev_iter(first), '>').base() - 1;
+ if (sub_last < sub_first) {
+ sub_first = sub_last = last;
+ }
+ auto islegal = [](char c) { return isalnum(c) || c == ':' || c == '_'; };
+ vector<string> tokens;
+ tokens.push_back("");
+ for (auto i = first; i != last;) {
+ if (i == sub_first) {
+ tokens.push_back("");
+ i = sub_last;
}
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;
}
- break;
-
- default:
- ++i;
- break;
-
}
- }
- // call recursively for each list argument
- if (!substrings.empty()) {
- string result;
- substrings.push_back(make_pair(anchor, end));
- for (const subseq& sstr : substrings) {
- if (!result.empty()) result += ",";
- result += to_uniform_name_impl(sstr.first, sstr.second);
+ parse_tree result;
+ if (sub_first != sub_last) {
+ result.m_template = true;
+ result.m_template_parameters = parse_tpl_args(sub_first + 1, sub_last);
+ }
+ for (auto& token: tokens) {
+ if (token == "const") {
+ 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;
}
- // we didn't got a list, compute unify name
- else {
- // is [begin, end) a template?
- Iterator substr_begin = find(begin, end, '<');
- if (substr_begin == end) {
- // not a template, return mapping
- string arg(begin, end);
- auto mapped = mapped_demangled_names.find(arg);
- return (mapped == mapped_demangled_names.end()) ? arg : mapped->second;
- }
- // skip leading '<'
- ++substr_begin;
- // find trailing '>'
- Iterator substr_end = find(reverse_iterator(end),
- reverse_iterator(substr_begin),
- '>')
- // get as an Iterator
- .base();
- // skip trailing '>'
- --substr_end;
- if (substr_end == substr_begin) {
- throw runtime_error("substr_end == substr_begin");
+
+ private:
+
+ parse_tree()
+ : m_const(false), m_pointer(false), m_volatile(false), m_template(false)
+ , m_lvalue_ref(false), m_rvalue_ref(false) {
+ dmm = singleton_manager::get_decorated_names_map();
+ }
+
+ bool m_const;
+ bool m_pointer;
+ bool m_volatile;
+ bool m_template;
+ bool m_lvalue_ref;
+ bool m_rvalue_ref;
+ const decorated_names_map* dmm;
+
+ string m_name;
+ vector<parse_tree> m_template_parameters;
+
+};
+
+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>
@@ -232,11 +220,7 @@ void replace_all(string& str, const char (&before)[RawSize], const char* after)
}
}
-const char s_rawstr[] =
-"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_rawan[] = "anonymous namespace";
const char s_an[] = "@_";
} // namespace <anonymous>
@@ -244,8 +228,8 @@ const char s_an[] = "@_";
namespace cppa { namespace detail {
std::string to_uniform_name(const std::string& dname) {
- auto r = to_uniform_name_impl(dname.begin(), dname.end(), true);
- replace_all(r, s_rawstr, s_str);
+ auto r = parse_tree::parse(begin(dname), end(dname)).compile();
+ // replace compiler-dependent "anonmyous namespace" with "@_"
replace_all(r, s_rawan, s_an);
return r;
}
View
16 src/unicast_network.cpp
@@ -57,10 +57,6 @@
#include "cppa/detail/actor_proxy_cache.hpp"
#include "cppa/detail/singleton_manager.hpp"
-
-using std::cout;
-using std::endl;
-
namespace cppa {
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) {
peer.first->read(&peer_pid, sizeof(std::uint32_t));
peer.first->read(peer_node_id.data(), peer_node_id.size());
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());
detail::middleman_add_peer(peer, pinfptr);
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) {
pinfptr->node_id());
}
-void publish(actor_ptr whom, std::uint16_t port) {
- if (whom) publish(whom, detail::ipv4_acceptor::create(port));
+void publish(actor_ptr whom, std::uint16_t port, const char* addr) {
+ if (whom) publish(whom, detail::ipv4_acceptor::create(port, addr));
}
actor_ptr remote_actor(const char* host, std::uint16_t port) {
View
186 src/uniform_type_info.cpp
@@ -66,11 +66,13 @@ namespace cppa { namespace detail {
namespace {
+using namespace std;
+
inline uniform_type_info_map& uti_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
return tinfo.raw_name();
#else
@@ -79,24 +81,20 @@ inline const char* raw_name(const std::type_info& tinfo) {
}
template<typename T>
-struct is_signed :
- std::integral_constant<bool, std::numeric_limits<T>::is_signed> { };
-
-template<typename T>
inline const char* raw_name() {
return raw_name(typeid(T));
}
-typedef std::set<std::string> string_set;
-typedef std::map<int, std::pair<string_set, string_set> > int_name_mapping;
+typedef set<string> string_set;
+typedef map<int, pair<string_set, string_set> > int_name_mapping;
template<typename Int>
-inline void push_impl(int_name_mapping& ints, std::true_type) {
+inline void push_impl(int_name_mapping& ints, true_type) {
ints[sizeof(Int)].first.insert(raw_name<Int>()); // signed version
}
template<typename Int>
-inline void push_impl(int_name_mapping& ints, std::false_type) {
+inline void push_impl(int_name_mapping& ints, false_type) {
ints[sizeof(Int)].second.insert(raw_name<Int>()); // unsigned version
}
@@ -111,7 +109,7 @@ inline void push(int_name_mapping& 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) {
sink->begin_object(s_nullptr_type_name);
@@ -131,7 +129,7 @@ class void_type_tinfo : public uniform_type_info {
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;
}
@@ -142,9 +140,9 @@ class void_type_tinfo : public uniform_type_info {
}
void deserialize(void*, deserializer* source) const {
- std::string cname = source->seek_object();
+ string cname = source->seek_object();
if (cname != name()) {
- throw std::logic_error("wrong type name found");
+ throw logic_error("wrong type name found");
}
deserialize_nullptr(source);
}
@@ -176,7 +174,7 @@ class actor_ptr_tinfo : public util::abstract_uniform_type_info<actor_ptr> {
static void s_serialize(const actor_ptr& ptr,
serializer* sink,
- const std::string& name) {
+ const string& name) {
if (ptr == nullptr) {
serialize_nullptr(sink);
}
@@ -196,16 +194,14 @@ class actor_ptr_tinfo : public util::abstract_uniform_type_info<actor_ptr> {
static void s_deserialize(actor_ptr& ptrref,
deserializer* source,
- const std::string& name) {
- std::string cname = source->seek_object();
+ const string& name) {
+ auto cname = source->seek_object();
if (cname != name) {
if (cname == s_nullptr_type_name) {
deserialize_nullptr(source);
ptrref.reset();
}
- else {
- throw std::logic_error("wrong type name found");
- }
+ else assert_type_name(source, name); // throws
}
else {
primitive_variant ptup[3];
@@ -213,28 +209,28 @@ class actor_ptr_tinfo : public util::abstract_uniform_type_info<actor_ptr> {
source->begin_object(cname);
source->read_tuple(3, ptypes, ptup);
source->end_object();
- const std::string& nstr = get<std::string>(ptup[2]);
+ const string& nstr = get<string>(ptup[2]);
// local actor?
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())) {
- auto id = get<std::uint32_t>(ptup[0]);
+ auto id = get<uint32_t>(ptup[0]);
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 {
/*
actor_proxy_cache::key_tuple key;
- std::get<0>(key) = get<std::uint32_t>(ptup[0]);
- std::get<1>(key) = get<std::uint32_t>(ptup[1]);
- node_id_from_string(nstr, std::get<2>(key));
+ get<0>(key) = get<uint32_t>(ptup[0]);
+ get<1>(key) = get<uint32_t>(ptup[1]);
+ node_id_from_string(nstr, get<2>(key));
ptrref = detail::get_actor_proxy_cache().get(key);
*/
process_information::node_id_type nid;
node_id_from_string(nstr, nid);
auto& cache = detail::get_actor_proxy_cache();
- ptrref = cache.get_or_put(get<std::uint32_t>(ptup[0]),
- get<std::uint32_t>(ptup[1]),
+ ptrref = cache.get_or_put(get<uint32_t>(ptup[0]),
+ get<uint32_t>(ptup[1]),
nid);
}
}
@@ -258,7 +254,7 @@ class group_ptr_tinfo : public util::abstract_uniform_type_info<group_ptr> {
static void s_serialize(const group_ptr& ptr,
serializer* sink,
- const std::string& name) {
+ const string& name) {
if (ptr == nullptr) {
serialize_nullptr(sink);
}
@@ -272,21 +268,19 @@ class group_ptr_tinfo : public util::abstract_uniform_type_info<group_ptr> {
static void s_deserialize(group_ptr& ptrref,
deserializer* source,
- const std::string& name) {
- std::string cname = source->seek_object();
+ const string& name) {
+ auto cname = source->seek_object();
if (cname != name) {
if (cname == s_nullptr_type_name) {
deserialize_nullptr(source);
ptrref.reset();
}
- else {
- throw std::logic_error("wrong type name found");
- }
+ else assert_type_name(source, name); // throws
}
else {
source->begin_object(name);
auto modname = source->read_value(pt_u8string);
- ptrref = group::get_module(get<std::string>(modname))
+ ptrref = group::get_module(get<string>(modname))
->deserialize(source);
source->end_object();
}
@@ -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> {
- std::string group_ptr_name;
- std::string actor_ptr_name;
+ string group_ptr_name;
+ string actor_ptr_name;
public:
static void s_serialize(const channel_ptr& ptr,
serializer* sink,
- const std::string& channel_type_name,
- const std::string& actor_ptr_type_name,
- const std::string& group_ptr_type_name) {
+ const string& channel_type_name,
+ const string& actor_ptr_type_name,
+ const string& group_ptr_type_name) {
sink->begin_object(channel_type_name);
if (ptr == nullptr) {
serialize_nullptr(sink);
@@ -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);
}
else {
- throw std::logic_error("channel is neither "
+ throw logic_error("channel is neither "
"an actor nor a group");
}
}
@@ -341,15 +335,12 @@ class channel_ptr_tinfo : public util::abstract_uniform_type_info<channel_ptr> {
static void s_deserialize(channel_ptr& ptrref,
deserializer* source,
- const std::string& name,
- const std::string& actor_ptr_type_name,
- const std::string& group_ptr_type_name) {
- std::string cname = source->seek_object();
- if (cname != name) {
- throw std::logic_error("wrong type name found");
- }
- source->begin_object(cname);
- std::string subobj = source->peek_object();
+ const string& name,
+ const string& actor_ptr_type_name,
+ const string& group_ptr_type_name) {
+ assert_type_name(source, name);
+ source->begin_object(name);
+ string subobj = source->peek_object();
if (subobj == actor_ptr_type_name) {
actor_ptr tmp;
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> {
ptrref.reset();
}
else {
- throw std::logic_error("unexpected type name: " + subobj);
+ throw logic_error("unexpected type name: " + subobj);
}
source->end_object();
}
@@ -401,7 +392,7 @@ class any_tuple_tinfo : public util::abstract_uniform_type_info<any_tuple> {
static void s_serialize(const any_tuple& atup,
serializer* sink,
- const std::string& name) {
+ const string& name) {
sink->begin_object(name);
sink->begin_sequence(atup.size());
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> {