Commit 092a6db1 authored by neverlord's avatar neverlord

documentation and maintenance

parent e39d7161
......@@ -190,24 +190,19 @@ nobase_library_include_HEADERS = \
cppa/util/enable_if.hpp \
cppa/util/fiber.hpp \
cppa/util/fixed_vector.hpp \
cppa/util/has_copy_member_fun.hpp \
cppa/util/if_else.hpp \
cppa/util/is_array_of.hpp \
cppa/util/is_builtin.hpp \
cppa/util/is_comparable.hpp \
cppa/util/is_copyable.hpp \
cppa/util/is_forward_iterator.hpp \
cppa/util/is_iterable.hpp \
cppa/util/is_iterable.hpp \
cppa/util/is_legal_tuple_type.hpp \
cppa/util/is_manipulator.hpp \
cppa/util/is_mutable_ref.hpp \
cppa/util/is_one_of.hpp \
cppa/util/is_primitive.hpp \
cppa/util/producer_consumer_list.hpp \
cppa/util/pt_dispatch.hpp \
cppa/util/pt_token.hpp \
cppa/util/remove_const_reference.hpp \
cppa/util/replace_type.hpp \
cppa/util/ripemd_160.hpp \
cppa/util/rm_ref.hpp \
......
......@@ -3,7 +3,6 @@ cppa/tuple.hpp
unit_testing/main.cpp
cppa/util/void_type.hpp
cppa/util/type_list.hpp
cppa/util/is_one_of.hpp
cppa/util/conjunction.hpp
cppa/util/disjunction.hpp
unit_testing/test.hpp
......@@ -22,15 +21,11 @@ unit_testing/test__spawn.cpp
src/mock_scheduler.cpp
cppa/actor.hpp
unit_testing/test__intrusive_ptr.cpp
cppa/util/is_comparable.hpp
cppa/util/callable_trait.hpp
unit_testing/test__type_list.cpp
cppa/util/remove_const_reference.hpp
cppa/util/compare_tuples.hpp
cppa/get.hpp
cppa/detail/tdata.hpp
cppa/util/is_copyable.hpp
cppa/util/has_copy_member_fun.hpp
cppa/detail/intermediate.hpp
cppa/detail/invokable.hpp
cppa/on.hpp
......@@ -260,3 +255,4 @@ src/partial_function.cpp
cppa/intrusive/singly_linked_list.hpp
cppa/intrusive/iterator.hpp
unit_testing/test__intrusive_containers.cpp
examples/dancing_kirby.cpp
......@@ -48,7 +48,11 @@
namespace cppa {
// implements linking and monitoring for actors
/**
* @brief Implements linking and monitoring for actors.
* @tparam Base Either {@link cppa::actor actor}
* or {@link cppa::local_actor local_actor}.
*/
template<class Base>
class abstract_actor : public Base
{
......
......@@ -95,6 +95,10 @@ class abstract_event_based_actor : public detail::abstract_scheduled_actor
// provoke compiler errors for usage of receive() and related functions
/**
* @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&&...)
{
......@@ -103,18 +107,27 @@ class abstract_event_based_actor : public detail::abstract_scheduled_actor
"Use become() instead.");
}
/**
* @brief Provokes a compiler error.
*/
template<typename... Args>
void receive_loop(Args&&... args)
{
receive(std::forward<Args>(args)...);
}
/**
* @brief Provokes a compiler error.
*/
template<typename... Args>
void receive_while(Args&&... args)
{
receive(std::forward<Args>(args)...);
}
/**
* @brief Provokes a compiler error.
*/
template<typename... Args>
void do_receive(Args&&... args)
{
......
......@@ -35,6 +35,10 @@
namespace cppa {
/**
* @brief Implements the deserializer interface with
* a binary serialization protocol.
*/
class binary_deserializer : public deserializer
{
......
......@@ -38,6 +38,10 @@ namespace cppa {
namespace detail { class binary_writer; }
/**
* @brief Implements the serializer interface with
* a binary serialization protocol.
*/
class binary_serializer : public serializer
{
......
......@@ -41,6 +41,9 @@ namespace cppa {
/**
* @ingroup CopyOnWrite
* @brief A copy-on-write smart pointer implementation.
* @tparam T A class that provides a copy() member function and has
* the same interface as or is a subclass of
* {@link ref_counted}.
*/
template<typename T>
class cow_ptr
......
......@@ -125,7 +125,7 @@
* implement Actor based applications.
*
* @namespace cppa::util
* @brief This namespace contains utility classes and meta programming
* @brief This namespace contains utility classes and metaprogramming
* utilities used by the libcppa implementation.
*
* @namespace cppa::intrusive
......@@ -283,24 +283,24 @@
*
* @section ReceiveLoops Receive loops
*
* Previous examples using @p receive create behavior on-the-fly.
* Previous examples using @p receive create behaviors on-the-fly.
* This is inefficient in a loop since the argument passed to receive
* is created in each iteration again. Its possible to store the behavior
* is created in each iteration again. It's possible to store the behavior
* in a variable and pass that variable to receive. This fixes the issue
* of re-creation each iteration but rips apart definition and usage.
*
* There are three convenience function implementing receive loops to
* declare patterns and behavior where they belong without unnecessary
* copies: @p receive_loop, @p receive_while and @p do_receive.
* There are four convenience functions implementing receive loops to
* declare behavior where it belongs without unnecessary
* copies: @p receive_loop, @p receive_while, @p receive_for and @p do_receive.
*
* @p receive_loop is analogous to @p receive and loops "forever" (until the
* actor finishes execution).
*
* @p receive_while creates a functor evaluating a lambda expression.
* The loop continues until the given returns false. A simple example:
* The loop continues until the given lambda returns @p false. A simple example:
*
* @code
* // receive two ints
* // receive two integers
* vector<int> received_values;
* receive_while([&]() { return received_values.size() < 2; })
* (
......@@ -312,6 +312,17 @@
* // ...
* @endcode
*
* @p receive_for is a simple ranged-based loop:
*
* @code
* std::vector<int> vec {1, 2, 3, 4};
* auto i = vec.begin();
* receive_for(i, vec.end())
* (
* on(atom("get")) >> [&]() { reply(atom("result"), *i); }
* );
* @endcode
*
* @p do_receive returns a functor providing the function @p until that
* takes a lambda expression. The loop continues until the given lambda
* returns true. Example:
......@@ -350,6 +361,8 @@
* );
* @endcode
*
* See also the {@link dancing_kirby.cpp dancing kirby example}.
*
* @defgroup ImplicitConversion Implicit type conversions.
*
* The message passing of @p libcppa prohibits pointers in messages because
......@@ -380,14 +393,39 @@
* on("hello actor!") >> []() { }
* );
* @endcode
*
* @defgroup ActorManagement Actor management.
*
*/
// examples
/**
* @brief A trivial example program.
* @example hello_world_example.cpp
*/
/**
* @brief Shows the usage of {@link cppa::atom atoms}
* and {@link cppa::arg_match arg_match}.
* @example math_actor_example.cpp
*/
/**
* @brief A simple example for a future_send based application.
* @example dancing_kirby.cpp
*/
/**
* @brief An event-based "Dining Philosophers" implementation.
* @example dining_philosophers.cpp
*/
namespace cppa {
/**
* @ingroup ActorManagement
* @brief Links @p lhs and @p rhs;
* @param lhs Left-hand operand.
* @param rhs Right-hand operand.
* @pre <tt>lhs != rhs</tt>
*/
void link(actor_ptr& lhs, actor_ptr& rhs);
......@@ -408,54 +446,68 @@ void link(actor_ptr&& lhs, actor_ptr&& rhs);
void link(actor_ptr& lhs, actor_ptr&& rhs);
/**
* @ingroup ActorManagement
* @brief Unlinks @p lhs from @p rhs;
* @param lhs Left-hand operand.
* @param rhs Right-hand operand.
* @pre <tt>lhs != rhs</tt>
*/
void unlink(actor_ptr& lhs, actor_ptr& rhs);
/**
* @brief Adds a monitor to @p whom.
*
* Sends a ":Down" message to the calling Actor if @p whom exited.
* @param whom Actor instance that should be monitored by the calling Actor.
* @ingroup ActorManagement
* @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);
/**
* @copydoc monitor(actor_ptr&)
*/
void monitor(actor_ptr&& whom);
/**
* @ingroup ActorManagement
* @brief Removes a monitor from @p whom.
* @param whom Monitored Actor.
*/
void demonitor(actor_ptr& whom);
/**
* @ingroup ActorManagement
* @brief Spans a new context-switching actor.
* @returns A pointer to the spawned {@link actor Actor}.
*/
inline actor_ptr spawn(scheduled_actor* what)
{
return get_scheduler()->spawn(what, scheduled);
}
/**
* @ingroup ActorManagement
* @brief Spans a new context-switching actor.
* @tparam Hint Hint to the scheduler for the best scheduling strategy.
* @returns A pointer to the spawned {@link actor Actor}.
*/
template<scheduling_hint Hint>
inline actor_ptr spawn(scheduled_actor* what)
{
return get_scheduler()->spawn(what, Hint);
}
/**
* @ingroup ActorManagement
* @brief Spans a new event-based actor.
* @returns A pointer to the spawned {@link actor Actor}.
*/
inline actor_ptr spawn(abstract_event_based_actor* what)
{
return get_scheduler()->spawn(what);
}
/**
* @ingroup ActorManagement
* @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 newly created {@link actor Actor}.
* @returns A pointer to the spawned {@link actor actor}.
*/
template<scheduling_hint Hint, typename F, typename... Args>
auto //actor_ptr
......@@ -471,10 +523,8 @@ spawn(F&& what, Args const&... args)
}
/**
* @ingroup ActorManagement
* @brief Alias for <tt>spawn<scheduled>(what, args...)</tt>.
* @param what Function or functor that the spawned Actor should execute.
* @param args Arguments needed to invoke @p what.
* @returns A pointer to the newly created {@link actor Actor}.
*/
template<typename F, typename... Args>
auto // actor_ptr
......@@ -489,27 +539,20 @@ spawn(F&& what, Args const&... args)
#ifdef CPPA_DOCUMENTATION
/**
* @brief Sends a message to @p whom.
*
* Sends the tuple <tt>{ arg0, args... }</tt> as a message to @p whom.
* @param whom Receiver of the message.
* @param arg0 First value for the message content.
* @param args Any number of values for the message content.
* @ingroup MessageHandling
* @brief Sends <tt>{arg0, args...}</tt> as a message to @p whom.
*/
template<typename Arg0, typename... Args>
void send(channel_ptr& whom, Arg0 const& arg0, Args const&... args);
/**
* @ingroup MessageHandling
* @brief Send a message to @p whom.
*
* <b>Usage example:</b>
* @code
* self << make_tuple(1, 2, 3);
* @endcode
*
* Sends the tuple @p what as a message to @p whom.
* @param whom Receiver of the message.
* @param what Content of the message.
* @returns @p whom.
*/
channel_ptr& operator<<(channel_ptr& whom, any_tuple const& what);
......@@ -586,6 +629,10 @@ self_type const& operator<<(self_type const& s, any_tuple&& what);
#endif // CPPA_DOCUMENTATION
/**
* @ingroup MessageHandling
* @brief Sends a message to the sender of the last received message.
*/
template<typename Arg0, typename... Args>
void reply(Arg0 const& arg0, Args const&... args)
{
......@@ -593,6 +640,7 @@ void reply(Arg0 const& arg0, Args const&... args)
}
/**
* @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.
......@@ -604,6 +652,17 @@ void future_send(actor_ptr whom, Duration const& rel_time, Data const&... data)
get_scheduler()->future_send(whom, rel_time, data...);
}
/**
* @ingroup MessageHandling
* @brief Sends a reply message that is delayed by @p rel_time.
* @see future_send()
*/
template<typename Duration, typename... Data>
void delayed_reply(Duration const& rel_time, Data const... data)
{
future_send(self->last_sender(), rel_time, data...);
}
/**
* @brief Blocks execution of this actor until all
* other actors finished execution.
......
......@@ -35,8 +35,6 @@
#include "cppa/util/rm_ref.hpp"
#include "cppa/util/void_type.hpp"
#include "cppa/util/conjunction.hpp"
#include "cppa/util/disjunction.hpp"
#include "cppa/util/is_iterable.hpp"
#include "cppa/util/is_primitive.hpp"
#include "cppa/util/is_forward_iterator.hpp"
......
......@@ -62,7 +62,7 @@ struct ptype_to_type :
util::if_else_c<PT == pt_u16string, std::u16string,
util::if_else_c<PT == pt_u32string, std::u32string,
// default case
util::wrapped<void> > > > > > > > > > > > > > >
void > > > > > > > > > > > > > >
{
};
......
......@@ -81,6 +81,44 @@ struct receive_while_helper
};
template<typename T>
class receive_for_helper
{
T& begin;
T end;
public:
receive_for_helper(T& first, T const& last) : begin(first), end(last) { }
void operator()(behavior& bhvr)
{
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);
}
void operator()(behavior&& bhvr)
{
behavior tmp{std::move(bhvr)};
(*this)(tmp);
}
template<typename... Args>
void operator()(partial_function&& arg0, Args&&... args)
{
typename select_bhvr<Args...>::type tmp;
(*this)(tmp.splice(std::move(arg0), std::forward<Args>(args)...));
}
};
class do_receive_helper
{
......
......@@ -57,12 +57,12 @@ class either
/**
* @brief Default constructor, creates a @p Left.
*/
either() : m_is_left(true) { new (&m_left) Left (); }
either() : m_is_left(true) { new (&m_left) left_type (); }
/**
* @brief Creates a @p Left from @p value.
*/
either(Left const& value) : m_is_left(true) { cr_left(value); }
either(left_type const& value) : m_is_left(true) { cr_left(value); }
/**
* @brief Creates a @p Left from @p value.
......@@ -72,25 +72,19 @@ class either
/**
* @brief Creates a @p Right from @p value.
*/
either(Right const& value) : m_is_left(false) { cr_right(value); }
either(right_type const& 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)); }
/**
* @brief Copy constructor.
*/
either(either const& other) : m_is_left(other.m_is_left)
{
if (other.m_is_left) cr_left(other.m_left);
else cr_right(other.m_right);
}
/**
* @brief Move constructor.
*/
either(either&& other) : m_is_left(other.m_is_left)
{
if (other.m_is_left) cr_left(std::move(other.m_left));
......@@ -99,9 +93,6 @@ class either
~either() { destroy(); }
/**
* @brief Copy assignment.
*/
either& operator=(either const& other)
{
if (m_is_left == other.m_is_left)
......@@ -119,9 +110,6 @@ class either
return *this;
}
/**
* @brief Move assignment.
*/
either& operator=(either&& other)
{
if (m_is_left == other.m_is_left)
......@@ -161,7 +149,7 @@ class either
/**
* @brief Returns this @p either as a @p Left.
*/
inline Left const& left() const
inline left_type const& left() const
{
CPPA_REQUIRE(m_is_left);
return m_left;
......@@ -179,7 +167,7 @@ class either
/**
* @brief Returns this @p either as a @p Right.
*/
inline Right const& right() const
inline right_type const& right() const
{
CPPA_REQUIRE(!m_is_left);
return m_right;
......@@ -191,8 +179,8 @@ class either
union
{
Left m_left;
Right m_right;
left_type m_left;
right_type m_right;
};
void destroy()
......@@ -204,17 +192,18 @@ class either
template<typename L>
void cr_left(L&& value)
{
new (&m_left) Left (std::forward<L>(value));
new (&m_left) left_type (std::forward<L>(value));
}
template<typename R>
void cr_right(R&& value)
{
new (&m_right) Right (std::forward<R>(value));
new (&m_right) right_type (std::forward<R>(value));
}
};
/** @relates either */
template<typename Left, typename Right>
bool operator==(either<Left, Right> const& lhs, either<Left, Right> const& rhs)
{
......@@ -226,54 +215,63 @@ bool operator==(either<Left, Right> const& lhs, either<Left, Right> const& rhs)
return false;
}
/** @relates either */
template<typename Left, typename Right>
bool operator==(either<Left, Right> const& lhs, Left const& rhs)
{
return lhs.is_left() && lhs.left() == rhs;
}
/** @relates either */
template<typename Left, typename Right>
bool operator==(Left const& lhs, either<Left, Right> const& rhs)
{
return rhs == lhs;
}
/** @relates either */
template<typename Left, typename Right>
bool operator==(either<Left, Right> const& lhs, Right const& rhs)
{
return lhs.is_right() && lhs.right() == rhs;
}
/** @relates either */
template<typename Left, typename Right>
bool operator==(Right const& lhs, either<Left, Right> const& rhs)
{
return rhs == lhs;
}
/** @relates either */
template<typename Left, typename Right>
bool operator!=(either<Left, Right> const& lhs, either<Left, Right> const& rhs)
{
return !(lhs == rhs);
}
/** @relates either */
template<typename Left, typename Right>
bool operator!=(either<Left, Right> const& lhs, Left const& rhs)
{
return !(lhs == rhs);
}
/** @relates either */
template<typename Left, typename Right>
bool operator!=(Left const& lhs, either<Left, Right> const& rhs)
{
return !(rhs == lhs);
}
/** @relates either */
template<typename Left, typename Right>
bool operator!=(either<Left, Right> const& lhs, Right const& rhs)
{
return !(lhs == rhs);
}
/** @relates either */
template<typename Left, typename Right>
bool operator!=(Right const& lhs, either<Left, Right> const& rhs)
{
......
......@@ -36,6 +36,9 @@
namespace cppa {
/**
* @brief Base class for non-stacked event-based actor implementations.
*/
class event_based_actor : public event_based_actor_base<event_based_actor>
{
......@@ -48,8 +51,13 @@ class event_based_actor : public event_based_actor_base<event_based_actor>
public:
/**
* @brief Terminates this actor with normal exit reason.
*/
void become_void();
void quit(std::uint32_t reason);
};
} // namespace cppa
......
......@@ -36,6 +36,9 @@
namespace cppa {
/**
* @brief Base class for event-based actor implementations.
*/
template<typename Derived>
class event_based_actor_base : public abstract_event_based_actor
{
......@@ -46,11 +49,19 @@ class event_based_actor_base : public abstract_event_based_actor
protected:
/**
* @brief Sets the actor's behavior to @p bhvr.
* @note @p bhvr is owned by caller and must remain valid until
* the actor terminates.
* This member function should be used to use a member of
* a subclass as behavior.
*/
inline void become(behavior* bhvr)
{
d_this()->do_become(bhvr, false);
}
/** @brief Sets the actor's behavior. */
template<typename... Args>
void become(partial_function&& arg0, Args&&... args)
{
......@@ -59,9 +70,10 @@ class event_based_actor_base : public abstract_event_based_actor
d_this()->do_become(ptr, true);
}
inline void become(behavior&& arg0)
/** @brief Sets the actor's behavior to @p bhvr. */
inline void become(behavior&& bhvr)
{
d_this()->do_become(new behavior(std::move(arg0)), true);
d_this()->do_become(new behavior(std::move(bhvr)), true);
}
};
......
......@@ -33,6 +33,11 @@
#include <cstdint>
/**
* @namespace cppa::exit_reason
* @brief This naemspace contains all predefined exit reasons.
*/
namespace cppa { namespace exit_reason {
/**
......
......@@ -40,7 +40,10 @@
namespace cppa {
/**
* @example dining_philosophers.cpp
* @brief A base class for event-based actors using the
* Curiously Recurring Template Pattern
* to initialize the derived actor with its @p init_state member.
* @tparam Derived Subclass of fsm_actor.
*/
template<class Derived>
class fsm_actor : public event_based_actor
......@@ -48,6 +51,10 @@ class fsm_actor : public event_based_actor
public:
/**
* @brief Overrides abstract_event_based_actor::init() and sets
* the initial actor behavior to <tt>Derived::init_state</tt>.
*/
void init()
{
become(&(static_cast<Derived*>(this)->init_state));
......
......@@ -96,60 +96,90 @@ class iterator // : std::iterator<forward_iterator_tag, T>
};
/**
* @relates iterator
*/
template<class T>
inline bool operator==(iterator<T> const& lhs, iterator<T> const& rhs)
{
return lhs.ptr() == rhs.ptr();
}
/**
* @relates iterator
*/
template<class T>
inline bool operator==(iterator<T> const& lhs, T const* rhs)
{
return lhs.ptr() == rhs;
}
/**
* @relates iterator
*/
template<class T>
inline bool operator==(T const* lhs, iterator<T> const& rhs)
{
return lhs == rhs.ptr();
}
/**
* @relates iterator
*/
template<class T>
inline bool operator==(iterator<T> const& lhs, decltype(nullptr))
{
return lhs.ptr() == nullptr;
}
/**
* @relates iterator
*/
template<class T>
inline bool operator==(decltype(nullptr), iterator<T> const& rhs)
{
return rhs.ptr() == nullptr;
}
/**
* @relates iterator
*/
template<class T>
inline bool operator!=(iterator<T> const& lhs, iterator<T> const& rhs)
{
return !(lhs == rhs);
}
/**
* @relates iterator
*/
template<class T>
inline bool operator!=(iterator<T> const& lhs, T const* rhs)
{
return !(lhs == rhs);
}
/**
* @relates iterator
*/
template<class T>
inline bool operator!=(T const* lhs, iterator<T> const& rhs)
{
return !(lhs == rhs);
}
/**
* @relates iterator
*/
template<class T>
inline bool operator!=(iterator<T> const& lhs, decltype(nullptr))
{
return !(lhs == nullptr);
}
/**
* @relates iterator
*/
template<class T>
inline bool operator!=(decltype(nullptr), iterator<T> const& rhs)
{
......
......@@ -38,7 +38,6 @@
#include "cppa/exception.hpp"
#include "cppa/util/rm_ref.hpp"
#include "cppa/util/disjunction.hpp"
#include "cppa/detail/implicit_conversions.hpp"
namespace cppa {
......
......@@ -69,17 +69,11 @@ class option
*/
option(T const& value) : m_valid(false) { cr(value); }
/**
* @brief Copy constructor.
*/
option(option const& other) : m_valid(false)
{
if (other.m_valid) cr(other.m_value);
}
/**
* @brief Move constructor.
*/
option(option&& other) : m_valid(false)
{
if (other.m_valid) cr(std::move(other.m_value));
......@@ -87,9 +81,6 @@ class option
~option() { destroy(); }
/**
* @brief Copy assignment.
*/
option& operator=(option const& other)
{
if (m_valid)
......@@ -104,9 +95,6 @@ class option
return *this;
}
/**
* @brief Move assignment.
*/
option& operator=(option&& other)
{
if (m_valid)
......@@ -121,9 +109,6 @@ class option
return *this;
}
/**
* @brief Copy assignment.
*/
option& operator=(T const& value)
{
if (m_valid) m_value = value;
......@@ -131,9 +116,6 @@ class option
return *this;
}
/**
* @brief Move assignment.
*/
option& operator=(T& value)
{
if (m_valid) m_value = std::move(value);
......@@ -153,8 +135,7 @@ class option
inline explicit operator bool() const { return m_valid; }
/**
* @brief Returns @p false if this @p option has a valid value;
* otherwise @p true.
* @brief Returns <tt>!valid()</tt>
*/
inline bool operator!() const { return !m_valid; }
......@@ -195,8 +176,9 @@ class option
}
/**
* @brief Returns the value of this @p option if it's valid
* or @p default_value.
* @brief Returns the value. The value is set to @p default_value
* if <tt>valid() == false</tt>.
* @post <tt>valid() == true</tt>
*/
inline T& get_or_else(T const& default_value)
{
......@@ -237,6 +219,7 @@ class option
};
/** @relates option */
template<typename T>
bool operator==(option<T> const& lhs, option<T> const& rhs)
{
......@@ -244,6 +227,7 @@ bool operator==(option<T> const& lhs, option<T> const& rhs)
return false;
}
/** @relates option */
template<typename T>
bool operator==(option<T> const& lhs, T const& rhs)
{
......@@ -251,24 +235,28 @@ bool operator==(option<T> const& lhs, T const& rhs)
return false;
}
/** @relates option */
template<typename T>
bool operator==(T const& lhs, option<T> const& rhs)
{
return rhs == lhs;
}
/** @relates option */
template<typename T>
bool operator!=(option<T> const& lhs, option<T> const& rhs)
{
return !(lhs == rhs);
}
/** @relates option */
template<typename T>
bool operator!=(option<T> const& lhs, T const& rhs)
{
return !(lhs == rhs);
}
/** @relates option */
template<typename T>
bool operator!=(T const& lhs, option<T> const& rhs)
{
......
......@@ -286,7 +286,7 @@ class primitive_variant
* @relates primitive_variant
* @param pv A primitive variant of type @p T.
* @returns A const reference to the value of @p pv of type @p T.
* @throws <tt>std::logic_error</tt> if @p pv is not of type @p T.
* @throws std::logic_error if @p pv is not of type @p T.
*/
template<typename T>
T const& get(primitive_variant const& pv)
......@@ -301,7 +301,7 @@ T const& get(primitive_variant const& pv)
* @relates primitive_variant
* @param pv A primitive variant of type @p T.
* @returns A reference to the value of @p pv of type @p T.
* @throws <tt>std::logic_error</tt> if @p pv is not of type @p T.
* @throws std::logic_error if @p pv is not of type @p T.
*/
template<typename T>
T& get_ref(primitive_variant& pv)
......
......@@ -75,6 +75,26 @@ void receive_loop(behavior& bhvr);
template<typename Statement>
auto receive_while(Statement&& stmt);
/**
* @brief Receives messages as in a range-based loop.
*
* Semantically equal to: <tt>for ( ; begin != end; ++begin) { receive(...); }</tt>.
*
* <b>Usage example:</b>
* @code
* int i = 0;
* receive_for(i, 10)
* (
* on(atom("get")) >> [&]() { reply("result", i); }
* );
* @endcode
* @param begin First value in range.
* @param end Last value in range (excluded).
* @returns A functor implementing the loop.
*/
template<typename T>
auto receive_for(T& begin, T const& end);
/**
* @brief Receives messages until @p stmt returns true.
*
......@@ -131,6 +151,12 @@ void receive_loop(partial_function&& arg0, Args&&... args)
receive_loop(tmp.splice(std::move(arg0), std::forward<Args>(args)...));
}
template<typename T>
detail::receive_for_helper<T> receive_for(T& begin, T const& end)
{
return {begin, end};
}
template<typename Statement>
detail::receive_while_helper<Statement> receive_while(Statement&& stmt)
{
......
......@@ -35,6 +35,9 @@
namespace cppa {
/**
* @brief A base class for event-based actors using a behavior stack.
*/
class stacked_event_based_actor : public event_based_actor_base<stacked_event_based_actor>
{
......@@ -46,7 +49,14 @@ class stacked_event_based_actor : public event_based_actor_base<stacked_event_ba
protected:
/**
* @brief Restores the last behavior.
*/
void unbecome();
/**
* @brief Terminates this actor with normal exit reason.
*/
void become_void();
};
......
......@@ -41,7 +41,6 @@
#include "cppa/object.hpp"
#include "cppa/util/comparable.hpp"
#include "cppa/util/disjunction.hpp"
#include "cppa/util/callable_trait.hpp"
#include "cppa/detail/demangle.hpp"
......
......@@ -38,11 +38,11 @@ namespace cppa { namespace util {
*
* @p Subclass must provide a @c compare member function that compares
* to instances of @p T and returns an integer @c x with:
* - <tt>x < 0</tt> if <tt>this < other</tt>
* - <tt>x > 0</tt> if <tt>this > other</tt>
* - <tt>x == 0</tt> if <tt>this == other</tt>
* - <tt>x < 0</tt> if <tt>*this < other</tt>
* - <tt>x > 0</tt> if <tt>*this > other</tt>
* - <tt>x == 0</tt> if <tt>*this == other</tt>
*/
template<typename Subclass, typename T = Subclass>
template<class Subclass, class T = Subclass>
class comparable
{
......@@ -108,7 +108,7 @@ class comparable
};
template<typename Subclass>
template<class Subclass>
class comparable<Subclass, Subclass>
{
......
......@@ -42,6 +42,11 @@ struct disable_if_c<false, T>
typedef T type;
};
/**
* @ingroup MetaProgramming
* @brief SFINAE trick to disable a template function based on its
* template parameters.
*/
template<class Trait, typename T = void>
struct disable_if : disable_if_c<Trait::value, T>
{
......
......@@ -36,6 +36,9 @@
namespace cppa { namespace util {
/**
* @brief SI time units to specify timeouts.
*/
enum class time_unit : std::uint32_t
{
none = 0,
......@@ -44,6 +47,10 @@ enum class time_unit : std::uint32_t
microseconds = 1000000
};
/**
* @brief Converts an STL time period to a
* {@link cppa::util::time_unit time_unit}.
*/
template<typename Period>
constexpr time_unit get_time_unit_from_period()
{
......@@ -58,6 +65,10 @@ constexpr time_unit get_time_unit_from_period()
: time_unit::none))));
}
/**
* @brief Time duration consisting of a {@link cppa::util::time_unit time_unit}
* and a 32 bit unsigned integer.
*/
class duration
{
......@@ -79,6 +90,9 @@ class duration
"only seconds, milliseconds or microseconds allowed");
}
/**
* @brief Returns true if <tt>unit != time_unit::none</tt>.
*/
inline bool valid() const { return unit != time_unit::none; }
time_unit unit;
......@@ -87,8 +101,14 @@ class duration
};
/**
* @relates duration
*/
bool operator==(duration const& lhs, duration const& rhs);
/**
* @relates duration
*/
inline bool operator!=(duration const& lhs, duration const& rhs)
{
return !(lhs == rhs);
......@@ -96,6 +116,9 @@ inline bool operator!=(duration const& lhs, duration const& rhs)
} } // namespace cppa::util
/**
* @relates cppa::util::duration
*/
template<class Clock, class Duration>
std::chrono::time_point<Clock, Duration>&
operator+=(std::chrono::time_point<Clock, Duration>& lhs,
......
......@@ -38,6 +38,9 @@ namespace cppa { namespace util {
template<size_t N, class C>
struct element_at;
/**
* @brief Returns the n-th template parameter of @p C.
*/
template<size_t N, template<typename...> class C, typename... Tn>
struct element_at<N, C<Tn...>> : at<N, Tn...>
{
......
......@@ -44,6 +44,11 @@ struct enable_if_c<true, T>
typedef T type;
};
/**
* @ingroup MetaProgramming
* @brief SFINAE trick to enable a template function based on its
* template parameters.
*/
template<class Trait, typename T = void>
struct enable_if : enable_if_c<Trait::value, T>
{
......
......@@ -39,8 +39,6 @@
#include "cppa/config.hpp"
#include "cppa/config.hpp"
namespace cppa { namespace util {
/**
......@@ -62,14 +60,16 @@ class fixed_vector
public:
typedef T value_type;
typedef size_t size_type;
typedef T& reference;
typedef T const& const_reference;
typedef ptrdiff_t difference_type;
typedef value_type& reference;
typedef value_type const& const_reference;
typedef value_type* pointer;
typedef value_type const* const_pointer;
typedef T* iterator;
typedef T const* const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
......@@ -77,7 +77,7 @@ class fixed_vector
fixed_vector(fixed_vector const& other) : m_size(other.m_size)
{
std::copy(other.begin(), other.end(), m_data);
std::copy(other.begin(), other.end(), begin());
}
fixed_vector& operator=(fixed_vector const& other)
......@@ -96,7 +96,22 @@ class fixed_vector
fixed_vector(std::initializer_list<T> init) : m_size(init.size())
{
CPPA_REQUIRE(init.size() <= MaxSize);
std::copy(init.begin(), init.end(), m_data);
std::copy(init.begin(), init.end(), begin());
}
void assign(size_type count, const_reference value)
{
resize(count);
std::fill(begin(), end(), value);
}
template<typename InputIterator>
void assign(InputIterator first, InputIterator last,
// dummy SFINAE argument
typename std::iterator_traits<InputIterator>::pointer = 0)
{
resize(std::distance(first, last));
std::copy(first, last, begin());
}
inline size_type size() const
......@@ -104,6 +119,16 @@ class fixed_vector
return m_size;
}
inline size_type max_size() const
{
return MaxSize;
}
inline size_type capacity() const
{
return max_size() - size();
}
inline void clear()
{
m_size = 0;
......@@ -114,17 +139,28 @@ class fixed_vector
return m_size == 0;
}
inline bool not_empty() const
{
return m_size > 0;
}
inline bool full() const
{
return m_size == MaxSize;
}
inline void push_back(T const& what)
inline void push_back(const_reference what)
{
CPPA_REQUIRE(!full());
m_data[m_size++] = what;
}
inline void pop_back()
{
CPPA_REQUIRE(not_empty());
--m_size;
}
inline reference at(size_type pos)
{
CPPA_REQUIRE(pos < m_size);
......@@ -242,30 +278,31 @@ class fixed_vector
}
/**
* @brief Inserts elements to specified position in the container.
* @warning This member function is implemented for <tt>pos == end()</tt>
* only by now. The user has to guarantee that the size of the
* sequence [first, last) fits into the vector.
* @brief Inserts elements before the element pointed to by @p pos.
* @throw std::length_error if
* <tt>size() + distance(first, last) > MaxSize</tt>
*/
template<class InputIterator>
inline void insert(iterator pos,
InputIterator first,
InputIterator last)
{
if (pos == end())
inline void insert(iterator pos, InputIterator first, InputIterator last)
{
if (m_size + static_cast<size_type>(last - first) > MaxSize)
auto num_elements = std::distance(first, last);
if ((size() + num_elements) > MaxSize)
{
throw std::runtime_error("fixed_vector::insert: full");
throw std::length_error("fixed_vector::insert: too much elements");
}
for ( ; first != last; ++first)
if (pos == end())
{
push_back(*first);
}
resize(size() + num_elements);
std::copy(first, last, pos);
}
else
{
throw std::runtime_error("not implemented fixed_vector::insert");
// move elements
auto old_end = end();
resize(size() + num_elements);
std::copy_backward(pos, old_end, end());
// insert new elements
std::copy(first, last, pos);
}
}
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011, 2012 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation, either version 3 of the License *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef HAS_COPY_MEMBER_FUN_HPP
#define HAS_COPY_MEMBER_FUN_HPP
#include <type_traits>
namespace cppa { namespace util {
template<typename T>
class has_copy_member_fun
{
template<typename A>
static bool hc_help_fun(A const* arg0, decltype(arg0->copy()) = 0)
{
return true;
}
template<typename A>
static void hc_help_fun(A const*, void* = 0) { }
typedef decltype(hc_help_fun((T*) 0, (T*) 0)) result_type;
public:
static constexpr bool value = std::is_same<bool, result_type>::value;
};
} } // namespace cppa::util
#endif // HAS_COPY_MEMBER_FUN_HPP
......@@ -36,13 +36,6 @@
namespace cppa { namespace util {
// if (IfStmt == true) type = T; else type = Else::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.
*/
template<bool IfStmt, typename T, class Else>
struct if_else_c
{
......@@ -55,7 +48,13 @@ struct if_else_c<false, T, Else>
typedef typename Else::type type;
};
// if (Stmt::value == true) type = T; else type = Else::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.
*/
template<class Stmt, typename T, class Else>
struct if_else : if_else_c<Stmt::value, T, Else> { };
......
......@@ -36,8 +36,9 @@
namespace cppa { namespace util {
/**
* @ingroup MetaProgramming
* @brief <tt>is_array_of<T,U>::value == true</tt> if and only
* if T is an array of U.
* if @p T is an array of @p U.
*/
template<typename T, typename U>
struct is_array_of
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011, 2012 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation, either version 3 of the License *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef IS_COPYABLE_HPP
#define IS_COPYABLE_HPP
#include <type_traits>
namespace cppa { namespace detail {
template<bool IsAbstract, typename T>
class is_copyable_
{
template<typename A>
static bool cpy_help_fun(A const* arg0, decltype(new A(*arg0)) = nullptr)
{
return true;
}
template<typename A>
static void cpy_help_fun(A const*, void* = nullptr) { }
typedef decltype(cpy_help_fun(static_cast<T*>(nullptr),
static_cast<T*>(nullptr)))
result_type;
public:
static constexpr bool value = std::is_same<bool, result_type>::value;
};
template<typename T>
class is_copyable_<true, T>
{
public:
static constexpr bool value = false;
};
} } // namespace cppa::detail
namespace cppa { namespace util {
template<typename T>
struct is_copyable : std::integral_constant<bool, detail::is_copyable_<std::is_abstract<T>::value, T>::value>
{
};
} } // namespace cppa::util
#endif // IS_COPYABLE_HPP
......@@ -37,6 +37,10 @@
namespace cppa { namespace util {
/**
* @ingroup MetaProgramming
* @brief Checks wheter @p T behaves like a forward iterator.
*/
template<typename T>
class is_forward_iterator
{
......
......@@ -36,6 +36,11 @@
namespace cppa { namespace util {
/**
* @ingroup MetaProgramming
* @brief Checks wheter @p T has <tt>begin()</tt> and <tt>end()</tt> member
* functions returning forward iterators.
*/
template<typename T>
class is_iterable
{
......
......@@ -35,6 +35,10 @@
namespace cppa { namespace util {
/**
* @ingroup MetaProgramming
* @brief Checks wheter @p T is neither a reference nor a pointer nor an array.
*/
template<typename T>
struct is_legal_tuple_type
{
......
......@@ -39,6 +39,10 @@ namespace cppa { namespace util {
// A manipulator is a function that manipulates its arguments via
// mutable references.
/**
* @ingroup MetaProgramming
* @brief Checks wheter functor or function @p F takes mutable references.
*/
template<typename F>
struct is_manipulator
{
......
......@@ -33,6 +33,9 @@
namespace cppa { namespace util {
/**
* @brief Checks wheter @p T is a non-const reference.
*/
template<typename T>
struct is_mutable_ref
{
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011, 2012 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation, either version 3 of the License *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef IS_ONE_OF_HPP
#define IS_ONE_OF_HPP
#include <type_traits>
#include "cppa/util/disjunction.hpp"
namespace cppa { namespace util {
template<typename T, typename... Types>
struct is_one_of;
template<typename T, typename X, typename... Types>
struct is_one_of<T, X, Types...>
: disjunction<std::is_same<T, X>, is_one_of<T, Types...>>
{
};
template<typename T>
struct is_one_of<T> : std::false_type { };
} } // namespace cppa::util
#endif // IS_ONE_OF_HPP
......@@ -36,7 +36,8 @@
namespace cppa { namespace util {
/**
* @brief Evaluates to @c true if @c T is a primitive type.
* @ingroup MetaProgramming
* @brief Chekcs wheter @p T is a primitive type.
*
* <code>is_primitive<T>::value == true</code> if and only if @c T
* is a signed / unsigned integer or one of the following types:
......
......@@ -9,7 +9,11 @@
namespace cppa { namespace util {
// T is any type
/**
* @brief A producer-consumer list.
*
* For implementation details see http://drdobbs.com/cpp/211601363.
*/
template<typename T>
class producer_consumer_list
{
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011, 2012 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation, either version 3 of the License *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef REMOVE_CONST_REFERENCE_HPP
#define REMOVE_CONST_REFERENCE_HPP
namespace cppa { namespace util {
template<typename T>
struct remove_const_reference
{
typedef T type;
};
template<typename T>
struct remove_const_reference<T const&>
{
typedef T type;
};
} } // namespace cppa::util
#endif // REMOVE_CONST_REFERENCE_HPP
......@@ -73,6 +73,9 @@
namespace cppa { namespace util {
/**
* @brief Creates a hash from @p data using the RIPEMD-160 algorithm.
*/
void ripemd_160(std::array<std::uint8_t, 20>& storage, std::string const& data);
} } // namespace cppa::util
......
......@@ -33,6 +33,9 @@
namespace cppa { namespace util {
/**
* @brief Similar to <tt>std::lock_guard</tt> but performs shared locking.
*/
template<typename SharedLockable>
class shared_lock_guard
{
......
......@@ -36,6 +36,9 @@
namespace cppa { namespace util {
/**
* @brief A spinlock implementation providing shared and exclusive locking.
*/
class shared_spinlock
{
......
......@@ -33,6 +33,10 @@
namespace cppa { namespace util {
/**
* @ingroup MetaProgramming
* @brief A for loop that can be used with tuples.
*/
template<size_t Begin, size_t End>
struct static_foreach
{
......
......@@ -34,7 +34,7 @@
namespace cppa { namespace util {
/**
* @ingroup TypeList
* @ingroup MetaProgramming
* @brief Predefines the first template parameter of @p Tp1.
*/
template<template<typename, typename> class Tpl, typename Arg1>
......
......@@ -48,11 +48,11 @@ uniform_type_info const* uniform_typeid(std::type_info const&);
namespace cppa { namespace util {
/**
* @defgroup TypeList Type list meta-programming utility.
* @defgroup MetaProgramming Metaprogramming utility.
*/
/**
* @addtogroup TypeList
* @addtogroup MetaProgramming
* @{
*/
......
......@@ -34,7 +34,7 @@
namespace cppa { namespace util {
/**
* @ingroup TypeList
* @ingroup MetaProgramming
* @brief A pair of two types.
*/
template<typename First, typename Second>
......
......@@ -33,6 +33,10 @@
namespace cppa { namespace util {
/**
* @ingroup MetaProgramming
* @brief A type wrapper as used in {@link cppa::util::if_else if_else}.
*/
template<typename T>
struct wrapped
{
......
......@@ -10,6 +10,7 @@ noinst_PROGRAMS = announce_example_1 \
announce_example_5 \
hello_world_example \
math_actor_example \
dancing_kirby \
dining_philosophers
announce_example_1_SOURCES = announce_example_1.cpp
......@@ -19,6 +20,7 @@ announce_example_4_SOURCES = announce_example_4.cpp
announce_example_5_SOURCES = announce_example_5.cpp
hello_world_example_SOURCES = hello_world_example.cpp
math_actor_example_SOURCES = math_actor_example.cpp
dancing_kirby_SOURCES = dancing_kirby.cpp
dining_philosophers_SOURCES = dining_philosophers.cpp
EXAMPLES_LIBS = -L../.libs/ -lcppa $(BOOST_LDFLAGS) $(BOOST_THREAD_LIB)
......@@ -30,5 +32,6 @@ announce_example_4_LDADD = $(EXAMPLES_LIBS)
announce_example_5_LDADD = $(EXAMPLES_LIBS)
hello_world_example_LDADD = $(EXAMPLES_LIBS)
math_actor_example_LDADD = $(EXAMPLES_LIBS)
dancing_kirby_LDADD = $(EXAMPLES_LIBS)
dining_philosophers_LDADD = $(EXAMPLES_LIBS)
#include <iostream>
#include "cppa/cppa.hpp"
using std::cout;
using std::endl;
using namespace cppa;
// ASCII art figures
constexpr const char* figures[] =
{
"<(^.^<)",
"<(^.^)>",
"(>^.^)>"
};
// array of {figure, offset} pairs
constexpr size_t animation_steps[][2] =
{
{1, 7}, {0, 7}, {0, 6}, {0, 5}, {1, 5}, {2, 5}, {2, 6},
{2, 7}, {2, 8}, {2, 9}, {2, 10}, {1, 10}, {0, 10}, {0, 9},
{1, 9}, {2, 10}, {2, 11}, {2, 12}, {2, 13}, {1, 13}, {0, 13},
{0, 12}, {0, 11}, {0, 10}, {0, 9}, {0, 8}, {0, 7}, {1, 7}
};
constexpr size_t animation_width = 20;
// "draws" an animation step: {offset_whitespaces}{figure}{padding}
void draw_kirby(size_t const (&animation)[2])
{
cout.width(animation_width);
cout << '\r';
std::fill_n(std::ostream_iterator<char>{cout}, animation[1], ' ');
cout << figures[animation[0]];
cout.fill(' ');
cout.flush();
}
void dancing_kirby()
{
// let's get it started
send(self, atom("Step"));
// iterate over animation_steps
auto i = std::begin(animation_steps);
receive_for(i, std::end(animation_steps))
(
on<atom("Step")>() >> [&]()
{
draw_kirby(*i);
// animate next step in 150ms
future_send(self, std::chrono::milliseconds(150), atom("Step"));
}
);
}
int main()
{
cout << endl;
dancing_kirby();
cout << endl;
}
......@@ -15,11 +15,12 @@ using namespace cppa;
struct chopstick : fsm_actor<chopstick>
{
behavior& init_state;
behavior& init_state; // a reference to available
behavior available;
behavior taken_by(actor_ptr const& philos)
{
// create a behavior new on-the-fly
return
(
on<atom("take"), actor_ptr>() >> [=](actor_ptr other)
......
#include <string>
#include <cassert>
#include <iostream>
#include "cppa/cppa.hpp"
......@@ -6,12 +7,16 @@ using std::cout;
using std::endl;
using namespace cppa;
void math_actor()
void math_fun()
{
// receive messages in an endless loop
receive_loop
bool done = false;
// receive messages until we receive {quit}
do_receive
(
// "arg_match" matches the parameter types of given lambda expression
// thus, it's equal to
// - on<atom("plus"), int, int>()
// - on(atom("plus"), val<int>, val<int>)
on(atom("plus"), arg_match) >> [](int a, int b)
{
reply(atom("result"), a + b);
......@@ -19,35 +24,73 @@ void math_actor()
on(atom("minus"), arg_match) >> [](int a, int b)
{
reply(atom("result"), a - b);
},
on(atom("quit")) >> [&]()
{
// note: quit(exit_reason::normal) would terminate the actor
// but is best avoided since it forces stack unwinding
// by throwing an exception
done = true;
}
);
)
.until([&]() { return done; });
}
int main()
struct math_actor : event_based_actor
{
// create a new actor that invokes the function echo_actor
auto ma = spawn(math_actor);
send(ma, atom("plus"), 1, 2);
receive
(
// on<> matches types only, but allows up to four leading atoms
on<atom("result"), int>() >> [](int result)
void init()
{
cout << "1 + 2 = " << result << endl;
}
);
send(ma, atom("minus"), 1, 2);
receive
// execute this behavior until actor terminates
become
(
// on() matches values; use val<T> to match any value of type T
on(atom("result"), val<int>) >> [](int result)
on(atom("plus"), arg_match) >> [](int a, int b)
{
reply(atom("result"), a + b);
},
on(atom("minus"), arg_match) >> [](int a, int b)
{
reply(atom("result"), a - b);
},
// the [=] capture copies the 'this' pointer into the lambda
// thus, it has access to all members and member functions
on(atom("quit")) >> [=]()
{
cout << "1 - 2 = " << result << endl;
// set an empty behavior
// (terminates actor with normal exit reason)
become_void();
}
);
// force ma to exit
send(ma, atom(":Exit"), exit_reason::user_defined);
// wait until ma exited
}
};
// utility function
int fetch_result(actor_ptr& calculator, atom_value operation, int a, int b)
{
// send request
send(calculator, operation, a, b);
// wait for result
int result;
receive(on<atom("result"), int>() >> [&](int r) { result = r; });
// print and return result
cout << a << " " << to_string(operation) << " " << b << " = " << result << endl;
return result;
}
int main()
{
// spawn a context-switching actor that invokes math_fun
auto a1 = spawn(math_fun);
// spawn an event-based math actor
auto a2 = spawn(new math_actor);
// do some testing on both implementations
assert((fetch_result(a1, atom("plus"), 1, 2) == 3));
assert((fetch_result(a2, atom("plus"), 1, 2) == 3));
assert((fetch_result(a1, atom("minus"), 2, 1) == 1));
assert((fetch_result(a2, atom("minus"), 2, 1) == 1));
// tell both actors to terminate
send(a1, atom("quit"));
send(a2, atom("quit"));
// wait until all spawned actors are terminated
await_all_others_done();
// done
return 0;
......
......@@ -34,9 +34,22 @@ namespace cppa {
void event_based_actor::become_void()
{
cleanup(exit_reason::normal);
m_loop_stack.clear();
}
void event_based_actor::quit(std::uint32_t reason)
{
if (reason == exit_reason::normal)
{
become_void();
}
else
{
abstract_scheduled_actor::quit(reason);
}
}
void event_based_actor::do_become(behavior* bhvr, bool has_ownership)
{
reset_timeout();
......
......@@ -23,12 +23,12 @@ size_t test__fixed_vector()
fixed_vector<int, 2> vec5 {3, 4};
vec4.insert(vec4.end(), vec5.begin(), vec5.end());
auto vec6 = vec4;
CPPA_CHECK_EQUAL(vec1.size(), static_cast<size_t>(4));
CPPA_CHECK_EQUAL(vec2.size(), static_cast<size_t>(4));
CPPA_CHECK_EQUAL(vec3.size(), static_cast<size_t>(4));
CPPA_CHECK_EQUAL(vec4.size(), static_cast<size_t>(4));
CPPA_CHECK_EQUAL(vec5.size(), static_cast<size_t>(2));
CPPA_CHECK_EQUAL(vec6.size(), static_cast<size_t>(4));
CPPA_CHECK_EQUAL(vec1.size(), 4);
CPPA_CHECK_EQUAL(vec2.size(), 4);
CPPA_CHECK_EQUAL(vec3.size(), 4);
CPPA_CHECK_EQUAL(vec4.size(), 4);
CPPA_CHECK_EQUAL(vec5.size(), 2);
CPPA_CHECK_EQUAL(vec6.size(), 4);
CPPA_CHECK_EQUAL(vec1.full(), true);
CPPA_CHECK_EQUAL(vec2.full(), false);
CPPA_CHECK_EQUAL(vec3.full(), true);
......@@ -40,5 +40,23 @@ size_t test__fixed_vector()
CPPA_CHECK(std::equal(vec4.begin(), vec4.end(), arr1));
CPPA_CHECK(std::equal(vec6.begin(), vec6.end(), arr1));
CPPA_CHECK(std::equal(vec6.begin(), vec6.end(), vec2.rbegin()));
fixed_vector<int, 10> vec7 {5, 9};
fixed_vector<int, 10> vec8 {1, 2, 3, 4};
fixed_vector<int, 10> vec9 {6, 7, 8};
vec7.insert(vec7.begin() + 1, vec9.begin(), vec9.end());
vec7.insert(vec7.begin(), vec8.begin(), vec8.end());
CPPA_CHECK_EQUAL(vec7.full(), false);
fixed_vector<int, 1> vec10 {10};
vec7.insert(vec7.end(), vec10.begin(), vec10.end());
CPPA_CHECK_EQUAL(vec7.full(), true);
CPPA_CHECK((std::is_sorted(vec7.begin(), vec7.end())));
int arr2[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
CPPA_CHECK((std::equal(vec7.begin(), vec7.end(), std::begin(arr2))));
vec7.assign(std::begin(arr2), std::end(arr2));
CPPA_CHECK((std::equal(vec7.begin(), vec7.end(), std::begin(arr2))));
vec7.assign(5, 0);
CPPA_CHECK_EQUAL(vec7.size(), 5);
CPPA_CHECK((std::all_of(vec7.begin(), vec7.end(),
[](int i) { return i == 0; })));
return CPPA_TEST_RESULT;
}
......@@ -17,7 +17,6 @@
#include "cppa/util/enable_if.hpp"
#include "cppa/util/disable_if.hpp"
#include "cppa/util/apply_tuple.hpp"
#include "cppa/util/conjunction.hpp"
#include "cppa/util/is_primitive.hpp"
#include "cppa/util/is_mutable_ref.hpp"
......
......@@ -287,7 +287,7 @@ void testee3(actor_ptr parent)
{
if (polls < 5)
{
//delayed_reply(std::chrono::milliseconds(50), atom("Poll"));
delayed_reply(std::chrono::milliseconds(50), atom("Poll"));
}
send(parent, atom("Push"), polls);
}
......
......@@ -20,7 +20,6 @@
#include "cppa/deserializer.hpp"
#include "cppa/uniform_type_info.hpp"
#include "cppa/util/disjunction.hpp"
#include "cppa/util/callable_trait.hpp"
using std::cout;
......
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