Commit 777fc9bf authored by neverlord's avatar neverlord

documentation

parent 4c39c810
...@@ -32,24 +32,27 @@ ...@@ -32,24 +32,27 @@
#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/fsm_actor.hpp" #include "cppa/cow_tuple.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/exit_reason.hpp" #include "cppa/exit_reason.hpp"
#include "cppa/local_actor.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"
...@@ -69,41 +72,45 @@ ...@@ -69,41 +72,45 @@
* *
* 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 using C++. * of both concurrent and distributed software.
* *
* @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. * Writing applications in @p libcppa requires a minimum of gluecode and
* 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, as the following example shows: * converted to an actor if needed.
*
* 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.6</tt>, @p Automake * To build @p libcppa, you need <tt>GCC >= 4.7</tt> or <tt>Clang >= 3.2</tt>,
* and the <tt>Boost.Thread</tt> library. * @p CMake 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>autoreconf -i</tt> *- <tt>mkdir build</tt>
* - <tt>./configure</tt> *- <tt>cd build</tt>
* - <tt>make</tt> *- <tt>cmake ..</tt>
* - <tt>make install</tt> (as root, optionally) *- <tt>make</tt>
*- <tt>make install</tt> (as root, optionally)
*
* Please run the unit tests as well to verify that @p libcppa works properly.
* *
* Use <tt>./configure --help</tt> if the script doesn't auto-select *- <tt>./bin/unit_tests</tt>
* the correct @p GCC binary or doesn't find your <tt>Boost.Thread</tt> *
* installation. * Please submit a bug report that includes (a) your compiler version,
* (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
...@@ -117,24 +124,32 @@ ...@@ -117,24 +124,32 @@
* features. * features.
* *
* @namespace cppa * @namespace cppa
* @brief This is the root namespace of libcppa. * @brief 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 This namespace contains utility classes and metaprogramming * @brief Contains utility classes and metaprogramming
* utilities used by the libcppa implementation. * utilities used by the libcppa implementation.
* *
* @namespace cppa::intrusive * @namespace cppa::intrusive
* @brief This namespace contains intrusive container implementations. * @brief 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::tuple Tuples} should @b always be used with by-value semantic, * {@link cppa::cow_tuple Tuples} should @b always be used with by-value
* since tuples use a copy-on-write smart pointer internally. Let's assume two * semantic,since tuples use a copy-on-write smart pointer internally.
* 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
...@@ -239,16 +254,13 @@ ...@@ -239,16 +254,13 @@
* 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>(), val<int>()>() >> [](int i0, int i1, int i2) * on(atom("compute"), val<int>(), val<int>()>() >> [](int i0, int i1) {
* {
* // 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 + i2); * reply(atom("result"), i0 + i1);
* } * }
* ); * );
* @endcode * @endcode
...@@ -263,16 +275,12 @@ ...@@ -263,16 +275,12 @@
* *
* Example actor: * Example actor:
* @code * @code
* void math_actor() * void math_actor() {
* { * receive_loop (
* receive_loop * on<atom("plus"), int, int>() >> [](int a, int b) {
* (
* 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);
* } * }
* ); * );
...@@ -300,10 +308,8 @@ ...@@ -300,10 +308,8 @@
* @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);
* } * }
* ); * );
...@@ -315,8 +321,7 @@ ...@@ -315,8 +321,7 @@
* @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
...@@ -328,10 +333,8 @@ ...@@ -328,10 +333,8 @@
* @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);
* } * }
* ) * )
...@@ -341,20 +344,18 @@ ...@@ -341,20 +344,18 @@
* *
* @section FutureSend Send delayed messages * @section FutureSend Send delayed messages
* *
* The function @p future_send provides a simple way to delay a message. * The function @p delayed_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
* future_send(self, std::chrono::seconds(1), atom("poll")); * delayed_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
* future_send(self, std::chrono::seconds(1), atom("poll")); * delayed_send(self, std::chrono::seconds(1), atom("poll"));
* } * }
* ); * );
* @endcode * @endcode
...@@ -365,7 +366,7 @@ ...@@ -365,7 +366,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>char const*</tt>, * Unfortunately, string literals in @p C++ have the type <tt>const char*</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.
...@@ -375,7 +376,7 @@ ...@@ -375,7 +376,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!");
* *
* char const* cstring = "cstring"; * const char* cstring = "cstring";
* // sends an std::string containing "cstring" to itself * // sends an std::string containing "cstring" to itself
* send(self, cstring); * send(self, cstring);
* *
...@@ -385,14 +386,13 @@ ...@@ -385,14 +386,13 @@
* // 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 ActorManagement Actor management. * @defgroup ActorCreation Actor creation.
* *
*/ */
...@@ -410,7 +410,7 @@ ...@@ -410,7 +410,7 @@
*/ */
/** /**
* @brief A simple example for a future_send based application. * @brief A simple example for a delayed_send based application.
* @example dancing_kirby.cpp * @example dancing_kirby.cpp
*/ */
...@@ -421,295 +421,323 @@ ...@@ -421,295 +421,323 @@
namespace cppa { namespace cppa {
/** #ifdef CPPA_DOCUMENTATION
* @ingroup ActorManagement
* @brief Links @p lhs and @p rhs;
* @pre <tt>lhs != rhs</tt>
*/
void link(actor_ptr& lhs, actor_ptr& rhs);
/** /**
* @copydoc link(actor_ptr&,actor_ptr&) * @ingroup MessageHandling
* @{
*/ */
void link(actor_ptr&& lhs, actor_ptr& rhs);
/** /**
* @copydoc link(actor_ptr&,actor_ptr&) * @brief Sends <tt>{what...}</tt> as a message to @p whom.
* @param whom Receiver of the message.
* @param what Message elements.
*/ */
void link(actor_ptr&& lhs, actor_ptr&& rhs); template<typename... Args>
void send(const channel_ptr& whom, Args&&... what);
/** /**
* @copydoc link(actor_ptr&,actor_ptr&) * @brief Send a message to @p whom.
*
* <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.
*/ */
void link(actor_ptr& lhs, actor_ptr&& rhs); const channel_ptr& operator<<(const channel_ptr& whom, any_tuple what);
/** /** @} */
* @ingroup ActorManagement
* @brief Unlinks @p lhs from @p rhs;
* @pre <tt>lhs != rhs</tt>
*/
void unlink(actor_ptr& lhs, actor_ptr& rhs);
/** /**
* @ingroup ActorManagement * @ingroup ActorCreation
* @brief Adds a unidirectional @p monitor to @p whom. * @{
* @note Each calls to @p monitor creates a new, independent monitor.
* @pre The calling actor receives a ":Down" message from @p whom when
* it terminates.
*/ */
void monitor(actor_ptr& whom);
void monitor(actor_ptr&& whom);
/** /**
* @ingroup ActorManagement * @brief Spawns a new context-switching or thread-mapped {@link actor}
* @brief Removes a monitor from @p whom. * that executes <tt>fun(args...)</tt>.
* @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}.
*/ */
void demonitor(actor_ptr& whom); template<scheduling_hint Hint, typename Fun, typename... Args>
actor_ptr spawn(Fun fun, Args&&... args);
/** /**
* @ingroup ActorManagement * @brief Spawns a new context-switching {@link actor}
* @brief Spans a new context-switching actor. * that executes <tt>fun(args...)</tt>.
* @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 This function is equal to <tt>spawn<scheduled>(fun, args...)</tt>.
*/ */
inline actor_ptr spawn(scheduled_actor* what) template<typename Fun, typename... Args>
{ actor_ptr spawn(Fun fun, Args&&... args);
return get_scheduler()->spawn(what, scheduled);
}
/** /**
* @ingroup ActorManagement * @brief Spawns a new context-switching or thread-mapped {@link actor}
* @brief Spans a new context-switching actor. * that executes <tt>fun(args...)</tt> and
* @tparam Hint Hint to the scheduler for the best scheduling strategy. * 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.
* @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> template<scheduling_hint Hint, 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, Hint);
}
/** /**
* @ingroup ActorManagement * @brief Spawns a new context-switching {@link actor}
* @brief Spans a new event-based actor. * that executes <tt>fun(args...)</tt> and
* @returns A pointer to the spawned {@link actor Actor}. * joins @p grp immediately.
* @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>.
*/ */
inline actor_ptr spawn(abstract_event_based_actor* what) template<typename Fun, typename... Args>
{ actor_ptr spawn_in_group(Fun fun, Args&&... args);
return get_scheduler()->spawn(what);
}
/** /**
* @ingroup ActorManagement * @brief Spawns an actor of type @p ActorImpl.
* @brief Spawns a new actor that executes @p what with given arguments. * @param args Optional constructor arguments.
* @tparam Hint Hint to the scheduler for the best scheduling strategy. * @tparam ActorImpl Subtype of {@link event_based_actor} or {@link sb_actor}.
* @param what Function or functor that the spawned Actor should execute. * @returns An {@link actor_ptr} to the spawned {@link actor}.
* @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> template<class ActorImpl, typename... Args>
auto //actor_ptr actor_ptr spawn(const group_ptr& grp, Args&&... args);
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);
}
/** /**
* @ingroup ActorManagement * @brief Spawns an actor of type @p ActorImpl that joins @p grp immediately.
* @brief Alias for <tt>spawn<scheduled>(what, args...)</tt>. * @param grp The group that the newly created actor shall join.
* @param args Optional constructor arguments.
* @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<typename F, typename... Args> template<class ActorImpl, typename... Args>
auto // actor_ptr actor_ptr spawn_in_group(const group_ptr& grp, Args&&... args);
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, #else
actor_ptr
>::type
{ inline actor_ptr spawn(void_function fun) {
return spawn<scheduled>(std::forward<F>(what), args...); return get_scheduler()->spawn(std::move(fun), scheduled);
} }
#ifdef CPPA_DOCUMENTATION template<scheduling_hint Hint>
inline actor_ptr spawn(void_function fun) {
return get_scheduler()->spawn(std::move(fun), Hint);
}
/** // forwards self_type as actor_ptr
* @ingroup MessageHandling template<typename T>
* @brief Sends <tt>{arg0, args...}</tt> as a message to @p whom. struct spawn_fwd_ {
*/ static inline T&& _(T&& arg) { return std::move(arg); }
template<typename Arg0, typename... Args> static inline T& _(T& arg) { return arg; }
void send(channel_ptr& whom, const Arg0& arg0, const Args&... args); static inline const T& _(const T& arg) { return arg; }
};
template<>
struct spawn_fwd_<self_type> {
static inline actor_ptr _(const self_type& s) { return s.get(); }
};
template<scheduling_hint Hint, typename Fun, typename Arg0, typename... 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>
* @ingroup MessageHandling inline actor_ptr spawn(Fun&& fun, Arg0&& arg0, Args&&... args) {
* @brief Send a message to @p whom. return spawn<scheduled>(std::forward<Fun>(fun),
* std::forward<Arg0>(arg0),
* <b>Usage example:</b> std::forward<Args>(args)...);
* @code }
* self << make_cow_tuple(1, 2, 3);
* @endcode
* @returns @p whom.
*/
channel_ptr& operator<<(channel_ptr& whom, const any_tuple& what);
#else template<class ActorImpl, typename... Args>
inline actor_ptr spawn(Args&&... args) {
return get_scheduler()->spawn(new ActorImpl(std::forward<Args>(args)...));
}
template<class C, typename Arg0, typename... Args> template<scheduling_hint Hint>
void send(intrusive_ptr<C>& whom, const Arg0& arg0, const Args&... args) inline actor_ptr spawn_in_group(const group_ptr& grp, void_function fun) {
{ return get_scheduler()->spawn(std::move(fun), Hint, [grp](local_actor* ptr){
static_assert(std::is_base_of<channel, C>::value, "C is not a channel"); ptr->join(grp);
if (whom) whom->enqueue(self, make_cow_tuple(arg0, args...)); });
} }
template<class C, typename Arg0, typename... Args> inline actor_ptr spawn_in_group(const group_ptr& grp, void_function fun) {
void send(intrusive_ptr<C>&& whom, const Arg0& arg0, const Args&... args) return spawn_in_group<scheduled>(grp, std::move(fun));
{
static_assert(std::is_base_of<channel, C>::value, "C is not a channel");
intrusive_ptr<C> tmp(std::move(whom));
if (tmp) tmp->enqueue(self, make_cow_tuple(arg0, args...));
} }
// matches "send(this, ...)" in event-based actors template<scheduling_hint Hint, typename Fun, typename Arg0, typename... Args>
template<typename Arg0, typename... Args> inline actor_ptr spawn_in_group(const group_ptr& grp,
void send(local_actor* whom, const Arg0& arg0, const Args&... args) Fun fun, Arg0&& arg0, Args&&... args) {
{ return spawn_in_group<Hint>(
whom->enqueue(whom, make_cow_tuple(arg0, args...)); grp,
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>
inline actor_ptr spawn_in_group(const group_ptr& grp,
Fun&& fun, Arg0&& arg0, Args&&... args) {
return spawn_in_group<scheduled>(grp,
std::forward<Fun>(fun),
std::forward<Arg0>(arg0),
std::forward<Args>(args)...);
}
// matches send(self, ...); template<class ActorImpl, typename... Args>
template<typename Arg0, typename... Args> inline actor_ptr spawn_in_group(const group_ptr& grp, Args&&... args) {
inline void send(const self_type&, const Arg0& arg0, const Args&... args) return get_scheduler()->spawn(new ActorImpl(std::forward<Args>(args)...),
{ [&grp](local_actor* ptr) { ptr->join(grp); });
send(static_cast<local_actor*>(self), arg0, args...);
} }
template<class C> namespace detail {
typename std::enable_if<
std::is_base_of<channel, C>::value, inline void send_impl(channel* whom, any_tuple&& what) {
intrusive_ptr<C>& if (whom) self->send_message(whom, std::move(what));
>::type
operator<<(intrusive_ptr<C>& whom, const any_tuple& what)
{
if (whom) whom->enqueue(self, what);
return whom;
} }
template<class C> template<typename Arg0, typename... Args>
typename std::enable_if< inline void send_tpl_impl(channel* whom, Arg0&& arg0, Args&&... args) {
std::is_base_of<channel, C>::value, if (whom) {
intrusive_ptr<C> self->send_message(whom, make_any_tuple(std::forward<Arg0>(arg0),
>::type std::forward<Args>(args)...));
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);
} }
} // namespace detail
template<class C> template<class C>
typename std::enable_if< inline typename std::enable_if<std::is_base_of<channel, C>::value,
std::is_base_of<channel, C>::value, const intrusive_ptr<C>& >::type
intrusive_ptr<C>& operator<<(const intrusive_ptr<C>& whom, any_tuple what) {
>::type detail::send_impl(whom.get(), std::move(what));
operator<<(intrusive_ptr<C>& whom, any_tuple&& what)
{
if (whom) whom->enqueue(self, std::move(what));
return whom; return whom;
} }
template<class C> inline const self_type& operator<<(const self_type& s, any_tuple what) {
typename std::enable_if< detail::send_impl(s.get(), std::move(what));
std::is_base_of<channel, C>::value, return s;
intrusive_ptr<C>
>::type
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); template<class C, typename Arg0, typename... Args>
inline typename std::enable_if<std::is_base_of<channel, C>::value>::type
send(const intrusive_ptr<C>& whom, Arg0&& arg0, Args&&... args) {
detail::send_tpl_impl(whom.get(),
std::forward<Arg0>(arg0),
std::forward<Args>(args)...);
}
const self_type& operator<<(const self_type& s, any_tuple&& what); // matches "send(this, ...)" and "send(self, ...)"
template<typename Arg0, typename... Args>
inline void send(local_actor* whom, Arg0&& arg0, Args&&... args) {
detail::send_tpl_impl(whom,
std::forward<Arg0>(arg0),
std::forward<Args>(args)...);
}
#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 Arg0, typename... Args> template<typename... Args>
void reply(const Arg0& arg0, const Args&... args) inline void reply(Args&&... what) {
{ 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. * @param rel_time Relative time duration to delay the message in
* @param data Any number of values for the message content. * microseconds, milliseconds, seconds or minutes.
* @param what Message elements.
*/ */
template<typename Duration, typename... Data> template<class Rep, class Period, typename... Args>
void future_send(actor_ptr whom, const Duration& rel_time, const Data&... data) inline void delayed_send(const actor_ptr& whom,
{ const std::chrono::duration<Rep, Period>& rel_time,
get_scheduler()->future_send(whom, rel_time, data...); Args&&... what) {
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.
* @see future_send() * @param rel_time Relative time duration to delay the message in
* microseconds, milliseconds, seconds or minutes.
* @param what Message elements.
* @see delayed_send()
*/ */
template<typename Duration, typename... Data> template<class Rep, class Period, typename... Args>
void delayed_reply(const Duration& rel_time, Data const... data) inline void delayed_reply(const std::chrono::duration<Rep, Period>& rel_time,
{ Args&&... what) {
future_send(self->last_sender(), rel_time, data...); delayed_send(self->last_sender(), rel_time, std::forward<Args>(what)...);
} }
/** /**
* @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 * @warning This function will cause a deadlock if called from multiple actors.
* called from multiple actors. * @warning Do not call this function in cooperatively scheduled 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 given @p port. * @brief Publishes @p whom at @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 given @p port. * @param whom Actor that should be published at @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 A pointer to the proxy instance that represents the remote Actor. * @returns An {@link actor_ptr} to the proxy instance
* representing a remote actor.
*/ */
actor_ptr remote_actor(char const* host, std::uint16_t port); actor_ptr remote_actor(const char* 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