Browse files

maintenance & documentation

  • Loading branch information...
1 parent b0fb47b commit 0f8c067ea98d8fd38ec7ab74542ec9388621ec33 @Neverlord Neverlord committed Jun 29, 2012
Showing with 217 additions and 254 deletions.
  1. +132 −223 cppa/cppa.hpp
  2. +75 −21 cppa/scheduler.hpp
  3. +2 −1 cppa/self.hpp
  4. +6 −7 src/local_actor.cpp
  5. +2 −2 src/scheduler.cpp
View
355 cppa/cppa.hpp
@@ -193,8 +193,8 @@
* The first argument is the receiver of the message followed by any number
* of values. @p send creates a tuple from the given values and enqueues the
* tuple to the receivers mailbox. Thus, send should @b not be used to send
- * a message to multiple receivers. You should use the @p enqueue
- * member function of the receivers instead as in the following example:
+ * a message to multiple receivers. You should use @p operator<<
+ * instead as in the following example:
*
* @code
* // spawn some actors
@@ -207,20 +207,20 @@
*
* // send a message to a1, a2 and a3
* auto msg = make_cow_tuple(atom("compute"), 1, 2, 3);
- * auto s = self; // cache self pointer
+ *
* // note: this is more efficient then using send() three times because
* // send() would create a new tuple each time;
* // this safes both time and memory thanks to libcppa's copy-on-write
- * a1->enqueue(s, msg);
- * a2->enqueue(s, msg);
- * a3->enqueue(s, msg);
+ * a1 << msg;
+ * a2 << msg;
+ * a3 << msg;
*
* // modify msg and send it again
* // (msg becomes detached due to copy-on-write optimization)
* get_ref<1>(msg) = 10; // msg is now { atom("compute"), 10, 2, 3 }
- * a1->enqueue(s, msg);
- * a2->enqueue(s, msg);
- * a3->enqueue(s, msg);
+ * a1 << msg;
+ * a2 << msg;
+ * a3 << msg;
* @endcode
*
* @section Receive Receive messages
@@ -231,39 +231,19 @@
* @code
* receive
* (
- * on<atom("hello"), std::string>() >> [](const std::string& msg)
+ * on(atom("hello"), arg_match) >> [](const std::string& msg)
* {
* cout << "received hello message: " << msg << endl;
* },
- * on<atom("compute"), int, int, int>() >> [](int i0, int i1, int i2)
+ * on(atom("compute"), arg_match) >> [](int i0, int i1, int i2)
* {
* // send our result back to the sender of this messages
* reply(atom("result"), i0 + i1 + i2);
* }
* );
* @endcode
*
- * The function @p on creates a pattern.
- * It provides two ways of defining patterns:
- * either by template parameters (prefixed by up to four atoms) or by arguments.
- * The first way matches for types only (exept for the prefixing atoms).
- * The second way compares values.
- * Use the template function @p val to match for the type only.
- *
- * This example is equivalent to the previous one but uses the second way
- * to define patterns:
- *
- * @code
- * receive (
- * on(atom("hello"), val<std::string>()) >> [](const std::string& msg) {
- * cout << "received hello message: " << msg << endl;
- * },
- * on(atom("compute"), val<int>(), val<int>()>() >> [](int i0, int i1) {
- * // send our result back to the sender of this messages
- * reply(atom("result"), i0 + i1);
- * }
- * );
- * @endcode
+ * Please read the manual for further details about pattern matching.
*
* @section Atoms Atoms
*
@@ -277,10 +257,10 @@
* @code
* void math_actor() {
* receive_loop (
- * on<atom("plus"), int, int>() >> [](int a, int b) {
+ * on(atom("plus"), arg_match) >> [](int a, int b) {
* reply(atom("result"), a + b);
* },
- * on<atom("minus"), int, int>() >> [](int a, int b) {
+ * on(atom("minus"), arg_match) >> [](int a, int b) {
* reply(atom("result"), a - b);
* }
* );
@@ -352,7 +332,7 @@
* delayed_send(self, std::chrono::seconds(1), atom("poll"));
* receive_loop (
* // ...
- * on<atom("poll")>() >> []() {
+ * on(atom("poll")) >> []() {
* // ... poll something ...
* // and do it again after 1sec
* delayed_send(self, std::chrono::seconds(1), atom("poll"));
@@ -421,23 +401,28 @@
namespace cppa {
-#ifdef CPPA_DOCUMENTATION
+namespace detail {
+
+template<typename T>
+inline void send_impl(T* whom, any_tuple&& what) {
+ if (whom) self->send_message(whom, std::move(what));
+}
+
+template<typename T, typename... Args>
+inline void send_tpl_impl(T* whom, Args&&... what) {
+ if (whom) self->send_message(whom,
+ make_any_tuple(std::forward<Args>(what)...));
+}
+
+} // namespace detail
/**
* @ingroup MessageHandling
* @{
*/
/**
- * @brief Sends <tt>{what...}</tt> as a message to @p whom.
- * @param whom Receiver of the message.
- * @param what Message elements.
- */
-template<typename... Args>
-void send(const channel_ptr& whom, Args&&... what);
-
-/**
- * @brief Send a message to @p whom.
+ * @brief Sends a message to @p whom.
*
* <b>Usage example:</b>
* @code
@@ -447,10 +432,85 @@ void send(const channel_ptr& whom, Args&&... what);
* @param what Message as instance of {@link any_tuple}.
* @returns @p whom.
*/
-const channel_ptr& operator<<(const channel_ptr& whom, any_tuple what);
+template<class C>
+inline typename std::enable_if<std::is_base_of<channel, C>::value,
+ const intrusive_ptr<C>& >::type
+operator<<(const intrusive_ptr<C>& whom, any_tuple what) {
+ detail::send_impl(whom.get(), std::move(what));
+ return whom;
+}
+
+/**
+ * @brief Sends <tt>{what...}</tt> as a message to @p whom.
+ * @param whom Receiver of the message.
+ * @param what Message elements.
+ * @pre <tt>sizeof...(Args) > 0</tt>
+ */
+template<class C, typename... Args>
+inline typename std::enable_if<std::is_base_of<channel, C>::value>::type
+send(const intrusive_ptr<C>& whom, Args&&... what) {
+ static_assert(sizeof...(Args) > 0, "no message to send");
+ detail::send_tpl_impl(whom.get(), std::forward<Args>(what)...);
+}
+
+
+/**
+ * @brief Sends a message to the sender of the last received message.
+ * @param what Message elements.
+ * @note Equal to <tt>send(self->last_received(), what...)</tt>.
+ */
+template<typename... Args>
+inline void reply(Args&&... what) {
+ send(self->last_sender(), std::forward<Args>(what)...);
+}
+
+/**
+ * @brief Sends a message to @p whom that is delayed by @p rel_time.
+ * @param whom Receiver of the message.
+ * @param rel_time Relative time duration to delay the message in
+ * microseconds, milliseconds, seconds or minutes.
+ * @param what Message elements.
+ */
+template<class Rep, class Period, typename... Args>
+inline void delayed_send(const channel_ptr& whom,
+ const std::chrono::duration<Rep, Period>& rel_time,
+ Args&&... what) {
+ if (whom) {
+ get_scheduler()->delayed_send(whom, rel_time,
+ std::forward<Args>(what)...);
+ }
+}
+
+/**
+ * @brief Sends a reply message that is delayed by @p rel_time.
+ * @param rel_time Relative time duration to delay the message in
+ * microseconds, milliseconds, seconds or minutes.
+ * @param what Message elements.
+ * @note Equal to <tt>delayed_send(self->last_sender(), rel_time, what...)</tt>.
+ * @see delayed_send()
+ */
+template<class Rep, class Period, typename... Args>
+inline void delayed_reply(const std::chrono::duration<Rep, Period>& rel_time,
+ Args&&... what) {
+ delayed_send(self->last_sender(), rel_time, std::forward<Args>(what)...);
+}
/** @} */
+#ifndef CPPA_DOCUMENTATION
+// 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)...);
+}
+inline const self_type& operator<<(const self_type& s, any_tuple what) {
+ detail::send_impl(s.get(), std::move(what));
+ return s;
+}
+#endif // CPPA_DOCUMENTATION
+
/**
* @ingroup ActorCreation
* @{
@@ -466,7 +526,11 @@ const channel_ptr& operator<<(const channel_ptr& whom, any_tuple what);
* @returns An {@link actor_ptr} to the spawned {@link actor}.
*/
template<scheduling_hint Hint, typename Fun, typename... Args>
-actor_ptr spawn(Fun fun, Args&&... args);
+actor_ptr spawn(Fun&& fun, Args&&... args) {
+ return get_scheduler()->spawn_impl(Hint,
+ std::forward<Fun>(fun),
+ std::forward<Args>(args)...);
+}
/**
* @brief Spawns a new context-switching {@link actor}
@@ -477,7 +541,10 @@ actor_ptr spawn(Fun fun, Args&&... args);
* @note This function is equal to <tt>spawn<scheduled>(fun, args...)</tt>.
*/
template<typename Fun, typename... Args>
-actor_ptr spawn(Fun fun, Args&&... args);
+actor_ptr spawn(Fun&& fun, Args&&... args) {
+ return spawn<scheduled>(std::forward<Fun>(fun),
+ std::forward<Args>(args)...);
+}
/**
* @brief Spawns a new context-switching or thread-mapped {@link actor}
@@ -493,7 +560,14 @@ actor_ptr spawn(Fun fun, Args&&... args);
* the group before this function returns.
*/
template<scheduling_hint Hint, typename Fun, typename... Args>
-actor_ptr spawn_in_group(Fun fun, Args&&... args);
+actor_ptr spawn_in_group(const group_ptr& grp, Fun&& fun, Args&&... args) {
+ return get_scheduler()->spawn_cb_impl(Hint,
+ [grp](local_actor* ptr) {
+ ptr->join(grp);
+ },
+ std::forward<Fun>(fun),
+ std::forward<Args>(args)...);
+}
/**
* @brief Spawns a new context-switching {@link actor}
@@ -510,7 +584,10 @@ actor_ptr spawn_in_group(Fun fun, Args&&... args);
* <tt>spawn_in_group<scheduled>(fun, args...)</tt>.
*/
template<typename Fun, typename... Args>
-actor_ptr spawn_in_group(Fun fun, Args&&... args);
+actor_ptr spawn_in_group(Fun&& fun, Args&&... args) {
+ return spawn_in_group<scheduled>(std::forward<Fun>(fun),
+ std::forward<Args>(args)...);
+}
/**
* @brief Spawns an actor of type @p ActorImpl.
@@ -519,7 +596,9 @@ actor_ptr spawn_in_group(Fun fun, Args&&... args);
* @returns An {@link actor_ptr} to the spawned {@link actor}.
*/
template<class ActorImpl, typename... Args>
-actor_ptr spawn(const group_ptr& grp, Args&&... args);
+actor_ptr spawn(Args&&... args) {
+ return get_scheduler()->spawn(new ActorImpl(std::forward<Args>(args)...));
+}
/**
* @brief Spawns an actor of type @p ActorImpl that joins @p grp immediately.
@@ -533,182 +612,12 @@ actor_ptr spawn(const group_ptr& grp, Args&&... args);
* the group before this function returns.
*/
template<class ActorImpl, typename... Args>
-actor_ptr spawn_in_group(const group_ptr& grp, Args&&... args);
-
-/** @} */
-
-#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) {
- return get_scheduler()->spawn(std::move(fun), Hint);
-}
-
-// forwards self_type as actor_ptr
-template<typename T>
-struct spawn_fwd_ {
- static inline T&& _(T&& arg) { return std::move(arg); }
- static inline T& _(T& arg) { return arg; }
- 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>
-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) {
- return get_scheduler()->spawn(new ActorImpl(std::forward<Args>(args)...));
-}
-
-template<scheduling_hint Hint>
-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){
- ptr->join(grp);
- });
-}
-
-inline actor_ptr spawn_in_group(const group_ptr& grp, void_function fun) {
- return spawn_in_group<scheduled>(grp, std::move(fun));
-}
-
-template<scheduling_hint Hint, 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<Hint>(
- 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)...);
-}
-
-template<class ActorImpl, typename... Args>
-inline actor_ptr spawn_in_group(const group_ptr& grp, Args&&... args) {
+actor_ptr spawn_in_group(const group_ptr& grp, Args&&... args) {
return get_scheduler()->spawn(new ActorImpl(std::forward<Args>(args)...),
[&grp](local_actor* ptr) { ptr->join(grp); });
}
-namespace detail {
-
-inline void send_impl(channel* whom, any_tuple&& what) {
- if (whom) self->send_message(whom, std::move(what));
-}
-
-template<typename Arg0, typename... Args>
-inline void send_tpl_impl(channel* whom, Arg0&& arg0, Args&&... args) {
- if (whom) {
- self->send_message(whom, make_any_tuple(std::forward<Arg0>(arg0),
- std::forward<Args>(args)...));
- }
-}
-
-} // namespace detail
-
-template<class C>
-inline typename std::enable_if<std::is_base_of<channel, C>::value,
- const intrusive_ptr<C>& >::type
-operator<<(const intrusive_ptr<C>& whom, any_tuple what) {
- detail::send_impl(whom.get(), std::move(what));
- return whom;
-}
-
-inline const self_type& operator<<(const self_type& s, any_tuple what) {
- detail::send_impl(s.get(), std::move(what));
- return s;
-}
-
-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)...);
-}
-
-// 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
-
-/**
- * @ingroup MessageHandling
- * @brief Sends a message to the sender of the last received message.
- * @param what Message elements.
- */
-template<typename... Args>
-inline void reply(Args&&... what) {
- send(self->last_sender(), std::forward<Args>(what)...);
-}
-
-/**
- * @ingroup MessageHandling
- * @brief Sends a message to @p whom that is delayed by @p rel_time.
- * @param whom Receiver of the message.
- * @param rel_time Relative time duration to delay the message in
- * microseconds, milliseconds, seconds or minutes.
- * @param what Message elements.
- */
-template<class Rep, class Period, typename... Args>
-inline void delayed_send(const actor_ptr& whom,
- const std::chrono::duration<Rep, Period>& rel_time,
- Args&&... what) {
- if (whom) {
- get_scheduler()->delayed_send(whom, rel_time,
- std::forward<Args>(what)...);
- }
-}
-
-/**
- * @ingroup MessageHandling
- * @brief Sends a reply message that is delayed by @p rel_time.
- * @param rel_time Relative time duration to delay the message in
- * microseconds, milliseconds, seconds or minutes.
- * @param what Message elements.
- * @see delayed_send()
- */
-template<class Rep, class Period, typename... Args>
-inline void delayed_reply(const std::chrono::duration<Rep, Period>& rel_time,
- Args&&... what) {
- delayed_send(self->last_sender(), rel_time, std::forward<Args>(what)...);
-}
+/** @} */
/**
* @brief Blocks execution of this actor until all
View
96 cppa/scheduler.hpp
@@ -55,6 +55,20 @@ class scheduler_helper;
typedef std::function<void()> void_function;
typedef std::function<void(local_actor*)> init_callback;
+namespace detail {
+// forwards self_type as actor_ptr, otherwise equal to std::forward
+template<typename T>
+struct spawn_fwd_ {
+static inline T&& _(T&& arg) { return std::move(arg); }
+static inline T& _(T& arg) { return arg; }
+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(); }
+};
+} // namespace detail
+
/**
* @brief
*/
@@ -85,6 +99,31 @@ class scheduler {
virtual void enqueue(scheduled_actor*) = 0;
/**
+ * @brief Informs the scheduler about a converted context
+ * (a thread that acts as actor).
+ * @note Calls <tt>what->attach(...)</tt>.
+ */
+ virtual void register_converted_context(local_actor* what);
+
+ /**
+ * @brief Informs the scheduler about a hidden (non-actor)
+ * context that should be counted by await_others_done().
+ * @returns An {@link attachable} that the hidden context has to destroy
+ * if his lifetime ends.
+ */
+ virtual attachable* register_hidden_context();
+
+ template<typename Duration, typename... Data>
+ void delayed_send(const channel_ptr& to,
+ const Duration& rel_time,
+ Data&&... data) {
+ static_assert(sizeof...(Data) > 0, "no message to send");
+ auto sub = make_any_tuple(std::forward<Data>(data)...);
+ auto tup = make_any_tuple(util::duration{rel_time}, to, std::move(sub));
+ delayed_send_helper()->enqueue(self, std::move(tup));
+ }
+
+ /**
* @brief Spawns a new actor that executes <code>fun()</code>
* with the scheduling policy @p hint if possible.
*/
@@ -112,31 +151,46 @@ class scheduler {
*/
virtual actor_ptr spawn(scheduled_actor* what, init_callback init_cb) = 0;
- /**
- * @brief Informs the scheduler about a converted context
- * (a thread that acts as actor).
- * @note Calls <tt>what->attach(...)</tt>.
- */
- virtual void register_converted_context(local_actor* what);
+ // hide implementation details for documentation
+# ifndef CPPA_DOCUMENTATION
+
+ template<typename Fun, typename Arg0, typename... Args>
+ actor_ptr spawn_impl(scheduling_hint hint, Fun&& fun, Arg0&& arg0, Args&&... args) {
+ return this->spawn(
+ std::bind(
+ std::forward<Fun>(fun),
+ detail::spawn_fwd_<typename util::rm_ref<Arg0>::type>::_(arg0),
+ detail::spawn_fwd_<typename util::rm_ref<Args>::type>::_(args)...),
+ hint);
+ }
- /**
- * @brief Informs the scheduler about a hidden (non-actor)
- * context that should be counted by await_others_done().
- * @returns An {@link attachable} that the hidden context has to destroy
- * if his lifetime ends.
- */
- virtual attachable* register_hidden_context();
+ template<typename Fun>
+ actor_ptr spawn_impl(scheduling_hint hint, Fun&& fun) {
+ return this->spawn(std::forward<Fun>(fun), hint);
+ }
- template<typename Duration, typename... Data>
- void delayed_send(const actor_ptr& to,
- const Duration& rel_time,
- Data&&... data) {
- static_assert(sizeof...(Data) > 0, "no message to send");
- auto sub = make_any_tuple(std::forward<Data>(data)...);
- auto tup = make_any_tuple(util::duration{rel_time}, to, std::move(sub));
- delayed_send_helper()->enqueue(self, std::move(tup));
+ template<typename InitCallback, typename Fun, typename Arg0, typename... Args>
+ actor_ptr spawn_cb_impl(scheduling_hint hint,
+ InitCallback&& init_cb,
+ Fun&& fun, Arg0&& arg0, Args&&... args) {
+ return this->spawn(
+ std::bind(
+ std::forward<Fun>(fun),
+ detail::spawn_fwd_<typename util::rm_ref<Arg0>::type>::_(arg0),
+ detail::spawn_fwd_<typename util::rm_ref<Args>::type>::_(args)...),
+ hint,
+ std::forward<InitCallback>(init_cb));
}
+ template<typename InitCallback, typename Fun>
+ actor_ptr spawn_cb_impl(scheduling_hint hint, InitCallback&& init_cb, Fun&& fun) {
+ return this->spawn(std::forward<Fun>(fun),
+ hint,
+ std::forward<InitCallback>(init_cb));
+ }
+
+# endif // CPPA_DOCUMENTATION
+
};
/**
View
3 cppa/self.hpp
@@ -49,7 +49,8 @@ extern local_actor* self;
class local_actor;
// convertible<...> enables "actor_ptr this_actor = self;"
-class self_type : public convertible<self_type, actor*> {
+class self_type : public convertible<self_type, actor*>,
+ public convertible<self_type, channel*> {
self_type(const self_type&) = delete;
self_type& operator=(const self_type&) = delete;
View
13 src/local_actor.cpp
@@ -68,8 +68,7 @@ class down_observer : public attachable {
} // namespace <anonymous>
local_actor::local_actor(bool sflag)
-: m_chaining(sflag), m_trap_exit(false), m_is_scheduled(sflag) {
-}
+: m_chaining(sflag), m_trap_exit(false), m_is_scheduled(sflag) { }
void local_actor::monitor(actor_ptr whom) {
if (whom) whom->attach(new down_observer(this, whom));
@@ -85,14 +84,14 @@ void local_actor::on_exit() { }
void local_actor::init() { }
void local_actor::join(const group_ptr& what) {
- if (!what) return;
- attach(what->subscribe(this));
+ if (what) attach(what->subscribe(this));
}
void local_actor::leave(const group_ptr& what) {
- if (!what) return;
- attachable::token group_token(typeid(group::unsubscriber), what.get());
- detach(group_token);
+ if (what) {
+ attachable::token group_token(typeid(group::unsubscriber), what.get());
+ detach(group_token);
+ }
}
} // namespace cppa
View
4 src/scheduler.cpp
@@ -108,8 +108,8 @@ void scheduler_helper::time_emitter(scheduler_helper::ptr_type m_self) {
bool done = false;
// message handling rules
auto mfun = (
- on<util::duration,actor_ptr,anything>() >> [&](const util::duration& d,
- const actor_ptr&) {
+ on<util::duration,channel_ptr,anything>() >> [&](const util::duration& d,
+ const channel_ptr&) {
// calculate timeout
auto timeout = now();
timeout += d;

0 comments on commit 0f8c067

Please sign in to comment.