Commit f6d2a84c authored by Dominik Charousset's avatar Dominik Charousset

Remove automated demangling, close #205

CAF no longer automatically tries to demangle platform-dependent type name
representations as returned by `typeid(...).name()`. Although this is a nice
convenience feature in theory, there are to many issues attached to it,
including broken ABI versions on some platforms. Instead of automatically
computing the uniform type name at runtime, users of CAF now need to pass it to
`announce`. This is a breaking change, as the signature of `announce` has been
changed to take a string as first argument.
parent e314976b
......@@ -80,9 +80,10 @@ void tester(event_based_actor* self, const calculator_type& testee) {
int main() {
// announce custom message types
announce<shutdown_request>();
announce<plus_request>(&plus_request::a, &plus_request::b);
announce<minus_request>(&minus_request::a, &minus_request::b);
announce<shutdown_request>("shutdown_request");
announce<plus_request>("plus_request", &plus_request::a, &plus_request::b);
announce<minus_request>("minus_request", &minus_request::a,
&minus_request::b);
// test function-based impl
spawn(tester, spawn_typed(typed_calculator));
await_all_actors_done();
......
......@@ -77,11 +77,11 @@ int main(int, char**) {
// announces foo to the libcaf type system;
// the function expects member pointers to all elements of foo
announce<foo>(&foo::a, &foo::b);
announce<foo>("foo", &foo::a, &foo::b);
// announce foo2 to the libcaf type system,
// note that recursive containers are managed automatically by libcaf
announce<foo2>(&foo2::a, &foo2::b);
announce<foo2>("foo2", &foo2::a, &foo2::b);
foo2 vd;
vd.a = 5;
......@@ -98,17 +98,11 @@ int main(int, char**) {
assert(vd == vd2);
// announce std::pair<int, int> to the type system;
// NOTE: foo_pair is NOT distinguishable from foo_pair2!
auto uti = announce<foo_pair>(&foo_pair::first, &foo_pair::second);
// since foo_pair and foo_pair2 are not distinguishable since typedefs
// do not 'create' an own type, this announce fails, since
// std::pair<int, int> is already announced
assert(announce<foo_pair2>(&foo_pair2::first, &foo_pair2::second) == uti);
// announce std::pair<int, int> to the type system
announce<foo_pair>("foo_pair", &foo_pair::first, &foo_pair::second);
// libcaf returns the same uniform_type_info
// instance for foo_pair and foo_pair2
// instance for the type aliases foo_pair and foo_pair2
assert(uniform_typeid<foo_pair>() == uniform_typeid<foo_pair2>());
// spawn a testee that receives two messages
......@@ -124,4 +118,3 @@ int main(int, char**) {
shutdown();
return 0;
}
......@@ -54,8 +54,8 @@ void testee(event_based_actor* self) {
int main(int, char**) {
// if a class uses getter and setter member functions,
// we pass those to the announce function as { getter, setter } pairs.
announce<foo>(make_pair(&foo::a, &foo::set_a),
make_pair(&foo::b, &foo::set_b));
announce<foo>("foo", make_pair(&foo::a, &foo::set_a),
make_pair(&foo::b, &foo::set_b));
{
scoped_actor self;
auto t = spawn(testee);
......
......@@ -68,14 +68,15 @@ int main(int, char**) {
foo_setter s2 = &foo::b;
// equal to example 3
announce<foo>(make_pair(g1, s1), make_pair(g2, s2));
announce<foo>("foo", make_pair(g1, s1), make_pair(g2, s2));
// alternative syntax that uses casts instead of variables
// (returns false since foo is already announced)
announce<foo>(make_pair(static_cast<foo_getter>(&foo::a),
static_cast<foo_setter>(&foo::a)),
make_pair(static_cast<foo_getter>(&foo::b),
static_cast<foo_setter>(&foo::b)));
announce<foo>("foo",
make_pair(static_cast<foo_getter>(&foo::a),
static_cast<foo_setter>(&foo::a)),
make_pair(static_cast<foo_getter>(&foo::b),
static_cast<foo_setter>(&foo::b)));
// spawn a new testee and send it a foo
{
......
......@@ -108,23 +108,20 @@ int main(int, char**) {
// it takes a pointer to the non-trivial member as first argument
// followed by all "sub-members" either as member pointer or
// { getter, setter } pair
announce<bar>(compound_member(&bar::f,
make_pair(&foo::a, &foo::set_a),
make_pair(&foo::b, &foo::set_b)),
&bar::i);
auto meta_bar_f = [] {
return compound_member(&bar::f,
make_pair(&foo::a, &foo::set_a),
make_pair(&foo::b, &foo::set_b));
};
// with meta_bar_f, we can now announce bar
announce<bar>("bar", meta_bar_f(), &bar::i);
// baz has non-trivial data members with getter/setter pair
// and getter returning a mutable reference
announce<baz>(compound_member(make_pair(&baz::f, &baz::set_f),
make_pair(&foo::a, &foo::set_a),
make_pair(&foo::b, &foo::set_b)),
// compound member that has a compound member
compound_member(&baz::b,
compound_member(&bar::f,
make_pair(&foo::a, &foo::set_a),
make_pair(&foo::b, &foo::set_b)),
&bar::i));
announce<baz>("baz", compound_member(make_pair(&baz::f, &baz::set_f),
make_pair(&foo::a, &foo::set_a),
make_pair(&foo::b, &foo::set_b)),
// compound member that has a compound member
compound_member(&baz::b, meta_bar_f(), &bar::i));
// spawn a testee that receives two messages
auto t = spawn(testee, 2);
{
......
......@@ -86,9 +86,12 @@ bool operator==(const tree& lhs, const tree& rhs) {
// - does have a copy constructor
// - does provide operator==
class tree_type_info : public detail::abstract_uniform_type_info<tree> {
public:
tree_type_info() : detail::abstract_uniform_type_info<tree>("tree") {
// nop
}
protected:
void serialize(const void* ptr, serializer* sink) const {
// ptr is guaranteed to be a pointer of type tree
auto tree_ptr = reinterpret_cast<const tree*>(ptr);
......@@ -105,7 +108,6 @@ class tree_type_info : public detail::abstract_uniform_type_info<tree> {
}
private:
void serialize_node(const tree_node& node, serializer* sink) const {
// value, ... children ...
sink->write_value(node.value);
......@@ -127,7 +129,6 @@ class tree_type_info : public detail::abstract_uniform_type_info<tree> {
}
source->end_sequence();
}
};
using tree_vector = std::vector<tree>;
......@@ -202,7 +203,7 @@ int main() {
self->send(t, t0);
// send a vector of trees
announce<tree_vector>();
announce<tree_vector>("tree_vector");
tree_vector tvec;
tvec.push_back(t0);
tvec.push_back(t0);
......
......@@ -38,7 +38,6 @@ set (LIBCAF_CORE_SRCS
src/continue_helper.cpp
src/decorated_tuple.cpp
src/default_attachable.cpp
src/demangle.cpp
src/deserializer.cpp
src/duration.cpp
src/event_based_actor.cpp
......@@ -73,7 +72,6 @@ set (LIBCAF_CORE_SRCS
src/string_algorithms.cpp
src/string_serialization.cpp
src/sync_request_bouncer.cpp
src/to_uniform_name.cpp
src/uniform_type_info.cpp
src/uniform_type_info_map.cpp)
......
......@@ -79,8 +79,8 @@ namespace caf {
*/
/**
* Adds a new mapping to the type system. Returns `false` if a mapping
* for `tinfo` already exists, otherwise `true`.
* Adds a new mapping to the type system. Returns `utype.get()` on
* success, otherwise a pointer to the previously installed singleton.
* @warning `announce` is **not** thead-safe!
*/
const uniform_type_info* announce(const std::type_info& tinfo,
......@@ -95,7 +95,7 @@ const uniform_type_info* announce(const std::type_info& tinfo,
template <class C, class Parent, class... Ts>
std::pair<C Parent::*, detail::abstract_uniform_type_info<C>*>
compound_member(C Parent::*c_ptr, const Ts&... args) {
return {c_ptr, new detail::default_uniform_type_info<C>(args...)};
return {c_ptr, new detail::default_uniform_type_info<C>("???", args...)};
}
// deals with getter returning a mutable reference
......@@ -108,7 +108,7 @@ compound_member(C Parent::*c_ptr, const Ts&... args) {
template <class C, class Parent, class... Ts>
std::pair<C& (Parent::*)(), detail::abstract_uniform_type_info<C>*>
compound_member(C& (Parent::*getter)(), const Ts&... args) {
return {getter, new detail::default_uniform_type_info<C>(args...)};
return {getter, new detail::default_uniform_type_info<C>("???", args...)};
}
// deals with getter/setter pair
......@@ -126,16 +126,17 @@ compound_member(const std::pair<GRes (Parent::*)() const,
SRes (Parent::*)(SArg)>& gspair,
const Ts&... args) {
using mtype = typename std::decay<GRes>::type;
return {gspair, new detail::default_uniform_type_info<mtype>(args...)};
return {gspair, new detail::default_uniform_type_info<mtype>("???", args...)};
}
/**
* Adds a new type mapping for `C` to the type system.
* Adds a new type mapping for `C` to the type system
* using `tname` as its uniform name.
* @warning `announce` is **not** thead-safe!
*/
template <class C, class... Ts>
inline const uniform_type_info* announce(const Ts&... args) {
auto ptr = new detail::default_uniform_type_info<C>(args...);
inline const uniform_type_info* announce(std::string tname, const Ts&... args) {
auto ptr = new detail::default_uniform_type_info<C>(std::move(tname), args...);
return announce(typeid(C), uniform_type_info_ptr{ptr});
}
......
......@@ -26,7 +26,6 @@
#include "caf/detail/type_traits.hpp"
#include "caf/detail/to_uniform_name.hpp"
#include "caf/detail/uniform_type_info_map.hpp"
namespace caf {
......@@ -61,13 +60,8 @@ class abstract_uniform_type_info : public uniform_type_info {
protected:
abstract_uniform_type_info() {
auto uname = detail::to_uniform_name<T>();
auto cname = detail::mapped_name_by_decorated_name(uname.c_str());
if (cname == uname.c_str())
m_name = std::move(uname);
else
m_name = cname;
abstract_uniform_type_info(std::string tname) {
m_name = detail::mapped_name_by_decorated_name(std::move(tname));
}
static inline const T& deref(const void* ptr) {
......
......@@ -248,16 +248,22 @@ template <class T, class AccessPolicy,
bool IsEmptyType = std::is_class<T>::value&& std::is_empty<T>::value>
class member_tinfo : public detail::abstract_uniform_type_info<T> {
public:
using super = detail::abstract_uniform_type_info<T>;
member_tinfo(AccessPolicy apol, SerializePolicy spol)
: m_apol(std::move(apol)), m_spol(std::move(spol)) {
: super("--member--"),
m_apol(std::move(apol)), m_spol(std::move(spol)) {
// nop
}
member_tinfo(AccessPolicy apol) : m_apol(std::move(apol)) {
member_tinfo(AccessPolicy apol)
: super("--member--"),
m_apol(std::move(apol)) {
// nop
}
member_tinfo() = default;
member_tinfo() : super("--member--") {
// nop
}
void serialize(const void* vptr, serializer* s) const override {
m_spol(m_apol(vptr), s);
......@@ -289,15 +295,19 @@ template <class T, class A, class S>
class member_tinfo<T, A, S, false, true>
: public detail::abstract_uniform_type_info<T> {
public:
member_tinfo(const A&, const S&) {
using super = detail::abstract_uniform_type_info<T>;
member_tinfo(const A&, const S&) : super("--member--") {
// nop
}
member_tinfo(const A&) {
member_tinfo(const A&) : super("--member--") {
// nop
}
member_tinfo() = default;
member_tinfo() : super("--member--") {
// nop
}
void serialize(const void*, serializer*) const override {
// nop
......@@ -312,14 +322,24 @@ template <class T, class AccessPolicy, class SerializePolicy>
class member_tinfo<T, AccessPolicy, SerializePolicy, true, false>
: public detail::abstract_uniform_type_info<T> {
public:
using super = detail::abstract_uniform_type_info<T>;
using value_type = typename std::underlying_type<T>::type;
member_tinfo(AccessPolicy apol, SerializePolicy spol)
: m_apol(std::move(apol)), m_spol(std::move(spol)) {}
: super("--member--"),
m_apol(std::move(apol)), m_spol(std::move(spol)) {
// nop
}
member_tinfo(AccessPolicy apol) : m_apol(std::move(apol)) {}
member_tinfo(AccessPolicy apol)
: super("--member--"),
m_apol(std::move(apol)) {
// nop
}
member_tinfo() = default;
member_tinfo() : super("--member--") {
// nop
}
void serialize(const void* p, serializer* s) const override {
auto val = m_apol(p);
......@@ -453,12 +473,15 @@ uniform_type_info_ptr new_member_tinfo(GRes (C::*getter)() const,
template <class T>
class default_uniform_type_info : public detail::abstract_uniform_type_info<T> {
public:
using super = detail::abstract_uniform_type_info<T>;
template <class... Ts>
default_uniform_type_info(Ts&&... args) {
default_uniform_type_info(std::string tname, Ts&&... args)
: super(std::move(tname)) {
push_back(std::forward<Ts>(args)...);
}
default_uniform_type_info() {
default_uniform_type_info(std::string tname) : super(std::move(tname)) {
using result_type = member_tinfo<T, fake_access_policy<T>>;
m_members.push_back(uniform_type_info_ptr(new result_type));
}
......@@ -552,9 +575,10 @@ template <class... Rs>
class default_uniform_type_info<typed_actor<Rs...>> :
public detail::abstract_uniform_type_info<typed_actor<Rs...>> {
public:
using super = detail::abstract_uniform_type_info<typed_actor<Rs...>>;
using handle_type = typed_actor<Rs...>;
default_uniform_type_info() {
default_uniform_type_info(std::string tname) : super(std::move(tname)) {
sub_uti = uniform_typeid<actor>();
}
......
......@@ -29,7 +29,6 @@
#include "caf/to_string.hpp"
#include "caf/abstract_actor.hpp"
#include "caf/detail/demangle.hpp"
#include "caf/detail/singletons.hpp"
#include "caf/detail/scope_guard.hpp"
......@@ -184,7 +183,7 @@ inline caf::actor_id caf_set_aid_dummy() { return 0; }
caf::detail::singletons::get_logger()->set_aid(aid_arg)
#endif
#define CAF_CLASS_NAME caf::detail::demangle(typeid(decltype(*this))).c_str()
#define CAF_CLASS_NAME typeid(*this).name()
#define CAF_PRINT0(lvlname, classname, funname, msg) \
CAF_LOG_IMPL(lvlname, classname, funname, msg)
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2014 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_DETAIL_TO_UNIFORM_NAME_HPP
#define CAF_DETAIL_TO_UNIFORM_NAME_HPP
#include <string>
#include <typeinfo>
namespace caf {
namespace detail {
std::string to_uniform_name(const std::string& demangled_name);
std::string to_uniform_name(const std::type_info& tinfo);
template <class T>
inline std::string to_uniform_name() {
return to_uniform_name(typeid(T));
}
} // namespace detail
} // namespace caf
#endif // CAF_DETAIL_TO_UNIFORM_NAME_HPP
......@@ -23,15 +23,11 @@
#include <atomic>
#include <typeinfo>
#include "caf/uniform_typeid.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/detail/type_traits.hpp"
// forward declarations
namespace caf {
class uniform_type_info;
const uniform_type_info* uniform_typeid(const std::type_info&);
} // namespace caf
namespace caf {
namespace detail {
......
......@@ -170,9 +170,8 @@ class event_based_resume {
}
}
catch (std::exception& e) {
CAF_LOG_INFO("actor died because of an exception: "
<< detail::demangle(typeid(e))
<< ", what() = " << e.what());
CAF_LOG_INFO("actor died because of an exception, what() = "
<< e.what());
if (d->exit_reason() == exit_reason::not_exited) {
d->quit(exit_reason::unhandled_exception);
}
......
......@@ -20,6 +20,7 @@
#ifndef CAF_REPLIES_TO_HPP
#define CAF_REPLIES_TO_HPP
#include "caf/uniform_type_info.hpp"
#include "caf/detail/type_list.hpp"
namespace caf {
......@@ -28,9 +29,33 @@ template <class... Is>
struct replies_to {
template <class... Os>
struct with {
static_assert(sizeof...(Is) > 0, "template parameter pack Is empty");
static_assert(sizeof...(Os) > 0, "template parameter pack Os empty");
using input_types = detail::type_list<Is...>;
using output_types = detail::type_list<Os...>;
static std::string as_string() {
const uniform_type_info* inputs[] = {uniform_typeid<Is>(true)...};
const uniform_type_info* outputs[] = {uniform_typeid<Os>(true)...};
std::string result;
// 'void' is not an announced type, hence we check whether uniform_typeid
// did return a valid pointer to identify 'void' (this has the
// possibility of false positives, but those will be catched anyways)
auto plot = [&](const uniform_type_info** arr) {
auto uti = arr[0];
result += uti ? uti->name() : "void";
for (size_t i = 1; i < sizeof...(Is); ++i) {
uti = arr[i];
result += ",";
result += uti ? uti->name() : "void";
}
};
result = "caf::replies_to<";
plot(inputs);
result += ">::with<";
plot(outputs);
result += ">";
return result;
}
};
};
......
......@@ -26,8 +26,6 @@
#include "caf/uniform_type_info.hpp"
#include "caf/primitive_variant.hpp"
#include "caf/detail/to_uniform_name.hpp"
namespace caf {
class actor_namespace;
......@@ -111,8 +109,7 @@ template <class T>
serializer& operator<<(serializer& s, const T& what) {
auto mtype = uniform_typeid<T>();
if (mtype == nullptr) {
throw std::logic_error("no uniform type info found for "
+ detail::to_uniform_name(typeid(T)));
throw std::logic_error("no uniform type info found for T");
}
mtype->serialize(&what, &s);
return s;
......
......@@ -69,7 +69,7 @@ intrusive_ptr<C> spawn_impl(execution_unit* host,
"spawned without blocking_api_flag");
static_assert(is_unbound(Os),
"top-level spawns cannot have monitor or link flag");
CAF_LOGF_TRACE("spawn " << detail::demangle<C>());
CAF_LOGF_TRACE("");
using scheduling_policy =
typename std::conditional<
has_detach_flag(Os) || has_blocking_api_flag(Os),
......
......@@ -60,7 +60,7 @@ std::string to_string(const node_id& what);
std::string to_string(const atom_value& what);
/**
* Converts `e` to a string including the demangled type of `e` and `e.what()`.
* Converts `e` to a string including `e.what()`.
*/
std::string to_verbose_string(const std::exception& e);
......
......@@ -131,7 +131,7 @@ class typed_actor
}
static std::set<std::string> message_types() {
return {detail::to_uniform_name<Rs>()...};
return {Rs::as_string()...};
}
explicit operator bool() const { return static_cast<bool>(m_ptr); }
......
......@@ -49,7 +49,7 @@ class typed_event_based_actor : public
using behavior_type = typed_behavior<Rs...>;
std::set<std::string> message_types() const override {
return {detail::to_uniform_name<Rs>()...};
return {Rs::as_string()...};
}
protected:
......
......@@ -29,20 +29,16 @@
#include <type_traits>
#include "caf/config.hpp"
#include "caf/uniform_typeid.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/detail/demangle.hpp"
#include "caf/detail/to_uniform_name.hpp"
namespace caf {
class serializer;
class deserializer;
class uniform_type_info;
const uniform_type_info* uniform_typeid(const std::type_info&);
struct uniform_value_t;
using uniform_value = std::unique_ptr<uniform_value_t>;
......@@ -203,8 +199,8 @@ class uniform_type_info {
/**
* Creates a copy of `other`.
*/
virtual uniform_value
create(const uniform_value& other = uniform_value{}) const = 0;
virtual uniform_value create(const uniform_value& other
= uniform_value{}) const = 0;
/**
* Deserializes an object of this type from `source`.
......@@ -279,18 +275,14 @@ using uniform_type_info_ptr = std::unique_ptr<uniform_type_info>;
/**
* @relates uniform_type_info
*/
template <class T>
inline const uniform_type_info* uniform_typeid() {
return uniform_typeid(typeid(T));
}
/**
* @relates uniform_type_info
*/
inline bool operator==(const uniform_type_info& lhs,
const uniform_type_info& rhs) {
// uniform_type_info instances are singletons,
// thus, equal == identical
const uniform_type_info& rhs) {
// uniform_type_info instances are singletons
return &lhs == &rhs;
}
......@@ -306,7 +298,7 @@ inline bool operator!=(const uniform_type_info& lhs,
* @relates uniform_type_info
*/
inline bool operator==(const uniform_type_info& lhs,
const std::type_info& rhs) {
const std::type_info& rhs) {
return lhs.equal_to(rhs);
}
......@@ -314,7 +306,7 @@ inline bool operator==(const uniform_type_info& lhs,
* @relates uniform_type_info
*/
inline bool operator!=(const uniform_type_info& lhs,
const std::type_info& rhs) {
const std::type_info& rhs) {
return !(lhs.equal_to(rhs));
}
......@@ -322,7 +314,7 @@ inline bool operator!=(const uniform_type_info& lhs,
* @relates uniform_type_info
*/
inline bool operator==(const std::type_info& lhs,
const uniform_type_info& rhs) {
const uniform_type_info& rhs) {
return rhs.equal_to(lhs);
}
......@@ -330,7 +322,7 @@ inline bool operator==(const std::type_info& lhs,
* @relates uniform_type_info
*/
inline bool operator!=(const std::type_info& lhs,
const uniform_type_info& rhs) {
const uniform_type_info& rhs) {
return !(rhs.equal_to(lhs));
}
......
......@@ -17,24 +17,23 @@
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_DETAIL_DEMANGLE_HPP
#define CAF_DETAIL_DEMANGLE_HPP
#ifndef CAF_UNIFORM_TYPEID_HPP
#define CAF_UNIFORM_TYPEID_HPP
#include <string>
#include <typeinfo>
namespace caf {
namespace detail {
std::string demangle(const char* typeid_name);
std::string demangle(const std::type_info& tinf);
class uniform_type_info;
const uniform_type_info* uniform_typeid(const std::type_info& tinf,
bool allow_nullptr = false);
template <class T>
inline std::string demangle() {
return demangle(typeid(T));
const uniform_type_info* uniform_typeid(bool allow_nullptr = false) {
return uniform_typeid(typeid(T), allow_nullptr);
}
} // namespace detail
} // namespace caf
#endif // CAF_DETAIL_DEMANGLE_HPP
#endif // CAF_UNIFORM_TYPEID_HPP
......@@ -32,8 +32,6 @@
#include "caf/on.hpp"
#include "caf/optional.hpp"
#include "caf/detail/demangle.hpp"
#include "cppa/opt_impls.hpp"
namespace caf {
......
......@@ -93,7 +93,7 @@ class rd_arg_functor {
auto opt = conv_arg_impl<T>::_(arg);
if (!opt) {
std::cerr << "*** error: cannot convert \"" << arg << "\" to "
<< detail::demangle(typeid(T).name())
<< typeid(T).name()
<< " [option: \"" << m_storage->arg_name << "\"]"
<< std::endl;
return false;
......@@ -126,7 +126,7 @@ class add_arg_functor {
auto opt = conv_arg_impl<T>::_(arg);
if (!opt) {
std::cerr << "*** error: cannot convert \"" << arg << "\" to "
<< detail::demangle(typeid(T))
<< typeid(T).name()
<< " [option: \"" << m_storage->arg_name << "\"]"
<< std::endl;
return false;
......
......@@ -217,7 +217,7 @@ void abstract_actor::cleanup(uint32_t reason) {
CAF_LOG_INFO_IF(!is_remote(), "cleanup actor with ID "
<< m_id << "; exit reason = "
<< reason << ", class = "
<< detail::demangle(typeid(*this)));
<< class_name());
// send exit messages
for (attachable* i = head.get(); i != nullptr; i = i->next.get()) {
i->actor_exited(this, reason);
......
......@@ -31,7 +31,7 @@ continue_helper& continue_helper::continue_with(behavior::continuation_fun f) {
behavior cpy = *ref_opt;
*ref_opt = cpy.add_continuation(std::move(f));
} else {
CAF_LOG_ERROR("failed to add continuation");
CAF_LOGF_ERROR("failed to add continuation");
}
return *this;
}
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2014 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include <memory>
#include <string>
#include <cstdlib>
#include <stdexcept>
#include "caf/config.hpp"
#include "caf/detail/demangle.hpp"
#if defined(CAF_CLANG) || defined(CAF_GCC)
# include <cxxabi.h>
# include <stdlib.h>
#endif
namespace caf {
namespace detail {
namespace {
// filter unnecessary characters from undecorated cstr
std::string filter_whitespaces(const char* cstr, size_t size = 0) {
std::string result;
if (size > 0) {
result.reserve(size);
}
char c = *cstr;
while (c != '\0') {
if (c == ' ') {
char previous_c = result.empty() ? ' ' : *(result.rbegin());
for (c = *++cstr; c == ' '; c = *++cstr) {
// scan for next non-space character
}
if (c != '\0') {
// skip whitespace unless it separates two alphanumeric
// characters (such as in "unsigned int")
if (isalnum(c) && isalnum(previous_c)) {
result += ' ';
result += c;
} else {
result += c;
}
c = *++cstr;
}
} else {
result += c;
c = *++cstr;
}
}
return result;
}
} // namespace <anonymous>
#if defined(CAF_CLANG) || defined(CAF_GCC)
std::string demangle(const char* decorated) {
using std::string;
size_t size;
int status;
using uptr = std::unique_ptr<char, void (*)(void*)>;
uptr undecorated{abi::__cxa_demangle(decorated, nullptr, &size, &status),
std::free};
if (status != 0) {
string error_msg = "Could not demangle type name ";
error_msg += decorated;
throw std::logic_error(error_msg);
}
// the undecorated typeid name
string result = filter_whitespaces(undecorated.get(), size);
# ifdef CAF_CLANG
// replace "std::__1::" with "std::" (fixes strange clang names)
string needle = "std::__1::";
string fixed_string = "std::";
for (auto pos = result.find(needle); pos != string::npos;
pos = result.find(needle)) {
result.replace(pos, needle.size(), fixed_string);
}
# endif
return result;
}
#elif defined(CAF_MSVC)
string demangle(const char* decorated) {
// on MSVC, name() returns a human-readable version, all we need
// to do is to remove "struct" and "class" qualifiers
// (handled in to_uniform_name)
return filter_whitespaces(decorated);
}
#else
# error "compiler or platform not supported"
#endif
std::string demangle(const std::type_info& tinf) {
return demangle(tinf.name());
}
} // namespace detail
} // namespace caf
......@@ -166,8 +166,8 @@ void local_actor::cleanup(uint32_t reason) {
}
void local_actor::quit(uint32_t reason) {
CAF_LOG_TRACE("reason = " << reason << ", class "
<< detail::demangle(typeid(*this)));
CAF_LOG_TRACE("reason = " << reason << ", class = "
<< class_name());
planned_exit_reason(reason);
if (is_blocking()) {
throw actor_exited(reason);
......
......@@ -609,7 +609,7 @@ string to_string(const node_id& what) {
string to_verbose_string(const std::exception& e) {
std::ostringstream oss;
oss << detail::demangle(typeid(e)) << ": " << e.what();
oss << "std::exception, what(): " << e.what();
return oss.str();
}
......
This diff is collapsed.
......@@ -40,10 +40,8 @@
#include "caf/uniform_type_info.hpp"
#include "caf/detail/logging.hpp"
#include "caf/detail/demangle.hpp"
#include "caf/detail/singletons.hpp"
#include "caf/detail/actor_registry.hpp"
#include "caf/detail/to_uniform_name.hpp"
#include "caf/detail/uniform_type_info_map.hpp"
namespace caf {
......@@ -73,8 +71,8 @@ const uniform_type_info* uniform_type_info::from(const std::type_info& tinf) {
auto result = uti_map().by_rtti(tinf);
if (result == nullptr) {
std::string error = "uniform_type_info::by_type_info(): ";
error += detail::to_uniform_name(tinf);
error += " is an unknown typeid name";
error += tinf.name();
error += " has not been announced";
CAF_LOGM_ERROR("caf::uniform_type_info", error);
throw std::runtime_error(error);
}
......@@ -99,8 +97,18 @@ std::vector<const uniform_type_info*> uniform_type_info::instances() {
return uti_map().get_all();
}
const uniform_type_info* uniform_typeid(const std::type_info& tinfo) {
return uniform_type_info::from(tinfo);
const uniform_type_info* uniform_typeid(const std::type_info& tinf,
bool allow_nullptr) {
auto result = uti_map().by_rtti(tinf);
if (result == nullptr && !allow_nullptr) {
std::string error = "uniform_typeid(): ";
error += tinf.name();
error += " has not been announced";
CAF_LOGM_ERROR("caf::uniform_type_info", error);
throw std::runtime_error(error);
}
return result;
}
} // namespace caf
......@@ -116,7 +116,8 @@ using static_type_table = type_list<bool,
std::u16string,
std::u32string,
std::map<std::string, std::string>,
std::vector<char>>;
std::vector<char>,
std::vector<std::string>>;
} // namespace <anonymous>
template <class T>
......@@ -453,6 +454,30 @@ inline void deserialize_impl(const sync_timeout_msg&, deserializer*) {
// nop
}
inline void serialize_impl(const std::map<std::string, std::string>& smap,
serializer* sink) {
default_serialize_policy sp;
sp(smap, sink);
}
inline void deserialize_impl(std::map<std::string, std::string>& smap,
deserializer* source) {
default_serialize_policy sp;
sp(smap, source);
}
template <class T>
inline void serialize_impl(const std::vector<T>& vec, serializer* sink) {
default_serialize_policy sp;
sp(vec, sink);
}
template <class T>
inline void deserialize_impl(std::vector<T>& vec, deserializer* source) {
default_serialize_policy sp;
sp(vec, source);
}
bool types_equal(const std::type_info* lhs, const std::type_info* rhs) {
// in some cases (when dealing with dynamic libraries),
// address can be different although types are equal
......@@ -795,7 +820,7 @@ class utim_impl : public uniform_type_info_map {
uti_impl<std::string>,
uti_impl<std::u16string>,
uti_impl<std::u32string>,
default_uniform_type_info<strmap>,
uti_impl<strmap>,
uti_impl<bool>,
uti_impl<float>,
uti_impl<double>,
......@@ -808,8 +833,8 @@ class utim_impl : public uniform_type_info_map {
int_tinfo<uint32_t>,
int_tinfo<int64_t>,
int_tinfo<uint64_t>,
default_uniform_type_info<charbuf>,
default_uniform_type_info<strvec>>;
uti_impl<charbuf>,
uti_impl<strvec>>;
builtin_types m_storage;
......
......@@ -25,6 +25,7 @@
#include "caf/io/spawn_io.hpp"
#include "caf/io/middleman.hpp"
#include "caf/io/unpublish.hpp"
#include "caf/io/basp_broker.hpp"
#include "caf/io/max_msg_size.hpp"
#include "caf/io/remote_actor.hpp"
#include "caf/io/remote_group.hpp"
......
......@@ -117,7 +117,7 @@ deserialize_impl(T& dm, deserializer* source) {
template <class T>
class uti_impl : public uniform_type_info {
public:
uti_impl() : m_native(&typeid(T)), m_name(detail::demangle<T>()) {
uti_impl(const char* tname) : m_native(&typeid(T)), m_name(tname) {
// nop
}
......@@ -165,23 +165,10 @@ class uti_impl : public uniform_type_info {
std::string m_name;
};
template <class... Ts>
struct announce_helper;
template <class T, class... Ts>
struct announce_helper<T, Ts...> {
static inline void exec() {
announce(typeid(T), uniform_type_info_ptr{new uti_impl<T>});
announce_helper<Ts...>::exec();
}
};
template <>
struct announce_helper<> {
static inline void exec() {
// end of recursion
}
};
template <class T>
void do_announce(const char* tname) {
announce(typeid(T), uniform_type_info_ptr{new uti_impl<T>(tname)});
}
} // namespace <anonymous>
......@@ -209,11 +196,16 @@ void middleman::initialize() {
});
m_backend->thread_id(m_thread.get_id());
// announce io-related types
announce_helper<new_data_msg, new_connection_msg,
acceptor_closed_msg, connection_closed_msg,
accept_handle, acceptor_closed_msg,
connection_closed_msg, connection_handle,
new_connection_msg, new_data_msg>::exec();
do_announce<new_data_msg>("caf::io::new_data_msg");
do_announce<new_connection_msg>("caf::io::new_connection_msg");
do_announce<acceptor_closed_msg>("caf::io::acceptor_closed_msg");
do_announce<connection_closed_msg>("caf::io::connection_closed_msg");
do_announce<accept_handle>("caf::io::accept_handle");
do_announce<acceptor_closed_msg>("caf::io::acceptor_closed_msg");
do_announce<connection_closed_msg>("caf::io::connection_closed_msg");
do_announce<connection_handle>("caf::io::connection_handle");
do_announce<new_connection_msg>("caf::io::new_connection_msg");
do_announce<new_data_msg>("caf::io::new_data_msg");
}
void middleman::stop() {
......
......@@ -10,8 +10,6 @@
#include "caf/detail/int_list.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/detail/demangle.hpp"
using std::cout;
using std::endl;
using std::is_same;
......@@ -53,10 +51,7 @@ int main() {
using il0 = int_list<0, 1, 2, 3, 4, 5>;
using il1 = int_list<4, 5>;
using il2 = typename il_right<il0, 2>::type;
CAF_CHECK_VERBOSE((is_same<il2, il1>::value),
"il_right<il0, 2> returned "
<< detail::demangle<il2>()
<< "expected: " << detail::demangle<il1>());
CAF_CHECK((is_same<il2, il1>::value));
/* test tl_is_strict_subset */ {
using list_a = type_list<int, float, double>;
......
......@@ -401,7 +401,7 @@ void test_remote_actor(std::string app_path, bool run_remote_actor) {
int main(int argc, char** argv) {
CAF_TEST(test_remote_actor);
announce<actor_vector>();
announce<actor_vector>("actor_vector");
cout << "this node is: " << to_string(caf::detail::singletons::get_node_id())
<< endl;
message_builder{argv + 1, argv + argc}.apply({
......
......@@ -77,6 +77,10 @@ bool operator==(const raw_struct& lhs, const raw_struct& rhs) {
}
struct raw_struct_type_info : detail::abstract_uniform_type_info<raw_struct> {
using super = detail::abstract_uniform_type_info<raw_struct>;
raw_struct_type_info() : super("raw_struct") {
// nop
}
void serialize(const void* ptr, serializer* sink) const override {
auto rs = reinterpret_cast<const raw_struct*>(ptr);
sink->write_value(static_cast<uint32_t>(rs->str.size()));
......@@ -92,7 +96,6 @@ struct raw_struct_type_info : detail::abstract_uniform_type_info<raw_struct> {
bool equals(const void* lhs, const void* rhs) const override {
return deref(lhs) == deref(rhs);
}
};
void test_ieee_754() {
......@@ -121,7 +124,7 @@ enum class test_enum {
int main() {
CAF_TEST(test_serialization);
announce<test_enum>();
announce<test_enum>("test_enum");
test_ieee_754();
......@@ -133,8 +136,7 @@ int main() {
CAF_CHECK_EQUAL(detail::impl_id<strmap>(), 2);
CAF_CHECK_EQUAL(token::value, 2);
announce(typeid(raw_struct),
uniform_type_info_ptr{new raw_struct_type_info});
announce(typeid(raw_struct), uniform_type_info_ptr{new raw_struct_type_info});
auto nid = detail::singletons::get_node_id();
auto nid_str = to_string(nid);
......
......@@ -166,28 +166,26 @@ void testee1(event_based_actor* self) {
});
}
template <class Testee>
string behavior_test(scoped_actor& self, actor et) {
string testee_name = detail::to_uniform_name(typeid(Testee));
CAF_LOGF_TRACE(CAF_TARG(et, to_string) << ", " << CAF_ARG(testee_name));
CAF_LOGF_TRACE(CAF_TARG(et, to_string));
string result;
self->send(et, 1);
self->send(et, 2);
self->send(et, 3);
self->send(et, .1f);
self->send(et, "hello " + testee_name);
self->send(et, "hello");
self->send(et, .2f);
self->send(et, .3f);
self->send(et, "hello again " + testee_name);
self->send(et, "goodbye " + testee_name);
self->send(et, "hello again");
self->send(et, "goodbye");
self->send(et, atom("get_state"));
self->receive (
[&](const string& str) {
result = str;
},
after(chrono::minutes(1)) >> [&]() {
CAF_LOGF_ERROR(testee_name << " does not reply");
throw runtime_error(testee_name + " does not reply");
CAF_LOGF_ERROR("actor does not reply");
throw runtime_error("actor does not reply");
}
);
self->send_exit(et, exit_reason::user_shutdown);
......@@ -529,9 +527,9 @@ void test_spawn() {
self->await_all_other_actors_done();
CAF_CHECKPOINT();
auto res1 = behavior_test<testee_actor>(self, spawn<blocking_api>(testee_actor{}));
auto res1 = behavior_test(self, spawn<blocking_api>(testee_actor{}));
CAF_CHECK_EQUAL("wait4int", res1);
CAF_CHECK_EQUAL(behavior_test<event_testee>(self, spawn<event_testee>()), "wait4int");
CAF_CHECK_EQUAL(behavior_test(self, spawn<event_testee>()), "wait4int");
self->await_all_other_actors_done();
CAF_CHECKPOINT();
......
......@@ -86,8 +86,8 @@ uint16_t run_server() {
}
int main(int argc, char** argv) {
announce<ping>(&ping::value);
announce<pong>(&pong::value);
announce<ping>("ping", &ping::value);
announce<pong>("pong", &pong::value);
message_builder{argv + 1, argv + argc}.apply({
on("-c", spro<uint16_t>)>> [](uint16_t port) {
CAF_PRINT("run in client mode");
......
......@@ -177,7 +177,7 @@ void test_event_testee() {
self->send(et, "goodbye event testee!");
typed_actor<replies_to<get_state_msg>::with<string>> sub_et = et;
// $:: is the anonymous namespace
set<string> iface{"caf::replies_to<$::get_state_msg>::with<@str>",
set<string> iface{"caf::replies_to<get_state_msg>::with<@str>",
"caf::replies_to<@str>::with<void>",
"caf::replies_to<float>::with<void>",
"caf::replies_to<@i32>::with<@i32>"};
......@@ -311,9 +311,9 @@ void test_sending_typed_actors_and_down_msg() {
int main() {
CAF_TEST(test_typed_spawn);
// announce stuff
announce<get_state_msg>();
announce<int_actor>();
announce<my_request>(&my_request::a, &my_request::b);
announce<get_state_msg>("get_state_msg");
announce<int_actor>("int_actor");
announce<my_request>("my_request", &my_request::a, &my_request::b);
// run test series with typed_server(1|2)
test_typed_spawn(spawn_typed(typed_server1));
await_all_actors_done();
......
......@@ -107,14 +107,14 @@ T& append(T& storage, U&& u, Us&&... us) {
int main() {
CAF_TEST(test_uniform_type);
auto announce1 = announce<foo>(&foo::value);
auto announce2 = announce<foo>(&foo::value);
auto announce3 = announce<foo>(&foo::value);
auto announce4 = announce<foo>(&foo::value);
auto announce1 = announce<foo>("foo", &foo::value);
auto announce2 = announce<foo>("foo", &foo::value);
auto announce3 = announce<foo>("foo", &foo::value);
auto announce4 = announce<foo>("foo", &foo::value);
CAF_CHECK(announce1 == announce2);
CAF_CHECK(announce1 == announce3);
CAF_CHECK(announce1 == announce4);
CAF_CHECK_EQUAL(announce1->name(), "$::foo");
CAF_CHECK_EQUAL(announce1->name(), "foo");
{
auto uti = uniform_typeid<atom_value>();
CAF_CHECK(uti != nullptr);
......@@ -124,7 +124,7 @@ int main() {
// the uniform_type_info implementation is correct
std::set<std::string> expected = {
// local types
"$::foo", // <anonymous namespace>::foo
"foo", // <anonymous namespace>::foo
// primitive types
"bool", "@i8", "@i16",
"@i32", "@i64", // signed integer names
......@@ -166,7 +166,7 @@ int main() {
"caf::io::new_data_msg"));
}
// check whether enums can be announced as members
announce<test_enum>();
announce<test_struct>(&test_struct::test_value);
announce<test_enum>("test_enum");
announce<test_struct>("test_struct", &test_struct::test_value);
return CAF_TEST_RESULT();
}
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