Commit 04fc1827 authored by Joseph Noir's avatar Joseph Noir

Merge branch 'unstable' into topic/opencl

parents 16cb9399 05d61a8d
......@@ -124,6 +124,7 @@ set(LIBCPPA_SRC
src/ipv4_io_stream.cpp
src/local_actor.cpp
src/logging.cpp
src/mailbox_element.cpp
src/match.cpp
src/memory.cpp
src/memory_managed.cpp
......@@ -137,8 +138,6 @@ set(LIBCPPA_SRC
src/primitive_variant.cpp
src/process_information.cpp
src/protocol.cpp
src/receive.cpp
src/recursive_queue_node.cpp
src/ref_counted.cpp
src/response_handle.cpp
src/ripemd_160.cpp
......
......@@ -24,7 +24,6 @@ cppa/detail/atom_val.hpp
cppa/detail/behavior_impl.hpp
cppa/detail/behavior_stack.hpp
cppa/detail/boxed.hpp
cppa/detail/channel.hpp
cppa/detail/container_tuple_view.hpp
cppa/detail/decorated_names_map.hpp
cppa/detail/decorated_tuple.hpp
......@@ -48,7 +47,8 @@ cppa/detail/pseudo_tuple.hpp
cppa/detail/ptype_to_type.hpp
cppa/detail/receive_loop_helper.hpp
cppa/detail/receive_policy.hpp
cppa/detail/recursive_queue_node.hpp
cppa/mailbox_element.hpp
cppa/mailbox_based.hpp
cppa/detail/scheduled_actor_dummy.hpp
cppa/detail/serialize_tuple.hpp
cppa/detail/singleton_manager.hpp
......@@ -68,7 +68,6 @@ cppa/detail/unboxed.hpp
cppa/detail/uniform_type_info_map.hpp
cppa/detail/value_guard.hpp
cppa/detail/yield_interface.hpp
cppa/either.hpp
cppa/enable_weak_ptr.hpp
cppa/event_based_actor.hpp
cppa/exception.hpp
......@@ -80,7 +79,6 @@ cppa/group.hpp
cppa/guard_expr.hpp
cppa/intrusive/blocking_single_reader_queue.hpp
cppa/intrusive/single_reader_queue.hpp
cppa/intrusive_fwd_ptr.hpp
cppa/intrusive_ptr.hpp
cppa/local_actor.hpp
cppa/logging.hpp
......@@ -145,7 +143,6 @@ cppa/util/duration.hpp
cppa/util/element_at.hpp
cppa/util/fiber.hpp
cppa/util/fixed_vector.hpp
cppa/util/if_else.hpp
cppa/util/int_list.hpp
cppa/util/is_array_of.hpp
cppa/util/is_builtin.hpp
......@@ -168,7 +165,6 @@ cppa/util/rm_ref.hpp
cppa/util/scope_guard.hpp
cppa/util/shared_lock_guard.hpp
cppa/util/shared_spinlock.hpp
cppa/util/static_foreach.hpp
cppa/util/tbind.hpp
cppa/util/type_list.hpp
cppa/util/type_pair.hpp
......@@ -244,8 +240,7 @@ src/partial_function.cpp
src/primitive_variant.cpp
src/process_information.cpp
src/protocol.cpp
src/receive.cpp
src/recursive_queue_node.cpp
src/mailbox_element.cpp
src/ref_counted.cpp
src/response_handle.cpp
src/ripemd_160.cpp
......@@ -302,3 +297,8 @@ cppa/extend.hpp
cppa/detail/sync_request_bouncer.hpp
cppa/memory_cached.hpp
cppa/singletons.hpp
cppa/threaded.hpp
cppa/util/dptr.hpp
cppa/util/is_callable.hpp
cppa/util/get_result_type.hpp
cppa/util/rebindable_reference.hpp
......@@ -86,7 +86,7 @@ class actor : public channel {
* @pre <tt>id.valid()</tt>
*/
virtual void sync_enqueue(const actor_ptr& sender,
message_id_t id,
message_id id,
any_tuple msg) = 0;
/**
......@@ -96,7 +96,7 @@ class actor : public channel {
* its state to @p pending in response to the enqueue operation.
*/
virtual bool chained_sync_enqueue(const actor_ptr& sender,
message_id_t id,
message_id id,
any_tuple msg);
/**
......@@ -110,7 +110,7 @@ class actor : public channel {
* otherwise (actor already exited) @p false.
* @warning The actor takes ownership of @p ptr.
*/
virtual bool attach(attachable_ptr ptr);
bool attach(attachable_ptr ptr);
/**
* @brief Convenience function that attaches the functor
......@@ -129,7 +129,7 @@ class actor : public channel {
/**
* @brief Detaches the first attached object that matches @p what.
*/
virtual void detach(const attachable::token& what);
void detach(const attachable::token& what);
/**
* @brief Links this actor to @p other.
......
......@@ -59,10 +59,10 @@ class actor_companion_mixin : public Base {
public:
typedef std::unique_ptr<detail::recursive_queue_node,detail::disposer> message_pointer;
typedef std::unique_ptr<mailbox_element,detail::disposer> message_pointer;
template<typename... Args>
actor_companion_mixin(Args&&... args) : super(std::forward<Args>(args)...) {
template<typename... Ts>
actor_companion_mixin(Ts&&... args) : super(std::forward<Ts>(args)...) {
m_self.reset(detail::memory::create<companion>(this));
}
......@@ -89,9 +89,9 @@ class actor_companion_mixin : public Base {
* @note While the message handler is invoked, @p self will point
* to the companion object to enable send() and reply().
*/
template<typename... Args>
void set_message_handler(Args&&... matchExpressions) {
m_message_handler = match_expr_convert(std::forward<Args>(matchExpressions)...);
template<typename... Ts>
void set_message_handler(Ts&&... args) {
m_message_handler = match_expr_convert(std::forward<Ts>(args)...);
}
/**
......@@ -112,8 +112,8 @@ class actor_companion_mixin : public Base {
class companion : public local_actor {
friend class actor_companion_mixin;
typedef util::shared_spinlock lock_type;
typedef std::unique_ptr<detail::recursive_queue_node,detail::disposer> node_ptr;
public:
......@@ -129,37 +129,33 @@ class actor_companion_mixin : public Base {
void enqueue(const actor_ptr& sender, any_tuple msg) {
util::shared_lock_guard<lock_type> guard(m_lock);
if (m_parent) {
m_parent->new_message(new_node_ptr(sender, std::move(msg)));
}
if (m_parent) push_message(sender, std::move(msg));
}
void sync_enqueue(const actor_ptr& sender,
message_id_t id,
message_id id,
any_tuple msg) {
util::shared_lock_guard<lock_type> guard(m_lock);
if (m_parent) {
m_parent->new_message(new_node_ptr(sender, std::move(msg), id));
}
if (m_parent) push_message(sender, std::move(msg), id);
}
bool initialized() const { return true; }
void quit(std::uint32_t) {
throw std::runtime_error("ActorWidgetMixin::Gateway::exit "
"is forbidden, use Qt's widget "
"management instead!");
throw std::runtime_error("Using actor_companion_mixin::quit "
"is prohibited; use Qt's widget "
"management instead.");
}
void dequeue(behavior&) { throw_no_recv(); }
void dequeue(partial_function&) { throw_no_recv(); }
void dequeue(behavior&) {
throw_no_recv();
}
void dequeue_response(behavior&, message_id_t) {
void dequeue_response(behavior&, message_id) {
throw_no_recv();
}
void become_waiting_for(behavior&&, message_id_t) {
void become_waiting_for(behavior, message_id) {
throw_no_become();
}
......@@ -169,9 +165,11 @@ class actor_companion_mixin : public Base {
private:
template<typename... Args>
node_ptr new_node_ptr(Args&&... args) {
return node_ptr(detail::memory::create<detail::recursive_queue_node>(std::forward<Args>(args)...));
template<typename... Ts>
void push_message(Ts&&... args) {
message_pointer ptr;
ptr.reset(detail::memory::create<mailbox_element>(std::forward<Ts>(args)...));
m_parent->new_message(std::move(ptr));
}
void throw_no_become() {
......@@ -186,12 +184,18 @@ class actor_companion_mixin : public Base {
"receive() API");
}
// guards access to m_parent
lock_type m_lock;
// set to nullptr if this companion became detached
actor_companion_mixin* m_parent;
};
// used as 'self' before calling message handler
intrusive_ptr<companion> m_self;
// user-defined message handler for incoming messages
partial_function m_message_handler;
};
......
......@@ -46,7 +46,7 @@ class actor_proxy_cache;
* @brief Represents a remote actor.
* @extends actor
*/
class actor_proxy : public extend<actor,actor_proxy>::with<enable_weak_ptr> {
class actor_proxy : public extend<actor>::with<enable_weak_ptr> {
typedef combined_type super;
......
......@@ -108,9 +108,9 @@ bool announce(const std::type_info& tinfo, uniform_type_info* utype);
* @see {@link announce_4.cpp announce example 4}
* @returns A pair of @p c_ptr and the created meta informations.
*/
template<class C, class Parent, typename... Args>
template<class C, class Parent, typename... Ts>
std::pair<C Parent::*, util::abstract_uniform_type_info<C>*>
compound_member(C Parent::*c_ptr, const Args&... args) {
compound_member(C Parent::*c_ptr, const Ts&... args) {
return {c_ptr, new detail::default_uniform_type_info_impl<C>(args...)};
}
......@@ -123,9 +123,9 @@ compound_member(C Parent::*c_ptr, const Args&... args) {
* @see {@link announce_4.cpp announce example 4}
* @returns A pair of @p c_ptr and the created meta informations.
*/
template<class C, class Parent, typename... Args>
template<class C, class Parent, typename... Ts>
std::pair<C& (Parent::*)(), util::abstract_uniform_type_info<C>*>
compound_member(C& (Parent::*getter)(), const Args&... args) {
compound_member(C& (Parent::*getter)(), const Ts&... args) {
return {getter, new detail::default_uniform_type_info_impl<C>(args...)};
}
......@@ -140,12 +140,12 @@ compound_member(C& (Parent::*getter)(), const Args&... args) {
* @returns A pair of @p c_ptr and the created meta informations.
*/
template<class Parent, typename GRes,
typename SRes, typename SArg, typename... Args>
typename SRes, typename SArg, typename... Ts>
std::pair<std::pair<GRes (Parent::*)() const, SRes (Parent::*)(SArg)>,
util::abstract_uniform_type_info<typename util::rm_ref<GRes>::type>*>
compound_member(const std::pair<GRes (Parent::*)() const,
SRes (Parent::*)(SArg) >& gspair,
const Args&... args) {
const Ts&... args) {
typedef typename util::rm_ref<GRes>::type mtype;
return {gspair, new detail::default_uniform_type_info_impl<mtype>(args...)};
}
......@@ -157,10 +157,9 @@ compound_member(const std::pair<GRes (Parent::*)() const,
* @returns @c true if @p T was added to the libcppa type system,
* @c false otherwise.
*/
template<typename T, typename... Args>
inline bool announce(const Args&... args) {
return announce(typeid(T),
new detail::default_uniform_type_info_impl<T>(args...));
template<typename T, typename... Ts>
inline bool announce(const Ts&... args) {
return announce(typeid(T), new detail::default_uniform_type_info_impl<T>(args...));
}
/**
......
......@@ -74,14 +74,14 @@ class any_tuple {
/**
* @brief Creates a tuple from @p t.
*/
template<typename... Args>
any_tuple(const cow_tuple<Args...>& t) : m_vals(t.vals()) { }
template<typename... Ts>
any_tuple(const cow_tuple<Ts...>& arg) : m_vals(arg.vals()) { }
/**
* @brief Creates a tuple and moves the content from @p t.
*/
template<typename... Args>
any_tuple(cow_tuple<Args...>&& t) : m_vals(std::move(t.m_vals)) { }
template<typename... Ts>
any_tuple(cow_tuple<Ts...>&& arg) : m_vals(std::move(arg.m_vals)) { }
/**
* @brief Move constructor.
......@@ -181,10 +181,13 @@ class any_tuple {
inline const std::type_info* type_token() const;
/**
* @brief Checks whether this
* @brief Checks whether this tuple is dynamically typed, i.e.,
* its types were not known during compile time.
*/
inline bool dynamically_typed() const;
/** @cond PRIVATE */
template<typename T>
static inline any_tuple view(T&& value);
......@@ -194,6 +197,8 @@ class any_tuple {
explicit any_tuple(detail::abstract_tuple*);
/** @endcond */
private:
data_ptr m_vals;
......@@ -244,9 +249,9 @@ inline bool operator!=(const any_tuple& lhs, const any_tuple& rhs) {
* @brief Creates an {@link any_tuple} containing the elements @p args.
* @param args Values to initialize the tuple elements.
*/
template<typename... Args>
inline any_tuple make_any_tuple(Args&&... args) {
return make_cow_tuple(std::forward<Args>(args)...);
template<typename... Ts>
inline any_tuple make_any_tuple(Ts&&... args) {
return make_cow_tuple(std::forward<Ts>(args)...);
}
/******************************************************************************
......
......@@ -40,7 +40,11 @@ namespace cppa {
/**
* @brief The value type of atoms.
*/
enum class atom_value : std::uint64_t { dirty_little_hack = 37337 };
enum class atom_value : std::uint64_t {
/** @cond PRIVATE */
dirty_little_hack = 37337
/** @endcond */
};
/**
* @brief Returns @p what as a string representation.
......
......@@ -39,7 +39,6 @@
#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"
......@@ -56,10 +55,18 @@ class behavior {
public:
/** @cond PRIVATE */
typedef intrusive_ptr<detail::behavior_impl> impl_ptr;
inline auto as_behavior_impl() const -> const impl_ptr&;
inline behavior(impl_ptr ptr);
static constexpr bool may_have_timeout = true;
/** @endcond */
behavior() = default;
behavior(behavior&&) = default;
behavior(const behavior&) = default;
......@@ -68,49 +75,39 @@ class behavior {
behavior(const partial_function& fun);
inline behavior(impl_ptr ptr) : m_impl(std::move(ptr)) { }
template<typename F>
behavior(const timeout_definition<F>& arg)
: m_impl(detail::new_default_behavior_impl(detail::dummy_match_expr{},
arg.timeout,
arg.handler) ) { }
behavior(const timeout_definition<F>& arg);
template<typename F>
behavior(util::duration d, F f)
: m_impl(detail::new_default_behavior_impl(detail::dummy_match_expr{}, d, f)) { }
template<typename... Cases>
behavior(const match_expr<Cases...>& arg0)
: m_impl(detail::new_default_behavior_impl(arg0, util::duration(), []() { })) { }
behavior(util::duration d, F f);
template<typename... Cases, typename Arg1, typename... Args>
behavior(const match_expr<Cases...>& arg0, const Arg1& arg1, const Args&... args)
: m_impl(detail::match_expr_concat(arg0, arg1, args...)) { }
template<typename... Cases, typename... Ts>
behavior(const match_expr<Cases...>& arg, const Ts&... args);
inline void handle_timeout() {
m_impl->handle_timeout();
}
inline const util::duration& timeout() const {
return m_impl->timeout();
}
/**
* @brief Invokes the timeout callback.
*/
inline void handle_timeout();
inline bool undefined() const {
return m_impl == nullptr || m_impl->timeout().valid() == false;
}
/**
* @brief Returns the duration after which receives using
* this behavior should time out.
*/
inline const util::duration& timeout() const;
/**
* @copydoc partial_function::operator()()
*/
template<typename T>
inline bool operator()(T&& arg) {
return (m_impl) && m_impl->invoke(std::forward<T>(arg));
}
inline bool operator()(T&& arg);
/**
* @brief Adds a continuation to this behavior that is executed
* whenever this behavior was successfully applied to
* a message.
*/
template<typename F>
inline behavior add_continuation(F fun) {
return {new detail::continuation_decorator<F>(std::move(fun), m_impl)};
}
const impl_ptr& as_behavior_impl() const { return m_impl; }
inline behavior add_continuation(F fun);
private:
......@@ -118,12 +115,60 @@ class behavior {
};
template<typename... Lhs, typename F>
inline behavior operator,(const match_expr<Lhs...>& lhs,
/**
* @brief Creates a behavior from a match expression and a timeout definition.
* @relates behavior
*/
template<typename... Cases, typename F>
inline behavior operator,(const match_expr<Cases...>& lhs,
const timeout_definition<F>& rhs) {
return match_expr_convert(lhs, rhs);
}
/******************************************************************************
* inline and template member function implementations *
******************************************************************************/
template<typename F>
behavior::behavior(const timeout_definition<F>& arg)
: m_impl(detail::new_default_behavior_impl(detail::dummy_match_expr{},
arg.timeout,
arg.handler) ) { }
template<typename F>
behavior::behavior(util::duration d, F f)
: m_impl(detail::new_default_behavior_impl(detail::dummy_match_expr{}, d, f)) { }
template<typename... Cases, typename... Ts>
behavior::behavior(const match_expr<Cases...>& arg, const Ts&... args)
: m_impl(detail::match_expr_concat(arg, args...)) { }
inline behavior::behavior(impl_ptr ptr) : m_impl(std::move(ptr)) { }
inline void behavior::handle_timeout() {
m_impl->handle_timeout();
}
inline const util::duration& behavior::timeout() const {
return m_impl->timeout();
}
template<typename T>
inline bool behavior::operator()(T&& arg) {
return (m_impl) && m_impl->invoke(std::forward<T>(arg));
}
inline auto behavior::as_behavior_impl() const -> const impl_ptr& {
return m_impl;
}
template<typename F>
inline behavior behavior::add_continuation(F fun) {
return {new detail::continuation_decorator<F>(std::move(fun), m_impl)};
}
} // namespace cppa
#endif // CPPA_BEHAVIOR_HPP
......@@ -67,12 +67,6 @@ class channel : public ref_counted {
virtual ~channel();
private:
// channel is a sealed class and the only
// allowed subclasses are actor and group.
channel() = default;
};
/**
......@@ -84,8 +78,8 @@ typedef intrusive_ptr<channel> channel_ptr;
/**
* @brief Convenience alias.
*/
template<typename T>
using enable_if_channel = std::enable_if<std::is_base_of<channel,T>::value>;
template<typename T, typename R = void>
using enable_if_channel = std::enable_if<std::is_base_of<channel,T>::value,R>;
} // namespace cppa
......
......@@ -34,7 +34,6 @@
#include <stack>
#include "cppa/config.hpp"
#include "cppa/either.hpp"
#include "cppa/extend.hpp"
#include "cppa/stacked.hpp"
#include "cppa/scheduled_actor.hpp"
......@@ -64,22 +63,22 @@ class context_switching_actor : public extend<scheduled_actor,context_switching_
*/
context_switching_actor(std::function<void()> fun);
resume_result resume(util::fiber* from, actor_ptr& next_job); //override
resume_result resume(util::fiber* from, actor_ptr& next_job);
scheduled_actor_type impl_type();
protected:
typedef std::chrono::high_resolution_clock::time_point timeout_type;
timeout_type init_timeout(const util::duration& rel_time);
detail::recursive_queue_node* await_message();
mailbox_element* await_message();
detail::recursive_queue_node* await_message(const timeout_type& abs_time);
mailbox_element* await_message(const timeout_type& abs_time);
private:
detail::recursive_queue_node* receive_node();
// required by util::fiber
static void trampoline(void* _this);
......
......@@ -86,6 +86,7 @@ class cow_tuple<Head, Tail...> {
public:
typedef util::type_list<Head, Tail...> types;
typedef cow_ptr<detail::abstract_tuple> cow_ptr_type;
static constexpr size_t num_elements = sizeof...(Tail) + 1;
......@@ -96,33 +97,24 @@ class cow_tuple<Head, Tail...> {
* @brief Initializes the cow_tuple with @p args.
* @param args Initialization values.
*/
template<typename... Args>
cow_tuple(const Head& arg0, Args&&... args)
: m_vals(new data_type(arg0, std::forward<Args>(args)...)) { }
template<typename... Ts>
cow_tuple(const Head& arg, Ts&&... args)
: m_vals(new data_type(arg, std::forward<Ts>(args)...)) { }
/**
* @brief Initializes the cow_tuple with @p args.
* @param args Initialization values.
*/
template<typename... Args>
cow_tuple(Head&& arg0, Args&&... args)
: m_vals(new data_type(std::move(arg0), std::forward<Args>(args)...)) { }
template<typename... Ts>
cow_tuple(Head&& arg, Ts&&... args)
: m_vals(new data_type(std::move(arg), std::forward<Ts>(args)...)) { }
cow_tuple(cow_tuple&&) = default;
cow_tuple(const cow_tuple&) = default;
cow_tuple& operator=(cow_tuple&&) = default;
cow_tuple& operator=(const cow_tuple&) = default;
inline static cow_tuple from(cow_ptr_type ptr) {
return {priv_ctor{}, std::move(ptr)};
}
inline static cow_tuple from(cow_ptr_type ptr,
const util::fixed_vector<size_t, num_elements>& mv) {
return {priv_ctor{}, decorated_type::create(std::move(ptr), mv)};
}
inline static cow_tuple offset_subtuple(cow_ptr_type ptr, size_t offset) {
static cow_tuple offset_subtuple(cow_ptr_type ptr, size_t offset) {
CPPA_REQUIRE(offset > 0);
return {priv_ctor{}, decorated_type::create(std::move(ptr), offset)};
}
......@@ -156,10 +148,23 @@ class cow_tuple<Head, Tail...> {
return m_vals->type_at(p);
}
/** @cond PRIVATE */
static cow_tuple from(cow_ptr_type ptr) {
return {priv_ctor{}, std::move(ptr)};
}
static cow_tuple from(cow_ptr_type ptr,
const util::fixed_vector<size_t, num_elements>& mv) {
return {priv_ctor{}, decorated_type::create(std::move(ptr), mv)};
}
inline const cow_ptr<detail::abstract_tuple>& vals() const {
return m_vals;
}
/** @endcond */
};
template<typename TypeList>
......@@ -206,10 +211,10 @@ typename util::at<N, Ts...>::type& get_ref(cow_tuple<Ts...>& tup) {
* @returns A cow_tuple object containing the values @p args.
* @relates cow_tuple
*/
template<typename... Args>
cow_tuple<typename detail::strip_and_convert<Args>::type...>
make_cow_tuple(Args&&... args) {
return {std::forward<Args>(args)...};
template<typename... Ts>
cow_tuple<typename detail::strip_and_convert<Ts>::type...>
make_cow_tuple(Ts&&... args) {
return {std::forward<Ts>(args)...};
}
/**
......
......@@ -48,6 +48,7 @@
#include "cppa/behavior.hpp"
#include "cppa/announce.hpp"
#include "cppa/sb_actor.hpp"
#include "cppa/threaded.hpp"
#include "cppa/scheduler.hpp"
#include "cppa/to_string.hpp"
#include "cppa/any_tuple.hpp"
......@@ -191,11 +192,20 @@
*
* @defgroup MessageHandling Message handling.
*
* This is the beating heart of @p libcppa. Actor programming is all about
* message handling.
* @brief This is the beating heart of @p libcppa. Actor programming is
* all about message handling.
*
* A message in @p libcppa is a n-tuple of values (with size >= 1). You can use
* almost every type in a messages.
* almost every type in a messages - as long as it is announced, i.e., known
* by libcppa's type system.
*
* @defgroup BlockingAPI Blocking API.
*
* @brief Blocking functions to receive messages.
*
* The blocking API of libcppa is intended to be used for migrating
* previously threaded applications. When writing new code, you should use
* ibcppas nonblocking become/unbecome API.
*
* @section Send Send messages
*
......@@ -414,15 +424,14 @@ namespace cppa {
namespace detail {
template<typename T>
inline void send_impl(T* whom, any_tuple&& what) {
if (whom) self->send_message(whom, std::move(what));
inline void send_impl(T* ptr, any_tuple&& arg) {
if (ptr) self->send_message(ptr, std::move(arg));
}
template<typename T, typename... Ts>
inline void send_tpl_impl(T* whom, Ts&&... what) {
inline void send_tpl_impl(T* ptr, Ts&&... args) {
static_assert(sizeof...(Ts) > 0, "no message to send");
if (whom) self->send_message(whom,
make_any_tuple(std::forward<Ts>(what)...));
if (ptr) self->send_message(ptr, make_any_tuple(std::forward<Ts>(args)...));
}
} // namespace detail
......@@ -438,7 +447,7 @@ inline void send_tpl_impl(T* whom, Ts&&... what) {
* @param what Message content as tuple.
*/
template<class C, typename... Ts>
inline typename std::enable_if<std::is_base_of<channel, C>::value>::type
inline typename enable_if_channel<C>::type
send_tuple(const intrusive_ptr<C>& whom, any_tuple what) {
detail::send_impl(whom.get(), std::move(what));
}
......@@ -450,9 +459,9 @@ send_tuple(const intrusive_ptr<C>& whom, any_tuple what) {
* @pre <tt>sizeof...(Ts) > 0</tt>
*/
template<class C, typename... Ts>
inline typename std::enable_if<std::is_base_of<channel, C>::value>::type
send(const intrusive_ptr<C>& whom, Ts&&... what) {
detail::send_tpl_impl(whom.get(), std::forward<Ts>(what)...);
inline typename enable_if_channel<C>::type
send(const intrusive_ptr<C>& whom, Ts&&... args) {
detail::send_tpl_impl(whom.get(), std::forward<Ts>(args)...);
}
/**
......@@ -464,7 +473,7 @@ send(const intrusive_ptr<C>& whom, Ts&&... what) {
* @pre <tt>sizeof...(Ts) > 0</tt>
*/
template<class C, typename... Ts>
inline typename std::enable_if<std::is_base_of<channel, C>::value>::type
inline typename enable_if_channel<C>::type
send_tuple_as(const actor_ptr& from, const intrusive_ptr<C>& whom, any_tuple what) {
if (whom) whom->enqueue(from.get(), std::move(what));
}
......@@ -478,7 +487,7 @@ send_tuple_as(const actor_ptr& from, const intrusive_ptr<C>& whom, any_tuple wha
* @pre <tt>sizeof...(Ts) > 0</tt>
*/
template<class C, typename... Ts>
inline typename std::enable_if<std::is_base_of<channel, C>::value>::type
inline typename enable_if_channel<C>::type
send_as(const actor_ptr& from, const intrusive_ptr<C>& whom, Ts&&... what) {
send_tuple_as(from, whom, make_any_tuple(std::forward<Ts>(what)...));
}
......@@ -495,8 +504,7 @@ send_as(const actor_ptr& from, const intrusive_ptr<C>& whom, Ts&&... what) {
* @returns @p whom.
*/
template<class C>
inline typename std::enable_if<std::is_base_of<channel, C>::value,
const intrusive_ptr<C>& >::type
inline typename enable_if_channel<C,const intrusive_ptr<C>&>::type
operator<<(const intrusive_ptr<C>& whom, any_tuple what) {
send_tuple(whom, std::move(what));
return whom;
......@@ -683,18 +691,20 @@ inline void delayed_reply(const std::chrono::duration<Rep, Period>& rtime,
delayed_reply_tuple(rtime, make_any_tuple(std::forward<Ts>(what)...));
}
/** @} */
/**
* @}
*/
// matches "send(this, ...)" and "send(self, ...)"
inline void send_tuple(local_actor* whom, any_tuple what) {
inline void send_tuple(channel* whom, any_tuple what) {
detail::send_impl(whom, std::move(what));
}
template<typename... Ts>
inline void send(local_actor* whom, Ts&&... args) {
inline void send(channel* whom, Ts&&... args) {
detail::send_tpl_impl(whom, std::forward<Ts>(args)...);
}
inline const self_type& operator<<(const self_type& s, any_tuple what) {
detail::send_impl(s.get(), std::move(what));
detail::send_impl(static_cast<channel*>(s.get()), std::move(what));
return s;
}
inline actor_ptr eval_sopts(spawn_options opts, actor_ptr ptr) {
......@@ -732,7 +742,14 @@ actor_ptr spawn(Ts&&... args) {
*/
template<class Impl, spawn_options Options = no_spawn_options, typename... Ts>
actor_ptr spawn(Ts&&... args) {
auto rawptr = detail::memory::create<Impl>(std::forward<Ts>(args)...);
static_assert(std::is_base_of<event_based_actor,Impl>::value,
"Impl is not a derived type of event_based_actor");
scheduled_actor* rawptr;
if (has_detach_flag(Options)) {
typedef typename extend<Impl>::template with<threaded> derived;
rawptr = detail::memory::create<derived>(std::forward<Ts>(args)...);
}
else rawptr = detail::memory::create<Impl>(std::forward<Ts>(args)...);
return eval_sopts(Options, get_scheduler()->exec(Options, rawptr));
}
......@@ -844,15 +861,24 @@ void shutdown(); // note: implemented in singleton_manager.cpp
*/
inline void quit_actor(const actor_ptr& whom, std::uint32_t reason) {
CPPA_REQUIRE(reason != exit_reason::normal);
send(whom, atom("EXIT"), reason);
send(whom.get(), atom("EXIT"), reason);
}
/**
* @brief Sets the actor's behavior and discards the previous behavior
* unless {@link keep_behavior} is given as first argument.
*/
template<typename... Ts>
inline void become(Ts&&... args) {
self->become(std::forward<Ts>(args)...);
}
inline void unbecome() { self->unbecome(); }
/**
* @brief Returns to a previous behavior if available.
*/
inline void unbecome() {
self->unbecome();
}
struct actor_ostream {
......@@ -883,9 +909,11 @@ inline const actor_ostream& operator<<(const actor_ostream& o, const any_tuple&
}
template<typename T>
inline typename std::enable_if< !std::is_convertible<T,std::string>::value
inline typename std::enable_if<
!std::is_convertible<T,std::string>::value
&& !std::is_convertible<T,any_tuple>::value,
const actor_ostream&>::type
const actor_ostream&
>::type
operator<<(const actor_ostream& o, T&& arg) {
return o.write(std::to_string(std::forward<T>(arg)));
}
......
......@@ -40,7 +40,7 @@
#include "cppa/config.hpp"
#include "cppa/behavior.hpp"
#include "cppa/message_id.hpp"
#include "cppa/detail/recursive_queue_node.hpp"
#include "cppa/mailbox_element.hpp"
namespace cppa { namespace detail {
......@@ -54,14 +54,14 @@ class behavior_stack
behavior_stack(const behavior_stack&) = delete;
behavior_stack& operator=(const behavior_stack&) = delete;
typedef std::pair<behavior,message_id_t> element_type;
typedef std::pair<behavior,message_id> element_type;
public:
behavior_stack() = default;
// @pre expected_response.valid()
option<behavior&> sync_handler(message_id_t expected_response);
option<behavior&> sync_handler(message_id expected_response);
// erases the last asynchronous message handler
void pop_async_back();
......@@ -69,7 +69,7 @@ class behavior_stack
void clear();
// erases the synchronous response handler associated with @p rid
void erase(message_id_t rid) {
void erase(message_id rid) {
erase_if([=](const element_type& e) { return e.second == rid; });
}
......@@ -81,7 +81,7 @@ class behavior_stack
}
inline void push_back(behavior&& what,
message_id_t response_id = message_id_t::invalid) {
message_id response_id = message_id::invalid) {
m_elements.emplace_back(std::move(what), response_id);
}
......@@ -90,7 +90,7 @@ class behavior_stack
}
template<class Policy, class Client>
bool invoke(Policy& policy, Client* client, recursive_queue_node* node) {
bool invoke(Policy& policy, Client* client, mailbox_element* node) {
CPPA_REQUIRE(!empty());
CPPA_REQUIRE(client != nullptr);
CPPA_REQUIRE(node != nullptr);
......@@ -122,7 +122,7 @@ class behavior_stack
template<class Policy, class Client>
void exec(Policy& policy, Client* client) {
while (!empty()) {
invoke(policy, client, client->await_message());
invoke(policy, client, policy.fetch_message(client));
cleanup();
}
}
......
......@@ -434,44 +434,44 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T
// terminates recursion
inline void push_back() { }
template<typename R, class C, typename... Args>
void push_back(R C::* memptr, Args&&... args) {
template<typename R, class C, typename... Ts>
void push_back(R C::* memptr, Ts&&... args) {
m_members.push_back(new_member_tinfo(memptr));
push_back(std::forward<Args>(args)...);
push_back(std::forward<Ts>(args)...);
}
// pr.first = member pointer
// pr.second = meta object to handle pr.first
template<typename R, class C, typename... Args>
template<typename R, class C, typename... Ts>
void push_back(const std::pair<R C::*, util::abstract_uniform_type_info<R>*>& pr,
Args&&... args) {
Ts&&... args) {
m_members.push_back(new_member_tinfo(pr.first, unique_uti(pr.second)));
push_back(std::forward<Args>(args)...);
push_back(std::forward<Ts>(args)...);
}
// pr.first = getter / setter pair
// pr.second = meta object to handle pr.first
template<typename GRes, typename SRes, typename SArg, typename C, typename... Args>
template<typename GRes, typename SRes, typename SArg, typename C, typename... Ts>
void push_back(const std::pair<GRes (C::*)() const, SRes (C::*)(SArg)>& pr,
Args&&... args) {
Ts&&... args) {
m_members.push_back(new_member_tinfo(pr.first, pr.second));
push_back(std::forward<Args>(args)...);
push_back(std::forward<Ts>(args)...);
}
// pr.first = getter / setter pair
// pr.second = meta object to handle pr.first
template<typename GRes, typename SRes, typename SArg, typename C, typename... Args>
template<typename GRes, typename SRes, typename SArg, typename C, typename... Ts>
void push_back(const std::pair<std::pair<GRes (C::*)() const, SRes (C::*)(SArg)>, util::abstract_uniform_type_info<typename util::rm_ref<GRes>::type>*>& pr,
Args&&... args) {
Ts&&... args) {
m_members.push_back(new_member_tinfo(pr.first.first, pr.first.second, unique_uti(pr.second)));
push_back(std::forward<Args>(args)...);
push_back(std::forward<Ts>(args)...);
}
public:
template<typename... Args>
default_uniform_type_info_impl(Args&&... args) {
push_back(std::forward<Args>(args)...);
template<typename... Ts>
default_uniform_type_info_impl(Ts&&... args) {
push_back(std::forward<Ts>(args)...);
}
default_uniform_type_info_impl() {
......
......@@ -59,8 +59,8 @@ class empty_tuple : public singleton_mixin<empty_tuple,abstract_tuple> {
empty_tuple();
inline void initialize() /*override*/ { ref(); }
inline void destroy() /*override*/ { deref(); }
inline void initialize() { ref(); }
inline void destroy() { deref(); }
};
......
......@@ -47,10 +47,10 @@ class event_based_actor_impl : public event_based_actor {
public:
template<typename... Args>
event_based_actor_impl(InitFun fun, CleanupFun cfun, Args&&... args)
template<typename... Ts>
event_based_actor_impl(InitFun fun, CleanupFun cfun, Ts&&... args)
: m_init(std::move(fun)), m_on_exit(std::move(cfun))
, m_members(std::forward<Args>(args)...) { }
, m_members(std::forward<Ts>(args)...) { }
void init() { apply(m_init); }
......@@ -71,9 +71,9 @@ class event_based_actor_impl : public event_based_actor {
f(args...);
}
template<typename F, typename... Args>
void apply(F& f, Args... args) {
apply(f, args..., &get_ref<sizeof...(Args)>(m_members));
template<typename F, typename... Ts>
void apply(F& f, Ts... args) {
apply(f, args..., &get_ref<sizeof...(Ts)>(m_members));
}
typedef std::integral_constant<size_t, 0> zero_t;
......@@ -102,11 +102,9 @@ class event_based_actor_factory {
event_based_actor_factory(InitFun fun, CleanupFun cfun)
: m_init(std::move(fun)), m_on_exit(std::move(cfun)) { }
template<typename... Args>
actor_ptr spawn(Args&&... args) {
auto ptr = memory::create<impl>(m_init,
m_on_exit,
std::forward<Args>(args)...);
template<typename... Ts>
actor_ptr spawn(Ts&&... args) {
auto ptr = memory::create<impl>(m_init, m_on_exit, std::forward<Ts>(args)...);
return get_scheduler()->exec(no_spawn_options, ptr);
}
......
......@@ -43,7 +43,7 @@
namespace cppa { namespace detail {
// default: <true, false, F>
template<bool IsFunctionPtr, bool HasArguments, typename F, typename... Args>
template<bool IsFunctionPtr, bool HasArguments, typename F, typename... Ts>
class ftor_behavior : public scheduled_actor {
F m_fun;
......@@ -56,15 +56,15 @@ class ftor_behavior : public scheduled_actor {
};
template<typename F, typename... Args>
class ftor_behavior<true, true, F, Args...> : public scheduled_actor {
template<typename F, typename... Ts>
class ftor_behavior<true, true, F, Ts...> : public scheduled_actor {
static_assert(sizeof...(Args) > 0, "sizeof...(Args) == 0");
static_assert(sizeof...(Ts) > 0, "sizeof...(Ts) == 0");
F m_fun;
typedef typename tdata_from_type_list<
typename util::tl_map<util::type_list<Args...>,
typename util::tl_map<util::type_list<Ts...>,
implicit_conversions>::type>::type
tdata_type;
......@@ -72,7 +72,7 @@ class ftor_behavior<true, true, F, Args...> : public scheduled_actor {
public:
ftor_behavior(F ptr, const Args&... args) : m_fun(ptr), m_args(args...) { }
ftor_behavior(F ptr, const Ts&... args) : m_fun(ptr), m_args(args...) { }
virtual void act() {
util::apply_args(m_fun, m_args, util::get_indices(m_args));
......@@ -95,15 +95,15 @@ class ftor_behavior<false, false, F> : public scheduled_actor {
};
template<typename F, typename... Args>
class ftor_behavior<false, true, F, Args...> : public scheduled_actor {
template<typename F, typename... Ts>
class ftor_behavior<false, true, F, Ts...> : public scheduled_actor {
static_assert(sizeof...(Args) > 0, "sizeof...(Args) == 0");
static_assert(sizeof...(Ts) > 0, "sizeof...(Ts) == 0");
F m_fun;
typedef typename tdata_from_type_list<
typename util::tl_map<util::type_list<Args...>,
typename util::tl_map<util::type_list<Ts...>,
implicit_conversions>::type>::type
tdata_type;
......@@ -111,10 +111,10 @@ class ftor_behavior<false, true, F, Args...> : public scheduled_actor {
public:
ftor_behavior(const F& f, const Args&... args) : m_fun(f), m_args(args...) {
ftor_behavior(const F& f, const Ts&... args) : m_fun(f), m_args(args...) {
}
ftor_behavior(F&& f,const Args&... args) : m_fun(std::move(f))
ftor_behavior(F&& f,const Ts&... args) : m_fun(std::move(f))
, m_args(args...) {
}
......@@ -143,31 +143,25 @@ scheduled_actor* get_behavior(std::integral_constant<bool,false>, F&& ftor) {
return new ftor_behavior<false, false, ftype>(std::forward<F>(ftor));
}
template<typename F, typename Arg0, typename... Args>
scheduled_actor* get_behavior(std::integral_constant<bool,true>,
F fptr,
const Arg0& arg0,
const Args&... args) {
static_assert(std::is_convertible<decltype(fptr(arg0, args...)), scheduled_actor*>::value == false,
template<typename F, typename T, typename... Ts>
scheduled_actor* get_behavior(std::true_type, F fptr, const T& arg, const Ts&... args) {
static_assert(std::is_convertible<decltype(fptr(arg, args...)), scheduled_actor*>::value == false,
"Spawning a function returning an actor_behavior? "
"Are you sure that you do not want to spawn the behavior "
"returned by that function?");
typedef ftor_behavior<true, true, F, Arg0, Args...> impl;
return new impl(fptr, arg0, args...);
typedef ftor_behavior<true, true, F, T, Ts...> impl;
return new impl(fptr, arg, args...);
}
template<typename F, typename Arg0, typename... Args>
scheduled_actor* get_behavior(std::integral_constant<bool,false>,
F ftor,
const Arg0& arg0,
const Args&... args) {
static_assert(std::is_convertible<decltype(ftor(arg0, args...)), scheduled_actor*>::value == false,
template<typename F, typename T, typename... Ts>
scheduled_actor* get_behavior(std::false_type, F ftor, const T& arg, const Ts&... args) {
static_assert(std::is_convertible<decltype(ftor(arg, args...)), scheduled_actor*>::value == false,
"Spawning a functor returning an actor_behavior? "
"Are you sure that you do not want to spawn the behavior "
"returned by that functor?");
typedef typename util::rm_ref<F>::type ftype;
typedef ftor_behavior<false, true, ftype, Arg0, Args...> impl;
return new impl(std::forward<F>(ftor), arg0, args...);
typedef ftor_behavior<false, true, ftype, T, Ts...> impl;
return new impl(std::forward<F>(ftor), arg, args...);
}
} } // namespace cppa::detail
......
......@@ -33,6 +33,7 @@
#include <new>
#include <vector>
#include <memory>
#include <utility>
#include <typeinfo>
#include <iostream>
......@@ -40,6 +41,8 @@
#include "cppa/config.hpp"
#include "cppa/ref_counted.hpp"
namespace cppa { class mailbox_element; }
namespace cppa { namespace detail {
namespace {
......@@ -49,8 +52,6 @@ constexpr size_t s_cache_size = 10240; // cache about 10kb per thread
} // namespace <anonymous>
class recursive_queue_node;
class instance_wrapper {
public:
......@@ -158,6 +159,12 @@ class basic_memory_cache : public memory_cache {
};
struct disposer {
inline void operator()(memory_managed* ptr) const {
ptr->request_deletion();
}
};
class memory {
memory() = delete;
......@@ -171,11 +178,11 @@ class memory {
* @brief Allocates storage, initializes a new object, and returns
* the new instance.
*/
template<typename T, typename... Args>
static inline T* create(Args&&... args) {
template<typename T, typename... Ts>
static T* create(Ts&&... args) {
auto mc = get_or_set_cache_map_entry<T>();
auto p = mc->new_instance();
auto result = new (p.second) T (std::forward<Args>(args)...);
auto result = new (p.second) T (std::forward<Ts>(args)...);
result->outer_memory = p.first;
return result;
}
......@@ -198,12 +205,6 @@ class memory {
};
struct disposer {
inline void operator()(memory_managed* ptr) const {
ptr->request_deletion();
}
};
} } // namespace cppa::detail
#endif // CPPA_MEMORY_HPP
......@@ -39,6 +39,7 @@
#include "cppa/util/type_list.hpp"
#include "cppa/util/apply_args.hpp"
#include "cppa/util/left_or_right.hpp"
#include "cppa/util/get_result_type.hpp"
#include "cppa/detail/tdata.hpp"
......@@ -49,7 +50,7 @@ inline bool is_defined_at(Fun& f, Tuple& tup, util::int_list<Is...>) {
return f.defined_at(get_cv_aware<Is>(tup)...);
}
template<typename ProjectionFuns, typename... Args>
template<typename ProjectionFuns, typename... Ts>
struct collected_args_tuple {
typedef typename tdata_from_type_list<
typename util::tl_zip<
......@@ -59,7 +60,7 @@ struct collected_args_tuple {
util::rm_option
>::type,
typename util::tl_map<
util::type_list<Args...>,
util::type_list<Ts...>,
mutable_gref_wrapped
>::type,
util::left_or_right
......@@ -71,7 +72,7 @@ struct collected_args_tuple {
/**
* @brief Projection implemented by a set of functors.
*/
template<class ProjectionFuns, typename... Args>
template<class ProjectionFuns, typename... Ts>
class projection {
public:
......@@ -90,10 +91,10 @@ class projection {
* @brief Invokes @p fun with a projection of <tt>args...</tt> and stores
* the result of @p fun in @p result.
*/
template<class PartialFun>
bool invoke(PartialFun& fun, typename PartialFun::result_type& result, Args... args) const {
typename collected_args_tuple<ProjectionFuns,Args...>::type pargs;
if (collect(pargs, m_funs, std::forward<Args>(args)...)) {
template<class PartFun>
bool invoke(PartFun& fun, typename PartFun::result_type& result, Ts... args) const {
typename collected_args_tuple<ProjectionFuns,Ts...>::type pargs;
if (collect(pargs, m_funs, std::forward<Ts>(args)...)) {
auto indices = util::get_indices(pargs);
if (is_defined_at(fun, pargs, indices)) {
result = util::apply_args(fun, pargs, indices);
......@@ -106,11 +107,11 @@ class projection {
/**
* @brief Invokes @p fun with a projection of <tt>args...</tt>.
*/
template<class PartialFun>
bool operator()(PartialFun& fun, Args... args) const {
typename collected_args_tuple<ProjectionFuns,Args...>::type pargs;
template<class PartFun>
bool operator()(PartFun& fun, Ts... args) const {
typename collected_args_tuple<ProjectionFuns,Ts...>::type pargs;
auto indices = util::get_indices(pargs);
if (collect(pargs, m_funs, std::forward<Args>(args)...)) {
if (collect(pargs, m_funs, std::forward<Ts>(args)...)) {
if (is_defined_at(fun, pargs, indices)) {
util::apply_args(fun, pargs, indices);
return true;
......@@ -123,13 +124,13 @@ class projection {
* @brief Invokes @p fun with a projection of <tt>args...</tt> and stores
* the result of @p fun in @p result.
*/
template<class PartialFun>
inline bool operator()(PartialFun& fun, typename PartialFun::result_type& result, Args... args) const {
template<class PartFun>
inline bool operator()(PartFun& fun, typename PartFun::result_type& result, Ts... args) const {
return invoke(fun, result, args...);
}
template<class PartialFun>
inline bool operator()(PartialFun& fun, const util::void_type&, Args... args) const {
template<class PartFun>
inline bool operator()(PartFun& fun, const util::void_type&, Ts... args) const {
return (*this)(fun, args...);
}
......@@ -166,11 +167,11 @@ class projection {
return true;
}
template<class TData, class Trans, typename T0, typename... Ts>
template<class TData, class Trans, typename U, typename... Us>
static inline bool collect(TData& td, const Trans& tr,
T0&& arg0, Ts&&... args) {
return store(td.head, fetch(tr.head, std::forward<T0>(arg0)))
&& collect(td.tail(), tr.tail(), std::forward<Ts>(args)...);
U&& arg, Us&&... args) {
return store(td.head, fetch(tr.head, std::forward<U>(arg)))
&& collect(td.tail(), tr.tail(), std::forward<Us>(args)...);
}
fun_container m_funs;
......@@ -186,8 +187,8 @@ class projection<util::empty_type_list> {
projection(const tdata<>&) { }
projection(const projection&) = default;
template<class PartialFun>
bool operator()(PartialFun& fun) const {
template<class PartFun>
bool operator()(PartFun& fun) const {
if (fun.defined_at()) {
fun();
return true;
......@@ -195,8 +196,8 @@ class projection<util::empty_type_list> {
return false;
}
template<class PartialFun>
bool operator()(PartialFun& fun, const util::void_type&) const {
template<class PartFun>
bool operator()(PartFun& fun, const util::void_type&) const {
if (fun.defined_at()) {
fun();
return true;
......@@ -204,8 +205,8 @@ class projection<util::empty_type_list> {
return false;
}
template<class PartialFun>
bool operator()(PartialFun& fun, typename PartialFun::result_type& res) const {
template<class PartFun>
bool operator()(PartFun& fun, typename PartFun::result_type& res) const {
if (fun.defined_at()) {
res = fun();
return true;
......@@ -218,9 +219,9 @@ class projection<util::empty_type_list> {
template<class ProjectionFuns, class List>
struct projection_from_type_list;
template<class ProjectionFuns, typename... Args>
struct projection_from_type_list<ProjectionFuns, util::type_list<Args...> > {
typedef projection<ProjectionFuns, Args...> type;
template<class ProjectionFuns, typename... Ts>
struct projection_from_type_list<ProjectionFuns, util::type_list<Ts...> > {
typedef projection<ProjectionFuns, Ts...> type;
};
} } // namespace cppa::detail
......
......@@ -35,35 +35,33 @@
#include "cppa/primitive_type.hpp"
#include "cppa/util/if_else.hpp"
#include "cppa/util/wrapped.hpp"
namespace cppa { namespace detail {
// maps the primitive_type PT to the corresponding type
template<primitive_type PT>
struct ptype_to_type :
// signed integers
util::if_else_c<PT == pt_int8, std::int8_t,
util::if_else_c<PT == pt_int16, std::int16_t,
util::if_else_c<PT == pt_int32, std::int32_t,
util::if_else_c<PT == pt_int64, std::int64_t,
util::if_else_c<PT == pt_uint8, std::uint8_t,
// unsigned integers
util::if_else_c<PT == pt_uint16, std::uint16_t,
util::if_else_c<PT == pt_uint32, std::uint32_t,
util::if_else_c<PT == pt_uint64, std::uint64_t,
// floating points
util::if_else_c<PT == pt_float, float,
util::if_else_c<PT == pt_double, double,
util::if_else_c<PT == pt_long_double, long double,
// strings
util::if_else_c<PT == pt_u8string, std::string,
util::if_else_c<PT == pt_u16string, std::u16string,
util::if_else_c<PT == pt_u32string, std::u32string,
// default case
void > > > > > > > > > > > > > > {
};
struct ptype_to_type : util::wrapped<void> { };
// integer types
template<> struct ptype_to_type<pt_int8 > : util::wrapped<std::int8_t > { };
template<> struct ptype_to_type<pt_uint8 > : util::wrapped<std::uint8_t > { };
template<> struct ptype_to_type<pt_int16 > : util::wrapped<std::int16_t > { };
template<> struct ptype_to_type<pt_uint16> : util::wrapped<std::uint16_t> { };
template<> struct ptype_to_type<pt_int32 > : util::wrapped<std::int32_t > { };
template<> struct ptype_to_type<pt_uint32> : util::wrapped<std::uint32_t> { };
template<> struct ptype_to_type<pt_int64 > : util::wrapped<std::int64_t > { };
template<> struct ptype_to_type<pt_uint64> : util::wrapped<std::uint64_t> { };
// floating points
template<> struct ptype_to_type<pt_float> : util::wrapped<float> { };
template<> struct ptype_to_type<pt_double> : util::wrapped<double> { };
template<> struct ptype_to_type<pt_long_double> : util::wrapped<long double> { };
// strings
template<> struct ptype_to_type<pt_u8string > : util::wrapped<std::string > { };
template<> struct ptype_to_type<pt_u16string> : util::wrapped<std::u16string> { };
template<> struct ptype_to_type<pt_u32string> : util::wrapped<std::u32string> { };
} } // namespace cppa::detail
......
......@@ -51,24 +51,15 @@ struct receive_while_helper {
template<typename S>
receive_while_helper(S&& stmt) : m_stmt(std::forward<S>(stmt)) { }
void operator()(behavior& bhvr) {
template<typename... Ts>
void operator()(Ts&&... args) {
static_assert(sizeof...(Ts) > 0,
"operator() requires at least one argument");
behavior tmp = match_expr_convert(std::forward<Ts>(args)...);
local_actor* sptr = self;
while (m_stmt()) sptr->dequeue(bhvr);
while (m_stmt()) sptr->dequeue(tmp);
}
void operator()(partial_function& fun) {
local_actor* sptr = self;
while (m_stmt()) sptr->dequeue(fun);
}
template<typename Arg0, typename... Args>
void operator()(Arg0&& arg0, Args&&... args) {
auto tmp = match_expr_convert(std::forward<Arg0>(arg0),
std::forward<Args>(args)...);
(*this)(tmp);
}
};
template<typename T>
......@@ -81,21 +72,11 @@ class receive_for_helper {
receive_for_helper(T& first, const T& last) : begin(first), end(last) { }
void operator()(behavior& bhvr) {
template<typename... Ts>
void operator()(Ts&&... args) {
auto tmp = match_expr_convert(std::forward<Ts>(args)...);
local_actor* sptr = self;
for ( ; begin != end; ++begin) sptr->dequeue(bhvr);
}
void operator()(partial_function& fun) {
local_actor* sptr = self;
for ( ; begin != end; ++begin) sptr->dequeue(fun);
}
template<typename Arg0, typename... Args>
void operator()(Arg0&& arg0, Args&&... args) {
auto tmp = match_expr_convert(std::forward<Arg0>(arg0),
std::forward<Args>(args)...);
(*this)(tmp);
for ( ; begin != end; ++begin) sptr->dequeue(tmp);
}
};
......@@ -106,10 +87,7 @@ class do_receive_helper {
public:
template<typename... Args>
do_receive_helper(Args&&... args)
: m_bhvr(match_expr_convert(std::forward<Args>(args)...)) {
}
inline do_receive_helper(behavior&& bhvr) : m_bhvr(std::move(bhvr)) { }
do_receive_helper(do_receive_helper&&) = default;
......
......@@ -41,10 +41,10 @@
#include "cppa/to_string.hpp"
#include "cppa/message_id.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/mailbox_element.hpp"
#include "cppa/partial_function.hpp"
#include "cppa/detail/memory.hpp"
#include "cppa/detail/recursive_queue_node.hpp"
namespace cppa { namespace detail {
......@@ -62,8 +62,8 @@ class receive_policy {
public:
typedef recursive_queue_node* pointer;
typedef std::unique_ptr<recursive_queue_node,disposer> smart_pointer;
typedef mailbox_element* pointer;
typedef std::unique_ptr<mailbox_element,disposer> smart_pointer;
enum handle_message_result {
hm_timeout_msg,
......@@ -76,7 +76,7 @@ class receive_policy {
template<class Client, class Fun>
bool invoke_from_cache(Client* client,
Fun& fun,
message_id_t awaited_response = message_id_t()) {
message_id awaited_response = message_id{}) {
std::integral_constant<receive_policy_flag,Client::receive_flag> policy;
auto i = m_cache.begin();
auto e = m_cache.end();
......@@ -108,7 +108,7 @@ class receive_policy {
bool invoke(Client* client,
pointer node_ptr,
Fun& fun,
message_id_t awaited_response = message_id_t()) {
message_id awaited_response = message_id()) {
smart_pointer node(node_ptr);
std::integral_constant<receive_policy_flag,Client::receive_flag> policy;
switch (this->handle_message(client, node.get(), fun,
......@@ -176,7 +176,7 @@ class receive_policy {
}
template<class Client>
void receive(Client* client, behavior& bhvr, message_id_t mid) {
void receive(Client* client, behavior& bhvr, message_id mid) {
CPPA_REQUIRE(mid.is_response());
if (!invoke_from_cache(client, bhvr, mid)) {
if (bhvr.timeout().valid()) {
......@@ -195,12 +195,17 @@ class receive_policy {
}
}
template<class Client>
mailbox_element* fetch_message(Client* client) {
return client->await_message();
}
private:
typedef typename rp_flag<rp_nestable>::type nestable;
typedef typename rp_flag<rp_sequential>::type sequential;
std::list<std::unique_ptr<recursive_queue_node,disposer> > m_cache;
std::list<std::unique_ptr<mailbox_element,disposer> > m_cache;
template<class Client>
inline void handle_timeout(Client* client, behavior& bhvr) {
......@@ -231,7 +236,7 @@ class receive_policy {
template<class Client>
filter_result filter_msg(Client* client, pointer node) {
const any_tuple& msg = node->msg;
auto message_id = node->mid;
auto mid = node->mid;
auto& arr = detail::static_types_array<atom_value,std::uint32_t>::arr;
if ( msg.size() == 2
&& msg.type_at(0) == arr[0]
......@@ -239,7 +244,7 @@ class receive_policy {
auto v0 = msg.get_as<atom_value>(0);
auto v1 = msg.get_as<std::uint32_t>(1);
if (v0 == atom("EXIT")) {
CPPA_REQUIRE(!message_id.valid());
CPPA_REQUIRE(!mid.valid());
if (client->m_trap_exit == false) {
if (v1 != exit_reason::normal) {
client->quit(v1);
......@@ -249,7 +254,7 @@ class receive_policy {
}
}
else if (v0 == atom("SYNC_TOUT")) {
CPPA_REQUIRE(!message_id.valid());
CPPA_REQUIRE(!mid.valid());
return client->waits_for_timeout(v1) ? timeout_message
: expired_timeout_message;
}
......@@ -257,11 +262,11 @@ class receive_policy {
else if ( msg.size() == 1
&& msg.type_at(0) == arr[0]
&& msg.get_as<atom_value>(0) == atom("TIMEOUT")
&& message_id.is_response()) {
&& mid.is_response()) {
return timeout_response_message;
}
if (message_id.is_response()) {
return (client->awaits(message_id)) ? sync_response
if (mid.is_response()) {
return (client->awaits(mid)) ? sync_response
: expired_sync_response;
}
return ordinary_message;
......@@ -340,7 +345,7 @@ class receive_policy {
handle_message_result handle_message(Client* client,
pointer node,
Fun& fun,
message_id_t awaited_response,
message_id awaited_response,
Policy policy ) {
bool handle_sync_failure_on_mismatch = true;
if (hm_should_skip(node, policy)) {
......
......@@ -38,14 +38,13 @@ namespace cppa { namespace detail {
struct scheduled_actor_dummy : scheduled_actor {
scheduled_actor_dummy();
void enqueue(const actor_ptr&, any_tuple);
void sync_enqueue(const actor_ptr&, message_id_t, any_tuple);
void sync_enqueue(const actor_ptr&, message_id, any_tuple);
resume_result resume(util::fiber*, actor_ptr&);
void quit(std::uint32_t);
void dequeue(behavior&);
void dequeue(partial_function&);
void dequeue_response(behavior&, message_id_t);
void dequeue_response(behavior&, message_id);
void do_become(behavior&&, bool);
void become_waiting_for(behavior&&, message_id_t);
void become_waiting_for(behavior, message_id);
bool has_behavior();
scheduled_actor_type impl_type();
};
......
......@@ -50,8 +50,8 @@ class singleton_mixin : public Base {
protected:
template<typename... Args>
singleton_mixin(Args&&... args) : Base(std::forward<Args>(args)...) { }
template<typename... Ts>
singleton_mixin(Ts&&... args) : Base(std::forward<Ts>(args)...) { }
virtual ~singleton_mixin() { }
......
......@@ -37,7 +37,7 @@
#include "cppa/any_tuple.hpp"
#include "cppa/message_id.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/detail/recursive_queue_node.hpp"
#include "cppa/mailbox_element.hpp"
namespace cppa { namespace detail {
......@@ -45,7 +45,7 @@ struct sync_request_bouncer {
std::uint32_t rsn;
constexpr sync_request_bouncer(std::uint32_t r)
: rsn(r == exit_reason::not_exited ? exit_reason::normal : r) { }
inline void operator()(const actor_ptr& sender, const message_id_t& mid) const {
inline void operator()(const actor_ptr& sender, const message_id& mid) const {
CPPA_REQUIRE(rsn != exit_reason::not_exited);
if (mid.is_request() && sender != nullptr) {
actor_ptr nobody;
......@@ -54,7 +54,7 @@ struct sync_request_bouncer {
make_any_tuple(atom("EXITED"), rsn));
}
}
inline void operator()(const recursive_queue_node& e) const {
inline void operator()(const mailbox_element& e) const {
(*this)(e.sender.get(), e.mid);
}
};
......
......@@ -42,6 +42,7 @@
#include "cppa/util/wrapped.hpp"
#include "cppa/util/type_list.hpp"
#include "cppa/util/arg_match_t.hpp"
#include "cppa/util/rebindable_reference.hpp"
#include "cppa/detail/boxed.hpp"
#include "cppa/detail/types_array.hpp"
......@@ -113,6 +114,11 @@ struct unbox_ref<std::reference_wrapper<T> > {
typedef typename std::remove_const<T>::type type;
};
template<typename T>
struct unbox_ref<util::rebindable_reference<T> > {
typedef typename std::remove_const<T>::type type;
};
/*
* "enhanced" std::tuple
*/
......@@ -136,9 +142,9 @@ struct tdata<> {
constexpr tdata() { }
// swallow any number of additional boxed or void_type arguments silently
template<typename... Args>
tdata(Args&&...) {
typedef util::type_list<typename util::rm_ref<Args>::type...> incoming;
template<typename... Ts>
tdata(Ts&&...) {
typedef util::type_list<typename util::rm_ref<Ts>::type...> incoming;
typedef typename util::tl_filter_not_type<incoming, tdata>::type iargs;
static_assert(util::tl_forall<iargs, boxed_or_void>::value,
"Additional unboxed arguments provided");
......@@ -239,9 +245,10 @@ struct tdata<Head, Tail...> : tdata<Tail...> {
typedef Head head_type;
typedef tdata<Tail...> tail_type;
typedef typename util::if_else_c< (sizeof...(Tail) > 0),
typedef typename std::conditional<
(sizeof...(Tail) > 0),
typename tdata<Tail...>::back_type,
util::wrapped<Head>
Head
>::type
back_type;
......@@ -252,10 +259,10 @@ struct tdata<Head, Tail...> : tdata<Tail...> {
tdata(const Head& arg) : super(), head(arg) { }
tdata(Head&& arg) : super(), head(std::move(arg)) { }
template<typename Arg0, typename Arg1, typename... Args>
tdata(Arg0&& arg0, Arg1&& arg1, Args&&... args)
: super(std::forward<Arg1>(arg1), std::forward<Args>(args)...)
, head(td_filter<Head>(std::forward<Arg0>(arg0))) {
template<typename T0, typename T1, typename... Ts>
tdata(T0&& arg0, T1&& arg1, Ts&&... args)
: super(std::forward<T1>(arg1), std::forward<Ts>(args)...)
, head(td_filter<Head>(std::forward<T0>(arg0))) {
}
tdata(const tdata&) = default;
......@@ -285,10 +292,10 @@ struct tdata<Head, Tail...> : tdata<Tail...> {
return *this;
}
template<typename Arg0, typename... Args>
inline void set(Arg0&& arg0, Args&&... args) {
head = std::forward<Arg0>(arg0);
super::set(std::forward<Args>(args)...);
template<typename T, typename... Ts>
inline void set(T&& arg, Ts&&... args) {
head = std::forward<T>(arg);
super::set(std::forward<Ts>(args)...);
}
inline size_t size() const { return num_elements; }
......@@ -317,10 +324,8 @@ struct tdata<Head, Tail...> : tdata<Tail...> {
case 2: return ptr_to(super::super::head);
case 3: return ptr_to(super::super::super::head);
case 4: return ptr_to(super::super::super::super::head);
case 5: return ptr_to(super::super::super::super::super::head);
default: return super::at(p - 1);
default: return super::super::super::super::super::at(p - 5);
}
//return (p == 0) ? ptr_to(head) : super::at(p - 1);
}
inline void* mutable_at(size_t p) {
......@@ -335,40 +340,47 @@ struct tdata<Head, Tail...> : tdata<Tail...> {
# else
return const_cast<void*>(at(p));
# endif
}
inline const uniform_type_info* type_at(size_t p) const {
return (p == 0) ? utype_of(head) : super::type_at(p-1);
CPPA_REQUIRE(p < num_elements);
switch (p) {
case 0: return utype_of(head);
case 1: return utype_of(super::head);
case 2: return utype_of(super::super::head);
case 3: return utype_of(super::super::super::head);
case 4: return utype_of(super::super::super::super::head);
default: return super::super::super::super::super::type_at(p - 5);
}
}
Head& _back(std::integral_constant<size_t, 0>) {
Head& _back(std::integral_constant<size_t,0>) {
return head;
}
template<size_t Pos>
back_type& _back(std::integral_constant<size_t, Pos>) {
std::integral_constant<size_t, Pos - 1> token;
back_type& _back(std::integral_constant<size_t,Pos>) {
std::integral_constant<size_t,Pos-1> token;
return super::_back(token);
}
back_type& back() {
std::integral_constant<size_t, sizeof...(Tail)> token;
std::integral_constant<size_t,sizeof...(Tail)> token;
return _back(token);
}
const Head& _back(std::integral_constant<size_t, 0>) const {
const Head& _back(std::integral_constant<size_t,0>) const {
return head;
}
template<size_t Pos>
const back_type& _back(std::integral_constant<size_t, Pos>) const {
std::integral_constant<size_t, Pos - 1> token;
const back_type& _back(std::integral_constant<size_t,Pos>) const {
std::integral_constant<size_t,Pos-1> token;
return super::_back(token);
}
const back_type& back() const {
std::integral_constant<size_t, sizeof...(Tail)> token;
std::integral_constant<size_t,sizeof...(Tail)> token;
return _back(token);
}
};
......@@ -398,35 +410,39 @@ struct tdata_upcast_helper<0, Head, Tail...> {
template<typename T>
struct tdata_from_type_list;
template<typename... T>
struct tdata_from_type_list<util::type_list<T...>> {
typedef tdata<T...> type;
template<typename... Ts>
struct tdata_from_type_list<util::type_list<Ts...>> {
typedef tdata<Ts...> type;
};
template<typename... T>
inline void collect_tdata(tdata<T...>&) { }
template<typename T, typename U>
inline void rebind_value(T& lhs, U& rhs) {
lhs = rhs;
}
template<typename Storage, typename... Args>
void collect_tdata(Storage& storage, const tdata<>&, const Args&... args) {
collect_tdata(storage, args...);
template<typename T, typename U>
inline void rebind_value(util::rebindable_reference<T>& lhs, U& rhs) {
lhs.rebind(rhs);
}
template<typename Storage, typename Arg0, typename... Args>
void collect_tdata(Storage& storage, const Arg0& arg0, const Args&... args) {
storage.head = arg0.head;
collect_tdata(storage.tail(), arg0.tail(), args...);
template<typename... Ts>
inline void rebind_tdata(tdata<Ts...>&) { }
template<typename... Ts, typename... Vs>
void rebind_tdata(tdata<Ts...>& td, const tdata<>&, const Vs&... args) {
rebind_tdata(td, args...);
}
template<typename... Ts, typename... Us, typename... Vs>
void rebind_tdata(tdata<Ts...>& td, const tdata<Us...>& arg, const Vs&... args) {
rebind_value(td.head, arg.head);
rebind_tdata(td.tail(), arg.tail(), args...);
}
} } // namespace cppa::detail
namespace cppa {
template<typename... Args>
detail::tdata<typename detail::implicit_conversions<typename util::rm_ref<Args>::type>::type...>
mk_tdata(Args&&... args) {
return {std::forward<Args>(args)...};
}
template<size_t N, typename... Ts>
const typename util::at<N, Ts...>::type& get(const detail::tdata<Ts...>& tv) {
static_assert(N < sizeof...(Ts), "N >= tv.size()");
......
......@@ -58,9 +58,8 @@ class tuple_vals : public abstract_tuple {
tuple_vals(const tuple_vals&) = default;
template<typename... Args>
tuple_vals(Args&&... args) : super(false)
, m_data(std::forward<Args>(args)...) { }
template<typename... Us>
tuple_vals(Us&&... args) : super(false), m_data(std::forward<Us>(args)...) { }
const void* native_data() const {
return &m_data;
......
......@@ -31,7 +31,9 @@
#ifndef CPPA_TUPLE_VIEW_HPP
#define CPPA_TUPLE_VIEW_HPP
#include "cppa/util/static_foreach.hpp"
#include "cppa/guard_expr.hpp"
#include "cppa/util/rebindable_reference.hpp"
#include "cppa/detail/tuple_vals.hpp"
#include "cppa/detail/abstract_tuple.hpp"
......@@ -58,7 +60,7 @@ class tuple_view : public abstract_tuple {
public:
typedef tdata<Ts*...> data_type;
typedef tdata<util::rebindable_reference<Ts>...> data_type;
typedef types_array<Ts...> element_types;
......@@ -83,20 +85,17 @@ class tuple_view : public abstract_tuple {
}
abstract_tuple* copy() const {
auto result = new tuple_vals<Ts...>;
tuple_view_copy_helper f{result};
util::static_foreach<0, sizeof...(Ts)>::_(m_data, f);
return result;
return new tuple_vals<Ts...>{m_data};
}
const void* at(size_t pos) const {
CPPA_REQUIRE(pos < size());
return m_data.at(pos);
return m_data.at(pos).get_ptr();
}
void* mutable_at(size_t pos) {
CPPA_REQUIRE(pos < size());
return m_data.mutable_at(pos);
return m_data.mutable_at(pos).get_ptr();
}
const uniform_type_info* type_at(size_t pos) const {
......@@ -114,6 +113,8 @@ class tuple_view : public abstract_tuple {
static types_array<Ts...> m_types;
tuple_view(const data_type& data) : m_data(data) { }
};
template<typename... Ts>
......
......@@ -37,59 +37,43 @@
#include "cppa/primitive_type.hpp"
namespace cppa { namespace detail {
// if (IfStmt == true) ptype = PT; else ptype = Else::ptype;
template<bool IfStmt, primitive_type PT, class Else>
struct if_else_ptype_c {
static const primitive_type ptype = PT;
};
#include "cppa/util/rm_ref.hpp"
template<primitive_type PT, class Else>
struct if_else_ptype_c<false, PT, Else> {
static const primitive_type ptype = Else::ptype;
};
// if (Stmt::value == true) ptype = FT; else ptype = Else::ptype;
template<class Stmt, primitive_type PT, class Else>
struct if_else_ptype : if_else_ptype_c<Stmt::value, PT, Else> { };
namespace cppa { namespace detail {
template<primitive_type PT>
struct wrapped_ptype { static const primitive_type ptype = PT; };
// maps type T the the corresponding fundamental_type
template<typename T>
struct type_to_ptype_impl :
// signed integers
if_else_ptype<std::is_same<T, std::int8_t>, pt_int8,
if_else_ptype<std::is_same<T, std::int16_t>, pt_int16,
if_else_ptype<std::is_same<T, std::int32_t>, pt_int32,
if_else_ptype<std::is_same<T, std::int64_t>, pt_int64,
// unsigned integers
if_else_ptype<std::is_same<T, std::uint8_t>, pt_uint8,
if_else_ptype<std::is_same<T, std::uint16_t>, pt_uint16,
if_else_ptype<std::is_same<T, std::uint32_t>, pt_uint32,
if_else_ptype<std::is_same<T, std::uint64_t>, pt_uint64,
// floating points
if_else_ptype<std::is_same<T, float>, pt_float,
if_else_ptype<std::is_same<T, double>, pt_double,
if_else_ptype<std::is_same<T, long double>, pt_long_double,
// strings
if_else_ptype<std::is_convertible<T, std::string>, pt_u8string,
if_else_ptype<std::is_convertible<T, std::u16string>, pt_u16string,
if_else_ptype<std::is_convertible<T, std::u32string>, pt_u32string,
// default case
wrapped_ptype<pt_null> > > > > > > > > > > > > > > {
struct type_to_ptype_impl {
static constexpr primitive_type ptype =
std::is_convertible<T,std::string>::value
? pt_u8string
: (std::is_convertible<T,std::u16string>::value
? pt_u16string
: (std::is_convertible<T,std::u32string>::value
? pt_u32string
: pt_null));
};
template<typename T>
struct type_to_ptype {
typedef typename std::remove_cv<typename std::remove_reference<T>::type>::type type;
static const primitive_type ptype = type_to_ptype_impl<type>::ptype;
// integers
template<> struct type_to_ptype_impl<std::int8_t > : wrapped_ptype<pt_int8 > { };
template<> struct type_to_ptype_impl<std::uint8_t > : wrapped_ptype<pt_uint8 > { };
template<> struct type_to_ptype_impl<std::int16_t > : wrapped_ptype<pt_int16 > { };
template<> struct type_to_ptype_impl<std::uint16_t> : wrapped_ptype<pt_uint16> { };
template<> struct type_to_ptype_impl<std::int32_t > : wrapped_ptype<pt_int32 > { };
template<> struct type_to_ptype_impl<std::uint32_t> : wrapped_ptype<pt_uint32> { };
template<> struct type_to_ptype_impl<std::int64_t > : wrapped_ptype<pt_int64 > { };
template<> struct type_to_ptype_impl<std::uint64_t> : wrapped_ptype<pt_uint64> { };
// floating points
template<> struct type_to_ptype_impl<float> : wrapped_ptype<pt_float > { };
template<> struct type_to_ptype_impl<double> : wrapped_ptype<pt_double > { };
template<> struct type_to_ptype_impl<long double> : wrapped_ptype<pt_long_double> { };
};
template<typename T>
struct type_to_ptype : type_to_ptype_impl<typename util::rm_ref<T>::type> { };
} } // namespace cppa::detail
......
......@@ -42,30 +42,20 @@
namespace cppa { namespace detail {
template<bool IsFun, typename T>
struct vg_fwd_ {
static inline const T& _(const T& arg) { return arg; }
static inline T&& _(T&& arg) { return std::move(arg); }
static inline T& _(T& arg) { return arg; }
};
// 'absorbs' callables and instances of `anything`
template<typename T>
struct vg_fwd_<true, T> {
template<typename Arg>
static inline util::void_type _(Arg&&) { return {}; }
};
const T& vg_fwd(const T& arg, typename std::enable_if<not util::is_callable<T>::value>::type* = 0) {
return arg;
}
template<>
struct vg_fwd_<false,anything> {
static inline util::void_type _(const anything&) { return {}; }
};
inline util::void_type vg_fwd(const anything&) {
return {};
}
// absorbs callables and instances of `anything`
template<typename T>
struct vg_fwd
: vg_fwd_<util::is_callable<typename util::rm_ref<T>::type>::value,
typename util::rm_ref<T>::type> {
};
util::void_type vg_fwd(const T&, typename std::enable_if<util::is_callable<T>::value>::type* = 0) {
return {};
}
template<typename T>
struct vg_cmp {
......@@ -91,11 +81,11 @@ class value_guard {
value_guard() = default;
value_guard(const value_guard&) = default;
template<typename... Args>
value_guard(const Args&... args) : m_args(vg_fwd<Args>::_(args)...) { }
template<typename... Ts>
value_guard(const Ts&... args) : m_args(vg_fwd(args)...) { }
template<typename... Args>
inline bool operator()(const Args&... args) const {
template<typename... Ts>
inline bool operator()(const Ts&... args) const {
return _eval(m_args.head, m_args.tail(), args...);
}
......@@ -117,17 +107,17 @@ class value_guard {
return true;
}
template<typename T0, typename Arg0, typename... Args>
static inline bool _eval(const T0& head, const tdata<>&,
const Arg0& arg0, const Args&...) {
return cmp(head, arg0);
template<typename T, typename U, typename... Us>
static inline bool _eval(const T& head, const tdata<>&,
const U& arg, const Us&...) {
return cmp(head, arg);
}
template<typename T0, typename T1, typename... Ts,
typename Arg0, typename... Args>
typename U, typename... Us>
static inline bool _eval(const T0& head, const tdata<T1,Ts...>& tail,
const Arg0& arg0, const Args&... args) {
return cmp(head, arg0) && _eval(tail.head, tail.tail(), args...);
const U& arg, const Us&... args) {
return cmp(head, arg) && _eval(tail.head, tail.tail(), args...);
}
};
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* 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/>. *
\******************************************************************************/
#ifndef CPPA_EITHER_HPP
#define CPPA_EITHER_HPP
#include <new>
#include <utility>
#include <type_traits>
#include "cppa/config.hpp"
namespace cppa {
/**
* @brief Represents either a @p Left or a @p Right.
*/
template<class Left, class Right>
class either {
//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:
typedef Left left_type;
typedef Right right_type;
/**
* @brief Default constructor, creates a @p Left.
*/
either() : m_is_left(true) { new (&m_left) left_type (); }
/**
* @brief Creates a @p Left from @p value.
*/
either(const left_type& 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(const right_type& 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)); }
either(const either& other) : m_is_left(other.m_is_left) {
if (other.m_is_left) cr_left(other.m_left);
else cr_right(other.m_right);
}
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));
}
~either() { destroy(); }
either& operator=(const either& other) {
if (m_is_left == other.m_is_left) {
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);
}
return *this;
}
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);
}
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));
}
return *this;
}
/**
* @brief Returns @p true if this is a @p Left; otherwise @p false.
*/
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_right() const { return !m_is_left; }
/**
* @brief Returns this @p either as a @p Left.
*/
inline Left& left() {
CPPA_REQUIRE(m_is_left);
return m_left;
}
/**
* @brief Returns this @p either as a @p Left.
*/
inline const left_type& left() const {
CPPA_REQUIRE(m_is_left);
return m_left;
}
/**
* @brief Returns this @p either as a @p Right.
*/
inline Right& right() {
CPPA_REQUIRE(!m_is_left);
return m_right;
}
/**
* @brief Returns this @p either as a @p Right.
*/
inline const right_type& right() const {
CPPA_REQUIRE(!m_is_left);
return m_right;
}
template<typename F>
void apply(const F& fun) {
if (is_left()) fun(left());
else fun(right());
}
template<typename F>
void apply(const F& fun) const {
if (is_left()) fun(left());
else fun(right());
}
template<typename Result, typename F>
Result inspect(const F& fun) {
if (is_left()) return fun(left());
else return fun(right());
}
template<typename Result, typename F>
Result inspect(const F& fun) const {
if (is_left()) return fun(left());
else return fun(right());
}
private:
bool m_is_left;
union {
left_type m_left;
right_type m_right;
};
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_type (std::forward<L>(value));
}
template<typename R>
void cr_right(R&& value) {
new (&m_right) right_type (std::forward<R>(value));
}
};
/** @relates either */
template<typename Left, typename Right>
bool operator==(const either<Left, Right>& lhs, const either<Left, Right>& 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;
}
/** @relates either */
template<typename Left, typename Right>
bool operator==(const either<Left, Right>& lhs, const Left& rhs) {
return lhs.is_left() && lhs.left() == rhs;
}
/** @relates either */
template<typename Left, typename Right>
bool operator==(const Left& lhs, const either<Left, Right>& rhs) {
return rhs == lhs;
}
/** @relates either */
template<typename Left, typename Right>
bool operator==(const either<Left, Right>& lhs, const Right& rhs) {
return lhs.is_right() && lhs.right() == rhs;
}
/** @relates either */
template<typename Left, typename Right>
bool operator==(const Right& lhs, const either<Left, Right>& rhs) {
return rhs == lhs;
}
/** @relates either */
template<typename Left, typename Right>
bool operator!=(const either<Left, Right>& lhs, const either<Left, Right>& rhs) {
return !(lhs == rhs);
}
/** @relates either */
template<typename Left, typename Right>
bool operator!=(const either<Left, Right>& lhs, const Left& rhs) {
return !(lhs == rhs);
}
/** @relates either */
template<typename Left, typename Right>
bool operator!=(const Left& lhs, const either<Left, Right>& rhs) {
return !(rhs == lhs);
}
/** @relates either */
template<typename Left, typename Right>
bool operator!=(const either<Left, Right>& lhs, const Right& rhs) {
return !(lhs == rhs);
}
/** @relates either */
template<typename Left, typename Right>
bool operator!=(const Right& lhs, const either<Left, Right>& rhs) {
return !(rhs == lhs);
}
} // namespace cppa
#endif // CPPA_EITHER_HPP
......@@ -60,9 +60,9 @@ class enable_weak_ptr : public Base {
typedef enable_weak_ptr combined_type;
template<typename... Args>
enable_weak_ptr(Args&&... args)
: Base(std::forward<Args>(args)...)
template<typename... Ts>
enable_weak_ptr(Ts&&... args)
: Base(std::forward<Ts>(args)...)
, m_anchor(new weak_ptr_anchor(this)) { }
void request_deletion() {
......
......@@ -37,7 +37,6 @@
#include <vector>
#include "cppa/config.hpp"
#include "cppa/either.hpp"
#include "cppa/extend.hpp"
#include "cppa/behavior.hpp"
#include "cppa/scheduled_actor.hpp"
......@@ -60,19 +59,14 @@ class event_based_actor : public scheduled_actor {
* @brief Finishes execution with exit reason
* {@link exit_reason::unallowed_function_call unallowed_function_call}.
*/
void dequeue(behavior&); //override
void dequeue(behavior&);
/**
* @copydoc dequeue(behavior&)
*/
void dequeue(partial_function&); //override
void dequeue_response(behavior&, message_id);
/**
* @copydoc dequeue(behavior&)
*/
void dequeue_response(behavior&, message_id_t);
resume_result resume(util::fiber*, actor_ptr&); //override
resume_result resume(util::fiber*, actor_ptr&);
/**
* @brief Initializes the actor.
......@@ -97,9 +91,10 @@ class event_based_actor : public scheduled_actor {
* @brief Provokes a compiler error to ensure that an event-based actor
* does not accidently uses receive() instead of become().
*/
template<typename... Args>
void receive(Args&&...) {
static_assert((sizeof...(Args) + 1) < 1,
template<typename... Ts>
void receive(Ts&&...) {
// this asssertion always fails
static_assert((sizeof...(Ts) + 1) < 1,
"You shall not use receive in an event-based actor. "
"Use become() instead.");
}
......@@ -107,30 +102,32 @@ class event_based_actor : public scheduled_actor {
/**
* @brief Provokes a compiler error.
*/
template<typename... Args>
void receive_loop(Args&&... args) {
receive(std::forward<Args>(args)...);
template<typename... Ts>
void receive_loop(Ts&&... args) {
receive(std::forward<Ts>(args)...);
}
/**
* @brief Provokes a compiler error.
*/
template<typename... Args>
void receive_while(Args&&... args) {
receive(std::forward<Args>(args)...);
template<typename... Ts>
void receive_while(Ts&&... args) {
receive(std::forward<Ts>(args)...);
}
/**
* @brief Provokes a compiler error.
*/
template<typename... Args>
void do_receive(Args&&... args) {
receive(std::forward<Args>(args)...);
template<typename... Ts>
void do_receive(Ts&&... args) {
receive(std::forward<Ts>(args)...);
}
void do_become(behavior&& bhvr, bool discard_old);
void become_waiting_for(behavior&& bhvr, message_id_t mf);
void become_waiting_for(behavior bhvr, message_id mf);
detail::receive_policy m_recv_policy;
private:
......@@ -154,8 +151,6 @@ class event_based_actor : public scheduled_actor {
}
}
detail::receive_policy m_policy;
};
} // namespace cppa
......
......@@ -56,12 +56,13 @@ struct extend_helper<B,D,M,Ms...> : extend_helper<B,M<D,B>,Ms...> { };
*
* Mixins in libcppa always have two template parameters: base type and
* derived type. This allows mixins to make use of the curiously recurring
* template pattern (CRTP).
* template pattern (CRTP). However, if none of the used mixins use CRTP,
* the second template argument can ignored (it is then set to Base).
*/
template<class Base, class Derived>
template<class Base, class Derived = Base>
struct extend {
/**
* @brief An alias for the result type.
* @brief Identifies the combined type.
*/
template<template<class,class> class... Mixins>
using with = typename detail::extend_helper<Derived,Base,Mixins...>::type;
......
......@@ -44,6 +44,7 @@
#include "cppa/util/rm_ref.hpp"
#include "cppa/util/void_type.hpp"
#include "cppa/util/apply_args.hpp"
#include "cppa/util/rebindable_reference.hpp"
#include "cppa/detail/tdata.hpp"
......@@ -96,8 +97,8 @@ struct guard_expr {
guard_expr(const guard_expr&) = default;
guard_expr(guard_expr&& other) : m_args(std::move(other.m_args)) { }
template<typename... Args>
bool operator()(const Args&... args) const;
template<typename... Ts>
bool operator()(const Ts&... args) const;
};
......@@ -109,58 +110,16 @@ struct guard_expr {
SubMacro (greater_eq_op, >=) SubMacro (equal_op, ==) \
SubMacro (not_equal_op, !=)
template<typename T>
struct ge_mutable_reference_wrapper {
T* value;
ge_mutable_reference_wrapper() : value(nullptr) { }
ge_mutable_reference_wrapper(T&&) = delete;
ge_mutable_reference_wrapper(T& vref) : value(&vref) { }
ge_mutable_reference_wrapper(const ge_mutable_reference_wrapper&) = default;
ge_mutable_reference_wrapper& operator=(T& vref) {
value = &vref;
return *this;
}
ge_mutable_reference_wrapper& operator=(const ge_mutable_reference_wrapper&) = default;
T& get() const { CPPA_REQUIRE(value != 0); return *value; }
operator T& () const { CPPA_REQUIRE(value != 0); return *value; }
};
template<typename T>
struct ge_reference_wrapper {
const T* value;
ge_reference_wrapper(T&&) = delete;
ge_reference_wrapper() : value(nullptr) { }
ge_reference_wrapper(const T& val_ref) : value(&val_ref) { }
ge_reference_wrapper(const ge_reference_wrapper&) = default;
ge_reference_wrapper& operator=(const T& vref) {
value = &vref;
return *this;
}
ge_reference_wrapper& operator=(const ge_reference_wrapper&) = default;
const T& get() const { CPPA_REQUIRE(value != 0); return *value; }
operator const T& () const { CPPA_REQUIRE(value != 0); return *value; }
};
// support use of gref(BooleanVariable) as receive loop 'guard'
template<>
struct ge_reference_wrapper<bool> {
const bool* value;
ge_reference_wrapper(bool&&) = delete;
ge_reference_wrapper(const bool& val_ref) : value(&val_ref) { }
ge_reference_wrapper(const ge_reference_wrapper&) = default;
ge_reference_wrapper& operator=(const ge_reference_wrapper&) = default;
const bool& get() const { CPPA_REQUIRE(value != 0); return *value; }
operator const bool& () const { CPPA_REQUIRE(value != 0); return *value; }
bool operator()() const { CPPA_REQUIRE(value != 0); return *value; }
};
/**
* @brief Creates a reference wrapper similar to std::reference_wrapper<const T>
* that could be used in guard expressions or to enforce lazy evaluation.
*/
template<typename T>
ge_reference_wrapper<T> gref(const T& value) { return {value}; }
util::rebindable_reference<const T> gref(const T& value) {
return {value};
}
//ge_reference_wrapper<T> gref(const T& value) { return {value}; }
// bind utility for placeholders
......@@ -385,7 +344,7 @@ template<typename T, class Tuple>
struct ge_unbound { typedef T type; };
template<typename T, class Tuple>
struct ge_unbound<ge_reference_wrapper<T>, Tuple> { typedef T type; };
struct ge_unbound<util::rebindable_reference<const T>, Tuple> { typedef T type; };
template<typename T, class Tuple>
struct ge_unbound<std::reference_wrapper<T>, Tuple> { typedef T type; };
......@@ -418,7 +377,7 @@ struct is_ge_type<guard_placeholder<X> > {
};
template<typename T>
struct is_ge_type<ge_reference_wrapper<T> > {
struct is_ge_type<util::rebindable_reference<T> > {
static constexpr bool value = true;
};
......@@ -553,7 +512,7 @@ inline const T& ge_resolve(const Tuple&, const std::reference_wrapper<const T>&
}
template<class Tuple, typename T>
inline const T& ge_resolve(const Tuple&, const ge_reference_wrapper<T>& value) {
inline const T& ge_resolve(const Tuple&, const util::rebindable_reference<const T>& value) {
return value.get();
}
......@@ -644,19 +603,19 @@ auto ge_resolve(const Tuple& tup,
return ge_eval<OP>(tup, ge.m_args.first, ge.m_args.second);
}
template<operator_id OP, typename First, typename Second, typename... Args>
template<operator_id OP, typename First, typename Second, typename... Ts>
auto ge_invoke_step2(const guard_expr<OP, First, Second>& ge,
const detail::tdata<Args...>& tup)
-> typename ge_result<OP, First, Second, detail::tdata<Args...>>::type {
const detail::tdata<Ts...>& tup)
-> typename ge_result<OP, First, Second, detail::tdata<Ts...>>::type {
return ge_eval<OP>(tup, ge.m_args.first, ge.m_args.second);
}
template<operator_id OP, typename First, typename Second, typename... Args>
template<operator_id OP, typename First, typename Second, typename... Ts>
auto ge_invoke(const guard_expr<OP, First, Second>& ge,
const Args&... args)
const Ts&... args)
-> typename ge_result<OP, First, Second,
detail::tdata<std::reference_wrapper<const Args>...>>::type {
detail::tdata<std::reference_wrapper<const Args>...> tup{args...};
detail::tdata<std::reference_wrapper<const Ts>...>>::type {
detail::tdata<std::reference_wrapper<const Ts>...> tup{args...};
return ge_invoke_step2(ge, tup);
}
......@@ -664,9 +623,9 @@ template<class GuardExpr>
struct ge_invoke_helper {
const GuardExpr& ge;
ge_invoke_helper(const GuardExpr& arg) : ge(arg) { }
template<typename... Args>
bool operator()(Args&&... args) const {
return ge_invoke(ge, std::forward<Args>(args)...);
template<typename... Ts>
bool operator()(Ts&&... args) const {
return ge_invoke(ge, std::forward<Ts>(args)...);
}
};
......@@ -687,10 +646,10 @@ ge_invoke_any(const guard_expr<OP, First, Second>& ge,
>::type
result_type;
using namespace util;
typename if_else<
std::is_same<typename TupleTypes::back, anything>,
typename std::conditional<
std::is_same<typename TupleTypes::back,anything>::value,
TupleTypes,
wrapped<typename tl_push_back<TupleTypes, anything>::type>
wrapped<typename tl_push_back<TupleTypes,anything>::type>
>::type
cast_token;
auto x = tuple_cast(tup, cast_token);
......@@ -700,8 +659,8 @@ ge_invoke_any(const guard_expr<OP, First, Second>& ge,
}
template<operator_id OP, typename First, typename Second>
template<typename... Args>
bool guard_expr<OP, First, Second>::operator()(const Args&... args) const {
template<typename... Ts>
bool guard_expr<OP, First, Second>::operator()(const Ts&... args) const {
static_assert(std::is_same<decltype(ge_invoke(*this, args...)), bool>::value,
"guard expression does not return a boolean");
return ge_invoke(*this, args...);
......@@ -711,17 +670,17 @@ bool guard_expr<OP, First, Second>::operator()(const Args&... args) const {
template<typename T>
struct gref_wrapped {
typedef ge_reference_wrapper<typename util::rm_ref<T>::type> type;
typedef util::rebindable_reference<const typename util::rm_ref<T>::type> type;
};
template<typename T>
struct mutable_gref_wrapped {
typedef ge_mutable_reference_wrapper<T> type;
typedef util::rebindable_reference<T> type;
};
template<typename T>
struct mutable_gref_wrapped<T&> {
typedef ge_mutable_reference_wrapper<T> type;
typedef util::rebindable_reference<T> type;
};
// finally ...
......
......@@ -36,7 +36,6 @@
#include <stdexcept>
#include <type_traits>
#include "cppa/intrusive_fwd_ptr.hpp"
#include "cppa/util/comparable.hpp"
namespace cppa {
......@@ -73,12 +72,6 @@ class intrusive_ptr : util::comparable<intrusive_ptr<T> >,
intrusive_ptr(const intrusive_ptr& other) { set_ptr(other.get()); }
template<typename Y, typename Ref, typename Deref>
intrusive_ptr(intrusive_fwd_ptr<Y,Ref,Deref> other) : m_ptr(other.release()) {
static_assert(std::is_convertible<Y*, T*>::value,
"Y* is not assignable to T*");
}
template<typename Y>
intrusive_ptr(intrusive_ptr<Y> other) : m_ptr(other.release()) {
static_assert(std::is_convertible<Y*, T*>::value,
......@@ -120,9 +113,9 @@ class intrusive_ptr : util::comparable<intrusive_ptr<T> >,
set_ptr(new_value);
}
template<typename... Args>
void emplace(Args&&... args) {
reset(new T(std::forward<Args>(args)...));
template<typename... Ts>
void emplace(Ts&&... args) {
reset(new T(std::forward<Ts>(args)...));
}
intrusive_ptr& operator=(pointer ptr) {
......@@ -214,9 +207,9 @@ inline bool operator!=(const intrusive_ptr<X>& lhs, const intrusive_ptr<Y>& rhs)
* @brief Constructs an object of type T which must be a derived type
* of {@link ref_counted} and wraps it in an {@link intrusive_ptr}.
*/
template<typename T, typename... Args>
intrusive_ptr<T> make_counted(Args&&... args) {
return {new T(std::forward<Args>(args)...)};
template<typename T, typename... Ts>
intrusive_ptr<T> make_counted(Ts&&... args) {
return {new T(std::forward<Ts>(args)...)};
}
} // namespace cppa
......
......@@ -42,14 +42,14 @@
#include "cppa/message_id.hpp"
#include "cppa/match_expr.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/memory_cached.hpp"
#include "cppa/mailbox_element.hpp"
#include "cppa/response_handle.hpp"
#include "cppa/partial_function.hpp"
#include "cppa/util/duration.hpp"
#include "cppa/memory_cached.hpp"
#include "cppa/detail/behavior_stack.hpp"
#include "cppa/detail/recursive_queue_node.hpp"
namespace cppa {
......@@ -85,15 +85,10 @@ constexpr keep_behavior_t keep_behavior = keep_behavior_t{};
* @brief Base class for local running Actors.
* @extends actor
*/
class local_actor : public extend<actor,local_actor>::with<memory_cached> {
class local_actor : public extend<actor>::with<memory_cached> {
typedef combined_type super;
friend class scheduler;
friend class detail::memory;
friend class detail::receive_policy;
template<typename> friend class detail::basic_memory_cache;
public:
/**
......@@ -119,36 +114,11 @@ class local_actor : public extend<actor,local_actor>::with<memory_cached> {
* linked actors, sets its state to @c exited and finishes execution.
* @param reason Exit reason that will be send to
* linked actors and monitors.
* @note Throws {@link actor_exited} to unwind the stack
* when called in context-switching or thread-based actors.
*/
virtual void quit(std::uint32_t reason = exit_reason::normal) = 0;
/**
* @brief Removes the first element from the mailbox @p pfun is defined
* for and invokes @p pfun with the removed element.
* Blocks until a matching message arrives if @p pfun is not
* defined for any message in the actor's mailbox.
* @param pfun A partial function denoting the actor's response to the
* next incoming message.
* @warning You should not call this member function by hand.
* Use the {@link cppa::receive receive} function or
* the @p become member function in case of event-based actors.
*/
virtual void dequeue(partial_function& pfun) = 0;
/**
* @brief Removes the first element from the mailbox @p bhvr is defined
* for and invokes @p bhvr with the removed element.
* Blocks until either a matching message arrives if @p bhvr is not
* defined for any message in the actor's mailbox or until a
* timeout occurs.
* @param bhvr A partial function with optional timeout denoting the
* actor's response to the next incoming message.
* @warning You should not call this member function by hand.
* Use the {@link cppa::receive receive} function or
* the @p become member function in case of event-based actors.
*/
virtual void dequeue(behavior& bhvr) = 0;
/**
* @brief Checks whether this actor traps exit messages.
*/
......@@ -191,47 +161,13 @@ class local_actor : public extend<actor,local_actor>::with<memory_cached> {
* @param whom The actor that should be monitored by this actor.
* @note Each call to @p monitor creates a new, independent monitor.
*/
void monitor(actor_ptr whom);
void monitor(const actor_ptr& whom);
/**
* @brief Removes a monitor from @p whom.
* @param whom A monitored actor.
*/
void demonitor(actor_ptr whom);
// become/unbecome API
/**
* @brief Sets the actor's behavior to @p bhvr and discards the
* previous behavior if the policy is {@link discard_behavior}.
*/
template<bool Discard>
inline void become(behavior_policy<Discard>, behavior bhvr);
/**
* @brief Sets the actor's behavior and discards the
* previous behavior if the policy is {@link discard_behavior}.
*/
template<bool Discard, typename T0, typename T1, typename... Ts>
inline void become(behavior_policy<Discard>, T0&& a0, T1&& a1, Ts&&... as);
/**
* @brief Sets the actor's behavior;
* equal to <tt>become(discard_old, bhvr</tt>.
*/
inline void become(behavior bhvr);
/**
* @brief Sets the actor's behavior;
* equal to <tt>become(discard_old, bhvr</tt>.
*/
template<typename... Cases, typename... Ts>
inline void become(match_expr<Cases...> a, Ts&&... as);
/**
* @brief Returns to a previous behavior if available.
*/
inline void unbecome();
void demonitor(const actor_ptr& whom);
/**
* @brief Can be overridden to initialize an actor before any
......@@ -256,6 +192,7 @@ class local_actor : public extend<actor,local_actor>::with<memory_cached> {
std::vector<group_ptr> joined_groups();
/**
* @ingroup BlockingAPI
* @brief Executes an actor's behavior stack until it is empty.
*
* This member function allows thread-based and context-switching actors
......@@ -308,146 +245,108 @@ class local_actor : public extend<actor,local_actor>::with<memory_cached> {
else quit(exit_reason::unhandled_sync_failure);
}
// library-internal members and member functions that shall
// not appear in the documentation
/** @cond PRIVATE */
virtual void dequeue(behavior& bhvr) = 0;
inline void dequeue(behavior&& bhvr);
virtual void dequeue_response(behavior&, message_id) = 0;
inline void dequeue_response(behavior&&, message_id);
# ifndef CPPA_DOCUMENTATION
template<bool Discard, typename... Ts>
void become(behavior_policy<Discard>, Ts&&... args);
// backward compatiblity, handle_response was part of local_actor
// until version 0.6
sync_handle_helper handle_response(const message_future& mf);
template<typename T, typename... Ts>
void become(T arg, Ts&&... args);
inline void unbecome();
local_actor(bool is_scheduled = false);
virtual bool initialized() const = 0;
inline bool chaining_enabled() {
return m_chaining && !m_chained_actor;
}
inline bool chaining_enabled();
inline void send_message(channel* whom, any_tuple&& what) {
whom->enqueue(this, std::move(what));
}
inline void send_message(channel* whom, any_tuple&& what);
inline void send_message(const actor_ptr& whom, any_tuple&& what) {
if (chaining_enabled()) {
if (whom->chained_enqueue(this, std::move(what))) {
m_chained_actor = whom;
}
}
else whom->enqueue(this, std::move(what));
}
inline void send_message(actor* whom, any_tuple&& what);
inline message_id_t send_sync_message(const actor_ptr& whom, any_tuple&& what) {
auto id = ++m_last_request_id;
CPPA_REQUIRE(id.is_request());
if (chaining_enabled()) {
if (whom->chained_sync_enqueue(this, id, std::move(what))) {
m_chained_actor = whom;
}
}
else whom->sync_enqueue(this, id, std::move(what));
auto awaited_response = id.response_id();
m_pending_responses.push_back(awaited_response);
return awaited_response;
}
inline message_id send_sync_message(const actor_ptr& whom,
any_tuple&& what);
message_id_t send_timed_sync_message(const actor_ptr& whom,
message_id send_timed_sync_message(const actor_ptr& whom,
const util::duration& rel_time,
any_tuple&& what);
// returns 0 if last_dequeued() is an asynchronous or sync request message,
// a response id generated from the request id otherwise
inline message_id_t get_response_id() {
auto id = m_current_node->mid;
return (id.is_request()) ? id.response_id() : message_id_t();
}
inline message_id get_response_id();
void reply_message(any_tuple&& what);
void forward_message(const actor_ptr& new_receiver);
inline const actor_ptr& chained_actor() {
return m_chained_actor;
}
inline const actor_ptr& chained_actor();
inline void chained_actor(const actor_ptr& value) {
m_chained_actor = value;
}
inline void chained_actor(const actor_ptr& value);
inline bool awaits(message_id_t response_id) {
CPPA_REQUIRE(response_id.is_response());
return std::any_of(m_pending_responses.begin(),
m_pending_responses.end(),
[=](message_id_t other) {
return response_id == other;
});
}
inline bool awaits(message_id response_id);
inline void mark_arrived(message_id_t response_id) {
auto last = m_pending_responses.end();
auto i = std::find(m_pending_responses.begin(), last, response_id);
if (i != last) m_pending_responses.erase(i);
}
inline void mark_arrived(message_id response_id);
virtual void dequeue_response(behavior&, message_id_t) = 0;
virtual void become_waiting_for(behavior, message_id) = 0;
inline void dequeue_response(behavior&& bhvr, message_id_t mid) {
behavior tmp{std::move(bhvr)};
dequeue_response(tmp, mid);
}
inline detail::behavior_stack& bhvr_stack();
virtual void become_waiting_for(behavior&&, message_id_t) = 0;
protected:
inline detail::behavior_stack& bhvr_stack() {
return m_bhvr_stack;
}
virtual void do_become(behavior&& bhvr, bool discard_old) = 0;
protected:
inline void do_become(const behavior& bhvr, bool discard_old);
inline void remove_handler(message_id id);
void cleanup(std::uint32_t reason);
// true if this actor uses the chained_send optimization
bool m_chaining;
// true if this actor receives EXIT messages as ordinary messages
bool m_trap_exit;
// true if this actor takes part in cooperative scheduling
bool m_is_scheduled;
// pointer to the actor that is marked as successor due to a chained send
actor_ptr m_chained_actor;
// identifies the ID of the last sent synchronous request
message_id_t m_last_request_id;
message_id m_last_request_id;
// identifies all IDs of sync messages waiting for a response
std::vector<message_id_t> m_pending_responses;
std::vector<message_id> m_pending_responses;
// "default value" for m_current_node
detail::recursive_queue_node m_dummy_node;
mailbox_element m_dummy_node;
// points to m_dummy_node if no callback is currently invoked,
// points to the node under processing otherwise
detail::recursive_queue_node* m_current_node;
mailbox_element* m_current_node;
// {group => subscription} map of all joined groups
std::map<group_ptr, group::subscription> m_subscriptions;
// allows actors to keep previous behaviors and enables unbecome()
detail::behavior_stack m_bhvr_stack;
inline void remove_handler(message_id_t id) {
m_bhvr_stack.erase(id);
}
void cleanup(std::uint32_t reason);
private:
std::function<void()> m_sync_failure_handler;
std::function<void()> m_sync_timeout_handler;
# endif // CPPA_DOCUMENTATION
protected:
virtual void do_become(behavior&& bhvr, bool discard_old) = 0;
inline void do_become(const behavior& bhvr, bool discard_old) {
behavior copy{bhvr};
do_become(std::move(copy), discard_old);
}
/** @endcond */
};
......@@ -457,10 +356,21 @@ class local_actor : public extend<actor,local_actor>::with<memory_cached> {
*/
typedef intrusive_ptr<local_actor> local_actor_ptr;
/******************************************************************************
* inline and template member function implementations *
******************************************************************************/
void local_actor::dequeue(behavior&& bhvr) {
behavior tmp{std::move(bhvr)};
dequeue(tmp);
}
inline void local_actor::dequeue_response(behavior&& bhvr, message_id id) {
behavior tmp{std::move(bhvr)};
dequeue_response(tmp, id);
}
inline bool local_actor::trap_exit() const {
return m_trap_exit;
}
......@@ -485,28 +395,90 @@ inline actor_ptr& local_actor::last_sender() {
return m_current_node->sender;
}
template<bool Discard>
inline void local_actor::become(behavior_policy<Discard>, behavior bhvr) {
do_become(std::move(bhvr), Discard);
template<bool Discard, typename... Ts>
inline void local_actor::become(behavior_policy<Discard>, Ts&&... args) {
do_become(match_expr_convert(std::forward<Ts>(args)...), Discard);
}
template<bool Discard, typename T0, typename T1, typename... Ts>
inline void local_actor::become(behavior_policy<Discard>, T0&& a0, T1&& a1, Ts&&... as) {
auto bhvr = match_expr_convert(std::forward<T0>(a0), std::forward<T1>(a1), std::forward<Ts>(as)...);
do_become(std::move(bhvr), Discard);
template<typename T, typename... Ts>
inline void local_actor::become(T arg, Ts&&... args) {
do_become(match_expr_convert(arg, std::forward<Ts>(args)...), true);
}
inline void local_actor::become(behavior bhvr) {
do_become(std::move(bhvr), true);
inline void local_actor::unbecome() {
m_bhvr_stack.pop_async_back();
}
template<typename... Cases, typename... Ts>
inline void local_actor::become(match_expr<Cases...> a, Ts&&... as) {
do_become(match_expr_convert(std::move(a), std::forward<Ts>(as)...), true);
inline bool local_actor::chaining_enabled() {
return m_chaining && !m_chained_actor;
}
inline void local_actor::unbecome() {
m_bhvr_stack.pop_async_back();
inline void local_actor::send_message(channel* whom, any_tuple&& what) {
whom->enqueue(this, std::move(what));
}
inline void local_actor::send_message(actor* whom, any_tuple&& what) {
if (chaining_enabled()) {
if (whom->chained_enqueue(this, std::move(what))) {
m_chained_actor.reset(whom);
}
}
else whom->enqueue(this, std::move(what));
}
inline message_id local_actor::send_sync_message(const actor_ptr& whom, any_tuple&& what) {
auto id = ++m_last_request_id;
CPPA_REQUIRE(id.is_request());
if (chaining_enabled()) {
if (whom->chained_sync_enqueue(this, id, std::move(what))) {
chained_actor(whom);
}
}
else whom->sync_enqueue(this, id, std::move(what));
auto awaited_response = id.response_id();
m_pending_responses.push_back(awaited_response);
return awaited_response;
}
inline message_id local_actor::get_response_id() {
auto id = m_current_node->mid;
return (id.is_request()) ? id.response_id() : message_id();
}
inline const actor_ptr& local_actor::chained_actor() {
return m_chained_actor;
}
inline void local_actor::chained_actor(const actor_ptr& value) {
m_chained_actor = value;
}
inline bool local_actor::awaits(message_id response_id) {
CPPA_REQUIRE(response_id.is_response());
return std::any_of(m_pending_responses.begin(),
m_pending_responses.end(),
[=](message_id other) {
return response_id == other;
});
}
inline void local_actor::mark_arrived(message_id response_id) {
auto last = m_pending_responses.end();
auto i = std::find(m_pending_responses.begin(), last, response_id);
if (i != last) m_pending_responses.erase(i);
}
inline detail::behavior_stack& local_actor::bhvr_stack() {
return m_bhvr_stack;
}
inline void local_actor::do_become(const behavior& bhvr, bool discard_old) {
behavior copy{bhvr};
do_become(std::move(copy), discard_old);
}
inline void local_actor::remove_handler(message_id id) {
m_bhvr_stack.erase(id);
}
} // namespace cppa
......
......@@ -33,10 +33,9 @@
#include <type_traits>
#include "cppa/mailbox_element.hpp"
#include "cppa/detail/sync_request_bouncer.hpp"
#include "cppa/detail/recursive_queue_node.hpp"
#include "cppa/intrusive/single_reader_queue.hpp"
#include "cppa/intrusive/blocking_single_reader_queue.hpp"
namespace cppa {
......@@ -61,14 +60,7 @@ class mailbox_based : public Base {
typedef mailbox_based combined_type;
typedef detail::recursive_queue_node mailbox_element;
typedef typename std::conditional<
has_blocking_receive<Subtype>::value,
intrusive::blocking_single_reader_queue<mailbox_element,del>,
intrusive::single_reader_queue<mailbox_element,del>
>::type
mailbox_type;
typedef intrusive::single_reader_queue<mailbox_element,del> mailbox_type;
template<typename... Ts>
mailbox_based(Ts&&... args) : Base(std::forward<Ts>(args)...) { }
......@@ -86,10 +78,6 @@ class mailbox_based : public Base {
mailbox_type m_mailbox;
private:
inline Subtype* dthis() { return static_cast<Subtype*>(this); }
};
} // namespace cppa
......
......@@ -34,51 +34,52 @@
#include <cstdint>
#include "cppa/actor.hpp"
#include "cppa/extend.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/message_id.hpp"
#include "cppa/ref_counted.hpp"
#include "cppa/memory_cached.hpp"
// needs access to constructor + destructor to initialize m_dummy_node
namespace cppa { class local_actor; }
namespace cppa {
namespace cppa { namespace detail {
class local_actor;
class recursive_queue_node : public memory_cached<memory_managed,recursive_queue_node> {
class mailbox_element : public extend<memory_managed>::with<memory_cached> {
friend class memory;
friend class ::cppa::local_actor;
friend class local_actor;
friend class detail::memory;
public:
typedef recursive_queue_node* pointer;
typedef mailbox_element* pointer;
pointer next; // intrusive next pointer
bool marked; // denotes if this node is currently processed
actor_ptr sender; // points to the sender of msg
any_tuple msg; // 'content field'
message_id_t mid;
message_id mid;
recursive_queue_node(recursive_queue_node&&) = delete;
recursive_queue_node(const recursive_queue_node&) = delete;
recursive_queue_node& operator=(recursive_queue_node&&) = delete;
recursive_queue_node& operator=(const recursive_queue_node&) = delete;
mailbox_element(mailbox_element&&) = delete;
mailbox_element(const mailbox_element&) = delete;
mailbox_element& operator=(mailbox_element&&) = delete;
mailbox_element& operator=(const mailbox_element&) = delete;
template<typename... Ts>
inline static recursive_queue_node* create(Ts&&... args) {
return memory::create<recursive_queue_node>(std::forward<Ts>(args)...);
inline static mailbox_element* create(Ts&&... args) {
return detail::memory::create<mailbox_element>(std::forward<Ts>(args)...);
}
private:
recursive_queue_node() = default;
mailbox_element() = default;
recursive_queue_node(const actor_ptr& sptr,
mailbox_element(const actor_ptr& sptr,
any_tuple data,
message_id_t id = message_id_t{});
message_id id = message_id{});
};
} } // namespace cppa::detail
} // namespace cppa
#endif // CPPA_RECURSIVE_QUEUE_NODE_HPP
......@@ -51,16 +51,10 @@ struct match_helper {
any_tuple tup;
match_helper(any_tuple t) : tup(std::move(t)) { }
match_helper(match_helper&&) = default;
/*
void operator()(partial_function&& arg) {
partial_function tmp{std::move(arg)};
tmp(tup);
}
*/
template<class Arg0, class... Args>
bool operator()(Arg0&& arg0, Args&&... args) {
auto tmp = match_expr_convert(std::forward<Arg0>(arg0),
std::forward<Args>(args)...);
template<typename... Ts>
bool operator()(Ts&&... args) {
static_assert(sizeof...(Ts) > 0, "at least one argument required");
auto tmp = match_expr_convert(std::forward<Ts>(args)...);
static_assert(std::is_same<partial_function, decltype(tmp)>::value,
"match statement contains timeout");
return tmp(tup);
......@@ -86,20 +80,15 @@ class match_each_helper {
match_each_helper(Iterator first, Iterator last, Projection proj)
: i(first), e(last), p(proj) { }
template<typename... Cases>
void operator()(match_expr<Cases...> expr) {
template<typename... Ts>
void operator()(Ts&&... args) {
static_assert(sizeof...(Ts) > 0, "at least one argument required");
auto expr = match_expr_collect(std::forward<Ts>(args)...);
for (; i != e; ++i) {
expr(p(*i));
}
}
template<class Arg0, class Arg1, class... Args>
void operator()(Arg0&& arg0, Arg1&& arg1, Args&&... args) {
(*this)(match_expr_collect(std::forward<Arg0>(arg0),
std::forward<Arg1>(arg1),
std::forward<Args>(args)...));
}
private:
Iterator i;
......@@ -126,20 +115,15 @@ class match_for_helper {
match_for_helper(Iterator first, Predicate p, Advance a = Advance(), Projection pj = Projection())
: i(first), adv(a), pred(p), proj(pj) { }
template<typename... Cases>
void operator()(match_expr<Cases...> expr) {
template<typename... Ts>
void operator()(Ts&&... args) {
static_assert(sizeof...(Ts) > 0, "at least one argument required");
auto expr = match_expr_collect(std::forward<Ts>(args)...);
for (; pred(i); adv(i)) {
expr(proj(*i));
}
}
template<class Arg0, class Arg1, class... Args>
void operator()(Arg0&& arg0, Arg1&& arg1, Args&&... args) {
(*this)(match_expr_collect(std::forward<Arg0>(arg0),
std::forward<Arg1>(arg1),
std::forward<Args>(args)...));
}
private:
Iterator i;
......@@ -199,8 +183,8 @@ struct unwind_and_call<Size, Size> {
return target.first.invoke(target.second, sub_result, std::forward<Unwinded>(args)...);
}
template<typename T, typename... Args>
static inline bool _(std::vector<T>&, Args&&...) { return false; }
template<typename T, typename... Ts>
static inline bool _(std::vector<T>&, Ts&&...) { return false; }
};
......@@ -272,34 +256,18 @@ class stream_matcher {
stream_matcher(iter first, iter last) : m_pos(first), m_end(last) { }
template<typename... Cases>
bool operator()(match_expr<Cases...>& expr) {
template<typename... Ts>
bool operator()(Ts&&... args) {
auto expr = match_expr_collect(std::forward<Ts>(args)...);
typedef decltype(expr) expr_type;
while (m_pos != m_end) {
if (!unwind_and_call<0, util::tl_size<typename match_expr<Cases...>::cases_list>::value>::_(m_cache, m_pos, m_end, expr)) {
if (!unwind_and_call<0, util::tl_size<typename expr_type::cases_list>::value>::_(m_cache, m_pos, m_end, expr)) {
return false;
}
}
return true;
}
template<typename... Cases>
bool operator()(match_expr<Cases...>&& expr) {
auto tmp = std::move(expr);
return (*this)(tmp);
}
template<typename... Cases>
bool operator()(const match_expr<Cases...>& expr) {
auto tmp = expr;
return (*this)(tmp);
}
template<typename Arg0, typename... Args>
bool operator()(Arg0&& arg0, Args&&... args) {
return (*this)(match_expr_collect(std::forward<Arg0>(arg0),
std::forward<Args>(args)...));
}
private:
iter m_pos;
......
......@@ -44,6 +44,8 @@
#include "cppa/util/disjunction.hpp"
#include "cppa/util/left_or_right.hpp"
#include "cppa/util/deduce_ref_type.hpp"
#include "cppa/util/get_result_type.hpp"
#include "cppa/util/rebindable_reference.hpp"
#include "cppa/detail/matches.hpp"
#include "cppa/detail/projection.hpp"
......@@ -197,10 +199,10 @@ struct invoke_policy_impl<wildcard_position::nil,
>::type* = 0) {
if (arg_types == typeid(util::type_list<Ts...>)) {
if (native_arg) {
typedef typename util::if_else_c<
typedef typename std::conditional<
std::is_const<PtrType>::value,
const native_data_type*,
util::wrapped<native_data_type*>
native_data_type*
>::type
cast_type;
auto arg = reinterpret_cast<cast_type>(native_arg);
......@@ -356,9 +358,9 @@ struct invoke_policy
template<class Pattern, class Projection, class PartialFun>
struct projection_partial_function_pair : std::pair<Projection,PartialFun> {
template<typename... Args>
projection_partial_function_pair(Args&&... args)
: std::pair<Projection,PartialFun>(std::forward<Args>(args)...) { }
template<typename... Ts>
projection_partial_function_pair(Ts&&... args)
: std::pair<Projection,PartialFun>(std::forward<Ts>(args)...) { }
typedef Pattern pattern_type;
};
......@@ -558,11 +560,6 @@ inline std::uint64_t calc_bitmask(PPFPs& fs, long_constant<N>, const std::type_i
return result | calc_bitmask(fs, long_constant<N-1l>(), tinf, tup);
}
template<typename T>
struct is_manipulator_case {
static constexpr bool value = T::second_type::manipulates_args;
};
template<bool IsManipulator, typename T0, typename T1>
struct mexpr_fwd_ {
typedef T1 type;
......@@ -620,29 +617,35 @@ inline const void* fetch_native_data(const Ptr& ptr, std::false_type) {
namespace cppa {
template<class... Cases>
/** @cond PRIVATE */
template<typename T>
struct is_manipulator_case {
static constexpr bool value = T::second_type::manipulates_args;
};
/** @endcond */
/**
* @brief A match expression encapsulating cases <tt>Cs...</tt>.
*/
template<class... Cs>
class match_expr {
static_assert(sizeof...(Cases) < 64, "too many functions");
static_assert(sizeof...(Cs) < 64, "too many functions");
public:
static constexpr bool may_have_timeout = false;
typedef util::type_list<Cases...> cases_list;
typedef util::type_list<Cs...> cases_list;
static constexpr size_t num_cases = sizeof...(Cases);
static constexpr bool has_manipulator = util::tl_exists<cases_list,is_manipulator_case>::value;
static constexpr bool has_manipulator =
util::tl_exists<cases_list,detail::is_manipulator_case>::value;
typedef detail::long_constant<static_cast<long>(num_cases)-1l>
idx_token_type;
typedef detail::long_constant<sizeof...(Cs)-1l> idx_token_type;
static constexpr idx_token_type idx_token = idx_token_type{};
template<typename... Args>
match_expr(Args&&... args) : m_cases(std::forward<Args>(args)...) {
template<typename... Ts>
match_expr(Ts&&... args) : m_cases(std::forward<Ts>(args)...) {
init();
}
......@@ -692,31 +695,34 @@ class match_expr {
return invoke_impl(tmp);
}
template<typename... Args>
bool operator()(Args&&... args) {
template<typename... Ts>
bool operator()(Ts&&... args) {
// wraps and applies implicit conversions to args
typedef detail::tdata<
typename detail::mexpr_fwd<has_manipulator,Args>::type...>
typename detail::mexpr_fwd<
has_manipulator,
Ts
>::type...
>
tuple_type;
// applies implicit conversions etc
tuple_type tup{std::forward<Args>(args)...};
tuple_type tup{std::forward<Ts>(args)...};
auto& type_token = typeid(typename tuple_type::types);
auto bitmask = get_cache_entry(&type_token, tup);
typedef typename util::if_else_c<
// ref_type keeps track of whether this match_expr is a mutator
typedef typename std::conditional<
has_manipulator,
tuple_type&,
const util::wrapped<tuple_type&>
const tuple_type&
>::type
ref_type;
typedef typename util::if_else_c<
// same here
typedef typename std::conditional<
has_manipulator,
void*,
util::wrapped<const void*>
const void*
>::type
ptr_type;
ptr_type ptr_arg = nullptr;
// iterate over cases and return if any case was invoked
bool invoke_result = true;
bool unroll_result = unroll_expr(m_cases,
invoke_result,
......@@ -724,21 +730,20 @@ class match_expr {
idx_token,
type_token,
false, // not dynamically_typed
ptr_arg,
static_cast<ptr_type>(nullptr),
static_cast<ref_type>(tup));
return unroll_result && invoke_result;
}
template<class... OtherCases>
match_expr<Cases...,OtherCases...>
or_else(const match_expr<OtherCases...>& other) const {
detail::tdata<ge_reference_wrapper<Cases>...,
ge_reference_wrapper<OtherCases>... > all_cases;
collect_tdata(all_cases, m_cases, other.cases());
template<class... Ds>
match_expr<Cs...,Ds...> or_else(const match_expr<Ds...>& other) const {
detail::tdata<util::rebindable_reference<const Cs>...,
util::rebindable_reference<const Ds>... > all_cases;
rebind_tdata(all_cases, m_cases, other.cases());
return {all_cases};
}
inline const detail::tdata<Cases...>& cases() const {
inline const detail::tdata<Cs...>& cases() const {
return m_cases;
}
......@@ -770,7 +775,7 @@ class match_expr {
// structure: tdata< tdata<type_list<...>, ...>,
// tdata<type_list<...>, ...>,
// ...>
detail::tdata<Cases...> m_cases;
detail::tdata<Cs...> m_cases;
static constexpr size_t cache_size = 10;
......@@ -828,13 +833,14 @@ class match_expr {
bool invoke_impl(Tuple& tup) {
std::integral_constant<bool,has_manipulator> mutator_token;
// returns either a reference or a new object
decltype(detail::detach_if_needed(tup, mutator_token)) tref = detail::detach_if_needed(tup, mutator_token);
typedef decltype(detail::detach_if_needed(tup, mutator_token)) detached;
detached tref = detail::detach_if_needed(tup, mutator_token);
auto& vals = tref.vals();
auto ndp = fetch_native_data(vals, mutator_token);
auto token_ptr = vals->type_token();
auto bitmask = get_cache_entry(token_ptr, *vals);
auto dynamically_typed = vals->dynamically_typed();
bool invoke_result = true; // maybe set to false by an invoked functor
bool invoke_result = true; // may be set to false by an invoked functor
bool unroll_result = unroll_expr(m_cases,
invoke_result,
bitmask,
......@@ -851,9 +857,9 @@ class match_expr {
template<class List>
struct match_expr_from_type_list;
template<typename... Args>
struct match_expr_from_type_list<util::type_list<Args...> > {
typedef match_expr<Args...> type;
template<typename... Ts>
struct match_expr_from_type_list<util::type_list<Ts...> > {
typedef match_expr<Ts...> type;
};
template<typename... Lhs, typename... Rhs>
......@@ -862,32 +868,41 @@ inline match_expr<Lhs...,Rhs...> operator,(const match_expr<Lhs...>& lhs,
return lhs.or_else(rhs);
}
template<typename Arg0, typename... Args>
template<typename... Cs>
match_expr<Cs...>& match_expr_collect(match_expr<Cs...>& arg) {
return arg;
}
template<typename... Cs>
match_expr<Cs...>&& match_expr_collect(match_expr<Cs...>&& arg) {
return std::move(arg);
}
template<typename... Cs>
const match_expr<Cs...>& match_expr_collect(const match_expr<Cs...>& arg) {
return arg;
}
template<typename T, typename... Ts>
typename match_expr_from_type_list<
typename util::tl_concat<
typename Arg0::cases_list,
typename Args::cases_list...
>::type
>::type
match_expr_collect(const Arg0& arg0, const Args&... args) {
typedef typename match_expr_from_type_list<
typename util::tl_concat<
typename Arg0::cases_list,
typename Args::cases_list...
typename T::cases_list,
typename Ts::cases_list...
>::type
>::type
combined_type;
match_expr_collect(const T& arg, const Ts&... args) {
typename detail::tdata_from_type_list<
typename util::tl_map<
typename util::tl_concat<
typename Arg0::cases_list,
typename Args::cases_list...
typename T::cases_list,
typename Ts::cases_list...
>::type,
gref_wrapped
>::type
>::type
all_cases;
detail::collect_tdata(all_cases, arg0.cases(), args.cases()...);
detail::rebind_tdata(all_cases, arg.cases(), args.cases()...);
return {all_cases};
}
......@@ -921,7 +936,7 @@ behavior_impl* concat_rec(const Data& data, Token, const T& arg, const Ts&... ar
>::type
next_data;
next_token_type next_token;
collect_tdata(next_data, data, arg.cases());
rebind_tdata(next_data, data, arg.cases());
return concat_rec(next_data, next_token, args...);
}
......@@ -940,7 +955,7 @@ behavior_impl* concat_expr(with_timeout, const T& arg, const Ts&... args) {
>::type
>::type
wrapper;
detail::collect_tdata(wrapper, arg.cases());
detail::rebind_tdata(wrapper, arg.cases());
return concat_rec(wrapper, typename T::cases_list{}, args...);
}
......@@ -967,7 +982,7 @@ behavior_impl* concat_expr(without_timeout, const T& arg, const Ts&... args) {
combined_type;
auto lvoid = []() { };
typedef default_behavior_impl<combined_type,decltype(lvoid)> impl_type;
collect_tdata(all_cases, arg.cases(), args.cases()...);
rebind_tdata(all_cases, arg.cases(), args.cases()...);
return new impl_type(all_cases, util::duration{}, lvoid);
}
......
......@@ -56,7 +56,7 @@ class message_future {
public:
inline continue_helper(message_id_t mid) : m_mid(mid) { }
inline continue_helper(message_id mid) : m_mid(mid) { }
template<typename F>
void continue_with(F fun) {
......@@ -71,7 +71,7 @@ class message_future {
private:
message_id_t m_mid;
message_id m_mid;
};
......@@ -80,20 +80,20 @@ class message_future {
/**
* @brief Sets @p mexpr as event-handler for the response message.
*/
template<typename... Cases, typename... Args>
continue_helper then(const match_expr<Cases...>& a0, const Args&... as) {
template<typename... Cs, typename... Ts>
continue_helper then(const match_expr<Cs...>& arg, const Ts&... args) {
check_consistency();
self->become_waiting_for(match_expr_convert(a0, as...), m_mid);
self->become_waiting_for(match_expr_convert(arg, args...), m_mid);
return {m_mid};
}
/**
* @brief Blocks until the response arrives and then executes @p mexpr.
*/
template<typename... Cases, typename... Args>
void await(const match_expr<Cases...>& arg0, const Args&... args) {
template<typename... Cs, typename... Ts>
void await(const match_expr<Cs...>& arg, const Ts&... args) {
check_consistency();
self->dequeue_response(match_expr_convert(arg0, args...), m_mid);
self->dequeue_response(match_expr_convert(arg, args...), m_mid);
}
/**
......@@ -127,16 +127,16 @@ class message_future {
/**
* @brief Returns the awaited response ID.
*/
inline const message_id_t& id() const { return m_mid; }
inline const message_id& id() const { return m_mid; }
message_future(const message_future&) = default;
message_future& operator=(const message_future&) = default;
inline message_future(const message_id_t& from) : m_mid(from) { }
inline message_future(const message_id& from) : m_mid(from) { }
private:
message_id_t m_mid;
message_id m_mid;
template<typename... Fs>
behavior fs2bhvr(Fs... fs) {
......@@ -169,9 +169,9 @@ class sync_handle_helper {
inline sync_handle_helper(const message_future& mf) : m_mf(mf) { }
template<typename... Args>
inline message_future::continue_helper operator()(Args&&... args) {
return m_mf.then(std::forward<Args>(args)...);
template<typename... Ts>
inline message_future::continue_helper operator()(Ts&&... args) {
return m_mf.then(std::forward<Ts>(args)...);
}
private:
......@@ -186,9 +186,9 @@ class sync_receive_helper {
inline sync_receive_helper(const message_future& mf) : m_mf(mf) { }
template<typename... Args>
inline void operator()(Args&&... args) {
m_mf.await(std::forward<Args>(args)...);
template<typename... Ts>
inline void operator()(Ts&&... args) {
m_mf.await(std::forward<Ts>(args)...);
}
private:
......
......@@ -42,7 +42,7 @@ struct invalid_message_id { constexpr invalid_message_id() { } };
* @brief
* @note Asynchronous messages always have an invalid message id.
*/
class message_id_t : util::comparable<message_id_t> {
class message_id : util::comparable<message_id> {
static constexpr std::uint64_t response_flag_mask = 0x8000000000000000;
static constexpr std::uint64_t answered_flag_mask = 0x4000000000000000;
......@@ -50,14 +50,14 @@ class message_id_t : util::comparable<message_id_t> {
public:
constexpr message_id_t() : m_value(0) { }
constexpr message_id() : m_value(0) { }
message_id_t(message_id_t&&) = default;
message_id_t(const message_id_t&) = default;
message_id_t& operator=(message_id_t&&) = default;
message_id_t& operator=(const message_id_t&) = default;
message_id(message_id&&) = default;
message_id(const message_id&) = default;
message_id& operator=(message_id&&) = default;
message_id& operator=(const message_id&) = default;
inline message_id_t& operator++() {
inline message_id& operator++() {
++m_value;
return *this;
}
......@@ -78,12 +78,12 @@ class message_id_t : util::comparable<message_id_t> {
return valid() && !is_response();
}
inline message_id_t response_id() const {
return message_id_t(valid() ? m_value | response_flag_mask : 0);
inline message_id response_id() const {
return message_id(valid() ? m_value | response_flag_mask : 0);
}
inline message_id_t request_id() const {
return message_id_t(m_value & request_id_mask);
inline message_id request_id() const {
return message_id(m_value & request_id_mask);
}
inline void mark_as_answered() {
......@@ -94,24 +94,24 @@ class message_id_t : util::comparable<message_id_t> {
return m_value;
}
static inline message_id_t from_integer_value(std::uint64_t value) {
message_id_t result;
static inline message_id from_integer_value(std::uint64_t value) {
message_id result;
result.m_value = value;
return result;
}
static constexpr invalid_message_id invalid = invalid_message_id{};
constexpr message_id_t(invalid_message_id) : m_value(0) { }
constexpr message_id(invalid_message_id) : m_value(0) { }
long compare(const message_id_t& other) const {
long compare(const message_id& other) const {
return (m_value == other.m_value)
? 0 : ((m_value < other.m_value) ? -1 : 1);
}
private:
explicit constexpr message_id_t(std::uint64_t value) : m_value(value) { }
explicit constexpr message_id(std::uint64_t value) : m_value(value) { }
std::uint64_t m_value;
......
......@@ -36,8 +36,6 @@
#include "cppa/config.hpp"
#include "cppa/ref_counted.hpp"
#include "cppa/network/protocol.hpp"
namespace cppa { namespace network {
class middleman;
......
......@@ -48,8 +48,7 @@ class basic_memory_cache;
namespace cppa { namespace network {
class sync_request_info : public extend<memory_managed,sync_request_info>::
with<memory_cached> {
class sync_request_info : public extend<memory_managed>::with<memory_cached> {
friend class detail::memory;
......@@ -59,11 +58,11 @@ class sync_request_info : public extend<memory_managed,sync_request_info>::
pointer next; // intrusive next pointer
actor_ptr sender; // points to the sender of the message
message_id_t mid; // sync message ID
message_id mid; // sync message ID
private:
sync_request_info(actor_ptr sptr, message_id_t id);
sync_request_info(actor_ptr sptr, message_id id);
};
......@@ -79,7 +78,7 @@ class default_actor_proxy : public actor_proxy {
void enqueue(const actor_ptr& sender, any_tuple msg);
void sync_enqueue(const actor_ptr& sender, message_id_t id, any_tuple msg);
void sync_enqueue(const actor_ptr& sender, message_id id, any_tuple msg);
void link_to(const actor_ptr& other);
......@@ -107,7 +106,7 @@ class default_actor_proxy : public actor_proxy {
void forward_msg(const actor_ptr& sender,
any_tuple msg,
message_id_t mid = message_id_t());
message_id mid = message_id());
default_protocol_ptr m_proto;
process_information_ptr m_pinf;
......
......@@ -45,9 +45,9 @@ class default_message_queue : public ref_counted {
typedef value_type& reference;
template<typename... Args>
void emplace(Args&&... args) {
m_impl.emplace_back(std::forward<Args>(args)...);
template<typename... Ts>
void emplace(Ts&&... args) {
m_impl.emplace_back(std::forward<Ts>(args)...);
}
inline bool empty() const { return m_impl.empty(); }
......
......@@ -146,15 +146,6 @@ class default_peer : public continuable_io {
enqueue({nullptr, nullptr}, msg);
}
/*
template<typename Arg0, typename Arg1, typename... Args>
inline void enqueue(Arg0&& arg0, Arg1&& arg1, Args&&... args) {
enqueue(make_any_tuple(std::forward<Arg0>(arg0),
std::forward<Arg1>(arg1),
std::forward<Args>(args)...));
}
*/
};
typedef intrusive_ptr<default_peer> default_peer_ptr;
......
......@@ -49,13 +49,13 @@ class message_header {
actor_ptr sender;
actor_ptr receiver;
message_id_t id;
message_id id;
message_header();
message_header(const actor_ptr& sender,
const actor_ptr& receiver,
message_id_t id = message_id_t::invalid);
message_id id = message_id::invalid);
inline void deliver(any_tuple msg) const {
if (receiver) {
......
......@@ -36,15 +36,16 @@
#include <memory>
#include <functional>
#include "cppa/network/protocol.hpp"
#include "cppa/network/acceptor.hpp"
#include "cppa/network/continuable_reader.hpp"
#include "cppa/network/continuable_io.hpp"
namespace cppa { namespace detail { class singleton_manager; } }
namespace cppa { namespace network {
class protocol;
typedef intrusive_ptr<protocol> protocol_ptr;
/**
* @brief Multiplexes asynchronous IO.
*/
......
......@@ -39,9 +39,9 @@
#include "cppa/actor.hpp"
#include "cppa/ref_counted.hpp"
#include "cppa/primitive_variant.hpp"
#include "cppa/intrusive_fwd_ptr.hpp"
#include "cppa/network/acceptor.hpp"
#include "cppa/network/middleman.hpp"
namespace cppa { class actor_addressing; }
......@@ -83,14 +83,6 @@ class protocol : public ref_counted {
void run_later(std::function<void()> fun);
struct ref_ftor {
void operator()(abstract_middleman*) const;
};
struct deref_ftor {
void operator()(abstract_middleman*) const;
};
protected:
// note: not thread-safe; call only in run_later functor!
......@@ -111,7 +103,7 @@ class protocol : public ref_counted {
private:
intrusive_fwd_ptr<abstract_middleman,ref_ftor,deref_ftor> m_parent;
intrusive_ptr<abstract_middleman> m_parent;
};
......
......@@ -119,7 +119,7 @@ class object {
/**
* @brief Creates a (deep) copy of @p other and assigns it to @p this.
* @return @p *this
* @returns @p *this
*/
object& operator=(const object& other);
......
......@@ -136,8 +136,8 @@ struct rvalue_builder {
rvalue_builder() = default;
template<typename... Args>
rvalue_builder(rvalue_builder_args_ctor, const Args&... args)
template<typename... Ts>
rvalue_builder(rvalue_builder_args_ctor, const Ts&... args)
: m_guard(args...)
, m_funs(args...) {
}
......@@ -262,8 +262,8 @@ __unspecified__ val();
* This overload can be used with the wildcards {@link cppa::val val},
* {@link cppa::any_vals any_vals} and {@link cppa::arg_match arg_match}.
*/
template<typename Arg0, typename... Args>
__unspecified__ on(const Arg0& arg0, const Args&... args);
template<typename T, typename... Ts>
__unspecified__ on(const T& arg, const Ts&... args);
/**
* @brief Left-hand side of a partial function expression that matches types.
......@@ -297,13 +297,13 @@ typedef typename detail::boxed<util::arg_match_t>::type boxed_arg_match_t;
constexpr boxed_arg_match_t arg_match = boxed_arg_match_t();
template<typename Arg0, typename... Args>
template<typename T, typename... Ts>
detail::rvalue_builder<
detail::value_guard<
typename util::tl_filter_not<
typename util::tl_trim<
typename util::tl_map<
util::type_list<Arg0, Args...>,
util::type_list<T,Ts...>,
detail::boxed_and_callable_to_void,
detail::implicit_conversions
>::type
......@@ -312,13 +312,13 @@ detail::rvalue_builder<
>::type
>,
typename util::tl_map<
util::type_list<Arg0, Args...>,
util::type_list<T,Ts...>,
detail::boxed_and_not_callable_to_void
>::type,
util::type_list<typename detail::pattern_type<Arg0>::type,
typename detail::pattern_type<Args>::type...> >
on(const Arg0& arg0, const Args&... args) {
return {detail::rvalue_builder_args_ctor{}, arg0, args...};
util::type_list<typename detail::pattern_type<T>::type,
typename detail::pattern_type<Ts>::type...> >
on(const T& arg, const Ts&... args) {
return {detail::rvalue_builder_args_ctor{}, arg, args...};
}
inline detail::rvalue_builder<detail::empty_value_guard,
......
......@@ -61,60 +61,54 @@ class partial_function {
public:
/** @cond PRIVATE */
typedef intrusive_ptr<detail::behavior_impl> impl_ptr;
inline auto as_behavior_impl() const -> const impl_ptr&;
partial_function(impl_ptr ptr);
static constexpr bool may_have_timeout = false;
/** @endcond */
partial_function() = default;
partial_function(partial_function&&) = default;
partial_function(const partial_function&) = default;
partial_function& operator=(partial_function&&) = default;
partial_function& operator=(const partial_function&) = default;
template<typename... Cases>
partial_function(const match_expr<Cases...>& mexpr)
: m_impl(mexpr.as_behavior_impl()) { }
partial_function(impl_ptr ptr);
inline bool undefined() const {
return m_impl == nullptr;
}
inline bool defined_at(const any_tuple& value) {
return (m_impl) && m_impl->defined_at(value);
}
template<typename T>
inline bool operator()(T&& arg) {
return (m_impl) && m_impl->invoke(std::forward<T>(arg));
}
inline partial_function or_else(const partial_function& other) const {
return m_impl->or_else(other.m_impl);
}
inline behavior or_else(const behavior& other) const {
return behavior{m_impl->or_else(other.m_impl)};
}
template<typename... Cs>
partial_function(const match_expr<Cs...>& mexpr);
/**
* @brief Returns @p true if this partial function is defined for the
* types of @p value, false otherwise.
*/
inline bool defined_at(const any_tuple& value);
/**
* @brief Returns @p true if this partial function was applied to
* @p args, false otherwise.
* @note This member function can return @p false even if
* {@link defined_at()} returns @p true, because {@link defined_at()}
* does <b>not</b> evaluate guards.
*/
template<typename T>
typename std::conditional<T::may_have_timeout,behavior,partial_function>::type
or_else(const T& arg) const;
inline bool operator()(T&& arg);
template<typename T0, typename T1, typename... Ts>
/**
* @brief Adds a fallback which is used where
* this partial function is not defined.
*/
template<typename... Ts>
typename std::conditional<
util::disjunction<
T0::may_have_timeout,
T1::may_have_timeout,
Ts::may_have_timeout...
>::value,
util::disjunction<Ts::may_have_timeout...>::value,
behavior,
partial_function
>::type
or_else(const T0& arg0, const T1& arg1, const Ts&... args) const;
inline const impl_ptr& as_behavior_impl() const;
or_else(Ts&&... args) const;
private:
......@@ -122,45 +116,57 @@ class partial_function {
};
template<typename T, typename... Ts>
template<typename T>
typename std::conditional<T::may_have_timeout,behavior,partial_function>::type
match_expr_convert(const T& arg) {
return {arg};
}
template<typename T0, typename T1, typename... Ts>
typename std::conditional<
util::disjunction<
T::may_have_timeout,
T0::may_have_timeout,
T1::may_have_timeout,
Ts::may_have_timeout...
>::value,
behavior,
partial_function
>::type
match_expr_convert(const T& arg0, const Ts&... args) {
return detail::match_expr_concat(arg0, args...);
match_expr_convert(const T0& arg0, const T1& arg1, const Ts&... args) {
return detail::match_expr_concat(arg0, arg1, args...);
}
/******************************************************************************
* inline and template member function implementations *
******************************************************************************/
inline const partial_function::impl_ptr& partial_function::as_behavior_impl() const {
return m_impl;
template<typename... Cs>
partial_function::partial_function(const match_expr<Cs...>& mexpr)
: m_impl(mexpr.as_behavior_impl()) { }
inline bool partial_function::defined_at(const any_tuple& value) {
return (m_impl) && m_impl->defined_at(value);
}
template<typename T>
typename std::conditional<T::may_have_timeout,behavior,partial_function>::type
partial_function::or_else(const T& arg) const {
return m_impl->or_else(arg.as_behavior_impl());
inline bool partial_function::operator()(T&& arg) {
return (m_impl) && m_impl->invoke(std::forward<T>(arg));
}
template<typename T0, typename T1, typename... Ts>
template<typename... Ts>
typename std::conditional<
util::disjunction<
T0::may_have_timeout,
T1::may_have_timeout,
Ts::may_have_timeout...
>::value,
util::disjunction<Ts::may_have_timeout...>::value,
behavior,
partial_function
>::type
partial_function::or_else(const T0& arg0, const T1& arg1, const Ts&... args) const {
return m_impl->or_else(match_expr_convert(arg0, arg1, args...).as_behavior_impl());
partial_function::or_else(Ts&&... args) const {
auto tmp = match_expr_convert(std::forward<Ts>(args)...);
return m_impl->or_else(tmp.as_behavior_impl());
}
inline auto partial_function::as_behavior_impl() const -> const impl_ptr& {
return m_impl;
}
} // namespace cppa
......
......@@ -47,8 +47,8 @@ class actor_widget_mixin : public actor_companion_mixin<Base> {
public:
template<typename... Args>
actor_widget_mixin(Args&&... args) : super(std::forward<Args>(args)...) { }
template<typename... Ts>
actor_widget_mixin(Ts&&... args) : super(std::forward<Ts>(args)...) { }
struct event_type : public QEvent {
......
......@@ -38,62 +38,64 @@
namespace cppa {
#ifdef CPPA_DOCUMENTATION
/**
* @ingroup BlockingAPI
* @{
*/
/**
* @brief Dequeues the next message from the mailbox that's matched
* by @p bhvr and executes the corresponding callback.
* @param bhvr Denotes the actor's response the next incoming message.
* @brief Dequeues the next message from the mailbox that
* is matched by given behavior.
*/
void receive(behavior& bhvr);
template<typename... Ts>
void receive(Ts&&... args);
/**
* @brief Receives messages in an endless loop.
*
* Semantically equal to: <tt>for (;;) { receive(bhvr); }</tt>
* @param bhvr Denotes the actor's response the next incoming message.
* Semantically equal to: <tt>for (;;) { receive(...); }</tt>
*/
void receive_loop(behavior& bhvr);
template<typename... Ts>
void receive_loop(Ts&&... args);
/**
* @brief Receives messages as long as @p stmt returns true.
* @brief Receives messages as in a range-based loop.
*
* Semantically equal to: <tt>while (stmt()) { receive(...); }</tt>.
* Semantically equal to:
* <tt>for ( ; begin != end; ++begin) { receive(...); }</tt>.
*
* <b>Usage example:</b>
* @code
* int i = 0;
* receive_while([&]() { return (++i <= 10); })
* (
* on<int>() >> int_fun,
* on<float>() >> float_fun
* receive_for(i, 10) (
* on(atom("get")) >> [&]() { reply("result", i); }
* );
* @endcode
* @param stmt Lambda expression, functor or function returning a @c bool.
* @param begin First value in range.
* @param end Last value in range (excluded).
* @returns A functor implementing the loop.
*/
template<typename Statement>
auto receive_while(Statement&& stmt);
template<typename T>
detail::receive_for_helper<T> receive_for(T& begin, const T& end);
/**
* @brief Receives messages as in a range-based loop.
* @brief Receives messages as long as @p stmt returns true.
*
* Semantically equal to: <tt>for ( ; begin != end; ++begin) { receive(...); }</tt>.
* Semantically equal to: <tt>while (stmt()) { receive(...); }</tt>.
*
* <b>Usage example:</b>
* @code
* int i = 0;
* receive_for(i, 10)
* receive_while([&]() { return (++i <= 10); })
* (
* on(atom("get")) >> [&]() { reply("result", i); }
* on<int>() >> int_fun,
* on<float>() >> float_fun
* );
* @endcode
* @param begin First value in range.
* @param end Last value in range (excluded).
* @param stmt Lambda expression, functor or function returning a @c bool.
* @returns A functor implementing the loop.
*/
template<typename T>
auto receive_for(T& begin, const T& end);
template<typename Statement>
detail::receive_while_helper<Statement> receive_while(Statement&& stmt);
/**
* @brief Receives messages until @p stmt returns true.
......@@ -113,32 +115,34 @@ auto receive_for(T& begin, const T& end);
* @param bhvr Denotes the actor's response the next incoming message.
* @returns A functor providing the @c until member function.
*/
auto do_receive(behavior& bhvr);
template<typename... Ts>
detail::do_receive_helper do_receive(Ts&&... args);
#else // CPPA_DOCUMENTATION
/**
* @}
*/
inline void receive(behavior& bhvr) { self->dequeue(bhvr); }
inline void receive(partial_function& fun) { self->dequeue(fun); }
/******************************************************************************
* inline and template function implementations *
******************************************************************************/
template<typename Arg0, typename... Args>
void receive(Arg0&& arg0, Args&&... args) {
auto tmp = match_expr_convert(std::forward<Arg0>(arg0),
std::forward<Args>(args)...);
receive(tmp);
template<typename... Ts>
void receive(Ts&&... args) {
static_assert(sizeof...(Ts), "receive() requires at least one argument");
self->dequeue(match_expr_convert(std::forward<Ts>(args)...));
}
void receive_loop(behavior& rules);
void receive_loop(behavior&& rules);
void receive_loop(partial_function& rules);
void receive_loop(partial_function&& rules);
inline void receive_loop(behavior rules) {
local_actor* sptr = self;
for (;;) sptr->dequeue(rules);
}
template<typename Arg0, typename... Args>
void receive_loop(Arg0&& arg0, Args&&... args) {
auto tmp = match_expr_convert(std::forward<Arg0>(arg0),
std::forward<Args>(args)...);
receive_loop(tmp);
template<typename... Ts>
void receive_loop(Ts&&... args) {
behavior bhvr = match_expr_convert(std::forward<Ts>(args)...);
local_actor* sptr = self;
for (;;) sptr->dequeue(bhvr);
}
template<typename T>
......@@ -153,13 +157,12 @@ detail::receive_while_helper<Statement> receive_while(Statement&& stmt) {
return std::move(stmt);
}
template<typename... Args>
detail::do_receive_helper do_receive(Args&&... args) {
return detail::do_receive_helper(std::forward<Args>(args)...);
template<typename... Ts>
detail::do_receive_helper do_receive(Ts&&... args) {
behavior bhvr = match_expr_convert(std::forward<Ts>(args)...);
return detail::do_receive_helper(std::move(bhvr));
}
#endif // CPPA_DOCUMENTATION
} // namespace cppa
#endif // CPPA_RECEIVE_HPP
......@@ -52,7 +52,7 @@ class response_handle {
response_handle(const actor_ptr& from,
const actor_ptr& to,
const message_id_t& response_id);
const message_id& response_id);
/**
* @brief Queries whether response message is still outstanding.
......@@ -73,7 +73,7 @@ class response_handle {
/**
* @brief Returns the message id for the response message.
*/
inline const message_id_t& response_id() const { return m_id; }
inline const message_id& response_id() const { return m_id; }
/**
* @brief Returns the actor that is going send the response message.
......@@ -89,7 +89,7 @@ class response_handle {
actor_ptr m_from;
actor_ptr m_to;
message_id_t m_id;
message_id m_id;
};
......
......@@ -66,8 +66,8 @@ class sb_actor : public Base {
protected:
template<typename... Args>
sb_actor(Args&&... args) : Base(std::forward<Args>(args)...) { }
template<typename... Ts>
sb_actor(Ts&&... args) : Base(std::forward<Ts>(args)...) { }
};
......
......@@ -38,9 +38,11 @@
#include "cppa/actor_state.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/mailbox_based.hpp"
#include "cppa/mailbox_element.hpp"
#include "cppa/detail/memory.hpp"
#include "cppa/detail/receive_policy.hpp"
#include "cppa/detail/recursive_queue_node.hpp"
#include "cppa/intrusive/single_reader_queue.hpp"
namespace cppa {
......@@ -68,7 +70,7 @@ struct has_blocking_receive<scheduled_actor> : std::true_type { };
* @brief A base class for cooperatively scheduled actors.
* @extends local_actor
*/
class scheduled_actor : public extend<local_actor,scheduled_actor>::with<mailbox_based>{
class scheduled_actor : public extend<local_actor>::with<mailbox_based>{
typedef combined_type super;
......@@ -115,13 +117,15 @@ class scheduled_actor : public extend<local_actor,scheduled_actor>::with<mailbox
*/
inline bool is_hidden() const;
virtual void run_detached();
void enqueue(const actor_ptr&, any_tuple);
bool chained_enqueue(const actor_ptr&, any_tuple);
void sync_enqueue(const actor_ptr&, message_id_t, any_tuple);
void sync_enqueue(const actor_ptr&, message_id, any_tuple);
bool chained_sync_enqueue(const actor_ptr&, message_id_t, any_tuple);
bool chained_sync_enqueue(const actor_ptr&, message_id, any_tuple);
void request_timeout(const util::duration& d);
......@@ -160,8 +164,6 @@ class scheduled_actor : public extend<local_actor,scheduled_actor>::with<mailbox
void cleanup(std::uint32_t reason);
typedef detail::recursive_queue_node mailbox_element;
typedef intrusive::single_reader_queue<mailbox_element,detail::disposer>
mailbox_type;
......@@ -195,7 +197,7 @@ class scheduled_actor : public extend<local_actor,scheduled_actor>::with<mailbox
bool sync_enqueue_impl(actor_state next,
const actor_ptr& sender,
any_tuple& msg,
message_id_t id);
message_id id);
bool m_has_pending_tout;
std::uint32_t m_pending_tout;
......
......@@ -144,7 +144,7 @@ class scheduler {
template<typename Duration, typename... Data>
void delayed_reply(const actor_ptr& to,
const Duration& rel_time,
message_id_t id,
message_id id,
any_tuple data ) {
CPPA_REQUIRE(!id.valid() || id.is_response());
if (id.valid()) {
......
......@@ -37,15 +37,18 @@
#include "cppa/behavior.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/mailbox_element.hpp"
#include "cppa/util/dptr.hpp"
#include "cppa/detail/behavior_stack.hpp"
#include "cppa/detail/receive_policy.hpp"
#include "cppa/detail/recursive_queue_node.hpp"
namespace cppa {
/**
* @tparam Base Either @p scheduled or @p threaded.
* @brief An actor that uses the blocking API of @p libcppa and thus needs
* its own stack.
*/
template<class Base, class Subtype>
class stacked : public Base {
......@@ -61,25 +64,18 @@ class stacked : public Base {
static constexpr auto receive_flag = detail::rp_nestable;
virtual void dequeue(partial_function& fun) {
m_recv_policy.receive(dthis(), fun);
}
virtual void dequeue(behavior& bhvr) {
m_recv_policy.receive(dthis(), bhvr);
m_recv_policy.receive(util::dptr<Subtype>(this), bhvr);
}
virtual void dequeue_response(behavior& bhvr, message_id_t request_id) {
m_recv_policy.receive(dthis(), bhvr, request_id);
virtual void dequeue_response(behavior& bhvr, message_id request_id) {
m_recv_policy.receive(util::dptr<Subtype>(this), bhvr, request_id);
}
virtual void run() {
if (!dthis()->m_bhvr_stack.empty()) {
dthis()->exec_behavior_stack();
}
if (m_behavior) {
m_behavior();
}
auto dthis = util::dptr<Subtype>(this);
if (!dthis->m_bhvr_stack.empty()) dthis->exec_behavior_stack();
if (m_behavior) m_behavior();
}
inline void set_behavior(std::function<void()> fun) {
......@@ -91,55 +87,46 @@ class stacked : public Base {
throw actor_exited(reason);
}
virtual void exec_behavior_stack() {
this->m_bhvr_stack.exec(m_recv_policy, util::dptr<Subtype>(this));
}
protected:
template<typename... Args>
stacked(std::function<void()> fun, Args&&... args)
: Base(std::forward<Args>(args)...), m_behavior(std::move(fun)) { }
template<typename... Ts>
stacked(std::function<void()> fun, Ts&&... args)
: Base(std::forward<Ts>(args)...), m_behavior(std::move(fun)) { }
virtual void do_become(behavior&& bhvr, bool discard_old) {
become_impl(std::move(bhvr), discard_old, message_id_t());
become_impl(std::move(bhvr), discard_old, message_id());
}
virtual void become_waiting_for(behavior&& bhvr, message_id_t mid) {
virtual void become_waiting_for(behavior bhvr, message_id mid) {
become_impl(std::move(bhvr), false, mid);
}
virtual bool has_behavior() {
return static_cast<bool>(m_behavior) || !dthis()->m_bhvr_stack.empty();
return static_cast<bool>(m_behavior)
|| !util::dptr<Subtype>(this)->m_bhvr_stack.empty();
}
typedef std::chrono::time_point<std::chrono::high_resolution_clock>
timeout_type;
virtual timeout_type init_timeout(const util::duration& rel_time) = 0;
virtual detail::recursive_queue_node* await_message() = 0;
virtual detail::recursive_queue_node* await_message(const timeout_type& abs_time) = 0;
private:
std::function<void()> m_behavior;
detail::receive_policy m_recv_policy;
void become_impl(behavior&& bhvr, bool discard_old, message_id_t mid) {
private:
void become_impl(behavior&& bhvr, bool discard_old, message_id mid) {
auto dthis = util::dptr<Subtype>(this);
if (bhvr.timeout().valid()) {
dthis()->reset_timeout();
dthis()->request_timeout(bhvr.timeout());
dthis->reset_timeout();
dthis->request_timeout(bhvr.timeout());
}
if (!dthis()->m_bhvr_stack.empty() && discard_old) {
dthis()->m_bhvr_stack.pop_async_back();
if (!dthis->m_bhvr_stack.empty() && discard_old) {
dthis->m_bhvr_stack.pop_async_back();
}
dthis()->m_bhvr_stack.push_back(std::move(bhvr), mid);
dthis->m_bhvr_stack.push_back(std::move(bhvr), mid);
}
virtual void exec_behavior_stack() {
this->m_bhvr_stack.exec(m_recv_policy, dthis());
}
inline Subtype* dthis() { return static_cast<Subtype*>(this); }
};
} // namespace cppa
......
......@@ -43,18 +43,16 @@
#include <cstdint>
#include "cppa/atom.hpp"
#include "cppa/either.hpp"
#include "cppa/extend.hpp"
#include "cppa/stacked.hpp"
#include "cppa/threaded.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/intrusive_ptr.hpp"
#include "cppa/mailbox_based.hpp"
#include "cppa/mailbox_element.hpp"
#include "cppa/detail/receive_policy.hpp"
#include "cppa/detail/recursive_queue_node.hpp"
#include "cppa/intrusive/blocking_single_reader_queue.hpp"
namespace cppa {
......@@ -66,10 +64,10 @@ template<>
struct has_blocking_receive<thread_mapped_actor> : std::true_type { };
/**
* @brief An actor running in its own thread.
* @brief An actor using the blocking API running in its own thread.
* @extends local_actor
*/
class thread_mapped_actor : public extend<local_actor,thread_mapped_actor>::with<stacked,mailbox_based> {
class thread_mapped_actor : public extend<local_actor,thread_mapped_actor>::with<mailbox_based,stacked,threaded> {
friend class self_type; // needs access to cleanup()
friend class scheduler_helper; // needs access to mailbox
......@@ -88,40 +86,14 @@ class thread_mapped_actor : public extend<local_actor,thread_mapped_actor>::with
bool initialized() const;
void enqueue(const actor_ptr& sender, any_tuple msg);
void sync_enqueue(const actor_ptr& sender, message_id_t id, any_tuple msg);
inline void reset_timeout() { }
inline void request_timeout(const util::duration&) { }
inline void handle_timeout(behavior& bhvr) { bhvr.handle_timeout(); }
inline void pop_timeout() { }
inline void push_timeout() { }
inline bool waits_for_timeout(std::uint32_t) { return false; }
protected:
typedef detail::recursive_queue_node mailbox_element;
typedef intrusive::blocking_single_reader_queue<mailbox_element,detail::disposer>
mailbox_type;
void cleanup(std::uint32_t reason);
private:
timeout_type init_timeout(const util::duration& rel_time);
detail::recursive_queue_node* await_message();
detail::recursive_queue_node* await_message(const timeout_type& abs_time);
bool m_initialized;
protected:
mailbox_type m_mailbox;
};
typedef intrusive_ptr<thread_mapped_actor> thread_mapped_actor_ptr;
......
......@@ -28,149 +28,142 @@
\******************************************************************************/
#ifndef CPPA_INTRUSIVE_FWD_PTR_HPP
#define CPPA_INTRUSIVE_FWD_PTR_HPP
#ifndef CPPA_THREADED_HPP
#define CPPA_THREADED_HPP
#include <memory>
#include <mutex>
#include <chrono>
#include <condition_variable>
#include "cppa/util/comparable.hpp"
#include "cppa/mailbox_element.hpp"
#include "cppa/util/dptr.hpp"
#include "cppa/detail/sync_request_bouncer.hpp"
#include "cppa/intrusive/single_reader_queue.hpp"
namespace cppa { namespace detail { class receive_policy; } }
namespace cppa {
/**
* @brief A reference counting smart pointer implementation that
* can be used with forward declarated types.
* @warning libcppa assumes T is derived from ref_counted and
* implicitly converts intrusive_fwd_ptr to intrusive_ptr
* @relates intrusive_ptr
* @relates ref_counted
*/
template<typename T, typename Ref, typename Deref>
class intrusive_fwd_ptr : util::comparable<intrusive_fwd_ptr<T,Ref,Deref> >,
util::comparable<intrusive_fwd_ptr<T,Ref,Deref>, const T*>,
util::comparable<intrusive_fwd_ptr<T,Ref,Deref>, std::nullptr_t> {
template<class Base, class Subtype>
class threaded : public Base {
friend class detail::receive_policy;
typedef std::unique_lock<std::mutex> lock_type;
public:
typedef T* pointer;
typedef const T* const_pointer;
typedef T element_type;
typedef T& reference;
typedef const T& const_reference;
template<typename... Ts>
threaded(Ts&&... args) : Base(std::forward<Ts>(args)...) { }
intrusive_fwd_ptr(pointer raw_ptr = nullptr, Ref ref = Ref(), Deref deref = Deref())
: m_ref(std::move(ref)), m_deref(std::move(deref)) { set_ptr(raw_ptr); }
inline void reset_timeout() { }
intrusive_fwd_ptr(intrusive_fwd_ptr&& other)
: m_ref(std::move(other.m_ref))
, m_deref(std::move(m_deref))
, m_ptr(other.release()) { }
inline void request_timeout(const util::duration&) { }
intrusive_fwd_ptr(const intrusive_fwd_ptr& other)
: m_ref(other.m_ref), m_deref(other.m_deref) { set_ptr(other.get()); }
inline void handle_timeout(behavior& bhvr) { bhvr.handle_timeout(); }
~intrusive_fwd_ptr() { if (m_ptr) m_deref(m_ptr); }
inline void pop_timeout() { }
inline void swap(intrusive_fwd_ptr& other) {
std::swap(m_ptr, other.m_ptr);
}
inline void push_timeout() { }
/**
* @brief Returns the raw pointer without modifying reference count.
*/
pointer release() {
auto result = m_ptr;
m_ptr = nullptr;
return result;
}
inline bool waits_for_timeout(std::uint32_t) { return false; }
/**
* @brief Sets this pointer to @p ptr without modifying reference count.
*/
void adopt(pointer ptr) {
reset();
m_ptr = ptr;
mailbox_element* pop() {
wait_for_data();
return this->m_mailbox.try_pop();
}
void reset(pointer new_value = nullptr) {
if (m_ptr) m_deref(m_ptr);
set_ptr(new_value);
inline mailbox_element* try_pop() {
return this->m_mailbox.try_pop();
}
template<typename... Args>
void emplace(Args&&... args) {
reset(new T(std::forward<Args>(args)...));
template<typename TimePoint>
mailbox_element* try_pop(const TimePoint& abs_time) {
return (timed_wait_for_data(abs_time)) ? try_pop() : nullptr;
}
intrusive_fwd_ptr& operator=(pointer ptr) {
reset(ptr);
return *this;
bool push_back(mailbox_element* new_element) {
switch (this->m_mailbox.enqueue(new_element)) {
case intrusive::first_enqueued: {
lock_type guard(m_mtx);
m_cv.notify_one();
return true;
}
default: return true;
case intrusive::queue_closed: return false;
}
intrusive_fwd_ptr& operator=(intrusive_fwd_ptr&& other) {
swap(other);
return *this;
}
intrusive_fwd_ptr& operator=(const intrusive_fwd_ptr& other) {
intrusive_fwd_ptr tmp(other);
swap(tmp);
return *this;
void run_detached() {
auto dthis = util::dptr<Subtype>(this);
dthis->init();
dthis->m_bhvr_stack.exec(dthis->m_recv_policy, dthis);
dthis->on_exit();
}
inline pointer get() const { return m_ptr; }
protected:
inline pointer operator->() const { return m_ptr; }
typedef threaded combined_type;
inline reference operator*() const { return *m_ptr; }
virtual void enqueue(const actor_ptr& sender, any_tuple msg) {
auto ptr = this->new_mailbox_element(sender, std::move(msg));
push_back(ptr);
}
inline bool operator!() const { return m_ptr == nullptr; }
virtual void sync_enqueue(const actor_ptr& sender, message_id id, any_tuple msg) {
auto ptr = this->new_mailbox_element(sender, std::move(msg), id);
if (!push_back(ptr)) {
detail::sync_request_bouncer f{this->exit_reason()};
f(sender, id);
}
}
inline explicit operator bool() const { return m_ptr != nullptr; }
typedef std::chrono::high_resolution_clock::time_point timeout_type;
inline ptrdiff_t compare(const_pointer ptr) const {
return static_cast<ptrdiff_t>(get() - ptr);
timeout_type init_timeout(const util::duration& rel_time) {
auto result = std::chrono::high_resolution_clock::now();
result += rel_time;
return result;
}
inline ptrdiff_t compare(const intrusive_fwd_ptr& other) const {
return compare(other.get());
mailbox_element* await_message() {
return pop();
}
inline ptrdiff_t compare(std::nullptr_t) const {
return reinterpret_cast<ptrdiff_t>(get());
mailbox_element* await_message(const timeout_type& abs_time) {
return try_pop(abs_time);
}
private:
Ref m_ref;
Deref m_deref;
pointer m_ptr;
bool timed_wait_for_data(const timeout_type& abs_time) {
CPPA_REQUIRE(not this->m_mailbox.closed());
if (this->m_mailbox.empty()) {
lock_type guard(m_mtx);
while (this->m_mailbox.empty()) {
if (m_cv.wait_until(guard, abs_time) == std::cv_status::timeout) {
return false;
}
}
}
return true;
}
inline void set_ptr(pointer raw_ptr) {
m_ptr = raw_ptr;
if (raw_ptr) m_ref(raw_ptr);
void wait_for_data() {
if (this->m_mailbox.empty()) {
lock_type guard(m_mtx);
while (this->m_mailbox.empty()) m_cv.wait(guard);
}
}
};
std::mutex m_mtx;
std::condition_variable m_cv;
/**
* @relates intrusive_ptr
*/
template<typename T, typename Ref, typename Deref>
inline bool operator==(const intrusive_fwd_ptr<T,Ref,Deref>& lhs,
const intrusive_fwd_ptr<T,Ref,Deref>& rhs) {
return lhs.get() == rhs.get();
}
/**
* @relates intrusive_ptr
*/
template<typename T, typename Ref, typename Deref>
inline bool operator!=(const intrusive_fwd_ptr<T,Ref,Deref>& lhs,
const intrusive_fwd_ptr<T,Ref,Deref>& rhs) {
return !(lhs == rhs);
}
};
} // namespace cppa
#endif // CPPA_INTRUSIVE_FWD_PTR_HPP
#endif // CPPA_THREADED_HPP
......@@ -43,22 +43,22 @@
namespace cppa {
template<class Expr, class Guard, typename Result, typename... Args>
template<class Expr, class Guard, typename Result, typename... Ts>
class tpartial_function {
typedef typename util::get_callable_trait<Expr>::type ctrait;
typedef typename ctrait::arg_types ctrait_args;
static constexpr size_t num_expr_args = util::tl_size<ctrait_args>::value;
static_assert(util::tl_exists<util::type_list<Args...>,
static_assert(util::tl_exists<util::type_list<Ts...>,
std::is_rvalue_reference >::value == false,
"partial functions using rvalue arguments are not supported");
public:
typedef util::type_list<Args...> arg_types;
typedef util::type_list<Ts...> arg_types;
static constexpr size_t num_arguments = sizeof...(Args);
static constexpr size_t num_arguments = sizeof...(Ts);
static constexpr bool manipulates_args =
util::tl_exists<arg_types, util::is_mutable_ref>::value;
......@@ -78,11 +78,11 @@ class tpartial_function {
tpartial_function(const tpartial_function&) = default;
bool defined_at(Args... args) const {
bool defined_at(Ts... args) const {
return m_guard(args...);
}
result_type operator()(Args... args) const {
result_type operator()(Ts... args) const {
auto targs = std::forward_as_tuple(args...);
auto indices = util::get_right_indices<num_expr_args>(targs);
return util::apply_args(m_expr, targs, indices);
......@@ -95,34 +95,34 @@ class tpartial_function {
};
template<class Expr, class Guard, typename Args,
template<class Expr, class Guard, typename Ts,
typename Result = util::void_type, size_t Step = 0>
struct get_tpartial_function;
template<class Expr, class Guard, typename... Args, typename Result>
struct get_tpartial_function<Expr, Guard, util::type_list<Args...>, Result, 1> {
typedef tpartial_function<Expr, Guard, Result, Args...> type;
template<class Expr, class Guard, typename... Ts, typename Result>
struct get_tpartial_function<Expr, Guard, util::type_list<Ts...>, Result, 1> {
typedef tpartial_function<Expr, Guard, Result, Ts...> type;
};
template<class Expr, class Guard, typename... Args>
template<class Expr, class Guard, typename... Ts>
struct get_tpartial_function<Expr, Guard,
util::type_list<Args...>, util::void_type, 0> {
util::type_list<Ts...>, util::void_type, 0> {
typedef typename util::get_callable_trait<Expr>::type ctrait;
typedef typename ctrait::arg_types arg_types;
static_assert(util::tl_size<arg_types>::value <= sizeof...(Args),
static_assert(util::tl_size<arg_types>::value <= sizeof...(Ts),
"Functor takes too much arguments");
typedef typename get_tpartial_function<
Expr,
Guard,
// fill arg_types of Expr from left with const Args&
// fill arg_types of Expr from left with const Ts&
typename util::tl_zip<
typename util::tl_pad_left<
typename ctrait::arg_types,
sizeof...(Args)
sizeof...(Ts)
>::type,
util::type_list<const Args&...>,
util::type_list<const Ts&...>,
util::left_or_right
>::type,
typename ctrait::result_type,
......
......@@ -44,16 +44,16 @@ inline auto apply_args(F& f, Tuple& tup, util::int_list<Is...>)
return f(get_cv_aware<Is>(tup)...);
}
template<typename F, class Tuple, long... Is, typename... Args>
inline auto apply_args_prefixed(F& f, Tuple& tup, util::int_list<Is...>, Args&&... args)
-> decltype(f(std::forward<Args>(args)..., get_cv_aware<Is>(tup)...)) {
return f(std::forward<Args>(args)..., get_cv_aware<Is>(tup)...);
template<typename F, class Tuple, long... Is, typename... Ts>
inline auto apply_args_prefixed(F& f, Tuple& tup, util::int_list<Is...>, Ts&&... args)
-> decltype(f(std::forward<Ts>(args)..., get_cv_aware<Is>(tup)...)) {
return f(std::forward<Ts>(args)..., get_cv_aware<Is>(tup)...);
}
template<typename F, class Tuple, long... Is, typename... Args>
inline auto apply_args_suffxied(F& f, Tuple& tup, util::int_list<Is...>, Args&&... args)
-> decltype(f(get_cv_aware<Is>(tup)..., std::forward<Args>(args)...)) {
return f(get_cv_aware<Is>(tup)..., std::forward<Args>(args)...);
template<typename F, class Tuple, long... Is, typename... Ts>
inline auto apply_args_suffxied(F& f, Tuple& tup, util::int_list<Is...>, Ts&&... args)
-> decltype(f(get_cv_aware<Is>(tup)..., std::forward<Ts>(args)...)) {
return f(get_cv_aware<Is>(tup)..., std::forward<Ts>(args)...);
}
} } // namespace cppa::util
......
......@@ -45,7 +45,7 @@ enum buffer_write_policy {
};
/**
*
* @brief
*/
class buffer {
......
......@@ -36,60 +36,63 @@
#include "cppa/util/rm_ref.hpp"
#include "cppa/util/type_list.hpp"
#include "cppa/util/conjunction.hpp"
namespace cppa { namespace util {
template<typename Signature>
struct callable_trait;
// member function pointer (const)
template<class C, typename ResultType, typename... Args>
struct callable_trait<ResultType (C::*)(Args...) const> {
typedef ResultType result_type;
typedef type_list<Args...> arg_types;
// member const function pointer
template<class C, typename Result, typename... Ts>
struct callable_trait<Result (C::*)(Ts...) const> {
typedef Result result_type;
typedef type_list<Ts...> arg_types;
};
// member function pointer
template<class C, typename ResultType, typename... Args>
struct callable_trait<ResultType (C::*)(Args...)> {
typedef ResultType result_type;
typedef type_list<Args...> arg_types;
template<class C, typename Result, typename... Ts>
struct callable_trait<Result (C::*)(Ts...)> {
typedef Result result_type;
typedef type_list<Ts...> arg_types;
};
// good ol' function
template<typename ResultType, typename... Args>
struct callable_trait<ResultType (Args...)> {
typedef ResultType result_type;
typedef type_list<Args...> arg_types;
template<typename Result, typename... Ts>
struct callable_trait<Result (Ts...)> {
typedef Result result_type;
typedef type_list<Ts...> arg_types;
};
// good ol' function pointer
template<typename ResultType, typename... Args>
struct callable_trait<ResultType (*)(Args...)> {
typedef ResultType result_type;
typedef type_list<Args...> arg_types;
template<typename Result, typename... Ts>
struct callable_trait<Result (*)(Ts...)> {
typedef Result result_type;
typedef type_list<Ts...> arg_types;
};
template<bool IsFun, bool IsMemberFun, typename C>
// matches (IsFun || IsMemberFun)
template<bool IsFun, bool IsMemberFun, typename T>
struct get_callable_trait_helper {
typedef callable_trait<C> type;
typedef callable_trait<T> type;
};
// assume functor providing operator()
template<typename C>
struct get_callable_trait_helper<false, false, C> {
// assuming functor
typedef callable_trait<decltype(&C::operator())> type;
};
template<typename C>
template<typename T>
struct get_callable_trait {
typedef typename rm_ref<C>::type fun_type;
typedef typename
get_callable_trait_helper< ( std::is_function<fun_type>::value
|| std::is_function<typename std::remove_pointer<fun_type>::type>::value),
std::is_member_function_pointer<fun_type>::value,
fun_type>::type
// type without cv qualifiers
typedef typename rm_ref<T>::type bare_type;
// if type is a function pointer, this typedef identifies the function
typedef typename std::remove_pointer<bare_type>::type fun_type;
typedef typename get_callable_trait_helper<
std::is_function<bare_type>::value
|| std::is_function<fun_type>::value,
std::is_member_function_pointer<bare_type>::value,
bare_type
>::type
type;
typedef typename type::result_type result_type;
typedef typename type::arg_types arg_types;
......@@ -101,51 +104,6 @@ struct get_arg_types {
typedef typename trait_type::arg_types types;
};
template<typename T>
struct is_callable {
template<typename C>
static bool _fun(C*, typename callable_trait<C>::result_type* = nullptr) {
return true;
}
template<typename C>
static bool _fun(C*, typename callable_trait<decltype(&C::operator())>::result_type* = nullptr) {
return true;
}
static void _fun(void*) { }
typedef decltype(_fun(static_cast<typename rm_ref<T>::type*>(nullptr)))
result_type;
public:
static constexpr bool value = std::is_same<bool, result_type>::value;
};
template<typename... Ts>
struct all_callable {
static constexpr bool value = conjunction<is_callable<Ts>...>::value;
};
template<bool IsCallable, typename C>
struct get_result_type_impl {
typedef typename get_callable_trait<C>::type trait_type;
typedef typename trait_type::result_type type;
};
template<typename C>
struct get_result_type_impl<false, C> {
typedef void_type type;
};
template<typename C>
struct get_result_type {
typedef typename get_result_type_impl<is_callable<C>::value, C>::type type;
};
} } // namespace cppa::util
#endif // CPPA_UTIL_CALLABLE_TRAIT
......@@ -28,34 +28,33 @@
\******************************************************************************/
#ifndef CPPA_IF_ELSE_HPP
#define CPPA_IF_ELSE_HPP
#ifndef CPPA_DTHIS_HPP
#define CPPA_DTHIS_HPP
#include "cppa/util/wrapped.hpp"
#include <type_traits>
namespace cppa { namespace util {
// if (IfStmt == true) type = T; else type = Else::type;
template<bool IfStmt, typename T, class Else>
struct if_else_c {
typedef T type;
};
template<typename T, class Else>
struct if_else_c<false, T, Else> {
typedef typename Else::type type;
};
/**
* @brief A conditinal expression for types that allows
* nested statements (unlike std::conditional).
*
* @c type is defined as @p T if <tt>IfStmt == true</tt>;
* otherwise @c type is defined as @p Else::type.
* @brief Returns <tt>static_cast<Subtype*>(ptr)</tt> if @p Subtype is a
* derived type of @p MixinType, returns @p ptr without cast otherwise.
*/
template<class Stmt, typename T, class Else>
struct if_else : if_else_c<Stmt::value, T, Else> { };
template<class Subtype, class MixinType>
typename std::conditional<
std::is_base_of<MixinType,Subtype>::value,
Subtype,
MixinType
>::type*
dptr(MixinType* ptr) {
typedef typename std::conditional<
std::is_base_of<MixinType,Subtype>::value,
Subtype,
MixinType
>::type
result_type;
return static_cast<result_type*>(ptr);
}
} } // namespace cppa::util
#endif // CPPA_IF_ELSE_HPP
#endif // CPPA_DTHIS_HPP
......@@ -28,20 +28,30 @@
\******************************************************************************/
#ifndef CPPA_CHANNEL_HPP
#define CPPA_CHANNEL_HPP
#ifndef CPPA_GET_RESULT_TYPE_HPP
#define CPPA_GET_RESULT_TYPE_HPP
#include "cppa/ref_counted.hpp"
#include "cppa/util/is_callable.hpp"
#include "cppa/util/callable_trait.hpp"
namespace cppa { class message; }
namespace cppa { namespace util {
namespace cppa { namespace detail {
template<bool IsCallable, typename C>
struct get_result_type_impl {
typedef typename get_callable_trait<C>::type trait_type;
typedef typename trait_type::result_type type;
};
template<typename C>
struct get_result_type_impl<false, C> {
typedef void_type type;
};
// public part of the actor interface
struct channel : ref_counted {
virtual void enqueue_msg(const message& msg) = 0;
template<typename C>
struct get_result_type {
typedef typename get_result_type_impl<is_callable<C>::value, C>::type type;
};
} } // namespace cppa::detail
} } // namespace cppa::util
#endif // CPPA_CHANNEL_HPP
#endif // CPPA_GET_RESULT_TYPE_HPP
......@@ -28,33 +28,43 @@
\******************************************************************************/
#include "cppa/cppa.hpp"
#include "cppa/receive.hpp"
#ifndef CPPA_IS_CALLABLE_HPP
#define CPPA_IS_CALLABLE_HPP
namespace cppa {
#include "cppa/util/conjunction.hpp"
#include "cppa/util/callable_trait.hpp"
void receive_loop(behavior& rules) {
local_actor* sptr = self;
for (;;) {
sptr->dequeue(rules);
}
}
namespace cppa { namespace util {
template<typename T>
struct is_callable {
void receive_loop(behavior&& rules) {
behavior tmp(std::move(rules));
receive_loop(tmp);
}
template<typename C>
static bool _fun(C*, typename callable_trait<C>::result_type* = nullptr) {
return true;
}
void receive_loop(partial_function& rules) {
local_actor* sptr = self;
for (;;) {
sptr->dequeue(rules);
template<typename C>
static bool _fun(C*, typename callable_trait<decltype(&C::operator())>::result_type* = nullptr) {
return true;
}
}
void receive_loop(partial_function&& rules) {
partial_function tmp(std::move(rules));
receive_loop(tmp);
}
static void _fun(void*) { }
typedef decltype(_fun(static_cast<typename rm_ref<T>::type*>(nullptr)))
result_type;
public:
static constexpr bool value = std::is_same<bool, result_type>::value;
};
template<typename... Ts>
struct all_callable {
static constexpr bool value = conjunction<is_callable<Ts>...>::value;
};
} } // namespace cppa::util
} // namespace cppa
#endif // CPPA_IS_CALLABLE_HPP
......@@ -35,6 +35,7 @@
#include "cppa/guard_expr.hpp"
#include "cppa/util/rm_ref.hpp"
#include "cppa/util/rebindable_reference.hpp"
namespace cppa { namespace util {
......@@ -44,12 +45,12 @@ struct purge_refs_impl {
};
template<typename T>
struct purge_refs_impl<ge_reference_wrapper<T> > {
struct purge_refs_impl<util::rebindable_reference<T> > {
typedef T type;
};
template<typename T>
struct purge_refs_impl<ge_mutable_reference_wrapper<T> > {
struct purge_refs_impl<util::rebindable_reference<const T> > {
typedef T type;
};
......@@ -58,6 +59,11 @@ struct purge_refs_impl<std::reference_wrapper<T> > {
typedef T type;
};
template<typename T>
struct purge_refs_impl<std::reference_wrapper<const T> > {
typedef T type;
};
/**
* @brief Removes references and reference wrappers.
*/
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* 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/>. *
\******************************************************************************/
#ifndef CPPA_REBINDABLE_REFERENCE_HPP
#define CPPA_REBINDABLE_REFERENCE_HPP
#include "cppa/config.hpp"
#include "cppa/util/get_result_type.hpp"
namespace cppa { namespace util {
template<typename T>
struct call_helper {
typedef typename get_result_type<T>::type result_type;
template<typename... Ts>
result_type operator()(T& f, const Ts&... args) const {
return f(std::forward<Ts>(args)...);
}
};
template<>
struct call_helper<bool> {
typedef bool result_type;
bool operator()(const bool& value) const {
return value;
}
};
template<>
struct call_helper<const bool> : call_helper<bool> { };
/**
* @brief A reference wrapper similar to std::reference_wrapper, but
* allows rebinding the reference. Note that this wrapper can
* be 'dangling', because it provides a default constructor.
*/
template<typename T>
class rebindable_reference {
public:
rebindable_reference() : m_ptr(nullptr) { }
rebindable_reference(T& value) : m_ptr(&value) { }
template<typename U>
rebindable_reference(const rebindable_reference<U>& other) : m_ptr(other.ptr()) { }
inline bool bound() const {
return m_ptr != nullptr;
}
inline void rebind(T& value) {
m_ptr = &value;
}
template<typename U>
inline void rebind(const rebindable_reference<U>& other) {
m_ptr = other.ptr();
}
inline T* ptr() const {
CPPA_REQUIRE(bound());
return m_ptr;
}
inline T& get() const {
CPPA_REQUIRE(bound());
return *m_ptr;
}
inline operator T&() const {
CPPA_REQUIRE(bound());
return *m_ptr;
}
template<typename... Ts>
typename call_helper<T>::result_type operator()(Ts&&... args) {
call_helper<T> f;
return f(get(), std::forward<Ts>(args)...);
}
private:
T* m_ptr;
};
} } // namespace cppa::util
#endif // CPPA_REBINDABLE_REFERENCE_HPP
......@@ -54,8 +54,7 @@ namespace cppa { namespace util {
template<typename What, typename With, typename... IfStmt>
struct replace_type {
static constexpr bool do_replace = disjunction<IfStmt::value...>::value;
typedef typename detail::replace_type<do_replace, What, With>::type
type;
typedef typename detail::replace_type<do_replace, What, With>::type type;
};
} } // namespace cppa::util
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* 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/>. *
\******************************************************************************/
#ifndef CPPA_STATIC_FOREACH_HPP
#define CPPA_STATIC_FOREACH_HPP
#include "cppa/get.hpp"
namespace cppa { namespace util {
template<bool BeginLessEnd, size_t Begin, size_t End>
struct static_foreach_impl {
template<typename Container, typename Fun, typename... Args>
static inline void _(const Container& c, Fun& f, Args&&... args) {
f(get<Begin>(c), std::forward<Args>(args)...);
static_foreach_impl<(Begin+1 < End), Begin+1, End>
::_(c, f, std::forward<Args>(args)...);
}
template<typename Container, typename Fun, typename... Args>
static inline void _ref(Container& c, Fun& f, Args&&... args) {
f(get_ref<Begin>(c), std::forward<Args>(args)...);
static_foreach_impl<(Begin+1 < End), Begin+1, End>
::_ref(c, f, std::forward<Args>(args)...);
}
template<typename Container, typename Fun, typename... Args>
static inline void _auto(Container& c, Fun& f, Args&&... args) {
_ref(c, f, std::forward<Args>(args)...);
}
template<typename Container, typename Fun, typename... Args>
static inline void _auto(const Container& c, Fun& f, Args&&... args) {
_(c, f, std::forward<Args>(args)...);
}
template<typename Container, typename Fun, typename... Args>
static inline bool eval(const Container& c, Fun& f, Args&&... args) {
return f(get<Begin>(c), std::forward<Args>(args)...)
&& static_foreach_impl<(Begin+1 < End), Begin+1, End>
::eval(c, f, std::forward<Args>(args)...);
}
template<typename Container, typename Fun, typename... Args>
static inline bool eval_or(const Container& c, Fun& f, Args&&... args) {
return f(get<Begin>(c), std::forward<Args>(args)...)
|| static_foreach_impl<(Begin+1 < End), Begin+1, End>
::eval_or(c, f, std::forward<Args>(args)...);
}
};
template<size_t X, size_t Y>
struct static_foreach_impl<false, X, Y> {
template<typename... Args>
static inline void _(Args&&...) { }
template<typename... Args>
static inline void _ref(Args&&...) { }
template<typename... Args>
static inline void _auto(Args&&...) { }
template<typename... Args>
static inline bool eval(Args&&...) { return true; }
template<typename... Args>
static inline bool eval_or(Args&&...) { return false; }
};
/**
* @ingroup MetaProgramming
* @brief A for loop that can be used with tuples.
*/
template<size_t Begin, size_t End>
struct static_foreach : static_foreach_impl<(Begin < End), Begin, End> {
};
} } // namespace cppa::util
#endif // CPPA_STATIC_FOREACH_HPP
......@@ -36,7 +36,6 @@
#include "cppa/util/at.hpp"
#include "cppa/util/tbind.hpp"
#include "cppa/util/if_else.hpp"
#include "cppa/util/type_pair.hpp"
#include "cppa/util/void_type.hpp"
......@@ -911,10 +910,10 @@ struct tl_is_zipped {
*/
template<class List, typename What = void_type>
struct tl_trim {
typedef typename util::if_else<
std::is_same<typename tl_back<List>::type, What>,
typedef typename std::conditional<
std::is_same<typename tl_back<List>::type,What>::value,
typename tl_trim<typename tl_pop_back<List>::type, What>::type,
util::wrapped<List>
List
>::type
type;
};
......
......@@ -35,7 +35,7 @@ namespace cppa { namespace util {
/**
* @ingroup MetaProgramming
* @brief A type wrapper as used in {@link cppa::util::if_else if_else}.
* @brief A simple type wrapper.
*/
template<typename T>
struct wrapped {
......
......@@ -69,7 +69,7 @@ bool actor::chained_enqueue(const actor_ptr& sender, any_tuple msg) {
return false;
}
bool actor::chained_sync_enqueue(const actor_ptr& ptr, message_id_t id, any_tuple msg) {
bool actor::chained_sync_enqueue(const actor_ptr& ptr, message_id id, any_tuple msg) {
sync_enqueue(ptr, id, std::move(msg));
return false;
}
......
......@@ -62,7 +62,7 @@ struct behavior_stack_mover : iterator<output_iterator_tag,void,void,void,void>{
inline behavior_stack_mover move_iter(behavior_stack* bs) { return {bs}; }
option<behavior&> behavior_stack::sync_handler(message_id_t expected_response) {
option<behavior&> behavior_stack::sync_handler(message_id expected_response) {
if (expected_response.valid()) {
auto e = m_elements.rend();
auto i = find_if(m_elements.rbegin(), e, [=](element_type& val) {
......
......@@ -48,12 +48,12 @@ auto context_switching_actor::init_timeout(const util::duration& tout) -> timeou
return {};
}
detail::recursive_queue_node* context_switching_actor::await_message(const timeout_type&) {
mailbox_element* context_switching_actor::await_message(const timeout_type&) {
// receives requested timeout message if timeout occured
return await_message();
}
detail::recursive_queue_node* context_switching_actor::await_message() {
mailbox_element* context_switching_actor::await_message() {
auto e = m_mailbox.try_pop();
while (e == nullptr) {
if (m_mailbox.can_fetch_more() == false) {
......
......@@ -42,11 +42,11 @@ using namespace std;
namespace cppa { namespace network {
inline sync_request_info* new_req_info(actor_ptr sptr, message_id_t id) {
inline sync_request_info* new_req_info(actor_ptr sptr, message_id id) {
return detail::memory::create<sync_request_info>(std::move(sptr), id);
}
sync_request_info::sync_request_info(actor_ptr sptr, message_id_t id)
sync_request_info::sync_request_info(actor_ptr sptr, message_id id)
: next(nullptr), sender(std::move(sptr)), mid(id) { }
default_actor_proxy::default_actor_proxy(actor_id mid,
......@@ -89,7 +89,7 @@ void default_actor_proxy::deliver(const network::message_header& hdr, any_tuple
void default_actor_proxy::forward_msg(const actor_ptr& sender,
any_tuple msg,
message_id_t mid) {
message_id mid) {
CPPA_LOG_TRACE("");
if (sender && mid.is_request()) {
switch (m_pending_requests.enqueue(new_req_info(sender, mid))) {
......@@ -147,7 +147,7 @@ void default_actor_proxy::enqueue(const actor_ptr& sender, any_tuple msg) {
}
void default_actor_proxy::sync_enqueue(const actor_ptr& sender,
message_id_t mid,
message_id mid,
any_tuple msg) {
CPPA_LOG_TRACE(CPPA_TARG(sender, to_string) << ", "
<< CPPA_MARG(mid, integer_value) << ", "
......
......@@ -78,11 +78,7 @@ void event_based_actor::dequeue(behavior&) {
quit(exit_reason::unallowed_function_call);
}
void event_based_actor::dequeue(partial_function&) {
quit(exit_reason::unallowed_function_call);
}
void event_based_actor::dequeue_response(behavior&, message_id_t) {
void event_based_actor::dequeue_response(behavior&, message_id) {
quit(exit_reason::unallowed_function_call);
}
......@@ -142,7 +138,7 @@ resume_result event_based_actor::resume(util::fiber*, actor_ptr& next_job) {
}
else {
CPPA_LOG_DEBUG("try to invoke message: " << to_string(e->msg));
if (m_bhvr_stack.invoke(m_policy, this, e)) {
if (m_bhvr_stack.invoke(m_recv_policy, this, e)) {
CPPA_LOG_DEBUG_IF(m_chained_actor,
"set actor with ID "
<< m_chained_actor->id()
......@@ -193,7 +189,7 @@ void event_based_actor::do_become(behavior&& bhvr, bool discard_old) {
m_bhvr_stack.push_back(std::move(bhvr));
}
void event_based_actor::become_waiting_for(behavior&& bhvr, message_id_t mf) {
void event_based_actor::become_waiting_for(behavior bhvr, message_id mf) {
if (bhvr.timeout().valid()) {
reset_timeout();
request_timeout(bhvr.timeout());
......
......@@ -182,9 +182,9 @@ class local_group_proxy : public local_group {
public:
template<typename... Args>
local_group_proxy(actor_ptr remote_broker, Args&&... args)
: super(false, forward<Args>(args)...) {
template<typename... Ts>
local_group_proxy(actor_ptr remote_broker, Ts&&... args)
: super(false, forward<Ts>(args)...) {
CPPA_REQUIRE(m_broker == nullptr);
CPPA_REQUIRE(remote_broker != nullptr);
CPPA_REQUIRE(remote_broker->is_proxy());
......
......@@ -75,11 +75,11 @@ local_actor::local_actor(bool sflag)
: m_chaining(sflag), m_trap_exit(false)
, m_is_scheduled(sflag), m_dummy_node(), m_current_node(&m_dummy_node) { }
void local_actor::monitor(actor_ptr whom) {
void local_actor::monitor(const actor_ptr& whom) {
if (whom) whom->attach(attachable_ptr{new down_observer(this, whom)});
}
void local_actor::demonitor(actor_ptr whom) {
void local_actor::demonitor(const actor_ptr& whom) {
attachable::token mtoken{typeid(down_observer), this};
if (whom) whom->detach(mtoken);
}
......@@ -113,12 +113,12 @@ void local_actor::reply_message(any_tuple&& what) {
}
auto& id = m_current_node->mid;
if (id.valid() == false || id.is_response()) {
send_message(whom, std::move(what));
send_message(whom.get(), std::move(what));
}
else if (!id.is_answered()) {
if (chaining_enabled()) {
if (whom->chained_sync_enqueue(this, id.response_id(), std::move(what))) {
m_chained_actor = whom;
chained_actor(whom);
}
}
else {
......@@ -140,7 +140,7 @@ void local_actor::forward_message(const actor_ptr& new_receiver) {
else {
new_receiver->sync_enqueue(from.get(), id, m_current_node->msg);
// treat this message as asynchronous message from now on
m_current_node->mid = message_id_t();
m_current_node->mid = message_id();
}
}
......@@ -151,7 +151,7 @@ response_handle local_actor::make_response_handle() {
return std::move(result);
}
message_id_t local_actor::send_timed_sync_message(const actor_ptr& whom,
message_id local_actor::send_timed_sync_message(const actor_ptr& whom,
const util::duration& rel_time,
any_tuple&& what) {
auto mid = this->send_sync_message(whom, std::move(what));
......@@ -164,10 +164,6 @@ void local_actor::exec_behavior_stack() {
// default implementation does nothing
}
sync_handle_helper local_actor::handle_response(const message_future& mf) {
return ::cppa::handle_response(mf);
}
void local_actor::cleanup(std::uint32_t reason) {
m_subscriptions.clear();
super::cleanup(reason);
......
......@@ -33,8 +33,6 @@
#include <fstream>
#include <algorithm>
#include <execinfo.h> //DEL_ME
#ifndef CPPA_WINDOWS
#include <unistd.h>
#include <sys/types.h>
......
......@@ -28,13 +28,13 @@
\******************************************************************************/
#include "cppa/detail/recursive_queue_node.hpp"
#include "cppa/mailbox_element.hpp"
namespace cppa { namespace detail {
namespace cppa {
recursive_queue_node::recursive_queue_node(const actor_ptr& sptr,
mailbox_element::mailbox_element(const actor_ptr& sptr,
any_tuple data,
message_id_t id)
message_id id)
: next(nullptr), marked(false), sender(sptr), msg(std::move(data)), mid(id) { }
} } // namespace cppa::detail
} // namespace cppa
......@@ -32,7 +32,7 @@
#include <typeinfo>
#include "cppa/detail/memory.hpp"
#include "cppa/detail/recursive_queue_node.hpp"
#include "cppa/mailbox_element.hpp"
using namespace std;
......@@ -64,8 +64,8 @@ cache_map& get_cache_map() {
cache = new cache_map;
pthread_setspecific(s_key, cache);
// insert default types
unique_ptr<memory_cache> tmp(new basic_memory_cache<recursive_queue_node>);
cache->insert(make_pair(&typeid(recursive_queue_node), move(tmp)));
unique_ptr<memory_cache> tmp(new basic_memory_cache<mailbox_element>);
cache->insert(make_pair(&typeid(mailbox_element), move(tmp)));
}
return *cache;
}
......
......@@ -34,7 +34,7 @@ namespace cppa { namespace network {
message_header::message_header(const actor_ptr& s,
const actor_ptr& r,
message_id_t mid )
message_id mid )
: sender(s), receiver(r), id(mid) { }
message_header::message_header() : sender(nullptr), receiver(nullptr), id() { }
......
......@@ -40,7 +40,6 @@
#include "cppa/actor.hpp"
#include "cppa/match.hpp"
#include "cppa/config.hpp"
#include "cppa/either.hpp"
#include "cppa/logging.hpp"
#include "cppa/to_string.hpp"
#include "cppa/actor_proxy.hpp"
......
......@@ -34,14 +34,6 @@
namespace cppa { namespace network {
void protocol::ref_ftor::operator()(abstract_middleman* ptr) const {
if (ptr) ptr->ref();
}
void protocol::deref_ftor::operator()(abstract_middleman* ptr) const {
if (ptr) ptr->deref();
}
protocol::protocol(abstract_middleman* parent) : m_parent(parent) {
CPPA_REQUIRE(parent != nullptr);
}
......
......@@ -40,7 +40,7 @@ namespace cppa {
response_handle::response_handle(const actor_ptr& from,
const actor_ptr& to,
const message_id_t& id)
const message_id& id)
: m_from(from), m_to(to), m_id(id) {
CPPA_REQUIRE(id.is_response());
}
......
......@@ -80,6 +80,10 @@ scheduled_actor::~scheduled_actor() {
}
}
void scheduled_actor::run_detached() {
throw std::logic_error("scheduled_actor::run_detached called");
}
void scheduled_actor::cleanup(std::uint32_t reason) {
detail::sync_request_bouncer f{reason};
m_mailbox.close(f);
......@@ -133,7 +137,7 @@ bool scheduled_actor::enqueue(actor_state next_state,
bool scheduled_actor::sync_enqueue_impl(actor_state next,
const actor_ptr& sender,
any_tuple& msg,
message_id_t id) {
message_id id) {
bool err = false;
auto ptr = new_mailbox_element(sender, std::move(msg), id);
bool res = enqueue(next, &err, ptr);
......@@ -162,13 +166,13 @@ bool scheduled_actor::chained_enqueue(const actor_ptr& sender, any_tuple msg) {
}
void scheduled_actor::sync_enqueue(const actor_ptr& sender,
message_id_t id,
message_id id,
any_tuple msg) {
sync_enqueue_impl(actor_state::ready, sender, msg, id);
}
bool scheduled_actor::chained_sync_enqueue(const actor_ptr& sender,
message_id_t id,
message_id id,
any_tuple msg) {
return sync_enqueue_impl(actor_state::pending, sender, msg, id);
}
......
......@@ -38,14 +38,13 @@ scheduled_actor_dummy::scheduled_actor_dummy()
void scheduled_actor_dummy::enqueue(const actor_ptr&, any_tuple) { }
void scheduled_actor_dummy::quit(std::uint32_t) { }
void scheduled_actor_dummy::dequeue(behavior&) { }
void scheduled_actor_dummy::dequeue(partial_function&) { }
void scheduled_actor_dummy::dequeue_response(behavior&, message_id_t) { }
void scheduled_actor_dummy::dequeue_response(behavior&, message_id) { }
void scheduled_actor_dummy::do_become(behavior&&, bool) { }
void scheduled_actor_dummy::become_waiting_for(behavior&&, message_id_t) { }
void scheduled_actor_dummy::become_waiting_for(behavior, message_id) { }
bool scheduled_actor_dummy::has_behavior() { return false; }
void scheduled_actor_dummy::sync_enqueue(const actor_ptr&,
message_id_t,
message_id,
any_tuple) { }
resume_result scheduled_actor_dummy::resume(util::fiber*,actor_ptr&) {
......
......@@ -68,13 +68,13 @@ class delayed_msg {
delayed_msg(const channel_ptr& arg0,
const actor_ptr& arg1,
message_id_t,
message_id,
any_tuple&& arg3)
: ptr_a(arg0), from(arg1), msg(move(arg3)) { }
delayed_msg(const actor_ptr& arg0,
const actor_ptr& arg1,
message_id_t arg2,
message_id arg2,
any_tuple&& arg3)
: ptr_b(arg0), from(arg1), id(arg2), msg(move(arg3)) { }
......@@ -94,7 +94,7 @@ class delayed_msg {
channel_ptr ptr_a;
actor_ptr ptr_b;
actor_ptr from;
message_id_t id;
message_id id;
any_tuple msg;
};
......@@ -146,7 +146,7 @@ inline void insert_dmsg(Map& storage,
const T& to,
const actor_ptr& sender,
any_tuple&& tup,
message_id_t id = message_id_t{}) {
message_id id = message_id{}) {
auto tout = hrc::now();
tout += d;
delayed_msg dmsg{to, sender, id, move(tup)};
......@@ -157,8 +157,7 @@ void scheduler_helper::timer_loop(scheduler_helper::ptr_type m_self) {
// setup & local variables
self.set(m_self.get());
bool done = false;
auto& queue = m_self->m_mailbox;
std::unique_ptr<detail::recursive_queue_node,detail::disposer> msg_ptr;
std::unique_ptr<mailbox_element,detail::disposer> msg_ptr;
auto tout = hrc::now();
std::multimap<decltype(tout),delayed_msg> messages;
// message handling rules
......@@ -170,7 +169,7 @@ void scheduler_helper::timer_loop(scheduler_helper::ptr_type m_self) {
},
on(atom("REPLY"), arg_match) >> [&](const util::duration& d,
const actor_ptr& ptr,
message_id_t id,
message_id id,
any_tuple& tup) {
insert_dmsg(messages, d, ptr, msg_ptr->sender, move(tup), id);
},
......@@ -188,7 +187,7 @@ void scheduler_helper::timer_loop(scheduler_helper::ptr_type m_self) {
// loop
while (!done) {
while (!msg_ptr) {
if (messages.empty()) msg_ptr.reset(queue.pop());
if (messages.empty()) msg_ptr.reset(m_self->pop());
else {
tout = hrc::now();
// handle timeouts (send messages)
......@@ -200,7 +199,7 @@ void scheduler_helper::timer_loop(scheduler_helper::ptr_type m_self) {
}
// wait for next message or next timeout
if (it != messages.end()) {
msg_ptr.reset(queue.try_pop(it->first));
msg_ptr.reset(m_self->try_pop(it->first));
}
}
}
......
......@@ -48,6 +48,7 @@ thread_mapped_actor::thread_mapped_actor() : super(std::function<void()>{}), m_i
thread_mapped_actor::thread_mapped_actor(std::function<void()> fun)
: super(std::move(fun)), m_initialized(false) { }
/*
auto thread_mapped_actor::init_timeout(const util::duration& rel_time) -> timeout_type {
auto result = std::chrono::high_resolution_clock::now();
result += rel_time;
......@@ -60,7 +61,7 @@ void thread_mapped_actor::enqueue(const actor_ptr& sender, any_tuple msg) {
}
void thread_mapped_actor::sync_enqueue(const actor_ptr& sender,
message_id_t id,
message_id id,
any_tuple msg) {
auto ptr = this->new_mailbox_element(sender, std::move(msg), id);
if (!this->m_mailbox.push_back(ptr)) {
......@@ -68,14 +69,7 @@ void thread_mapped_actor::sync_enqueue(const actor_ptr& sender,
f(sender, id);
}
}
detail::recursive_queue_node* thread_mapped_actor::await_message() {
return m_mailbox.pop();
}
detail::recursive_queue_node* thread_mapped_actor::await_message(const timeout_type& abs_time) {
return m_mailbox.try_pop(abs_time);
}
*/
bool thread_mapped_actor::initialized() const {
return m_initialized;
......
......@@ -204,8 +204,7 @@ actor_ptr thread_pool_scheduler::exec(spawn_options os, scheduled_actor_ptr p) {
bool is_hidden = has_hide_flag(os);
if (has_detach_flag(os)) {
exec_as_thread(is_hidden, p, [p] {
p->exec_behavior_stack();
p->on_exit();
p->run_detached();
});
return std::move(p);
}
......
......@@ -43,29 +43,27 @@
#include "cppa/atom.hpp"
#include "cppa/to_string.hpp"
#include "cppa/exception.hpp"
#include "cppa/singletons.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/binary_serializer.hpp"
#include "cppa/binary_deserializer.hpp"
#include "cppa/intrusive/single_reader_queue.hpp"
#include "cppa/network/acceptor.hpp"
#include "cppa/network/protocol.hpp"
#include "cppa/network/middleman.hpp"
#include "cppa/network/ipv4_acceptor.hpp"
#include "cppa/network/ipv4_io_stream.hpp"
#include "cppa/detail/actor_registry.hpp"
#include "cppa/detail/singleton_manager.hpp"
namespace cppa {
using namespace detail;
using namespace network;
namespace {
protocol* proto() {
return singleton_manager::get_middleman()->protocol(atom("DEFAULT")).get();
}
} // namespace <anonymous>
namespace { protocol_ptr proto() {
return get_middleman()->protocol(atom("DEFAULT")).get();
} }
void publish(actor_ptr whom, std::unique_ptr<acceptor> aptr) {
proto()->publish(whom, move(aptr), {});
......
......@@ -412,7 +412,7 @@ class msg_hdr_tinfo : public util::abstract_uniform_type_info<network::message_h
actor_ptr_tinfo::s_deserialize(msg.sender, source, actor_ptr_name);
actor_ptr_tinfo::s_deserialize(msg.receiver, source, actor_ptr_name);
auto msg_id = source->read<std::uint64_t>();
msg.id = message_id_t::from_integer_value(msg_id);
msg.id = message_id::from_integer_value(msg_id);
source->end_object();
}
......
......@@ -302,9 +302,24 @@ int main() {
);
CPPA_CHECKPOINT();
CPPA_PRINT("test mirror"); {
auto mirror = spawn<simple_mirror,monitored>();
send(mirror, "hello mirror");
receive (
on("hello mirror") >> CPPA_CHECKPOINT_CB(),
others() >> CPPA_UNEXPECTED_MSG_CB()
);
quit_actor(mirror, exit_reason::user_defined);
receive (
on(atom("DOWN"), exit_reason::user_defined) >> CPPA_CHECKPOINT_CB(),
others() >> CPPA_UNEXPECTED_MSG_CB()
);
await_all_others_done();
CPPA_CHECKPOINT();
}
CPPA_PRINT("test mirror");
CPPA_PRINT("test detached mirror"); {
auto mirror = spawn<simple_mirror,monitored+detached>();
send(mirror, "hello mirror");
receive (
on("hello mirror") >> CPPA_CHECKPOINT_CB(),
......@@ -317,6 +332,7 @@ int main() {
);
await_all_others_done();
CPPA_CHECKPOINT();
}
CPPA_PRINT("test echo actor");
auto mecho = spawn(echo_actor);
......@@ -461,7 +477,7 @@ int main() {
self->become (
on("hi") >> [&]() {
auto handle = sync_send(self->last_sender(), "whassup?");
self->handle_response(handle) (
handle_response(handle) (
on_arg_match >> [&](const string& str) {
CPPA_CHECK(self->last_sender() != nullptr);
CPPA_CHECK_EQUAL(str, "nothing");
......
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