Commit 092a6db1 authored by neverlord's avatar neverlord

documentation and maintenance

parent e39d7161
...@@ -190,24 +190,19 @@ nobase_library_include_HEADERS = \ ...@@ -190,24 +190,19 @@ nobase_library_include_HEADERS = \
cppa/util/enable_if.hpp \ cppa/util/enable_if.hpp \
cppa/util/fiber.hpp \ cppa/util/fiber.hpp \
cppa/util/fixed_vector.hpp \ cppa/util/fixed_vector.hpp \
cppa/util/has_copy_member_fun.hpp \
cppa/util/if_else.hpp \ cppa/util/if_else.hpp \
cppa/util/is_array_of.hpp \ cppa/util/is_array_of.hpp \
cppa/util/is_builtin.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_forward_iterator.hpp \
cppa/util/is_iterable.hpp \ cppa/util/is_iterable.hpp \
cppa/util/is_iterable.hpp \ cppa/util/is_iterable.hpp \
cppa/util/is_legal_tuple_type.hpp \ cppa/util/is_legal_tuple_type.hpp \
cppa/util/is_manipulator.hpp \ cppa/util/is_manipulator.hpp \
cppa/util/is_mutable_ref.hpp \ cppa/util/is_mutable_ref.hpp \
cppa/util/is_one_of.hpp \
cppa/util/is_primitive.hpp \ cppa/util/is_primitive.hpp \
cppa/util/producer_consumer_list.hpp \ cppa/util/producer_consumer_list.hpp \
cppa/util/pt_dispatch.hpp \ cppa/util/pt_dispatch.hpp \
cppa/util/pt_token.hpp \ cppa/util/pt_token.hpp \
cppa/util/remove_const_reference.hpp \
cppa/util/replace_type.hpp \ cppa/util/replace_type.hpp \
cppa/util/ripemd_160.hpp \ cppa/util/ripemd_160.hpp \
cppa/util/rm_ref.hpp \ cppa/util/rm_ref.hpp \
......
...@@ -3,7 +3,6 @@ cppa/tuple.hpp ...@@ -3,7 +3,6 @@ cppa/tuple.hpp
unit_testing/main.cpp unit_testing/main.cpp
cppa/util/void_type.hpp cppa/util/void_type.hpp
cppa/util/type_list.hpp cppa/util/type_list.hpp
cppa/util/is_one_of.hpp
cppa/util/conjunction.hpp cppa/util/conjunction.hpp
cppa/util/disjunction.hpp cppa/util/disjunction.hpp
unit_testing/test.hpp unit_testing/test.hpp
...@@ -22,15 +21,11 @@ unit_testing/test__spawn.cpp ...@@ -22,15 +21,11 @@ unit_testing/test__spawn.cpp
src/mock_scheduler.cpp src/mock_scheduler.cpp
cppa/actor.hpp cppa/actor.hpp
unit_testing/test__intrusive_ptr.cpp unit_testing/test__intrusive_ptr.cpp
cppa/util/is_comparable.hpp
cppa/util/callable_trait.hpp cppa/util/callable_trait.hpp
unit_testing/test__type_list.cpp unit_testing/test__type_list.cpp
cppa/util/remove_const_reference.hpp
cppa/util/compare_tuples.hpp cppa/util/compare_tuples.hpp
cppa/get.hpp cppa/get.hpp
cppa/detail/tdata.hpp cppa/detail/tdata.hpp
cppa/util/is_copyable.hpp
cppa/util/has_copy_member_fun.hpp
cppa/detail/intermediate.hpp cppa/detail/intermediate.hpp
cppa/detail/invokable.hpp cppa/detail/invokable.hpp
cppa/on.hpp cppa/on.hpp
...@@ -260,3 +255,4 @@ src/partial_function.cpp ...@@ -260,3 +255,4 @@ src/partial_function.cpp
cppa/intrusive/singly_linked_list.hpp cppa/intrusive/singly_linked_list.hpp
cppa/intrusive/iterator.hpp cppa/intrusive/iterator.hpp
unit_testing/test__intrusive_containers.cpp unit_testing/test__intrusive_containers.cpp
examples/dancing_kirby.cpp
...@@ -48,7 +48,11 @@ ...@@ -48,7 +48,11 @@
namespace cppa { 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> template<class Base>
class abstract_actor : public Base class abstract_actor : public Base
{ {
......
...@@ -95,6 +95,10 @@ class abstract_event_based_actor : public detail::abstract_scheduled_actor ...@@ -95,6 +95,10 @@ class abstract_event_based_actor : public detail::abstract_scheduled_actor
// provoke compiler errors for usage of receive() and related functions // 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> template<typename... Args>
void receive(Args&&...) void receive(Args&&...)
{ {
...@@ -103,18 +107,27 @@ class abstract_event_based_actor : public detail::abstract_scheduled_actor ...@@ -103,18 +107,27 @@ class abstract_event_based_actor : public detail::abstract_scheduled_actor
"Use become() instead."); "Use become() instead.");
} }
/**
* @brief Provokes a compiler error.
*/
template<typename... Args> template<typename... Args>
void receive_loop(Args&&... args) void receive_loop(Args&&... args)
{ {
receive(std::forward<Args>(args)...); receive(std::forward<Args>(args)...);
} }
/**
* @brief Provokes a compiler error.
*/
template<typename... Args> template<typename... Args>
void receive_while(Args&&... args) void receive_while(Args&&... args)
{ {
receive(std::forward<Args>(args)...); receive(std::forward<Args>(args)...);
} }
/**
* @brief Provokes a compiler error.
*/
template<typename... Args> template<typename... Args>
void do_receive(Args&&... args) void do_receive(Args&&... args)
{ {
......
...@@ -35,6 +35,10 @@ ...@@ -35,6 +35,10 @@
namespace cppa { namespace cppa {
/**
* @brief Implements the deserializer interface with
* a binary serialization protocol.
*/
class binary_deserializer : public deserializer class binary_deserializer : public deserializer
{ {
......
...@@ -38,6 +38,10 @@ namespace cppa { ...@@ -38,6 +38,10 @@ namespace cppa {
namespace detail { class binary_writer; } namespace detail { class binary_writer; }
/**
* @brief Implements the serializer interface with
* a binary serialization protocol.
*/
class binary_serializer : public serializer class binary_serializer : public serializer
{ {
......
...@@ -41,6 +41,9 @@ namespace cppa { ...@@ -41,6 +41,9 @@ namespace cppa {
/** /**
* @ingroup CopyOnWrite * @ingroup CopyOnWrite
* @brief A copy-on-write smart pointer implementation. * @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> template<typename T>
class cow_ptr class cow_ptr
......
...@@ -125,7 +125,7 @@ ...@@ -125,7 +125,7 @@
* implement Actor based applications. * implement Actor based applications.
* *
* @namespace cppa::util * @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. * utilities used by the libcppa implementation.
* *
* @namespace cppa::intrusive * @namespace cppa::intrusive
...@@ -283,24 +283,24 @@ ...@@ -283,24 +283,24 @@
* *
* @section ReceiveLoops Receive loops * @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 * 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 * in a variable and pass that variable to receive. This fixes the issue
* of re-creation each iteration but rips apart definition and usage. * of re-creation each iteration but rips apart definition and usage.
* *
* There are three convenience function implementing receive loops to * There are four convenience functions implementing receive loops to
* declare patterns and behavior where they belong without unnecessary * declare behavior where it belongs without unnecessary
* copies: @p receive_loop, @p receive_while and @p do_receive. * 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 * @p receive_loop is analogous to @p receive and loops "forever" (until the
* actor finishes execution). * actor finishes execution).
* *
* @p receive_while creates a functor evaluating a lambda expression. * @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 * @code
* // receive two ints * // 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; })
* ( * (
...@@ -312,6 +312,17 @@ ...@@ -312,6 +312,17 @@
* // ... * // ...
* @endcode * @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 * @p do_receive returns a functor providing the function @p until that
* takes a lambda expression. The loop continues until the given lambda * takes a lambda expression. The loop continues until the given lambda
* returns true. Example: * returns true. Example:
...@@ -350,6 +361,8 @@ ...@@ -350,6 +361,8 @@
* ); * );
* @endcode * @endcode
* *
* See also the {@link dancing_kirby.cpp dancing kirby example}.
*
* @defgroup ImplicitConversion Implicit type conversions. * @defgroup ImplicitConversion Implicit type conversions.
* *
* The message passing of @p libcppa prohibits pointers in messages because * The message passing of @p libcppa prohibits pointers in messages because
...@@ -380,14 +393,39 @@ ...@@ -380,14 +393,39 @@
* on("hello actor!") >> []() { } * on("hello actor!") >> []() { }
* ); * );
* @endcode * @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 { namespace cppa {
/** /**
* @ingroup ActorManagement
* @brief Links @p lhs and @p rhs; * @brief Links @p lhs and @p rhs;
* @param lhs Left-hand operand.
* @param rhs Right-hand operand.
* @pre <tt>lhs != rhs</tt> * @pre <tt>lhs != rhs</tt>
*/ */
void link(actor_ptr& lhs, actor_ptr& rhs); void link(actor_ptr& lhs, actor_ptr& rhs);
...@@ -408,54 +446,68 @@ 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); void link(actor_ptr& lhs, actor_ptr&& rhs);
/** /**
* @ingroup ActorManagement
* @brief Unlinks @p lhs from @p rhs; * @brief Unlinks @p lhs from @p rhs;
* @param lhs Left-hand operand.
* @param rhs Right-hand operand.
* @pre <tt>lhs != rhs</tt> * @pre <tt>lhs != rhs</tt>
*/ */
void unlink(actor_ptr& lhs, actor_ptr& rhs); void unlink(actor_ptr& lhs, actor_ptr& rhs);
/** /**
* @brief Adds a monitor to @p whom. * @ingroup ActorManagement
* * @brief Adds a unidirectional @p monitor to @p whom.
* Sends a ":Down" message to the calling Actor if @p whom exited. * @note Each calls to @p monitor creates a new, independent monitor.
* @param whom Actor instance that should be monitored by the calling Actor. * @pre The calling actor receives a ":Down" message from @p whom when
* it terminates.
*/ */
void monitor(actor_ptr& whom); void monitor(actor_ptr& whom);
/**
* @copydoc monitor(actor_ptr&)
*/
void monitor(actor_ptr&& whom); void monitor(actor_ptr&& whom);
/** /**
* @ingroup ActorManagement
* @brief Removes a monitor from @p whom. * @brief Removes a monitor from @p whom.
* @param whom Monitored Actor.
*/ */
void demonitor(actor_ptr& whom); 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) inline actor_ptr spawn(scheduled_actor* what)
{ {
return get_scheduler()->spawn(what, scheduled); 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> template<scheduling_hint Hint>
inline actor_ptr spawn(scheduled_actor* what) inline actor_ptr spawn(scheduled_actor* what)
{ {
return get_scheduler()->spawn(what, Hint); 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) inline actor_ptr spawn(abstract_event_based_actor* what)
{ {
return get_scheduler()->spawn(what); return get_scheduler()->spawn(what);
} }
/** /**
* @ingroup ActorManagement
* @brief Spawns a new actor that executes @p what with given arguments. * @brief Spawns a new actor that executes @p what with given arguments.
* @tparam Hint Hint to the scheduler for the best scheduling strategy. * @tparam Hint Hint to the scheduler for the best scheduling strategy.
* @param what Function or functor that the spawned Actor should execute. * @param what Function or functor that the spawned Actor should execute.
* @param args Arguments needed to invoke @p what. * @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> template<scheduling_hint Hint, typename F, typename... Args>
auto //actor_ptr auto //actor_ptr
...@@ -471,10 +523,8 @@ spawn(F&& what, Args const&... args) ...@@ -471,10 +523,8 @@ spawn(F&& what, Args const&... args)
} }
/** /**
* @ingroup ActorManagement
* @brief Alias for <tt>spawn<scheduled>(what, args...)</tt>. * @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> template<typename F, typename... Args>
auto // actor_ptr auto // actor_ptr
...@@ -489,27 +539,20 @@ spawn(F&& what, Args const&... args) ...@@ -489,27 +539,20 @@ spawn(F&& what, Args const&... args)
#ifdef CPPA_DOCUMENTATION #ifdef CPPA_DOCUMENTATION
/** /**
* @brief Sends a message to @p whom. * @ingroup MessageHandling
* * @brief Sends <tt>{arg0, args...}</tt> as 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.
*/ */
template<typename Arg0, typename... Args> template<typename Arg0, typename... Args>
void send(channel_ptr& whom, Arg0 const& arg0, Args const&... args); void send(channel_ptr& whom, Arg0 const& arg0, Args const&... args);
/** /**
* @ingroup MessageHandling
* @brief Send a message to @p whom. * @brief Send a message to @p whom.
* *
* <b>Usage example:</b> * <b>Usage example:</b>
* @code * @code
* self << make_tuple(1, 2, 3); * self << make_tuple(1, 2, 3);
* @endcode * @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. * @returns @p whom.
*/ */
channel_ptr& operator<<(channel_ptr& whom, any_tuple const& what); 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); ...@@ -586,6 +629,10 @@ self_type const& operator<<(self_type const& s, any_tuple&& what);
#endif // CPPA_DOCUMENTATION #endif // CPPA_DOCUMENTATION
/**
* @ingroup MessageHandling
* @brief Sends a message to the sender of the last received message.
*/
template<typename Arg0, typename... Args> template<typename Arg0, typename... Args>
void reply(Arg0 const& arg0, Args const&... args) void reply(Arg0 const& arg0, Args const&... args)
{ {
...@@ -593,6 +640,7 @@ 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. * @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.
...@@ -604,6 +652,17 @@ void future_send(actor_ptr whom, Duration const& rel_time, Data const&... data) ...@@ -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...); 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 * @brief Blocks execution of this actor until all
* other actors finished execution. * other actors finished execution.
......
...@@ -35,8 +35,6 @@ ...@@ -35,8 +35,6 @@
#include "cppa/util/rm_ref.hpp" #include "cppa/util/rm_ref.hpp"
#include "cppa/util/void_type.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_iterable.hpp"
#include "cppa/util/is_primitive.hpp" #include "cppa/util/is_primitive.hpp"
#include "cppa/util/is_forward_iterator.hpp" #include "cppa/util/is_forward_iterator.hpp"
......
...@@ -62,7 +62,7 @@ struct ptype_to_type : ...@@ -62,7 +62,7 @@ struct ptype_to_type :
util::if_else_c<PT == pt_u16string, std::u16string, util::if_else_c<PT == pt_u16string, std::u16string,
util::if_else_c<PT == pt_u32string, std::u32string, util::if_else_c<PT == pt_u32string, std::u32string,
// default case // default case
util::wrapped<void> > > > > > > > > > > > > > > void > > > > > > > > > > > > > >
{ {
}; };
......
...@@ -81,6 +81,44 @@ struct receive_while_helper ...@@ -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 class do_receive_helper
{ {
......
...@@ -57,12 +57,12 @@ class either ...@@ -57,12 +57,12 @@ class either
/** /**
* @brief Default constructor, creates a @p Left. * @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. * @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. * @brief Creates a @p Left from @p value.
...@@ -72,25 +72,19 @@ class either ...@@ -72,25 +72,19 @@ class either
/** /**
* @brief Creates a @p Right from @p value. * @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. * @brief Creates a @p Right from @p value.
*/ */
either(Right&& value) : m_is_left(false) { cr_right(std::move(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) either(either const& other) : m_is_left(other.m_is_left)
{ {
if (other.m_is_left) cr_left(other.m_left); if (other.m_is_left) cr_left(other.m_left);
else cr_right(other.m_right); else cr_right(other.m_right);
} }
/**
* @brief Move constructor.
*/
either(either&& other) : m_is_left(other.m_is_left) either(either&& other) : m_is_left(other.m_is_left)
{ {
if (other.m_is_left) cr_left(std::move(other.m_left)); if (other.m_is_left) cr_left(std::move(other.m_left));
...@@ -99,9 +93,6 @@ class either ...@@ -99,9 +93,6 @@ class either
~either() { destroy(); } ~either() { destroy(); }
/**
* @brief Copy assignment.
*/
either& operator=(either const& other) either& operator=(either const& other)
{ {
if (m_is_left == other.m_is_left) if (m_is_left == other.m_is_left)
...@@ -119,9 +110,6 @@ class either ...@@ -119,9 +110,6 @@ class either
return *this; return *this;
} }
/**
* @brief Move assignment.
*/
either& operator=(either&& other) either& operator=(either&& other)
{ {
if (m_is_left == other.m_is_left) if (m_is_left == other.m_is_left)
...@@ -161,7 +149,7 @@ class either ...@@ -161,7 +149,7 @@ class either
/** /**
* @brief Returns this @p either as a @p Left. * @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); CPPA_REQUIRE(m_is_left);
return m_left; return m_left;
...@@ -179,7 +167,7 @@ class either ...@@ -179,7 +167,7 @@ class either
/** /**
* @brief Returns this @p either as a @p Right. * @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); CPPA_REQUIRE(!m_is_left);
return m_right; return m_right;
...@@ -191,8 +179,8 @@ class either ...@@ -191,8 +179,8 @@ class either
union union
{ {
Left m_left; left_type m_left;
Right m_right; right_type m_right;
}; };
void destroy() void destroy()
...@@ -204,17 +192,18 @@ class either ...@@ -204,17 +192,18 @@ class either
template<typename L> template<typename L>
void cr_left(L&& value) 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> template<typename R>
void cr_right(R&& value) 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> template<typename Left, typename Right>
bool operator==(either<Left, Right> const& lhs, either<Left, Right> const& rhs) 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) ...@@ -226,54 +215,63 @@ bool operator==(either<Left, Right> const& lhs, either<Left, Right> const& rhs)
return false; return false;
} }
/** @relates either */
template<typename Left, typename Right> template<typename Left, typename Right>
bool operator==(either<Left, Right> const& lhs, Left const& rhs) bool operator==(either<Left, Right> const& lhs, Left const& rhs)
{ {
return lhs.is_left() && lhs.left() == rhs; return lhs.is_left() && lhs.left() == rhs;
} }
/** @relates either */
template<typename Left, typename Right> template<typename Left, typename Right>
bool operator==(Left const& lhs, either<Left, Right> const& rhs) bool operator==(Left const& lhs, either<Left, Right> const& rhs)
{ {
return rhs == lhs; return rhs == lhs;
} }
/** @relates either */
template<typename Left, typename Right> template<typename Left, typename Right>
bool operator==(either<Left, Right> const& lhs, Right const& rhs) bool operator==(either<Left, Right> const& lhs, Right const& rhs)
{ {
return lhs.is_right() && lhs.right() == rhs; return lhs.is_right() && lhs.right() == rhs;
} }
/** @relates either */
template<typename Left, typename Right> template<typename Left, typename Right>
bool operator==(Right const& lhs, either<Left, Right> const& rhs) bool operator==(Right const& lhs, either<Left, Right> const& rhs)
{ {
return rhs == lhs; return rhs == lhs;
} }
/** @relates either */
template<typename Left, typename Right> template<typename Left, typename Right>
bool operator!=(either<Left, Right> const& lhs, either<Left, Right> const& rhs) bool operator!=(either<Left, Right> const& lhs, either<Left, Right> const& rhs)
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
/** @relates either */
template<typename Left, typename Right> template<typename Left, typename Right>
bool operator!=(either<Left, Right> const& lhs, Left const& rhs) bool operator!=(either<Left, Right> const& lhs, Left const& rhs)
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
/** @relates either */
template<typename Left, typename Right> template<typename Left, typename Right>
bool operator!=(Left const& lhs, either<Left, Right> const& rhs) bool operator!=(Left const& lhs, either<Left, Right> const& rhs)
{ {
return !(rhs == lhs); return !(rhs == lhs);
} }
/** @relates either */
template<typename Left, typename Right> template<typename Left, typename Right>
bool operator!=(either<Left, Right> const& lhs, Right const& rhs) bool operator!=(either<Left, Right> const& lhs, Right const& rhs)
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
/** @relates either */
template<typename Left, typename Right> template<typename Left, typename Right>
bool operator!=(Right const& lhs, either<Left, Right> const& rhs) bool operator!=(Right const& lhs, either<Left, Right> const& rhs)
{ {
......
...@@ -36,6 +36,9 @@ ...@@ -36,6 +36,9 @@
namespace cppa { namespace cppa {
/**
* @brief Base class for non-stacked event-based actor implementations.
*/
class event_based_actor : public event_based_actor_base<event_based_actor> 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> ...@@ -48,8 +51,13 @@ class event_based_actor : public event_based_actor_base<event_based_actor>
public: public:
/**
* @brief Terminates this actor with normal exit reason.
*/
void become_void(); void become_void();
void quit(std::uint32_t reason);
}; };
} // namespace cppa } // namespace cppa
......
...@@ -36,6 +36,9 @@ ...@@ -36,6 +36,9 @@
namespace cppa { namespace cppa {
/**
* @brief Base class for event-based actor implementations.
*/
template<typename Derived> template<typename Derived>
class event_based_actor_base : public abstract_event_based_actor class event_based_actor_base : public abstract_event_based_actor
{ {
...@@ -46,11 +49,19 @@ 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: 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) inline void become(behavior* bhvr)
{ {
d_this()->do_become(bhvr, false); d_this()->do_become(bhvr, false);
} }
/** @brief Sets the actor's behavior. */
template<typename... Args> template<typename... Args>
void become(partial_function&& arg0, Args&&... args) void become(partial_function&& arg0, Args&&... args)
{ {
...@@ -59,9 +70,10 @@ class event_based_actor_base : public abstract_event_based_actor ...@@ -59,9 +70,10 @@ class event_based_actor_base : public abstract_event_based_actor
d_this()->do_become(ptr, true); 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 @@ ...@@ -33,6 +33,11 @@
#include <cstdint> #include <cstdint>
/**
* @namespace cppa::exit_reason
* @brief This naemspace contains all predefined exit reasons.
*/
namespace cppa { namespace exit_reason { namespace cppa { namespace exit_reason {
/** /**
......
...@@ -40,7 +40,10 @@ ...@@ -40,7 +40,10 @@
namespace cppa { 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> template<class Derived>
class fsm_actor : public event_based_actor class fsm_actor : public event_based_actor
...@@ -48,6 +51,10 @@ class fsm_actor : public event_based_actor ...@@ -48,6 +51,10 @@ class fsm_actor : public event_based_actor
public: public:
/**
* @brief Overrides abstract_event_based_actor::init() and sets
* the initial actor behavior to <tt>Derived::init_state</tt>.
*/
void init() void init()
{ {
become(&(static_cast<Derived*>(this)->init_state)); become(&(static_cast<Derived*>(this)->init_state));
......
...@@ -96,60 +96,90 @@ class iterator // : std::iterator<forward_iterator_tag, T> ...@@ -96,60 +96,90 @@ class iterator // : std::iterator<forward_iterator_tag, T>
}; };
/**
* @relates iterator
*/
template<class T> template<class T>
inline bool operator==(iterator<T> const& lhs, iterator<T> const& rhs) inline bool operator==(iterator<T> const& lhs, iterator<T> const& rhs)
{ {
return lhs.ptr() == rhs.ptr(); return lhs.ptr() == rhs.ptr();
} }
/**
* @relates iterator
*/
template<class T> template<class T>
inline bool operator==(iterator<T> const& lhs, T const* rhs) inline bool operator==(iterator<T> const& lhs, T const* rhs)
{ {
return lhs.ptr() == rhs; return lhs.ptr() == rhs;
} }
/**
* @relates iterator
*/
template<class T> template<class T>
inline bool operator==(T const* lhs, iterator<T> const& rhs) inline bool operator==(T const* lhs, iterator<T> const& rhs)
{ {
return lhs == rhs.ptr(); return lhs == rhs.ptr();
} }
/**
* @relates iterator
*/
template<class T> template<class T>
inline bool operator==(iterator<T> const& lhs, decltype(nullptr)) inline bool operator==(iterator<T> const& lhs, decltype(nullptr))
{ {
return lhs.ptr() == nullptr; return lhs.ptr() == nullptr;
} }
/**
* @relates iterator
*/
template<class T> template<class T>
inline bool operator==(decltype(nullptr), iterator<T> const& rhs) inline bool operator==(decltype(nullptr), iterator<T> const& rhs)
{ {
return rhs.ptr() == nullptr; return rhs.ptr() == nullptr;
} }
/**
* @relates iterator
*/
template<class T> template<class T>
inline bool operator!=(iterator<T> const& lhs, iterator<T> const& rhs) inline bool operator!=(iterator<T> const& lhs, iterator<T> const& rhs)
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
/**
* @relates iterator
*/
template<class T> template<class T>
inline bool operator!=(iterator<T> const& lhs, T const* rhs) inline bool operator!=(iterator<T> const& lhs, T const* rhs)
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
/**
* @relates iterator
*/
template<class T> template<class T>
inline bool operator!=(T const* lhs, iterator<T> const& rhs) inline bool operator!=(T const* lhs, iterator<T> const& rhs)
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
/**
* @relates iterator
*/
template<class T> template<class T>
inline bool operator!=(iterator<T> const& lhs, decltype(nullptr)) inline bool operator!=(iterator<T> const& lhs, decltype(nullptr))
{ {
return !(lhs == nullptr); return !(lhs == nullptr);
} }
/**
* @relates iterator
*/
template<class T> template<class T>
inline bool operator!=(decltype(nullptr), iterator<T> const& rhs) inline bool operator!=(decltype(nullptr), iterator<T> const& rhs)
{ {
......
...@@ -38,7 +38,6 @@ ...@@ -38,7 +38,6 @@
#include "cppa/exception.hpp" #include "cppa/exception.hpp"
#include "cppa/util/rm_ref.hpp" #include "cppa/util/rm_ref.hpp"
#include "cppa/util/disjunction.hpp"
#include "cppa/detail/implicit_conversions.hpp" #include "cppa/detail/implicit_conversions.hpp"
namespace cppa { namespace cppa {
......
...@@ -69,17 +69,11 @@ class option ...@@ -69,17 +69,11 @@ class option
*/ */
option(T const& value) : m_valid(false) { cr(value); } option(T const& value) : m_valid(false) { cr(value); }
/**
* @brief Copy constructor.
*/
option(option const& other) : m_valid(false) option(option const& other) : m_valid(false)
{ {
if (other.m_valid) cr(other.m_value); if (other.m_valid) cr(other.m_value);
} }
/**
* @brief Move constructor.
*/
option(option&& other) : m_valid(false) option(option&& other) : m_valid(false)
{ {
if (other.m_valid) cr(std::move(other.m_value)); if (other.m_valid) cr(std::move(other.m_value));
...@@ -87,9 +81,6 @@ class option ...@@ -87,9 +81,6 @@ class option
~option() { destroy(); } ~option() { destroy(); }
/**
* @brief Copy assignment.
*/
option& operator=(option const& other) option& operator=(option const& other)
{ {
if (m_valid) if (m_valid)
...@@ -104,9 +95,6 @@ class option ...@@ -104,9 +95,6 @@ class option
return *this; return *this;
} }
/**
* @brief Move assignment.
*/
option& operator=(option&& other) option& operator=(option&& other)
{ {
if (m_valid) if (m_valid)
...@@ -121,9 +109,6 @@ class option ...@@ -121,9 +109,6 @@ class option
return *this; return *this;
} }
/**
* @brief Copy assignment.
*/
option& operator=(T const& value) option& operator=(T const& value)
{ {
if (m_valid) m_value = value; if (m_valid) m_value = value;
...@@ -131,9 +116,6 @@ class option ...@@ -131,9 +116,6 @@ class option
return *this; return *this;
} }
/**
* @brief Move assignment.
*/
option& operator=(T& value) option& operator=(T& value)
{ {
if (m_valid) m_value = std::move(value); if (m_valid) m_value = std::move(value);
...@@ -153,8 +135,7 @@ class option ...@@ -153,8 +135,7 @@ class option
inline explicit operator bool() const { return m_valid; } inline explicit operator bool() const { return m_valid; }
/** /**
* @brief Returns @p false if this @p option has a valid value; * @brief Returns <tt>!valid()</tt>
* otherwise @p true.
*/ */
inline bool operator!() const { return !m_valid; } inline bool operator!() const { return !m_valid; }
...@@ -195,8 +176,9 @@ class option ...@@ -195,8 +176,9 @@ class option
} }
/** /**
* @brief Returns the value of this @p option if it's valid * @brief Returns the value. The value is set to @p default_value
* or @p default_value. * if <tt>valid() == false</tt>.
* @post <tt>valid() == true</tt>
*/ */
inline T& get_or_else(T const& default_value) inline T& get_or_else(T const& default_value)
{ {
...@@ -237,6 +219,7 @@ class option ...@@ -237,6 +219,7 @@ class option
}; };
/** @relates option */
template<typename T> template<typename T>
bool operator==(option<T> const& lhs, option<T> const& rhs) bool operator==(option<T> const& lhs, option<T> const& rhs)
{ {
...@@ -244,6 +227,7 @@ 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; return false;
} }
/** @relates option */
template<typename T> template<typename T>
bool operator==(option<T> const& lhs, T const& rhs) bool operator==(option<T> const& lhs, T const& rhs)
{ {
...@@ -251,24 +235,28 @@ bool operator==(option<T> const& lhs, T const& rhs) ...@@ -251,24 +235,28 @@ bool operator==(option<T> const& lhs, T const& rhs)
return false; return false;
} }
/** @relates option */
template<typename T> template<typename T>
bool operator==(T const& lhs, option<T> const& rhs) bool operator==(T const& lhs, option<T> const& rhs)
{ {
return rhs == lhs; return rhs == lhs;
} }
/** @relates option */
template<typename T> template<typename T>
bool operator!=(option<T> const& lhs, option<T> const& rhs) bool operator!=(option<T> const& lhs, option<T> const& rhs)
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
/** @relates option */
template<typename T> template<typename T>
bool operator!=(option<T> const& lhs, T const& rhs) bool operator!=(option<T> const& lhs, T const& rhs)
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
/** @relates option */
template<typename T> template<typename T>
bool operator!=(T const& lhs, option<T> const& rhs) bool operator!=(T const& lhs, option<T> const& rhs)
{ {
......
...@@ -286,7 +286,7 @@ class primitive_variant ...@@ -286,7 +286,7 @@ class primitive_variant
* @relates primitive_variant * @relates primitive_variant
* @param pv A primitive variant of type @p T. * @param pv A primitive variant of type @p T.
* @returns A const reference to the value of @p pv 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> template<typename T>
T const& get(primitive_variant const& pv) T const& get(primitive_variant const& pv)
...@@ -301,7 +301,7 @@ T const& get(primitive_variant const& pv) ...@@ -301,7 +301,7 @@ T const& get(primitive_variant const& pv)
* @relates primitive_variant * @relates primitive_variant
* @param pv A primitive variant of type @p T. * @param pv A primitive variant of type @p T.
* @returns A reference to the value of @p pv 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> template<typename T>
T& get_ref(primitive_variant& pv) T& get_ref(primitive_variant& pv)
......
...@@ -75,6 +75,26 @@ void receive_loop(behavior& bhvr); ...@@ -75,6 +75,26 @@ void receive_loop(behavior& bhvr);
template<typename Statement> template<typename Statement>
auto receive_while(Statement&& stmt); 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. * @brief Receives messages until @p stmt returns true.
* *
...@@ -131,6 +151,12 @@ void receive_loop(partial_function&& arg0, Args&&... args) ...@@ -131,6 +151,12 @@ void receive_loop(partial_function&& arg0, Args&&... args)
receive_loop(tmp.splice(std::move(arg0), std::forward<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> template<typename Statement>
detail::receive_while_helper<Statement> receive_while(Statement&& stmt) detail::receive_while_helper<Statement> receive_while(Statement&& stmt)
{ {
......
...@@ -35,6 +35,9 @@ ...@@ -35,6 +35,9 @@
namespace cppa { 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> 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 ...@@ -46,7 +49,14 @@ class stacked_event_based_actor : public event_based_actor_base<stacked_event_ba
protected: protected:
/**
* @brief Restores the last behavior.
*/
void unbecome(); void unbecome();
/**
* @brief Terminates this actor with normal exit reason.
*/
void become_void(); void become_void();
}; };
......
...@@ -41,7 +41,6 @@ ...@@ -41,7 +41,6 @@
#include "cppa/object.hpp" #include "cppa/object.hpp"
#include "cppa/util/comparable.hpp" #include "cppa/util/comparable.hpp"
#include "cppa/util/disjunction.hpp"
#include "cppa/util/callable_trait.hpp" #include "cppa/util/callable_trait.hpp"
#include "cppa/detail/demangle.hpp" #include "cppa/detail/demangle.hpp"
......
...@@ -38,109 +38,109 @@ namespace cppa { namespace util { ...@@ -38,109 +38,109 @@ namespace cppa { namespace util {
* *
* @p Subclass must provide a @c compare member function that compares * @p Subclass must provide a @c compare member function that compares
* to instances of @p T and returns an integer @c x with: * 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 class comparable
{ {
friend bool operator==(Subclass const& lhs, T const& rhs) friend bool operator==(Subclass const& lhs, T const& rhs)
{ {
return lhs.compare(rhs) == 0; return lhs.compare(rhs) == 0;
} }
friend bool operator==(T const& lhs, Subclass const& rhs) friend bool operator==(T const& lhs, Subclass const& rhs)
{ {
return rhs.compare(lhs) == 0; return rhs.compare(lhs) == 0;
} }
friend bool operator!=(Subclass const& lhs, T const& rhs) friend bool operator!=(Subclass const& lhs, T const& rhs)
{ {
return lhs.compare(rhs) != 0; return lhs.compare(rhs) != 0;
} }
friend bool operator!=(T const& lhs, Subclass const& rhs) friend bool operator!=(T const& lhs, Subclass const& rhs)
{ {
return rhs.compare(lhs) != 0; return rhs.compare(lhs) != 0;
} }
friend bool operator<(Subclass const& lhs, T const& rhs) friend bool operator<(Subclass const& lhs, T const& rhs)
{ {
return lhs.compare(rhs) < 0; return lhs.compare(rhs) < 0;
} }
friend bool operator>(Subclass const& lhs, T const& rhs) friend bool operator>(Subclass const& lhs, T const& rhs)
{ {
return lhs.compare(rhs) > 0; return lhs.compare(rhs) > 0;
} }
friend bool operator<(T const& lhs, Subclass const& rhs) friend bool operator<(T const& lhs, Subclass const& rhs)
{ {
return rhs > lhs; return rhs > lhs;
} }
friend bool operator>(T const& lhs, Subclass const& rhs) friend bool operator>(T const& lhs, Subclass const& rhs)
{ {
return rhs < lhs; return rhs < lhs;
} }
friend bool operator<=(Subclass const& lhs, T const& rhs) friend bool operator<=(Subclass const& lhs, T const& rhs)
{ {
return lhs.compare(rhs) <= 0; return lhs.compare(rhs) <= 0;
} }
friend bool operator>=(Subclass const& lhs, T const& rhs) friend bool operator>=(Subclass const& lhs, T const& rhs)
{ {
return lhs.compare(rhs) >= 0; return lhs.compare(rhs) >= 0;
} }
friend bool operator<=(T const& lhs, Subclass const& rhs) friend bool operator<=(T const& lhs, Subclass const& rhs)
{ {
return rhs >= lhs; return rhs >= lhs;
} }
friend bool operator>=(T const& lhs, Subclass const& rhs) friend bool operator>=(T const& lhs, Subclass const& rhs)
{ {
return rhs <= lhs; return rhs <= lhs;
} }
}; };
template<typename Subclass> template<class Subclass>
class comparable<Subclass, Subclass> class comparable<Subclass, Subclass>
{ {
friend bool operator==(Subclass const& lhs, Subclass const& rhs) friend bool operator==(Subclass const& lhs, Subclass const& rhs)
{ {
return lhs.compare(rhs) == 0; return lhs.compare(rhs) == 0;
} }
friend bool operator!=(Subclass const& lhs, Subclass const& rhs) friend bool operator!=(Subclass const& lhs, Subclass const& rhs)
{ {
return lhs.compare(rhs) != 0; return lhs.compare(rhs) != 0;
} }
friend bool operator<(Subclass const& lhs, Subclass const& rhs) friend bool operator<(Subclass const& lhs, Subclass const& rhs)
{ {
return lhs.compare(rhs) < 0; return lhs.compare(rhs) < 0;
} }
friend bool operator<=(Subclass const& lhs, Subclass const& rhs) friend bool operator<=(Subclass const& lhs, Subclass const& rhs)
{ {
return lhs.compare(rhs) <= 0; return lhs.compare(rhs) <= 0;
} }
friend bool operator>(Subclass const& lhs, Subclass const& rhs) friend bool operator>(Subclass const& lhs, Subclass const& rhs)
{ {
return lhs.compare(rhs) > 0; return lhs.compare(rhs) > 0;
} }
friend bool operator>=(Subclass const& lhs, Subclass const& rhs) friend bool operator>=(Subclass const& lhs, Subclass const& rhs)
{ {
return lhs.compare(rhs) >= 0; return lhs.compare(rhs) >= 0;
} }
}; };
......
...@@ -42,6 +42,11 @@ struct disable_if_c<false, T> ...@@ -42,6 +42,11 @@ struct disable_if_c<false, T>
typedef T type; typedef T type;
}; };
/**
* @ingroup MetaProgramming
* @brief SFINAE trick to disable a template function based on its
* template parameters.
*/
template<class Trait, typename T = void> template<class Trait, typename T = void>
struct disable_if : disable_if_c<Trait::value, T> struct disable_if : disable_if_c<Trait::value, T>
{ {
......
...@@ -36,6 +36,9 @@ ...@@ -36,6 +36,9 @@
namespace cppa { namespace util { namespace cppa { namespace util {
/**
* @brief SI time units to specify timeouts.
*/
enum class time_unit : std::uint32_t enum class time_unit : std::uint32_t
{ {
none = 0, none = 0,
...@@ -44,6 +47,10 @@ enum class time_unit : std::uint32_t ...@@ -44,6 +47,10 @@ enum class time_unit : std::uint32_t
microseconds = 1000000 microseconds = 1000000
}; };
/**
* @brief Converts an STL time period to a
* {@link cppa::util::time_unit time_unit}.
*/
template<typename Period> template<typename Period>
constexpr time_unit get_time_unit_from_period() constexpr time_unit get_time_unit_from_period()
{ {
...@@ -58,6 +65,10 @@ constexpr time_unit get_time_unit_from_period() ...@@ -58,6 +65,10 @@ constexpr time_unit get_time_unit_from_period()
: time_unit::none)))); : time_unit::none))));
} }
/**
* @brief Time duration consisting of a {@link cppa::util::time_unit time_unit}
* and a 32 bit unsigned integer.
*/
class duration class duration
{ {
...@@ -79,6 +90,9 @@ class duration ...@@ -79,6 +90,9 @@ class duration
"only seconds, milliseconds or microseconds allowed"); "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; } inline bool valid() const { return unit != time_unit::none; }
time_unit unit; time_unit unit;
...@@ -87,8 +101,14 @@ class duration ...@@ -87,8 +101,14 @@ class duration
}; };
/**
* @relates duration
*/
bool operator==(duration const& lhs, duration const& rhs); bool operator==(duration const& lhs, duration const& rhs);
/**
* @relates duration
*/
inline bool operator!=(duration const& lhs, duration const& rhs) inline bool operator!=(duration const& lhs, duration const& rhs)
{ {
return !(lhs == rhs); return !(lhs == rhs);
...@@ -96,6 +116,9 @@ inline bool operator!=(duration const& lhs, duration const& rhs) ...@@ -96,6 +116,9 @@ inline bool operator!=(duration const& lhs, duration const& rhs)
} } // namespace cppa::util } } // namespace cppa::util
/**
* @relates cppa::util::duration
*/
template<class Clock, class Duration> template<class Clock, class Duration>
std::chrono::time_point<Clock, Duration>& std::chrono::time_point<Clock, Duration>&
operator+=(std::chrono::time_point<Clock, Duration>& lhs, operator+=(std::chrono::time_point<Clock, Duration>& lhs,
......
...@@ -38,6 +38,9 @@ namespace cppa { namespace util { ...@@ -38,6 +38,9 @@ namespace cppa { namespace util {
template<size_t N, class C> template<size_t N, class C>
struct element_at; struct element_at;
/**
* @brief Returns the n-th template parameter of @p C.
*/
template<size_t N, template<typename...> class C, typename... Tn> template<size_t N, template<typename...> class C, typename... Tn>
struct element_at<N, C<Tn...>> : at<N, Tn...> struct element_at<N, C<Tn...>> : at<N, Tn...>
{ {
......
...@@ -44,6 +44,11 @@ struct enable_if_c<true, T> ...@@ -44,6 +44,11 @@ struct enable_if_c<true, T>
typedef T type; typedef T type;
}; };
/**
* @ingroup MetaProgramming
* @brief SFINAE trick to enable a template function based on its
* template parameters.
*/
template<class Trait, typename T = void> template<class Trait, typename T = void>
struct enable_if : enable_if_c<Trait::value, T> struct enable_if : enable_if_c<Trait::value, T>
{ {
......
...@@ -39,8 +39,6 @@ ...@@ -39,8 +39,6 @@
#include "cppa/config.hpp" #include "cppa/config.hpp"
#include "cppa/config.hpp"
namespace cppa { namespace util { namespace cppa { namespace util {
/** /**
...@@ -62,22 +60,24 @@ class fixed_vector ...@@ -62,22 +60,24 @@ class fixed_vector
public: public:
typedef size_t size_type; typedef T value_type;
typedef size_t size_type;
typedef T& reference; typedef ptrdiff_t difference_type;
typedef T const& const_reference; typedef value_type& reference;
typedef value_type const& const_reference;
typedef T* iterator; typedef value_type* pointer;
typedef T const* const_iterator; typedef value_type const* const_pointer;
typedef std::reverse_iterator<iterator> reverse_iterator; typedef T* iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator; typedef T const* const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
constexpr fixed_vector() : m_size(0) { } constexpr fixed_vector() : m_size(0) { }
fixed_vector(fixed_vector const& other) : m_size(other.m_size) 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) fixed_vector& operator=(fixed_vector const& other)
...@@ -96,7 +96,22 @@ class fixed_vector ...@@ -96,7 +96,22 @@ class fixed_vector
fixed_vector(std::initializer_list<T> init) : m_size(init.size()) fixed_vector(std::initializer_list<T> init) : m_size(init.size())
{ {
CPPA_REQUIRE(init.size() <= MaxSize); 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 inline size_type size() const
...@@ -104,6 +119,16 @@ class fixed_vector ...@@ -104,6 +119,16 @@ class fixed_vector
return m_size; return m_size;
} }
inline size_type max_size() const
{
return MaxSize;
}
inline size_type capacity() const
{
return max_size() - size();
}
inline void clear() inline void clear()
{ {
m_size = 0; m_size = 0;
...@@ -114,17 +139,28 @@ class fixed_vector ...@@ -114,17 +139,28 @@ class fixed_vector
return m_size == 0; return m_size == 0;
} }
inline bool not_empty() const
{
return m_size > 0;
}
inline bool full() const inline bool full() const
{ {
return m_size == MaxSize; return m_size == MaxSize;
} }
inline void push_back(T const& what) inline void push_back(const_reference what)
{ {
CPPA_REQUIRE(!full()); CPPA_REQUIRE(!full());
m_data[m_size++] = what; m_data[m_size++] = what;
} }
inline void pop_back()
{
CPPA_REQUIRE(not_empty());
--m_size;
}
inline reference at(size_type pos) inline reference at(size_type pos)
{ {
CPPA_REQUIRE(pos < m_size); CPPA_REQUIRE(pos < m_size);
...@@ -242,30 +278,31 @@ class fixed_vector ...@@ -242,30 +278,31 @@ class fixed_vector
} }
/** /**
* @brief Inserts elements to specified position in the container. * @brief Inserts elements before the element pointed to by @p pos.
* @warning This member function is implemented for <tt>pos == end()</tt> * @throw std::length_error if
* only by now. The user has to guarantee that the size of the * <tt>size() + distance(first, last) > MaxSize</tt>
* sequence [first, last) fits into the vector.
*/ */
template<class InputIterator> template<class InputIterator>
inline void insert(iterator pos, inline void insert(iterator pos, InputIterator first, InputIterator last)
InputIterator first,
InputIterator last)
{ {
auto num_elements = std::distance(first, last);
if ((size() + num_elements) > MaxSize)
{
throw std::length_error("fixed_vector::insert: too much elements");
}
if (pos == end()) if (pos == end())
{ {
if (m_size + static_cast<size_type>(last - first) > MaxSize) resize(size() + num_elements);
{ std::copy(first, last, pos);
throw std::runtime_error("fixed_vector::insert: full");
}
for ( ; first != last; ++first)
{
push_back(*first);
}
} }
else 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 @@ ...@@ -36,13 +36,6 @@
namespace cppa { namespace util { namespace cppa { namespace util {
// if (IfStmt == true) type = T; else type = Else::type; // 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> template<bool IfStmt, typename T, class Else>
struct if_else_c struct if_else_c
{ {
...@@ -55,7 +48,13 @@ struct if_else_c<false, T, Else> ...@@ -55,7 +48,13 @@ struct if_else_c<false, T, Else>
typedef typename Else::type type; 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> template<class Stmt, typename T, class Else>
struct if_else : if_else_c<Stmt::value, T, Else> { }; struct if_else : if_else_c<Stmt::value, T, Else> { };
......
...@@ -36,8 +36,9 @@ ...@@ -36,8 +36,9 @@
namespace cppa { namespace util { namespace cppa { namespace util {
/** /**
* @ingroup MetaProgramming
* @brief <tt>is_array_of<T,U>::value == true</tt> if and only * @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> template<typename T, typename U>
struct is_array_of struct is_array_of
...@@ -45,7 +46,7 @@ struct is_array_of ...@@ -45,7 +46,7 @@ struct is_array_of
typedef typename std::remove_all_extents<T>::type step1_type; typedef typename std::remove_all_extents<T>::type step1_type;
typedef typename std::remove_cv<step1_type>::type step2_type; typedef typename std::remove_cv<step1_type>::type step2_type;
static constexpr bool value = std::is_array<T>::value static constexpr bool value = std::is_array<T>::value
&& std::is_same<step2_type, U>::value; && std::is_same<step2_type, U>::value;
}; };
} } // namespace cppa::util } } // namespace cppa::util
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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 @@ ...@@ -37,6 +37,10 @@
namespace cppa { namespace util { namespace cppa { namespace util {
/**
* @ingroup MetaProgramming
* @brief Checks wheter @p T behaves like a forward iterator.
*/
template<typename T> template<typename T>
class is_forward_iterator class is_forward_iterator
{ {
......
...@@ -36,6 +36,11 @@ ...@@ -36,6 +36,11 @@
namespace cppa { namespace util { 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> template<typename T>
class is_iterable class is_iterable
{ {
......
...@@ -35,6 +35,10 @@ ...@@ -35,6 +35,10 @@
namespace cppa { namespace util { namespace cppa { namespace util {
/**
* @ingroup MetaProgramming
* @brief Checks wheter @p T is neither a reference nor a pointer nor an array.
*/
template<typename T> template<typename T>
struct is_legal_tuple_type struct is_legal_tuple_type
{ {
......
...@@ -39,6 +39,10 @@ namespace cppa { namespace util { ...@@ -39,6 +39,10 @@ namespace cppa { namespace util {
// A manipulator is a function that manipulates its arguments via // A manipulator is a function that manipulates its arguments via
// mutable references. // mutable references.
/**
* @ingroup MetaProgramming
* @brief Checks wheter functor or function @p F takes mutable references.
*/
template<typename F> template<typename F>
struct is_manipulator struct is_manipulator
{ {
......
...@@ -33,6 +33,9 @@ ...@@ -33,6 +33,9 @@
namespace cppa { namespace util { namespace cppa { namespace util {
/**
* @brief Checks wheter @p T is a non-const reference.
*/
template<typename T> template<typename T>
struct is_mutable_ref 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 @@ ...@@ -36,7 +36,8 @@
namespace cppa { namespace util { 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 * <code>is_primitive<T>::value == true</code> if and only if @c T
* is a signed / unsigned integer or one of the following types: * is a signed / unsigned integer or one of the following types:
......
...@@ -9,7 +9,11 @@ ...@@ -9,7 +9,11 @@
namespace cppa { namespace util { 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> template<typename T>
class producer_consumer_list 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 @@ ...@@ -73,6 +73,9 @@
namespace cppa { namespace util { 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); void ripemd_160(std::array<std::uint8_t, 20>& storage, std::string const& data);
} } // namespace cppa::util } } // namespace cppa::util
......
...@@ -33,6 +33,9 @@ ...@@ -33,6 +33,9 @@
namespace cppa { namespace util { namespace cppa { namespace util {
/**
* @brief Similar to <tt>std::lock_guard</tt> but performs shared locking.
*/
template<typename SharedLockable> template<typename SharedLockable>
class shared_lock_guard class shared_lock_guard
{ {
......
...@@ -36,6 +36,9 @@ ...@@ -36,6 +36,9 @@
namespace cppa { namespace util { namespace cppa { namespace util {
/**
* @brief A spinlock implementation providing shared and exclusive locking.
*/
class shared_spinlock class shared_spinlock
{ {
......
...@@ -33,6 +33,10 @@ ...@@ -33,6 +33,10 @@
namespace cppa { namespace util { namespace cppa { namespace util {
/**
* @ingroup MetaProgramming
* @brief A for loop that can be used with tuples.
*/
template<size_t Begin, size_t End> template<size_t Begin, size_t End>
struct static_foreach struct static_foreach
{ {
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
namespace cppa { namespace util { namespace cppa { namespace util {
/** /**
* @ingroup TypeList * @ingroup MetaProgramming
* @brief Predefines the first template parameter of @p Tp1. * @brief Predefines the first template parameter of @p Tp1.
*/ */
template<template<typename, typename> class Tpl, typename Arg1> template<template<typename, typename> class Tpl, typename Arg1>
......
...@@ -48,11 +48,11 @@ uniform_type_info const* uniform_typeid(std::type_info const&); ...@@ -48,11 +48,11 @@ uniform_type_info const* uniform_typeid(std::type_info const&);
namespace cppa { namespace util { namespace cppa { namespace util {
/** /**
* @defgroup TypeList Type list meta-programming utility. * @defgroup MetaProgramming Metaprogramming utility.
*/ */
/** /**
* @addtogroup TypeList * @addtogroup MetaProgramming
* @{ * @{
*/ */
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
namespace cppa { namespace util { namespace cppa { namespace util {
/** /**
* @ingroup TypeList * @ingroup MetaProgramming
* @brief A pair of two types. * @brief A pair of two types.
*/ */
template<typename First, typename Second> template<typename First, typename Second>
......
...@@ -33,6 +33,10 @@ ...@@ -33,6 +33,10 @@
namespace cppa { namespace util { namespace cppa { namespace util {
/**
* @ingroup MetaProgramming
* @brief A type wrapper as used in {@link cppa::util::if_else if_else}.
*/
template<typename T> template<typename T>
struct wrapped struct wrapped
{ {
......
...@@ -10,6 +10,7 @@ noinst_PROGRAMS = announce_example_1 \ ...@@ -10,6 +10,7 @@ noinst_PROGRAMS = announce_example_1 \
announce_example_5 \ announce_example_5 \
hello_world_example \ hello_world_example \
math_actor_example \ math_actor_example \
dancing_kirby \
dining_philosophers dining_philosophers
announce_example_1_SOURCES = announce_example_1.cpp announce_example_1_SOURCES = announce_example_1.cpp
...@@ -19,6 +20,7 @@ announce_example_4_SOURCES = announce_example_4.cpp ...@@ -19,6 +20,7 @@ announce_example_4_SOURCES = announce_example_4.cpp
announce_example_5_SOURCES = announce_example_5.cpp announce_example_5_SOURCES = announce_example_5.cpp
hello_world_example_SOURCES = hello_world_example.cpp hello_world_example_SOURCES = hello_world_example.cpp
math_actor_example_SOURCES = math_actor_example.cpp math_actor_example_SOURCES = math_actor_example.cpp
dancing_kirby_SOURCES = dancing_kirby.cpp
dining_philosophers_SOURCES = dining_philosophers.cpp dining_philosophers_SOURCES = dining_philosophers.cpp
EXAMPLES_LIBS = -L../.libs/ -lcppa $(BOOST_LDFLAGS) $(BOOST_THREAD_LIB) EXAMPLES_LIBS = -L../.libs/ -lcppa $(BOOST_LDFLAGS) $(BOOST_THREAD_LIB)
...@@ -30,5 +32,6 @@ announce_example_4_LDADD = $(EXAMPLES_LIBS) ...@@ -30,5 +32,6 @@ announce_example_4_LDADD = $(EXAMPLES_LIBS)
announce_example_5_LDADD = $(EXAMPLES_LIBS) announce_example_5_LDADD = $(EXAMPLES_LIBS)
hello_world_example_LDADD = $(EXAMPLES_LIBS) hello_world_example_LDADD = $(EXAMPLES_LIBS)
math_actor_example_LDADD = $(EXAMPLES_LIBS) math_actor_example_LDADD = $(EXAMPLES_LIBS)
dancing_kirby_LDADD = $(EXAMPLES_LIBS)
dining_philosophers_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; ...@@ -15,11 +15,12 @@ using namespace cppa;
struct chopstick : fsm_actor<chopstick> struct chopstick : fsm_actor<chopstick>
{ {
behavior& init_state; behavior& init_state; // a reference to available
behavior available; behavior available;
behavior taken_by(actor_ptr const& philos) behavior taken_by(actor_ptr const& philos)
{ {
// create a behavior new on-the-fly
return return
( (
on<atom("take"), actor_ptr>() >> [=](actor_ptr other) on<atom("take"), actor_ptr>() >> [=](actor_ptr other)
......
#include <string> #include <string>
#include <cassert>
#include <iostream> #include <iostream>
#include "cppa/cppa.hpp" #include "cppa/cppa.hpp"
...@@ -6,12 +7,16 @@ using std::cout; ...@@ -6,12 +7,16 @@ using std::cout;
using std::endl; using std::endl;
using namespace cppa; using namespace cppa;
void math_actor() void math_fun()
{ {
// receive messages in an endless loop bool done = false;
receive_loop // receive messages until we receive {quit}
do_receive
( (
// "arg_match" matches the parameter types of given lambda expression // "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) on(atom("plus"), arg_match) >> [](int a, int b)
{ {
reply(atom("result"), a + b); reply(atom("result"), a + b);
...@@ -19,35 +24,73 @@ void math_actor() ...@@ -19,35 +24,73 @@ void math_actor()
on(atom("minus"), arg_match) >> [](int a, int b) on(atom("minus"), arg_match) >> [](int a, int b)
{ {
reply(atom("result"), a - 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; });
}
struct math_actor : event_based_actor
{
void init()
{
// execute this behavior until actor terminates
become
(
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")) >> [=]()
{
// set an empty behavior
// (terminates actor with normal exit reason)
become_void();
}
);
}
};
// 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() int main()
{ {
// create a new actor that invokes the function echo_actor // spawn a context-switching actor that invokes math_fun
auto ma = spawn(math_actor); auto a1 = spawn(math_fun);
send(ma, atom("plus"), 1, 2); // spawn an event-based math actor
receive auto a2 = spawn(new math_actor);
( // do some testing on both implementations
// on<> matches types only, but allows up to four leading atoms assert((fetch_result(a1, atom("plus"), 1, 2) == 3));
on<atom("result"), int>() >> [](int result) assert((fetch_result(a2, atom("plus"), 1, 2) == 3));
{ assert((fetch_result(a1, atom("minus"), 2, 1) == 1));
cout << "1 + 2 = " << result << endl; assert((fetch_result(a2, atom("minus"), 2, 1) == 1));
} // tell both actors to terminate
); send(a1, atom("quit"));
send(ma, atom("minus"), 1, 2); send(a2, atom("quit"));
receive // wait until all spawned actors are terminated
(
// on() matches values; use val<T> to match any value of type T
on(atom("result"), val<int>) >> [](int result)
{
cout << "1 - 2 = " << result << endl;
}
);
// force ma to exit
send(ma, atom(":Exit"), exit_reason::user_defined);
// wait until ma exited
await_all_others_done(); await_all_others_done();
// done // done
return 0; return 0;
......
...@@ -34,9 +34,22 @@ namespace cppa { ...@@ -34,9 +34,22 @@ namespace cppa {
void event_based_actor::become_void() void event_based_actor::become_void()
{ {
cleanup(exit_reason::normal);
m_loop_stack.clear(); 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) void event_based_actor::do_become(behavior* bhvr, bool has_ownership)
{ {
reset_timeout(); reset_timeout();
......
...@@ -23,12 +23,12 @@ size_t test__fixed_vector() ...@@ -23,12 +23,12 @@ size_t test__fixed_vector()
fixed_vector<int, 2> vec5 {3, 4}; fixed_vector<int, 2> vec5 {3, 4};
vec4.insert(vec4.end(), vec5.begin(), vec5.end()); vec4.insert(vec4.end(), vec5.begin(), vec5.end());
auto vec6 = vec4; auto vec6 = vec4;
CPPA_CHECK_EQUAL(vec1.size(), static_cast<size_t>(4)); CPPA_CHECK_EQUAL(vec1.size(), 4);
CPPA_CHECK_EQUAL(vec2.size(), static_cast<size_t>(4)); CPPA_CHECK_EQUAL(vec2.size(), 4);
CPPA_CHECK_EQUAL(vec3.size(), static_cast<size_t>(4)); CPPA_CHECK_EQUAL(vec3.size(), 4);
CPPA_CHECK_EQUAL(vec4.size(), static_cast<size_t>(4)); CPPA_CHECK_EQUAL(vec4.size(), 4);
CPPA_CHECK_EQUAL(vec5.size(), static_cast<size_t>(2)); CPPA_CHECK_EQUAL(vec5.size(), 2);
CPPA_CHECK_EQUAL(vec6.size(), static_cast<size_t>(4)); CPPA_CHECK_EQUAL(vec6.size(), 4);
CPPA_CHECK_EQUAL(vec1.full(), true); CPPA_CHECK_EQUAL(vec1.full(), true);
CPPA_CHECK_EQUAL(vec2.full(), false); CPPA_CHECK_EQUAL(vec2.full(), false);
CPPA_CHECK_EQUAL(vec3.full(), true); CPPA_CHECK_EQUAL(vec3.full(), true);
...@@ -40,5 +40,23 @@ size_t test__fixed_vector() ...@@ -40,5 +40,23 @@ size_t test__fixed_vector()
CPPA_CHECK(std::equal(vec4.begin(), vec4.end(), arr1)); 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(), arr1));
CPPA_CHECK(std::equal(vec6.begin(), vec6.end(), vec2.rbegin())); 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; return CPPA_TEST_RESULT;
} }
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#include "cppa/util/enable_if.hpp" #include "cppa/util/enable_if.hpp"
#include "cppa/util/disable_if.hpp" #include "cppa/util/disable_if.hpp"
#include "cppa/util/apply_tuple.hpp" #include "cppa/util/apply_tuple.hpp"
#include "cppa/util/conjunction.hpp"
#include "cppa/util/is_primitive.hpp" #include "cppa/util/is_primitive.hpp"
#include "cppa/util/is_mutable_ref.hpp" #include "cppa/util/is_mutable_ref.hpp"
......
...@@ -287,7 +287,7 @@ void testee3(actor_ptr parent) ...@@ -287,7 +287,7 @@ void testee3(actor_ptr parent)
{ {
if (polls < 5) if (polls < 5)
{ {
//delayed_reply(std::chrono::milliseconds(50), atom("Poll")); delayed_reply(std::chrono::milliseconds(50), atom("Poll"));
} }
send(parent, atom("Push"), polls); send(parent, atom("Push"), polls);
} }
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include "cppa/deserializer.hpp" #include "cppa/deserializer.hpp"
#include "cppa/uniform_type_info.hpp" #include "cppa/uniform_type_info.hpp"
#include "cppa/util/disjunction.hpp"
#include "cppa/util/callable_trait.hpp" #include "cppa/util/callable_trait.hpp"
using std::cout; 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