Commit a9300af4 authored by neverlord's avatar neverlord

RIP invoke_rules, long live partial_function

parent 550a4200
This diff is collapsed.
......@@ -3,7 +3,6 @@ cppa/tuple.hpp
unit_testing/main.cpp
cppa/util/void_type.hpp
cppa/util/type_list.hpp
cppa/util.hpp
cppa/util/is_one_of.hpp
cppa/util/conjunction.hpp
cppa/util/disjunction.hpp
......@@ -34,7 +33,6 @@ cppa/util/is_copyable.hpp
cppa/util/has_copy_member_fun.hpp
cppa/detail/intermediate.hpp
cppa/detail/invokable.hpp
cppa/invoke_rules.hpp
cppa/on.hpp
unit_testing/test__serialization.cpp
cppa/serializer.hpp
......@@ -176,7 +174,6 @@ cppa/detail/receive_loop_helper.hpp
cppa/util/wrapped.hpp
cppa/detail/boxed.hpp
cppa/detail/unboxed.hpp
src/invoke_rules.cpp
src/abstract_tuple.cpp
cppa/util/duration.hpp
src/duration.cpp
......@@ -262,3 +259,5 @@ cppa/detail/disablable_delete.hpp
unit_testing/test__fixed_vector.cpp
cppa/detail/tuple_cast_impl.hpp
cppa/match.hpp
cppa/partial_function.hpp
src/partial_function.cpp
......@@ -52,60 +52,125 @@ namespace cppa {
template<class Base>
class abstract_actor : public Base
{
typedef detail::lock_guard<detail::mutex> guard_type;
//typedef std::lock_guard<std::mutex> guard_type;
typedef std::unique_ptr<attachable> attachable_ptr;
// true if the associated thread has finished execution
std::atomic<std::uint32_t> m_exit_reason;
// guards access to m_exited, m_subscriptions and m_links
detail::mutex m_mtx;
// links to other actors
std::vector<actor_ptr> m_links;
// code that is executed on cleanup
std::vector<attachable_ptr> m_attachables;
typedef std::unique_ptr<attachable> attachable_ptr;
typedef detail::lock_guard<detail::mutex> guard_type;
public:
struct queue_node
{
friend class abstract_actor;
friend class queue_node_ptr;
queue_node* next;
actor_ptr sender;
any_tuple msg;
queue_node() : next(nullptr) { }
queue_node(actor* from, any_tuple&& content)
: next(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), sender(from), msg(content) { }
};
typedef std::unique_ptr<queue_node> queue_node_ptr;
bool attach(attachable* ptr) /*override*/
{
if (ptr == nullptr)
{
guard_type guard(m_mtx);
return m_exit_reason.load() == exit_reason::not_exited;
}
queue_node(actor* from, any_tuple const& content)
: next(nullptr), sender(from), msg(content)
else
{
attachable_ptr uptr(ptr);
std::uint32_t reason;
// lifetime scope of guard
{
guard_type guard(m_mtx);
reason = m_exit_reason.load();
if (reason == exit_reason::not_exited)
{
m_attachables.push_back(std::move(uptr));
return true;
}
}
uptr->actor_exited(reason);
return false;
}
};
}
typedef std::unique_ptr<queue_node> queue_node_ptr;
void detach(attachable::token const& what) /*override*/
{
attachable_ptr uptr;
// lifetime scope of guard
{
guard_type guard(m_mtx);
auto end = m_attachables.end();
auto i = std::find_if(
m_attachables.begin(), end,
[&](attachable_ptr& p) { return p->matches(what); });
if (i != end)
{
uptr = std::move(*i);
m_attachables.erase(i);
}
}
// uptr will be destroyed here, without locked mutex
}
protected:
void link_to(intrusive_ptr<actor>& other) /*override*/
{
(void) link_to_impl(other);
}
util::single_reader_queue<queue_node> m_mailbox;
void unlink_from(intrusive_ptr<actor>& other) /*override*/
{
(void) unlink_from_impl(other);
}
private:
bool remove_backlink(intrusive_ptr<actor>& other) /*override*/
{
if (other && other != this)
{
guard_type guard(m_mtx);
auto i = std::find(m_links.begin(), m_links.end(), other);
if (i != m_links.end())
{
m_links.erase(i);
return true;
}
}
return false;
}
// @pre m_mtx.locked()
bool exited() const
bool establish_backlink(intrusive_ptr<actor>& other) /*override*/
{
return m_exit_reason.load() != exit_reason::not_exited;
std::uint32_t reason = exit_reason::not_exited;
if (other && other != this)
{
guard_type guard(m_mtx);
reason = m_exit_reason.load();
if (reason == exit_reason::not_exited)
{
auto i = std::find(m_links.begin(), m_links.end(), other);
if (i == m_links.end())
{
m_links.push_back(other);
return true;
}
}
}
// send exit message without lock
if (reason != exit_reason::not_exited)
{
other->enqueue(this, make_tuple(atom(":Exit"), reason));
}
return false;
}
protected:
util::single_reader_queue<queue_node> m_mailbox;
template<typename T>
inline queue_node* fetch_node(actor* sender, T&& msg)
{
......@@ -185,105 +250,22 @@ class abstract_actor : public Base
return false;
}
public:
bool attach(attachable* ptr) /*override*/
{
if (ptr == nullptr)
{
guard_type guard(m_mtx);
return m_exit_reason.load() == exit_reason::not_exited;
}
else
{
attachable_ptr uptr(ptr);
std::uint32_t reason;
// lifetime scope of guard
{
guard_type guard(m_mtx);
reason = m_exit_reason.load();
if (reason == exit_reason::not_exited)
{
m_attachables.push_back(std::move(uptr));
return true;
}
}
uptr->actor_exited(reason);
return false;
}
}
void detach(attachable::token const& what) /*override*/
{
attachable_ptr uptr;
// lifetime scope of guard
{
guard_type guard(m_mtx);
auto end = m_attachables.end();
auto i = std::find_if(m_attachables.begin(),
end,
[&](attachable_ptr& ptr)
{
return ptr->matches(what);
});
if (i != end)
{
uptr = std::move(*i);
m_attachables.erase(i);
}
}
// uptr will be destroyed here, without locked mutex
}
void link_to(intrusive_ptr<actor>& other) /*override*/
{
(void) link_to_impl(other);
}
void unlink_from(intrusive_ptr<actor>& other) /*override*/
{
(void) unlink_from_impl(other);
}
private:
bool remove_backlink(intrusive_ptr<actor>& other) /*override*/
// @pre m_mtx.locked()
bool exited() const
{
if (other && other != this)
{
guard_type guard(m_mtx);
auto i = std::find(m_links.begin(), m_links.end(), other);
if (i != m_links.end())
{
m_links.erase(i);
return true;
}
}
return false;
return m_exit_reason.load() != exit_reason::not_exited;
}
bool establish_backlink(intrusive_ptr<actor>& other) /*override*/
{
std::uint32_t reason = exit_reason::not_exited;
if (other && other != this)
{
guard_type guard(m_mtx);
reason = m_exit_reason.load();
if (reason == exit_reason::not_exited)
{
auto i = std::find(m_links.begin(), m_links.end(), other);
if (i == m_links.end())
{
m_links.push_back(other);
return true;
}
}
}
// send exit message without lock
if (reason != exit_reason::not_exited)
{
other->enqueue(this, make_tuple(atom(":Exit"), reason));
}
return false;
}
// true if the associated thread has finished execution
std::atomic<std::uint32_t> m_exit_reason;
// guards access to m_exited, m_subscriptions and m_links
detail::mutex m_mtx;
// links to other actors
std::vector<actor_ptr> m_links;
// code that is executed on cleanup
std::vector<attachable_ptr> m_attachables;
};
......
......@@ -38,7 +38,7 @@
#include "cppa/config.hpp"
#include "cppa/either.hpp"
#include "cppa/pattern.hpp"
#include "cppa/invoke_rules.hpp"
#include "cppa/behavior.hpp"
#include "cppa/detail/disablable_delete.hpp"
#include "cppa/detail/abstract_scheduled_actor.hpp"
......@@ -56,9 +56,9 @@ class abstract_event_based_actor : public detail::abstract_scheduled_actor
public:
void dequeue(invoke_rules&) /*override*/;
void dequeue(behavior&) /*override*/;
void dequeue(timed_invoke_rules&) /*override*/;
void dequeue(partial_function&) /*override*/;
void resume(util::fiber*, resume_callback* callback) /*override*/;
......@@ -74,31 +74,20 @@ class abstract_event_based_actor : public detail::abstract_scheduled_actor
template<typename Scheduler>
abstract_event_based_actor*
attach_to_scheduler(void (*enqueue_fun)(Scheduler*, abstract_scheduled_actor*),
attach_to_scheduler(void (*enq_fun)(Scheduler*, abstract_scheduled_actor*),
Scheduler* sched)
{
m_enqueue_to_scheduler.reset(enqueue_fun, sched, this);
m_enqueue_to_scheduler.reset(enq_fun, sched, this);
this->init();
return this;
}
private:
void handle_message(queue_node_ptr& node,
invoke_rules& behavior);
void handle_message(queue_node_ptr& node,
timed_invoke_rules& behavior);
void handle_message(queue_node_ptr& node);
protected:
abstract_event_based_actor();
// ownership flag + pointer
typedef either<std::unique_ptr<invoke_rules, detail::disablable_delete<invoke_rules>>,
std::unique_ptr<timed_invoke_rules, detail::disablable_delete<timed_invoke_rules>>>
typedef std::unique_ptr<behavior, detail::disablable_delete<behavior>>
stack_element;
queue_node_buffer m_buffer;
......@@ -132,6 +121,10 @@ class abstract_event_based_actor : public detail::abstract_scheduled_actor
receive(std::forward<Args>(args)...);
}
private:
void handle_message(queue_node_ptr& node);
};
} // namespace cppa
......
......@@ -56,17 +56,6 @@ typedef std::uint32_t actor_id;
class actor : public channel
{
bool m_is_proxy;
actor_id m_id;
process_information_ptr m_parent_process;
protected:
actor(process_information_ptr const& parent = process_information::get());
actor(std::uint32_t aid,
process_information_ptr const& parent = process_information::get());
public:
~actor();
......@@ -202,6 +191,20 @@ class actor : public channel
*/
inline bool is_proxy() const;
protected:
actor(process_information_ptr const& parent = process_information::get());
actor(std::uint32_t aid,
process_information_ptr const& parent = process_information::get());
private:
actor_id m_id;
bool m_is_proxy;
process_information_ptr m_parent_process;
};
/**
......
......@@ -50,9 +50,6 @@ class actor_proxy : public abstract_actor<actor>
typedef abstract_actor<actor> super;
void forward_message(process_information_ptr const&,
actor*, any_tuple const&);
public:
actor_proxy(std::uint32_t mid, process_information_ptr const& parent);
......@@ -77,6 +74,11 @@ class actor_proxy : public abstract_actor<actor>
bool establish_backlink(intrusive_ptr<actor>& to);
public:
void forward_message(process_information_ptr const&,
actor*, any_tuple const&);
};
#endif // CPPA_DOCUMENTATION
......
......@@ -45,10 +45,6 @@ namespace cppa {
class any_tuple
{
cow_ptr<detail::abstract_tuple> m_vals;
explicit any_tuple(cow_ptr<detail::abstract_tuple> const& vals);
public:
/**
......@@ -143,11 +139,22 @@ class any_tuple
cow_ptr<detail::abstract_tuple> const& vals() const;
inline std::type_info const* values_type_list() const
inline void const* type_token() const
{
return m_vals->type_token();
}
inline std::type_info const* impl_type() const
{
return m_vals->values_type_list();
return m_vals->impl_type();
}
private:
cow_ptr<detail::abstract_tuple> m_vals;
explicit any_tuple(cow_ptr<detail::abstract_tuple> const& vals);
};
inline bool operator==(any_tuple const& lhs, any_tuple const& rhs)
......
......@@ -31,15 +31,111 @@
#ifndef BEHAVIOR_HPP
#define BEHAVIOR_HPP
#include "cppa/either.hpp"
#include "cppa/invoke_rules.hpp"
#include <functional>
#include <type_traits>
#include "cppa/util/tbind.hpp"
#include "cppa/util/rm_ref.hpp"
#include "cppa/util/if_else.hpp"
#include "cppa/util/duration.hpp"
#include "cppa/util/type_list.hpp"
#include "cppa/partial_function.hpp"
namespace cppa {
/**
* @brief
*/
typedef either<invoke_rules, timed_invoke_rules> behavior;
class behavior
{
behavior(behavior const&) = delete;
behavior& operator=(behavior const&) = delete;
public:
behavior() = default;
behavior(behavior&&) = default;
behavior& operator=(behavior&&) = default;
inline behavior(partial_function&& fun) : m_fun(std::move(fun))
{
}
inline behavior(util::duration tout, std::function<void()>&& handler)
: m_timeout(tout), m_timeout_handler(std::move(handler))
{
}
inline void handle_timeout() const
{
m_timeout_handler();
}
inline util::duration const& timeout() const
{
return m_timeout;
}
inline void operator()(any_tuple const& value)
{
m_fun(value);
}
inline detail::intermediate* get_intermediate(any_tuple const& value)
{
return m_fun.get_intermediate(value);
}
inline partial_function& get_partial_function()
{
return m_fun;
}
inline behavior& splice(behavior&& what)
{
m_fun.splice(std::move(what.get_partial_function()));
m_timeout = what.m_timeout;
m_timeout_handler = std::move(what.m_timeout_handler);
return *this;
}
template<class... Args>
inline behavior& splice(partial_function&& arg0, Args&&... args)
{
m_fun.splice(std::move(arg0));
return splice(std::forward<Args>(args)...);
}
private:
// terminates recursion
inline behavior& splice() { return *this; }
partial_function m_fun;
util::duration m_timeout;
std::function<void()> m_timeout_handler;
};
namespace detail {
template<typename... Ts>
struct select_bhvr
{
static constexpr bool timed =
util::tl_exists<
util::type_list<Ts...>,
util::tbind<std::is_same, behavior>::type
>::value;
typedef typename util::if_else_c<timed,
behavior,
util::wrapped<partial_function> >::type
type;
};
} // namespace detail
} // namespace cppa
......
......@@ -53,10 +53,6 @@ class channel : public ref_counted
friend class actor;
friend class group;
// channel is a sealed class and the only
// allowed subclasses are actor and group.
channel() = default;
public:
virtual ~channel();
......@@ -68,6 +64,12 @@ class channel : public ref_counted
virtual void enqueue(actor* sender, any_tuple&& msg) = 0;
private:
// channel is a sealed class and the only
// allowed subclasses are actor and group.
channel() = default;
};
/**
......
......@@ -42,6 +42,7 @@
#include "cppa/actor.hpp"
#include "cppa/channel.hpp"
#include "cppa/receive.hpp"
#include "cppa/behavior.hpp"
#include "cppa/announce.hpp"
#include "cppa/scheduler.hpp"
#include "cppa/to_string.hpp"
......@@ -49,7 +50,6 @@
#include "cppa/fsm_actor.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/invoke_rules.hpp"
#include "cppa/scheduled_actor.hpp"
#include "cppa/scheduling_hint.hpp"
#include "cppa/event_based_actor.hpp"
......
......@@ -84,7 +84,7 @@ class abstract_scheduled_actor : public abstract_actor<local_actor>
filter_result filter_msg(any_tuple const& msg);
dq_result dq(queue_node_ptr& node,
invoke_rules_base& rules,
partial_function& rules,
queue_node_buffer& buffer);
bool has_pending_timeout()
......@@ -157,8 +157,8 @@ struct scheduled_actor_dummy : abstract_scheduled_actor
{
void resume(util::fiber*, resume_callback*);
void quit(std::uint32_t);
void dequeue(invoke_rules&);
void dequeue(timed_invoke_rules&);
void dequeue(behavior&);
void dequeue(partial_function&);
void link_to(intrusive_ptr<actor>&);
void unlink_from(intrusive_ptr<actor>&);
bool establish_backlink(intrusive_ptr<actor>&);
......
......@@ -56,14 +56,19 @@ struct abstract_tuple : ref_counted
virtual abstract_tuple* copy() const = 0;
virtual void const* at(size_t pos) const = 0;
virtual uniform_type_info const* type_at(size_t pos) const = 0;
// type_list of values or nullptr
virtual std::type_info const* values_type_list() const = 0;
// identifies the type of the implementation, this is NOT the
// typeid of the implementation class
virtual std::type_info const* impl_type() const = 0;
// uniquely identifies this category (element types) of messages
virtual void const* type_token() const = 0;
bool equals(abstract_tuple const& other) const;
// iterator support
class const_iterator : public std::iterator<std::bidirectional_iterator_tag,
type_value_pair>
class const_iterator //: public std::iterator<std::bidirectional_iterator_tag,
// type_value_pair>
{
size_t m_pos;
......@@ -142,7 +147,7 @@ struct abstract_tuple : ref_counted
inline const_iterator& operator*() { return *this; }
inline operator type_value_pair() const { return {type(), value()}; }
//inline operator type_value_pair() const { return {type(), value()}; }
};
......@@ -160,19 +165,45 @@ inline bool full_eq(abstract_tuple::const_iterator const& lhs,
|| lhs.type()->equals(lhs.value(), rhs.second));
}
inline bool full_eq_v2(type_value_pair const& lhs,
abstract_tuple::const_iterator const& rhs)
{
return full_eq(rhs, lhs);
}
inline bool full_eq_v3(abstract_tuple::const_iterator const& lhs,
abstract_tuple::const_iterator const& rhs)
{
return lhs.type() == rhs.type()
&& lhs.type()->equals(lhs.value(), rhs.value());
}
inline bool values_only_eq(abstract_tuple::const_iterator const& lhs,
type_value_pair const& rhs)
type_value_pair const& rhs)
{
return rhs.second == nullptr
|| lhs.type()->equals(lhs.value(), rhs.second);
}
inline bool values_only_eq_v2(type_value_pair const& lhs,
abstract_tuple::const_iterator const& rhs)
{
return values_only_eq(rhs, lhs);
}
inline bool types_only_eq(abstract_tuple::const_iterator const& lhs,
type_value_pair const& rhs)
{
return lhs.type() == rhs.first;
}
inline bool types_only_eq_v2(type_value_pair const& lhs,
abstract_tuple::const_iterator const& rhs)
{
return lhs.first == rhs.type();
}
} } // namespace cppa::detail
#endif // ABSTRACT_TUPLE_HPP
......@@ -75,9 +75,9 @@ class converted_thread_context : public abstract_actor<local_actor>
void enqueue(actor* sender, any_tuple const& msg) /*override*/;
void dequeue(invoke_rules& rules) /*override*/;
void dequeue(behavior& rules) /*override*/;
void dequeue(timed_invoke_rules& rules) /*override*/;
void dequeue(partial_function& rules) /*override*/;
inline decltype(m_mailbox)& mailbox()
{
......@@ -97,7 +97,7 @@ class converted_thread_context : public abstract_actor<local_actor>
// returns true if node->msg was accepted by rules
bool dq(queue_node_ptr& node,
invoke_rules_base& rules,
partial_function& rules,
queue_node_buffer& buffer);
throw_on_exit_result throw_on_exit(any_tuple const& msg);
......
......@@ -102,7 +102,12 @@ class decorated_tuple : public abstract_tuple
return m_decorated->type_at(m_mapping[pos]);
}
std::type_info const* values_type_list() const
void const* type_token() const
{
return detail::static_type_list<ElementTypes...>::list;
}
std::type_info const* impl_type() const
{
return detail::static_type_list<ElementTypes...>::list;
}
......
......@@ -46,8 +46,8 @@ struct empty_tuple : abstract_tuple
void const* at(size_t) const;
bool equals(abstract_tuple const& other) const;
uniform_type_info const* type_at(size_t) const;
std::type_info const& impl_type() const;
std::type_info const* values_type_list() const;
std::type_info const* impl_type() const;
void const* type_token() const;
};
......
This diff is collapsed.
......@@ -68,7 +68,9 @@ class object_array : public abstract_tuple
uniform_type_info const* type_at(size_t pos) const;
std::type_info const* values_type_list() const;
void const* type_token() const;
std::type_info const* impl_type() const;
};
......
......@@ -36,7 +36,12 @@
#include "cppa/self.hpp"
#include "cppa/behavior.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/invoke_rules.hpp"
#include "cppa/partial_function.hpp"
#include "cppa/util/tbind.hpp"
#include "cppa/util/type_list.hpp"
#include "cppa/detail/invokable.hpp"
namespace cppa { namespace detail {
......@@ -47,54 +52,33 @@ struct receive_while_helper
Statement m_stmt;
template<typename S>
receive_while_helper(S&& stmt) : m_stmt(std::forward<S>(stmt))
{
}
receive_while_helper(S&& stmt) : m_stmt(std::forward<S>(stmt)) { }
void operator()(invoke_rules& rules)
void operator()(behavior& bhvr)
{
local_actor* sptr = self;
while (m_stmt())
{
sptr->dequeue(rules);
}
}
void operator()(invoke_rules&& rules)
{
invoke_rules tmp(std::move(rules));
(*this)(tmp);
while (m_stmt()) sptr->dequeue(bhvr);
}
void operator()(timed_invoke_rules& rules)
void operator()(partial_function& fun)
{
local_actor* sptr = self;
while (m_stmt())
{
sptr->dequeue(rules);
}
while (m_stmt()) sptr->dequeue(fun);
}
void operator()(timed_invoke_rules&& rules)
void operator()(behavior&& bhvr)
{
timed_invoke_rules tmp(std::move(rules));
behavior tmp{std::move(bhvr)};
(*this)(tmp);
}
template<typename Arg0, typename... Args>
void operator()(invoke_rules& rules, Arg0&& arg0, Args&&... args)
template<typename... Args>
void operator()(partial_function&& arg0, Args&&... args)
{
(*this)(rules.splice(std::forward<Arg0>(arg0)),
std::forward<Args>(args)...);
typename select_bhvr<Args...>::type tmp;
(*this)(tmp.splice(std::move(arg0), std::forward<Args>(args)...));
}
template<typename Arg0, typename... Args>
void operator()(invoke_rules&& rules, Arg0&& arg0, Args&&... args)
{
invoke_rules tmp(std::move(rules));
(*this)(tmp.splice(std::forward<Arg0>(arg0)),
std::forward<Args>(args)...);
}
};
class do_receive_helper
......@@ -102,44 +86,19 @@ class do_receive_helper
behavior m_bhvr;
inline void init(timed_invoke_rules&& bhvr)
{
m_bhvr = std::move(bhvr);
}
inline void init(invoke_rules& bhvr)
{
m_bhvr = std::move(bhvr);
}
template<typename Arg0, typename... Args>
inline void init(invoke_rules& rules, Arg0&& arg0, Args&&... args)
{
init(rules.splice(std::forward<Arg0>(arg0)),
std::forward<Args>(args)...);
}
public:
do_receive_helper(invoke_rules&& rules) : m_bhvr(std::move(rules))
{
}
do_receive_helper(timed_invoke_rules&& rules) : m_bhvr(std::move(rules))
do_receive_helper(behavior&& bhvr) : m_bhvr(std::move(bhvr))
{
}
template<typename Arg0, typename... Args>
do_receive_helper(invoke_rules&& rules, Arg0&& arg0, Args&&... args)
do_receive_helper(Arg0&& arg0, Args&&... args)
{
invoke_rules tmp(std::move(rules));
init(tmp.splice(std::forward<Arg0>(arg0)), std::forward<Args>(args)...);
m_bhvr.splice(std::forward<Arg0>(arg0), std::forward<Args>(args)...);
}
do_receive_helper(do_receive_helper&& other)
: m_bhvr(std::move(other.m_bhvr))
{
}
do_receive_helper(do_receive_helper&&) = default;
template<typename Statement>
void until(Statement&& stmt)
......@@ -147,11 +106,11 @@ class do_receive_helper
static_assert(std::is_same<bool, decltype(stmt())>::value,
"functor or function does not return a boolean");
local_actor* sptr = self;
if (m_bhvr.is_left())
if (m_bhvr.timeout().valid())
{
do
{
sptr->dequeue(m_bhvr.left());
sptr->dequeue(m_bhvr);
}
while (stmt() == false);
}
......@@ -159,7 +118,7 @@ class do_receive_helper
{
do
{
sptr->dequeue(m_bhvr.right());
sptr->dequeue(m_bhvr.get_partial_function());
}
while (stmt() == false);
}
......
......@@ -112,7 +112,12 @@ class tuple_vals : public abstract_tuple
return abstract_tuple::equals(other);
}
std::type_info const* values_type_list() const
void const* type_token() const
{
return detail::static_type_list<ElementTypes...>::list;
}
std::type_info const* impl_type() const
{
return detail::static_type_list<ElementTypes...>::list;
}
......
......@@ -79,9 +79,9 @@ class yielding_actor : public abstract_scheduled_actor
~yielding_actor() /*override*/;
void dequeue(invoke_rules& rules) /*override*/;
void dequeue(behavior& rules) /*override*/;
void dequeue(timed_invoke_rules& rules) /*override*/;
void dequeue(partial_function& rules) /*override*/;
void resume(util::fiber* from, resume_callback* callback) /*override*/;
......
......@@ -44,9 +44,7 @@ class event_based_actor : public event_based_actor_base<event_based_actor>
typedef abstract_event_based_actor::stack_element stack_element;
// has_ownership == false
void do_become(behavior* bhvr);
void do_become(invoke_rules* bhvr, bool has_ownership);
void do_become(timed_invoke_rules* bhvr, bool has_ownership);
void do_become(behavior* bhvr, bool has_ownership);
public:
......
......@@ -42,64 +42,26 @@ class event_based_actor_base : public abstract_event_based_actor
typedef abstract_event_based_actor super;
inline void become_impl(invoke_rules& rules)
{
become(std::move(rules));
}
inline void become_impl(timed_invoke_rules&& rules)
{
become(std::move(rules));
}
template<typename Head, typename... Tail>
void become_impl(invoke_rules& rules, Head&& head, Tail&&... tail)
{
become_impl(rules.splice(std::forward<Head>(head)),
std::forward<Tail>(tail)...);
}
inline Derived* d_this() { return static_cast<Derived*>(this); }
protected:
inline void become(behavior* bhvr)
{
d_this()->do_become(bhvr);
}
inline void become(invoke_rules* bhvr)
{
d_this()->do_become(bhvr, false);
}
inline void become(timed_invoke_rules* bhvr)
{
d_this()->do_become(bhvr, false);
}
inline void become(invoke_rules&& bhvr)
{
d_this()->do_become(new invoke_rules(std::move(bhvr)), true);
}
inline void become(timed_invoke_rules&& bhvr)
{
d_this()->do_become(new timed_invoke_rules(std::move(bhvr)), true);
}
inline void become(behavior&& bhvr)
template<typename... Args>
void become(partial_function&& arg0, Args&&... args)
{
if (bhvr.is_left()) become(std::move(bhvr.left()));
else become(std::move(bhvr.right()));
auto ptr = new behavior;
ptr->splice(std::move(arg0), std::forward<Args>(args)...);
d_this()->do_become(ptr, true);
}
template<typename Head, typename... Tail>
void become(invoke_rules&& rules, Head&& head, Tail&&... tail)
inline void become(behavior&& arg0)
{
invoke_rules tmp(std::move(rules));
become_impl(tmp.splice(std::forward<Head>(head)),
std::forward<Tail>(tail)...);
d_this()->do_become(new behavior(std::move(arg0)), true);
}
};
......
......@@ -32,8 +32,9 @@
#define CONTEXT_HPP
#include "cppa/actor.hpp"
#include "cppa/behavior.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/invoke_rules.hpp"
#include "cppa/partial_function.hpp"
#include "cppa/util/single_reader_queue.hpp"
namespace cppa {
......@@ -70,19 +71,19 @@ class local_actor : public actor
virtual void quit(std::uint32_t reason) = 0;
/**
* @brief Removes the first element from the queue that is matched
* by @p rules and invokes the corresponding callback.
* @brief
* @param rules
* @warning Call only from the owner of the queue.
*/
virtual void dequeue(invoke_rules& rules) = 0;
virtual void dequeue(behavior& rules) = 0;
/**
* @brief
* @brief Removes the first element from the queue that is matched
* by @p rules and invokes the corresponding callback.
* @param rules
* @warning Call only from the owner of the queue.
*/
virtual void dequeue(timed_invoke_rules& rules) = 0;
virtual void dequeue(partial_function& rules) = 0;
inline bool trap_exit() const;
......
......@@ -210,14 +210,16 @@ struct matcher<wildcard_position::nil, T...>
static inline bool tmatch(any_tuple const& tup)
{
// match implementation type if possible
auto vals = tup.values_type_list();
auto prns = detail::static_type_list<T...>::list;
if (vals == prns || *vals == *prns)
auto impl = tup.impl_type();
// the impl_type of both decorated_tuple and tuple_vals
// is &typeid(type_list<T...>)
auto tinf = detail::static_type_list<T...>::list;
if (impl == tinf || *impl == *tinf)
{
return true;
}
// always use a full dynamic match for object arrays
else if (*vals == typeid(detail::object_array)
else if (*impl == typeid(detail::object_array)
&& tup.size() == sizeof...(T))
{
auto& tarr = detail::static_types_array<T...>::arr;
......@@ -241,8 +243,9 @@ struct matcher<wildcard_position::nil, T...>
static inline bool vmatch(any_tuple const& tup, pattern<T...> const& ptrn)
{
return std::equal(tup.begin(), tup.end(), ptrn.begin(),
detail::values_only_eq);
CPPA_REQUIRE(tup.size() == sizeof...(T));
return std::equal(ptrn.begin(), ptrn.vend(), tup.begin(),
detail::values_only_eq_v2);
}
};
......@@ -277,9 +280,8 @@ struct matcher<wildcard_position::trailing, T...>
static inline bool vmatch(any_tuple const& tup, pattern<T...> const& ptrn)
{
auto begin = tup.begin();
return std::equal(begin, begin + size, ptrn.begin(),
detail::values_only_eq);
return std::equal(ptrn.begin(), ptrn.vend(), tup.begin(),
detail::values_only_eq_v2);
}
};
......@@ -334,11 +336,12 @@ struct matcher<wildcard_position::leading, T...>
static inline bool vmatch(any_tuple const& tup, pattern<T...> const& ptrn)
{
auto begin = tup.begin();
begin += (tup.size() - size);
return std::equal(begin, tup.end(),
ptrn.begin() + 1, // skip 'anything'
detail::values_only_eq);
auto tbegin = tup.begin();
// skip unmatched elements
tbegin += (tup.size() - size);
// skip leading wildcard ++(ptr.begin())
return std::equal(++(ptrn.begin()), ptrn.vend(), tbegin,
detail::values_only_eq_v2);
}
};
......
......@@ -37,8 +37,9 @@
#include "cppa/atom.hpp"
#include "cppa/pattern.hpp"
#include "cppa/anything.hpp"
#include "cppa/behavior.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/invoke_rules.hpp"
#include "cppa/partial_function.hpp"
#include "cppa/util/duration.hpp"
#include "cppa/util/type_list.hpp"
......@@ -54,28 +55,27 @@
namespace cppa { namespace detail {
class timed_invoke_rule_builder
class behavior_rvalue_builder
{
util::duration m_timeout;
public:
constexpr timed_invoke_rule_builder(util::duration const& d) : m_timeout(d)
constexpr behavior_rvalue_builder(util::duration const& d) : m_timeout(d)
{
}
template<typename F>
timed_invoke_rules operator>>(F&& f)
behavior operator>>(F&& f)
{
typedef timed_invokable_impl<F> impl;
return timed_invokable_ptr(new impl(m_timeout, std::forward<F>(f)));
return {m_timeout, std::function<void()>{std::forward<F>(f)}};
}
};
template<typename... TypeList>
class invoke_rule_builder
class rvalue_builder
{
typedef util::arg_match_t arg_match_t;
......@@ -85,9 +85,10 @@ class invoke_rule_builder
static constexpr bool is_complete =
!std::is_same<arg_match_t, typename raw_types::back>::value;
typedef typename util::if_else_c<is_complete == false,
typename util::tl_pop_back<raw_types>::type,
util::wrapped<raw_types> >::type
typedef typename util::if_else_c<
is_complete == false,
typename util::tl_pop_back<raw_types>::type,
util::wrapped<raw_types> >::type
types;
static_assert(util::tl_find<types, arg_match_t>::value == -1,
......@@ -103,13 +104,13 @@ class invoke_rule_builder
std::unique_ptr<pattern_type> m_ptr;
template<typename F>
invoke_rules cr_rules(F&& f, std::integral_constant<bool, true>)
partial_function cr_rvalue(F&& f, std::integral_constant<bool, true>)
{
return get_invokable_impl(std::forward<F>(f), std::move(m_ptr));
}
template<typename F>
invoke_rules cr_rules(F&& f, std::integral_constant<bool, false>)
partial_function cr_rvalue(F&& f, std::integral_constant<bool, false>)
{
using namespace ::cppa::util;
typedef typename get_callable_trait<F>::type ctrait;
......@@ -125,32 +126,31 @@ class invoke_rule_builder
public:
template<typename... Args>
invoke_rule_builder(Args const&... args)
: m_ptr(new pattern_type(args...))
rvalue_builder(Args const&... args) : m_ptr(new pattern_type(args...))
{
}
template<typename F>
invoke_rules operator>>(F&& f)
partial_function operator>>(F&& f)
{
std::integral_constant<bool,is_complete> token;
return cr_rules(std::forward<F>(f), token);
std::integral_constant<bool, is_complete> token;
return cr_rvalue(std::forward<F>(f), token);
}
};
class on_the_fly_invoke_rule_builder
class on_the_fly_rvalue_builder
{
public:
constexpr on_the_fly_invoke_rule_builder()
constexpr on_the_fly_rvalue_builder()
{
}
template<typename F>
invoke_rules operator>>(F&& f) const
partial_function operator>>(F&& f) const
{
using namespace ::cppa::util;
typedef typename get_callable_trait<F>::type ctrait;
......@@ -180,10 +180,10 @@ typedef typename detail::boxed<util::arg_match_t>::type boxed_arg_match_t;
constexpr boxed_arg_match_t arg_match = boxed_arg_match_t();
constexpr detail::on_the_fly_invoke_rule_builder on_arg_match;
constexpr detail::on_the_fly_rvalue_builder on_arg_match;
template<typename Arg0, typename... Args>
detail::invoke_rule_builder<typename detail::unboxed<Arg0>::type,
detail::rvalue_builder<typename detail::unboxed<Arg0>::type,
typename detail::unboxed<Args>::type...>
on(Arg0 const& arg0, Args const&... args)
{
......@@ -191,25 +191,25 @@ on(Arg0 const& arg0, Args const&... args)
}
template<typename... TypeList>
detail::invoke_rule_builder<TypeList...> on()
detail::rvalue_builder<TypeList...> on()
{
return { };
}
template<atom_value A0, typename... TypeList>
detail::invoke_rule_builder<atom_value, TypeList...> on()
detail::rvalue_builder<atom_value, TypeList...> on()
{
return { A0 };
}
template<atom_value A0, atom_value A1, typename... TypeList>
detail::invoke_rule_builder<atom_value, atom_value, TypeList...> on()
detail::rvalue_builder<atom_value, atom_value, TypeList...> on()
{
return { A0, A1 };
}
template<atom_value A0, atom_value A1, atom_value A2, typename... TypeList>
detail::invoke_rule_builder<atom_value, atom_value,
detail::rvalue_builder<atom_value, atom_value,
atom_value, TypeList...> on()
{
return { A0, A1, A2 };
......@@ -218,20 +218,20 @@ detail::invoke_rule_builder<atom_value, atom_value,
template<atom_value A0, atom_value A1,
atom_value A2, atom_value A3,
typename... TypeList>
detail::invoke_rule_builder<atom_value, atom_value, atom_value,
detail::rvalue_builder<atom_value, atom_value, atom_value,
atom_value, TypeList...> on()
{
return { A0, A1, A2, A3 };
}
template<class Rep, class Period>
constexpr detail::timed_invoke_rule_builder
after(const std::chrono::duration<Rep, Period>& d)
constexpr detail::behavior_rvalue_builder
after(std::chrono::duration<Rep, Period> const& d)
{
return { util::duration(d) };
}
inline detail::invoke_rule_builder<anything> others()
inline detail::rvalue_builder<anything> others()
{
return { };
}
......
......@@ -28,24 +28,75 @@
\******************************************************************************/
#ifndef UTIL_HPP
#define UTIL_HPP
#include "cppa/util/callable_trait.hpp"
#include "cppa/util/compare_tuples.hpp"
#include "cppa/util/conjunction.hpp"
#include "cppa/util/disjunction.hpp"
#include "cppa/util/enable_if.hpp"
#include "cppa/util/has_copy_member_fun.hpp"
#include "cppa/util/is_comparable.hpp"
#include "cppa/util/is_copyable.hpp"
#include "cppa/util/is_legal_tuple_type.hpp"
#include "cppa/util/is_one_of.hpp"
#include "cppa/util/remove_const_reference.hpp"
#include "cppa/util/replace_type.hpp"
#include "cppa/util/single_reader_queue.hpp"
#include "cppa/util/singly_linked_list.hpp"
#include "cppa/util/type_list.hpp"
#include "cppa/util/void_type.hpp"
#endif // UTIL_HPP
#ifndef PARTIAL_FUNCTION_HPP
#define PARTIAL_FUNCTION_HPP
#include <vector>
#include <memory>
#include <utility>
#include "cppa/detail/invokable.hpp"
namespace cppa {
class behavior;
class partial_function
{
public:
typedef std::unique_ptr<detail::invokable> invokable_ptr;
partial_function() = default;
partial_function(partial_function&& other);
partial_function(invokable_ptr&& ptr);
bool defined_at(any_tuple const& value);
void operator()(any_tuple const& value);
detail::invokable const* definition_at(any_tuple const& value);
detail::intermediate* get_intermediate(any_tuple const& value);
template<class... Args>
partial_function& splice(partial_function&& arg0, Args&&... args)
{
auto& vec = arg0.m_funs;
std::move(vec.begin(), vec.end(), std::back_inserter(m_funs));
return splice(std::forward<Args>(args)...);
}
inline partial_function operator,(partial_function&& arg)
{
return std::move(splice(std::move(arg)));
}
behavior operator,(behavior&& arg);
private:
// terminates recursion
inline partial_function& splice()
{
m_cache.clear();
return *this;
}
typedef std::vector<detail::invokable*> cache_entry;
typedef std::pair<void const*, cache_entry> cache_element;
std::vector<invokable_ptr> m_funs;
std::vector<cache_element> m_cache;
cache_element m_dummy; // binary search dummy
cache_entry& get_cache_entry(any_tuple const& value);
};
} // namespace cppa
#endif // PARTIAL_FUNCTION_HPP
......@@ -111,10 +111,25 @@ class pattern
typedef type_value_pair_const_iterator const_iterator;
typedef std::reverse_iterator<const_iterator> reverse_const_iterator;
const_iterator begin() const { return m_ptrs; }
inline const_iterator begin() const { return m_ptrs; }
const_iterator end() const { return m_ptrs + size; }
inline const_iterator end() const { return m_ptrs + size; }
inline reverse_const_iterator rbegin() const
{
return reverse_const_iterator{end()};
}
inline reverse_const_iterator rend() const
{
return reverse_const_iterator{begin()};
}
inline const_iterator vbegin() const { return m_vbegin; }
inline const_iterator vend() const { return m_vend; }
pattern() : m_has_values(false)
{
......@@ -124,6 +139,7 @@ class pattern
m_ptrs[i].first = arr[i];
m_ptrs[i].second = nullptr;
}
m_vbegin = m_vend = begin();
}
template<typename Arg0, typename... Args>
......@@ -152,6 +168,7 @@ class pattern
m_ptrs[i].first = arr[i];
m_ptrs[i].second = nullptr;
}
init_value_iterators();
}
inline bool has_values() const { return m_has_values; }
......@@ -174,10 +191,28 @@ class pattern
}
};
void init_value_iterators()
{
auto pred = [](type_value_pair const& tvp) { return tvp.second != 0; };
auto last = end();
m_vbegin = std::find_if(begin(), last, pred);
if (m_vbegin == last)
{
m_vbegin = m_vend = begin();
}
else
{
m_vend = std::find_if(rbegin(), rend(), pred).base();
}
}
detail::tdata<option<Types>...> m_data;
bool m_has_values;
type_value_pair m_ptrs[size];
const_iterator m_vbegin;
const_iterator m_vend;
};
template<class ExtendedType, class BasicType>
......@@ -189,10 +224,13 @@ ExtendedType* extend_pattern(BasicType const* p)
detail::tdata_set(et->m_data, p->m_data);
et->m_has_values = true;
typedef typename ExtendedType::types extended_types;
typedef typename detail::static_types_array_from_type_list<extended_types>::type tarr;
typedef typename
detail::static_types_array_from_type_list<extended_types>::type
tarr;
auto& arr = tarr::arr;
typename ExtendedType::init_helper f(et->m_ptrs, arr);
util::static_foreach<0, BasicType::size>::_(et->m_data, f);
et->init_value_iterators();
}
return et;
}
......
......@@ -97,84 +97,42 @@ auto do_receive(behavior& bhvr);
#else // CPPA_DOCUMENTATION
inline void receive(invoke_rules& bhvr) { self->dequeue(bhvr); }
inline void receive(behavior& bhvr) { self->dequeue(bhvr); }
inline void receive(timed_invoke_rules& bhvr) { self->dequeue(bhvr); }
inline void receive(partial_function& fun) { self->dequeue(fun); }
inline void receive(behavior& bhvr)
inline void receive(behavior&& arg0)
{
if (bhvr.is_left()) self->dequeue(bhvr.left());
else self->dequeue(bhvr.right());
behavior tmp{std::move(arg0)};
receive(tmp);
}
inline void receive(timed_invoke_rules&& bhvr)
{
timed_invoke_rules tmp(std::move(bhvr));
self->dequeue(tmp);
}
inline void receive(invoke_rules&& bhvr)
{
invoke_rules tmp(std::move(bhvr));
self->dequeue(tmp);
}
template<typename Head, typename... Tail>
void receive(invoke_rules&& bhvr, Head&& head, Tail&&... tail)
{
invoke_rules tmp(std::move(bhvr));
receive(tmp.splice(std::forward<Head>(head)),
std::forward<Tail>(tail)...);
}
template<typename Head, typename... Tail>
void receive(invoke_rules& bhvr, Head&& head, Tail&&... tail)
template<typename... Args>
void receive(partial_function&& arg0, Args&&... args)
{
receive(bhvr.splice(std::forward<Head>(head)),
std::forward<Tail>(tail)...);
typename detail::select_bhvr<Args...>::type tmp;
receive(tmp.splice(std::move(arg0), std::forward<Args>(args)...));
}
void receive_loop(behavior& rules);
void receive_loop(invoke_rules& rules);
void receive_loop(timed_invoke_rules& rules);
void receive_loop(partial_function& rules);
inline void receive_loop(behavior& bhvr)
inline void receive_loop(behavior&& arg0)
{
if (bhvr.is_left()) receive_loop(bhvr.left());
else receive_loop(bhvr.right());
}
inline void receive_loop(invoke_rules&& rules)
{
invoke_rules tmp(std::move(rules));
behavior tmp{std::move(arg0)};
receive_loop(tmp);
}
inline void receive_loop(timed_invoke_rules&& rules)
{
timed_invoke_rules tmp(std::move(rules));
receive_loop(tmp);
}
template<typename Head, typename... Tail>
void receive_loop(invoke_rules& rules, Head&& head, Tail&&... tail)
{
receive_loop(rules.splice(std::forward<Head>(head)),
std::forward<Tail>(tail)...);
}
template<typename Head, typename... Tail>
void receive_loop(invoke_rules&& rules, Head&& head, Tail&&... tail)
template<typename... Args>
void receive_loop(partial_function&& arg0, Args&&... args)
{
invoke_rules tmp(std::move(rules));
receive_loop(tmp.splice(std::forward<Head>(head)),
std::forward<Tail>(tail)...);
typename detail::select_bhvr<Args...>::type tmp;
receive_loop(tmp.splice(std::move(arg0), std::forward<Args>(args)...));
}
template<typename Statement>
detail::receive_while_helper<Statement>
receive_while(Statement&& stmt)
detail::receive_while_helper<Statement> receive_while(Statement&& stmt)
{
static_assert(std::is_same<bool, decltype(stmt())>::value,
"functor or function does not return a boolean");
......
......@@ -42,8 +42,7 @@ class stacked_event_based_actor : public event_based_actor_base<stacked_event_ba
typedef abstract_event_based_actor::stack_element stack_element;
void do_become(invoke_rules* behavior, bool has_ownership);
void do_become(timed_invoke_rules* behavior, bool has_ownership);
void do_become(behavior* behavior, bool has_ownership);
protected:
......
......@@ -71,7 +71,7 @@ class duration
{
}
template <class Rep, class Period>
template<class Rep, class Period>
constexpr duration(std::chrono::duration<Rep, Period> d)
: unit(get_time_unit_from_period<Period>()), count(d.count())
{
......@@ -79,6 +79,8 @@ class duration
"only seconds, milliseconds or microseconds allowed");
}
inline bool valid() const { return unit != time_unit::none; }
time_unit unit;
std::uint32_t count;
......
......@@ -33,7 +33,7 @@
namespace cppa { namespace util {
template<template <typename, typename> class Tpl, typename Arg1>
template<template<typename, typename> class Tpl, typename Arg1>
struct tbind
{
template<typename Arg2>
......
......@@ -185,7 +185,7 @@ struct tl_first_n
/**
* @brief Tests whether a predicate holds for all elements of a list.
*/
template<class List, template <typename> class Predicate>
template<class List, template<typename> class Predicate>
struct tl_forall
{
static constexpr bool value =
......@@ -193,7 +193,7 @@ struct tl_forall
&& tl_forall<typename List::tail, Predicate>::value;
};
template<template <typename> class Predicate>
template<template<typename> class Predicate>
struct tl_forall<type_list<>, Predicate>
{
static constexpr bool value = true;
......@@ -202,7 +202,7 @@ struct tl_forall<type_list<>, Predicate>
/**
* @brief Tests whether a predicate holds for some of the elements of a list.
*/
template<class List, template <typename> class Predicate>
template<class List, template<typename> class Predicate>
struct tl_exists
{
static constexpr bool value =
......@@ -210,7 +210,7 @@ struct tl_exists
|| tl_exists<typename List::tail, Predicate>::value;
};
template<template <typename> class Predicate>
template<template<typename> class Predicate>
struct tl_exists<type_list<>, Predicate>
{
static constexpr bool value = false;
......@@ -222,7 +222,7 @@ struct tl_exists<type_list<>, Predicate>
/**
* @brief Counts the number of elements in the list which satisfy a predicate.
*/
template<class List, template <typename> class Predicate>
template<class List, template<typename> class Predicate>
struct tl_count
{
static constexpr size_t value =
......@@ -230,7 +230,7 @@ struct tl_count
+ tl_count<typename List::tail, Predicate>::value;
};
template<template <typename> class Predicate>
template<template<typename> class Predicate>
struct tl_count<type_list<>, Predicate>
{
static constexpr size_t value = 0;
......@@ -241,7 +241,7 @@ struct tl_count<type_list<>, Predicate>
/**
* @brief Counts the number of elements in the list which satisfy a predicate.
*/
template<class List, template <typename> class Predicate>
template<class List, template<typename> class Predicate>
struct tl_count_not
{
static constexpr size_t value =
......@@ -249,7 +249,7 @@ struct tl_count_not
+ tl_count_not<typename List::tail, Predicate>::value;
};
template<template <typename> class Predicate>
template<template<typename> class Predicate>
struct tl_count_not<type_list<>, Predicate>
{
static constexpr size_t value = 0;
......@@ -260,7 +260,7 @@ struct tl_count_not<type_list<>, Predicate>
/**
* @brief Tests whether a predicate holds for all elements of a zipped list.
*/
template<class ZippedList, template <typename, typename> class Predicate>
template<class ZippedList, template<typename, typename> class Predicate>
struct tl_zipped_forall
{
typedef typename ZippedList::head head;
......@@ -269,7 +269,7 @@ struct tl_zipped_forall
&& tl_zipped_forall<typename ZippedList::tail, Predicate>::value;
};
template<template <typename, typename> class Predicate>
template<template<typename, typename> class Predicate>
struct tl_zipped_forall<type_list<>, Predicate>
{
static constexpr bool value = true;
......@@ -294,10 +294,10 @@ struct tl_concat<type_list<ListATypes...>, type_list<ListBTypes...> >
/**
* @brief Applies a "template function" to each element in the list.
*/
template<typename List, template <typename> class Trait>
template<typename List, template<typename> class Trait>
struct tl_apply;
template<template <typename> class Trait, typename... Elements>
template<template<typename> class Trait, typename... Elements>
struct tl_apply<type_list<Elements...>, Trait>
{
typedef type_list<typename Trait<Elements>::type...> type;
......
......@@ -44,7 +44,7 @@ class upgrade_lock_guard
public:
template<template <typename> class LockType>
template<template<typename> class LockType>
upgrade_lock_guard(LockType<UpgradeLockable>& other)
{
m_lockable = other.release();
......
......@@ -39,61 +39,46 @@ abstract_event_based_actor::abstract_event_based_actor()
{
}
void abstract_event_based_actor::dequeue(invoke_rules&)
void abstract_event_based_actor::dequeue(behavior&)
{
quit(exit_reason::unallowed_function_call);
}
void abstract_event_based_actor::dequeue(timed_invoke_rules&)
void abstract_event_based_actor::dequeue(partial_function&)
{
quit(exit_reason::unallowed_function_call);
}
void abstract_event_based_actor::handle_message(queue_node_ptr& node,
invoke_rules& behavior)
{
// no need to handle result
(void) dq(node, behavior, m_buffer);
}
void abstract_event_based_actor::handle_message(queue_node_ptr& node,
timed_invoke_rules& behavior)
void abstract_event_based_actor::handle_message(queue_node_ptr& node)
{
switch (dq(node, behavior, m_buffer))
auto& bhvr = *(m_loop_stack.back());
if (bhvr.timeout().valid())
{
case dq_timeout_occured:
switch (dq(node, bhvr.get_partial_function(), m_buffer))
{
behavior.handle_timeout();
// fall through
}
case dq_done:
{
// callback might have called become()/unbecome()
// request next timeout if needed
if (!m_loop_stack.empty())
case dq_timeout_occured:
{
bhvr.handle_timeout();
// fall through
}
case dq_done:
{
auto& back = m_loop_stack.back();
if (back.is_right())
// callback might have called become()/unbecome()
// request next timeout if needed
if (!m_loop_stack.empty())
{
request_timeout(back.right()->timeout());
auto& next_bhvr = *(m_loop_stack.back());
request_timeout(next_bhvr.timeout());
}
break;
}
break;
default: break;
}
default: break;
}
}
void abstract_event_based_actor::handle_message(queue_node_ptr& node)
{
auto& bhvr = m_loop_stack.back();
if (bhvr.is_left())
{
handle_message(node, *(bhvr.left()));
}
else
{
handle_message(node, *(bhvr.right()));
// no need to handle result
(void) dq(node, bhvr.get_partial_function(), m_buffer);
}
}
......
......@@ -129,8 +129,11 @@ int abstract_scheduled_actor::compare_exchange_state(int expected,
void abstract_scheduled_actor::request_timeout(util::duration const& d)
{
future_send(this, d, atom(":Timeout"), ++m_active_timeout_id);
m_has_pending_timeout_request = true;
if (d.valid())
{
future_send(this, d, atom(":Timeout"), ++m_active_timeout_id);
m_has_pending_timeout_request = true;
}
}
auto abstract_scheduled_actor::filter_msg(const any_tuple& msg) -> filter_result
......@@ -162,7 +165,7 @@ auto abstract_scheduled_actor::filter_msg(const any_tuple& msg) -> filter_result
}
auto abstract_scheduled_actor::dq(queue_node_ptr& node,
invoke_rules_base& rules,
partial_function& rules,
queue_node_buffer& buffer) -> dq_result
{
switch (filter_msg(node->msg))
......@@ -232,11 +235,11 @@ void scheduled_actor_dummy::quit(std::uint32_t)
{
}
void scheduled_actor_dummy::dequeue(invoke_rules&)
void scheduled_actor_dummy::dequeue(behavior&)
{
}
void scheduled_actor_dummy::dequeue(timed_invoke_rules&)
void scheduled_actor_dummy::dequeue(partial_function&)
{
}
......
......@@ -36,7 +36,7 @@ bool abstract_tuple::equals(const abstract_tuple &other) const
{
return this == &other
|| ( size() == other.size()
&& std::equal(begin(), end(), other.begin(), detail::full_eq));
&& std::equal(begin(), end(), other.begin(), detail::full_eq_v3));
}
abstract_tuple::abstract_tuple(abstract_tuple const&) : ref_counted() { }
......
......@@ -55,7 +55,7 @@ inline cppa::detail::actor_registry& registry()
namespace cppa {
actor::actor(std::uint32_t aid, const process_information_ptr& pptr)
: m_is_proxy(true), m_id(aid), m_parent_process(pptr)
: m_id(aid), m_is_proxy(true), m_parent_process(pptr)
{
if (!pptr)
{
......@@ -64,7 +64,7 @@ actor::actor(std::uint32_t aid, const process_information_ptr& pptr)
}
actor::actor(const process_information_ptr& pptr)
: m_is_proxy(false), m_id(registry().next_id()), m_parent_process(pptr)
: m_id(registry().next_id()), m_is_proxy(false), m_parent_process(pptr)
{
if (!pptr)
{
......
......@@ -69,7 +69,7 @@ void converted_thread_context::enqueue(actor* sender, const any_tuple& msg)
m_mailbox.push_back(fetch_node(sender, msg));
}
void converted_thread_context::dequeue(invoke_rules& rules) /*override*/
void converted_thread_context::dequeue(partial_function& rules) /*override*/
{
queue_node_buffer buffer;
queue_node_ptr node(m_mailbox.pop());
......@@ -79,26 +79,33 @@ void converted_thread_context::dequeue(invoke_rules& rules) /*override*/
}
}
void converted_thread_context::dequeue(timed_invoke_rules& rules) /*override*/
void converted_thread_context::dequeue(behavior& rules) /*override*/
{
auto timeout = now();
timeout += rules.timeout();
queue_node_buffer buffer;
queue_node_ptr node(m_mailbox.try_pop());
do
if (rules.timeout().valid())
{
if (!node)
auto timeout = now();
timeout += rules.timeout();
queue_node_buffer buffer;
queue_node_ptr node(m_mailbox.try_pop());
do
{
node.reset(m_mailbox.try_pop(timeout));
if (!node)
{
if (!buffer.empty()) m_mailbox.push_front(std::move(buffer));
rules.handle_timeout();
return;
node.reset(m_mailbox.try_pop(timeout));
if (!node)
{
if (!buffer.empty()) m_mailbox.push_front(std::move(buffer));
rules.handle_timeout();
return;
}
}
}
while (dq(node, rules.get_partial_function(), buffer) == false);
}
else
{
converted_thread_context::dequeue(rules.get_partial_function());
}
while (dq(node, rules, buffer) == false);
}
converted_thread_context::throw_on_exit_result
......@@ -121,7 +128,7 @@ converted_thread_context::throw_on_exit(any_tuple const& msg)
}
bool converted_thread_context::dq(queue_node_ptr& node,
invoke_rules_base& rules,
partial_function& rules,
queue_node_buffer& buffer)
{
if (m_trap_exit == false && throw_on_exit(node->msg) == normal_exit_signal)
......
......@@ -63,7 +63,12 @@ bool empty_tuple::equals(const abstract_tuple& other) const
return other.size() == 0;
}
std::type_info const* empty_tuple::values_type_list() const
void const* empty_tuple::type_token() const
{
return &typeid(empty_tuple);
}
std::type_info const* empty_tuple::impl_type() const
{
return &typeid(empty_tuple);
}
......
......@@ -30,27 +30,6 @@
#include "cppa/event_based_actor.hpp"
namespace {
template<class StackElement, class Vec, class What>
void push_to(Vec& vec, What&& bhvr)
{
// 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(std::move(bhvr));
}
else
{
vec[0] = std::move(vec[1]);
vec[1] = std::move(bhvr);
}
}
} // namespace <anonymous>
namespace cppa {
void event_based_actor::become_void()
......@@ -58,32 +37,24 @@ void event_based_actor::become_void()
m_loop_stack.clear();
}
void event_based_actor::do_become(behavior* bhvr)
void event_based_actor::do_become(behavior* bhvr, bool has_ownership)
{
if (bhvr->is_left())
reset_timeout();
request_timeout(bhvr->timeout());
stack_element se{bhvr};
if (!has_ownership) se.get_deleter().disable();
// 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 (m_loop_stack.size() < 2)
{
do_become(&(bhvr->left()), false);
m_loop_stack.push_back(std::move(se));
}
else
{
do_become(&(bhvr->right()), false);
m_loop_stack[0] = std::move(m_loop_stack[1]);
m_loop_stack[1] = std::move(se);
}
}
void event_based_actor::do_become(invoke_rules* bhvr, bool has_ownership)
{
reset_timeout();
stack_element::left_type ptr(bhvr);
if (!has_ownership) ptr.get_deleter().disable();
push_to<stack_element>(m_loop_stack, std::move(ptr));
}
void event_based_actor::do_become(timed_invoke_rules* bhvr, bool has_ownership)
{
request_timeout(bhvr->timeout());
stack_element::right_type ptr(bhvr);
if (!has_ownership) ptr.get_deleter().disable();
push_to<stack_element>(m_loop_stack, std::move(ptr));
}
} // namespace cppa
......@@ -32,11 +32,7 @@
namespace cppa { namespace detail {
invokable_base::~invokable_base()
{
}
timed_invokable::timed_invokable(const util::duration& d) : m_timeout(d)
invokable::~invokable()
{
}
......
......@@ -35,10 +35,9 @@
#include "cppa/self.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/scheduler.hpp"
#include "cppa/attachable.hpp"
#include "cppa/invoke_rules.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/scheduled_actor.hpp"
#include "cppa/detail/thread.hpp"
......
......@@ -67,7 +67,12 @@ uniform_type_info const* object_array::type_at(size_t pos) const
return m_elements[pos].type();
}
std::type_info const* object_array::values_type_list() const
void const* object_array::type_token() const
{
return &typeid(object_array);
}
std::type_info const* object_array::impl_type() const
{
return &typeid(object_array);
}
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011, 2012 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation, either version 3 of the License *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#include "cppa/config.hpp"
#include "cppa/behavior.hpp"
#include "cppa/partial_function.hpp"
#include "cppa/detail/invokable.hpp"
namespace cppa {
partial_function::partial_function(partial_function&& other)
: m_funs(std::move(other.m_funs))
{
}
partial_function::partial_function(invokable_ptr&& ptr)
{
m_funs.push_back(std::move(ptr));
}
auto partial_function::get_cache_entry(any_tuple const& value) -> cache_entry&
{
m_dummy.first = value.type_token();
auto end = m_cache.end();
// note: uses >= for comparison (not a "real" upper bound)
auto i = std::upper_bound(m_cache.begin(), end, m_dummy,
[](cache_element const& lhs,
cache_element const& rhs)
{
return lhs.first >= rhs.first;
});
// if we didn't found a cache entry ...
if (i == end || i->first != m_dummy.first)
{
// ... create one (store all invokables with matching types)
cache_entry tmp;
for (auto& fun : m_funs)
{
if (fun->types_match(value))
{
tmp.push_back(fun.get());
}
}
// m_cache is always sorted,
// due to emplace(upper_bound, ...) insertions
i = m_cache.emplace(i, std::move(m_dummy.first), std::move(tmp));
}
return i->second;
}
void partial_function::operator()(any_tuple const& value)
{
auto& v = get_cache_entry(value);
(void) std::any_of(
v.begin(), v.end(),
[&](detail::invokable* i) { return i->unsafe_invoke(value); });
}
detail::invokable const* partial_function::definition_at(any_tuple const& value)
{
auto& v = get_cache_entry(value);
auto i = std::find_if(
v.begin(), v.end(),
[&](detail::invokable* i) { return i->could_invoke(value); });
return (i != v.end()) ? *i : nullptr;
}
bool partial_function::defined_at(any_tuple const& value)
{
return definition_at(value) != nullptr;
}
detail::intermediate* partial_function::get_intermediate(any_tuple const& value)
{
detail::intermediate* result = nullptr;
for (auto& i : get_cache_entry(value))
{
if ((result = i->get_unsafe_intermediate(value)) != nullptr)
{
return result;
}
}
return nullptr;
}
behavior partial_function::operator,(behavior&& arg)
{
behavior bhvr{std::move(arg)};
bhvr.get_partial_function().m_funs = std::move(m_funs);
return bhvr;
}
} // namespace cppa
......@@ -32,7 +32,7 @@
namespace cppa {
void receive_loop(invoke_rules& rules)
void receive_loop(behavior& rules)
{
local_actor* sptr = self;
for (;;)
......@@ -41,7 +41,7 @@ void receive_loop(invoke_rules& rules)
}
}
void receive_loop(timed_invoke_rules& rules)
void receive_loop(partial_function& rules)
{
local_actor* sptr = self;
for (;;)
......
......@@ -45,22 +45,14 @@ void stacked_event_based_actor::unbecome()
}
}
void stacked_event_based_actor::do_become(invoke_rules* behavior,
void stacked_event_based_actor::do_become(behavior* bhvr,
bool has_ownership)
{
reset_timeout();
stack_element::left_type ptr(behavior);
if (!has_ownership) ptr.get_deleter().disable();
m_loop_stack.push_back(std::move(ptr));
}
void stacked_event_based_actor::do_become(timed_invoke_rules* behavior,
bool has_ownership)
{
request_timeout(behavior->timeout());
stack_element::right_type ptr(behavior);
if (!has_ownership) ptr.get_deleter().disable();
m_loop_stack.push_back(std::move(ptr));
request_timeout(bhvr->timeout());
stack_element se{bhvr};
if (!has_ownership) se.get_deleter().disable();
m_loop_stack.push_back(std::move(se));
}
} // namespace cppa
......@@ -93,7 +93,7 @@ void yielding_actor::yield_until_not_empty()
}
}
void yielding_actor::dequeue(invoke_rules& rules)
void yielding_actor::dequeue(partial_function& rules)
{
queue_node_buffer buffer;
yield_until_not_empty();
......@@ -105,33 +105,41 @@ void yielding_actor::dequeue(invoke_rules& rules)
}
}
void yielding_actor::dequeue(timed_invoke_rules& rules)
void yielding_actor::dequeue(behavior& rules)
{
queue_node_buffer buffer;
// try until a message was successfully dequeued
request_timeout(rules.timeout());
for (;;)
if (rules.timeout().valid())
{
//if (m_mailbox.empty() && has_pending_timeout() == false)
//{
// request_timeout(rules.timeout());
//}
yield_until_not_empty();
queue_node_ptr node(m_mailbox.pop());
switch (dq(node, rules, buffer))
queue_node_buffer buffer;
// try until a message was successfully dequeued
request_timeout(rules.timeout());
for (;;)
{
case dq_done:
//if (m_mailbox.empty() && has_pending_timeout() == false)
//{
// request_timeout(rules.timeout());
//}
yield_until_not_empty();
queue_node_ptr node(m_mailbox.pop());
switch (dq(node, rules.get_partial_function(), buffer))
{
return;
}
case dq_timeout_occured:
{
rules.handle_timeout();
return;
case dq_done:
{
return;
}
case dq_timeout_occured:
{
rules.handle_timeout();
return;
}
default: break;
}
default: break;
}
}
else
{
// suppress virtual function call
yielding_actor::dequeue(rules.get_partial_function());
}
}
void yielding_actor::resume(util::fiber* from, resume_callback* callback)
......
......@@ -3,7 +3,6 @@
#include <iostream>
#include "test.hpp"
#include "cppa/util.hpp"
#include "cppa/cppa.hpp"
......
#include <string>
#include <sstream>
#include <functional>
#include "test.hpp"
......@@ -11,6 +12,7 @@
#include "cppa/pattern.hpp"
#include "cppa/announce.hpp"
#include "cppa/tuple_cast.hpp"
#include "cppa/partial_function.hpp"
#include "cppa/util/enable_if.hpp"
#include "cppa/util/disable_if.hpp"
......@@ -19,9 +21,12 @@
#include "cppa/util/is_primitive.hpp"
#include "cppa/util/is_mutable_ref.hpp"
#include "cppa/detail/invokable.hpp"
#include "cppa/detail/types_array.hpp"
#include "cppa/detail/decorated_tuple.hpp"
#include <boost/progress.hpp>
using namespace cppa;
template<typename Arr>
......@@ -59,6 +64,35 @@ void match_test(T const& value)
);
}
template<class Testee>
void invoke_test(std::vector<any_tuple>& test_tuples, Testee& x)
{
boost::progress_timer t;
for (int i = 0; i < 1000000; ++i)
{
for (auto& t : test_tuples) x(t);
}
}
inline detail::intermediate* get_i(partial_function& pf, any_tuple const& value)
{
return pf.get_intermediate(value);
}
template<class Testee>
void intermediate_test(std::vector<any_tuple>& test_tuples, Testee& x)
{
boost::progress_timer t;
for (int i = 0; i < 1000000; ++i)
{
for (auto& t : test_tuples)
{
auto i = get_i(x, t);
if (i) i->invoke();
}
}
}
size_t test__pattern()
{
CPPA_TEST(test__pattern);
......
......@@ -9,13 +9,11 @@
#include "test.hpp"
#include "cppa/on.hpp"
#include "cppa/util.hpp"
#include "cppa/tuple.hpp"
#include "cppa/pattern.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/to_string.hpp"
#include "cppa/tuple_cast.hpp"
#include "cppa/invoke_rules.hpp"
#include "cppa/intrusive_ptr.hpp"
#include "cppa/uniform_type_info.hpp"
......
......@@ -5,7 +5,6 @@
#include "test.hpp"
#include "cppa/util.hpp"
#include "cppa/util/at.hpp"
#include "cppa/util/element_at.hpp"
#include "cppa/uniform_type_info.hpp"
......
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