Commit e3a18cba authored by neverlord's avatar neverlord

minor bugfix and documentation

parent 828669b0
...@@ -88,6 +88,7 @@ nobase_library_include_HEADERS = \ ...@@ -88,6 +88,7 @@ nobase_library_include_HEADERS = \
cppa/cow_ptr.hpp \ cppa/cow_ptr.hpp \
cppa/cppa.hpp \ cppa/cppa.hpp \
cppa/deserializer.hpp \ cppa/deserializer.hpp \
cppa/either.hpp \
cppa/event_based_actor.hpp \ cppa/event_based_actor.hpp \
cppa/event_based_actor_base.hpp \ cppa/event_based_actor_base.hpp \
cppa/abstract_event_based_actor.hpp \ cppa/abstract_event_based_actor.hpp \
...@@ -179,7 +180,6 @@ nobase_library_include_HEADERS = \ ...@@ -179,7 +180,6 @@ nobase_library_include_HEADERS = \
cppa/util/disable_if.hpp \ cppa/util/disable_if.hpp \
cppa/util/disjunction.hpp \ cppa/util/disjunction.hpp \
cppa/util/duration.hpp \ cppa/util/duration.hpp \
cppa/util/either.hpp \
cppa/util/element_at.hpp \ cppa/util/element_at.hpp \
cppa/util/enable_if.hpp \ cppa/util/enable_if.hpp \
cppa/util/fiber.hpp \ cppa/util/fiber.hpp \
......
...@@ -215,7 +215,7 @@ examples/hello_world_example.cpp ...@@ -215,7 +215,7 @@ examples/hello_world_example.cpp
examples/math_actor_example.cpp examples/math_actor_example.cpp
cppa/detail/yielding_actor.hpp cppa/detail/yielding_actor.hpp
src/yielding_actor.cpp src/yielding_actor.cpp
cppa/util/either.hpp cppa/either.hpp
cppa/abstract_event_based_actor.hpp cppa/abstract_event_based_actor.hpp
src/abstract_event_based_actor.cpp src/abstract_event_based_actor.cpp
cppa/event_based_actor.hpp cppa/event_based_actor.hpp
...@@ -261,3 +261,4 @@ benchmarks/theron_actor_creation.cpp ...@@ -261,3 +261,4 @@ benchmarks/theron_actor_creation.cpp
benchmarks/theron_mixed_case.cpp benchmarks/theron_mixed_case.cpp
cppa/util/static_foreach.hpp cppa/util/static_foreach.hpp
cppa/type_value_pair.hpp cppa/type_value_pair.hpp
examples/dining_hakkers.cpp
...@@ -71,113 +71,32 @@ class abstract_actor : public Base ...@@ -71,113 +71,32 @@ class abstract_actor : public Base
public: public:
class queue_node_ptr; class queue_node_ptr;
struct queue_node_deallocator;
struct queue_node struct queue_node
{ {
friend class abstract_actor; friend class abstract_actor;
friend class queue_node_ptr; friend class queue_node_ptr;
friend struct queue_node_deallocator;
queue_node* next; queue_node* next;
std::atomic<queue_node*>* owner;
actor_ptr sender; actor_ptr sender;
any_tuple msg; any_tuple msg;
private: // you have to be a friend to create or destroy a node queue_node() : next(nullptr) { }
inline ~queue_node() { }
queue_node() : next(nullptr), owner(nullptr) { }
queue_node(actor* from, any_tuple&& content) queue_node(actor* from, any_tuple&& content)
: next(nullptr), owner(nullptr), sender(from), msg(std::move(content)) : next(nullptr), sender(from), msg(std::move(content))
{ {
} }
queue_node(actor* from, any_tuple const& content) queue_node(actor* from, any_tuple const& content)
: next(nullptr), owner(nullptr), sender(from), msg(content) : next(nullptr), sender(from), msg(content)
{
}
};
struct queue_node_deallocator
{
inline void operator()(queue_node* ptr)
{
if (ptr)
{
if (ptr->owner != nullptr)
{
ptr->sender.reset();
ptr->msg = any_tuple();
auto owner = ptr->owner;
ptr->next = owner->load();
for (;;)
{
if (owner->compare_exchange_weak(ptr->next, ptr)) return;
}
}
else
{ {
delete ptr;
}
}
} }
}; };
class queue_node_ptr typedef std::unique_ptr<queue_node> queue_node_ptr;
{
queue_node* m_ptr;
queue_node_deallocator d;
queue_node_ptr(queue_node_ptr const&) = delete;
queue_node_ptr& operator=(queue_node_ptr const&) = delete;
public:
inline queue_node_ptr(queue_node* ptr = nullptr) : m_ptr(ptr)
{
}
inline queue_node_ptr(queue_node_ptr&& other) : m_ptr(other.m_ptr)
{
other.m_ptr = nullptr;
}
inline ~queue_node_ptr()
{
d(m_ptr);
}
inline queue_node* operator->() { return m_ptr; }
inline queue_node* release()
{
auto result = m_ptr;
m_ptr = nullptr;
return result;
}
inline void reset(queue_node* ptr = nullptr)
{
d(m_ptr);
m_ptr = ptr;
}
inline queue_node_ptr& operator=(queue_node_ptr&& other)
{
reset(other.release());
return *this;
}
inline operator bool() const { return m_ptr != nullptr; }
};
protected: protected:
queue_node m_prefetched_nodes[10]; util::single_reader_queue<queue_node> m_mailbox;
std::atomic<queue_node*> m_prefetched;
util::single_reader_queue<queue_node,queue_node_deallocator> m_mailbox;
private: private:
...@@ -220,20 +139,8 @@ class abstract_actor : public Base ...@@ -220,20 +139,8 @@ class abstract_actor : public Base
protected: protected:
template<typename T> template<typename T>
queue_node* fetch_node(actor* sender, T&& msg) inline queue_node* fetch_node(actor* sender, T&& msg)
{ {
queue_node* result = m_prefetched.load();
while (result)
{
queue_node* next = result->next;
if (m_prefetched.compare_exchange_weak(result, next))
{
result->next = nullptr;
result->sender.reset(sender);
result->msg = std::forward<T>(msg);
return result;
}
}
return new queue_node(sender, std::forward<T>(msg)); return new queue_node(sender, std::forward<T>(msg));
} }
...@@ -241,13 +148,6 @@ class abstract_actor : public Base ...@@ -241,13 +148,6 @@ class abstract_actor : public Base
abstract_actor(Args&&... args) : Base(std::forward<Args>(args)...) abstract_actor(Args&&... args) : Base(std::forward<Args>(args)...)
, m_exit_reason(exit_reason::not_exited) , m_exit_reason(exit_reason::not_exited)
{ {
for (int i = 0; i < 9; ++i)
{
m_prefetched_nodes[i].next = &(m_prefetched_nodes[i+1]);
m_prefetched_nodes[i].owner = &m_prefetched;
}
m_prefetched_nodes[9].owner = &m_prefetched;
m_prefetched.store(m_prefetched_nodes);
} }
void cleanup(std::uint32_t reason) void cleanup(std::uint32_t reason)
......
...@@ -35,9 +35,10 @@ ...@@ -35,9 +35,10 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
#include "cppa/config.hpp"
#include "cppa/either.hpp"
#include "cppa/pattern.hpp" #include "cppa/pattern.hpp"
#include "cppa/invoke_rules.hpp" #include "cppa/invoke_rules.hpp"
#include "cppa/util/either.hpp"
#include "cppa/detail/abstract_scheduled_actor.hpp" #include "cppa/detail/abstract_scheduled_actor.hpp"
namespace cppa { namespace cppa {
...@@ -101,7 +102,7 @@ class abstract_event_based_actor : public detail::abstract_scheduled_actor ...@@ -101,7 +102,7 @@ class abstract_event_based_actor : public detail::abstract_scheduled_actor
stack_element(stack_element const&) = delete; stack_element(stack_element const&) = delete;
stack_element& operator=(stack_element const&) = delete; stack_element& operator=(stack_element const&) = delete;
util::either<invoke_rules*, timed_invoke_rules*> m_ptr; either<invoke_rules*, timed_invoke_rules*> m_ptr;
bool m_ownership; bool m_ownership;
inline stack_element(invoke_rules* ptr, bool take_ownership) inline stack_element(invoke_rules* ptr, bool take_ownership)
...@@ -142,30 +143,24 @@ class abstract_event_based_actor : public detail::abstract_scheduled_actor ...@@ -142,30 +143,24 @@ class abstract_event_based_actor : public detail::abstract_scheduled_actor
} }
} }
} }
inline bool is_left() inline bool is_left() { return m_ptr.is_left(); }
{ inline bool is_right() { return m_ptr.is_right(); }
return m_ptr.is_left();
}
inline bool is_right()
{
return m_ptr.is_right();
}
inline invoke_rules& left() inline invoke_rules& left()
{ {
auto ptr = m_ptr.left(); auto ptr = m_ptr.left();
if (ptr == nullptr) throw std::runtime_error("nullptr"); CPPA_REQUIRE(ptr != nullptr);
return *(ptr); return *(ptr);
} }
inline timed_invoke_rules& right() inline timed_invoke_rules& right()
{ {
auto ptr = m_ptr.right(); auto ptr = m_ptr.right();
if (ptr == nullptr) throw std::runtime_error("nullptr"); CPPA_REQUIRE(ptr != nullptr);
return *(ptr); return *(ptr);
} }
}; };
queue_node_buffer m_buffer; queue_node_buffer m_buffer;
std::stack<stack_element, std::vector<stack_element> > m_loop_stack; std::vector<stack_element> m_loop_stack;
// provoke compiler errors for usage of receive() and related functions // provoke compiler errors for usage of receive() and related functions
......
...@@ -52,14 +52,11 @@ class any_tuple ...@@ -52,14 +52,11 @@ class any_tuple
/** /**
* @brief Creates an empty tuple. * @brief Creates an empty tuple.
* @post <tt>empty() == true</tt>
*/ */
any_tuple(); any_tuple();
/** /**
* @brief Creates a tuple from @p t. * @brief Creates a tuple from @p t.
* @param t A typed tuple representation.
* @post <tt>empty() == false</tt>
*/ */
template<typename... Args> template<typename... Args>
any_tuple(tuple<Args...> const& t) : m_vals(t.vals()) { } any_tuple(tuple<Args...> const& t) : m_vals(t.vals()) { }
...@@ -78,13 +75,11 @@ class any_tuple ...@@ -78,13 +75,11 @@ class any_tuple
/** /**
* @brief Move assignment. * @brief Move assignment.
* @returns <tt>*this</tt>.
*/ */
any_tuple& operator=(any_tuple&&); any_tuple& operator=(any_tuple&&);
/** /**
* @brief Copy assignment. * @brief Copy assignment.
* @returns <tt>*this</tt>.
*/ */
any_tuple& operator=(any_tuple const&) = default; any_tuple& operator=(any_tuple const&) = default;
......
...@@ -52,7 +52,7 @@ namespace cppa { ...@@ -52,7 +52,7 @@ namespace cppa {
class any_tuple_view class any_tuple_view
{ {
typedef std::vector< std::pair<uniform_type_info const*, void const*> > typedef std::vector< std::pair<uniform_type_info const*, void*> >
vector_type; vector_type;
vector_type m_values; vector_type m_values;
...@@ -86,6 +86,7 @@ class any_tuple_view ...@@ -86,6 +86,7 @@ class any_tuple_view
} }
} }
/*
template<typename... T> template<typename... T>
explicit any_tuple_view(tuple<T...> const& tup) explicit any_tuple_view(tuple<T...> const& tup)
{ {
...@@ -94,6 +95,7 @@ class any_tuple_view ...@@ -94,6 +95,7 @@ class any_tuple_view
m_values.push_back(std::make_pair(tup.type_at(i), tup.at(i))); m_values.push_back(std::make_pair(tup.type_at(i), tup.at(i)));
} }
} }
*/
template<typename... T> template<typename... T>
any_tuple_view(tuple_view<T...> const& tup) any_tuple_view(tuple_view<T...> const& tup)
...@@ -113,16 +115,16 @@ class any_tuple_view ...@@ -113,16 +115,16 @@ class any_tuple_view
} }
template<typename T> template<typename T>
any_tuple_view(std::set<T> const& vec) { from_list(vec); } any_tuple_view(std::set<T>& vec) { from_list(vec); }
template<typename T> template<typename T>
any_tuple_view(std::list<T> const& vec) { from_list(vec); } any_tuple_view(std::list<T>& vec) { from_list(vec); }
template<typename T> template<typename T>
any_tuple_view(std::vector<T> const& vec) { from_list(vec); } any_tuple_view(std::vector<T>& vec) { from_list(vec); }
template<typename T> template<typename T>
any_tuple_view(T const& val, any_tuple_view(T& val,
typename util::enable_if<util::is_primitive<T> >::type* = 0) typename util::enable_if<util::is_primitive<T> >::type* = 0)
{ {
auto& arr = detail::static_types_array<T>::arr; auto& arr = detail::static_types_array<T>::arr;
...@@ -135,6 +137,8 @@ class any_tuple_view ...@@ -135,6 +137,8 @@ class any_tuple_view
inline void const* at(size_t p) const { return m_values[p].second; } inline void const* at(size_t p) const { return m_values[p].second; }
void* mutable_at(size_t p) { return m_values[p].second; }
inline uniform_type_info const* type_at(size_t p) const inline uniform_type_info const* type_at(size_t p) const
{ {
return m_values[p].first; return m_values[p].first;
......
...@@ -31,12 +31,15 @@ ...@@ -31,12 +31,15 @@
#ifndef BEHAVIOR_HPP #ifndef BEHAVIOR_HPP
#define BEHAVIOR_HPP #define BEHAVIOR_HPP
#include "cppa/util/either.hpp" #include "cppa/either.hpp"
#include "cppa/invoke_rules.hpp" #include "cppa/invoke_rules.hpp"
namespace cppa { namespace cppa {
typedef util::either<invoke_rules, timed_invoke_rules> behavior; /**
* @brief
*/
typedef either<invoke_rules, timed_invoke_rules> behavior;
} // namespace cppa } // namespace cppa
......
...@@ -66,4 +66,16 @@ ...@@ -66,4 +66,16 @@
# error Plattform and/or compiler not supportet # error Plattform and/or compiler not supportet
#endif #endif
#ifdef CPPA_DEBUG
#include <cstdlib>
#define CPPA_REQUIRE__(stmt, file, line) \
printf("%s:%u: requirement failed '%s'\n", file, line, stmt); abort()
#define CPPA_REQUIRE(stmt) \
if ((stmt) == false) { \
CPPA_REQUIRE__(#stmt, __FILE__, __LINE__); \
}((void) 0)
#else // CPPA_DEBUG
#define CPPA_REQUIRE(unused) ((void) 0)
#endif // CPPA_DEBUG
#endif // CPPA_CONFIG_HPP #endif // CPPA_CONFIG_HPP
...@@ -524,12 +524,19 @@ void send(intrusive_ptr<C>&& whom, Arg0 const& arg0, Args const&... args) ...@@ -524,12 +524,19 @@ void send(intrusive_ptr<C>&& whom, Arg0 const& arg0, Args const&... args)
if (tmp) tmp->enqueue(self, make_tuple(arg0, args...)); if (tmp) tmp->enqueue(self, make_tuple(arg0, args...));
} }
// matches "send(this, ...)" in event-based actors
template<typename Arg0, typename... Args>
void send(local_actor* whom, Arg0 const& arg0, Args const&... args)
{
whom->enqueue(whom, make_tuple(arg0, args...));
}
// matches send(self, ...); // matches send(self, ...);
template<typename Arg0, typename... Args> template<typename Arg0, typename... Args>
void send(self_type const&, Arg0 const& arg0, Args const&... args) inline void send(self_type const&, Arg0 const& arg0, Args const&... args)
{ {
local_actor* s = self; send(static_cast<local_actor*>(self), arg0, args...);
s->enqueue(s, make_tuple(arg0, args...));
} }
template<class C> template<class C>
......
...@@ -45,9 +45,7 @@ namespace cppa { namespace detail { ...@@ -45,9 +45,7 @@ namespace cppa { namespace detail {
class task_scheduler; class task_scheduler;
/** // A spawned, scheduled Actor.
* @brief A spawned, scheduled Actor.
*/
class abstract_scheduled_actor : public abstract_actor<local_actor> class abstract_scheduled_actor : public abstract_actor<local_actor>
{ {
...@@ -65,7 +63,7 @@ class abstract_scheduled_actor : public abstract_actor<local_actor> ...@@ -65,7 +63,7 @@ class abstract_scheduled_actor : public abstract_actor<local_actor>
typedef abstract_actor super; typedef abstract_actor super;
typedef super::queue_node queue_node; typedef super::queue_node queue_node;
typedef util::singly_linked_list<queue_node,super::queue_node_deallocator> typedef util::singly_linked_list<queue_node>
queue_node_buffer; queue_node_buffer;
enum dq_result enum dq_result
......
...@@ -43,12 +43,11 @@ ...@@ -43,12 +43,11 @@
#include <cstdint> #include <cstdint>
#include "cppa/atom.hpp" #include "cppa/atom.hpp"
#include "cppa/either.hpp"
#include "cppa/pattern.hpp" #include "cppa/pattern.hpp"
#include "cppa/local_actor.hpp" #include "cppa/local_actor.hpp"
#include "cppa/exit_reason.hpp" #include "cppa/exit_reason.hpp"
#include "cppa/abstract_actor.hpp" #include "cppa/abstract_actor.hpp"
#include "cppa/util/either.hpp"
#include "cppa/util/singly_linked_list.hpp" #include "cppa/util/singly_linked_list.hpp"
namespace cppa { namespace detail { namespace cppa { namespace detail {
...@@ -87,7 +86,7 @@ class converted_thread_context : public abstract_actor<local_actor> ...@@ -87,7 +86,7 @@ class converted_thread_context : public abstract_actor<local_actor>
private: private:
typedef util::singly_linked_list<queue_node,super::queue_node_deallocator> typedef util::singly_linked_list<queue_node>
queue_node_buffer; queue_node_buffer;
enum throw_on_exit_result enum throw_on_exit_result
......
...@@ -49,6 +49,8 @@ class group_manager ...@@ -49,6 +49,8 @@ class group_manager
intrusive_ptr<group> get(std::string const& module_name, intrusive_ptr<group> get(std::string const& module_name,
std::string const& group_identifier); std::string const& group_identifier);
intrusive_ptr<group> anonymous();
void add_module(group::module*); void add_module(group::module*);
private: private:
......
...@@ -67,9 +67,8 @@ struct implicit_conversions ...@@ -67,9 +67,8 @@ struct implicit_conversions
subtype3; subtype3;
typedef typename util::replace_type<subtype3, actor_ptr, typedef typename util::replace_type<subtype3, actor_ptr,
std::is_same<actor*,T>, std::is_convertible<T, actor*>,
std::is_same<local_actor*,T>, std::is_convertible<T, local_actor*>,
std::is_same<self_type,T>,
std::is_same<self_type,T>>::type std::is_same<self_type,T>>::type
type; type;
......
...@@ -37,13 +37,13 @@ ...@@ -37,13 +37,13 @@
#include <stack> #include <stack>
#include "cppa/either.hpp"
#include "cppa/pattern.hpp" #include "cppa/pattern.hpp"
#include "cppa/detail/delegate.hpp" #include "cppa/detail/delegate.hpp"
#include "cppa/detail/abstract_scheduled_actor.hpp"
#include "cppa/detail/yield_interface.hpp" #include "cppa/detail/yield_interface.hpp"
#include "cppa/detail/abstract_scheduled_actor.hpp"
#include "cppa/util/either.hpp"
#include "cppa/util/singly_linked_list.hpp" #include "cppa/util/singly_linked_list.hpp"
namespace cppa { namespace detail { namespace cppa { namespace detail {
......
...@@ -32,283 +32,251 @@ ...@@ -32,283 +32,251 @@
#define EITHER_HPP #define EITHER_HPP
#include <new> #include <new>
#include <stdexcept> #include <utility>
#include <type_traits> #include <type_traits>
#include "cppa/config.hpp"
namespace cppa { namespace util { namespace cppa {
/**
* @brief Represents either a @p Left or a @p Right.
*/
template<class Left, class Right> template<class Left, class Right>
class either class either
{ {
static_assert(std::is_same<Left, Right>::value == false, "Left == Right"); static_assert( std::is_convertible<Left, Right>::value == false
&& std::is_convertible<Right, Left>::value == false,
union "Left is not allowed to be convertible to Right");
{
Left m_left;
Right m_right;
};
bool m_is_left;
void check_flag(bool flag, char const* side) const
{
if (m_is_left != flag)
{
std::string err = "not a ";
err += side;
throw std::runtime_error(err);
}
}
void destroy()
{
if (m_is_left)
{
m_left.~Left();
}
else
{
m_right.~Right();
}
}
template<typename L>
void cr_left(L&& value)
{
new (&m_left) Left (std::forward<L>(value));
}
template<typename R>
void cr_right(R&& value)
{
new (&m_right) Right (std::forward<R>(value));
}
public: public:
// default constructor creates a left /**
either() : m_is_left(true) * @brief Default constructor, creates a @p Left.
{ */
new (&m_left) Left (); either() : m_is_left(true) { new (&m_left) Left (); }
}
/**
either(Left const& value) : m_is_left(true) * @brief Creates a @p Left from @p value.
{ */
cr_left(value); either(Left const& value) : m_is_left(true) { cr_left(value); }
}
/**
either(Left&& value) : m_is_left(true) * @brief Creates a @p Left from @p value.
{ */
cr_left(std::move(value)); either(Left&& value) : m_is_left(true) { cr_left(std::move(value)); }
}
/**
either(Right const& value) : m_is_left(false) * @brief Creates a @p Right from @p value.
{ */
cr_right(value); either(Right const& value) : m_is_left(false) { cr_right(value); }
}
/**
either(Right&& value) : m_is_left(false) * @brief Creates a @p Right from @p value.
{ */
cr_right(std::move(value)); either(Right&& value) : m_is_left(false) { cr_right(std::move(value)); }
}
/**
* @brief Copy constructor.
*/
either(either const& other) : m_is_left(other.m_is_left) either(either const& other) : m_is_left(other.m_is_left)
{ {
if (other.m_is_left) if (other.m_is_left) cr_left(other.m_left);
{ else cr_right(other.m_right);
cr_left(other.m_left);
}
else
{
cr_right(other.m_right);
}
} }
/**
* @brief Move constructor.
*/
either(either&& other) : m_is_left(other.m_is_left) either(either&& other) : m_is_left(other.m_is_left)
{ {
if (other.m_is_left) if (other.m_is_left) cr_left(std::move(other.m_left));
{ else cr_right(std::move(other.m_right));
cr_left(std::move(other.m_left));
}
else
{
cr_right(std::move(other.m_right));
}
} }
~either() ~either() { destroy(); }
{
destroy();
}
/**
* @brief Copy assignment.
*/
either& operator=(either const& other) either& operator=(either const& other)
{ {
if (m_is_left == other.m_is_left) if (m_is_left == other.m_is_left)
{ {
if (m_is_left) if (m_is_left) m_left = other.m_left;
{ else m_right = other.m_right;
m_left = other.m_left;
}
else
{
m_right = other.m_right;
}
} }
else else
{ {
destroy(); destroy();
m_is_left = other.m_is_left; m_is_left = other.m_is_left;
if (other.m_is_left) if (other.m_is_left) cr_left(other.m_left);
{ else cr_right(other.m_right);
cr_left(other.m_left);
}
else
{
cr_right(other.m_right);
}
} }
return *this; return *this;
} }
/**
* @brief Move assignment.
*/
either& operator=(either&& other) either& operator=(either&& other)
{ {
if (m_is_left == other.m_is_left) if (m_is_left == other.m_is_left)
{ {
if (m_is_left) if (m_is_left) m_left = std::move(other.m_left);
{ else m_right = std::move(other.m_right);
m_left = std::move(other.m_left);
}
else
{
m_right = std::move(other.m_right);
}
} }
else else
{ {
destroy(); destroy();
m_is_left = other.m_is_left; m_is_left = other.m_is_left;
if (other.m_is_left) if (other.m_is_left) cr_left(std::move(other.m_left));
{ else cr_right(std::move(other.m_right));
cr_left(std::move(other.m_left));
}
else
{
cr_right(std::move(other.m_right));
}
} }
return *this; return *this;
} }
inline bool is_left() const /**
{ * @brief Returns @p true if this is a @p Left; otherwise @p false.
return m_is_left; */
} inline bool is_left() const { return m_is_left; }
inline bool is_right() const /**
{ * @brief Returns @p true if this is a @p Left; otherwise @p false.
return !m_is_left; */
} inline bool is_right() const { return !m_is_left; }
Left& left() /**
* @brief Returns this @p either as a @p Left.
*/
inline Left& left()
{ {
//check_flag(true, "left"); CPPA_REQUIRE(m_is_left);
return m_left; return m_left;
} }
Left const& left() const /**
* @brief Returns this @p either as a @p Left.
*/
inline Left const& left() const
{ {
//check_flag(true, "left"); CPPA_REQUIRE(m_is_left);
return m_left; return m_left;
} }
Right& right() /**
* @brief Returns this @p either as a @p Right.
*/
inline Right& right()
{ {
//check_flag(false, "right"); CPPA_REQUIRE(!m_is_left);
return m_right; return m_right;
} }
Right const& right() const /**
* @brief Returns this @p either as a @p Right.
*/
inline Right const& right() const
{ {
//check_flag(false, "right"); CPPA_REQUIRE(!m_is_left);
return m_right; return m_right;
} }
}; private:
template<typename Left, typename Right> bool m_is_left;
bool operator==(const either<Left, Right>& lhs,
const either<Left, Right>& rhs) union
{
if (lhs.is_left() == rhs.is_left())
{ {
if (lhs.is_left()) Left m_left;
Right m_right;
};
void destroy()
{ {
return lhs.left() == rhs.left(); if (m_is_left) m_left.~Left();
else m_right.~Right();
} }
else
template<typename L>
void cr_left(L&& value)
{ {
return lhs.right() == rhs.right(); new (&m_left) Left (std::forward<L>(value));
}
template<typename R>
void cr_right(R&& value)
{
new (&m_right) Right (std::forward<R>(value));
} }
};
template<typename Left, typename Right>
bool operator==(either<Left, Right> const& lhs, either<Left, Right> const& rhs)
{
if (lhs.is_left() == rhs.is_left())
{
if (lhs.is_left()) return lhs.left() == rhs.left();
else return lhs.right() == rhs.right();
} }
return false; return false;
} }
template<typename Left, typename Right> template<typename Left, typename Right>
bool operator==(const either<Left, Right>& lhs, Left const& rhs) bool operator==(either<Left, Right> const& lhs, Left const& rhs)
{ {
return lhs.is_left() && lhs.left() == rhs; return lhs.is_left() && lhs.left() == rhs;
} }
template<typename Left, typename Right> template<typename Left, typename Right>
bool operator==(Left const& lhs, const either<Left, Right>& rhs) bool operator==(Left const& lhs, either<Left, Right> const& rhs)
{ {
return rhs == lhs; return rhs == lhs;
} }
template<typename Left, typename Right> template<typename Left, typename Right>
bool operator==(const either<Left, Right>& lhs, Right const& rhs) bool operator==(either<Left, Right> const& lhs, Right const& rhs)
{ {
return lhs.is_right() && lhs.right() == rhs; return lhs.is_right() && lhs.right() == rhs;
} }
template<typename Left, typename Right> template<typename Left, typename Right>
bool operator==(Right const& lhs, const either<Left, Right>& rhs) bool operator==(Right const& lhs, either<Left, Right> const& rhs)
{ {
return rhs == lhs; return rhs == lhs;
} }
template<typename Left, typename Right> template<typename Left, typename Right>
bool operator!=(const either<Left, Right>& lhs, bool operator!=(either<Left, Right> const& lhs, either<Left, Right> const& rhs)
const either<Left, Right>& rhs)
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
template<typename Left, typename Right> template<typename Left, typename Right>
bool operator!=(const either<Left, Right>& lhs, Left const& rhs) bool operator!=(either<Left, Right> const& lhs, Left const& rhs)
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
template<typename Left, typename Right> template<typename Left, typename Right>
bool operator!=(Left const& lhs, const either<Left, Right>& rhs) bool operator!=(Left const& lhs, either<Left, Right> const& rhs)
{ {
return !(rhs == lhs); return !(rhs == lhs);
} }
template<typename Left, typename Right> template<typename Left, typename Right>
bool operator!=(const either<Left, Right>& lhs, Right const& rhs) bool operator!=(either<Left, Right> const& lhs, Right const& rhs)
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
template<typename Left, typename Right> template<typename Left, typename Right>
bool operator!=(Right const& lhs, const either<Left, Right>& rhs) bool operator!=(Right const& lhs, either<Left, Right> const& rhs)
{ {
return !(rhs == lhs); return !(rhs == lhs);
} }
} } // namespace cppa::util } // namespace cppa
#endif // EITHER_HPP #endif // EITHER_HPP
...@@ -151,6 +151,15 @@ class group : public channel ...@@ -151,6 +151,15 @@ class group : public channel
static intrusive_ptr<group> get(std::string const& module_name, static intrusive_ptr<group> get(std::string const& module_name,
std::string const& group_identifier); std::string const& group_identifier);
/**
* @brief Returns an anonymous group.
*
* Each calls to this member function returns a new instances
* of an anonymous group. Anonymous groups can be used whenever
* a set of actors wants to communicate over an exclusive channel.
*/
static intrusive_ptr<group> anonymous();
/** /**
* @brief Add a new group module to the libcppa group management. * @brief Add a new group module to the libcppa group management.
* @threadsafe * @threadsafe
......
...@@ -31,60 +31,67 @@ ...@@ -31,60 +31,67 @@
#ifndef OPTION_HPP #ifndef OPTION_HPP
#define OPTION_HPP #define OPTION_HPP
#include <new>
#include <utility>
#include "cppa/config.hpp"
namespace cppa { namespace cppa {
/**
* @brief Represents an optional value of @p T.
*/
template<typename T> template<typename T>
class option class option
{ {
union
{
T m_value;
};
bool m_valid;
void destroy()
{
if (m_valid) m_value.~T();
}
template<typename V>
void cr(V&& value)
{
m_valid = true;
new (&m_value) T (std::forward<V>(value));
}
public: public:
/**
* @brief Typdef for @p T.
*/
typedef T value_type; typedef T value_type;
/**
* @brief Default constructor.
* @post <tt>valid() == false</tt>
*/
option() : m_valid(false) { } option() : m_valid(false) { }
template<typename V> /**
option(V&& value) * @brief Creates an @p option from @p value.
{ * @post <tt>valid() == true</tt>
cr(std::forward<V>(value)); */
} option(T&& value) { cr(std::move(value)); }
/**
* @brief Creates an @p option from @p value.
* @post <tt>valid() == true</tt>
*/
option(T const& value) { cr(value); }
/**
* @brief Copy constructor.
*/
option(option const& other) option(option const& other)
{ {
if (other.m_valid) cr(other.m_value); if (other.m_valid) cr(other.m_value);
else m_valid = false; else m_valid = false;
} }
/**
* @brief Move constructor.
*/
option(option&& other) option(option&& other)
{ {
if (other.m_valid) cr(std::move(other.m_value)); if (other.m_valid) cr(std::move(other.m_value));
else m_valid = false; else m_valid = false;
} }
~option() ~option() { destroy(); }
{
destroy();
}
/**
* @brief Copy assignment.
*/
option& operator=(option const& other) option& operator=(option const& other)
{ {
if (m_valid) if (m_valid)
...@@ -99,16 +106,16 @@ class option ...@@ -99,16 +106,16 @@ class option
m_valid = false; m_valid = false;
} }
} }
else else if (other.m_valid)
{
if (other.m_valid)
{ {
cr(other.m_value); cr(other.m_value);
} }
}
return *this; return *this;
} }
/**
* @brief Move assignment.
*/
option& operator=(option&& other) option& operator=(option&& other)
{ {
if (m_valid) if (m_valid)
...@@ -123,16 +130,16 @@ class option ...@@ -123,16 +130,16 @@ class option
m_valid = false; m_valid = false;
} }
} }
else else if (other.m_valid)
{
if (other.m_valid)
{ {
cr(std::move(other.m_value)); cr(std::move(other.m_value));
} }
}
return *this; return *this;
} }
/**
* @brief Copy assignment.
*/
option& operator=(T const& value) option& operator=(T const& value)
{ {
if (m_valid) m_value = value; if (m_valid) m_value = value;
...@@ -140,6 +147,9 @@ class option ...@@ -140,6 +147,9 @@ class option
return *this; return *this;
} }
/**
* @brief Move assignment.
*/
option& operator=(T& value) option& operator=(T& value)
{ {
if (m_valid) m_value = std::move(value); if (m_valid) m_value = std::move(value);
...@@ -147,33 +157,132 @@ class option ...@@ -147,33 +157,132 @@ class option
return *this; return *this;
} }
/**
* @brief Returns @p true if this @p option has a valid value;
* otherwise @p false.
*/
inline bool valid() const { return m_valid; } inline bool valid() const { return m_valid; }
/**
* @copydoc valid()
*/
inline explicit operator bool() const { return m_valid; } inline explicit operator bool() const { return m_valid; }
/**
* @brief Returns @p false if this @p option has a valid value;
* otherwise @p true.
*/
inline bool operator!() const { return !m_valid; } inline bool operator!() const { return !m_valid; }
inline T& operator*() { return m_value; } /**
inline T const& operator*() const { return m_value; } * @brief Returns the value.
*/
inline T& operator*()
{
CPPA_REQUIRE(valid());
return m_value;
}
inline T& get() { return m_value; } /**
* @brief Returns the value.
*/
inline T const& operator*() const
{
CPPA_REQUIRE(valid());
return m_value;
}
inline T const& get() const { return m_value; } /**
* @brief Returns the value.
*/
inline T& get()
{
CPPA_REQUIRE(valid());
return m_value;
}
inline T& get_or_else(T const& val) /**
* @brief Returns the value.
*/
inline T const& get() const
{ {
if (!m_valid) cr(val); CPPA_REQUIRE(valid());
return m_value; return m_value;
} }
inline T& get_or_else(T&& val) /**
* @brief Returns the value of this @p option if it's valid
* or @p default_value.
*/
inline T& get_or_else(T const& default_value)
{ {
if (!m_valid) cr(std::move(val)); if (!m_valid) cr(default_value);
return m_value; return m_value;
} }
/**
* @copydoc get_or_else(T const&)
*/
inline T& get_or_else(T&& default_value)
{
if (!m_valid) cr(std::move(default_value));
return m_value;
}
public:
bool m_valid;
union { T m_value; };
void destroy() { if (m_valid) m_value.~T(); }
template<typename V>
void cr(V&& value)
{
m_valid = true;
new (&m_value) T (std::forward<V>(value));
}
}; };
template<typename T>
bool operator==(option<T> const& lhs, option<T> const& rhs)
{
if ((lhs) && (rhs)) return *lhs == *rhs;
return false;
}
template<typename T>
bool operator==(option<T> const& lhs, T const& rhs)
{
if (lhs) return *lhs == rhs;
return false;
}
template<typename T>
bool operator==(T const& lhs, option<T> const& rhs)
{
return rhs == lhs;
}
template<typename T>
bool operator!=(option<T> const& lhs, option<T> const& rhs)
{
return !(lhs == rhs);
}
template<typename T>
bool operator!=(option<T> const& lhs, T const& rhs)
{
return !(lhs == rhs);
}
template<typename T>
bool operator!=(T const& lhs, option<T> const& rhs)
{
return !(lhs == rhs);
}
} // namespace cppa } // namespace cppa
#endif // OPTION_HPP #endif // OPTION_HPP
...@@ -60,7 +60,7 @@ class tuple_view ...@@ -60,7 +60,7 @@ class tuple_view
template<size_t N, typename... Types> template<size_t N, typename... Types>
friend typename util::at<N, Types...>::type& get_ref(tuple_view<Types...>&); friend typename util::at<N, Types...>::type& get_ref(tuple_view<Types...>&);
void const* m_data[sizeof...(ElementTypes)]; void* m_data[sizeof...(ElementTypes)];
tuple_view() { } tuple_view() { }
...@@ -70,7 +70,7 @@ class tuple_view ...@@ -70,7 +70,7 @@ class tuple_view
typedef util::type_list<ElementTypes...> types; typedef util::type_list<ElementTypes...> types;
static tuple_view from(std::vector< std::pair<uniform_type_info const*, void const*> > const& vec) static tuple_view from(std::vector< std::pair<uniform_type_info const*, void*> > const& vec)
{ {
tuple_view result; tuple_view result;
size_t j = 0; size_t j = 0;
...@@ -81,7 +81,7 @@ class tuple_view ...@@ -81,7 +81,7 @@ class tuple_view
return std::move(result); return std::move(result);
} }
static tuple_view from(std::vector< std::pair<uniform_type_info const*, void const*> > const& vec, static tuple_view from(std::vector< std::pair<uniform_type_info const*, void*> > const& vec,
util::fixed_vector<size_t, sizeof...(ElementTypes)> const& mv) util::fixed_vector<size_t, sizeof...(ElementTypes)> const& mv)
{ {
tuple_view result; tuple_view result;
...@@ -110,6 +110,8 @@ class tuple_view ...@@ -110,6 +110,8 @@ class tuple_view
inline void const* at(size_t p) const { return m_data[p]; } inline void const* at(size_t p) const { return m_data[p]; }
inline void* mutable_at(size_t p) { return m_data[p]; }
}; };
template<size_t N, typename... Types> template<size_t N, typename... Types>
...@@ -120,13 +122,13 @@ const typename util::at<N, Types...>::type& get(tuple_view<Types...> const& t) ...@@ -120,13 +122,13 @@ const typename util::at<N, Types...>::type& get(tuple_view<Types...> const& t)
return *reinterpret_cast<result_t const*>(t.at(N)); return *reinterpret_cast<result_t const*>(t.at(N));
} }
//template<size_t N, typename... Types> template<size_t N, typename... Types>
//typename util::at<N, Types...>::type& get_ref(tuple_view<Types...>& t) typename util::at<N, Types...>::type& get_ref(tuple_view<Types...>& t)
//{ {
// static_assert(N < sizeof...(Types), "N >= t.size()"); static_assert(N < sizeof...(Types), "N >= t.size()");
// typedef typename util::at<N, Types...>::type result_t; typedef typename util::at<N, Types...>::type result_t;
// return *reinterpret_cast<result_t*>(t.m_vals->mutable_at(N)); return *reinterpret_cast<result_t*>(t.mutable_at(N));
//} }
template<typename TypeList> template<typename TypeList>
struct tuple_view_from_type_list; struct tuple_view_from_type_list;
......
#CXX = /opt/local/bin/g++-mp-4.6 #CXX = /opt/local/bin/g++-mp-4.6
CXX = /usr/bin/g++-4.6 CXX = /opt/local/bin/g++-mp-4.6
CXXFLAGS = -std=c++0x -pedantic -Wall -Wextra -I/opt/local/include/ -I../ -fpermissive -O2 CXXFLAGS = -std=c++0x -pedantic -Wall -Wextra -I/opt/local/include/ -I../ -fpermissive
LIBS = -L../.libs/ -lcppa -L/opt/local/lib -L/usr/lib -lboost_thread-mt LIBS = -L../.libs/ -lcppa -L/opt/local/lib -L/usr/lib -lboost_thread-mt
all: all:
......
...@@ -31,10 +31,10 @@ long the_test(int msg_count) ...@@ -31,10 +31,10 @@ long the_test(int msg_count)
auto msg = make_tuple(atom("AddCount"), val); auto msg = make_tuple(atom("AddCount"), val);
for (int i = 0; i < msg_count; ++i) for (int i = 0; i < msg_count; ++i)
{ {
send_tuple(counter, msg); counter << msg;
//send(counter, atom("AddCount"), val); //send(counter, atom("AddCount"), val);
} }
send(counter, atom("Get"), self()); send(counter, atom("Get"), self);
long result = 0; long result = 0;
receive receive
( (
...@@ -64,3 +64,4 @@ int main() ...@@ -64,3 +64,4 @@ int main()
await_all_others_done(); await_all_others_done();
return 0; return 0;
} }
...@@ -72,9 +72,9 @@ void abstract_event_based_actor::handle_message(queue_node_ptr& node, ...@@ -72,9 +72,9 @@ void abstract_event_based_actor::handle_message(queue_node_ptr& node,
// request next timeout if needed // request next timeout if needed
if (!m_loop_stack.empty()) if (!m_loop_stack.empty())
{ {
if (m_loop_stack.top().is_right()) if (m_loop_stack.back().is_right())
{ {
request_timeout(m_loop_stack.top().right().timeout()); request_timeout(m_loop_stack.back().right().timeout());
} }
} }
break; break;
...@@ -85,7 +85,7 @@ void abstract_event_based_actor::handle_message(queue_node_ptr& node, ...@@ -85,7 +85,7 @@ void abstract_event_based_actor::handle_message(queue_node_ptr& node,
void abstract_event_based_actor::handle_message(queue_node_ptr& node) void abstract_event_based_actor::handle_message(queue_node_ptr& node)
{ {
auto& bhvr = m_loop_stack.top(); auto& bhvr = m_loop_stack.back();
if (bhvr.is_left()) if (bhvr.is_left())
{ {
handle_message(node, bhvr.left()); handle_message(node, bhvr.left());
...@@ -102,7 +102,7 @@ void abstract_event_based_actor::resume(util::fiber*, resume_callback* callback) ...@@ -102,7 +102,7 @@ void abstract_event_based_actor::resume(util::fiber*, resume_callback* callback)
auto done_cb = [&]() auto done_cb = [&]()
{ {
m_state.store(abstract_scheduled_actor::done); m_state.store(abstract_scheduled_actor::done);
while (!m_loop_stack.empty()) m_loop_stack.pop(); while (!m_loop_stack.empty()) m_loop_stack.pop_back();
on_exit(); on_exit();
callback->exec_done(); callback->exec_done();
}; };
......
...@@ -29,12 +29,17 @@ ...@@ -29,12 +29,17 @@
#include "cppa/cppa.hpp" #include "cppa/cppa.hpp"
#include "cppa/to_string.hpp"
#include "cppa/exception.hpp" #include "cppa/exception.hpp"
#include "cppa/detail/types_array.hpp" #include "cppa/detail/types_array.hpp"
#include "cppa/detail/task_scheduler.hpp" #include "cppa/detail/task_scheduler.hpp"
#include "cppa/detail/yield_interface.hpp" #include "cppa/detail/yield_interface.hpp"
#include "cppa/detail/abstract_scheduled_actor.hpp" #include "cppa/detail/abstract_scheduled_actor.hpp"
using std::cout;
using std::endl;
#include <iostream>
namespace cppa { namespace detail { namespace cppa { namespace detail {
namespace { namespace {
...@@ -202,6 +207,12 @@ auto abstract_scheduled_actor::dq(queue_node_ptr& node, ...@@ -202,6 +207,12 @@ auto abstract_scheduled_actor::dq(queue_node_ptr& node,
} }
else else
{ {
std::string err_msg = "unhandled message in actor ";
err_msg += std::to_string(id());
err_msg += ": ";
err_msg += to_string(node->msg);
err_msg += "\n";
cout << err_msg;
buffer.push_back(node.release()); buffer.push_back(node.release());
return dq_indeterminate; return dq_indeterminate;
} }
......
...@@ -30,11 +30,32 @@ ...@@ -30,11 +30,32 @@
#include "cppa/event_based_actor.hpp" #include "cppa/event_based_actor.hpp"
namespace {
template<class StackElement, class Vec, class What>
void push_to(Vec& vec, What* bhvr, bool has_ownership)
{
// keep always the latest element in the stack to prevent subtle errors,
// e.g., the addresses of all variables in a lambda expression calling
// become() suddenly are invalid if we would pop the behavior!
if (vec.size() < 2)
{
vec.push_back(StackElement(bhvr, has_ownership));
}
else
{
vec[0] = std::move(vec[1]);
vec[1] = StackElement(bhvr, has_ownership);
}
}
} // namespace <anonymous>
namespace cppa { namespace cppa {
void event_based_actor::become_void() void event_based_actor::become_void()
{ {
while (!m_loop_stack.empty()) m_loop_stack.pop(); m_loop_stack.clear();
} }
void event_based_actor::do_become(behavior* bhvr) void event_based_actor::do_become(behavior* bhvr)
...@@ -51,16 +72,14 @@ void event_based_actor::do_become(behavior* bhvr) ...@@ -51,16 +72,14 @@ void event_based_actor::do_become(behavior* bhvr)
void event_based_actor::do_become(invoke_rules* bhvr, bool has_ownership) void event_based_actor::do_become(invoke_rules* bhvr, bool has_ownership)
{ {
become_void();
reset_timeout(); reset_timeout();
m_loop_stack.push(stack_element(bhvr, has_ownership)); push_to<stack_element>(m_loop_stack, bhvr, has_ownership);
} }
void event_based_actor::do_become(timed_invoke_rules* bhvr, bool has_ownership) void event_based_actor::do_become(timed_invoke_rules* bhvr, bool has_ownership)
{ {
become_void();
request_timeout(bhvr->timeout()); request_timeout(bhvr->timeout());
m_loop_stack.push(stack_element(bhvr, has_ownership)); push_to<stack_element>(m_loop_stack, bhvr, has_ownership);
} }
} // namespace cppa } // namespace cppa
...@@ -38,19 +38,24 @@ ...@@ -38,19 +38,24 @@
namespace cppa { namespace cppa {
intrusive_ptr<group> group::get(const std::string& arg0, intrusive_ptr<group> group::get(std::string const& arg0,
const std::string& arg1) std::string const& arg1)
{ {
return detail::singleton_manager::get_group_manager()->get(arg0, arg1); return detail::singleton_manager::get_group_manager()->get(arg0, arg1);
} }
intrusive_ptr<group> group::anonymous()
{
return detail::singleton_manager::get_group_manager()->anonymous();
}
void group::add_module(group::module* ptr) void group::add_module(group::module* ptr)
{ {
detail::singleton_manager::get_group_manager()->add_module(ptr); detail::singleton_manager::get_group_manager()->add_module(ptr);
} }
group::unsubscriber::unsubscriber(const channel_ptr& s, group::unsubscriber::unsubscriber(channel_ptr const& s,
const intrusive_ptr<group>& g) intrusive_ptr<group> const& g)
: m_self(s), m_group(g) : m_self(s), m_group(g)
{ {
} }
...@@ -65,7 +70,7 @@ void group::unsubscriber::actor_exited(std::uint32_t) ...@@ -65,7 +70,7 @@ void group::unsubscriber::actor_exited(std::uint32_t)
// unsubscription is done in destructor // unsubscription is done in destructor
} }
bool group::unsubscriber::matches(const attachable::token& what) bool group::unsubscriber::matches(attachable::token const& what)
{ {
if (what.subtype == typeid(group::unsubscriber)) if (what.subtype == typeid(group::unsubscriber))
{ {
...@@ -74,7 +79,7 @@ bool group::unsubscriber::matches(const attachable::token& what) ...@@ -74,7 +79,7 @@ bool group::unsubscriber::matches(const attachable::token& what)
return false; return false;
} }
group::module::module(const std::string& name) : m_name(name) group::module::module(std::string const& name) : m_name(name)
{ {
} }
...@@ -82,7 +87,7 @@ group::module::module(std::string&& name) : m_name(std::move(name)) ...@@ -82,7 +87,7 @@ group::module::module(std::string&& name) : m_name(std::move(name))
{ {
} }
const std::string& group::module::name() std::string const& group::module::name()
{ {
return m_name; return m_name;
} }
...@@ -92,17 +97,17 @@ group::group(std::string&& id, std::string&& mod_name) ...@@ -92,17 +97,17 @@ group::group(std::string&& id, std::string&& mod_name)
{ {
} }
group::group(const std::string& id, const std::string& mod_name) group::group(std::string const& id, std::string const& mod_name)
: m_identifier(id), m_module_name(mod_name) : m_identifier(id), m_module_name(mod_name)
{ {
} }
const std::string& group::identifier() const std::string const& group::identifier() const
{ {
return m_identifier; return m_identifier;
} }
const std::string& group::module_name() const std::string const& group::module_name() const
{ {
return m_module_name; return m_module_name;
} }
......
...@@ -47,22 +47,16 @@ typedef util::upgrade_lock_guard<util::shared_spinlock> upgrade_guard; ...@@ -47,22 +47,16 @@ typedef util::upgrade_lock_guard<util::shared_spinlock> upgrade_guard;
class local_group_module; class local_group_module;
class local_group : public group class group_impl : public group
{ {
friend class local_group_module;
util::shared_spinlock m_shared_mtx; util::shared_spinlock m_shared_mtx;
std::set<channel_ptr> m_subscribers; std::set<channel_ptr> m_subscribers;
// allow access to local_group_module only protected:
local_group(std::string&& gname) : group(std::move(gname), "local")
{
}
local_group(const std::string& gname) : group(gname, "local") template<typename F, typename S>
{ group_impl(F&& f, S&& s) : group(std::forward<F>(f), std::forward<S>(s)) { }
}
public: public:
...@@ -71,6 +65,8 @@ class local_group : public group ...@@ -71,6 +65,8 @@ class local_group : public group
shared_guard guard(m_shared_mtx); shared_guard guard(m_shared_mtx);
for (auto i = m_subscribers.begin(); i != m_subscribers.end(); ++i) for (auto i = m_subscribers.begin(); i != m_subscribers.end(); ++i)
{ {
// this cast is safe because we don't affect the "value"
// of *i, thus, the set remains in a consistent state
const_cast<channel_ptr&>(*i)->enqueue(sender, msg); const_cast<channel_ptr&>(*i)->enqueue(sender, msg);
} }
} }
...@@ -81,7 +77,7 @@ class local_group : public group ...@@ -81,7 +77,7 @@ class local_group : public group
enqueue(sender, tmp); enqueue(sender, tmp);
} }
virtual group::subscription subscribe(const channel_ptr& who) group::subscription subscribe(const channel_ptr& who) /*override*/
{ {
group::subscription result; group::subscription result;
exclusive_guard guard(m_shared_mtx); exclusive_guard guard(m_shared_mtx);
...@@ -92,11 +88,24 @@ class local_group : public group ...@@ -92,11 +88,24 @@ class local_group : public group
return result; return result;
} }
virtual void unsubscribe(const channel_ptr& who) void unsubscribe(const channel_ptr& who) /*override*/
{ {
exclusive_guard guard(m_shared_mtx); exclusive_guard guard(m_shared_mtx);
m_subscribers.erase(who); m_subscribers.erase(who);
} }
};
struct anonymous_group : group_impl
{
anonymous_group() : group_impl("anonymous", "anonymous") { }
};
class local_group : public group_impl
{
friend class local_group_module;
local_group(std::string const& gname) : group_impl(gname, "local") { }
}; };
...@@ -110,9 +119,7 @@ class local_group_module : public group::module ...@@ -110,9 +119,7 @@ class local_group_module : public group::module
public: public:
local_group_module() : super("local") local_group_module() : super("local") { }
{
}
group_ptr get(const std::string& group_name) group_ptr get(const std::string& group_name)
{ {
...@@ -147,6 +154,11 @@ group_manager::group_manager() ...@@ -147,6 +154,11 @@ group_manager::group_manager()
m_mmap.insert(std::make_pair(std::string("local"), std::move(ptr))); m_mmap.insert(std::make_pair(std::string("local"), std::move(ptr)));
} }
intrusive_ptr<group> group_manager::anonymous()
{
return new anonymous_group;
}
intrusive_ptr<group> group_manager::get(const std::string& module_name, intrusive_ptr<group> group_manager::get(const std::string& module_name,
const std::string& group_identifier) const std::string& group_identifier)
{ {
......
...@@ -159,7 +159,7 @@ void scheduler_helper::time_emitter(scheduler_helper::ptr_type m_self) ...@@ -159,7 +159,7 @@ void scheduler_helper::time_emitter(scheduler_helper::ptr_type m_self)
// wait for next message or next timeout // wait for next message or next timeout
if (it != messages.end()) if (it != messages.end())
{ {
msg_ptr = queue.try_pop(it->first); msg_ptr.reset(queue.try_pop(it->first));
} }
} }
} }
......
...@@ -34,26 +34,26 @@ namespace cppa { ...@@ -34,26 +34,26 @@ namespace cppa {
void stacked_event_based_actor::become_void() void stacked_event_based_actor::become_void()
{ {
while (!m_loop_stack.empty()) m_loop_stack.pop(); m_loop_stack.clear();
} }
void stacked_event_based_actor::unbecome() void stacked_event_based_actor::unbecome()
{ {
if (!m_loop_stack.empty()) m_loop_stack.pop(); if (!m_loop_stack.empty()) m_loop_stack.pop_back();
} }
void stacked_event_based_actor::do_become(invoke_rules* behavior, void stacked_event_based_actor::do_become(invoke_rules* behavior,
bool has_ownership) bool has_ownership)
{ {
reset_timeout(); reset_timeout();
m_loop_stack.push(stack_element(behavior, has_ownership)); m_loop_stack.push_back(stack_element(behavior, has_ownership));
} }
void stacked_event_based_actor::do_become(timed_invoke_rules* behavior, void stacked_event_based_actor::do_become(timed_invoke_rules* behavior,
bool has_ownership) bool has_ownership)
{ {
request_timeout(behavior->timeout()); request_timeout(behavior->timeout());
m_loop_stack.push(stack_element(behavior, has_ownership)); m_loop_stack.push_back(stack_element(behavior, has_ownership));
} }
} // namespace cppa } // namespace cppa
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