Commit e8f7d3f1 authored by Dominik Charousset's avatar Dominik Charousset

fixed wrong commit

parent 777fc9bf
...@@ -32,27 +32,24 @@ ...@@ -32,27 +32,24 @@
#define CPPA_HPP #define CPPA_HPP
#include <tuple> #include <tuple>
#include <chrono>
#include <cstdint> #include <cstdint>
#include <functional>
#include <type_traits> #include <type_traits>
#include "cppa/on.hpp" #include "cppa/on.hpp"
#include "cppa/atom.hpp" #include "cppa/atom.hpp"
#include "cppa/self.hpp" #include "cppa/self.hpp"
#include "cppa/cow_tuple.hpp"
#include "cppa/actor.hpp" #include "cppa/actor.hpp"
#include "cppa/channel.hpp" #include "cppa/channel.hpp"
#include "cppa/receive.hpp" #include "cppa/receive.hpp"
#include "cppa/factory.hpp"
#include "cppa/behavior.hpp" #include "cppa/behavior.hpp"
#include "cppa/announce.hpp" #include "cppa/announce.hpp"
#include "cppa/sb_actor.hpp"
#include "cppa/scheduler.hpp" #include "cppa/scheduler.hpp"
#include "cppa/to_string.hpp" #include "cppa/to_string.hpp"
#include "cppa/any_tuple.hpp" #include "cppa/any_tuple.hpp"
#include "cppa/cow_tuple.hpp" #include "cppa/fsm_actor.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/local_actor.hpp" #include "cppa/local_actor.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/scheduled_actor.hpp" #include "cppa/scheduled_actor.hpp"
#include "cppa/scheduling_hint.hpp" #include "cppa/scheduling_hint.hpp"
#include "cppa/event_based_actor.hpp" #include "cppa/event_based_actor.hpp"
...@@ -72,45 +69,41 @@ ...@@ -72,45 +69,41 @@
* *
* This library provides an implementation of the actor model for C++. * This library provides an implementation of the actor model for C++.
* It uses a network transparent messaging system to ease development * It uses a network transparent messaging system to ease development
* of both concurrent and distributed software. * of both concurrent and distributed software using C++.
* *
* @p libcppa uses a thread pool to schedule actors by default. * @p libcppa uses a thread pool to schedule actors by default.
* A scheduled actor should not call blocking functions. * A scheduled actor should not call blocking functions.
* Individual actors can be spawned (created) with a special flag to run in * Individual actors can be spawned (created) with a special flag to run in
* an own thread if one needs to make use of blocking APIs. * an own thread if one needs to make use of blocking APIs.
* *
* Writing applications in @p libcppa requires a minimum of gluecode and * Writing applications in @p libcppa requires a minimum of gluecode.
* You don't have to derive a particular class to implement an actor and
* each context <i>is</i> an actor. Even main is implicitly * each context <i>is</i> an actor. Even main is implicitly
* converted to an actor if needed. * converted to an actor if needed, as the following example shows:
*
* It's recommended to read at least the
* {@link MessageHandling message handling}
* section of this documentation.
* *
* @section GettingStarted Getting Started * @section GettingStarted Getting Started
* *
* To build @p libcppa, you need <tt>GCC >= 4.7</tt> or <tt>Clang >= 3.2</tt>, * To build @p libcppa, you need <tt>GCC >= 4.6</tt>, @p Automake
* @p CMake and the <tt>Boost.Thread</tt> library. * and the <tt>Boost.Thread</tt> library.
* *
* The usual build steps on Linux and Mac OS X are: * The usual build steps on Linux and Mac OS X are:
* *
*- <tt>mkdir build</tt> * - <tt>autoreconf -i</tt>
*- <tt>cd build</tt> * - <tt>./configure</tt>
*- <tt>cmake ..</tt> * - <tt>make</tt>
*- <tt>make</tt> * - <tt>make install</tt> (as root, optionally)
*- <tt>make install</tt> (as root, optionally)
*
* Please run the unit tests as well to verify that @p libcppa works properly.
* *
*- <tt>./bin/unit_tests</tt> * Use <tt>./configure --help</tt> if the script doesn't auto-select
* * the correct @p GCC binary or doesn't find your <tt>Boost.Thread</tt>
* Please submit a bug report that includes (a) your compiler version, * installation.
* (b) your OS, and (c) the output of the unit tests if an error occurs.
* *
* Windows is not supported yet, because MVSC++ doesn't implement the * Windows is not supported yet, because MVSC++ doesn't implement the
* C++11 features needed to compile @p libcppa. * C++11 features needed to compile @p libcppa.
* *
* Please read the <b>Manual</b> for an introduction to @p libcppa.
* It is available online at
* http://neverlord.github.com/libcppa/manual/index.html or as PDF version at
* http://neverlord.github.com/libcppa/manual/libcppa_manual.pdf
*
* @section IntroHelloWorld Hello World Example * @section IntroHelloWorld Hello World Example
* *
* @include hello_world_example.cpp * @include hello_world_example.cpp
...@@ -124,32 +117,24 @@ ...@@ -124,32 +117,24 @@
* features. * features.
* *
* @namespace cppa * @namespace cppa
* @brief Root namespace of libcppa. * @brief This is the root namespace of libcppa.
*
* Thie @b cppa namespace contains all functions and classes to
* implement Actor based applications.
* *
* @namespace cppa::util * @namespace cppa::util
* @brief Contains utility classes and metaprogramming * @brief This namespace contains utility classes and metaprogramming
* utilities used by the libcppa implementation. * utilities used by the libcppa implementation.
* *
* @namespace cppa::intrusive * @namespace cppa::intrusive
* @brief Contains intrusive container implementations. * @brief This namespace contains intrusive container implementations.
*
* @namespace cppa::factory
* @brief Contains factory functions to create actors from lambdas or
* other functors.
*
* @namespace cppa::exit_reason
* @brief Contains all predefined exit reasons.
*
* @namespace cppa::placeholders
* @brief Contains the guard placeholders @p _x1 to @p _x9.
* *
* @defgroup CopyOnWrite Copy-on-write optimization. * @defgroup CopyOnWrite Copy-on-write optimization.
* @p libcppa uses a copy-on-write optimization for its message * @p libcppa uses a copy-on-write optimization for its message
* passing implementation. * passing implementation.
* *
* {@link cppa::cow_tuple Tuples} should @b always be used with by-value * {@link cppa::tuple Tuples} should @b always be used with by-value semantic,
* semantic,since tuples use a copy-on-write smart pointer internally. * since tuples use a copy-on-write smart pointer internally. Let's assume two
* Let's assume two
* tuple @p x and @p y, whereas @p y is a copy of @p x: * tuple @p x and @p y, whereas @p y is a copy of @p x:
* *
* @code * @code
...@@ -254,13 +239,16 @@ ...@@ -254,13 +239,16 @@
* to define patterns: * to define patterns:
* *
* @code * @code
* receive ( * receive
* on(atom("hello"), val<std::string>()) >> [](const std::string& msg) { * (
* on(atom("hello"), val<std::string>()) >> [](const std::string& msg)
* {
* cout << "received hello message: " << msg << endl; * cout << "received hello message: " << msg << endl;
* }, * },
* on(atom("compute"), val<int>(), val<int>()>() >> [](int i0, int i1) { * on(atom("compute"), val<int>(), val<int>(), val<int>()>() >> [](int i0, int i1, int i2)
* {
* // send our result back to the sender of this messages * // send our result back to the sender of this messages
* reply(atom("result"), i0 + i1); * reply(atom("result"), i0 + i1 + i2);
* } * }
* ); * );
* @endcode * @endcode
...@@ -275,12 +263,16 @@ ...@@ -275,12 +263,16 @@
* *
* Example actor: * Example actor:
* @code * @code
* void math_actor() { * void math_actor()
* receive_loop ( * {
* on<atom("plus"), int, int>() >> [](int a, int b) { * receive_loop
* (
* on<atom("plus"), int, int>() >> [](int a, int b)
* {
* reply(atom("result"), a + b); * reply(atom("result"), a + b);
* }, * },
* on<atom("minus"), int, int>() >> [](int a, int b) { * on<atom("minus"), int, int>() >> [](int a, int b)
* {
* reply(atom("result"), a - b); * reply(atom("result"), a - b);
* } * }
* ); * );
...@@ -308,8 +300,10 @@ ...@@ -308,8 +300,10 @@
* @code * @code
* // receive two integers * // receive two integers
* vector<int> received_values; * vector<int> received_values;
* receive_while([&]() { return received_values.size() < 2; }) ( * receive_while([&]() { return received_values.size() < 2; })
* on<int>() >> [](int value) { * (
* on<int>() >> [](int value)
* {
* received_values.push_back(value); * received_values.push_back(value);
* } * }
* ); * );
...@@ -321,7 +315,8 @@ ...@@ -321,7 +315,8 @@
* @code * @code
* std::vector<int> vec {1, 2, 3, 4}; * std::vector<int> vec {1, 2, 3, 4};
* auto i = vec.begin(); * auto i = vec.begin();
* receive_for(i, vec.end()) ( * receive_for(i, vec.end())
* (
* on(atom("get")) >> [&]() { reply(atom("result"), *i); } * on(atom("get")) >> [&]() { reply(atom("result"), *i); }
* ); * );
* @endcode * @endcode
...@@ -333,8 +328,10 @@ ...@@ -333,8 +328,10 @@
* @code * @code
* // receive ints until zero was received * // receive ints until zero was received
* vector<int> received_values; * vector<int> received_values;
* do_receive ( * do_receive
* on<int>() >> [](int value) { * (
* on<int>() >> [](int value)
* {
* received_values.push_back(value); * received_values.push_back(value);
* } * }
* ) * )
...@@ -344,18 +341,20 @@ ...@@ -344,18 +341,20 @@
* *
* @section FutureSend Send delayed messages * @section FutureSend Send delayed messages
* *
* The function @p delayed_send provides a simple way to delay a message. * The function @p future_send provides a simple way to delay a message.
* This is particularly useful for recurring events, e.g., periodical polling. * This is particularly useful for recurring events, e.g., periodical polling.
* Usage example: * Usage example:
* *
* @code * @code
* delayed_send(self, std::chrono::seconds(1), atom("poll")); * future_send(self, std::chrono::seconds(1), atom("poll"));
* receive_loop ( * receive_loop
* (
* // ... * // ...
* on<atom("poll")>() >> []() { * on<atom("poll")>() >> []()
* {
* // ... poll something ... * // ... poll something ...
* // and do it again after 1sec * // and do it again after 1sec
* delayed_send(self, std::chrono::seconds(1), atom("poll")); * future_send(self, std::chrono::seconds(1), atom("poll"));
* } * }
* ); * );
* @endcode * @endcode
...@@ -366,7 +365,7 @@ ...@@ -366,7 +365,7 @@
* *
* The message passing of @p libcppa prohibits pointers in messages because * The message passing of @p libcppa prohibits pointers in messages because
* it enforces network transparent messaging. * it enforces network transparent messaging.
* Unfortunately, string literals in @p C++ have the type <tt>const char*</tt>, * Unfortunately, string literals in @p C++ have the type <tt>char const*</tt>,
* resp. <tt>const char[]</tt>. Since @p libcppa is a user-friendly library, * resp. <tt>const char[]</tt>. Since @p libcppa is a user-friendly library,
* it silently converts string literals and C-strings to @p std::string objects. * it silently converts string literals and C-strings to @p std::string objects.
* It also converts unicode literals to the corresponding STL container. * It also converts unicode literals to the corresponding STL container.
...@@ -376,7 +375,7 @@ ...@@ -376,7 +375,7 @@
* // sends an std::string containing "hello actor!" to itself * // sends an std::string containing "hello actor!" to itself
* send(self, "hello actor!"); * send(self, "hello actor!");
* *
* const char* cstring = "cstring"; * char const* cstring = "cstring";
* // sends an std::string containing "cstring" to itself * // sends an std::string containing "cstring" to itself
* send(self, cstring); * send(self, cstring);
* *
...@@ -386,13 +385,14 @@ ...@@ -386,13 +385,14 @@
* // x has the type cppa::tuple<std::string, std::string> * // x has the type cppa::tuple<std::string, std::string>
* auto x = make_cow_tuple("hello", "tuple"); * auto x = make_cow_tuple("hello", "tuple");
* *
* receive ( * receive
* (
* // equal to: on(std::string("hello actor!")) * // equal to: on(std::string("hello actor!"))
* on("hello actor!") >> []() { } * on("hello actor!") >> []() { }
* ); * );
* @endcode * @endcode
* *
* @defgroup ActorCreation Actor creation. * @defgroup ActorManagement Actor management.
* *
*/ */
...@@ -410,7 +410,7 @@ ...@@ -410,7 +410,7 @@
*/ */
/** /**
* @brief A simple example for a delayed_send based application. * @brief A simple example for a future_send based application.
* @example dancing_kirby.cpp * @example dancing_kirby.cpp
*/ */
...@@ -421,323 +421,295 @@ ...@@ -421,323 +421,295 @@
namespace cppa { namespace cppa {
#ifdef CPPA_DOCUMENTATION
/** /**
* @ingroup MessageHandling * @ingroup ActorManagement
* @{ * @brief Links @p lhs and @p rhs;
* @pre <tt>lhs != rhs</tt>
*/ */
void link(actor_ptr& lhs, actor_ptr& rhs);
/** /**
* @brief Sends <tt>{what...}</tt> as a message to @p whom. * @copydoc link(actor_ptr&,actor_ptr&)
* @param whom Receiver of the message.
* @param what Message elements.
*/ */
template<typename... Args> void link(actor_ptr&& lhs, actor_ptr& rhs);
void send(const channel_ptr& whom, Args&&... what);
/** /**
* @brief Send a message to @p whom. * @copydoc link(actor_ptr&,actor_ptr&)
*
* <b>Usage example:</b>
* @code
* self << make_any_tuple(1, 2, 3);
* @endcode
* @param whom Receiver of the message.
* @param what Message as instance of {@link any_tuple}.
* @returns @p whom.
*/ */
const channel_ptr& operator<<(const channel_ptr& whom, any_tuple what); void link(actor_ptr&& lhs, actor_ptr&& rhs);
/** @} */
/** /**
* @ingroup ActorCreation * @copydoc link(actor_ptr&,actor_ptr&)
* @{
*/ */
void link(actor_ptr& lhs, actor_ptr&& rhs);
/** /**
* @brief Spawns a new context-switching or thread-mapped {@link actor} * @ingroup ActorManagement
* that executes <tt>fun(args...)</tt>. * @brief Unlinks @p lhs from @p rhs;
* @param fun A function implementing the actor's behavior. * @pre <tt>lhs != rhs</tt>
* @param args Optional function parameters for @p fun.
* @tparam Hint A hint to the scheduler for the best scheduling strategy.
* @returns An {@link actor_ptr} to the spawned {@link actor}.
*/ */
template<scheduling_hint Hint, typename Fun, typename... Args> void unlink(actor_ptr& lhs, actor_ptr& rhs);
actor_ptr spawn(Fun fun, Args&&... args);
/** /**
* @brief Spawns a new context-switching {@link actor} * @ingroup ActorManagement
* that executes <tt>fun(args...)</tt>. * @brief Adds a unidirectional @p monitor to @p whom.
* @param fun A function implementing the actor's behavior. * @note Each calls to @p monitor creates a new, independent monitor.
* @param args Optional function parameters for @p fun. * @pre The calling actor receives a ":Down" message from @p whom when
* @returns An {@link actor_ptr} to the spawned {@link actor}. * it terminates.
* @note This function is equal to <tt>spawn<scheduled>(fun, args...)</tt>.
*/ */
template<typename Fun, typename... Args> void monitor(actor_ptr& whom);
actor_ptr spawn(Fun fun, Args&&... args);
void monitor(actor_ptr&& whom);
/** /**
* @brief Spawns a new context-switching or thread-mapped {@link actor} * @ingroup ActorManagement
* that executes <tt>fun(args...)</tt> and * @brief Removes a monitor from @p whom.
* joins @p grp immediately.
* @param fun A function implementing the actor's behavior.
* @param args Optional function parameters for @p fun.
* @tparam Hint A hint to the scheduler for the best scheduling strategy.
* @returns An {@link actor_ptr} to the spawned {@link actor}.
* @note The spawned actor joins @p grp after its
* {@link local_actor::init() init} member function is called but
* before it is executed. Hence, the spawned actor already joined
* the group before this function returns.
*/ */
template<scheduling_hint Hint, typename Fun, typename... Args> void demonitor(actor_ptr& whom);
actor_ptr spawn_in_group(Fun fun, Args&&... args);
/** /**
* @brief Spawns a new context-switching {@link actor} * @ingroup ActorManagement
* that executes <tt>fun(args...)</tt> and * @brief Spans a new context-switching actor.
* joins @p grp immediately. * @returns A pointer to the spawned {@link actor Actor}.
* @param fun A function implementing the actor's behavior.
* @param args Optional function parameters for @p fun.
* @returns An {@link actor_ptr} to the spawned {@link actor}.
* @note The spawned actor joins @p grp after its
* {@link local_actor::init() init} member function is called but
* before it is executed. Hence, the spawned actor already joined
* the group before this function returns.
* @note This function is equal to
* <tt>spawn_in_group<scheduled>(fun, args...)</tt>.
*/ */
template<typename Fun, typename... Args> inline actor_ptr spawn(scheduled_actor* what)
actor_ptr spawn_in_group(Fun fun, Args&&... args); {
return get_scheduler()->spawn(what, scheduled);
}
/** /**
* @brief Spawns an actor of type @p ActorImpl. * @ingroup ActorManagement
* @param args Optional constructor arguments. * @brief Spans a new context-switching actor.
* @tparam ActorImpl Subtype of {@link event_based_actor} or {@link sb_actor}. * @tparam Hint Hint to the scheduler for the best scheduling strategy.
* @returns An {@link actor_ptr} to the spawned {@link actor}. * @returns A pointer to the spawned {@link actor Actor}.
*/ */
template<class ActorImpl, typename... Args> template<scheduling_hint Hint>
actor_ptr spawn(const group_ptr& grp, Args&&... args); inline actor_ptr spawn(scheduled_actor* what)
{
return get_scheduler()->spawn(what, Hint);
}
/** /**
* @brief Spawns an actor of type @p ActorImpl that joins @p grp immediately. * @ingroup ActorManagement
* @param grp The group that the newly created actor shall join. * @brief Spans a new event-based actor.
* @param args Optional constructor arguments. * @returns A pointer to the spawned {@link actor Actor}.
* @tparam ActorImpl Subtype of {@link event_based_actor} or {@link sb_actor}.
* @returns An {@link actor_ptr} to the spawned {@link actor}.
* @note The spawned actor joins @p grp after its
* {@link local_actor::init() init} member function is called but
* before it is executed. Hence, the spawned actor already joined
* the group before this function returns.
*/ */
template<class ActorImpl, typename... Args> inline actor_ptr spawn(abstract_event_based_actor* what)
actor_ptr spawn_in_group(const group_ptr& grp, Args&&... args); {
return get_scheduler()->spawn(what);
/** @} */
#else
inline actor_ptr spawn(void_function fun) {
return get_scheduler()->spawn(std::move(fun), scheduled);
} }
template<scheduling_hint Hint> /**
inline actor_ptr spawn(void_function fun) { * @ingroup ActorManagement
return get_scheduler()->spawn(std::move(fun), Hint); * @brief Spawns a new actor that executes @p what with given arguments.
* @tparam Hint Hint to the scheduler for the best scheduling strategy.
* @param what Function or functor that the spawned Actor should execute.
* @param args Arguments needed to invoke @p what.
* @returns A pointer to the spawned {@link actor actor}.
*/
template<scheduling_hint Hint, typename F, typename... Args>
auto //actor_ptr
spawn(F&& what, const Args&... args)
-> typename std::enable_if<
!std::is_convertible<typename util::rm_ref<F>::type, scheduled_actor*>::value
&& !std::is_convertible<typename util::rm_ref<F>::type, event_based_actor*>::value,
actor_ptr
>::type
{
typedef typename util::rm_ref<F>::type ftype;
std::integral_constant<bool, std::is_function<ftype>::value> is_fun;
auto ptr = detail::get_behavior(is_fun, std::forward<F>(what), args...);
return get_scheduler()->spawn(ptr, Hint);
} }
// forwards self_type as actor_ptr /**
template<typename T> * @ingroup ActorManagement
struct spawn_fwd_ { * @brief Alias for <tt>spawn<scheduled>(what, args...)</tt>.
static inline T&& _(T&& arg) { return std::move(arg); } */
static inline T& _(T& arg) { return arg; } template<typename F, typename... Args>
static inline const T& _(const T& arg) { return arg; } auto // actor_ptr
}; spawn(F&& what, const Args&... args)
-> typename std::enable_if<
template<> !std::is_convertible<typename util::rm_ref<F>::type, scheduled_actor*>::value
struct spawn_fwd_<self_type> { && !std::is_convertible<typename util::rm_ref<F>::type, event_based_actor*>::value,
static inline actor_ptr _(const self_type& s) { return s.get(); } actor_ptr
}; >::type
{
template<scheduling_hint Hint, typename Fun, typename Arg0, typename... Args> return spawn<scheduled>(std::forward<F>(what), args...);
inline actor_ptr spawn(Fun fun, Arg0&& arg0, Args&&... args) {
return get_scheduler()->spawn(
std::bind(
std::move(fun),
spawn_fwd_<typename util::rm_ref<Arg0>::type>::_(arg0),
spawn_fwd_<typename util::rm_ref<Args>::type>::_(args)...),
Hint);
} }
template<typename Fun, typename Arg0, typename... Args> #ifdef CPPA_DOCUMENTATION
inline actor_ptr spawn(Fun&& fun, Arg0&& arg0, Args&&... args) {
return spawn<scheduled>(std::forward<Fun>(fun),
std::forward<Arg0>(arg0),
std::forward<Args>(args)...);
}
template<class ActorImpl, typename... Args> /**
inline actor_ptr spawn(Args&&... args) { * @ingroup MessageHandling
return get_scheduler()->spawn(new ActorImpl(std::forward<Args>(args)...)); * @brief Sends <tt>{arg0, args...}</tt> as a message to @p whom.
} */
template<typename Arg0, typename... Args>
void send(channel_ptr& whom, const Arg0& arg0, const Args&... args);
template<scheduling_hint Hint> /**
inline actor_ptr spawn_in_group(const group_ptr& grp, void_function fun) { * @ingroup MessageHandling
return get_scheduler()->spawn(std::move(fun), Hint, [grp](local_actor* ptr){ * @brief Send a message to @p whom.
ptr->join(grp); *
}); * <b>Usage example:</b>
} * @code
* self << make_cow_tuple(1, 2, 3);
* @endcode
* @returns @p whom.
*/
channel_ptr& operator<<(channel_ptr& whom, const any_tuple& what);
inline actor_ptr spawn_in_group(const group_ptr& grp, void_function fun) { #else
return spawn_in_group<scheduled>(grp, std::move(fun));
}
template<scheduling_hint Hint, typename Fun, typename Arg0, typename... Args> template<class C, typename Arg0, typename... Args>
inline actor_ptr spawn_in_group(const group_ptr& grp, void send(intrusive_ptr<C>& whom, const Arg0& arg0, const Args&... args)
Fun fun, Arg0&& arg0, Args&&... args) { {
return spawn_in_group<Hint>( static_assert(std::is_base_of<channel, C>::value, "C is not a channel");
grp, if (whom) whom->enqueue(self, make_cow_tuple(arg0, args...));
std::bind(
std::move(fun),
spawn_fwd_<typename util::rm_ref<Arg0>::type>::_(arg0),
spawn_fwd_<typename util::rm_ref<Args>::type>::_(args)...));
} }
template<typename Fun, typename Arg0, typename... Args> template<class C, typename Arg0, typename... Args>
inline actor_ptr spawn_in_group(const group_ptr& grp, void send(intrusive_ptr<C>&& whom, const Arg0& arg0, const Args&... args)
Fun&& fun, Arg0&& arg0, Args&&... args) { {
return spawn_in_group<scheduled>(grp, static_assert(std::is_base_of<channel, C>::value, "C is not a channel");
std::forward<Fun>(fun), intrusive_ptr<C> tmp(std::move(whom));
std::forward<Arg0>(arg0), if (tmp) tmp->enqueue(self, make_cow_tuple(arg0, args...));
std::forward<Args>(args)...);
} }
template<class ActorImpl, typename... Args> // matches "send(this, ...)" in event-based actors
inline actor_ptr spawn_in_group(const group_ptr& grp, Args&&... args) { template<typename Arg0, typename... Args>
return get_scheduler()->spawn(new ActorImpl(std::forward<Args>(args)...), void send(local_actor* whom, const Arg0& arg0, const Args&... args)
[&grp](local_actor* ptr) { ptr->join(grp); }); {
whom->enqueue(whom, make_cow_tuple(arg0, args...));
} }
namespace detail {
inline void send_impl(channel* whom, any_tuple&& what) {
if (whom) self->send_message(whom, std::move(what));
}
// matches send(self, ...);
template<typename Arg0, typename... Args> template<typename Arg0, typename... Args>
inline void send_tpl_impl(channel* whom, Arg0&& arg0, Args&&... args) { inline void send(const self_type&, const Arg0& arg0, const Args&... args)
if (whom) { {
self->send_message(whom, make_any_tuple(std::forward<Arg0>(arg0), send(static_cast<local_actor*>(self), arg0, args...);
std::forward<Args>(args)...));
}
} }
} // namespace detail
template<class C> template<class C>
inline typename std::enable_if<std::is_base_of<channel, C>::value, typename std::enable_if<
const intrusive_ptr<C>& >::type std::is_base_of<channel, C>::value,
operator<<(const intrusive_ptr<C>& whom, any_tuple what) { intrusive_ptr<C>&
detail::send_impl(whom.get(), std::move(what)); >::type
operator<<(intrusive_ptr<C>& whom, const any_tuple& what)
{
if (whom) whom->enqueue(self, what);
return whom; return whom;
} }
inline const self_type& operator<<(const self_type& s, any_tuple what) { template<class C>
detail::send_impl(s.get(), std::move(what)); typename std::enable_if<
return s; std::is_base_of<channel, C>::value,
intrusive_ptr<C>
>::type
operator<<(intrusive_ptr<C>&& whom, const any_tuple& what)
{
intrusive_ptr<C> tmp(std::move(whom));
if (tmp) tmp->enqueue(self, what);
return std::move(tmp);
} }
template<class C, typename Arg0, typename... Args> template<class C>
inline typename std::enable_if<std::is_base_of<channel, C>::value>::type typename std::enable_if<
send(const intrusive_ptr<C>& whom, Arg0&& arg0, Args&&... args) { std::is_base_of<channel, C>::value,
detail::send_tpl_impl(whom.get(), intrusive_ptr<C>&
std::forward<Arg0>(arg0), >::type
std::forward<Args>(args)...); operator<<(intrusive_ptr<C>& whom, any_tuple&& what)
{
if (whom) whom->enqueue(self, std::move(what));
return whom;
} }
// matches "send(this, ...)" and "send(self, ...)" template<class C>
template<typename Arg0, typename... Args> typename std::enable_if<
inline void send(local_actor* whom, Arg0&& arg0, Args&&... args) { std::is_base_of<channel, C>::value,
detail::send_tpl_impl(whom, intrusive_ptr<C>
std::forward<Arg0>(arg0), >::type
std::forward<Args>(args)...); operator<<(intrusive_ptr<C>&& whom, any_tuple&& what)
{
intrusive_ptr<C> tmp(std::move(whom));
if (tmp) tmp->enqueue(self, std::move(what));
return std::move(tmp);
} }
const self_type& operator<<(const self_type& s, const any_tuple& what);
const self_type& operator<<(const self_type& s, any_tuple&& what);
#endif // CPPA_DOCUMENTATION #endif // CPPA_DOCUMENTATION
/** /**
* @ingroup MessageHandling * @ingroup MessageHandling
* @brief Sends a message to the sender of the last received message. * @brief Sends a message to the sender of the last received message.
* @param what Message elements.
*/ */
template<typename... Args> template<typename Arg0, typename... Args>
inline void reply(Args&&... what) { void reply(const Arg0& arg0, const Args&... args)
send(self->last_sender(), std::forward<Args>(what)...); {
send(self->last_sender(), arg0, args...);
} }
/** /**
* @ingroup MessageHandling * @ingroup MessageHandling
* @brief Sends a message to @p whom that is delayed by @p rel_time. * @brief Sends a message to @p whom that is delayed by @p rel_time.
* @param whom Receiver of the message. * @param whom Receiver of the message.
* @param rel_time Relative time duration to delay the message in * @param rel_time Relative time duration to delay the message.
* microseconds, milliseconds, seconds or minutes. * @param data Any number of values for the message content.
* @param what Message elements.
*/ */
template<class Rep, class Period, typename... Args> template<typename Duration, typename... Data>
inline void delayed_send(const actor_ptr& whom, void future_send(actor_ptr whom, const Duration& rel_time, const Data&... data)
const std::chrono::duration<Rep, Period>& rel_time, {
Args&&... what) { get_scheduler()->future_send(whom, rel_time, data...);
if (whom) {
get_scheduler()->delayed_send(whom, rel_time,
std::forward<Args>(what)...);
}
} }
/** /**
* @ingroup MessageHandling * @ingroup MessageHandling
* @brief Sends a reply message that is delayed by @p rel_time. * @brief Sends a reply message that is delayed by @p rel_time.
* @param rel_time Relative time duration to delay the message in * @see future_send()
* microseconds, milliseconds, seconds or minutes.
* @param what Message elements.
* @see delayed_send()
*/ */
template<class Rep, class Period, typename... Args> template<typename Duration, typename... Data>
inline void delayed_reply(const std::chrono::duration<Rep, Period>& rel_time, void delayed_reply(const Duration& rel_time, Data const... data)
Args&&... what) { {
delayed_send(self->last_sender(), rel_time, std::forward<Args>(what)...); future_send(self->last_sender(), rel_time, data...);
} }
/** /**
* @brief Blocks execution of this actor until all * @brief Blocks execution of this actor until all
* other actors finished execution. * other actors finished execution.
* @warning This function will cause a deadlock if called from multiple actors. * @warning This function will cause a deadlock if
* @warning Do not call this function in cooperatively scheduled actors. * called from multiple actors.
*/ */
inline void await_all_others_done() { inline void await_all_others_done()
{
detail::actor_count_wait_until((self.unchecked() == nullptr) ? 0 : 1); detail::actor_count_wait_until((self.unchecked() == nullptr) ? 0 : 1);
} }
/** /**
* @brief Publishes @p whom at @p port. * @brief Publishes @p whom at given @p port.
* *
* The connection is automatically closed if the lifetime of @p whom ends. * The connection is automatically closed if the lifetime of @p whom ends.
* @param whom Actor that should be published at @p port. * @param whom Actor that should be published at given @p port.
* @param port Unused TCP port. * @param port Unused TCP port.
* @throws bind_failure * @throws bind_failure
*/ */
void publish(actor_ptr whom, std::uint16_t port); void publish(actor_ptr& whom, std::uint16_t port);
/**
* @copydoc publish(actor_ptr&,std::uint16_t)
*/
void publish(actor_ptr&& whom, std::uint16_t port);
/** /**
* @brief Establish a new connection to the actor at @p host on given @p port. * @brief Establish a new connection to the actor at @p host on given @p port.
* @param host Valid hostname or IP address. * @param host Valid hostname or IP address.
* @param port TCP port. * @param port TCP port.
* @returns An {@link actor_ptr} to the proxy instance * @returns A pointer to the proxy instance that represents the remote Actor.
* representing a remote actor.
*/ */
actor_ptr remote_actor(const char* host, std::uint16_t port); actor_ptr remote_actor(char const* host, std::uint16_t port);
} // namespace cppa } // namespace cppa
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment