Commit e0042862 authored by neverlord's avatar neverlord

atoms

parent e9fdcb8d
...@@ -145,8 +145,6 @@ cppa/any_tuple.hpp ...@@ -145,8 +145,6 @@ cppa/any_tuple.hpp
src/any_tuple.cpp src/any_tuple.cpp
cppa/util/abstract_uniform_type_info.hpp cppa/util/abstract_uniform_type_info.hpp
cppa/util/upgrade_lock_guard.hpp cppa/util/upgrade_lock_guard.hpp
cppa/exit_signal.hpp
src/exit_signal.cpp
cppa/to_string.hpp cppa/to_string.hpp
src/string_serialization.cpp src/string_serialization.cpp
cppa/from_string.hpp cppa/from_string.hpp
...@@ -173,3 +171,8 @@ cppa/detail/actor_proxy_cache.hpp ...@@ -173,3 +171,8 @@ cppa/detail/actor_proxy_cache.hpp
src/actor_proxy_cache.cpp src/actor_proxy_cache.cpp
src/attachable.cpp src/attachable.cpp
cppa/attachable.hpp cppa/attachable.hpp
cppa/atom.hpp
cppa/detail/atom_val.hpp
src/atom.cpp
src/cppa.cpp
cppa/exit_reason.hpp
#ifndef ACTOR_HPP #ifndef ACTOR_HPP
#define ACTOR_HPP #define ACTOR_HPP
#include <memory>
#include <cstdint> #include <cstdint>
#include <type_traits>
#include "cppa/group.hpp" #include "cppa/group.hpp"
#include "cppa/channel.hpp" #include "cppa/channel.hpp"
#include "cppa/attachable.hpp" #include "cppa/attachable.hpp"
#include "cppa/process_information.hpp" #include "cppa/process_information.hpp"
#include "cppa/util/enable_if.hpp"
namespace cppa { namespace cppa {
class serializer; class serializer;
...@@ -48,14 +52,25 @@ class actor : public channel ...@@ -48,14 +52,25 @@ class actor : public channel
virtual bool attach(attachable* ptr) = 0; 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 * @brief
...@@ -104,6 +119,15 @@ serializer& operator<<(serializer&, const actor_ptr&); ...@@ -104,6 +119,15 @@ serializer& operator<<(serializer&, const actor_ptr&);
deserializer& operator>>(deserializer&, 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 } // namespace cppa
#endif // ACTOR_HPP #endif // ACTOR_HPP
...@@ -18,6 +18,8 @@ class actor_proxy : public actor ...@@ -18,6 +18,8 @@ class actor_proxy : public actor
bool attach(attachable* ptr); bool attach(attachable* ptr);
void detach(const attachable::token&);
void enqueue(const message& msg); void enqueue(const message& msg);
void join(group_ptr& what); 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 @@ ...@@ -2,6 +2,7 @@
#define ATTACHABLE_HPP #define ATTACHABLE_HPP
#include <cstdint> #include <cstdint>
#include <typeinfo>
namespace cppa { namespace cppa {
...@@ -20,6 +21,16 @@ class attachable ...@@ -20,6 +21,16 @@ class attachable
public: 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(); virtual ~attachable();
/** /**
...@@ -30,6 +41,8 @@ class attachable ...@@ -30,6 +41,8 @@ class attachable
*/ */
virtual void detach(std::uint32_t reason); virtual void detach(std::uint32_t reason);
virtual bool matches(const token&);
}; };
} // namespace cppa } // namespace cppa
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
#define CONTEXT_HPP #define CONTEXT_HPP
#include "cppa/actor.hpp" #include "cppa/actor.hpp"
#include "cppa/exit_signal.hpp"
#include "cppa/message_queue.hpp" #include "cppa/message_queue.hpp"
namespace cppa { namespace cppa {
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <type_traits> #include <type_traits>
#include "cppa/on.hpp" #include "cppa/on.hpp"
#include "cppa/atom.hpp"
#include "cppa/tuple.hpp" #include "cppa/tuple.hpp"
#include "cppa/actor.hpp" #include "cppa/actor.hpp"
#include "cppa/invoke.hpp" #include "cppa/invoke.hpp"
...@@ -41,7 +42,7 @@ ...@@ -41,7 +42,7 @@
#include "cppa/context.hpp" #include "cppa/context.hpp"
#include "cppa/message.hpp" #include "cppa/message.hpp"
#include "cppa/scheduler.hpp" #include "cppa/scheduler.hpp"
#include "cppa/exit_signal.hpp" #include "cppa/exit_reason.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"
...@@ -159,6 +160,13 @@ send(intrusive_ptr<C>&& whom, const Arg0& arg0, const Args&... args) ...@@ -159,6 +160,13 @@ send(intrusive_ptr<C>&& whom, const Arg0& arg0, const Args&... args)
if (whom) whom->enqueue(message(self(), whom, arg0, 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> template<class C>
typename util::enable_if<std::is_base_of<channel, C>, intrusive_ptr<C>&>::type typename util::enable_if<std::is_base_of<channel, C>, intrusive_ptr<C>&>::type
operator<<(intrusive_ptr<C>& whom, const any_tuple& what) operator<<(intrusive_ptr<C>& whom, const any_tuple& what)
...@@ -191,6 +199,12 @@ operator<<(intrusive_ptr<C>&& whom, any_tuple&& what) ...@@ -191,6 +199,12 @@ operator<<(intrusive_ptr<C>&& whom, any_tuple&& what)
return std::move(whom); 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> template<typename Arg0, typename... Args>
void reply(const Arg0& arg0, const Args&... 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 @@ ...@@ -10,6 +10,7 @@
#include <memory> #include <memory>
#include "cppa/context.hpp" #include "cppa/context.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/detail/blocking_message_queue.hpp" #include "cppa/detail/blocking_message_queue.hpp"
namespace cppa { namespace detail { namespace cppa { namespace detail {
...@@ -26,9 +27,6 @@ class converted_thread_context : public context ...@@ -26,9 +27,6 @@ class converted_thread_context : public context
// guards access to m_exited, m_subscriptions and m_links // guards access to m_exited, m_subscriptions and m_links
std::mutex m_mtx; std::mutex m_mtx;
// manages group subscriptions
std::map<group_ptr, group::subscription> m_subscriptions;
// manages actor links // manages actor links
std::list<actor_ptr> m_links; std::list<actor_ptr> m_links;
...@@ -51,12 +49,10 @@ class converted_thread_context : public context ...@@ -51,12 +49,10 @@ class converted_thread_context : public context
bool attach /*[[override]]*/ (attachable* ptr); 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 quit /*[[override]]*/ (std::uint32_t reason);
void leave /*[[override]]*/ (const group_ptr& what);
void link_to /*[[override]]*/ (intrusive_ptr<actor>& other); void link_to /*[[override]]*/ (intrusive_ptr<actor>& other);
void unlink_from /*[[override]]*/ (intrusive_ptr<actor>& other); void unlink_from /*[[override]]*/ (intrusive_ptr<actor>& other);
......
...@@ -85,7 +85,15 @@ struct tdata_upcast_helper<0, Head, Tail...> ...@@ -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> template<size_t N, typename... Tn>
const typename util::at<N, Tn...>::type& get(const detail::tdata<Tn...>& tv) 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) ...@@ -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; return static_cast<typename detail::tdata_upcast_helper<N, Tn...>::type &>(tv).head;
} }
} // namespace cppa::detail } // namespace cppa
#endif // TDATA_HPP #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 @@ ...@@ -2,8 +2,10 @@
#define GROUP_HPP #define GROUP_HPP
#include <string> #include <string>
#include <memory>
#include "cppa/channel.hpp" #include "cppa/channel.hpp"
#include "cppa/attachable.hpp"
#include "cppa/ref_counted.hpp" #include "cppa/ref_counted.hpp"
namespace cppa { namespace cppa {
...@@ -24,33 +26,36 @@ class group : public channel ...@@ -24,33 +26,36 @@ class group : public channel
public: 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; channel_ptr m_self;
intrusive_ptr<group> m_group; intrusive_ptr<group> m_group;
subscription() = delete; unsubscriber() = delete;
subscription(const subscription&) = delete; unsubscriber(const unsubscriber&) = delete;
subscription& operator=(const subscription&) = delete; unsubscriber& operator=(const unsubscriber&) = delete;
public: public:
inline explicit operator bool() unsubscriber(const channel_ptr& s, const intrusive_ptr<group>& g);
{
return m_self != nullptr && m_group != nullptr; // matches on group
} bool matches(const attachable::token& what);
subscription(const channel_ptr& s, const intrusive_ptr<group>& g); virtual ~unsubscriber();
subscription(subscription&& other);
~subscription();
}; };
typedef std::unique_ptr<unsubscriber> subscription;
class module class module
{ {
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
namespace cppa { namespace cppa {
template<typename T> 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>> util::comparable<intrusive_ptr<T>>
{ {
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include <utility> #include <utility>
#include <stdexcept> #include <stdexcept>
#include "cppa/atom.hpp"
#include "cppa/any_type.hpp" #include "cppa/any_type.hpp"
#include "cppa/any_tuple.hpp" #include "cppa/any_tuple.hpp"
#include "cppa/tuple_view.hpp" #include "cppa/tuple_view.hpp"
...@@ -18,6 +19,7 @@ ...@@ -18,6 +19,7 @@
namespace cppa { namespace cppa {
// match types only; don't calculate view mapping
template<typename... MatchRules> template<typename... MatchRules>
bool match(const any_tuple& what) bool match(const any_tuple& what)
{ {
...@@ -26,6 +28,7 @@ bool match(const any_tuple& what) ...@@ -26,6 +28,7 @@ bool match(const any_tuple& what)
return detail::matcher<MatchRules...>::match(begin, end); return detail::matcher<MatchRules...>::match(begin, end);
} }
// match types only; calculate view mapping
template<typename... MatchRules> template<typename... MatchRules>
bool match(const any_tuple& what, std::vector<size_t>& mappings) 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) ...@@ -34,6 +37,7 @@ bool match(const any_tuple& what, std::vector<size_t>& mappings)
return detail::matcher<MatchRules...>::match(begin, end, &mappings); return detail::matcher<MatchRules...>::match(begin, end, &mappings);
} }
// match types and values; calculate view mapping
template<typename... MatchRules, class ValuesTuple> template<typename... MatchRules, class ValuesTuple>
bool match(const any_tuple& what, const ValuesTuple& vals, bool match(const any_tuple& what, const ValuesTuple& vals,
std::vector<size_t>& mappings) std::vector<size_t>& mappings)
...@@ -44,7 +48,8 @@ bool match(const any_tuple& what, const ValuesTuple& vals, ...@@ -44,7 +48,8 @@ bool match(const any_tuple& what, const ValuesTuple& vals,
typedef typename tuple_view_type_from_type_list<filtered_rules>::type typedef typename tuple_view_type_from_type_list<filtered_rules>::type
view_type; view_type;
static_assert(util::eval_type_lists<filtered_rules, static_assert(util::eval_type_lists<filtered_rules,
ValuesTuple, view_type,
//ValuesTuple,
util::is_comparable>::value, util::is_comparable>::value,
"given values are not comparable to matched types"); "given values are not comparable to matched types");
if (match<MatchRules...>(what, mappings)) if (match<MatchRules...>(what, mappings))
...@@ -56,6 +61,7 @@ bool match(const any_tuple& what, const ValuesTuple& vals, ...@@ -56,6 +61,7 @@ bool match(const any_tuple& what, const ValuesTuple& vals,
return false; return false;
} }
// match types and values; don't calculate view mapping
template<typename... MatchRules, class ValuesTuple> template<typename... MatchRules, class ValuesTuple>
bool match(const any_tuple& what, const ValuesTuple& vals) bool match(const any_tuple& what, const ValuesTuple& vals)
{ {
...@@ -63,6 +69,12 @@ 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); 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 } // namespace cppa
#endif // MATCH_HPP #endif // MATCH_HPP
#ifndef ON_HPP #ifndef ON_HPP
#define ON_HPP #define ON_HPP
#include "cppa/atom.hpp"
#include "cppa/match.hpp" #include "cppa/match.hpp"
#include "cppa/any_tuple.hpp" #include "cppa/any_tuple.hpp"
#include "cppa/invoke_rules.hpp" #include "cppa/invoke_rules.hpp"
...@@ -189,6 +190,24 @@ inline detail::invoke_rule_builder<Types...> on(const Arg0& arg0, ...@@ -189,6 +190,24 @@ inline detail::invoke_rule_builder<Types...> on(const Arg0& arg0,
return detail::invoke_rule_builder<Types...>(arg0, args...); 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 } // namespace cppa
#endif // ON_HPP #endif // ON_HPP
...@@ -55,4 +55,17 @@ const process_information& actor::parent_process() const ...@@ -55,4 +55,17 @@ const process_information& actor::parent_process() const
return process_information::get(); 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 } // namespace cppa
...@@ -25,6 +25,10 @@ bool actor_proxy::attach(attachable* ptr) ...@@ -25,6 +25,10 @@ bool actor_proxy::attach(attachable* ptr)
return false; return false;
} }
void actor_proxy::detach(const attachable::token&)
{
}
void actor_proxy::join(group_ptr& what) 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) ...@@ -10,4 +10,9 @@ void attachable::detach(std::uint32_t)
{ {
} }
bool attachable::matches(const attachable::token&)
{
return false;
}
} // namespace cppa::detail } // namespace cppa::detail
#include <vector> #include <vector>
#include "cppa/atom.hpp"
#include "cppa/match.hpp" #include "cppa/match.hpp"
#include "cppa/context.hpp" #include "cppa/context.hpp"
#include "cppa/exit_signal.hpp" #include "cppa/exit_reason.hpp"
#include "cppa/invoke_rules.hpp" #include "cppa/invoke_rules.hpp"
#include "cppa/util/singly_linked_list.hpp" #include "cppa/util/singly_linked_list.hpp"
...@@ -10,7 +11,7 @@ ...@@ -10,7 +11,7 @@
#include "cppa/detail/intermediate.hpp" #include "cppa/detail/intermediate.hpp"
#include "cppa/detail/blocking_message_queue.hpp" #include "cppa/detail/blocking_message_queue.hpp"
namespace { namespace cppa { namespace {
enum throw_on_exit_result enum throw_on_exit_result
{ {
...@@ -18,15 +19,12 @@ enum throw_on_exit_result ...@@ -18,15 +19,12 @@ enum throw_on_exit_result
normal_exit_signal 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 (match<atom(":Exit"), std::uint32_t>(msg.content()))
if (cppa::match<cppa::exit_signal>(msg.content(), mappings))
{ {
cppa::tuple_view<cppa::exit_signal> tview(msg.content().vals(), auto reason = *reinterpret_cast<const std::uint32_t*>(msg.content().at(1));
std::move(mappings)); if (reason != exit_reason::normal)
auto reason = cppa::get<0>(tview).reason();
if (reason != static_cast<std::uint32_t>(cppa::exit_reason::normal))
{ {
// throws // throws
cppa::self()->quit(reason); cppa::self()->quit(reason);
...@@ -39,7 +37,7 @@ throw_on_exit_result throw_on_exit(const cppa::message& msg) ...@@ -39,7 +37,7 @@ throw_on_exit_result throw_on_exit(const cppa::message& msg)
return not_an_exit_signal; return not_an_exit_signal;
} }
} // namespace <anonymous> } } // namespace cppa::<anonymous>
namespace cppa { namespace detail { namespace cppa { namespace detail {
......
#include <memory> #include <memory>
#include <algorithm> #include <algorithm>
#include "cppa/atom.hpp"
#include "cppa/exception.hpp" #include "cppa/exception.hpp"
#include "cppa/exit_signal.hpp"
#include "cppa/detail/converted_thread_context.hpp" #include "cppa/detail/converted_thread_context.hpp"
namespace { namespace {
...@@ -72,29 +72,39 @@ bool converted_thread_context::attach(attachable* ptr) ...@@ -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) void converted_thread_context::cleanup(std::uint32_t reason)
{ {
if (reason == exit_reason::not_exited) return; if (reason == exit_reason::not_exited) return;
decltype(m_links) mlinks; decltype(m_links) mlinks;
decltype(m_subscriptions) msubscriptions;
decltype(m_attachables) mattachables; decltype(m_attachables) mattachables;
// lifetime scope of guard // lifetime scope of guard
{ {
std::lock_guard<std::mutex> guard(m_mtx); std::lock_guard<std::mutex> guard(m_mtx);
m_exit_reason = reason; m_exit_reason = reason;
mlinks = std::move(m_links); mlinks = std::move(m_links);
msubscriptions = std::move(m_subscriptions);
mattachables = std::move(m_attachables); mattachables = std::move(m_attachables);
// make sure lists are definitely empty // make sure lists are definitely empty
m_links.clear(); m_links.clear();
m_subscriptions.clear();
m_attachables.clear(); m_attachables.clear();
} }
actor_ptr mself = self(); actor_ptr mself = self();
// send exit messages // send exit messages
for (actor_ptr& aptr : mlinks) 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) for (std::unique_ptr<attachable>& ptr : mattachables)
{ {
...@@ -165,24 +175,6 @@ void converted_thread_context::unlink_from(intrusive_ptr<actor>& other) ...@@ -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() message_queue& converted_thread_context::mailbox()
{ {
return m_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 ...@@ -51,15 +51,13 @@ class local_group : public group
virtual group::subscription subscribe(const channel_ptr& who) virtual group::subscription subscribe(const channel_ptr& who)
{ {
group::subscription result;
exclusive_guard guard(m_mtx); exclusive_guard guard(m_mtx);
if (m_subscribers.insert(who).second) if (m_subscribers.insert(who).second)
{ {
return { who, this }; result.reset(new group::unsubscriber(who, this));
}
else
{
return { nullptr, nullptr };
} }
return result;
} }
virtual void unsubscribe(const channel_ptr& who) virtual void unsubscribe(const channel_ptr& who)
...@@ -171,20 +169,24 @@ void group::add_module(group::module* ptr) ...@@ -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) const intrusive_ptr<group>& g)
: m_self(s), m_group(g) : m_self(s), m_group(g)
{ {
} }
group::subscription::subscription(group::subscription&& other) group::unsubscriber::~unsubscriber()
: m_self(std::move(other.m_self)), m_group(std::move(other.m_group))
{ {
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) group::group(std::string&& id, std::string&& mod_name)
......
...@@ -6,13 +6,13 @@ ...@@ -6,13 +6,13 @@
#include <stdexcept> #include <stdexcept>
#include <algorithm> #include <algorithm>
#include "cppa/atom.hpp"
#include "cppa/actor.hpp" #include "cppa/actor.hpp"
#include "cppa/group.hpp" #include "cppa/group.hpp"
#include "cppa/channel.hpp" #include "cppa/channel.hpp"
#include "cppa/message.hpp" #include "cppa/message.hpp"
#include "cppa/any_type.hpp" #include "cppa/any_type.hpp"
#include "cppa/any_tuple.hpp" #include "cppa/any_tuple.hpp"
#include "cppa/exit_signal.hpp"
#include "cppa/util/void_type.hpp" #include "cppa/util/void_type.hpp"
...@@ -90,9 +90,9 @@ std::string to_uniform_name_impl(Iterator begin, Iterator end, ...@@ -90,9 +90,9 @@ std::string to_uniform_name_impl(Iterator begin, Iterator end,
{ demangled<std::u32string>(), "@u32str" }, { demangled<std::u32string>(), "@u32str" },
// cppa types // cppa types
{ demangled<cppa::any_type>(), "@*" }, { demangled<cppa::any_type>(), "@*" },
{ demangled<cppa::atom_value>(), "@atom" },
{ demangled<cppa::util::void_type>(), "@0" }, { demangled<cppa::util::void_type>(), "@0" },
{ demangled<cppa::any_tuple>(), "@<>" }, { demangled<cppa::any_tuple>(), "@<>" },
{ demangled<cppa::exit_signal>(), "@exit" },
{ demangled<cppa::actor_ptr>(), "@actor" }, { demangled<cppa::actor_ptr>(), "@actor" },
{ demangled<cppa::group_ptr>(), "@group" }, { demangled<cppa::group_ptr>(), "@group" },
{ demangled<cppa::channel_ptr>(), "@channel" }, { demangled<cppa::channel_ptr>(), "@channel" },
......
...@@ -14,9 +14,11 @@ ...@@ -14,9 +14,11 @@
#include <boost/thread.hpp> #include <boost/thread.hpp>
#include "cppa/cppa.hpp" #include "cppa/cppa.hpp"
#include "cppa/atom.hpp"
#include "cppa/match.hpp" #include "cppa/match.hpp"
#include "cppa/to_string.hpp" #include "cppa/to_string.hpp"
#include "cppa/exception.hpp" #include "cppa/exception.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/binary_serializer.hpp" #include "cppa/binary_serializer.hpp"
#include "cppa/binary_deserializer.hpp" #include "cppa/binary_deserializer.hpp"
#include "cppa/util/single_reader_queue.hpp" #include "cppa/util/single_reader_queue.hpp"
...@@ -202,7 +204,7 @@ void fake_exits_from_disconnected_links(link_map& links) ...@@ -202,7 +204,7 @@ void fake_exits_from_disconnected_links(link_map& links)
for (auto& rem_actor : remote_actors) for (auto& rem_actor : remote_actors)
{ {
message msg(rem_actor, local_actor, message msg(rem_actor, local_actor,
exit_signal(exit_reason::remote_link_unreachable)); atom(":Exit"), exit_reason::remote_link_unreachable);
local_actor->enqueue(msg); local_actor->enqueue(msg);
} }
} }
...@@ -250,7 +252,7 @@ void mailman_loop() ...@@ -250,7 +252,7 @@ void mailman_loop()
mailman_send_job& sjob = job->send_job(); mailman_send_job& sjob = job->send_job();
// keep track about link states of local actors // keep track about link states of local actors
// (remove link states between local and remote actors if needed) // (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(); auto sender = sjob.original_message.sender();
if (pself == sender->parent_process()) if (pself == sender->parent_process())
......
#include "cppa/config.hpp"
#include <map> #include <map>
#include <set> #include <set>
#include <locale> #include <locale>
...@@ -9,15 +11,13 @@ ...@@ -9,15 +11,13 @@
#include <iostream> #include <iostream>
#include <type_traits> #include <type_traits>
#include "cppa/config.hpp" #include "cppa/atom.hpp"
#include "cppa/actor.hpp" #include "cppa/actor.hpp"
#include "cppa/object.hpp" #include "cppa/object.hpp"
#include "cppa/message.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"
#include "cppa/exit_signal.hpp"
#include "cppa/intrusive_ptr.hpp" #include "cppa/intrusive_ptr.hpp"
#include "cppa/uniform_type_info.hpp" #include "cppa/uniform_type_info.hpp"
...@@ -485,6 +485,32 @@ class message_tinfo : public util::abstract_uniform_type_info<message> ...@@ -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 class uniform_type_info_map
{ {
...@@ -528,15 +554,12 @@ class uniform_type_info_map ...@@ -528,15 +554,12 @@ 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_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 any_tuple_tinfo, { raw_name<any_tuple>() });
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(new message_tinfo, { raw_name<message>() });
insert(new atom_value_tinfo, { raw_name<atom_value>() });
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))
......
...@@ -6,134 +6,39 @@ ...@@ -6,134 +6,39 @@
#include "hash_of.hpp" #include "hash_of.hpp"
#include "cppa/util.hpp" #include "cppa/util.hpp"
#include "cppa/cppa.hpp"
using std::cout; using std::cout;
using std::endl; using std::endl;
using namespace cppa; using namespace cppa;
using namespace cppa::util; using namespace cppa::util;
namespace { static constexpr auto s_foo = atom("abc");
// 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) { }
public: template<atom_value AtomValue, typename... Types>
void foo()
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)
{ {
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"; CPPA_TEST(test__atom);
static constexpr atom s_a3 = atom::get<'a','b','c'>();
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 << "a = " << get_atom_value<'a'>::_(0) << endl;
cout << "ab = " << get_atom_value<'a', 'b'>::_(0) << endl; cout << "ab = " << get_atom_value<'a', 'b'>::_(0) << endl;
...@@ -145,12 +50,15 @@ size_t test__atom() ...@@ -145,12 +50,15 @@ size_t test__atom()
atom a1 = "cppa::exit"; atom a1 = "cppa::exit";
cout << "a1 = " << to_string(a1) << endl; 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 << "to_string(a3) = " << to_string(a3) << endl;
cout << "s_a3 = " << to_string(s_a3) << endl;
cout << "a3.value() = " << a3.value() << endl; cout << "a3.value() = " << a3.value() << endl;
cout << "s_a1.value() = " << s_a1.value() << endl; cout << "s_a1.value() = " << s_a1.value() << endl;
cout << "s_foo = " << s_foo << endl; cout << "s_foo = " << s_foo << endl;
*/
return CPPA_TEST_RESULT; return CPPA_TEST_RESULT;
......
...@@ -87,10 +87,10 @@ size_t test__uniform_type() ...@@ -87,10 +87,10 @@ 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
"@atom", // cppa::atom_value
"@*", // cppa::any_type "@*", // cppa::any_type
"@<>", // cppa::any_tuple "@<>", // cppa::any_tuple
"@msg", // cppa::message "@msg", // cppa::message
"@exit", // cppa::exit_signal
"@actor", // cppa::actor_ptr "@actor", // cppa::actor_ptr
"@group", // cppa::group_ptr "@group", // cppa::group_ptr
"@channel" // cppa::channel_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