Commit b07c74d8 authored by neverlord's avatar neverlord

to_string, from_string, uniform name improvements, type_list stuff, etc

parent 4c840dac
...@@ -135,7 +135,7 @@ ...@@ -135,7 +135,7 @@
</data> </data>
<data> <data>
<variable>ProjectExplorer.Project.Updater.EnvironmentId</variable> <variable>ProjectExplorer.Project.Updater.EnvironmentId</variable>
<value type="QString">{07fcd197-092d-45a0-8500-3be614e6ae31}</value> <value type="QString">{23902c37-f07e-47cd-bb19-c366b9f708db}</value>
</data> </data>
<data> <data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable> <variable>ProjectExplorer.Project.Updater.FileVersion</variable>
......
...@@ -94,7 +94,6 @@ queue_performances/blocking_cached_stack2.hpp ...@@ -94,7 +94,6 @@ queue_performances/blocking_cached_stack2.hpp
queue_performances/blocking_sutter_list.hpp queue_performances/blocking_sutter_list.hpp
queue_performances/lockfree_list.hpp queue_performances/lockfree_list.hpp
queue_performances/intrusive_sutter_list.hpp queue_performances/intrusive_sutter_list.hpp
cppa/detail/cpp0x_thread_wrapper.hpp
src/context.cpp src/context.cpp
cppa/scheduler.hpp cppa/scheduler.hpp
cppa/detail/mock_scheduler.hpp cppa/detail/mock_scheduler.hpp
...@@ -151,3 +150,6 @@ cppa/util/abstract_uniform_type_info.hpp ...@@ -151,3 +150,6 @@ cppa/util/abstract_uniform_type_info.hpp
cppa/util/upgrade_lock_guard.hpp cppa/util/upgrade_lock_guard.hpp
cppa/exit_signal.hpp cppa/exit_signal.hpp
src/exit_signal.cpp src/exit_signal.cpp
cppa/to_string.hpp
src/string_serialization.cpp
cppa/from_string.hpp
...@@ -29,21 +29,119 @@ ...@@ -29,21 +29,119 @@
#ifndef CPPA_HPP #ifndef CPPA_HPP
#define CPPA_HPP #define CPPA_HPP
#include <tuple>
#include <type_traits>
#include "cppa/tuple.hpp" #include "cppa/tuple.hpp"
#include "cppa/actor.hpp" #include "cppa/actor.hpp"
#include "cppa/invoke.hpp" #include "cppa/invoke.hpp"
#include "cppa/channel.hpp" #include "cppa/channel.hpp"
#include "cppa/context.hpp" #include "cppa/context.hpp"
#include "cppa/message.hpp" #include "cppa/message.hpp"
#include "cppa/scheduler.hpp"
#include "cppa/invoke_rules.hpp" #include "cppa/invoke_rules.hpp"
#include "cppa/actor_behavior.hpp" #include "cppa/actor_behavior.hpp"
#include "cppa/scheduling_hint.hpp" #include "cppa/scheduling_hint.hpp"
#include "cppa/scheduler.hpp"
#include "cppa/util/rm_ref.hpp"
#include "cppa/util/enable_if.hpp"
#include "cppa/util/disable_if.hpp"
namespace cppa { namespace cppa {
namespace detail {
template<bool IsFunctionPtr, typename F>
class fun_behavior : public actor_behavior
{
F m_fun;
public:
fun_behavior(F ptr) : m_fun(ptr) { }
virtual void act()
{
m_fun();
}
};
template<typename F>
class fun_behavior<false, F> : public actor_behavior
{
F m_fun;
public:
fun_behavior(const F& arg) : m_fun(arg) { }
fun_behavior(F&& arg) : m_fun(std::move(arg)) { }
virtual void act()
{
m_fun();
}
};
template<typename R>
actor_behavior* get_behavior(std::integral_constant<bool,true>, R (*fptr)())
{
return new fun_behavior<true, R (*)()>(fptr);
}
template<typename F>
actor_behavior* get_behavior(std::integral_constant<bool,false>, F&& ftor)
{
typedef typename util::rm_ref<F>::type ftype;
return new fun_behavior<false, ftype>(std::forward<F>(ftor));
}
template<typename F, typename Arg0, typename... Args>
actor_behavior* get_behavior(std::integral_constant<bool,true>,
F fptr,
const Arg0& arg0,
const Args&... args)
{
auto arg_tuple = std::make_tuple(arg0, args...);
auto lambda = [fptr, arg_tuple]() { invoke(fptr, arg_tuple); };
return new fun_behavior<false, decltype(lambda)>(std::move(lambda));
}
template<typename F, typename Arg0, typename... Args>
actor_behavior* get_behavior(std::integral_constant<bool,false>,
F ftor,
const Arg0& arg0,
const Args&... args)
{
auto arg_tuple = std::make_tuple(arg0, args...);
auto lambda = [ftor, arg_tuple]() { invoke(ftor, arg_tuple); };
return new fun_behavior<false, decltype(lambda)>(std::move(lambda));
}
} // namespace detail
template<scheduling_hint Hint, typename F, typename... Args>
actor_ptr spawn(F&& what, const Args&... args)
{
typedef typename util::rm_ref<F>::type ftype;
std::integral_constant<bool, std::is_function<ftype>::value> is_fun;
auto ptr = detail::get_behavior(is_fun, std::forward<F>(what), args...);
return get_scheduler()->spawn(ptr, Hint);
}
template<typename F, typename... Args>
actor_ptr spawn(F&& what, const Args&... args)
{
return spawn<scheduled>(std::forward<F>(what), args...);
}
/*
template<typename F> template<typename F>
actor_ptr spawn(scheduling_hint hint, F fun) actor_ptr spawn(scheduling_hint hint, const F& fun)
{ {
struct fun_behavior : actor_behavior struct fun_behavior : actor_behavior
{ {
...@@ -54,31 +152,22 @@ actor_ptr spawn(scheduling_hint hint, F fun) ...@@ -54,31 +152,22 @@ actor_ptr spawn(scheduling_hint hint, F fun)
m_fun(); m_fun();
} }
}; };
return get_scheduler()->spawn(new fun_behavior(fun), hint); return spawn(hint, new fun_behavior(fun));
} }
template<typename F, typename Arg0, typename... Args> template<typename F, typename Arg0, typename... Args>
actor_ptr spawn(scheduling_hint hint, F fun, const Arg0& arg0, const Args&... args) actor_ptr spawn(scheduling_hint hint, const F& fun, const Arg0& arg0, const Args&... args)
{ {
auto arg_tuple = make_tuple(arg0, args...); auto arg_tuple = make_tuple(arg0, args...);
return spawn(hint, [=]() { invoke(fun, arg_tuple); }); return spawn(hint, [=]() { invoke(fun, arg_tuple); });
} }
template<typename F, typename... Args> template<typename F, typename... Args>
inline actor_ptr spawn(F fun, const Args&... args) inline actor_ptr spawn(const F& fun, const Args&... args)
{ {
return spawn(scheduled, fun, args...); return spawn(scheduled, fun, args...);
} }
*/
inline actor_ptr spawn(scheduling_hint hint, actor_behavior* ab)
{
return get_scheduler()->spawn(ab, hint);
}
inline actor_ptr spawn(actor_behavior* ab)
{
return get_scheduler()->spawn(ab, scheduled);
}
inline const message& receive() inline const message& receive()
{ {
...@@ -124,6 +213,12 @@ void reply(const Arg0& arg0, const Args&... args) ...@@ -124,6 +213,12 @@ void reply(const Arg0& arg0, const Args&... args)
if (whom) whom->enqueue(message(sptr, whom, arg0, args...)); if (whom) whom->enqueue(message(sptr, whom, arg0, args...));
} }
/**
* @brief Blocks execution of this actor until all
* other actors finished execution.
* @warning This function will cause a deadlock if
* called from multiple actors.
*/
inline void await_all_others_done() inline void await_all_others_done()
{ {
get_scheduler()->await_others_done(); get_scheduler()->await_others_done();
......
#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 {
using boost::mutex;
using boost::recursive_mutex;
using boost::timed_mutex;
using boost::recursive_timed_mutex;
using boost::adopt_lock;
using boost::defer_lock;
using boost::try_to_lock;
using boost::lock_guard;
using boost::unique_lock;
} // namespace std
#endif // CPPA_DETAIL_CPP0X_THREAD_WRAPPER_HPP
...@@ -14,14 +14,6 @@ template<> ...@@ -14,14 +14,6 @@ template<>
struct tdata<> struct tdata<>
{ {
typedef util::type_list<> element_types;
typedef typename element_types::head_type head_type;
typedef typename element_types::tail_type tail_type;
static const size_t type_list_size = element_types::type_list_size;
util::void_type head; util::void_type head;
tdata<>& tail() tdata<>& tail()
...@@ -47,14 +39,6 @@ struct tdata<Head, Tail...> : tdata<Tail...> ...@@ -47,14 +39,6 @@ struct tdata<Head, Tail...> : tdata<Tail...>
typedef tdata<Tail...> super; typedef tdata<Tail...> super;
typedef util::type_list<Head, Tail...> element_types;
typedef typename element_types::head_type head_type;
typedef typename element_types::tail_type tail_type;
static const size_t type_list_size = element_types::type_list_size;
Head head; Head head;
inline tdata() : super(), head() { } inline tdata() : super(), head() { }
...@@ -99,8 +83,7 @@ template<size_t N, typename... ElementTypes> ...@@ -99,8 +83,7 @@ template<size_t N, typename... ElementTypes>
const typename util::type_at<N, util::type_list<ElementTypes...>>::type& const typename util::type_at<N, util::type_list<ElementTypes...>>::type&
tdata_get(const tdata<ElementTypes...>& tv) tdata_get(const tdata<ElementTypes...>& tv)
{ {
static_assert(N < util::type_list<ElementTypes...>::type_list_size, static_assert(N < sizeof...(ElementTypes), "N >= tv.size()");
"N < tv.size()");
return static_cast<const typename tdata_upcast_helper<N, ElementTypes...>::type&>(tv).head; return static_cast<const typename tdata_upcast_helper<N, ElementTypes...>::type&>(tv).head;
} }
...@@ -108,8 +91,7 @@ template<size_t N, typename... ElementTypes> ...@@ -108,8 +91,7 @@ template<size_t N, typename... ElementTypes>
typename util::type_at<N, util::type_list<ElementTypes...>>::type& typename util::type_at<N, util::type_list<ElementTypes...>>::type&
tdata_get_ref(tdata<ElementTypes...>& tv) tdata_get_ref(tdata<ElementTypes...>& tv)
{ {
static_assert(N < util::type_list<ElementTypes...>::type_list_size, static_assert(N < sizeof...(ElementTypes), "N >= tv.size()");
"N >= tv.size()");
return static_cast<typename tdata_upcast_helper<N, ElementTypes...>::type &>(tv).head; return static_cast<typename tdata_upcast_helper<N, ElementTypes...>::type &>(tv).head;
} }
......
...@@ -39,12 +39,6 @@ class tuple_vals : public abstract_tuple ...@@ -39,12 +39,6 @@ class tuple_vals : public abstract_tuple
public: public:
typedef typename element_types::head_type head_type;
typedef typename element_types::tail_type tail_type;
static const size_t type_list_size = element_types::type_list_size;
tuple_vals(const tuple_vals& other) : super(), m_data(other.m_data) { } tuple_vals(const tuple_vals& other) : super(), m_data(other.m_data) { }
tuple_vals() : m_data() { } tuple_vals() : m_data() { }
...@@ -62,7 +56,7 @@ class tuple_vals : public abstract_tuple ...@@ -62,7 +56,7 @@ class tuple_vals : public abstract_tuple
virtual size_t size() const virtual size_t size() const
{ {
return element_types::type_list_size; return sizeof...(ElementTypes);
} }
virtual tuple_vals* copy() const virtual tuple_vals* copy() const
......
...@@ -61,7 +61,7 @@ class exit_signal ...@@ -61,7 +61,7 @@ class exit_signal
* <tt>reason() == @p r</tt>. * <tt>reason() == @p r</tt>.
* @pre {@code r >= exit_reason::user_defined}. * @pre {@code r >= exit_reason::user_defined}.
*/ */
exit_signal(std::uint32_t r); explicit exit_signal(std::uint32_t r);
/** /**
* @brief Reads the exit reason. * @brief Reads the exit reason.
...@@ -86,6 +86,16 @@ class exit_signal ...@@ -86,6 +86,16 @@ class exit_signal
}; };
inline bool operator==(const exit_signal& lhs, const exit_signal& rhs)
{
return lhs.reason() == rhs.reason();
}
inline bool operator!=(const exit_signal& lhs, const exit_signal& rhs)
{
return !(lhs == rhs);
}
} // namespace cppa } // namespace cppa
#endif // EXIT_SIGNAL_HPP #endif // EXIT_SIGNAL_HPP
#ifndef FROM_STRING_HPP
#define FROM_STRING_HPP
#include <string>
#include <typeinfo>
#include <exception>
#include "cppa/object.hpp"
#include "cppa/uniform_type_info.hpp"
namespace cppa {
object from_string(const std::string& what);
template<typename T>
T from_string(const std::string &what)
{
object o = from_string(what);
const std::type_info& tinfo = typeid(T);
if (o.type() == tinfo)
{
return std::move(get<T>(o));
}
else
{
std::string error_msg = "expected type name ";
error_msg += uniform_typeid(tinfo)->name();
error_msg += " found ";
error_msg += o.type().name();
throw std::logic_error(error_msg);
}
}
} // namespace cppa
#endif // FROM_STRING_HPP
...@@ -27,7 +27,8 @@ struct invoke_helper ...@@ -27,7 +27,8 @@ struct invoke_helper
static_assert(std::is_convertible<tuple_val_type, back_type>::value, static_assert(std::is_convertible<tuple_val_type, back_type>::value,
"tuple element is not convertible to expected argument"); "tuple element is not convertible to expected argument");
invoke_helper<N - 1, F, Tuple, next_list, tuple_val_type, Args...> invoke_helper<N - 1, F, Tuple, next_list, tuple_val_type, Args...>
::_(f, t, t.get<N>(), args...); //::_(f, t, t.get<N>(), args...);
::_(f, t, get<N>(t), args...);
} }
}; };
...@@ -40,33 +41,40 @@ struct invoke_helper<N, F, Tuple, util::type_list<>, Args...> ...@@ -40,33 +41,40 @@ struct invoke_helper<N, F, Tuple, util::type_list<>, Args...>
} }
}; };
template<bool HasCallableTrait, typename Tuple, typename F> template<bool HasCallableTrati, typename F, class Tuple>
struct invoke_impl struct invoke_impl;
template<typename F, template<typename...> class Tuple, typename... TTypes>
struct invoke_impl<true, F, Tuple<TTypes...> >
{ {
static_assert(sizeof...(TTypes) > 0, "empty tuple type");
typedef typename util::callable_trait<F>::arg_types arg_types; typedef typename util::callable_trait<F>::arg_types arg_types;
static const size_t tuple_size = Tuple::type_list_size - 1; typedef Tuple<TTypes...> tuple_type;
inline static void _(F& f, const Tuple& t) inline static void _(F& f, const tuple_type& t)
{ {
invoke_helper<tuple_size, F, Tuple, arg_types>::_(f, t); invoke_helper<sizeof...(TTypes) - 1, F, tuple_type, arg_types>::_(f, t);
} }
}; };
template<typename Tuple, typename F> template<typename F, template<typename...> class Tuple, typename... TTypes>
struct invoke_impl<false, Tuple, F> struct invoke_impl<false, F, Tuple<TTypes...> >
{ {
static_assert(sizeof...(TTypes) > 0, "empty tuple type");
typedef typename util::callable_trait<decltype(&F::operator())>::arg_types typedef typename util::callable_trait<decltype(&F::operator())>::arg_types
arg_types; arg_types;
static const size_t tuple_size = Tuple::type_list_size - 1; typedef Tuple<TTypes...> tuple_type;
inline static void _(F& f, const Tuple& t) inline static void _(F& f, const tuple_type& t)
{ {
invoke_helper<tuple_size, F, Tuple, arg_types>::_(f, t); invoke_helper<sizeof...(TTypes) - 1, F, tuple_type, arg_types>::_(f, t);
} }
}; };
...@@ -79,7 +87,7 @@ template<typename Tuple, typename F> ...@@ -79,7 +87,7 @@ template<typename Tuple, typename F>
void invoke(F what, const Tuple& args) void invoke(F what, const Tuple& args)
{ {
typedef typename std::remove_pointer<F>::type f_type; typedef typename std::remove_pointer<F>::type f_type;
detail::invoke_impl<std::is_function<f_type>::value, Tuple, F>::_(what, args); detail::invoke_impl<std::is_function<f_type>::value, F, Tuple>::_(what, args);
} }
} // namespace cppa } // namespace cppa
......
...@@ -51,7 +51,7 @@ bool match(const any_tuple& what, const ValuesTuple& vals, ...@@ -51,7 +51,7 @@ bool match(const any_tuple& what, const ValuesTuple& vals,
{ {
std::vector<size_t> tmp(mappings); std::vector<size_t> tmp(mappings);
view_type view(what.vals(), std::move(tmp)); view_type view(what.vals(), std::move(tmp));
return compare_first_elements(view, vals); return util::compare_first_elements(view, vals);
} }
return false; return false;
} }
......
...@@ -40,8 +40,9 @@ struct invoke_rule_builder ...@@ -40,8 +40,9 @@ struct invoke_rule_builder
{ {
typedef util::type_list<Arg0, Args...> arg_types; typedef util::type_list<Arg0, Args...> arg_types;
static_assert(arg_types::type_list_size static constexpr size_t num_args = sizeof...(Args) + 1;
<= filtered_types::type_list_size,
static_assert(num_args <= filtered_types::type_list_size,
"too much arguments"); "too much arguments");
class helper_impl : public irb_helper class helper_impl : public irb_helper
...@@ -66,7 +67,7 @@ struct invoke_rule_builder ...@@ -66,7 +67,7 @@ struct invoke_rule_builder
m_helper = new helper_impl(arg0, args...); m_helper = new helper_impl(arg0, args...);
static_assert(util::eval_first_n<arg_types::type_list_size, static_assert(util::eval_first_n<num_args,
filtered_types, filtered_types,
arg_types, arg_types,
util::is_comparable>::value, util::is_comparable>::value,
......
#ifndef TO_STRING_HPP
#define TO_STRING_HPP
#include "cppa/uniform_type_info.hpp"
namespace cppa {
namespace detail {
std::string to_string(const void* what, const uniform_type_info* utype);
} // namespace detail
template<typename T>
std::string to_string(const T& what)
{
auto utype = uniform_typeid<T>();
if (utype == nullptr)
{
throw std::logic_error( detail::to_uniform_name(typeid(T))
+ " is not announced");
}
return detail::to_string(&what, utype);
}
} // namespace cppa
#endif // TO_STRING_HPP
...@@ -80,7 +80,7 @@ class tuple ...@@ -80,7 +80,7 @@ class tuple
private: private:
static_assert(element_types::type_list_size > 0, "tuple is empty"); static_assert(sizeof...(ElementTypes) > 0, "tuple is empty");
static_assert(util::eval_type_list<element_types, static_assert(util::eval_type_list<element_types,
util::is_legal_tuple_type>::value, util::is_legal_tuple_type>::value,
...@@ -113,8 +113,6 @@ class tuple ...@@ -113,8 +113,6 @@ class tuple
typedef typename element_types::tail_type tail_type; typedef typename element_types::tail_type tail_type;
static const size_t type_list_size = element_types::type_list_size;
tuple() : m_vals(new vals_t) { } tuple() : m_vals(new vals_t) { }
tuple(const ElementTypes&... args) : m_vals(new vals_t(args...)) { } tuple(const ElementTypes&... args) : m_vals(new vals_t(args...)) { }
...@@ -144,7 +142,7 @@ class tuple ...@@ -144,7 +142,7 @@ class tuple
template<typename... Args> template<typename... Args>
bool equal_to(const tuple<Args...>& other) const bool equal_to(const tuple<Args...>& other) const
{ {
static_assert(type_list_size == tuple<Args...>::type_list_size, static_assert(sizeof...(ElementTypes) == sizeof...(Args),
"Can't compare tuples of different size"); "Can't compare tuples of different size");
return compare_vals(vals()->data(), other.vals()->data()); return compare_vals(vals()->data(), other.vals()->data());
} }
......
...@@ -29,7 +29,7 @@ class tuple_view ...@@ -29,7 +29,7 @@ class tuple_view
typedef util::type_list<ElementTypes...> element_types; typedef util::type_list<ElementTypes...> element_types;
static_assert(element_types::type_list_size > 0, static_assert(sizeof...(ElementTypes) > 0,
"could not declare an empty tuple_view"); "could not declare an empty tuple_view");
typedef cow_ptr<detail::abstract_tuple> vals_t; typedef cow_ptr<detail::abstract_tuple> vals_t;
...@@ -51,21 +51,19 @@ class tuple_view ...@@ -51,21 +51,19 @@ class tuple_view
typedef typename element_types::tail_type tail_type; typedef typename element_types::tail_type tail_type;
static const size_t type_list_size = element_types::type_list_size;
const element_types& types() const { return m_types; } const element_types& types() const { return m_types; }
template<size_t N> template<size_t N>
const typename util::type_at<N, element_types>::type& get() const const typename util::type_at<N, element_types>::type& get() const
{ {
static_assert(N < element_types::type_list_size, "N >= size()"); static_assert(N < sizeof...(ElementTypes), "N >= size()");
return *reinterpret_cast<const typename util::type_at<N, element_types>::type*>(m_vals->at(N)); return *reinterpret_cast<const typename util::type_at<N, element_types>::type*>(m_vals->at(N));
} }
template<size_t N> template<size_t N>
typename util::type_at<N, element_types>::type& get_ref() typename util::type_at<N, element_types>::type& get_ref()
{ {
static_assert(N < element_types::type_list_size, "N >= size()"); static_assert(N < sizeof...(ElementTypes), "N >= size()");
return *reinterpret_cast<typename util::type_at<N, element_types>::type*>(m_vals->mutable_at(N)); return *reinterpret_cast<typename util::type_at<N, element_types>::type*>(m_vals->mutable_at(N));
} }
...@@ -82,14 +80,20 @@ template<size_t N, typename... Types> ...@@ -82,14 +80,20 @@ template<size_t N, typename... Types>
const typename util::type_at<N, util::type_list<Types...>>::type& const typename util::type_at<N, util::type_list<Types...>>::type&
get(const tuple_view<Types...>& t) get(const tuple_view<Types...>& t)
{ {
return t.get<N>(); static_assert(N < sizeof...(Types), "N >= t.size()");
typedef typename util::type_at<N, util::type_list<Types...>>::type result_t;
return *reinterpret_cast<const result_t*>(t.vals()->at(N));
//return t.get<N>();
} }
template<size_t N, typename... Types> template<size_t N, typename... Types>
typename util::type_at<N, util::type_list<Types...>>::type& typename util::type_at<N, util::type_list<Types...>>::type&
get_ref(tuple_view<Types...>& t) get_ref(tuple_view<Types...>& t)
{ {
return t.get_ref<N>(); static_assert(N < sizeof...(Types), "N >= t.size()");
typedef typename util::type_at<N, util::type_list<Types...>>::type result_t;
return *reinterpret_cast<result_t*>(t.vals()->mutable_at(N));
//return t.get_ref<N>();
} }
template<typename TypeList> template<typename TypeList>
......
...@@ -62,14 +62,13 @@ template<template<typename...> class LhsTuple, typename... LhsTypes, ...@@ -62,14 +62,13 @@ template<template<typename...> class LhsTuple, typename... LhsTypes,
bool compare_tuples(const LhsTuple<LhsTypes...>& lhs, bool compare_tuples(const LhsTuple<LhsTypes...>& lhs,
const RhsTuple<RhsTypes...>& rhs) const RhsTuple<RhsTypes...>& rhs)
{ {
static_assert( LhsTuple<LhsTypes...>::type_list_size static_assert(sizeof...(LhsTypes) == sizeof...(RhsTypes),
== RhsTuple<RhsTypes...>::type_list_size,
"could not compare tuples of different size"); "could not compare tuples of different size");
static_assert(util::eval_type_lists<util::type_list<LhsTypes...>, static_assert(util::eval_type_lists<util::type_list<LhsTypes...>,
util::type_list<RhsTypes...>, util::type_list<RhsTypes...>,
util::is_comparable>::value, util::is_comparable>::value,
"types of lhs are not comparable to the types of rhs"); "types of lhs are not comparable to the types of rhs");
return detail::cmp_helper<(LhsTuple<LhsTypes...>::type_list_size - 1), return detail::cmp_helper<(sizeof...(LhsTypes) - 1),
LhsTuple<LhsTypes...>, LhsTuple<LhsTypes...>,
RhsTuple<RhsTypes...>>::cmp(lhs, rhs); RhsTuple<RhsTypes...>>::cmp(lhs, rhs);
} }
...@@ -82,8 +81,8 @@ bool compare_first_elements(const LhsTuple<LhsTypes...>& lhs, ...@@ -82,8 +81,8 @@ bool compare_first_elements(const LhsTuple<LhsTypes...>& lhs,
typedef util::type_list<LhsTypes...> lhs_types; typedef util::type_list<LhsTypes...> lhs_types;
typedef util::type_list<RhsTypes...> rhs_types; typedef util::type_list<RhsTypes...> rhs_types;
static_assert(util::eval_first_n<detail::min_<lhs_types::type_list_size, static_assert(util::eval_first_n<detail::min_<sizeof...(LhsTypes),
rhs_types::type_list_size> sizeof...(RhsTypes)>
::value, ::value,
lhs_types, lhs_types,
rhs_types, rhs_types,
......
...@@ -16,6 +16,9 @@ struct rm_ref<const T&> { typedef T type; }; ...@@ -16,6 +16,9 @@ struct rm_ref<const T&> { typedef T type; };
template<typename T> template<typename T>
struct rm_ref<T&> { typedef T type; }; struct rm_ref<T&> { typedef T type; };
template<typename T>
struct rm_ref<T&&> { typedef T type; };
template<> template<>
struct rm_ref<void> { }; struct rm_ref<void> { };
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
namespace cppa { namespace util { namespace cppa { namespace util {
/*
template<size_t N, typename TypeList> template<size_t N, typename TypeList>
struct type_at struct type_at
{ {
...@@ -19,6 +20,31 @@ struct type_at<0, TypeList> ...@@ -19,6 +20,31 @@ struct type_at<0, TypeList>
{ {
typedef typename TypeList::head_type type; typedef typename TypeList::head_type type;
}; };
*/
template<size_t N, class TypeList>
struct type_at;
template<size_t N, template<typename...> class TypeList, typename T0, typename... Tn>
struct type_at< N, TypeList<T0,Tn...> >
{
// use type_list to avoid instantiations of TypeList parameter
typedef typename type_at< N-1, type_list<Tn...> >::type type;
};
template<template<typename...> class TypeList, typename T0, typename... Tn>
struct type_at< 0, TypeList<T0,Tn...> >
{
typedef T0 type;
};
template<size_t N, template<typename...> class TypeList>
struct type_at< N, TypeList<> >
{
typedef void_type type;
};
} } // namespace cppa::util } } // namespace cppa::util
......
...@@ -70,7 +70,7 @@ struct type_list<Head, Tail...> : abstract_type_list ...@@ -70,7 +70,7 @@ struct type_list<Head, Tail...> : abstract_type_list
typedef type_list<Tail...> tail_type; typedef type_list<Tail...> tail_type;
static const size_t type_list_size = tail_type::type_list_size + 1; static const size_t type_list_size = sizeof...(Tail) + 1;
type_list() type_list()
{ {
......
#include <stack>
#include <sstream>
#include <algorithm>
#include "cppa/object.hpp"
#include "cppa/to_string.hpp"
#include "cppa/serializer.hpp"
#include "cppa/from_string.hpp"
#include "cppa/deserializer.hpp"
#include "cppa/primitive_variant.hpp"
#include "cppa/uniform_type_info.hpp"
namespace cppa {
namespace {
class string_serializer : public serializer
{
std::ostream& out;
struct pt_writer
{
std::ostream& out;
pt_writer(std::ostream& mout) : out(mout) { }
template<typename T>
void operator()(const T& value)
{
out << value;
}
void operator()(const std::string& str)
{
out << "\"";// << str << "\"";
for (char c : str)
{
if (c == '"') out << "\\\"";
else out << c;
}
out << '"';
}
void operator()(const std::u16string&) { }
void operator()(const std::u32string&) { }
};
int m_open_objects;
bool m_after_value;
bool m_obj_just_opened;
inline void clear()
{
if (m_after_value)
{
out << ", ";
m_after_value = false;
}
else if (m_obj_just_opened)
{
out << " ( ";
m_obj_just_opened = false;
}
}
public:
string_serializer(std::ostream& mout)
: out(mout), m_open_objects(0)
, m_after_value(false), m_obj_just_opened(false)
{
}
void begin_object(const std::string& type_name)
{
clear();
++m_open_objects;
out << type_name;// << " ( ";
m_obj_just_opened = true;
}
void end_object()
{
if (m_obj_just_opened)
{
m_obj_just_opened = false;
}
else
{
out << (m_after_value ? " )" : ")");
}
m_after_value = true;
}
void begin_sequence(size_t)
{
clear();
out << "{ ";
}
void end_sequence()
{
out << (m_after_value ? " }" : "}");
}
void write_value(const primitive_variant& value)
{
clear();
value.apply(pt_writer(out));
m_after_value = true;
}
void write_tuple(size_t size, const primitive_variant* values)
{
clear();
out << " {";
const primitive_variant* end = values + size;
for ( ; values != end; ++values)
{
write_value(*values);
}
out << (m_after_value ? " }" : "}");
}
};
class string_deserializer : public deserializer
{
std::string m_str;
std::string::iterator m_pos;
size_t m_obj_count;
std::stack<bool> m_obj_had_left_parenthesis;
void skip_space_and_comma()
{
while (*m_pos == ' ' || *m_pos == ',') ++m_pos;
}
void throw_malformed(const std::string& error_msg)
{
throw std::logic_error("malformed string: " + error_msg);
}
void consume(char c)
{
skip_space_and_comma();
if (*m_pos != c)
{
std::string error;
error += "expected '";
error += c;
error += "' found '";
error += *m_pos;
error += "'";
throw_malformed(error);
}
++m_pos;
}
bool try_consume(char c)
{
skip_space_and_comma();
if (*m_pos == c)
{
++m_pos;
return true;
}
return false;
}
inline std::string::iterator next_delimiter()
{
return std::find_if(m_pos, m_str.end(), [] (char c) -> bool {
switch (c)
{
case '(':
case ')':
case '{':
case '}':
case ' ':
case ',': return true;
default : return false;
}
});
}
void integrity_check()
{
if (m_obj_had_left_parenthesis.empty())
{
throw_malformed("missing begin_object()");
}
else if (m_obj_had_left_parenthesis.top() == false)
{
throw_malformed("expected left parenthesis after "
"begin_object call or void value");
}
}
public:
string_deserializer(const std::string& str) : m_str(str)
{
m_pos = m_str.begin();
m_obj_count = 0;
}
string_deserializer(std::string&& str) : m_str(std::move(str))
{
m_pos = m_str.begin();
m_obj_count = 0;
}
std::string seek_object()
{
skip_space_and_comma();
auto substr_end = next_delimiter();
if (m_pos == substr_end)
{
throw_malformed("could not seek object type name");
}
std::string result(m_pos, substr_end);
m_pos = substr_end;
return result;
}
std::string peek_object()
{
std::string result = seek_object();
// restore position in stream
m_pos -= result.size();
return result;
}
void begin_object(const std::string&)
{
++m_obj_count;
skip_space_and_comma();
m_obj_had_left_parenthesis.push(try_consume('('));
//consume('(');
}
void end_object()
{
if (m_obj_had_left_parenthesis.empty())
{
throw_malformed("missing begin_object()");
}
else
{
if (m_obj_had_left_parenthesis.top() == true)
{
consume(')');
}
m_obj_had_left_parenthesis.pop();
}
if (--m_obj_count == 0)
{
skip_space_and_comma();
if (m_pos != m_str.end())
{
throw_malformed("expected end of of string");
}
}
}
size_t begin_sequence()
{
integrity_check();
consume('{');
auto list_end = std::find(m_pos, m_str.end(), '}');
return std::count(m_pos, list_end, ',') + 1;
}
void end_sequence()
{
consume('}');
}
struct from_string
{
const std::string& str;
from_string(const std::string& s) : str(s) { }
template<typename T>
void operator()(T& what)
{
std::istringstream s(str);
s >> what;
}
void operator()(std::string& what)
{
what = str;
}
void operator()(std::u16string&) { }
void operator()(std::u32string&) { }
};
primitive_variant read_value(primitive_type ptype)
{
integrity_check();
skip_space_and_comma();
std::string::iterator substr_end;
auto find_if_cond = [] (char c) -> bool
{
switch (c)
{
case ')':
case '}':
case ' ':
case ',': return true;
default : return false;
}
};
if (ptype == pt_u8string)
{
if (*m_pos == '"')
{
// skip leading "
++m_pos;
char last_char = '"';
auto find_if_str_cond = [&last_char] (char c) -> bool
{
if (c == '"' && last_char != '\\')
{
return true;
}
last_char = c;
return false;
};
substr_end = std::find_if(m_pos, m_str.end(), find_if_str_cond);
}
else
{
substr_end = std::find_if(m_pos, m_str.end(), find_if_cond);
}
}
else
{
substr_end = std::find_if(m_pos, m_str.end(), find_if_cond);
}
if (substr_end == m_str.end())
{
throw std::logic_error("malformed string (unterminated value)");
}
std::string substr(m_pos, substr_end);
m_pos += substr.size();
if (ptype == pt_u8string)
{
// skip trailing "
if (*m_pos != '"')
{
std::string error_msg;
error_msg = "malformed string, expected '\"' found '";
error_msg += *m_pos;
error_msg += "'";
throw std::logic_error(error_msg);
}
++m_pos;
// replace '\"' by '"'
char last_char = ' ';
auto cond = [&last_char] (char c) -> bool
{
if (c == '"' && last_char == '\\')
{
return true;
}
last_char = c;
return false;
};
std::string tmp;
auto sbegin = substr.begin();
auto send = substr.end();
for (auto i = std::find_if(sbegin, send, cond);
i != send;
i = std::find_if(i, send, cond))
{
--i;
tmp.append(sbegin, i);
tmp += '"';
i += 2;
sbegin = i;
}
if (sbegin != substr.begin())
{
tmp.append(sbegin, send);
}
if (!tmp.empty())
{
substr = std::move(tmp);
}
}
primitive_variant result(ptype);
result.apply(from_string(substr));
return result;
}
void read_tuple(size_t size,
const primitive_type* begin,
primitive_variant* storage)
{
integrity_check();
consume('{');
const primitive_type* end = begin + size;
for ( ; begin != end; ++begin)
{
*storage = std::move(read_value(*begin));
++storage;
}
consume('}');
}
};
} // namespace <anonymous>
object from_string(const std::string& what)
{
string_deserializer strd(what);
std::string uname = strd.peek_object();
auto utype = uniform_type_info::by_uniform_name(uname);
if (utype == nullptr)
{
throw std::logic_error(uname + " is not announced");
}
return utype->deserialize(&strd);
}
namespace detail {
std::string to_string(const void *what, const uniform_type_info *utype)
{
std::ostringstream osstr;
string_serializer strs(osstr);
utype->serialize(what, &strs);
return osstr.str();
}
} // namespace detail
} // namespace cppa
...@@ -6,7 +6,16 @@ ...@@ -6,7 +6,16 @@
#include <stdexcept> #include <stdexcept>
#include <algorithm> #include <algorithm>
#include "cppa/actor.hpp"
#include "cppa/group.hpp"
#include "cppa/channel.hpp"
#include "cppa/message.hpp"
#include "cppa/any_type.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/exit_signal.hpp"
#include "cppa/util/void_type.hpp" #include "cppa/util/void_type.hpp"
#include "cppa/detail/demangle.hpp" #include "cppa/detail/demangle.hpp"
#include "cppa/detail/to_uniform_name.hpp" #include "cppa/detail/to_uniform_name.hpp"
...@@ -51,6 +60,7 @@ std::string to_uniform_name_impl(Iterator begin, Iterator end, ...@@ -51,6 +60,7 @@ std::string to_uniform_name_impl(Iterator begin, Iterator end,
// all integer type names as uniform representation // all integer type names as uniform representation
static std::map<std::string, std::string> mapped_demangled_names = static std::map<std::string, std::string> mapped_demangled_names =
{ {
// integer types
{ demangled<char>(), mapped_int_name<char>() }, { demangled<char>(), mapped_int_name<char>() },
{ demangled<signed char>(), mapped_int_name<signed char>() }, { demangled<signed char>(), mapped_int_name<signed char>() },
{ demangled<unsigned char>(), mapped_int_name<unsigned char>() }, { demangled<unsigned char>(), mapped_int_name<unsigned char>() },
...@@ -72,14 +82,21 @@ std::string to_uniform_name_impl(Iterator begin, Iterator end, ...@@ -72,14 +82,21 @@ std::string to_uniform_name_impl(Iterator begin, Iterator end,
{ demangled<long long>(), mapped_int_name<long long>() }, { demangled<long long>(), mapped_int_name<long long>() },
{ demangled<signed long long>(), mapped_int_name<signed long long>() }, { demangled<signed long long>(), mapped_int_name<signed long long>() },
{ demangled<unsigned long long>(), mapped_int_name<unsigned 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<char16_t>(), mapped_int_name<char16_t>() },
{ demangled<char32_t>(), mapped_int_name<char32_t>() }, { demangled<char32_t>(), mapped_int_name<char32_t>() },
{ demangled<cppa::util::void_type>(), "@0" }, // string types
// { demangled<std::wstring>(), "@wstr" },
{ demangled<std::string>(), "@str" }, { demangled<std::string>(), "@str" },
{ demangled<std::u16string>(), "@u16str" }, { demangled<std::u16string>(), "@u16str" },
{ demangled<std::u32string>(), "@u32str" } { demangled<std::u32string>(), "@u32str" },
// cppa types
{ demangled<cppa::any_type>(), "@*" },
{ demangled<cppa::util::void_type>(), "@0" },
{ demangled<cppa::any_tuple>(), "@<>" },
{ demangled<cppa::exit_signal>(), "@exit" },
{ demangled<cppa::actor_ptr>(), "@actor" },
{ demangled<cppa::group_ptr>(), "@group" },
{ demangled<cppa::channel_ptr>(), "@channel" },
{ demangled<cppa::message>(), "@msg" }
}; };
// check if we could find the whole string in our lookup map // check if we could find the whole string in our lookup map
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "cppa/actor.hpp" #include "cppa/actor.hpp"
#include "cppa/object.hpp" #include "cppa/object.hpp"
#include "cppa/message.hpp"
#include "cppa/announce.hpp" #include "cppa/announce.hpp"
#include "cppa/any_type.hpp" #include "cppa/any_type.hpp"
#include "cppa/any_tuple.hpp" #include "cppa/any_tuple.hpp"
...@@ -178,8 +179,9 @@ class group_ptr_tinfo : public util::abstract_uniform_type_info<group_ptr> ...@@ -178,8 +179,9 @@ class group_ptr_tinfo : public util::abstract_uniform_type_info<group_ptr>
public: public:
static void s_serialize(const group* ptr, serializer* sink, static void s_serialize(const group* ptr,
const std::string name) serializer* sink,
const std::string& name)
{ {
if (!ptr) if (!ptr)
{ {
...@@ -194,8 +196,9 @@ class group_ptr_tinfo : public util::abstract_uniform_type_info<group_ptr> ...@@ -194,8 +196,9 @@ class group_ptr_tinfo : public util::abstract_uniform_type_info<group_ptr>
} }
} }
static void s_deserialize(group_ptr& ptrref, deserializer* source, static void s_deserialize(group_ptr& ptrref,
const std::string name) deserializer* source,
const std::string& name)
{ {
std::string cname = source->seek_object(); std::string cname = source->seek_object();
if (cname != name) if (cname != name)
...@@ -243,12 +246,15 @@ class channel_ptr_tinfo : public util::abstract_uniform_type_info<channel_ptr> ...@@ -243,12 +246,15 @@ class channel_ptr_tinfo : public util::abstract_uniform_type_info<channel_ptr>
std::string group_ptr_name; std::string group_ptr_name;
std::string actor_ptr_name; std::string actor_ptr_name;
protected: public:
void serialize(const void* instance, serializer* sink) const static void s_serialize(const channel* ptr,
serializer* sink,
const std::string& channel_type_name,
const std::string& actor_ptr_type_name,
const std::string& group_ptr_type_name)
{ {
sink->begin_object(name()); sink->begin_object(channel_type_name);
auto ptr = reinterpret_cast<const channel_ptr*>(instance)->get();
if (!ptr) if (!ptr)
{ {
serialize_nullptr(sink); serialize_nullptr(sink);
...@@ -259,11 +265,11 @@ class channel_ptr_tinfo : public util::abstract_uniform_type_info<channel_ptr> ...@@ -259,11 +265,11 @@ class channel_ptr_tinfo : public util::abstract_uniform_type_info<channel_ptr>
auto aptr = dynamic_cast<const actor*>(ptr); auto aptr = dynamic_cast<const actor*>(ptr);
if (aptr) if (aptr)
{ {
actor_ptr_tinfo::s_serialize(aptr, sink, actor_ptr_name); actor_ptr_tinfo::s_serialize(aptr, sink, actor_ptr_type_name);
} }
else if ((gptr = dynamic_cast<const group*>(ptr)) != nullptr) else if ((gptr = dynamic_cast<const group*>(ptr)) != nullptr)
{ {
group_ptr_tinfo::s_serialize(gptr, sink, group_ptr_name); group_ptr_tinfo::s_serialize(gptr, sink, group_ptr_type_name);
} }
else else
{ {
...@@ -274,41 +280,64 @@ class channel_ptr_tinfo : public util::abstract_uniform_type_info<channel_ptr> ...@@ -274,41 +280,64 @@ class channel_ptr_tinfo : public util::abstract_uniform_type_info<channel_ptr>
sink->end_object(); sink->end_object();
} }
void deserialize(void* instance, deserializer* source) const static void s_deserialize(channel_ptr& ptrref,
deserializer* source,
const std::string& name,
const std::string& actor_ptr_type_name,
const std::string& group_ptr_type_name)
{ {
std::string cname = source->seek_object(); std::string cname = source->seek_object();
if (cname != name()) if (cname != name)
{ {
throw std::logic_error("wrong type name found"); throw std::logic_error("wrong type name found");
} }
source->begin_object(cname); source->begin_object(cname);
std::string subobj = source->peek_object(); std::string subobj = source->peek_object();
if (subobj == actor_ptr_name) if (subobj == actor_ptr_type_name)
{ {
actor_ptr tmp; actor_ptr tmp;
actor_ptr_tinfo::s_deserialize(tmp, source, actor_ptr_name); actor_ptr_tinfo::s_deserialize(tmp, source, actor_ptr_type_name);
*reinterpret_cast<channel_ptr*>(instance) = tmp; ptrref = tmp;
} }
else if (subobj == group_ptr_name) else if (subobj == group_ptr_type_name)
{ {
group_ptr tmp; group_ptr tmp;
group_ptr_tinfo::s_deserialize(tmp, source, group_ptr_name); group_ptr_tinfo::s_deserialize(tmp, source, group_ptr_type_name);
*reinterpret_cast<channel_ptr*>(instance) = tmp; ptrref = tmp;
} }
else if (subobj == nullptr_type_name) else if (subobj == nullptr_type_name)
{ {
(void) source->seek_object(); (void) source->seek_object();
deserialize_nullptr(source); deserialize_nullptr(source);
reinterpret_cast<channel_ptr*>(instance)->reset(); ptrref.reset();
} }
else else
{ {
throw std::logic_error("unexpected type name: " + subobj); throw std::logic_error("unexpected type name: " + subobj);
} }
source->end_object(); source->end_object();
} }
protected:
void serialize(const void* instance, serializer* sink) const
{
s_serialize(reinterpret_cast<const channel_ptr*>(instance)->get(),
sink,
name(),
actor_ptr_name,
group_ptr_name);
}
void deserialize(void* instance, deserializer* source) const
{
s_deserialize(*reinterpret_cast<channel_ptr*>(instance),
source,
name(),
actor_ptr_name,
group_ptr_name);
}
public: public:
channel_ptr_tinfo() : group_ptr_name(to_uniform_name(typeid(group_ptr))) channel_ptr_tinfo() : group_ptr_name(to_uniform_name(typeid(group_ptr)))
...@@ -321,26 +350,29 @@ class channel_ptr_tinfo : public util::abstract_uniform_type_info<channel_ptr> ...@@ -321,26 +350,29 @@ class channel_ptr_tinfo : public util::abstract_uniform_type_info<channel_ptr>
class any_tuple_tinfo : public util::abstract_uniform_type_info<any_tuple> class any_tuple_tinfo : public util::abstract_uniform_type_info<any_tuple>
{ {
protected: public:
void serialize(const void* instance, serializer* sink) const static void s_serialize(const any_tuple& atup,
serializer* sink,
const std::string& name)
{ {
auto atup = reinterpret_cast<const any_tuple*>(instance); sink->begin_object(name);
sink->begin_object(name()); sink->begin_sequence(atup.size());
sink->begin_sequence(atup->size()); for (size_t i = 0; i < atup.size(); ++i)
for (size_t i = 0; i < atup->size(); ++i)
{ {
atup->type_at(i).serialize(atup->at(i), sink); atup.type_at(i).serialize(atup.at(i), sink);
} }
sink->end_sequence(); sink->end_sequence();
sink->end_object(); sink->end_object();
} }
void deserialize(void* instance, deserializer* source) const static void s_deserialize(any_tuple& atref,
deserializer* source,
const std::string& name)
{ {
auto result = new detail::object_array; auto result = new detail::object_array;
auto str = source->seek_object(); auto str = source->seek_object();
if (str != name()) throw std::logic_error("invalid type found: " + str); if (str != name) throw std::logic_error("invalid type found: " + str);
source->begin_object(str); source->begin_object(str);
size_t tuple_size = source->begin_sequence(); size_t tuple_size = source->begin_sequence();
for (size_t i = 0; i < tuple_size; ++i) for (size_t i = 0; i < tuple_size; ++i)
...@@ -351,7 +383,80 @@ class any_tuple_tinfo : public util::abstract_uniform_type_info<any_tuple> ...@@ -351,7 +383,80 @@ class any_tuple_tinfo : public util::abstract_uniform_type_info<any_tuple>
} }
source->end_sequence(); source->end_sequence();
source->end_object(); source->end_object();
*reinterpret_cast<any_tuple*>(instance) = any_tuple(result); atref = any_tuple(result);
}
protected:
void serialize(const void* instance, serializer* sink) const
{
s_serialize(*reinterpret_cast<const any_tuple*>(instance),sink,name());
}
void deserialize(void* instance, deserializer* source) const
{
s_deserialize(*reinterpret_cast<any_tuple*>(instance), source, name());
}
};
class message_tinfo : public util::abstract_uniform_type_info<message>
{
std::string any_tuple_name;
std::string actor_ptr_name;
std::string group_ptr_name;
std::string ch_ptr_name;
public:
virtual void serialize(const void* instance, serializer* sink) const
{
const message& msg = *reinterpret_cast<const message*>(instance);
const any_tuple& data = msg.content();
sink->begin_object(name());
actor_ptr_tinfo::s_serialize(msg.sender().get(), sink, actor_ptr_name);
channel_ptr_tinfo::s_serialize(msg.receiver().get(),
sink,
ch_ptr_name,
actor_ptr_name,
group_ptr_name);
any_tuple_tinfo::s_serialize(data, sink, any_tuple_name);
//uniform_typeid<actor_ptr>()->serialize(&(msg.sender()), sink);
//uniform_typeid<channel_ptr>()->serialize(&(msg.receiver()), sink);
//uniform_typeid<any_tuple>()->serialize(&data, sink);
sink->end_object();
}
virtual void deserialize(void* instance, deserializer* source) const
{
auto tname = source->seek_object();
if (tname != name()) throw 42;
source->begin_object(tname);
actor_ptr sender;
channel_ptr receiver;
any_tuple content;
actor_ptr_tinfo::s_deserialize(sender, source, actor_ptr_name);
channel_ptr_tinfo::s_deserialize(receiver,
source,
ch_ptr_name,
actor_ptr_name,
group_ptr_name);
any_tuple_tinfo::s_deserialize(content, source, any_tuple_name);
//uniform_typeid<actor_ptr>()->deserialize(&sender, source);
//uniform_typeid<channel_ptr>()->deserialize(&receiver, source);
//uniform_typeid<any_tuple>()->deserialize(&content, source);
source->end_object();
*reinterpret_cast<message*>(instance) = message(sender,
receiver,
content);
}
message_tinfo() : any_tuple_name(to_uniform_name(typeid(any_tuple)))
, actor_ptr_name(to_uniform_name(typeid(actor_ptr)))
, group_ptr_name(to_uniform_name(typeid(group_ptr)))
, ch_ptr_name(to_uniform_name(typeid(channel_ptr)))
{
} }
}; };
...@@ -399,7 +504,7 @@ class uniform_type_info_map ...@@ -399,7 +504,7 @@ class uniform_type_info_map
insert<std::string>(); insert<std::string>();
insert<std::u16string>(); insert<std::u16string>();
insert<std::u32string>(); insert<std::u32string>();
insert(new default_uniform_type_info_impl<exit_reason>( insert(new default_uniform_type_info_impl<exit_signal>(
std::make_pair(&exit_signal::reason, std::make_pair(&exit_signal::reason,
&exit_signal::set_uint_reason)), &exit_signal::set_uint_reason)),
{ raw_name<exit_signal>() }); { raw_name<exit_signal>() });
...@@ -407,6 +512,7 @@ class uniform_type_info_map ...@@ -407,6 +512,7 @@ class uniform_type_info_map
insert(new actor_ptr_tinfo, { raw_name<actor_ptr>() }); insert(new actor_ptr_tinfo, { raw_name<actor_ptr>() });
insert(new group_ptr_tinfo, { raw_name<actor_ptr>() }); insert(new group_ptr_tinfo, { raw_name<actor_ptr>() });
insert(new channel_ptr_tinfo, { raw_name<channel_ptr>() }); insert(new channel_ptr_tinfo, { raw_name<channel_ptr>() });
insert(new message_tinfo, { raw_name<message>() });
insert<float>(); insert<float>();
insert<cppa::util::void_type>(); insert<cppa::util::void_type>();
if (sizeof(double) == sizeof(long double)) if (sizeof(double) == sizeof(long double))
......
include ../Makefile.rules include ../Makefile.rules
INCLUDE_FLAGS = $(INCLUDES) -I../ ./ INCLUDE_FLAGS = $(INCLUDES) -I../ -I./
LIB_FLAGS = $(LIBS) -L../ -lcppa LIB_FLAGS = $(LIBS) -L../ -lcppa
......
#include "cppa/config.hpp"
#include <new> #include <new>
#include <set> #include <set>
#include <list> #include <list>
...@@ -28,7 +30,9 @@ ...@@ -28,7 +30,9 @@
#include "cppa/announce.hpp" #include "cppa/announce.hpp"
#include "cppa/get_view.hpp" #include "cppa/get_view.hpp"
#include "cppa/any_tuple.hpp" #include "cppa/any_tuple.hpp"
#include "cppa/to_string.hpp"
#include "cppa/serializer.hpp" #include "cppa/serializer.hpp"
#include "cppa/from_string.hpp"
#include "cppa/ref_counted.hpp" #include "cppa/ref_counted.hpp"
#include "cppa/deserializer.hpp" #include "cppa/deserializer.hpp"
#include "cppa/primitive_type.hpp" #include "cppa/primitive_type.hpp"
...@@ -110,467 +114,11 @@ bool operator!=(const struct_c& lhs, const struct_c& rhs) ...@@ -110,467 +114,11 @@ bool operator!=(const struct_c& lhs, const struct_c& rhs)
return !(lhs == rhs); return !(lhs == rhs);
} }
class string_serializer : public serializer static const char* msg1str = u8R"__(@msg ( @0, @channel ( @0 ), @<> ( { @i32 ( 42 ), @str ( "Hello \"World\"!" ) } ) ))__";
{
std::ostream& out;
struct pt_writer
{
std::ostream& out;
pt_writer(std::ostream& mout) : out(mout) { }
template<typename T>
void operator()(const T& value)
{
out << value;
}
void operator()(const std::string& str)
{
out << "\"";// << str << "\"";
for (char c : str)
{
if (c == '"') out << "\\\"";
else out << c;
}
out << '"';
}
void operator()(const std::u16string&) { }
void operator()(const std::u32string&) { }
};
int m_open_objects;
bool m_after_value;
bool m_obj_just_opened;
inline void clear()
{
if (m_after_value)
{
out << ", ";
m_after_value = false;
}
else if (m_obj_just_opened)
{
out << " ( ";
m_obj_just_opened = false;
}
}
public:
string_serializer(std::ostream& mout)
: out(mout), m_open_objects(0)
, m_after_value(false), m_obj_just_opened(false)
{
}
void begin_object(const std::string& type_name)
{
clear();
++m_open_objects;
out << type_name;// << " ( ";
m_obj_just_opened = true;
}
void end_object()
{
if (m_obj_just_opened)
{
m_obj_just_opened = false;
}
else
{
out << (m_after_value ? " )" : ")");
}
m_after_value = true;
}
void begin_sequence(size_t)
{
clear();
out << "{ ";
}
void end_sequence()
{
out << (m_after_value ? " }" : "}");
}
void write_value(const primitive_variant& value)
{
clear();
value.apply(pt_writer(out));
m_after_value = true;
}
void write_tuple(size_t size, const primitive_variant* values)
{
clear();
out << " {";
const primitive_variant* end = values + size;
for ( ; values != end; ++values)
{
write_value(*values);
}
out << (m_after_value ? " }" : "}");
}
};
class string_deserializer : public deserializer
{
std::string m_str;
std::string::iterator m_pos;
size_t m_obj_count;
std::stack<bool> m_obj_had_left_parenthesis;
void skip_space_and_comma()
{
while (*m_pos == ' ' || *m_pos == ',') ++m_pos;
}
void throw_malformed(const std::string& error_msg)
{
throw std::logic_error("malformed string: " + error_msg);
}
void consume(char c)
{
skip_space_and_comma();
if (*m_pos != c)
{
std::string error;
error += "expected '";
error += c;
error += "' found '";
error += *m_pos;
error += "'";
throw_malformed(error);
}
++m_pos;
}
bool try_consume(char c)
{
skip_space_and_comma();
if (*m_pos == c)
{
++m_pos;
return true;
}
return false;
}
inline std::string::iterator next_delimiter()
{
return std::find_if(m_pos, m_str.end(), [] (char c) -> bool {
switch (c)
{
case '(':
case ')':
case '{':
case '}':
case ' ':
case ',': return true;
default : return false;
}
});
}
void integrity_check()
{
if (m_obj_had_left_parenthesis.empty())
{
throw_malformed("missing begin_object()");
}
else if (m_obj_had_left_parenthesis.top() == false)
{
throw_malformed("expected left parenthesis after "
"begin_object call or void value");
}
}
public:
string_deserializer(const std::string& str) : m_str(str)
{
m_pos = m_str.begin();
m_obj_count = 0;
}
string_deserializer(std::string&& str) : m_str(std::move(str))
{
m_pos = m_str.begin();
m_obj_count = 0;
}
std::string seek_object()
{
skip_space_and_comma();
auto substr_end = next_delimiter();
if (m_pos == substr_end)
{
if (m_pos != m_str.end())
{
std::string remain(m_pos, m_str.end());
cout << remain << endl;
}
throw_malformed("wtf?");
}
std::string result(m_pos, substr_end);
m_pos = substr_end;
return result;
}
std::string peek_object()
{
std::string result = seek_object();
// restore position in stream
m_pos -= result.size();
return result;
}
void begin_object(const std::string&)
{
++m_obj_count;
skip_space_and_comma();
m_obj_had_left_parenthesis.push(try_consume('('));
//consume('(');
}
void end_object()
{
if (m_obj_had_left_parenthesis.empty())
{
throw_malformed("missing begin_object()");
}
else
{
if (m_obj_had_left_parenthesis.top() == true)
{
consume(')');
}
m_obj_had_left_parenthesis.pop();
}
if (--m_obj_count == 0)
{
skip_space_and_comma();
if (m_pos != m_str.end())
{
throw_malformed("expected end of of string");
}
}
}
size_t begin_sequence()
{
integrity_check();
consume('{');
auto list_end = std::find(m_pos, m_str.end(), '}');
return std::count(m_pos, list_end, ',') + 1;
}
void end_sequence()
{
consume('}');
}
struct from_string
{
const std::string& str;
from_string(const std::string& s) : str(s) { }
template<typename T>
void operator()(T& what)
{
std::istringstream s(str);
s >> what;
}
void operator()(std::string& what)
{
what = str;
}
void operator()(std::u16string&) { }
void operator()(std::u32string&) { }
};
primitive_variant read_value(primitive_type ptype)
{
integrity_check();
skip_space_and_comma();
std::string::iterator substr_end;
auto find_if_cond = [] (char c) -> bool
{
switch (c)
{
case ')':
case '}':
case ' ':
case ',': return true;
default : return false;
}
};
if (ptype == pt_u8string)
{
if (*m_pos == '"')
{
// skip leading "
++m_pos;
char last_char = '"';
auto find_if_str_cond = [&last_char] (char c) -> bool
{
if (c == '"' && last_char != '\\')
{
return true;
}
last_char = c;
return false;
};
substr_end = std::find_if(m_pos, m_str.end(), find_if_str_cond);
}
else
{
substr_end = std::find_if(m_pos, m_str.end(), find_if_cond);
}
}
else
{
substr_end = std::find_if(m_pos, m_str.end(), find_if_cond);
}
if (substr_end == m_str.end())
{
throw std::logic_error("malformed string (unterminated value)");
}
std::string substr(m_pos, substr_end);
m_pos += substr.size();
if (ptype == pt_u8string)
{
// skip trailing "
if (*m_pos != '"')
{
std::string error_msg;
error_msg = "malformed string, expected '\"' found '";
error_msg += *m_pos;
error_msg += "'";
throw std::logic_error(error_msg);
}
++m_pos;
// replace '\"' by '"'
char last_char = ' ';
auto cond = [&last_char] (char c) -> bool
{
if (c == '"' && last_char == '\\')
{
return true;
}
last_char = c;
return false;
};
std::string tmp;
auto sbegin = substr.begin();
auto send = substr.end();
for (auto i = std::find_if(sbegin, send, cond);
i != send;
i = std::find_if(i, send, cond))
{
--i;
tmp.append(sbegin, i);
tmp += '"';
i += 2;
sbegin = i;
}
if (sbegin != substr.begin())
{
tmp.append(sbegin, send);
}
if (!tmp.empty())
{
substr = std::move(tmp);
}
}
primitive_variant result(ptype);
result.apply(from_string(substr));
return result;
}
void foo() {}
void read_tuple(size_t size, const primitive_type* begin, primitive_variant* storage)
{
integrity_check();
consume('{');
const primitive_type* end = begin + size;
for ( ; begin != end; ++begin)
{
*storage = std::move(read_value(*begin));
++storage;
}
consume('}');
}
};
class message_tinfo : public util::abstract_uniform_type_info<message>
{
public:
virtual void serialize(const void* instance, serializer* sink) const
{
const message& msg = *reinterpret_cast<const message*>(instance);
const any_tuple& data = msg.content();
sink->begin_object(name());
uniform_typeid<actor_ptr>()->serialize(&(msg.sender()), sink);
uniform_typeid<channel_ptr>()->serialize(&(msg.receiver()), sink);
uniform_typeid<any_tuple>()->serialize(&data, sink);
sink->end_object();
}
virtual void deserialize(void* instance, deserializer* source) const
{
auto tname = source->seek_object();
if (tname != name()) throw 42;
source->begin_object(tname);
actor_ptr sender;
channel_ptr receiver;
any_tuple content;
uniform_typeid<actor_ptr>()->deserialize(&sender, source);
uniform_typeid<channel_ptr>()->deserialize(&receiver, source);
uniform_typeid<any_tuple>()->deserialize(&content, source);
source->end_object();
*reinterpret_cast<message*>(instance) = message(sender,
receiver,
content);
}
};
template<typename T>
std::string to_string(const T& what)
{
auto utype = uniform_typeid<T>();
if (!utype)
{
throw std::logic_error( detail::to_uniform_name(typeid(T))
+ " not found");
}
std::ostringstream osstr;
string_serializer strs(osstr);
utype->serialize(&what, &strs);
return osstr.str();
}
size_t test__serialization() size_t test__serialization()
{ {
CPPA_TEST(test__serialization); CPPA_TEST(test__serialization);
announce(typeid(message), new message_tinfo);
auto oarr = new detail::object_array; auto oarr = new detail::object_array;
oarr->push_back(object(static_cast<std::uint32_t>(42))); oarr->push_back(object(static_cast<std::uint32_t>(42)));
...@@ -612,15 +160,13 @@ size_t test__serialization() ...@@ -612,15 +160,13 @@ size_t test__serialization()
{ {
message msg1(0, 0, 42, std::string("Hello \"World\"!")); message msg1(0, 0, 42, std::string("Hello \"World\"!"));
cout << "msg = " << to_string(msg1) << endl; CPPA_CHECK_EQUAL(msg1str, to_string(msg1));
binary_serializer bs; binary_serializer bs;
bs << msg1; bs << msg1;
binary_deserializer bd(bs.data(), bs.size()); binary_deserializer bd(bs.data(), bs.size());
string_deserializer sd(to_string(msg1));
object obj1; object obj1;
bd >> obj1; bd >> obj1;
object obj2; object obj2 = from_string(to_string(msg1));
sd >> obj2;
CPPA_CHECK_EQUAL(obj1, obj2); CPPA_CHECK_EQUAL(obj1, obj2);
if (obj1.type() == typeid(message) && obj2.type() == obj1.type()) if (obj1.type() == typeid(message) && obj2.type() == obj1.type())
{ {
...@@ -689,11 +235,9 @@ size_t test__serialization() ...@@ -689,11 +235,9 @@ size_t test__serialization()
// verify result of serialization / deserialization // verify result of serialization / deserialization
CPPA_CHECK_EQUAL(b1, b2); CPPA_CHECK_EQUAL(b1, b2);
CPPA_CHECK_EQUAL(to_string(b2), b1str); CPPA_CHECK_EQUAL(to_string(b2), b1str);
// deserialize b3 from string, using string_deserializer // deserialize b3 from string
{ {
string_deserializer strd(b1str); object res = from_string(b1str);
object res;
strd >> res;
CPPA_CHECK_EQUAL(res.type().name(), "struct_b"); CPPA_CHECK_EQUAL(res.type().name(), "struct_b");
b3 = get<struct_b>(res); b3 = get<struct_b>(res);
} }
......
...@@ -19,16 +19,48 @@ void pong() ...@@ -19,16 +19,48 @@ void pong()
}); });
} }
void echo(actor_ptr whom, int what)
{
send(whom, what);
}
size_t test__spawn() size_t test__spawn()
{ {
CPPA_TEST(test__spawn); CPPA_TEST(test__spawn);
actor_ptr self_ptr = self();
{ {
auto sl = spawn(pong); auto sl = spawn(pong);
spawn(echo, self_ptr, 1);
send(sl, 23.f); send(sl, 23.f);
send(sl, 2); send(sl, 2);
receive(on<int>() >> [&](int value) { bool received_pong = false;
CPPA_CHECK_EQUAL(value, 42); bool received_echo = false;
auto rules = (on<int>(42) >> [&]() { received_pong = true; },
on<int>(1) >> [&]() { received_echo = true; });
receive(rules);
receive(rules);
CPPA_CHECK(received_pong);
CPPA_CHECK(received_echo);
}
{
auto sl = spawn([]() {
receive(on<int>() >> [](int value) {
reply((value * 20) + 2);
});
}); });
spawn([](actor_ptr whom, int what) { send(whom, what); },
self_ptr,
1);
send(sl, 23.f);
send(sl, 2);
bool received_pong = false;
bool received_echo = false;
auto rules = (on<int>(42) >> [&]() { received_pong = true; },
on<int>(1) >> [&]() { received_echo = true; });
receive(rules);
receive(rules);
CPPA_CHECK(received_pong);
CPPA_CHECK(received_echo);
} }
await_all_others_done(); await_all_others_done();
return CPPA_TEST_RESULT; return CPPA_TEST_RESULT;
......
...@@ -87,12 +87,13 @@ size_t test__uniform_type() ...@@ -87,12 +87,13 @@ size_t test__uniform_type()
"float", "double", // floating points "float", "double", // floating points
"@0", // cppa::util::void_type "@0", // cppa::util::void_type
// default announced cppa types // default announced cppa types
"cppa::any_type", "@*", // cppa::any_type
"cppa::any_tuple", "@<>", // cppa::any_tuple
"cppa::exit_reason", "@msg", // cppa::message
"cppa::intrusive_ptr<cppa::actor>", "@exit", // cppa::exit_signal
"cppa::intrusive_ptr<cppa::group>", "@actor", // cppa::actor_ptr
"cppa::intrusive_ptr<cppa::channel>" "@group", // cppa::group_ptr
"@channel" // cppa::channel_ptr
}; };
if (sizeof(double) != sizeof(long double)) if (sizeof(double) != sizeof(long double))
{ {
......
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