Commit 61cf341e authored by neverlord's avatar neverlord

uniform_type_info changes

parent 03e2d174
CXX = /opt/local/bin/g++-mp-4.6
CXXFLAGS = -std=c++0x -pedantic -Wall -Wextra -O2 -I/opt/local/include/
#CXXFLAGS = -std=c++0x -pedantic -Wall -Wextra -g -O0 -I/opt/local/include/
#CXXFLAGS = -std=c++0x -pedantic -Wall -Wextra -O2 -I/opt/local/include/ -fpermissive
CXXFLAGS = -std=c++0x -pedantic -Wall -Wextra -g -O0 -I/opt/local/include/ -fpermissive
LIBS = -L/opt/local/lib -lboost_thread-mt
......@@ -60,15 +60,15 @@
<valuemap type="QVariantMap">
<value key="ProjectExplorer.BuildConfiguration.DisplayName" type="QString">all</value>
<valuelist key="abstractProcess.Environment" type="QVariantList">
<value type="QString">Apple_PubSub_Socket_Render=/tmp/launch-qTxq6l/Render</value>
<value type="QString">Apple_PubSub_Socket_Render=/tmp/launch-tO8Wwx/Render</value>
<value type="QString">COMMAND_MODE=unix2003</value>
<value type="QString">DISPLAY=/tmp/launch-b33dXE/org.x:0</value>
<value type="QString">DISPLAY=/tmp/launch-w1qNYf/org.x:0</value>
<value type="QString">HOME=/Users/neverlord</value>
<value type="QString">LOGNAME=neverlord</value>
<value type="QString">PATH=/usr/bin:/bin:/usr/sbin:/sbin</value>
<value type="QString">SHELL=/bin/bash</value>
<value type="QString">SSH_AUTH_SOCK=/tmp/launch-ZcReR3/Listeners</value>
<value type="QString">TMPDIR=/var/folders/1p/1p6iuPgbH7GoDkrjrT20tU+++TI/-Tmp-/</value>
<value type="QString">SSH_AUTH_SOCK=/tmp/launch-dnUZas/Listeners</value>
<value type="QString">TMPDIR=/var/folders/SE/SEReyCW0H-yDPCnNCe8mN++++TI/-Tmp-/</value>
<value type="QString">USER=neverlord</value>
<value type="QString">__CF_USER_TEXT_ENCODING=0x1F5:0:3</value>
</valuelist>
......
......@@ -19,7 +19,6 @@ cppa/detail/abstract_tuple.hpp
cppa/tuple_view.hpp
cppa/untyped_tuple.hpp
cppa/any_type.hpp
cppa/util/utype_iterator.hpp
cppa/detail/matcher.hpp
cppa/detail/tuple_vals.hpp
cppa/match.hpp
......@@ -28,7 +27,6 @@ cppa/cow_ptr.hpp
cppa/util/detach.hpp
cppa/detail/ref_counted_impl.hpp
cppa/intrusive_ptr.hpp
cppa/detail/scheduler.hpp
unit_testing/test__spawn.cpp
src/mock_scheduler.cpp
cppa/actor.hpp
......@@ -60,8 +58,6 @@ cppa/deserializer.hpp
cppa/util/is_serializable.hpp
cppa/util/enable_if.hpp
cppa/object.hpp
cppa/utype.hpp
cppa/detail/utype_impl.hpp
cppa/detail/object_impl.hpp
cppa/detail/swap_bytes.hpp
src/serializer.cpp
......@@ -107,3 +103,18 @@ queue_performances/blocking_sutter_list.hpp
queue_performances/lockfree_list.hpp
queue_performances/intrusive_sutter_list.hpp
cppa/detail/cpp0x_thread_wrapper.hpp
src/context.cpp
cppa/scheduler.hpp
cppa/detail/mock_scheduler.hpp
src/scheduler.cpp
cppa/detail/blocking_message_queue.hpp
src/blocking_message_queue.cpp
cppa/detail/converted_thread_context.hpp
src/converted_thread_context.cpp
unit_testing/test__uniform_type.cpp
cppa/detail/demangle.hpp
src/demangle.cpp
cppa/detail/to_uniform_name.hpp
src/to_uniform_name.cpp
cppa/util/default_object_base.hpp
cppa/detail/default_object_impl.hpp
......@@ -7,6 +7,7 @@
#if defined(__APPLE__)
# define CPPA_MACOS
# define _GLIBCXX_HAS_GTHREADS
#elif defined(__GNUC__) && defined(__linux__)
# define CPPA_LINUX
#elif defined(WIN32)
......
......@@ -13,8 +13,24 @@ class context : public actor
virtual message_queue& mailbox() = 0;
/**
* @brief Default implementation of
* {@link channel::enqueue(const message&)}.
*
* Calls <code>mailbox().enqueue(msg)</code>.
*/
virtual void enqueue /*[[override]]*/ (const message& msg);
};
/**
* @brief Get a pointer to the current active context.
*/
context* self();
// "private" function
void set_self(context*);
} // namespace cppa
#endif // CONTEXT_HPP
......@@ -10,7 +10,7 @@
#include "cppa/invoke_rules.hpp"
#include "cppa/actor_behavior.hpp"
#include "cppa/scheduling_hint.hpp"
#include "cppa/detail/scheduler.hpp"
#include "cppa/scheduler.hpp"
namespace cppa {
......@@ -26,7 +26,7 @@ actor_ptr spawn(scheduling_hint hint, F fun)
m_fun();
}
};
return detail::scheduler::spawn(new fun_behavior(fun), hint);
return get_scheduler()->spawn(new fun_behavior(fun), hint);
}
template<typename F, typename Arg0, typename... Args>
......@@ -44,17 +44,12 @@ inline actor_ptr spawn(F fun, const Args&... args)
inline actor_ptr spawn(scheduling_hint hint, actor_behavior* ab)
{
return detail::scheduler::spawn(ab, hint);
return get_scheduler()->spawn(ab, hint);
}
inline actor_ptr spawn(actor_behavior* ab)
{
return detail::scheduler::spawn(ab, scheduled);
}
inline context* self()
{
return detail::scheduler::get_context();
return get_scheduler()->spawn(ab, scheduled);
}
inline const message& receive()
......@@ -103,7 +98,7 @@ void reply(const Arg0& arg0, const Args&... args)
inline void await_all_actors_done()
{
detail::scheduler::await_all_done();
get_scheduler()->await_all_done();
}
} // namespace cppa
......
......@@ -18,7 +18,7 @@ struct abstract_tuple : ref_counted
virtual std::size_t size() const = 0;
virtual abstract_tuple* copy() const = 0;
virtual const void* at(std::size_t pos) const = 0;
virtual const utype& utype_at(std::size_t pos) const = 0;
virtual const uniform_type_info* utype_at(std::size_t pos) const = 0;
virtual const util::abstract_type_list& types() const = 0;
virtual bool equal_to(const abstract_tuple& other) const = 0;
virtual void serialize(serializer&) const = 0;
......
#ifndef ACTOR_PRIVATE_HPP
#define ACTOR_PRIVATE_HPP
/*
#include <boost/thread/thread.hpp>
#include "cppa/invoke_rules.hpp"
......@@ -54,4 +56,6 @@ inline const message& last_dequeued()
} // namespace cppa
*/
#endif // ACTOR_PRIVATE_HPP
#ifndef ACTOR_PUBLIC_HPP
#define ACTOR_PUBLIC_HPP
/*
#include "cppa/detail/channel.hpp"
namespace cppa { namespace detail {
......@@ -13,4 +15,6 @@ struct actor_public : channel
} } // namespace cppa::detail
*/
#endif // ACTOR_PUBLIC_HPP
#ifndef BLOCKING_MESSAGE_QUEUE_HPP
#define BLOCKING_MESSAGE_QUEUE_HPP
#include "cppa/message.hpp"
#include "cppa/message_queue.hpp"
#include "cppa/util/single_reader_queue.hpp"
namespace cppa { namespace detail {
// blocks if single_reader_queue blocks
class blocking_message_queue : public message_queue
{
struct queue_node
{
queue_node* next;
message msg;
queue_node(const message& from) : next(0), msg(from) { }
};
message m_last_dequeued;
util::single_reader_queue<queue_node> m_queue;
public:
virtual void enqueue /*[[override]]*/ (const message& msg);
virtual const message& dequeue /*[[override]]*/ ();
virtual void dequeue /*[[override]]*/ (invoke_rules& rules);
virtual bool try_dequeue /*[[override]]*/ (message& msg);
virtual bool try_dequeue /*[[override]]*/ (invoke_rules& rules);
virtual const message& last_dequeued /*[[override]]*/ ();
};
} } // namespace hamcast::detail
#endif // BLOCKING_MESSAGE_QUEUE_HPP
......@@ -3,6 +3,7 @@
namespace cppa { namespace detail {
// Barton–Nackman trick
template<typename Subclass, typename T = Subclass>
class comparable
{
......
#ifndef CONVERTED_THREAD_CONTEXT_HPP
#define CONVERTED_THREAD_CONTEXT_HPP
#include "cppa/config.hpp"
#include <map>
#include <set>
#include <mutex>
#include "cppa/context.hpp"
#include "cppa/detail/blocking_message_queue.hpp"
namespace cppa { namespace detail {
class converted_thread_context : public context
{
// mailbox implementation
detail::blocking_message_queue m_mailbox;
// guards access to m_exited, m_subscriptions and m_links
std::mutex m_mtx;
// true if the associated thread has finished execution
bool m_exited;
// manages group subscriptions
std::map<group_ptr, intrusive_ptr<group::subscription>> m_subscriptions;
// manages actor links
std::set<actor_ptr> m_links;
public:
message_queue& mailbox /*[[override]]*/ ();
void join /*[[override]]*/ (group_ptr& what);
void leave /*[[override]]*/ (const group_ptr& what);
void link /*[[override]]*/ (intrusive_ptr<actor>& other);
void unlink /*[[override]]*/ (intrusive_ptr<actor>& other);
bool remove_backlink /*[[override]]*/ (const intrusive_ptr<actor>& to);
bool establish_backlink /*[[override]]*/ (const intrusive_ptr<actor>& to);
};
} } // namespace cppa::detail
#endif // CONVERTED_THREAD_CONTEXT_HPP
#ifndef CPPA_DETAIL_CPP0X_THREAD_WRAPPER_HPP
#define CPPA_DETAIL_CPP0X_THREAD_WRAPPER_HPP
// This header imports C++0x compatible parts of the boost threading library
// to the std namespace. It's a workaround to the missing stl threading
// library on GCC 4.6 under Mac OS X
#include <boost/thread.hpp>
namespace std {
......
......@@ -50,7 +50,7 @@ class decorated_tuple : public abstract_tuple
return m_decorated->at(m_mappings[pos]);
}
virtual const utype& utype_at(std::size_t pos) const
virtual const uniform_type_info* utype_at(std::size_t pos) const
{
return m_decorated->utype_at(m_mappings[pos]);
}
......
#ifndef DEFAULT_OBJECT_IMPL_HPP
#define DEFAULT_OBJECT_IMPL_HPP
#include <sstream>
#include "cppa/serializer.hpp"
#include "cppa/deserializer.hpp"
#include "cppa/util/default_object_base.hpp"
namespace cppa { namespace detail {
template<typename T>
class default_object_impl : public util::default_object_base<T>
{
typedef util::default_object_base<T> super;
public:
default_object_impl(const uniform_type_info* uti, const T& val = T())
: super(uti, val)
{
}
object* copy /*[[override]]*/ () const
{
return new default_object_impl(this->type(), this->m_value);
}
std::string to_string /*[[override]]*/ () const
{
std::ostringstream sstr;
sstr << this->m_value;
return sstr.str();
}
void from_string /*[[override]]*/ (const std::string& str)
{
T tmp;
std::istringstream istr(str);
istr >> tmp;
this->m_value = std::move(tmp);
}
void deserialize /*[[override]]*/ (deserializer& d)
{
d >> this->m_value;
}
void serialize /*[[override]]*/ (serializer& s) const
{
s << this->m_value;
}
};
} } // namespace cppa::detail
#endif // DEFAULT_OBJECT_IMPL_HPP
#ifndef DEMANGLE_HPP
#define DEMANGLE_HPP
#include <string>
namespace cppa { namespace detail {
std::string demangle(const char* typeid_name);
} } // namespace cppa::detail
#endif // DEMANGLE_HPP
......@@ -4,7 +4,8 @@
#include <vector>
#include "cppa/any_type.hpp"
#include "cppa/util/utype_iterator.hpp"
#include "cppa/uniform_type_info.hpp"
#include "cppa/util/abstract_type_list.hpp"
namespace cppa { namespace detail {
......@@ -13,14 +14,15 @@ template<typename... Types> struct matcher;
template<typename Head, typename... Tail>
struct matcher<Head, Tail...>
{
static bool match(util::utype_iterator& begin,
util::utype_iterator& end,
static bool match(util::abstract_type_list::const_iterator& begin,
util::abstract_type_list::const_iterator& end,
std::vector<std::size_t>* res = nullptr,
std::size_t pos = 0)
{
auto head_uti = uniform_typeid<Head>();
if (begin != end)
{
if (begin->native() == typeid(Head))
if (*(*begin) == *head_uti)
{
if (res)
{
......@@ -38,8 +40,8 @@ struct matcher<Head, Tail...>
template<typename... Tail>
struct matcher<any_type, Tail...>
{
static bool match(util::utype_iterator &begin,
util::utype_iterator &end,
static bool match(util::abstract_type_list::const_iterator& begin,
util::abstract_type_list::const_iterator& end,
std::vector<std::size_t>* res = nullptr,
std::size_t pos = 0)
{
......@@ -56,15 +58,15 @@ struct matcher<any_type, Tail...>
template<typename Next, typename... Tail>
struct matcher<any_type*, Next, Tail...>
{
static bool match(util::utype_iterator &begin,
util::utype_iterator &end,
static bool match(util::abstract_type_list::const_iterator& begin,
util::abstract_type_list::const_iterator& end,
std::vector<std::size_t>* res = nullptr,
std::size_t pos = 0)
{
bool result = false;
while (!result)
{
util::utype_iterator begin_cpy = begin;
util::abstract_type_list::const_iterator begin_cpy = begin;
result = matcher<Next, Tail...>::match(begin_cpy,end,nullptr,pos);
if (!result)
{
......@@ -86,8 +88,8 @@ struct matcher<any_type*, Next, Tail...>
template<>
struct matcher<any_type*>
{
static bool match(util::utype_iterator&,
util::utype_iterator&,
static bool match(util::abstract_type_list::const_iterator&,
util::abstract_type_list::const_iterator&,
std::vector<std::size_t>* = nullptr,
std::size_t = 0)
{
......@@ -98,8 +100,8 @@ struct matcher<any_type*>
template<>
struct matcher<>
{
static bool match(util::utype_iterator& begin,
util::utype_iterator& end,
static bool match(util::abstract_type_list::const_iterator& begin,
util::abstract_type_list::const_iterator& end,
std::vector<std::size_t>* = nullptr,
std::size_t = 0)
{
......
#ifndef MOCK_SCHEDULER_HPP
#define MOCK_SCHEDULER_HPP
#include "cppa/scheduler.hpp"
namespace cppa { namespace detail {
class mock_scheduler : public scheduler
{
public:
actor_ptr spawn(actor_behavior* behavior, scheduling_hint hint);
void await_all_done();
};
} } // namespace cppa::detail
#endif // MOCK_SCHEDULER_HPP
......@@ -16,7 +16,7 @@ struct serialize_tuple
template<typename T>
inline static void _(serializer& s, const T* self)
{
s << uniform_type_info<typename List::head_type>().name()
s << uniform_typeid<typename List::head_type>()->name()
<< *reinterpret_cast<const typename List::head_type*>(self->at(Pos));
serialize_tuple<typename List::tail_type, Pos + 1>::_(s, self);
}
......
#ifndef TO_UNIFORM_NAME_HPP
#define TO_UNIFORM_NAME_HPP
#include <string>
namespace cppa { namespace detail {
std::string to_uniform_name(const std::string& demangled_name);
} } // namespace cppa::detail
#endif // TO_UNIFORM_NAME_HPP
......@@ -75,7 +75,7 @@ class tuple_vals : public abstract_tuple
return tdata_at(m_data, pos);
}
virtual const utype& utype_at(std::size_t pos) const
virtual const uniform_type_info* utype_at(std::size_t pos) const
{
return m_types.at(pos);
}
......
#ifndef UTYPE_IMPL_HPP
#define UTYPE_IMPL_HPP
#include <map>
#include <string>
#include "cppa/utype.hpp"
#include "cppa/detail/object_impl.hpp"
namespace cppa { namespace detail {
std::string demangle(const char*);
std::map<std::string, utype*>& uniform_types();
// default implementation of utype
template<typename T>
class utype_impl : public utype
{
const std::string m_name;
const std::type_info& m_native;
utype_impl() : m_name(demangle(typeid(T).name())), m_native(typeid(T))
{
(uniform_types())[m_name] = this;
}
public:
static const utype_impl instance;
std::uint8_t announce_helper() const { return 42; }
virtual object* create() const
{
return new obj_impl<T>;
}
virtual const std::string& name() const
{
return m_name;
}
virtual const std::type_info& native() const
{
return m_native;
}
};
template<typename A> const utype_impl<A> utype_impl<A>::instance;
} } // namespace cppa::detail
#endif // UTYPE_IMPL_HPP
......@@ -11,7 +11,6 @@
#include "cppa/util/compare_tuples.hpp"
#include "cppa/util/type_list.hpp"
#include "cppa/util/is_comparable.hpp"
#include "cppa/util/utype_iterator.hpp"
#include "cppa/util/eval_type_lists.hpp"
#include "cppa/util/filter_type_list.hpp"
......@@ -22,16 +21,16 @@ namespace cppa {
template<typename... MatchRules>
bool match(const untyped_tuple& what)
{
util::utype_iterator begin = what.types().begin();
util::utype_iterator end = what.types().end();
util::abstract_type_list::const_iterator begin = what.types().begin();
util::abstract_type_list::const_iterator end = what.types().end();
return detail::matcher<MatchRules...>::match(begin, end);
}
template<typename... MatchRules>
bool match(const untyped_tuple& what, std::vector<std::size_t>& mappings)
{
util::utype_iterator begin = what.types().begin();
util::utype_iterator end = what.types().end();
util::abstract_type_list::const_iterator begin = what.types().begin();
util::abstract_type_list::const_iterator end = what.types().end();
return detail::matcher<MatchRules...>::match(begin, end, &mappings);
}
......@@ -72,8 +71,8 @@ get_view(const Tuple<TupleTypes...>& t)
util::type_list<TupleTypes...>>::value,
"MatchRules does not match Tuple");
std::vector<std::size_t> mappings;
util::utype_iterator begin = t.types().begin();
util::utype_iterator end = t.types().end();
util::abstract_type_list::const_iterator begin = t.types().begin();
util::abstract_type_list::const_iterator end = t.types().end();
if (detail::matcher<MatchRules...>::match(begin, end, &mappings))
{
return { t.vals(), std::move(mappings) };
......
#ifndef OBJECT_HPP
#define OBJECT_HPP
#include <string>
#include "cppa/ref_counted.hpp"
namespace cppa {
struct utype;
class uniform_type_info;
class serializer;
class deserializer;
struct object : public ref_counted
class object : public ref_counted
{
public:
// mutators
virtual void* mutable_value() = 0;
virtual void deserialize(deserializer&) = 0;
virtual void from_string(const std::string&) = 0;
// accessors
virtual object* copy() const = 0;
virtual const utype& type() const = 0;
virtual const uniform_type_info* type() const = 0;
virtual const void* value() const = 0;
virtual std::string to_string() const = 0;
virtual void serialize(serializer&) const = 0;
};
......
......@@ -6,17 +6,31 @@
#include "cppa/actor_behavior.hpp"
#include "cppa/scheduling_hint.hpp"
namespace cppa { namespace detail {
namespace cppa {
struct scheduler
class scheduler
{
static actor_ptr spawn(actor_behavior*, scheduling_hint);
static context* get_context();
static void await_all_done();
public:
virtual ~scheduler();
/**
* @brief Spawn a new actor that executes <code>behavior->act()</code>
* with the scheduling policy @p hint if possible.
*/
virtual actor_ptr spawn(actor_behavior* behavior,
scheduling_hint hint) = 0;
/**
* @brief Wait until all (other) actors finished execution.
*/
virtual void await_all_done() = 0;
};
} } // namespace cppa::detail
scheduler* get_scheduler();
} // namespace cppa::detail
#endif // SCHEDULER_HPP
......@@ -121,7 +121,7 @@ class tuple
const void* at(std::size_t p) const { return m_vals->at(p); }
const utype& utype_at(std::size_t p) const { return m_vals->utype_at(p); }
const uniform_type_info* utype_at(std::size_t p) const { return m_vals->utype_at(p); }
const util::abstract_type_list& types() const { return m_vals->types(); }
......
......@@ -2,34 +2,156 @@
#define UNIFORM_TYPE_INFO_HPP
#include <map>
#include <vector>
#include <string>
#include <cstdint>
#include <typeinfo>
#include "cppa/utype.hpp"
#include "cppa/object.hpp"
#include "cppa/serializer.hpp"
#include "cppa/deserializer.hpp"
#include "cppa/detail/utype_impl.hpp"
#include "cppa/detail/object_impl.hpp"
#include "cppa/detail/demangle.hpp"
#include "cppa/detail/to_uniform_name.hpp"
namespace cppa {
/**
* @brief Get the uniform type information ({@link utype}) for @p T.
* @brief Provides a platform independent type name and (very primitive)
* reflection in combination with {@link cppa::object object}.
*
* The platform dependent type name (from GCC or Microsofts VC++ Compiler) is
* translated to a (usually) shorter and platform independent name.
*
* This name is usually equal to the "in-sourcecode-name",
* with a few exceptions:
* - <i>std::string</i> is named <code>@str</code>
* - <i>std::wstring</i> is named <code>@wstr</code>
* - <i>integers</i> are named <code>@(i|u)$size</code>\n
* e.g.: @i32 is a 32 bit signed integer; @u16 is a 16 bit unsigned integer
* - <i>anonymous namespace</i> is named <b>@_</b>\n
* e.g.: <code>namespace { class foo { }; }</code> is mapped to
* <code>@_::foo</code>
*/
class uniform_type_info : cppa::detail::comparable<uniform_type_info>
{
template<typename T> friend uniform_type_info* uniform_typeid();
public:
class identifier : cppa::detail::comparable<identifier>
{
friend class uniform_type_info;
friend class cppa::detail::comparable<identifier>;
int m_value;
identifier(int val) : m_value(val) { }
// enable default copy and move constructors
identifier(identifier&&) = default;
identifier(const identifier&) = default;
// disable any assignment
identifier& operator=(identifier&&) = delete;
identifier& operator=(const identifier&) = delete;
public:
inline int compare(const identifier& other) const
{
return m_value - other.m_value;
}
};
private:
// unique identifier
identifier m_id;
// uniform type name
std::string m_name;
// prohibit all default constructors
uniform_type_info() = delete;
uniform_type_info(uniform_type_info&&) = delete;
uniform_type_info(const uniform_type_info&) = delete;
// prohibit all assignment operators
uniform_type_info& operator=(uniform_type_info&&) = delete;
uniform_type_info& operator=(const uniform_type_info&) = delete;
static uniform_type_info* by_type_info(const std::type_info& tinfo);
protected:
uniform_type_info(const std::string& uniform_type_name);
public:
virtual ~uniform_type_info();
inline const std::string& name() const { return m_name; }
inline const identifier& id() const { return m_id; }
inline int compare(const uniform_type_info& other) const
{
return id().compare(other.id());
}
virtual object* create() const = 0;
static uniform_type_info* by_uniform_name(const std::string& uniform_name);
static bool announce(const std::type_info& plain_type,
uniform_type_info* uniform_type);
template<class ObjectImpl>
static bool announce(const std::type_info& plain_type);
static std::vector<uniform_type_info*> get_all();
};
template<typename T>
const utype& uniform_type_info()
uniform_type_info* uniform_typeid()
{
return detail::utype_impl<T>::instance;
return uniform_type_info::by_type_info(typeid(T));
}
/**
* @brief Get the uniform type information ({@link utype}) associated with
* the name @p uniform_type_name.
*/
const utype& uniform_type_info(const std::string& uniform_type_name);
namespace detail {
template<class ObjectImpl>
class default_uniform_type_info_impl : public uniform_type_info
{
public:
default_uniform_type_info_impl(const std::string& tname)
: uniform_type_info(tname)
{
}
object* create /*[[override]]*/ () const
{
return new ObjectImpl(this);
}
};
} // namespace detail
template<class ObjImpl>
bool uniform_type_info::announce(const std::type_info& plain)
{
std::string uname = detail::to_uniform_name(detail::demangle(plain.name()));
return announce(plain,
new detail::default_uniform_type_info_impl<ObjImpl>(uname));
}
} // namespace cppa
......@@ -37,15 +159,17 @@ const utype& uniform_type_info(const std::string& uniform_type_name);
#define CPPA_CONCAT_I(lhs, rhs) CPPA_CONCAT_II(lhs ## rhs)
#define CPPA_CONCAT(lhs, rhs) CPPA_CONCAT_I( lhs, rhs )
/*
#ifdef __GNUC__
# define CPPA_ANNOUNCE(what) \
static const std::uint8_t CPPA_CONCAT( __unused_val , __LINE__ ) \
__attribute__ ((unused)) \
= cppa::detail::utype_impl< what >::instance.announce_helper()
= cppa::detail::utype_impl< what >::announce_helper()
#else
# define CPPA_ANNOUNCE(what) \
static const std::uint8_t CPPA_CONCAT( __unused_val , __LINE__ ) \
= cppa::detail::utype_impl< what >::instance.announce_helper()
= cppa::detail::utype_impl< what >::announce_helper()
#endif
*/
#endif // UNIFORM_TYPE_INFO_HPP
......@@ -28,7 +28,7 @@ class untyped_tuple
const void* at(std::size_t p) const { return m_vals->at(p); }
const utype& utype_at(std::size_t p) const { return m_vals->utype_at(p); }
const uniform_type_info* utype_at(std::size_t p) const { return m_vals->utype_at(p); }
const util::abstract_type_list& types() const { return m_vals->types(); }
......
......@@ -32,7 +32,6 @@
#include "cppa/util/type_list.hpp"
#include "cppa/util/type_list_apply.hpp"
#include "cppa/util/type_list_pop_back.hpp"
#include "cppa/util/utype_iterator.hpp"
#include "cppa/util/void_type.hpp"
#endif // UTIL_HPP
#ifndef ABSTRACT_TYPE_LIST_HPP
#define ABSTRACT_TYPE_LIST_HPP
#include "cppa/util/utype_iterator.hpp"
#include <iterator>
#include "cppa/uniform_type_info.hpp"
namespace cppa { class serializer; }
......@@ -10,9 +11,69 @@ namespace cppa { namespace util {
struct abstract_type_list
{
typedef utype_iterator iterator;
class const_iterator : public std::iterator<std::bidirectional_iterator_tag,
const uniform_type_info*>
{
typedef utype_iterator const_iterator;
const uniform_type_info* const* p;
public:
inline const_iterator(const uniform_type_info* const* x = nullptr) : p(x) { }
const_iterator(const_iterator&&) = default;
const_iterator(const const_iterator&) = default;
const_iterator& operator=(const_iterator&&) = default;
const_iterator& operator=(const const_iterator&) = default;
inline bool operator==(const const_iterator& other) const
{
return p == other.p;
}
inline bool operator!=(const const_iterator& other) const
{
return p != other.p;
}
inline const uniform_type_info* operator*()
{
return *p;
}
inline const uniform_type_info* const* operator->()
{
return p;
}
inline const_iterator& operator++()
{
++p;
return *this;
}
inline const_iterator operator++(int)
{
const_iterator tmp(*this);
operator++();
return tmp;
}
inline const_iterator& operator--()
{
--p;
return *this;
}
inline const_iterator operator--(int)
{
const_iterator tmp(*this);
operator--();
return tmp;
}
};
virtual abstract_type_list* copy() const = 0;
......@@ -20,7 +81,7 @@ struct abstract_type_list
virtual const_iterator end() const = 0;
virtual const utype& at(std::size_t pos) const = 0;
virtual const uniform_type_info* at(std::size_t pos) const = 0;
};
......
#ifndef DEFAULT_OBJECT_BASE_HPP
#define DEFAULT_OBJECT_BASE_HPP
#include "cppa/object.hpp"
#include "cppa/uniform_type_info.hpp"
namespace cppa { namespace util {
template<typename T>
class default_object_base : public object
{
const uniform_type_info* m_type;
protected:
T m_value;
public:
default_object_base(const uniform_type_info* uti, const T& val = T())
: m_type(uti), m_value(val)
{
}
// mutators
void* mutable_value /*[[override]]*/ ()
{
return &m_value;
}
const uniform_type_info* type /*[[override]]*/ () const
{
return m_type;
}
const void* value /*[[override]]*/ () const
{
return &m_value;
}
};
} } // namespace cppa::util
#endif // DEFAULT_OBJECT_BASE_HPP
......@@ -66,14 +66,7 @@ class single_reader_queue
auto p = list.take();
if (p.first)
{
if (p.first == p.second)
{
push_front(p.first);
}
else
{
push_front(p.first, p.second);
}
push_front(p.first, p.second);
}
}
}
......@@ -103,6 +96,9 @@ class single_reader_queue
}
}
/**
* @warning call only from the reader (owner)
*/
bool empty()
{
return !m_head && !(m_tail.load());
......
......@@ -41,14 +41,9 @@ struct type_list<Head, Tail...> : abstract_type_list
return m_arr + type_list_size;
}
const utype& operator[](std::size_t pos) const
virtual const uniform_type_info* at(std::size_t pos) const
{
return *m_arr[pos];
}
virtual const utype& at(std::size_t pos) const
{
return *m_arr[pos];
return m_arr[pos];
}
virtual type_list* copy() const
......@@ -57,19 +52,27 @@ struct type_list<Head, Tail...> : abstract_type_list
}
template<typename TypeList>
static void init(const utype** what)
static void init(const uniform_type_info** what)
{
what[0] = uniform_typeid<typename TypeList::head_type>();
if (TypeList::type_list_size > 1)
{
++what;
init<typename TypeList::tail_type>(what);
}
/*
what[0] = &uniform_type_info<typename TypeList::head_type>();
if (TypeList::type_list_size > 1)
{
++what;
init<typename TypeList::tail_type>(what);
}
*/
}
private:
const utype* m_arr[type_list_size];
const uniform_type_info* m_arr[type_list_size];
};
......
#ifndef UTYPE_ITERATOR_HPP
#define UTYPE_ITERATOR_HPP
#include "cppa/uniform_type_info.hpp"
namespace cppa { namespace util {
struct utype_iterator
{
typedef const utype* const* arr_ptr;
arr_ptr m_pos;
public:
utype_iterator(arr_ptr p) : m_pos(p) { }
inline utype_iterator& operator++()
{
++m_pos;
return *this;
}
inline bool operator==(const utype_iterator& other) const
{
return m_pos == other.m_pos;
}
inline bool operator!=(const utype_iterator& other) const
{
return !(*this == other);
}
inline const utype& operator*()
{
return *m_pos[0];
}
inline const utype* operator->()
{
return m_pos[0];
}
};
} } // namespace cppa::util
#endif // UTYPE_ITERATOR_HPP
#ifndef UTYPE_HPP
#define UTYPE_HPP
#include <string>
#include <typeinfo>
#include "cppa/object.hpp"
#include "cppa/detail/comparable.hpp"
namespace cppa {
/**
* @brief Uniform type information.
*/
struct utype : detail::comparable<utype>,
detail::comparable<utype, std::type_info>
{
/**
* @brief Create an object of this type, initialized with
* the default constructor.
*/
virtual object* create() const = 0;
/**
* @brief Get the uniform type name (equal on all supported plattforms).
*/
virtual const std::string& name() const = 0;
/**
* @brief Get the result of typeid(T) where T is the native type.
*/
virtual const std::type_info& native() const = 0;
inline bool equal_to(const std::type_info& what) const
{
return native() == what;
}
inline bool equal_to(const utype& what) const
{
return native() == what.native();
}
};
} // namespace cppa
#endif // UTYPE_HPP
......@@ -7,28 +7,38 @@ INCLUDES = -I./
HEADERS = cppa/actor.hpp \
cppa/any_type.hpp \
cppa/config.hpp \
cppa/context.hpp \
cppa/cow_ptr.hpp \
cppa/cppa.hpp \
cppa/deserializer.hpp \
cppa/get.hpp \
cppa/group.hpp \
cppa/intrusive_ptr.hpp \
cppa/invoke.hpp \
cppa/invoke_rules.hpp \
cppa/match.hpp \
cppa/message.hpp \
cppa/message_queue.hpp \
cppa/object.hpp \
cppa/on.hpp \
cppa/ref_counted.hpp \
cppa/scheduler.hpp \
cppa/scheduling_hint.hpp \
cppa/serializer.hpp \
cppa/tuple.hpp \
cppa/tuple_view.hpp \
cppa/uniform_type_info.hpp \
cppa/untyped_tuple.hpp \
cppa/util.hpp \
cppa/detail/abstract_tuple.hpp \
cppa/detail/blocking_message_queue.hpp \
cppa/detail/converted_thread_context.hpp \
cppa/detail/decorated_tuple.hpp \
cppa/detail/channel.hpp \
cppa/detail/intermediate.hpp \
cppa/detail/invokable.hpp \
cppa/detail/matcher.hpp \
cppa/detail/ref_counted_impl.hpp \
cppa/detail/scheduler.hpp \
cppa/detail/tdata.hpp \
cppa/detail/tuple_vals.hpp \
cppa/util/a_matches_b.hpp \
......@@ -51,15 +61,20 @@ HEADERS = cppa/actor.hpp \
cppa/util/type_list.hpp \
cppa/util/type_list_apply.hpp \
cppa/util/type_list_pop_back.hpp \
cppa/util/utype_iterator.hpp \
cppa/util/void_type.hpp
SOURCES = src/actor_behavior.cpp \
src/blocking_message_queue.cpp \
src/channel.cpp \
src/context.cpp \
src/converted_thread_context.cpp \
src/demangle.cpp \
src/deserializer.cpp \
src/group.cpp \
src/mock_scheduler.cpp \
src/scheduler.cpp \
src/serializer.cpp \
src/to_uniform_name.cpp \
src/uniform_type_info.cpp \
src/untyped_tuple.cpp
......
#include "cppa/invoke_rules.hpp"
#include "cppa/util/singly_linked_list.hpp"
#include "cppa/detail/intermediate.hpp"
#include "cppa/detail/blocking_message_queue.hpp"
namespace cppa { namespace detail {
void blocking_message_queue::enqueue(const message& msg)
{
m_queue.push_back(new queue_node(msg));
}
const message& blocking_message_queue::dequeue()
{
queue_node* msg = m_queue.pop();
m_last_dequeued = std::move(msg->msg);
delete msg;
return m_last_dequeued;
}
void blocking_message_queue::dequeue(invoke_rules& rules)
{
queue_node* amsg = m_queue.pop();
util::singly_linked_list<queue_node> buffer;
intrusive_ptr<detail::intermediate> imd;
while (!(imd = rules.get_intermediate(amsg->msg.data())))
{
buffer.push_back(amsg);
amsg = m_queue.pop();
}
m_last_dequeued = amsg->msg;
if (!buffer.empty()) m_queue.push_front(std::move(buffer));
imd->invoke();
delete amsg;
}
bool blocking_message_queue::try_dequeue(message& msg)
{
if (!m_queue.empty())
{
msg = dequeue();
return true;
}
return false;
}
bool blocking_message_queue::try_dequeue(invoke_rules& rules)
{
if (!m_queue.empty())
{
dequeue(rules);
return true;
}
return false;
}
const message& blocking_message_queue::last_dequeued()
{
return m_last_dequeued;
}
} } // namespace hamcast::detail
#include "cppa/context.hpp"
#include "cppa/message.hpp"
#include "cppa/detail/converted_thread_context.hpp"
#include <boost/thread.hpp>
namespace {
void cleanup_fun(cppa::context* what)
{
if (what && !what->deref()) delete what;
}
boost::thread_specific_ptr<cppa::context> m_this_context(cleanup_fun);
} // namespace <anonymous>
namespace cppa {
void context::enqueue(const message& msg)
{
mailbox().enqueue(msg);
}
context* self()
{
context* result = m_this_context.get();
if (!result)
{
result = new detail::converted_thread_context;
result->ref();
m_this_context.reset(result);
}
return result;
}
void set_self(context* ctx)
{
if (ctx) ctx->ref();
context* old = m_this_context.get();
m_this_context.reset(ctx);
if (old)
{
cleanup_fun(ctx);
}
}
} // namespace cppa
#include "cppa/detail/converted_thread_context.hpp"
namespace cppa { namespace detail {
void converted_thread_context::link(intrusive_ptr<actor>& other)
{
std::lock_guard<std::mutex> guard(m_mtx);
if (other && !m_exited && other->establish_backlink(this))
{
m_links.insert(other);
}
}
bool converted_thread_context::remove_backlink(const intrusive_ptr<actor>& other)
{
if (other && other != this)
{
std::lock_guard<std::mutex> guard(m_mtx);
return m_links.erase(other) > 0;
}
return false;
}
bool converted_thread_context::establish_backlink(const intrusive_ptr<actor>& other)
{
if (other && other != this)
{
std::lock_guard<std::mutex> guard(m_mtx);
return m_links.insert(other).second;
}
return false;
}
void converted_thread_context::unlink(intrusive_ptr<actor>& other)
{
std::lock_guard<std::mutex> guard(m_mtx);
if (other && !m_exited && other->remove_backlink(this))
{
m_links.erase(other);
}
}
void converted_thread_context::join(group_ptr& what)
{
std::lock_guard<std::mutex> guard(m_mtx);
if (!m_exited && m_subscriptions.count(what) == 0)
{
m_subscriptions[what] = what->subscribe(this);
}
}
void converted_thread_context::leave(const group_ptr& what)
{
std::lock_guard<std::mutex> guard(m_mtx);
m_subscriptions.erase(what);
}
message_queue& converted_thread_context::mailbox()
{
return m_mailbox;
}
} } // namespace cppa::detail
#include <stdexcept>
#include "cppa/config.hpp"
#include "cppa/detail/demangle.hpp"
#ifdef CPPA_GCC
#include <cxxabi.h>
#endif
namespace cppa { namespace detail {
std::string demangle(const char* typeid_name)
{
size_t size;
int status;
char* undecorated = abi::__cxa_demangle(typeid_name, NULL, &size, &status);
if (status != 0)
{
std::string error_msg = "Could not demangle type name ";
error_msg += typeid_name;
throw std::logic_error(error_msg);
}
std::string result; // the undecorated typeid name
result.reserve(size);
const char* cstr = undecorated;
// this loop filter unnecessary characters from undecorated
for (char c = *cstr; c != '\0'; c = *++cstr)
{
if (c == ' ')
{
char previous_c = result.empty() ? ' ' : *(result.rbegin());
// get next non-space character
do { c = *++cstr; } while (c == ' ');
// 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;
}
}
else
{
result += c;
}
}
free(undecorated);
return result;
}
} } // namespace cppa::detail
#include "cppa/config.hpp"
#include <set>
#include <map>
#ifdef __APPLE__
#include "cppa/detail/cpp0x_thread_wrapper.hpp"
#else
#include <thread>
#endif
// for thread_specific_ptr
// needed unless the new keyword "thread_local" works in GCC
......@@ -14,201 +11,29 @@
#include "cppa/message.hpp"
#include "cppa/context.hpp"
#include "cppa/invoke_rules.hpp"
#include "cppa/detail/scheduler.hpp"
#include "cppa/util/singly_linked_list.hpp"
#include "cppa/util/single_reader_queue.hpp"
#include "cppa/scheduler.hpp"
#include "cppa/detail/mock_scheduler.hpp"
using namespace cppa;
#include "cppa/detail/converted_thread_context.hpp"
namespace {
struct actor_message
{
actor_message* next;
message msg;
actor_message(const message& from) : next(0), msg(from) { }
};
struct actor_impl;
void cleanup_fun(context* what);
boost::thread_specific_ptr<context> m_this_context(cleanup_fun);
struct mbox : message_queue
{
message m_last_dequeued;
util::single_reader_queue<actor_message> m_impl;
void enqueue(const message& msg)
{
m_impl.push_back(new actor_message(msg));
}
virtual const message& dequeue()
{
actor_message* msg = m_impl.pop();
m_last_dequeued = std::move(msg->msg);
delete msg;
return m_last_dequeued;
}
virtual void dequeue(invoke_rules& rules)
{
actor_message* amsg = m_impl.pop();
util::singly_linked_list<actor_message> buffer;
intrusive_ptr<detail::intermediate> imd;
while (!(imd = rules.get_intermediate(amsg->msg.data())))
{
buffer.push_back(amsg);
amsg = m_impl.pop();
}
m_last_dequeued = amsg->msg;
if (!buffer.empty()) m_impl.push_front(std::move(buffer));
imd->invoke();
delete amsg;
}
virtual bool try_dequeue(message& msg)
{
if (!m_impl.empty())
{
msg = dequeue();
return true;
}
return false;
}
virtual bool try_dequeue(invoke_rules& rules)
{
if (!m_impl.empty())
{
dequeue(rules);
return true;
}
return false;
}
virtual const message& last_dequeued()
{
return m_last_dequeued;
}
};
struct actor_impl : context
{
actor_behavior* m_behavior;
bool m_exited;
// guards m_exited, m_grp_lst and m_links
boost::mutex m_mtx;
std::map<group_ptr, intrusive_ptr<group::subscription> > m_grp_lst;
std::set<actor_ptr> m_links;
mbox m_mbox;
actor_impl(actor_behavior* b = nullptr) : m_behavior(b), m_exited(false) { }
~actor_impl()
{
if (m_behavior) delete m_behavior;
}
virtual void enqueue(const message& msg)
{
m_mbox.enqueue(msg);
}
virtual void link(intrusive_ptr<actor>& other)
{
boost::mutex::scoped_lock guard(m_mtx);
if (other && !m_exited && other->establish_backlink(this))
{
m_links.insert(other);
}
}
virtual bool remove_backlink(const intrusive_ptr<actor>& other)
{
if (other && other != this)
{
boost::mutex::scoped_lock guard(m_mtx);
return m_links.erase(other) > 0;
}
return false;
}
virtual bool establish_backlink(const intrusive_ptr<actor>& other)
{
if (other && other != this)
{
boost::mutex::scoped_lock guard(m_mtx);
return m_links.insert(other).second;
}
return false;
}
virtual void unlink(intrusive_ptr<actor>& other)
{
boost::mutex::scoped_lock guard(m_mtx);
if (other && !m_exited && other->remove_backlink(this))
{
m_links.erase(other);
}
}
virtual void join(group_ptr& what)
{
boost::mutex::scoped_lock guard(m_mtx);
if (!m_exited && m_grp_lst.count(what) == 0)
{
m_grp_lst[what] = what->subscribe(this);
}
}
virtual void leave(const group_ptr& what)
{
boost::mutex::scoped_lock guard(m_mtx);
m_grp_lst.erase(what);
}
virtual message_queue& mailbox()
{
return m_mbox;
}
};
void cleanup_fun(context* what)
{
if (what && !what->deref()) delete what;
}
std::atomic<int> m_running_actors(0);
boost::mutex m_ra_mtx;
boost::condition_variable m_ra_cv;
void run_actor_impl(intrusive_ptr<actor_impl> m_impl)
void run_actor(cppa::intrusive_ptr<cppa::context> m_self,
cppa::actor_behavior* behavior)
{
{
actor_impl* self_ptr = m_impl.get();
self_ptr->ref();
m_this_context.reset(self_ptr);
}
actor_behavior* ab = m_impl->m_behavior;
if (ab)
cppa::set_self(m_self.get());
if (behavior)
{
try
{
ab->act();
behavior->act();
}
catch(...) { }
ab->on_exit();
behavior->on_exit();
}
if (--m_running_actors == 0)
{
......@@ -221,27 +46,15 @@ void run_actor_impl(intrusive_ptr<actor_impl> m_impl)
namespace cppa { namespace detail {
actor_ptr scheduler::spawn(actor_behavior* ab, scheduling_hint)
actor_ptr mock_scheduler::spawn(actor_behavior* ab, scheduling_hint)
{
++m_running_actors;
intrusive_ptr<actor_impl> result(new actor_impl(ab));
boost::thread(run_actor_impl, result).detach();
return result;
}
context* scheduler::get_context()
{
context* result = m_this_context.get();
if (!result)
{
result = new actor_impl;
result->ref();
m_this_context.reset(result);
}
return result;
intrusive_ptr<context> ctx(new detail::converted_thread_context);
boost::thread(run_actor, ctx, ab).detach();
return ctx;
}
void scheduler::await_all_done()
void mock_scheduler::await_all_done()
{
boost::mutex::scoped_lock lock(m_ra_mtx);
while (m_running_actors.load() > 0)
......
#include <atomic>
#define _GLIBCXX_HAS_GTHREADS
#include <mutex>
#include "cppa/scheduler.hpp"
#include "cppa/detail/mock_scheduler.hpp"
namespace {
std::mutex m_instance_mtx;
std::atomic<cppa::scheduler*> m_instance;
}
namespace cppa {
scheduler::~scheduler() { }
scheduler* get_scheduler()
{
scheduler* result = m_instance.load();
if (!result)
{
std::lock_guard<std::mutex> lock(m_instance_mtx);
result = m_instance.load();
if (!result)
{
result = new detail::mock_scheduler;
m_instance.store(result);
}
}
return result;
}
} // namespace cppa
#include <map>
#include <cwchar>
#include <limits>
#include <vector>
#include <typeinfo>
#include <stdexcept>
#include <algorithm>
#include "cppa/detail/demangle.hpp"
#include "cppa/detail/to_uniform_name.hpp"
namespace {
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(std::numeric_limits<T>::is_integer, "T is not an integer");
return std::numeric_limits<T>::is_signed ? 0 : 1;
}
template<typename T>
inline std::string demangled()
{
return cppa::detail::demangle(typeid(T).name());
}
template<typename T>
constexpr const char* mapped_int_name()
{
return mapped_int_names[sizeof(T)][sign_index<T>()];
}
template<typename Iterator>
std::string to_uniform_name_impl(Iterator begin, Iterator end,
bool first_run = false)
{
// all integer type names as uniform representation
static std::map<std::string, std::string> mapped_demangled_names =
{
{ 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<wchar_t>(), mapped_int_name<wchar_t>() },
{ demangled<char16_t>(), mapped_int_name<char16_t>() },
{ demangled<char32_t>(), mapped_int_name<char32_t>() },
{ demangled<std::wstring>(), "@wstr" },
{ demangled<std::string>(), "@str" }
};
// check if we could find the whole string in our lookup map
if (first_run)
{
std::string tmp(begin, end);
auto i = mapped_demangled_names.find(tmp);
if (i != mapped_demangled_names.end())
{
return i->second;
}
}
// does [begin, end) represents an empty string?
if (begin == end) return "";
// derived reverse_iterator type
typedef std::reverse_iterator<Iterator> reverse_iterator;
// a subsequence [begin', end') within [begin, end)
typedef std::pair<Iterator, Iterator> subseq;
std::vector<subseq> substrings;
// explode string if we got a list of types
int open_brackets = 0; // counts "open" '<'
// denotes the begin of a possible subsequence
Iterator anchor = begin;
for (Iterator i = begin; i != end; /* i is incemented in the loop */)
{
switch (*i)
{
case '<':
++open_brackets;
++i;
break;
case '>':
if (--open_brackets < 0)
{
throw std::runtime_error("malformed string");
}
++i;
break;
case ',':
if (open_brackets == 0)
{
substrings.push_back(std::make_pair(anchor, i));
++i;
anchor = i;
}
else
{
++i;
}
break;
default:
++i;
break;
}
}
// call recursively for each list argument
if (!substrings.empty())
{
std::string result;
substrings.push_back(std::make_pair(anchor, end));
for (const subseq& sstr : substrings)
{
if (!result.empty()) result += ",";
result += to_uniform_name_impl(sstr.first, sstr.second);
}
return result;
}
// we didn't got a list, compute unify name
else
{
// is [begin, end) a template?
Iterator substr_begin = std::find(begin, end, '<');
if (substr_begin == end)
{
// not a template, return mapping
std::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 = std::find(reverse_iterator(end),
reverse_iterator(substr_begin),
'>')
// get as an Iterator
.base();
// skip trailing '>'
--substr_end;
if (substr_end == substr_begin)
{
throw std::runtime_error("substr_end == substr_begin");
}
std::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;
}
}
} // namespace <anonymous>
namespace cppa { namespace detail {
std::string to_uniform_name(const std::string& dname)
{
static std::string an = "(anonymous namespace)";
static std::string an_replacement = "@_";
auto r = to_uniform_name_impl(dname.begin(), dname.end(), true);
// replace all occurrences of an with "@_"
if (r.size() > an.size())
{
auto i = std::search(r.begin(), r.end(), an.begin(), an.end());
while (i != r.end())
{
auto substr_end = i + an.size();
r.replace(i, substr_end, an_replacement);
// next iteration
i = std::search(r.begin(), r.end(), an.begin(), an.end());
}
}
return r;
}
} } // namespace cppa::detail
#include <limits>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <memory>
#include <cstdint>
#include <cassert>
#include <iostream>
#include <algorithm>
#include <stdexcept>
#include <atomic>
#include <limits>
#include <cstdint>
#include <sstream>
#include <type_traits>
#include "cppa/config.hpp"
#include "cppa/actor.hpp"
#include "cppa/any_type.hpp"
#include "cppa/intrusive_ptr.hpp"
#include "cppa/uniform_type_info.hpp"
#ifdef CPPA_GCC
#include <cxxabi.h>
#endif
#include "cppa/util/default_object_base.hpp"
using std::cout;
using std::endl;
#include "cppa/detail/demangle.hpp"
#include "cppa/detail/to_uniform_name.hpp"
#include "cppa/detail/default_object_impl.hpp"
namespace {
namespace std {
typedef std::map<std::string, std::string> string_map;
inline ostream& operator<<(ostream& o, const cppa::any_type&) { return o; }
inline istream& operator>>(istream& i, cppa::any_type&) { return i; }
template<int Size, bool IsSigned>
struct int_helper { };
inline ostream& operator<<(ostream& o, const cppa::actor_ptr&) { return o; }
inline istream& operator>>(istream& i, cppa::actor_ptr&) { return i; }
template<>
struct int_helper<1, true>
{
static std::string name() { return "@i8"; }
};
} // namespace std
template<>
struct int_helper<2, true>
{
static std::string name() { return "@i16"; }
};
namespace {
template<>
struct int_helper<4, true>
inline const char* raw_name(const std::type_info& tinfo)
{
static std::string name() { return "@i32"; }
};
#ifdef CPPA_WINDOWS
return tinfo.raw_name();
#else
return tinfo.name();
#endif
}
template<>
struct int_helper<8, true>
class wstring_obj : public cppa::util::default_object_base<std::wstring>
{
static std::string name() { return "@i64"; }
};
template<>
struct int_helper<1, false>
{
static std::string name() { return "@u8"; }
};
typedef cppa::util::default_object_base<std::wstring> super;
template<>
struct int_helper<2, false>
{
static std::string name() { return "@u16"; }
};
public:
template<>
struct int_helper<4, false>
{
static std::string name() { return "@u32"; }
};
wstring_obj(const cppa::uniform_type_info* uti) : super(uti) { }
void deserialize(cppa::deserializer&)
{
}
void from_string(const std::string&)
{
}
cppa::object* copy() const
{
return new wstring_obj(type());
}
std::string to_string() const
{
return "";
}
void serialize(cppa::serializer&) const
{
}
template<>
struct int_helper<8, false>
{
static std::string name() { return "@u64"; }
};
template<typename T>
struct uniform_int : int_helper<sizeof(T), std::numeric_limits<T>::is_signed>{};
inline const char* raw_name()
{
return raw_name(typeid(T));
}
std::map<std::string, cppa::utype*>* ut_map = nullptr;
typedef std::set<std::string> string_set;
#ifdef CPPA_GCC
template<typename T>
std::string raw_name()
template<typename Int>
void push(std::map<int, std::pair<string_set, string_set>>& ints,
std::integral_constant<bool, true>)
{
size_t size;
int status;
char* undecorated = abi::__cxa_demangle(typeid(T).name(),
NULL, &size, &status);
assert(status == 0);
std::string result(undecorated, size);
free(undecorated);
return result;
ints[sizeof(Int)].first.insert(raw_name<Int>());
}
#elif defined(CPPA_WINDOWS)
template<typename T>
inline const char* raw_name()
template<typename Int>
void push(std::map<int, std::pair<string_set, string_set>>& ints,
std::integral_constant<bool, false>)
{
return typeid(T).name();
ints[sizeof(Int)].second.insert(raw_name<Int>());
}
#endif
std::unique_ptr<string_map> btm_ptr;
template<typename Int>
void push(std::map<int, std::pair<string_set, string_set>>& ints)
{
push<Int>(ints, std::integral_constant<bool, std::numeric_limits<Int>::is_signed>());
}
const string_map& builtin_type_mappings()
template<typename Int0, typename Int1, typename... Ints>
void push(std::map<int, std::pair<string_set, string_set>>& ints)
{
if (!btm_ptr)
{
string_map* value = new string_map
{
{ raw_name<char>(),
uniform_int<char>::name() },
{ raw_name<signed char>(),
uniform_int<signed char>::name() },
{ raw_name<unsigned char>(),
uniform_int<unsigned char>::name() },
{ raw_name<short>(),
uniform_int<short>::name() },
{ raw_name<signed short>(),
uniform_int<signed short>::name() },
{ raw_name<unsigned short>(),
uniform_int<unsigned short>::name() },
{ raw_name<short int>(),
uniform_int<short int>::name() },
{ raw_name<signed short int>(),
uniform_int<signed short int>::name() },
{ raw_name<unsigned short int>(),
uniform_int<unsigned short int>::name() },
{ raw_name<int>(),
uniform_int<int>::name() },
{ raw_name<signed int>(),
uniform_int<signed int>::name() },
{ raw_name<unsigned int>(),
uniform_int<unsigned int>::name() },
{ raw_name<long>(),
uniform_int<long>::name() },
{ raw_name<signed long>(),
uniform_int<signed long>::name() },
{ raw_name<unsigned long>(),
uniform_int<unsigned long>::name() },
{ raw_name<long int>(),
uniform_int<long int>::name() },
{ raw_name<signed long int>(),
uniform_int<signed long int>::name() },
{ raw_name<unsigned long int>(),
uniform_int<unsigned long int>::name() },
{ raw_name<long long>(),
uniform_int<long long>::name() },
{ raw_name<signed long long>(),
uniform_int<signed long long>::name() },
{ raw_name<unsigned long long>(),
uniform_int<unsigned long long>::name() },
{ raw_name<std::string>(),
"@str" },
{ raw_name<std::wstring>(),
"@wstr" }
// "std::basic_string<char,std::char_traits<char>,std::allocator<char>>" }
};
btm_ptr.reset(value);
return *btm_ptr;
}
else
{
return *btm_ptr;
}
push<Int0>(ints, std::integral_constant<bool, std::numeric_limits<Int0>::is_signed>());
push<Int1, Ints...>(ints);
}
} // namespace <anonymous>
namespace cppa { namespace detail {
namespace cppa { namespace detail { namespace {
std::string demangle_impl(const char* begin, const char* end, size_t size)
class uniform_type_info_map
{
// demangling of a template?
const char* pos = std::find(begin, end, '<');
if (pos == end)
typedef std::map<std::string, uniform_type_info*> uti_map;
// maps typeid names to uniform type informations
uti_map m_by_tname;
// maps uniform names to uniform type informations
uti_map m_by_uname;
template<typename ObjImpl>
void insert(const std::set<std::string>& tnames)
{
return std::string(begin, size);
if (tnames.empty())
{
throw std::logic_error("tnames.empty()");
}
std::string uname = to_uniform_name(demangle(tnames.begin()->c_str()));
auto uti = new default_uniform_type_info_impl<ObjImpl>(uname);
for (const std::string& tname : tnames)
{
m_by_tname.insert(std::make_pair(tname, uti));
}
m_by_uname.insert(std::make_pair(uti->name(), uti));
}
else
template<typename T>
void insert()
{
std::string processed(begin, pos);
std::string tmp;
// skip leading '<'
for ( ++pos; pos != end; ++pos)
std::string tname(raw_name<T>());
insert<default_object_impl<T>>({tname});
}
public:
uniform_type_info_map()
{
insert<std::string>();
insert<wstring_obj>({std::string(raw_name<std::wstring>())});
insert<float>();
if (sizeof(double) == sizeof(long double))
{
char c = *pos;
switch (c)
{
std::string dbl = raw_name<double>();
std::string ldbl = raw_name<long double>();
insert<default_object_impl<double>>({ dbl, ldbl });
}
else
{
insert<double>();
insert<long double>();
}
insert<any_type>();
insert<actor_ptr>();
// first: signed
// second: unsigned
std::map<int, std::pair<string_set, string_set>> ints;
push<char,
signed char,
unsigned char,
short,
signed short,
unsigned short,
short int,
signed short int,
unsigned short int,
int,
signed int,
unsigned int,
long int,
signed long int,
unsigned long int,
long,
signed long,
unsigned long,
long long,
signed long long,
unsigned long long,
wchar_t,
char16_t,
char32_t>(ints);
insert<default_object_impl<std::int8_t>>(ints[sizeof(std::int8_t)].first);
insert<default_object_impl<std::uint8_t>>(ints[sizeof(std::uint8_t)].second);
insert<default_object_impl<std::int16_t>>(ints[sizeof(std::int16_t)].first);
insert<default_object_impl<std::uint16_t>>(ints[sizeof(std::uint16_t)].second);
insert<default_object_impl<std::int32_t>>(ints[sizeof(std::int32_t)].first);
insert<default_object_impl<std::uint32_t>>(ints[sizeof(std::uint32_t)].second);
insert<default_object_impl<std::int64_t>>(ints[sizeof(std::int64_t)].first);
insert<default_object_impl<std::uint64_t>>(ints[sizeof(std::uint64_t)].second);
//insert<std::wstring>();
}
case ',':
case '>':
case '<':
{
// erase trailing whitespaces
while (!tmp.empty() && (*(tmp.rbegin()) == ' '))
{
tmp.resize(tmp.size() - 1);
}
auto i = builtin_type_mappings().find(tmp);
if (i != builtin_type_mappings().end())
{
processed += i->second;
}
else
{
processed += tmp;
}
}
processed += c;
tmp.clear();
break;
case ' ':
// the VC++ compiler adds "class" and "struct" before type names
if (tmp == "class" || tmp == "struct")
{
tmp.clear();
}
else
{
// ignore leading spaces
if (!tmp.empty()) tmp += ' ';
}
break;
default:
tmp += c;
break;
uniform_type_info* by_raw_name(const std::string& name)
{
auto i = m_by_tname.find(name);
if (i != m_by_tname.end())
{
return i->second;
}
return nullptr;
}
}
uniform_type_info* by_uniform_name(const std::string& name)
{
auto i = m_by_uname.find(name);
if (i != m_by_uname.end())
{
return i->second;
}
return processed;
return nullptr;
}
}
std::string demangle(const char* decorated_type_name)
{
# ifdef CPPA_WINDOWS
result = type_name;
std::vector<std::string> needles;
needles.push_back("class ");
needles.push_back("struct ");
// the VC++ compiler adds "class " and "struct " before type names
for (size_t i = 0; i < needles.size(); ++i)
bool insert(std::set<std::string> plain_names,
uniform_type_info* what)
{
const std::string& needle = needles[i];
bool string_changed = false;
do
if (m_by_uname.count(what->name()) > 0)
{
// result is our haystack
size_t pos = result.find(needle);
if (pos != std::string::npos)
return false;
}
m_by_uname.insert(std::make_pair(what->name(), what));
for (const std::string& plain_name : plain_names)
{
if (!m_by_tname.insert(std::make_pair(plain_name, what)).second)
{
result.erase(pos, needle.size());
string_changed = true;
throw std::runtime_error(plain_name + " already mapped to an uniform_type_info");
}
else string_changed = false;
}
while (string_changed);
return true;
}
# elif defined(CPPA_GCC)
size_t size = 0;
int status = 0;
char* undecorated = abi::__cxa_demangle(decorated_type_name,
NULL, &size, &status);
assert(status == 0);
std::string result = demangle_impl(undecorated, undecorated + size, size);
free(undecorated);
# else
# error "Unsupported plattform"
# endif
// template class?
auto i = builtin_type_mappings().find(result);
if (i != builtin_type_mappings().end())
std::vector<uniform_type_info*> get_all()
{
result = i->second;
std::vector<uniform_type_info*> result;
result.reserve(m_by_uname.size());
for (const uti_map::value_type& i : m_by_uname)
{
result.push_back(i.second);
}
return std::move(result);
}
return result;
}
std::map<std::string, utype*>& uniform_types()
};
uniform_type_info_map& s_uniform_type_info_map()
{
if (!ut_map)
{
ut_map = new std::map<std::string, utype*>();
}
return *ut_map;
static uniform_type_info_map s_utimap;
return s_utimap;
}
} } // namespace cppa
} } } // namespace detail::<anonymous>
namespace {
std::atomic<int> s_ids;
inline int next_id() { return s_ids.fetch_add(1); }
} // namespace <anonymous>
namespace cppa {
const utype& uniform_type_info(const std::string& uniform_type_name)
uniform_type_info::uniform_type_info(const std::string& uniform_type_name)
: m_id(next_id()), m_name(uniform_type_name)
{
}
uniform_type_info::~uniform_type_info()
{
}
uniform_type_info* uniform_type_info::by_type_info(const std::type_info& tinf)
{
decltype(detail::uniform_types()) ut = detail::uniform_types();
auto i = ut.find(uniform_type_name);
if (i == ut.end())
auto result = detail::s_uniform_type_info_map().by_raw_name(raw_name(tinf));
if (!result)
{
throw std::runtime_error("");
throw std::runtime_error(std::string(raw_name(tinf))
+ " is an unknown typeid name");
}
else
return result;
}
uniform_type_info* uniform_type_info::by_uniform_name(const std::string& name)
{
auto result = detail::s_uniform_type_info_map().by_uniform_name(name);
if (!result)
{
return *(i->second);
throw std::runtime_error(name + " is an unknown typeid name");
}
return result;
}
bool uniform_type_info::announce(const std::type_info& plain_type,
uniform_type_info* uniform_type)
{
string_set tmp = { std::string(raw_name(plain_type)) };
if (!detail::s_uniform_type_info_map().insert(tmp, uniform_type))
{
delete uniform_type;
return false;
}
return true;
}
std::vector<uniform_type_info*> uniform_type_info::get_all()
{
return detail::s_uniform_type_info_map().get_all();
}
} // namespace cppa
......@@ -14,7 +14,7 @@ struct empty_type_list : cppa::util::abstract_type_list
virtual const_iterator end() const { return 0; }
virtual const cppa::utype& at(std::size_t) const
virtual const cppa::uniform_type_info* at(std::size_t) const
{
throw std::range_error("empty_type_list::at()");
}
......@@ -40,7 +40,7 @@ struct empty_tuple : cppa::detail::abstract_tuple
throw std::range_error("empty_tuple::at()");
}
virtual const cppa::utype& utype_at(std::size_t) const
virtual const cppa::uniform_type_info* utype_at(std::size_t) const
{
throw std::range_error("empty_tuple::utype_at()");
}
......
......@@ -22,6 +22,7 @@ SOURCES = hash_of.cpp \
test__serialization.cpp \
test__spawn.cpp \
test__tuple.cpp \
test__uniform_type.cpp \
test__type_list.cpp
OBJECTS = $(SOURCES:.cpp=.o)
......
......@@ -54,14 +54,15 @@ int main(int argc, char** c_argv)
{
std::cout << std::boolalpha;
std::size_t errors = 0;
RUN_TEST(test__a_matches_b);
RUN_TEST(test__uniform_type);
RUN_TEST(test__intrusive_ptr);
RUN_TEST(test__spawn);
RUN_TEST(test__tuple);
RUN_TEST(test__a_matches_b);
RUN_TEST(test__type_list);
RUN_TEST(test__tuple);
RUN_TEST(test__serialization);
RUN_TEST(test__atom);
RUN_TEST(test__spawn);
RUN_TEST(test__local_group);
RUN_TEST(test__atom);
cout << endl
<< "error(s) in all tests: " << errors
<< endl;
......
......@@ -13,8 +13,7 @@ struct cppa_test_scope \
{ \
std::cout << error_count << " error(s) detected" << std::endl; \
} \
} cppa_ts; \
std::size_t& error_count = cppa_ts.error_count
} cppa_ts;
#define CPPA_TEST_RESULT cppa_ts.error_count
......@@ -23,7 +22,7 @@ if (!(line_of_code)) \
{ \
std::cerr << "ERROR in file " << __FILE__ << " on line " << __LINE__ \
<< " => " << #line_of_code << std::endl; \
++error_count; \
++cppa_ts.error_count; \
} ((void) 0)
#define CPPA_CHECK_EQUAL(lhs_loc, rhs_loc) \
......@@ -31,9 +30,10 @@ if ((lhs_loc) != (rhs_loc)) \
{ \
std::cerr << "ERROR in file " << __FILE__ << " on line " << __LINE__ \
<< " => " << #lhs_loc << " != " << #rhs_loc << std::endl; \
++error_count; \
++cppa_ts.error_count; \
} ((void) 0)
std::size_t test__uniform_type();
std::size_t test__type_list();
std::size_t test__a_matches_b();
std::size_t test__atom();
......
......@@ -89,11 +89,11 @@ struct storage
template<typename T>
T& get(const std::string& key)
{
const utype& uti = uniform_type_info<T>();
auto uti = uniform_type_info::by_type_info(typeid(T));
auto i = m_map.find(key);
if (i == m_map.end())
{
i = m_map.insert(std::make_pair(key, uti.create())).first;
i = m_map.insert(std::make_pair(key, uti->create())).first;
}
else if (uti != i->second->type())
{
......
......@@ -27,21 +27,14 @@ using std::endl;
using namespace cppa;
using namespace cppa::util;
class format_error : public std::exception
class format_error : public std::runtime_error
{
std::string m_what;
typedef std::runtime_error super;
public:
format_error(const std::string& what_str) : m_what(what_str) { }
virtual const char* what() const throw()
{
return m_what.c_str();
}
virtual ~format_error() throw() { }
format_error(const std::string& what_str) : super(what_str) { }
};
......@@ -171,22 +164,22 @@ struct obj_types : util::abstract_type_list
{
std::size_t m_size;
const utype** m_arr;
const uniform_type_info** m_arr;
public:
obj_types(const std::vector<intrusive_ptr<object>>& objs) : m_size(objs.size())
{
m_arr = new const utype*[m_size];
m_arr = new const uniform_type_info*[m_size];
for (std::size_t i = 0; i != m_size; ++i)
{
m_arr[i] = &(objs[i]->type());
m_arr[i] = objs[i]->type();
}
}
obj_types(const obj_types& other) : m_size(other.size())
{
m_arr = new const utype*[m_size];
m_arr = new const uniform_type_info*[m_size];
for (std::size_t i = 0; i != m_size; ++i)
{
m_arr[i] = other.m_arr[i];
......@@ -215,9 +208,9 @@ struct obj_types : util::abstract_type_list
return m_arr + m_size;
}
virtual const utype& at(std::size_t pos) const
virtual const uniform_type_info* at(std::size_t pos) const
{
return *m_arr[pos];
return m_arr[pos];
}
};
......@@ -258,7 +251,7 @@ class obj_tuple : public detail::abstract_tuple
return m_obj[pos]->value();
}
virtual const utype& utype_at(std::size_t pos) const
virtual const uniform_type_info* utype_at(std::size_t pos) const
{
return m_obj[pos]->type();
}
......@@ -279,7 +272,7 @@ class obj_tuple : public detail::abstract_tuple
for (std::size_t i = 0; i < m_obj.size(); ++i)
{
decltype(m_obj[i]) o = m_obj[i];
s << o->type().name();
s << o->type()->name();
o->serialize(s);
}
}
......@@ -342,7 +335,7 @@ struct serialize_tuple_at
{
inline static void _(serializer& s, const Tuple& t)
{
s << uniform_type_info<typename type_at<Pos, Tuple>::type>().name()
s << uniform_typeid<typename type_at<Pos, Tuple>::type>()->name()
<< t.get<Pos>();
serialize_tuple_at<Pos + 1, Size, Tuple>::_(s, t);
}
......@@ -365,15 +358,6 @@ serializer& operator<<(serializer& s, const tuple<Types...>& t)
serializer& operator<<(serializer& s, const untyped_tuple& ut)
{
/*
auto tsize = static_cast<std::uint8_t>(ut.size());
s << tsize;
for (std::size_t i = 0; i < ut.size(); ++i)
{
s << ut.utype_at(i).name();
}
*/
ut.vals()->serialize(s);
return s;
}
......@@ -387,7 +371,7 @@ deserializer& operator>>(deserializer& d, untyped_tuple& ut)
{
std::string type_name;
d >> type_name;
object* obj = uniform_type_info(type_name).create();
object* obj = uniform_type_info::by_uniform_name(type_name)->create();
obj->deserialize(d);
obj_vec.push_back(obj);
}
......@@ -423,8 +407,8 @@ std::size_t test__serialization()
obj_vec.reserve(2);
obj_vec.push_back(uniform_type_info<std::string>().create());
obj_vec.push_back(uniform_type_info<int>().create());
obj_vec.push_back(uniform_typeid<std::string>()->create());
obj_vec.push_back(uniform_typeid<int>()->create());
cow_ptr<detail::abstract_tuple> vals(new obj_tuple(obj_vec));
untyped_tuple ut0(vals);
......@@ -465,15 +449,6 @@ std::size_t test__serialization()
deserializer d(io1);
untyped_tuple ut3;
d >> ut3;
/*
cout << "ut3 (size = " << ut3.size() << "): ";
for (std::size_t i = 0; i < ut3.size(); ++i)
{
if (i > 0) cout << ", ";
cout << ut3.utype_at(i).name();
}
cout << endl;
*/
std::vector<std::size_t> mappings;
bool does_match = match<std::string, std::string, int, int, int>(ut3, mappings);
CPPA_CHECK_EQUAL(does_match, true);
......
......@@ -6,7 +6,6 @@
#include "cppa/on.hpp"
#include "cppa/cppa.hpp"
#include "cppa/actor.hpp"
#include "cppa/detail/scheduler.hpp"
using std::cout;
using std::endl;
......
#include <string>
#include <cstdint>
#include <typeinfo>
#include <type_traits>
......@@ -46,6 +47,20 @@ std::size_t test__type_list()
CPPA_CHECK((is_same<int, l2::head_type>::value));
CPPA_CHECK((is_same<l1, l2::tail_type>::value));
type_list<std::int32_t, float, char> ifc;
auto i = ifc.begin();
CPPA_CHECK((i != ifc.end()));
CPPA_CHECK(((*i)->name() == "@i32"));
++i;
CPPA_CHECK((i != ifc.end()));
CPPA_CHECK(((*i)->name() == "float"));
++i;
CPPA_CHECK((i != ifc.end()));
CPPA_CHECK(((*i)->name() == "@i8"));
++i;
CPPA_CHECK((i == ifc.end()));
return CPPA_TEST_RESULT;
}
#include <map>
#include <set>
#include <cctype>
#include <atomic>
#include <vector>
#include <string>
#include <cstdint>
#include <cstring>
#include <sstream>
#include <iostream>
#include <iterator>
#include <algorithm>
#include <stdexcept>
#include "test.hpp"
#include "cppa/uniform_type_info.hpp"
#include "cppa/util/default_object_base.hpp"
using std::cout;
using std::endl;
using cppa::uniform_type_info;
namespace {
struct foo
{
int value;
foo(int val = 0) : value(val) { }
};
class foo_object : public cppa::util::default_object_base<foo>
{
typedef default_object_base<foo> super;
public:
foo_object(const uniform_type_info* uti, const foo& val = foo())
: super(uti, val) { }
object* copy /*[[override]]*/ () const
{
return new foo_object(type(), m_value);
}
std::string to_string /*[[override]]*/ () const
{
std::ostringstream sstr;
sstr << m_value.value;
return sstr.str();
}
void from_string /*[[override]]*/ (const std::string& str)
{
int tmp;
std::istringstream istr(str);
istr >> tmp;
m_value.value = tmp;
}
void deserialize(cppa::deserializer&) { }
void serialize(cppa::serializer&) const { }
};
bool unused1 = cppa::uniform_type_info::announce<foo_object>(typeid(foo));
bool unused2 = cppa::uniform_type_info::announce<foo_object>(typeid(foo));
bool unused3 = cppa::uniform_type_info::announce<foo_object>(typeid(foo));
bool unused4 = cppa::uniform_type_info::announce<foo_object>(typeid(foo));
typedef cppa::intrusive_ptr<cppa::object> obj_ptr;
} // namespace <anonymous>
std::size_t test__uniform_type()
{
CPPA_TEST(test__uniform_type);
int successful_announces = (unused1 ? 1 : 0)
+ (unused2 ? 1 : 0)
+ (unused3 ? 1 : 0)
+ (unused4 ? 1 : 0);
CPPA_CHECK_EQUAL(successful_announces, 1);
// test foo_object implementation
obj_ptr o = cppa::uniform_typeid<foo>()->create();
o->from_string("123");
CPPA_CHECK_EQUAL(o->to_string(), "123");
int val = reinterpret_cast<const foo*>(o->value())->value;
CPPA_CHECK_EQUAL(val, 123);
// these types (and only those) are present if the uniform_type_info
// implementation is correct
std::set<std::string> expected =
{
"@_::foo", // name of <anonymous namespace>::foo
"@i8", "@i16", "@i32", "@i64", // signed integer names
"@u8", "@u16", "@u32", "@u64", // unsigned integer names
"@str", "@wstr", // strings
"float", "double", // floating points
// default announced cppa types
"cppa::any_type",
"cppa::intrusive_ptr<cppa::actor>"
};
if (sizeof(double) != sizeof(long double))
{
// long double is only present if it's not an alias for double
expected.insert("long double");
}
// holds the type names we see at runtime
std::set<std::string> found;
// fetch all available type names
auto types = cppa::uniform_type_info::get_all();
for (cppa::uniform_type_info* tinfo : types)
{
found.insert(tinfo->name());
}
// compare the two sets
CPPA_CHECK_EQUAL(expected.size(), found.size());
if (expected.size() == found.size())
{
CPPA_CHECK((std::equal(found.begin(), found.end(), expected.begin())));
}
return CPPA_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