Commit e0042862 authored by neverlord's avatar neverlord

atoms

parent e9fdcb8d
......@@ -145,8 +145,6 @@ cppa/any_tuple.hpp
src/any_tuple.cpp
cppa/util/abstract_uniform_type_info.hpp
cppa/util/upgrade_lock_guard.hpp
cppa/exit_signal.hpp
src/exit_signal.cpp
cppa/to_string.hpp
src/string_serialization.cpp
cppa/from_string.hpp
......@@ -173,3 +171,8 @@ cppa/detail/actor_proxy_cache.hpp
src/actor_proxy_cache.cpp
src/attachable.cpp
cppa/attachable.hpp
cppa/atom.hpp
cppa/detail/atom_val.hpp
src/atom.cpp
src/cppa.cpp
cppa/exit_reason.hpp
#ifndef ACTOR_HPP
#define ACTOR_HPP
#include <memory>
#include <cstdint>
#include <type_traits>
#include "cppa/group.hpp"
#include "cppa/channel.hpp"
#include "cppa/attachable.hpp"
#include "cppa/process_information.hpp"
#include "cppa/util/enable_if.hpp"
namespace cppa {
class serializer;
......@@ -48,14 +52,25 @@ class actor : public channel
virtual bool attach(attachable* ptr) = 0;
/**
* @brief
* @brief Detaches the first attached object that matches @p what.
*/
virtual void join(group_ptr& what) = 0;
virtual void detach(const attachable::token& what) = 0;
template<typename T>
bool attach(std::unique_ptr<T>&& ptr,
typename util::enable_if<std::is_base_of<attachable,T>>::type* = 0);
/**
* @brief
* @brief Forces this actor to subscribe to the group @p what.
*
* The group will be unsubscribed if the actor exits.
*/
void join(group_ptr& what);
/**
* @brief Forces this actor to leave the group @p what.
*/
virtual void leave(const group_ptr& what) = 0;
void leave(const group_ptr& what);
/**
* @brief
......@@ -104,6 +119,15 @@ serializer& operator<<(serializer&, const actor_ptr&);
deserializer& operator>>(deserializer&, actor_ptr&);
template<typename T>
bool actor::attach(std::unique_ptr<T>&& ptr,
typename util::enable_if<std::is_base_of<attachable,T>>::type*)
{
return attach(static_cast<attachable*>(ptr.release()));
}
} // namespace cppa
#endif // ACTOR_HPP
......@@ -18,6 +18,8 @@ class actor_proxy : public actor
bool attach(attachable* ptr);
void detach(const attachable::token&);
void enqueue(const message& msg);
void join(group_ptr& what);
......
#ifndef ATOM_HPP
#define ATOM_HPP
#include <string>
#include "cppa/detail/atom_val.hpp"
namespace cppa {
enum class atom_value : std::uint64_t { dirty_little_hack = 37337 };
std::string to_string(const atom_value& a);
template<size_t Size>
constexpr atom_value atom(const char (&str) [Size])
{
// last character is the NULL terminator
static_assert(Size <= 11, "only 10 characters are allowed");
return static_cast<atom_value>(detail::atom_val(str, 0));
}
} // namespace cppa
#endif // ATOM_HPP
......@@ -2,6 +2,7 @@
#define ATTACHABLE_HPP
#include <cstdint>
#include <typeinfo>
namespace cppa {
......@@ -20,6 +21,16 @@ class attachable
public:
struct token
{
const std::type_info& subtype;
const void* ptr;
inline token(const std::type_info& msubtype, const void* mptr)
: subtype(msubtype), ptr(mptr)
{
}
};
virtual ~attachable();
/**
......@@ -30,6 +41,8 @@ class attachable
*/
virtual void detach(std::uint32_t reason);
virtual bool matches(const token&);
};
} // namespace cppa
......
......@@ -2,7 +2,6 @@
#define CONTEXT_HPP
#include "cppa/actor.hpp"
#include "cppa/exit_signal.hpp"
#include "cppa/message_queue.hpp"
namespace cppa {
......
......@@ -34,6 +34,7 @@
#include <type_traits>
#include "cppa/on.hpp"
#include "cppa/atom.hpp"
#include "cppa/tuple.hpp"
#include "cppa/actor.hpp"
#include "cppa/invoke.hpp"
......@@ -41,7 +42,7 @@
#include "cppa/context.hpp"
#include "cppa/message.hpp"
#include "cppa/scheduler.hpp"
#include "cppa/exit_signal.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/invoke_rules.hpp"
#include "cppa/actor_behavior.hpp"
#include "cppa/scheduling_hint.hpp"
......@@ -159,6 +160,13 @@ send(intrusive_ptr<C>&& whom, const Arg0& arg0, const Args&... args)
if (whom) whom->enqueue(message(self(), whom, arg0, args...));
}
// 'matches' send(self(), ...);
template<typename Arg0, typename... Args>
void send(context* whom, const Arg0& arg0, const Args&... args)
{
if (whom) whom->enqueue(message(self(), whom, arg0, args...));
}
template<class C>
typename util::enable_if<std::is_base_of<channel, C>, intrusive_ptr<C>&>::type
operator<<(intrusive_ptr<C>& whom, const any_tuple& what)
......@@ -191,6 +199,12 @@ operator<<(intrusive_ptr<C>&& whom, any_tuple&& what)
return std::move(whom);
}
// matches self() << make_tuple(...)
context* operator<<(context* whom, const any_tuple& what);
// matches self() << make_tuple(...)
context* operator<<(context* whom, any_tuple&& what);
template<typename Arg0, typename... Args>
void reply(const Arg0& arg0, const Args&... args)
{
......
#ifndef ATOM_VAL_HPP
#define ATOM_VAL_HPP
namespace cppa { namespace detail { namespace {
// encodes ASCII characters to 6bit encoding
constexpr char encoding_table[] =
{
/* ..0 ..1 ..2 ..3 ..4 ..5 ..6 ..7 ..8 ..9 ..A ..B ..C ..D ..E ..F */
/* 0.. */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 1.. */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 2.. */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 3.. */ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 0, 0, 0, 0,
/* 4.. */ 0, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
/* 5.. */ 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 0, 0, 0, 0, 38,
/* 6.. */ 0, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
/* 7.. */ 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 0, 0, 0, 0, 0
};
// decodes 6bit characters to ASCII
constexpr char decoding_table[] = " 0123456789:"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ_"
"abcdefghijklmnopqrstuvwxyz";
inline constexpr std::uint64_t next_interim(std::uint64_t tmp, size_t char_code)
{
return (tmp << 6) | encoding_table[char_code];
}
constexpr std::uint64_t atom_val(const char* str, std::uint64_t interim = 0)
{
return (*str == '\0') ? interim
: atom_val(str + 1, next_interim(interim, *str));
}
} } } // namespace cppa::detail::<anonymous>
#endif // ATOM_VAL_HPP
......@@ -10,6 +10,7 @@
#include <memory>
#include "cppa/context.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/detail/blocking_message_queue.hpp"
namespace cppa { namespace detail {
......@@ -26,9 +27,6 @@ class converted_thread_context : public context
// guards access to m_exited, m_subscriptions and m_links
std::mutex m_mtx;
// manages group subscriptions
std::map<group_ptr, group::subscription> m_subscriptions;
// manages actor links
std::list<actor_ptr> m_links;
......@@ -51,12 +49,10 @@ class converted_thread_context : public context
bool attach /*[[override]]*/ (attachable* ptr);
void join /*[[override]]*/ (group_ptr& what);
void detach /*[[override]]*/ (const attachable::token&);
void quit /*[[override]]*/ (std::uint32_t reason);
void leave /*[[override]]*/ (const group_ptr& what);
void link_to /*[[override]]*/ (intrusive_ptr<actor>& other);
void unlink_from /*[[override]]*/ (intrusive_ptr<actor>& other);
......
......@@ -85,7 +85,15 @@ struct tdata_upcast_helper<0, Head, Tail...>
};
} // namespace detail
} } // namespace cppa::detail
namespace cppa {
template<typename... Tn>
inline detail::tdata<Tn...> make_tdata(const Tn&... args)
{
return detail::tdata<Tn...>(args...);
}
template<size_t N, typename... Tn>
const typename util::at<N, Tn...>::type& get(const detail::tdata<Tn...>& tv)
......@@ -101,6 +109,6 @@ typename util::at<N, Tn...>::type& get_ref(detail::tdata<Tn...>& tv)
return static_cast<typename detail::tdata_upcast_helper<N, Tn...>::type &>(tv).head;
}
} // namespace cppa::detail
} // namespace cppa
#endif // TDATA_HPP
#ifndef EXIT_REASON_HPP
#define EXIT_REASON_HPP
#include <cstdint>
namespace cppa { namespace exit_reason {
/**
* @brief Indicates that the actor is still alive.
*/
static constexpr std::uint32_t not_exited = 0x00000;
/**
* @brief Indicates that an actor finished execution.
*/
static constexpr std::uint32_t normal = 0x00001;
/**
* @brief Indicates that an actor finished execution
* because of an unhandled exception.
*/
static constexpr std::uint32_t unhandled_exception = 0x00002;
/**
* @brief Indicates that an actor finishied execution
* because a connection to a remote link was
* closed unexpectedly.
*/
static constexpr std::uint32_t remote_link_unreachable = 0x00101;
/**
* @brief Any user defined exit reason should have a
* value greater or equal to prevent collisions
* with default defined exit reasons.
*/
static constexpr std::uint32_t user_defined = 0x10000;
} } // namespace cppa::exit_reason
#endif // EXIT_REASON_HPP
#ifndef EXIT_SIGNAL_HPP
#define EXIT_SIGNAL_HPP
#include <cstdint>
namespace cppa {
namespace exit_reason
{
/**
* @brief Indicates that the actor is still alive.
*/
static constexpr std::uint32_t not_exited = 0x00000;
/**
* @brief Indicates that an actor finished execution.
*/
static constexpr std::uint32_t normal = 0x00001;
/**
* @brief Indicates that an actor finished execution
* because of an unhandled exception.
*/
static constexpr std::uint32_t unhandled_exception = 0x00002;
/**
* @brief Indicates that an actor finishied execution
* because a connection to a remote link was
* closed unexpectedly.
*/
static constexpr std::uint32_t remote_link_unreachable = 0x00101;
/**
* @brief Any user defined exit reason should have a
* value greater or equal to prevent collisions
* with default defined exit reasons.
*/
static constexpr std::uint32_t user_defined = 0x10000;
}
class exit_signal
{
std::uint32_t m_reason;
public:
/**
* @brief Creates an exit signal with
* <tt>reason() == exit_reason::normal</tt>.
*/
exit_signal();
/**
* @brief Creates an exit signal with
* <tt>reason() == @p r</tt>.
* @pre {@code r >= exit_reason::user_defined}.
*/
explicit exit_signal(std::uint32_t r);
/**
* @brief Reads the exit reason.
*/
inline std::uint32_t reason() const
{
return m_reason;
}
/**
* @brief Sets the exit reason to @p value.
*/
void set_reason(std::uint32_t value);
};
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
#endif // EXIT_SIGNAL_HPP
......@@ -2,8 +2,10 @@
#define GROUP_HPP
#include <string>
#include <memory>
#include "cppa/channel.hpp"
#include "cppa/attachable.hpp"
#include "cppa/ref_counted.hpp"
namespace cppa {
......@@ -24,33 +26,36 @@ class group : public channel
public:
class subscription;
class unsubscriber;
friend class subscription;
friend class unsubscriber;
class subscription
// unsubscribes its channel from the group on destruction
class unsubscriber : public attachable
{
friend class group;
channel_ptr m_self;
intrusive_ptr<group> m_group;
subscription() = delete;
subscription(const subscription&) = delete;
subscription& operator=(const subscription&) = delete;
unsubscriber() = delete;
unsubscriber(const unsubscriber&) = delete;
unsubscriber& operator=(const unsubscriber&) = delete;
public:
inline explicit operator bool()
{
return m_self != nullptr && m_group != nullptr;
}
unsubscriber(const channel_ptr& s, const intrusive_ptr<group>& g);
// matches on group
bool matches(const attachable::token& what);
subscription(const channel_ptr& s, const intrusive_ptr<group>& g);
subscription(subscription&& other);
~subscription();
virtual ~unsubscriber();
};
typedef std::unique_ptr<unsubscriber> subscription;
class module
{
......
......@@ -11,7 +11,7 @@
namespace cppa {
template<typename T>
class intrusive_ptr : util::comparable<intrusive_ptr<T>, T*>,
class intrusive_ptr : util::comparable<intrusive_ptr<T>, const T*>,
util::comparable<intrusive_ptr<T>>
{
......
......@@ -4,6 +4,7 @@
#include <utility>
#include <stdexcept>
#include "cppa/atom.hpp"
#include "cppa/any_type.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/tuple_view.hpp"
......@@ -18,6 +19,7 @@
namespace cppa {
// match types only; don't calculate view mapping
template<typename... MatchRules>
bool match(const any_tuple& what)
{
......@@ -26,6 +28,7 @@ bool match(const any_tuple& what)
return detail::matcher<MatchRules...>::match(begin, end);
}
// match types only; calculate view mapping
template<typename... MatchRules>
bool match(const any_tuple& what, std::vector<size_t>& mappings)
{
......@@ -34,6 +37,7 @@ bool match(const any_tuple& what, std::vector<size_t>& mappings)
return detail::matcher<MatchRules...>::match(begin, end, &mappings);
}
// match types and values; calculate view mapping
template<typename... MatchRules, class ValuesTuple>
bool match(const any_tuple& what, const ValuesTuple& vals,
std::vector<size_t>& mappings)
......@@ -44,7 +48,8 @@ bool match(const any_tuple& what, const ValuesTuple& vals,
typedef typename tuple_view_type_from_type_list<filtered_rules>::type
view_type;
static_assert(util::eval_type_lists<filtered_rules,
ValuesTuple,
view_type,
//ValuesTuple,
util::is_comparable>::value,
"given values are not comparable to matched types");
if (match<MatchRules...>(what, mappings))
......@@ -56,6 +61,7 @@ bool match(const any_tuple& what, const ValuesTuple& vals,
return false;
}
// match types and values; don't calculate view mapping
template<typename... MatchRules, class ValuesTuple>
bool match(const any_tuple& what, const ValuesTuple& vals)
{
......@@ -63,6 +69,12 @@ bool match(const any_tuple& what, const ValuesTuple& vals)
return match<MatchRules...>(what, vals, mappings);
}
template<atom_value A0, typename... MatchRules>
bool match(const any_tuple& what)
{
return match<atom_value, MatchRules...>(what, make_tdata(A0));
}
} // namespace cppa
#endif // MATCH_HPP
#ifndef ON_HPP
#define ON_HPP
#include "cppa/atom.hpp"
#include "cppa/match.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/invoke_rules.hpp"
......@@ -189,6 +190,24 @@ inline detail::invoke_rule_builder<Types...> on(const Arg0& arg0,
return detail::invoke_rule_builder<Types...>(arg0, args...);
}
template<atom_value A0, typename... Types, typename... Args>
inline auto on(const Args&... args) -> decltype(on<atom_value, Types...>(A0, args...))
{
return on<atom_value, Types...>(A0, args...);
}
template<atom_value A0, atom_value A1, typename... Types, typename... Args>
inline auto on(const Args&... args) -> decltype(on<atom_value, atom_value, Types...>(A0, A1, args...))
{
return on<atom_value, atom_value, Types...>(A0, A1, args...);
}
template<atom_value A0, atom_value A1, atom_value A2, typename... Types, typename... Args>
inline auto on(const Args&... args) -> decltype(on<atom_value, atom_value, atom_value, Types...>(A0, A1, A2, args...))
{
return on<atom_value, atom_value, atom_value, Types...>(A0, A1, A2, args...);
}
} // namespace cppa
#endif // ON_HPP
......@@ -55,4 +55,17 @@ const process_information& actor::parent_process() const
return process_information::get();
}
void actor::join(group_ptr& what)
{
if (!what) return;
attach(what->subscribe(this));
}
void actor::leave(const group_ptr& what)
{
if (!what) return;
attachable::token group_token(typeid(group::unsubscriber), what.get());
detach(group_token);
}
} // namespace cppa
......@@ -25,6 +25,10 @@ bool actor_proxy::attach(attachable* ptr)
return false;
}
void actor_proxy::detach(const attachable::token&)
{
}
void actor_proxy::join(group_ptr& what)
{
}
......
#include "cppa/atom.hpp"
namespace cppa {
std::string to_string(const atom_value& a)
{
std::string result;
result.reserve(11);
for (auto x = static_cast<std::uint64_t>(a); x != 0; x >>= 6)
{
// decode 6 bit characters to ASCII
result += detail::decoding_table[static_cast<size_t>(x & 0x3F)];
}
// result is reversed, since we read from right-to-left
return std::string(result.rbegin(), result.rend());
}
} // namespace cppa
......@@ -10,4 +10,9 @@ void attachable::detach(std::uint32_t)
{
}
bool attachable::matches(const attachable::token&)
{
return false;
}
} // namespace cppa::detail
#include <vector>
#include "cppa/atom.hpp"
#include "cppa/match.hpp"
#include "cppa/context.hpp"
#include "cppa/exit_signal.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/invoke_rules.hpp"
#include "cppa/util/singly_linked_list.hpp"
......@@ -10,7 +11,7 @@
#include "cppa/detail/intermediate.hpp"
#include "cppa/detail/blocking_message_queue.hpp"
namespace {
namespace cppa { namespace {
enum throw_on_exit_result
{
......@@ -18,15 +19,12 @@ enum throw_on_exit_result
normal_exit_signal
};
throw_on_exit_result throw_on_exit(const cppa::message& msg)
throw_on_exit_result throw_on_exit(const message& msg)
{
std::vector<size_t> mappings;
if (cppa::match<cppa::exit_signal>(msg.content(), mappings))
if (match<atom(":Exit"), std::uint32_t>(msg.content()))
{
cppa::tuple_view<cppa::exit_signal> tview(msg.content().vals(),
std::move(mappings));
auto reason = cppa::get<0>(tview).reason();
if (reason != static_cast<std::uint32_t>(cppa::exit_reason::normal))
auto reason = *reinterpret_cast<const std::uint32_t*>(msg.content().at(1));
if (reason != exit_reason::normal)
{
// throws
cppa::self()->quit(reason);
......@@ -39,7 +37,7 @@ throw_on_exit_result throw_on_exit(const cppa::message& msg)
return not_an_exit_signal;
}
} // namespace <anonymous>
} } // namespace cppa::<anonymous>
namespace cppa { namespace detail {
......
#include <memory>
#include <algorithm>
#include "cppa/atom.hpp"
#include "cppa/exception.hpp"
#include "cppa/exit_signal.hpp"
#include "cppa/detail/converted_thread_context.hpp"
namespace {
......@@ -72,29 +72,39 @@ bool converted_thread_context::attach(attachable* ptr)
}
}
void converted_thread_context::detach(const attachable::token& what)
{
std::lock_guard<std::mutex> guard(m_mtx);
for (auto i = m_attachables.begin(); i != m_attachables.end(); ++i)
{
if ((*i)->matches(what))
{
m_attachables.erase(i);
return;
}
}
}
void converted_thread_context::cleanup(std::uint32_t reason)
{
if (reason == exit_reason::not_exited) return;
decltype(m_links) mlinks;
decltype(m_subscriptions) msubscriptions;
decltype(m_attachables) mattachables;
// lifetime scope of guard
{
std::lock_guard<std::mutex> guard(m_mtx);
m_exit_reason = reason;
mlinks = std::move(m_links);
msubscriptions = std::move(m_subscriptions);
mattachables = std::move(m_attachables);
// make sure lists are definitely empty
m_links.clear();
m_subscriptions.clear();
m_attachables.clear();
}
actor_ptr mself = self();
// send exit messages
for (actor_ptr& aptr : mlinks)
{
aptr->enqueue(message(mself, aptr, exit_signal(reason)));
aptr->enqueue(message(mself, aptr, atom(":Exit"), reason));
}
for (std::unique_ptr<attachable>& ptr : mattachables)
{
......@@ -165,24 +175,6 @@ void converted_thread_context::unlink_from(intrusive_ptr<actor>& other)
}
}
void converted_thread_context::join(group_ptr& what)
{
std::lock_guard<std::mutex> guard(m_mtx);
if (!exited() && m_subscriptions.count(what) == 0)
{
auto s = what->subscribe(this);
// insert only valid subscriptions
// (a subscription is invalid if this actor already joined the group)
if (s) m_subscriptions.insert(std::make_pair(what, std::move(s)));
}
}
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;
......
#include "cppa/cppa.hpp"
namespace cppa {
context* operator<<(context* whom, const any_tuple& what)
{
if (whom) whom->enqueue(message(self(), whom, what));
return whom;
}
// matches self() << make_tuple(...)
context* operator<<(context* whom, any_tuple&& what)
{
if (whom) whom->enqueue(message(self(), whom, std::move(what)));
return whom;
}
} // namespace cppa
#include "cppa/exit_signal.hpp"
namespace cppa {
exit_signal::exit_signal() : m_reason(exit_reason::normal)
{
}
exit_signal::exit_signal(std::uint32_t r) : m_reason(r)
{
}
void exit_signal::set_reason(std::uint32_t value)
{
m_reason = value;
}
} // namespace cppa
......@@ -51,15 +51,13 @@ class local_group : public group
virtual group::subscription subscribe(const channel_ptr& who)
{
group::subscription result;
exclusive_guard guard(m_mtx);
if (m_subscribers.insert(who).second)
{
return { who, this };
}
else
{
return { nullptr, nullptr };
result.reset(new group::unsubscriber(who, this));
}
return result;
}
virtual void unsubscribe(const channel_ptr& who)
......@@ -171,20 +169,24 @@ void group::add_module(group::module* ptr)
}
group::subscription::subscription(const channel_ptr& s,
group::unsubscriber::unsubscriber(const channel_ptr& s,
const intrusive_ptr<group>& g)
: m_self(s), m_group(g)
{
}
group::subscription::subscription(group::subscription&& other)
: m_self(std::move(other.m_self)), m_group(std::move(other.m_group))
group::unsubscriber::~unsubscriber()
{
if (m_group) m_group->unsubscribe(m_self);
}
group::subscription::~subscription()
bool group::unsubscriber::matches(const attachable::token& what)
{
if (m_group) m_group->unsubscribe(m_self);
if (what.subtype == typeid(group::unsubscriber))
{
return m_group == reinterpret_cast<const group*>(what.ptr);
}
return false;
}
group::group(std::string&& id, std::string&& mod_name)
......
......@@ -6,13 +6,13 @@
#include <stdexcept>
#include <algorithm>
#include "cppa/atom.hpp"
#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"
......@@ -90,9 +90,9 @@ std::string to_uniform_name_impl(Iterator begin, Iterator end,
{ demangled<std::u32string>(), "@u32str" },
// cppa types
{ demangled<cppa::any_type>(), "@*" },
{ demangled<cppa::atom_value>(), "@atom" },
{ 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" },
......
......@@ -14,9 +14,11 @@
#include <boost/thread.hpp>
#include "cppa/cppa.hpp"
#include "cppa/atom.hpp"
#include "cppa/match.hpp"
#include "cppa/to_string.hpp"
#include "cppa/exception.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/binary_serializer.hpp"
#include "cppa/binary_deserializer.hpp"
#include "cppa/util/single_reader_queue.hpp"
......@@ -202,7 +204,7 @@ void fake_exits_from_disconnected_links(link_map& links)
for (auto& rem_actor : remote_actors)
{
message msg(rem_actor, local_actor,
exit_signal(exit_reason::remote_link_unreachable));
atom(":Exit"), exit_reason::remote_link_unreachable);
local_actor->enqueue(msg);
}
}
......@@ -250,7 +252,7 @@ void mailman_loop()
mailman_send_job& sjob = job->send_job();
// keep track about link states of local actors
// (remove link states between local and remote actors if needed)
if (match<exit_signal>(sjob.original_message.content()))
if (match<atom(":Exit"), std::uint32_t>(sjob.original_message.content()))
{
auto sender = sjob.original_message.sender();
if (pself == sender->parent_process())
......
#include "cppa/config.hpp"
#include <map>
#include <set>
#include <locale>
......@@ -9,15 +11,13 @@
#include <iostream>
#include <type_traits>
#include "cppa/config.hpp"
#include "cppa/atom.hpp"
#include "cppa/actor.hpp"
#include "cppa/object.hpp"
#include "cppa/message.hpp"
#include "cppa/announce.hpp"
#include "cppa/any_type.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/exit_signal.hpp"
#include "cppa/intrusive_ptr.hpp"
#include "cppa/uniform_type_info.hpp"
......@@ -485,6 +485,32 @@ class message_tinfo : public util::abstract_uniform_type_info<message>
};
class atom_value_tinfo : public util::abstract_uniform_type_info<atom_value>
{
public:
virtual void serialize(const void* instance, serializer* sink) const
{
auto val = reinterpret_cast<const atom_value*>(instance);
sink->begin_object(name());
sink->write_value(static_cast<std::uint64_t>(*val));
sink->end_object();
}
virtual void deserialize(void* instance, deserializer* source) const
{
auto val = reinterpret_cast<atom_value*>(instance);
auto tname = source->seek_object();
if (tname != name()) throw 42;
source->begin_object(tname);
auto ptval = source->read_value(pt_uint64);
source->end_object();
*val = static_cast<atom_value>(get<std::uint64_t>(ptval));
}
};
class uniform_type_info_map
{
......@@ -528,15 +554,12 @@ class uniform_type_info_map
insert<std::string>();
insert<std::u16string>();
insert<std::u32string>();
insert(new default_uniform_type_info_impl<exit_signal>(
std::make_pair(&exit_signal::reason,
&exit_signal::set_reason)),
{ raw_name<exit_signal>() });
insert(new any_tuple_tinfo, { raw_name<any_tuple>() });
insert(new actor_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 message_tinfo, { raw_name<message>() });
insert(new atom_value_tinfo, { raw_name<atom_value>() });
insert<float>();
insert<cppa::util::void_type>();
if (sizeof(double) == sizeof(long double))
......
......@@ -6,134 +6,39 @@
#include "hash_of.hpp"
#include "cppa/util.hpp"
#include "cppa/cppa.hpp"
using std::cout;
using std::endl;
using namespace cppa;
using namespace cppa::util;
namespace {
// encodes ASCII characters to 6bit encoding
constexpr char encoding_table[256] =
{
/* ..0 ..1 ..2 ..3 ..4 ..5 ..6 ..7 ..8 ..9 ..A ..B ..C ..D ..E ..F */
/* 0.. */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 1.. */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 2.. */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 3.. */ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 0, 0, 0, 0,
/* 4.. */ 0, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
/* 5.. */ 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 0, 0, 0, 0, 38,
/* 6.. */ 0, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
/* 7.. */ 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 0, 0, 0, 0, 0
};
// decodes 6bit characters to ASCII
constexpr char decoding_table[] = " 0123456789:"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ_"
"abcdefghijklmnopqrstuvwxyz";
} // namespace <anonymous>
// use 6 bit per character, stored in a 64 bit integer = max. 10 characters
template<char... Str>
struct get_atom_value;
template<char C0, char... Str>
struct get_atom_value<C0, Str...>
{
static_assert(sizeof...(Str) <= 9,
"only 10 characters are allowed");
static constexpr char mapped_c0 = encoding_table[C0 >= 0 ? static_cast<size_t>(C0) : 0];
inline static constexpr std::uint64_t _(std::uint64_t interim)
{
static_assert(mapped_c0 != 0,
"only alphanumeric characters, '_' or ':' are allowed");
return get_atom_value<Str...>::_((interim << 6) | mapped_c0);
}
};
template<>
struct get_atom_value<>
{
inline static constexpr std::uint64_t _(std::uint64_t result)
{
return result;
}
};
constexpr std::uint64_t atom_val(const char* str, std::uint64_t interim = 0)
{
return (str[0] != '\0') ? atom_val(str + 1, (interim << 6) | encoding_table[static_cast<size_t>(str[0])]) : interim;
}
class atom
{
protected:
std::uint64_t m_value;
constexpr atom(std::uint64_t val) : m_value(val) { }
static constexpr auto s_foo = atom("abc");
public:
constexpr atom(const atom& other) : m_value(other.m_value) { }
template<size_t Size>
constexpr atom(const char (&str) [Size]) : m_value(atom_val(str))
{
// 11 because the last character is the NULL terminator
static_assert(Size <= 11, "only 10 characters are allowed");
}
template<char... Str>
static constexpr atom get()
{
return atom(get_atom_value<Str...>::_(0));
}
std::uint64_t value() const
{
return m_value;
}
};
std::string to_string(const atom& a)
{
std::string result;
result.reserve(11);
for (auto x = a.value(); x != 0; x >>= 6)
{
// decode 6 bit characters to ASCII
result += decoding_table[static_cast<size_t>(x & 0x3F)];
}
// result is reversed, since we read from right-to-left
return std::string(result.rbegin(), result.rend());
}
bool operator==(const atom& lhs, const atom& rhs)
template<atom_value AtomValue, typename... Types>
void foo()
{
return lhs.value() == rhs.value();
cout << "foo(" << static_cast<std::uint64_t>(AtomValue)
<< " = "
<< to_string(AtomValue)
<< ")"
<< endl;
}
bool operator!=(const atom& lhs, const atom& rhs)
size_t test__atom()
{
return !(lhs == rhs);
}
static constexpr atom s_a1 = "abc";
static constexpr atom s_a3 = atom::get<'a','b','c'>();
CPPA_TEST(test__atom);
static constexpr std::uint64_t s_foo = atom_val("abc");
self() << make_tuple(atom("foo"), static_cast<std::uint32_t>(42));
size_t test__atom()
{
receive(on<atom("foo"), std::uint32_t>() >> [&](std::uint32_t value) {
CPPA_CHECK_EQUAL(value, 42);
});
CPPA_TEST(test__atom);
/*
foo<static_cast<atom_value_type>(atom("abc").value()), int, float>();
cout << "a = " << get_atom_value<'a'>::_(0) << endl;
cout << "ab = " << get_atom_value<'a', 'b'>::_(0) << endl;
......@@ -145,12 +50,15 @@ size_t test__atom()
atom a1 = "cppa::exit";
cout << "a1 = " << to_string(a1) << endl;
atom a3 = atom::get<'a','b','c'>();
atom a3 = "abc";
cout << "to_string(a3) = " << to_string(a3) << endl;
cout << "s_a3 = " << to_string(s_a3) << endl;
cout << "a3.value() = " << a3.value() << endl;
cout << "s_a1.value() = " << s_a1.value() << endl;
cout << "s_foo = " << s_foo << endl;
*/
return CPPA_TEST_RESULT;
......
......@@ -87,10 +87,10 @@ size_t test__uniform_type()
"float", "double", // floating points
"@0", // cppa::util::void_type
// default announced cppa types
"@atom", // cppa::atom_value
"@*", // cppa::any_type
"@<>", // cppa::any_tuple
"@msg", // cppa::message
"@exit", // cppa::exit_signal
"@actor", // cppa::actor_ptr
"@group", // cppa::group_ptr
"@channel" // cppa::channel_ptr
......
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