Commit e3a18cba authored by neverlord's avatar neverlord

minor bugfix and documentation

parent 828669b0
......@@ -88,6 +88,7 @@ nobase_library_include_HEADERS = \
cppa/cow_ptr.hpp \
cppa/cppa.hpp \
cppa/deserializer.hpp \
cppa/either.hpp \
cppa/event_based_actor.hpp \
cppa/event_based_actor_base.hpp \
cppa/abstract_event_based_actor.hpp \
......@@ -179,7 +180,6 @@ nobase_library_include_HEADERS = \
cppa/util/disable_if.hpp \
cppa/util/disjunction.hpp \
cppa/util/duration.hpp \
cppa/util/either.hpp \
cppa/util/element_at.hpp \
cppa/util/enable_if.hpp \
cppa/util/fiber.hpp \
......
......@@ -215,7 +215,7 @@ examples/hello_world_example.cpp
examples/math_actor_example.cpp
cppa/detail/yielding_actor.hpp
src/yielding_actor.cpp
cppa/util/either.hpp
cppa/either.hpp
cppa/abstract_event_based_actor.hpp
src/abstract_event_based_actor.cpp
cppa/event_based_actor.hpp
......@@ -261,3 +261,4 @@ benchmarks/theron_actor_creation.cpp
benchmarks/theron_mixed_case.cpp
cppa/util/static_foreach.hpp
cppa/type_value_pair.hpp
examples/dining_hakkers.cpp
......@@ -71,113 +71,32 @@ class abstract_actor : public Base
public:
class queue_node_ptr;
struct queue_node_deallocator;
struct queue_node
{
friend class abstract_actor;
friend class queue_node_ptr;
friend struct queue_node_deallocator;
queue_node* next;
std::atomic<queue_node*>* owner;
actor_ptr sender;
any_tuple msg;
private: // you have to be a friend to create or destroy a node
inline ~queue_node() { }
queue_node() : next(nullptr), owner(nullptr) { }
queue_node() : next(nullptr) { }
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)
: next(nullptr), owner(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
: next(nullptr), sender(from), msg(content)
{
delete ptr;
}
}
}
};
class 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; }
};
typedef std::unique_ptr<queue_node> queue_node_ptr;
protected:
queue_node m_prefetched_nodes[10];
std::atomic<queue_node*> m_prefetched;
util::single_reader_queue<queue_node,queue_node_deallocator> m_mailbox;
util::single_reader_queue<queue_node> m_mailbox;
private:
......@@ -220,20 +139,8 @@ class abstract_actor : public Base
protected:
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));
}
......@@ -241,13 +148,6 @@ class abstract_actor : public Base
abstract_actor(Args&&... args) : Base(std::forward<Args>(args)...)
, 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)
......
......@@ -35,9 +35,10 @@
#include <memory>
#include <vector>
#include "cppa/config.hpp"
#include "cppa/either.hpp"
#include "cppa/pattern.hpp"
#include "cppa/invoke_rules.hpp"
#include "cppa/util/either.hpp"
#include "cppa/detail/abstract_scheduled_actor.hpp"
namespace cppa {
......@@ -101,7 +102,7 @@ class abstract_event_based_actor : public detail::abstract_scheduled_actor
stack_element(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;
inline stack_element(invoke_rules* ptr, bool take_ownership)
......@@ -142,30 +143,24 @@ class abstract_event_based_actor : public detail::abstract_scheduled_actor
}
}
}
inline bool is_left()
{
return m_ptr.is_left();
}
inline bool is_right()
{
return m_ptr.is_right();
}
inline bool is_left() { return m_ptr.is_left(); }
inline bool is_right() { return m_ptr.is_right(); }
inline invoke_rules& left()
{
auto ptr = m_ptr.left();
if (ptr == nullptr) throw std::runtime_error("nullptr");
CPPA_REQUIRE(ptr != nullptr);
return *(ptr);
}
inline timed_invoke_rules& right()
{
auto ptr = m_ptr.right();
if (ptr == nullptr) throw std::runtime_error("nullptr");
CPPA_REQUIRE(ptr != nullptr);
return *(ptr);
}
};
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
......
......@@ -52,14 +52,11 @@ class any_tuple
/**
* @brief Creates an empty tuple.
* @post <tt>empty() == true</tt>
*/
any_tuple();
/**
* @brief Creates a tuple from @p t.
* @param t A typed tuple representation.
* @post <tt>empty() == false</tt>
*/
template<typename... Args>
any_tuple(tuple<Args...> const& t) : m_vals(t.vals()) { }
......@@ -78,13 +75,11 @@ class any_tuple
/**
* @brief Move assignment.
* @returns <tt>*this</tt>.
*/
any_tuple& operator=(any_tuple&&);
/**
* @brief Copy assignment.
* @returns <tt>*this</tt>.
*/
any_tuple& operator=(any_tuple const&) = default;
......
......@@ -52,7 +52,7 @@ namespace cppa {
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 m_values;
......@@ -86,6 +86,7 @@ class any_tuple_view
}
}
/*
template<typename... T>
explicit any_tuple_view(tuple<T...> const& tup)
{
......@@ -94,6 +95,7 @@ class any_tuple_view
m_values.push_back(std::make_pair(tup.type_at(i), tup.at(i)));
}
}
*/
template<typename... T>
any_tuple_view(tuple_view<T...> const& tup)
......@@ -113,16 +115,16 @@ class any_tuple_view
}
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>
any_tuple_view(std::list<T> const& vec) { from_list(vec); }
any_tuple_view(std::list<T>& vec) { from_list(vec); }
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>
any_tuple_view(T const& val,
any_tuple_view(T& val,
typename util::enable_if<util::is_primitive<T> >::type* = 0)
{
auto& arr = detail::static_types_array<T>::arr;
......@@ -135,6 +137,8 @@ class any_tuple_view
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
{
return m_values[p].first;
......
......@@ -31,12 +31,15 @@
#ifndef BEHAVIOR_HPP
#define BEHAVIOR_HPP
#include "cppa/util/either.hpp"
#include "cppa/either.hpp"
#include "cppa/invoke_rules.hpp"
namespace cppa {
typedef util::either<invoke_rules, timed_invoke_rules> behavior;
/**
* @brief
*/
typedef either<invoke_rules, timed_invoke_rules> behavior;
} // namespace cppa
......
......@@ -66,4 +66,16 @@
# error Plattform and/or compiler not supportet
#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
......@@ -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...));
}
// 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, ...);
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;
s->enqueue(s, make_tuple(arg0, args...));
send(static_cast<local_actor*>(self), arg0, args...);
}
template<class C>
......
......@@ -45,9 +45,7 @@ namespace cppa { namespace detail {
class task_scheduler;
/**
* @brief A spawned, scheduled Actor.
*/
// A spawned, scheduled Actor.
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 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;
enum dq_result
......
......@@ -43,12 +43,11 @@
#include <cstdint>
#include "cppa/atom.hpp"
#include "cppa/either.hpp"
#include "cppa/pattern.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/abstract_actor.hpp"
#include "cppa/util/either.hpp"
#include "cppa/util/singly_linked_list.hpp"
namespace cppa { namespace detail {
......@@ -87,7 +86,7 @@ class converted_thread_context : public abstract_actor<local_actor>
private:
typedef util::singly_linked_list<queue_node,super::queue_node_deallocator>
typedef util::singly_linked_list<queue_node>
queue_node_buffer;
enum throw_on_exit_result
......
......@@ -49,6 +49,8 @@ class group_manager
intrusive_ptr<group> get(std::string const& module_name,
std::string const& group_identifier);
intrusive_ptr<group> anonymous();
void add_module(group::module*);
private:
......
......@@ -67,9 +67,8 @@ struct implicit_conversions
subtype3;
typedef typename util::replace_type<subtype3, actor_ptr,
std::is_same<actor*,T>,
std::is_same<local_actor*,T>,
std::is_same<self_type,T>,
std::is_convertible<T, actor*>,
std::is_convertible<T, local_actor*>,
std::is_same<self_type,T>>::type
type;
......
......@@ -37,13 +37,13 @@
#include <stack>
#include "cppa/either.hpp"
#include "cppa/pattern.hpp"
#include "cppa/detail/delegate.hpp"
#include "cppa/detail/abstract_scheduled_actor.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"
namespace cppa { namespace detail {
......
......@@ -32,283 +32,251 @@
#define EITHER_HPP
#include <new>
#include <stdexcept>
#include <utility>
#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>
class either
{
static_assert(std::is_same<Left, Right>::value == false, "Left == Right");
union
{
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));
}
static_assert( std::is_convertible<Left, Right>::value == false
&& std::is_convertible<Right, Left>::value == false,
"Left is not allowed to be convertible to Right");
public:
// default constructor creates a left
either() : m_is_left(true)
{
new (&m_left) Left ();
}
either(Left const& value) : m_is_left(true)
{
cr_left(value);
}
either(Left&& value) : m_is_left(true)
{
cr_left(std::move(value));
}
either(Right const& value) : m_is_left(false)
{
cr_right(value);
}
either(Right&& value) : m_is_left(false)
{
cr_right(std::move(value));
}
/**
* @brief Default constructor, creates a @p Left.
*/
either() : m_is_left(true) { new (&m_left) Left (); }
/**
* @brief Creates a @p Left from @p value.
*/
either(Left const& value) : m_is_left(true) { cr_left(value); }
/**
* @brief Creates a @p Left from @p value.
*/
either(Left&& value) : m_is_left(true) { cr_left(std::move(value)); }
/**
* @brief Creates a @p Right from @p value.
*/
either(Right const& value) : m_is_left(false) { cr_right(value); }
/**
* @brief Creates a @p Right from @p 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)
{
if (other.m_is_left)
{
cr_left(other.m_left);
}
else
{
cr_right(other.m_right);
}
if (other.m_is_left) cr_left(other.m_left);
else cr_right(other.m_right);
}
/**
* @brief Move constructor.
*/
either(either&& other) : m_is_left(other.m_is_left)
{
if (other.m_is_left)
{
cr_left(std::move(other.m_left));
}
else
{
cr_right(std::move(other.m_right));
}
if (other.m_is_left) cr_left(std::move(other.m_left));
else cr_right(std::move(other.m_right));
}
~either()
{
destroy();
}
~either() { destroy(); }
/**
* @brief Copy assignment.
*/
either& operator=(either const& other)
{
if (m_is_left == other.m_is_left)
{
if (m_is_left)
{
m_left = other.m_left;
}
else
{
m_right = other.m_right;
}
if (m_is_left) m_left = other.m_left;
else m_right = other.m_right;
}
else
{
destroy();
m_is_left = other.m_is_left;
if (other.m_is_left)
{
cr_left(other.m_left);
}
else
{
cr_right(other.m_right);
}
if (other.m_is_left) cr_left(other.m_left);
else cr_right(other.m_right);
}
return *this;
}
/**
* @brief Move assignment.
*/
either& operator=(either&& other)
{
if (m_is_left == other.m_is_left)
{
if (m_is_left)
{
m_left = std::move(other.m_left);
}
else
{
m_right = std::move(other.m_right);
}
if (m_is_left) m_left = std::move(other.m_left);
else m_right = std::move(other.m_right);
}
else
{
destroy();
m_is_left = other.m_is_left;
if (other.m_is_left)
{
cr_left(std::move(other.m_left));
}
else
{
cr_right(std::move(other.m_right));
}
if (other.m_is_left) cr_left(std::move(other.m_left));
else cr_right(std::move(other.m_right));
}
return *this;
}
inline bool is_left() const
{
return m_is_left;
}
/**
* @brief Returns @p true if this is a @p Left; otherwise @p false.
*/
inline bool is_left() const { return m_is_left; }
inline bool is_right() const
{
return !m_is_left;
}
/**
* @brief Returns @p true if this is a @p Left; otherwise @p false.
*/
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;
}
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;
}
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;
}
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;
}
};
private:
template<typename Left, typename Right>
bool operator==(const either<Left, Right>& lhs,
const either<Left, Right>& rhs)
{
if (lhs.is_left() == rhs.is_left())
bool m_is_left;
union
{
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;
}
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;
}
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;
}
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;
}
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;
}
template<typename Left, typename Right>
bool operator!=(const either<Left, Right>& lhs,
const either<Left, Right>& rhs)
bool operator!=(either<Left, Right> const& lhs, either<Left, Right> const& rhs)
{
return !(lhs == rhs);
}
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);
}
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);
}
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);
}
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);
}
} } // namespace cppa::util
} // namespace cppa
#endif // EITHER_HPP
......@@ -151,6 +151,15 @@ class group : public channel
static intrusive_ptr<group> get(std::string const& module_name,
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.
* @threadsafe
......
......@@ -31,60 +31,67 @@
#ifndef OPTION_HPP
#define OPTION_HPP
#include <new>
#include <utility>
#include "cppa/config.hpp"
namespace cppa {
/**
* @brief Represents an optional value of @p T.
*/
template<typename T>
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:
/**
* @brief Typdef for @p T.
*/
typedef T value_type;
/**
* @brief Default constructor.
* @post <tt>valid() == false</tt>
*/
option() : m_valid(false) { }
template<typename V>
option(V&& value)
{
cr(std::forward<V>(value));
}
/**
* @brief Creates an @p option from @p value.
* @post <tt>valid() == true</tt>
*/
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)
{
if (other.m_valid) cr(other.m_value);
else m_valid = false;
}
/**
* @brief Move constructor.
*/
option(option&& other)
{
if (other.m_valid) cr(std::move(other.m_value));
else m_valid = false;
}
~option()
{
destroy();
}
~option() { destroy(); }
/**
* @brief Copy assignment.
*/
option& operator=(option const& other)
{
if (m_valid)
......@@ -99,16 +106,16 @@ class option
m_valid = false;
}
}
else
{
if (other.m_valid)
else if (other.m_valid)
{
cr(other.m_value);
}
}
return *this;
}
/**
* @brief Move assignment.
*/
option& operator=(option&& other)
{
if (m_valid)
......@@ -123,16 +130,16 @@ class option
m_valid = false;
}
}
else
{
if (other.m_valid)
else if (other.m_valid)
{
cr(std::move(other.m_value));
}
}
return *this;
}
/**
* @brief Copy assignment.
*/
option& operator=(T const& value)
{
if (m_valid) m_value = value;
......@@ -140,6 +147,9 @@ class option
return *this;
}
/**
* @brief Move assignment.
*/
option& operator=(T& value)
{
if (m_valid) m_value = std::move(value);
......@@ -147,33 +157,132 @@ class option
return *this;
}
/**
* @brief Returns @p true if this @p option has a valid value;
* otherwise @p false.
*/
inline bool valid() const { return m_valid; }
/**
* @copydoc 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 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;
}
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;
}
/**
* @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
#endif // OPTION_HPP
......@@ -60,7 +60,7 @@ class tuple_view
template<size_t N, typename... 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() { }
......@@ -70,7 +70,7 @@ class tuple_view
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;
size_t j = 0;
......@@ -81,7 +81,7 @@ class tuple_view
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)
{
tuple_view result;
......@@ -110,6 +110,8 @@ class tuple_view
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>
......@@ -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));
}
//template<size_t N, typename... Types>
//typename util::at<N, Types...>::type& get_ref(tuple_view<Types...>& t)
//{
// static_assert(N < sizeof...(Types), "N >= t.size()");
// typedef typename util::at<N, Types...>::type result_t;
// return *reinterpret_cast<result_t*>(t.m_vals->mutable_at(N));
//}
template<size_t N, typename... Types>
typename util::at<N, Types...>::type& get_ref(tuple_view<Types...>& t)
{
static_assert(N < sizeof...(Types), "N >= t.size()");
typedef typename util::at<N, Types...>::type result_t;
return *reinterpret_cast<result_t*>(t.mutable_at(N));
}
template<typename TypeList>
struct tuple_view_from_type_list;
......
#CXX = /opt/local/bin/g++-mp-4.6
CXX = /usr/bin/g++-4.6
CXXFLAGS = -std=c++0x -pedantic -Wall -Wextra -I/opt/local/include/ -I../ -fpermissive -O2
CXX = /opt/local/bin/g++-mp-4.6
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
all:
......
......@@ -31,10 +31,10 @@ long the_test(int msg_count)
auto msg = make_tuple(atom("AddCount"), val);
for (int i = 0; i < msg_count; ++i)
{
send_tuple(counter, msg);
counter << msg;
//send(counter, atom("AddCount"), val);
}
send(counter, atom("Get"), self());
send(counter, atom("Get"), self);
long result = 0;
receive
(
......@@ -64,3 +64,4 @@ int main()
await_all_others_done();
return 0;
}
......@@ -72,9 +72,9 @@ void abstract_event_based_actor::handle_message(queue_node_ptr& node,
// request next timeout if needed
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;
......@@ -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)
{
auto& bhvr = m_loop_stack.top();
auto& bhvr = m_loop_stack.back();
if (bhvr.is_left())
{
handle_message(node, bhvr.left());
......@@ -102,7 +102,7 @@ void abstract_event_based_actor::resume(util::fiber*, resume_callback* callback)
auto done_cb = [&]()
{
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();
callback->exec_done();
};
......
......@@ -29,12 +29,17 @@
#include "cppa/cppa.hpp"
#include "cppa/to_string.hpp"
#include "cppa/exception.hpp"
#include "cppa/detail/types_array.hpp"
#include "cppa/detail/task_scheduler.hpp"
#include "cppa/detail/yield_interface.hpp"
#include "cppa/detail/abstract_scheduled_actor.hpp"
using std::cout;
using std::endl;
#include <iostream>
namespace cppa { namespace detail {
namespace {
......@@ -202,6 +207,12 @@ auto abstract_scheduled_actor::dq(queue_node_ptr& node,
}
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());
return dq_indeterminate;
}
......
......@@ -30,11 +30,32 @@
#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 {
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)
......@@ -51,16 +72,14 @@ void event_based_actor::do_become(behavior* bhvr)
void event_based_actor::do_become(invoke_rules* bhvr, bool has_ownership)
{
become_void();
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)
{
become_void();
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
......@@ -38,19 +38,24 @@
namespace cppa {
intrusive_ptr<group> group::get(const std::string& arg0,
const std::string& arg1)
intrusive_ptr<group> group::get(std::string const& arg0,
std::string const& 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)
{
detail::singleton_manager::get_group_manager()->add_module(ptr);
}
group::unsubscriber::unsubscriber(const channel_ptr& s,
const intrusive_ptr<group>& g)
group::unsubscriber::unsubscriber(channel_ptr const& s,
intrusive_ptr<group> const& g)
: m_self(s), m_group(g)
{
}
......@@ -65,7 +70,7 @@ void group::unsubscriber::actor_exited(std::uint32_t)
// 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))
{
......@@ -74,7 +79,7 @@ bool group::unsubscriber::matches(const attachable::token& what)
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))
{
}
const std::string& group::module::name()
std::string const& group::module::name()
{
return m_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)
{
}
const std::string& group::identifier() const
std::string const& group::identifier() const
{
return m_identifier;
}
const std::string& group::module_name() const
std::string const& group::module_name() const
{
return m_module_name;
}
......
......@@ -47,22 +47,16 @@ typedef util::upgrade_lock_guard<util::shared_spinlock> upgrade_guard;
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;
std::set<channel_ptr> m_subscribers;
// allow access to local_group_module only
local_group(std::string&& gname) : group(std::move(gname), "local")
{
}
protected:
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:
......@@ -71,6 +65,8 @@ class local_group : public group
shared_guard guard(m_shared_mtx);
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);
}
}
......@@ -81,7 +77,7 @@ class local_group : public group
enqueue(sender, tmp);
}
virtual group::subscription subscribe(const channel_ptr& who)
group::subscription subscribe(const channel_ptr& who) /*override*/
{
group::subscription result;
exclusive_guard guard(m_shared_mtx);
......@@ -92,11 +88,24 @@ class local_group : public group
return result;
}
virtual void unsubscribe(const channel_ptr& who)
void unsubscribe(const channel_ptr& who) /*override*/
{
exclusive_guard guard(m_shared_mtx);
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
public:
local_group_module() : super("local")
{
}
local_group_module() : super("local") { }
group_ptr get(const std::string& group_name)
{
......@@ -147,6 +154,11 @@ group_manager::group_manager()
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,
const std::string& group_identifier)
{
......
......@@ -159,7 +159,7 @@ void scheduler_helper::time_emitter(scheduler_helper::ptr_type m_self)
// wait for next message or next timeout
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 {
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()
{
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,
bool has_ownership)
{
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,
bool has_ownership)
{
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
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