Commit 03b3b68b authored by neverlord's avatar neverlord

documentation and minor API changes

parent 1bfe10c2
......@@ -30,12 +30,12 @@ object Matching {
case Msg5(0, 0, 0) => msg5Matched += 1
case Msg6(0, 0.0, "0") => msg6Matched += 1
}
val m1 = Msg1(0)
val m2 = Msg2(0.0)
val m3 = Msg3(List(0))
val m4 = Msg4(0, "0")
val m5 = Msg5(0, 0, 0)
val m6 = Msg6(0, 0.0, "0")
val m1: Any = Msg1(0)
val m2: Any = Msg2(0.0)
val m3: Any = Msg3(List(0))
val m4: Any = Msg4(0, "0")
val m5: Any = Msg5(0, 0, 0)
val m6: Any = Msg6(0, 0.0, "0")
for (_ <- zero until numLoops) {
partFun(m1)
partFun(m2)
......
......@@ -88,7 +88,7 @@ struct fsm_chain_link : fsm_actor<fsm_chain_link>
(
on<atom("token"), int>() >> [=](int v)
{
next->enqueue(nullptr, std::move(last_received()));
next->enqueue(nullptr, std::move(self->last_dequeued()));
if (v == 0) become_void();
}
);
......@@ -174,7 +174,7 @@ void chain_link(actor_ptr next)
(
on<atom("token"), int>() >> [&](int v)
{
next << last_received();
next << self->last_dequeued();
if (v == 0)
{
done = true;
......
#!/bin/bash
#export JAVA_OPTS="-Xmx1024"
#echo "scala -cp /home/neverlord/akka-microkernel-1.2/lib/akka/akka-actor-1.2.jar $@" | ./exec.sh
echo "/home/neverlord/scala/bin/scala -cp /home/neverlord/akka-microkernel-1.2/lib/akka/akka-actor-1.2.jar $@" | ./exec.sh
echo "scala -cp /home/neverlord/akka-microkernel-1.2/lib/akka/akka-actor-1.2.jar $@" | ./exec.sh
......@@ -259,3 +259,5 @@ benchmarks/theron_mailbox_performance.cpp
benchmarks/utility.hpp
benchmarks/theron_actor_creation.cpp
benchmarks/theron_mixed_case.cpp
cppa/util/static_foreach.hpp
cppa/type_value_pair.hpp
......@@ -42,6 +42,9 @@
namespace cppa {
/**
* @brief Base class for all event-based actor implementations.
*/
class abstract_event_based_actor : public detail::abstract_scheduled_actor
{
......@@ -58,12 +61,12 @@ class abstract_event_based_actor : public detail::abstract_scheduled_actor
void resume(util::fiber*, resume_callback* callback) /*override*/;
/**
*
* @brief Initializes the actor by defining an initial behavior.
*/
virtual void init() = 0;
/**
*
* @copydoc cppa::scheduled_actor::on_exit()
*/
virtual void on_exit();
......
......@@ -72,22 +72,26 @@ class actor : public channel
~actor();
/**
* @brief Attaches @p ptr to this actor
* (the actor takes ownership of @p ptr).
*
* The actor will call <tt>ptr->detach(...)</tt> on exit or immediately
* if he already exited.
* @brief Attaches @p ptr to this actor.
*
* The actor will call <tt>ptr->detach(...)</tt> on exit, or immediately
* if it already finished execution.
* @param ptr A callback object that's executed if the actor finishes
* execution.
* @returns @c true if @p ptr was successfully attached to the actor;
* otherwise (actor already exited) @p false.
* @warning The actor takes ownership of @p ptr.
*/
virtual bool attach(attachable* ptr) = 0;
/**
* @brief Attaches the functor or function @p ftor to this actor.
* @brief Convenience function that attaches the functor
* or function @p ftor to this actor.
*
* The actor executes <tt>ftor()</tt> on exit or immediatley if he
* already exited.
* The actor executes <tt>ftor()</tt> on exit, or immediatley
* if it already finished execution.
* @param ftor A functor, function or lambda expression that's executed
* if the actor finishes execution.
* @returns @c true if @p ftor was successfully attached to the actor;
* otherwise (actor already exited) @p false.
*/
......@@ -128,7 +132,7 @@ class actor : public channel
/**
* @brief Unlinks this actor from @p other.
* @param oter Linked Actor.
* @param other Linked Actor.
* @note Links are automatically removed if the Actor finishes execution.
*/
virtual void unlink_from(intrusive_ptr<actor>& other) = 0;
......@@ -152,27 +156,23 @@ class actor : public channel
// rvalue support
/**
* @copydoc link_to(intrusive_ptr<actor>&)
* Support for rvalue references.
*/
void link_to(intrusive_ptr<actor>&& other);
/**
* @copydoc unlink_from(intrusive_ptr<actor>&)
* Support for rvalue references.
*/
void unlink_from(intrusive_ptr<actor>&& other);
/**
* @copydoc remove_backlink(intrusive_ptr<actor>&)
* Support for rvalue references.
*/
bool remove_backlink(intrusive_ptr<actor>&& to);
bool remove_backlink(intrusive_ptr<actor>&& other);
/**
* @copydoc establish_backlink(intrusive_ptr<actor>&)
* Support for rvalue references.
*/
bool establish_backlink(intrusive_ptr<actor>&& to);
bool establish_backlink(intrusive_ptr<actor>&& other);
/**
* @brief Gets the {@link process_information} of the parent process.
......@@ -195,6 +195,11 @@ class actor : public channel
*/
inline actor_id id() const;
/**
* @brief Checks if this actor is running on a remote node.
* @returns @c true if this actor represents a remote actor;
* otherwise @c false.
*/
inline bool is_proxy() const;
};
......
......@@ -36,9 +36,15 @@
namespace cppa {
#ifdef CPPA_DOCUMENTATION
/**
* @brief Represents a remote Actor.
*/
class actor_proxy : public actor { };
#else // CPPA_DOCUMENTATION
class actor_proxy : public abstract_actor<actor>
{
......@@ -65,6 +71,8 @@ class actor_proxy : public abstract_actor<actor>
};
#endif // CPPA_DOCUMENTATION
typedef intrusive_ptr<actor_proxy> actor_proxy_ptr;
} // namespace cppa
......
......@@ -50,19 +50,42 @@ class any_tuple
public:
/**
* @brief Creates an empty tuple.
* @post <tt>empty() == true</tt>
*/
any_tuple();
/**
* @brief Creates a tuple from @p t.
* @param t A typed tuple representation.
* @post <tt>empty() == false</tt>
*/
template<typename... Args>
any_tuple(tuple<Args...> const& t) : m_vals(t.vals()) { }
explicit any_tuple(detail::abstract_tuple*);
/**
* @brief Move constructor.
*/
any_tuple(any_tuple&&);
/**
* @brief Copy constructor.
*/
any_tuple(any_tuple const&) = default;
/**
* @brief Move assignment.
* @returns <tt>*this</tt>.
*/
any_tuple& operator=(any_tuple&&);
/**
* @brief Copy assignment.
* @returns <tt>*this</tt>.
*/
any_tuple& operator=(any_tuple const&) = default;
size_t size() const;
......@@ -77,7 +100,7 @@ class any_tuple
bool equals(any_tuple const& other) const;
any_tuple tail(size_t offset = 1) const;
std::type_info const& impl_type() const;
inline bool empty() const
{
......
......@@ -45,6 +45,7 @@
#include "cppa/util/is_primitive.hpp"
#include "cppa/detail/types_array.hpp"
#include "cppa/detail/object_array.hpp"
namespace cppa {
......@@ -147,6 +148,13 @@ class any_tuple_view
return *reinterpret_cast<T const*>(at(p));
}
inline std::type_info const& impl_type() const
{
// this is a lie, but the pattern matching implementation
// needs to do a full runtime check of each element
return typeid(detail::object_array);
}
class const_iterator
{
typedef typename vector_type::const_iterator vec_iterator;
......
......@@ -34,7 +34,7 @@
namespace cppa {
/**
* @brief Acts as wildcard pattern.
* @brief Acts as wildcard expression in patterns.
*/
struct anything { };
......
......@@ -51,9 +51,18 @@ class attachable
public:
/**
* @brief Represents a pointer to a value with its RTTI.
*/
struct token
{
/**
* @brief Denotes the type of @c ptr.
*/
std::type_info const& subtype;
/**
* @brief Any value, used to identify @c attachable instances.
*/
void const* ptr;
inline token(std::type_info const& msubtype, void const* mptr)
: subtype(msubtype), ptr(mptr)
......@@ -64,14 +73,19 @@ class attachable
virtual ~attachable();
/**
* @brief Executed if the actor finished execution
* with given @p reason.
* @brief Executed if the actor finished execution with given @p reason.
*
* The default implementation does nothing.
* @param reason The exit rason of the observed actor.
*/
virtual void actor_exited(std::uint32_t reason) = 0;
virtual bool matches(token const&) = 0;
/**
* @brief Selects a group of @c attachable instances by @p what.
* @param what A value that selects zero or more @c attachable instances.
* @returns @c true if @p what selects this instance; otherwise @c false.
*/
virtual bool matches(token const& what) = 0;
};
......
......@@ -205,7 +205,7 @@
*
* @section Receive Receive messages
*
* The function @p receive takes a @i behavior as argument. The behavior
* The function @p receive takes a @p behavior as argument. The behavior
* is a list of { pattern >> callback } rules.
*
* @code
......@@ -377,46 +377,34 @@
namespace cppa {
/**
* @brief Links the calling actor to @p other.
* @param other An Actor that is related with the calling Actor.
*/
void link(actor_ptr& other);
/**
* @copydoc link(actor_ptr&)
* Support for rvalue references.
*/
void link(actor_ptr&& other);
/**
* @brief Links @p lhs and @p rhs;
* @param lhs First Actor instance.
* @param rhs Second Actor instance.
* @param lhs Left-hand operand.
* @param rhs Right-hand operand.
* @pre <tt>lhs != rhs</tt>
*/
void link(actor_ptr& lhs, actor_ptr& rhs);
/**
* @copydoc link(actor_ptr&,actor_ptr&)
* Support for rvalue references.
*/
void link(actor_ptr&& lhs, actor_ptr& rhs);
/**
* @copydoc link(actor_ptr&,actor_ptr&)
* Support for rvalue references.
*/
void link(actor_ptr&& lhs, actor_ptr&& rhs);
/**
* @copydoc link(actor_ptr&,actor_ptr&)
* Support for rvalue references.
*/
void link(actor_ptr& lhs, actor_ptr&& rhs);
/**
* @brief Unlinks @p lhs and @p rhs;
* @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);
......@@ -430,7 +418,6 @@ void monitor(actor_ptr& whom);
/**
* @copydoc monitor(actor_ptr&)
* Support for rvalue references.
*/
void monitor(actor_ptr&& whom);
......@@ -440,29 +427,6 @@ void monitor(actor_ptr&& whom);
*/
void demonitor(actor_ptr& whom);
/**
* @brief Gets the @c trap_exit state of the calling Actor.
* @returns @c true if the Actor explicitly handles Exit messages;
* @c false if the Actor uses the default behavior (finish execution
* if an Exit message with non-normal exit reason was received).
*/
inline bool trap_exit()
{
return self->trap_exit();
}
/**
* @brief Sets the @c trap_exit state of the calling Actor.
* @param new_value Set this to @c true if you want to explicitly handle Exit
* messages. The default is @c false, causing an Actor to
* finish execution if an Exit message with non-normal
* exit reason was received.
*/
inline void trap_exit(bool new_value)
{
self->trap_exit(new_value);
}
inline actor_ptr spawn(scheduled_actor* what)
{
return get_scheduler()->spawn(what, scheduled);
......@@ -481,7 +445,7 @@ inline actor_ptr spawn(abstract_event_based_actor* what)
/**
* @brief Spawns a new actor that executes @p what with given arguments.
* @param 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 args Arguments needed to invoke @p what.
* @returns A pointer to the newly created {@link actor Actor}.
......@@ -515,34 +479,6 @@ spawn(F&& what, Args const&... args)
return spawn<scheduled>(std::forward<F>(what), args...);
}
/**
* @copydoc local_actor::quit()
*
* Alias for <tt>self->quit(reason);</tt>
*/
inline void quit(std::uint32_t reason)
{
self->quit(reason);
}
/**
* @brief Gets the last dequeued message from the mailbox.
* @returns The last dequeued message from the mailbox.
*/
inline any_tuple& last_received()
{
return self->last_dequeued();
}
/**
* @brief Gets the sender of the last received message.
* @returns An {@link actor_ptr} to the sender of the last received message.
*/
inline actor_ptr& last_sender()
{
return self->last_sender();
}
#ifdef CPPA_DOCUMENTATION
/**
......@@ -634,7 +570,7 @@ self_type const& operator<<(self_type const& s, any_tuple const& what);
self_type const& operator<<(self_type const& s, any_tuple&& what);
#endif
#endif // CPPA_DOCUMENTATION
template<typename Arg0, typename... Args>
void reply(Arg0 const& arg0, Args const&... args)
......@@ -677,7 +613,6 @@ void publish(actor_ptr& whom, std::uint16_t port);
/**
* @copydoc publish(actor_ptr&,std::uint16_t)
* Support for rvalue references.
*/
void publish(actor_ptr&& whom, std::uint16_t port);
......
......@@ -32,6 +32,7 @@
#define ABSTRACT_TUPLE_HPP
#include "cppa/ref_counted.hpp"
#include "cppa/type_value_pair.hpp"
#include "cppa/uniform_type_info.hpp"
#include "cppa/util/type_list.hpp"
......@@ -41,6 +42,8 @@ namespace cppa { namespace detail {
struct abstract_tuple : ref_counted
{
typedef type_value_pair const* const_iterator;
// mutators
virtual void* mutable_at(size_t pos) = 0;
......@@ -49,8 +52,10 @@ struct abstract_tuple : ref_counted
virtual abstract_tuple* copy() const = 0;
virtual void const* at(size_t pos) const = 0;
virtual uniform_type_info const* type_at(size_t pos) const = 0;
// type of the implementation class
virtual std::type_info const& impl_type() const = 0;
virtual bool equals(abstract_tuple const& other) const;
bool equals(abstract_tuple const& other) const;
};
......
......@@ -45,13 +45,13 @@
namespace cppa { namespace detail {
template<size_t VectorSize>
template<typename... ElementTypes>
class decorated_tuple : public abstract_tuple
{
public:
typedef util::fixed_vector<size_t, VectorSize> vector_type;
typedef util::fixed_vector<size_t, sizeof...(ElementTypes)> vector_type;
typedef cow_ptr<abstract_tuple> ptr_type;
......@@ -95,6 +95,12 @@ class decorated_tuple : public abstract_tuple
return false;
}
virtual std::type_info const& impl_type() const
{
return typeid(decorated_tuple);
}
private:
ptr_type m_decorated;
......@@ -111,6 +117,15 @@ class decorated_tuple : public abstract_tuple
};
template<typename TypeList>
struct decorated_tuple_from_type_list;
template<typename... Types>
struct decorated_tuple_from_type_list< util::type_list<Types...> >
{
typedef decorated_tuple<Types...> type;
};
} } // namespace cppa::detail
#endif // DECORATED_TUPLE_HPP
......@@ -44,6 +44,7 @@ struct empty_tuple : cppa::detail::abstract_tuple
void const* at(size_t) const;
bool equals(abstract_tuple const& other) const;
uniform_type_info const* type_at(size_t) const;
std::type_info const& impl_type() const;
};
......
......@@ -197,7 +197,7 @@ class invokable_impl<0, Fun, Tuple, Pattern> : public invokable
template<typename T>
bool invoke_impl(T const& data) const
{
if (detail::matches(data.begin(), m_pattern->begin()))
if (matches(data, *m_pattern))
{
m_iimpl.m_fun();
return true;
......@@ -225,8 +225,7 @@ class invokable_impl<0, Fun, Tuple, Pattern> : public invokable
intermediate* get_intermediate(any_tuple const& data)
{
return detail::matches(data.begin(), m_pattern->begin()) ? &m_iimpl
: nullptr;
return matches(data, *m_pattern) ? &m_iimpl : nullptr;
}
};
......
......@@ -31,9 +31,15 @@
#ifndef DO_MATCH_HPP
#define DO_MATCH_HPP
#include <type_traits>
#include "cppa/pattern.hpp"
#include "cppa/util/enable_if.hpp"
#include "cppa/util/fixed_vector.hpp"
#include "cppa/detail/tuple_vals.hpp"
#include "cppa/detail/types_array.hpp"
#include "cppa/detail/object_array.hpp"
#include "cppa/detail/decorated_tuple.hpp"
namespace cppa { namespace detail {
......@@ -153,20 +159,20 @@ class is_pm_decorated
};
template<class TupleIterator, class PatternIterator>
auto matches(TupleIterator targ, PatternIterator iter)
auto matches(TupleIterator targ, PatternIterator pbegin, PatternIterator pend)
-> typename util::enable_if_c<is_pm_decorated<TupleIterator>::value,bool>::type
{
for ( ; !(iter.at_end() && targ.at_end()); iter.next(), targ.next())
for ( ; !(pbegin == pend && targ.at_end()); ++pbegin, targ.next())
{
if (iter.at_end())
if (pbegin == pend)
{
return false;
}
else if (iter.type() == nullptr) // nullptr == wildcard (anything)
else if (pbegin->first == nullptr) // nullptr == wildcard (anything)
{
// perform submatching
iter.next();
if (iter.at_end())
++pbegin;
if (pbegin == pend)
{
// always true at the end of the pattern
return true;
......@@ -176,7 +182,7 @@ auto matches(TupleIterator targ, PatternIterator iter)
// iterate over tu_args until we found a match
for ( ; targ.at_end() == false; mv.clear(), targ.next())
{
if (matches(TupleIterator(targ, mv_ptr), iter))
if (matches(TupleIterator(targ, mv_ptr), pbegin, pend))
{
targ.push_mapping(mv);
return true;
......@@ -185,11 +191,11 @@ auto matches(TupleIterator targ, PatternIterator iter)
return false; // no submatch found
}
// compare types
else if (targ.at_end() == false && iter.type() == targ.type())
else if (targ.at_end() == false && pbegin->first == targ.type())
{
// compare values if needed
if ( iter.has_value() == false
|| iter.type()->equals(iter.value(), targ.value()))
if ( pbegin->second == nullptr
|| pbegin->first->equals(pbegin->second, targ.value()))
{
targ.push_mapping();
}
......@@ -203,24 +209,24 @@ auto matches(TupleIterator targ, PatternIterator iter)
return false; // no match
}
}
return true; // iter.at_end() && targ.at_end()
return true; // pbegin == pend && targ.at_end()
}
template<class TupleIterator, class PatternIterator>
auto matches(TupleIterator targ, PatternIterator iter)
auto matches(TupleIterator targ, PatternIterator pbegin, PatternIterator pend)
-> typename util::enable_if_c<!is_pm_decorated<TupleIterator>::value,bool>::type
{
for ( ; !(iter.at_end() && targ.at_end()); iter.next(), targ.next())
for ( ; !(pbegin == pend && targ.at_end()); ++pbegin, targ.next())
{
if (iter.at_end())
if (pbegin == pend)
{
return false;
}
else if (iter.type() == nullptr) // nullptr == wildcard (anything)
else if (pbegin->first == nullptr) // nullptr == wildcard (anything)
{
// perform submatching
iter.next();
if (iter.at_end())
++pbegin;
if (pbegin == pend)
{
// always true at the end of the pattern
return true;
......@@ -228,7 +234,7 @@ auto matches(TupleIterator targ, PatternIterator iter)
// iterate over tu_args until we found a match
for ( ; targ.at_end() == false; targ.next())
{
if (matches(targ, iter))
if (matches(targ, pbegin, pend))
{
return true;
}
......@@ -236,15 +242,11 @@ auto matches(TupleIterator targ, PatternIterator iter)
return false; // no submatch found
}
// compare types
else if (targ.at_end() == false && iter.type() == targ.type())
else if (targ.at_end() == false && pbegin->first == targ.type())
{
// compare values if needed
if ( iter.has_value() == false
|| iter.type()->equals(iter.value(), targ.value()))
{
// ok, match next
}
else
if ( pbegin->second != nullptr
&& !pbegin->first->equals(pbegin->second, targ.value()))
{
return false; // values didn't match
}
......@@ -254,7 +256,131 @@ auto matches(TupleIterator targ, PatternIterator iter)
return false; // no match
}
}
return true; // iter.at_end() && targ.at_end()
return true; // pbegin == pend && targ.at_end()
}
// pattern does not contain "anything"
template<class Tuple, class Pattern>
bool matches(std::integral_constant<int, 0>,
Tuple const& tpl, Pattern const& pttrn,
util::fixed_vector<size_t, Pattern::filtered_size>* mv)
{
typedef typename Pattern::types ptypes;
typedef typename decorated_tuple_from_type_list<ptypes>::type dec_t;
typedef typename tuple_vals_from_type_list<ptypes>::type tv_t;
std::type_info const& tinfo = tpl.impl_type();
if (tinfo == typeid(dec_t) || tinfo == typeid(tv_t))
{
if (pttrn.has_values())
{
size_t i = 0;
auto end = pttrn.end();
for (auto iter = pttrn.begin(); iter != end; ++iter)
{
if (iter->second)
{
if (iter->first->equals(iter->second, tpl.at(i)) == false)
{
return false;
}
}
++i;
}
}
}
else if (tinfo == typeid(object_array))
{
if (pttrn.has_values())
{
size_t i = 0;
auto end = pttrn.end();
for (auto iter = pttrn.begin(); iter != end; ++iter, ++i)
{
if (iter->first != tpl.type_at(i)) return false;
if (iter->second)
{
if (iter->first->equals(iter->second, tpl.at(i)) == false)
return false;
}
}
}
else
{
size_t i = 0;
auto end = pttrn.end();
for (auto iter = pttrn.begin(); iter != end; ++iter, ++i)
{
if (iter->first != tpl.type_at(i)) return false;
}
}
}
else
{
return false;
}
// ok => match
if (mv) for (size_t i = 0; i < Pattern::size; ++i) mv->push_back(i);
return true;
}
// "anything" at end of pattern
template<class Tuple, class Pattern>
bool matches(std::integral_constant<int, 1>,
Tuple const& tpl, Pattern const& pttrn,
util::fixed_vector<size_t, Pattern::filtered_size>* mv)
{
auto end = pttrn.end();
--end; // iterate until we reach "anything"
size_t i = 0;
if (pttrn.has_values())
{
for (auto iter = pttrn.begin(); iter != end; ++iter, ++i)
{
if (iter->first != tpl.type_at(i)) return false;
if (iter->second)
{
if (iter->first->equals(iter->second, tpl.at(i)) == false)
return false;
}
}
}
else
{
for (auto iter = pttrn.begin(); iter != end; ++iter, ++i)
{
if (iter->first != tpl.type_at(i)) return false;
}
}
// ok => match
if (mv) for (size_t i = 0; i < Pattern::size; ++i) mv->push_back(i);
return true;
}
// "anything" somewhere in between (ugh!)
template<class Tuple, class Pattern>
bool matches(std::integral_constant<int, 2>,
Tuple const& tpl, Pattern const& ptrn,
util::fixed_vector<size_t, Pattern::filtered_size>* mv = 0)
{
if (mv)
return matches(pm_decorated(tpl.begin(), mv), ptrn.begin(), ptrn.end());
return matches(tpl.begin(), ptrn.begin(), ptrn.end());
}
template<class Tuple, class Pattern>
inline bool matches(Tuple const& tpl, Pattern const& pttrn,
util::fixed_vector<size_t, Pattern::filtered_size>* mv = 0)
{
typedef typename Pattern::types ptypes;
static constexpr int first_anything = util::tl_find<ptypes, anything>::value;
// impl1 = no anything
// impl2 = anything at end
// impl3 = anything somewhere in between
static constexpr int impl = (first_anything == -1)
? 0
: ((first_anything == ((int) Pattern::size) - 1) ? 1 : 2);
static constexpr std::integral_constant<int, impl> token;
return matches(token, tpl, pttrn, mv);
}
} } // namespace cppa::detail
......
......@@ -70,6 +70,8 @@ class object_array : public detail::abstract_tuple
uniform_type_info const* type_at(size_t pos) const;
std::type_info const& impl_type() const;
};
} } // namespace cppa::detail
......
......@@ -34,6 +34,7 @@
#include <typeinfo>
#include "cppa/get.hpp"
#include "cppa/option.hpp"
#include "cppa/util/at.hpp"
#include "cppa/util/wrapped.hpp"
......@@ -145,23 +146,69 @@ struct tdata<Head, Tail...> : tdata<Tail...>
return *this;
}
inline tdata<Tail...>& tail()
// upcast
inline tdata<Tail...>& tail() { return *this; }
inline tdata<Tail...> const& tail() const { return *this; }
inline void const* at(size_t p) const
{
// upcast
return *this;
return (p == 0) ? &head : super::at(p-1);
}
inline tdata<Tail...> const& tail() const
inline uniform_type_info const* type_at(size_t p) const
{
return (p == 0) ? uniform_typeid(typeid(Head)) : super::type_at(p-1);
}
};
template<typename Head, typename... Tail>
struct tdata<option<Head>, Tail...> : tdata<Tail...>
{
typedef tdata<Tail...> super;
option<Head> head;
typedef option<Head> opt_type;
inline tdata() : super(), head() { }
template<typename... Args>
tdata(Head const& v0, Args const&... vals) : super(vals...), head(v0) { }
template<typename... Args>
tdata(Head&& v0, Args const&... vals) : super(vals...), head(std::move(v0)) { }
template<typename... Args>
tdata(util::wrapped<Head> const&, Args const&... vals) : super(vals...) { }
// allow (partial) initialization from a different tdata
template<typename... Y>
tdata(tdata<Y...> const& other) : super(other.tail()), head(other.head) { }
template<typename... Y>
tdata(tdata<Y...>&& other) : super(std::move(other.tail())), head(std::move(other.head)) { }
// allow initialization with a function pointer or reference
// returning a wrapped<Head>
template<typename...Args>
tdata(util::wrapped<Head>(*)(), Args const&... vals)
: super(vals...), head()
{
// upcast
return *this;
}
inline bool operator==(tdata const& other) const
template<typename... Y>
tdata& operator=(tdata<Y...> const& other)
{
return head == other.head && tail() == other.tail();
tdata_set(*this, other);
return *this;
}
// upcast
inline tdata<Tail...>& tail() { return *this; }
inline tdata<Tail...> const& tail() const { return *this; }
inline void const* at(size_t p) const
{
return (p == 0) ? &head : super::at(p-1);
......
......@@ -116,11 +116,25 @@ class tuple_vals : public abstract_tuple
return abstract_tuple::equals(other);
}
std::type_info const& impl_type() const
{
return typeid(tuple_vals);
}
};
template<typename... ElementTypes>
types_array<ElementTypes...> tuple_vals<ElementTypes...>::m_types;
template<typename TypeList>
struct tuple_vals_from_type_list;
template<typename... Types>
struct tuple_vals_from_type_list< util::type_list<Types...> >
{
typedef tuple_vals<Types...> type;
};
} } // namespace cppa::detail
#endif // TUPLE_VALS_HPP
......@@ -3,6 +3,9 @@
#include <typeinfo>
#include "cppa/type_value_pair.hpp"
#include "cppa/util/tbind.hpp"
#include "cppa/util/type_list.hpp"
#include "cppa/util/is_builtin.hpp"
......@@ -57,27 +60,39 @@ struct ta_util<cppa_tinf, false, T>
template<bool BuiltinOnlyTypes, typename... T>
struct types_array_impl
{
static constexpr bool builtin_only = true;
// all types are builtin, perform lookup on constuction
uniform_type_info const* data[sizeof...(T)];
type_value_pair pairs[sizeof...(T)];
types_array_impl()
: data{ta_util<cppa_tinf,util::is_builtin<T>::value,T>::get()...}
{
for (size_t i = 0; i < sizeof...(T); ++i)
{
pairs[i].first = data[i];
pairs[i].second = nullptr;
}
}
inline size_t size() const { return sizeof...(T); }
inline uniform_type_info const* operator[](size_t p) const
{
return data[p];
}
typedef type_value_pair const* const_iterator;
inline const_iterator begin() const { return pairs; }
inline const_iterator end() const { return pairs + sizeof...(T); }
};
template<typename... T>
struct types_array_impl<false, T...>
{
static constexpr bool builtin_only = false;
// contains std::type_info for all non-builtin types
std::type_info const* tinfo_data[sizeof...(T)];
// contains uniform_type_infos for builtin types and lazy initializes
// non-builtin types at runtime
mutable std::atomic<uniform_type_info const*> data[sizeof...(T)];
mutable std::atomic<type_value_pair const*> pairs;
// pairs[sizeof...(T)];
types_array_impl()
: tinfo_data{ta_util<std_tinf,util::is_builtin<T>::value,T>::get()...}
{
......@@ -92,7 +107,6 @@ struct types_array_impl<false, T...>
}
}
}
inline size_t size() const { return sizeof...(T); }
inline uniform_type_info const* operator[](size_t p) const
{
auto result = data[p].load();
......@@ -107,41 +121,48 @@ struct types_array_impl<false, T...>
}
return result;
}
typedef type_value_pair const* const_iterator;
inline const_iterator begin() const
{
auto result = pairs.load();
if (result == nullptr)
{
auto parr = new type_value_pair[sizeof...(T)];
for (size_t i = 0; i < sizeof...(T); ++i)
{
parr[i].first = (*this)[i];
parr[i].second = nullptr;
}
if (!pairs.compare_exchange_weak(result, parr, std::memory_order_relaxed))
{
delete[] parr;
}
else
{
result = parr;
}
}
return result;
}
inline const_iterator end() const
{
return begin() + sizeof...(T);
}
};
// a container for uniform_type_information singletons with optimization
// for builtin types; can act as pattern
template<typename... T>
struct types_array : types_array_impl<util::tl_forall<util::type_list<T...>,
util::is_builtin>::value,
T...>
{
class const_iterator
{
types_array const& m_ref;
size_t m_pos;
public:
const_iterator(const_iterator const&) = default;
const_iterator& operator=(const_iterator const&) = default;
const_iterator(types_array const& ptr) : m_ref(ptr), m_pos(0) { }
inline void next() { ++m_pos; }
inline bool at_end() const { return m_pos == sizeof...(T); }
inline uniform_type_info const* type() const
{
return m_ref[m_pos];
}
inline bool has_value() const { return false; }
inline void const* value() const { return nullptr; }
};
const_iterator begin() const { return {*this}; }
static constexpr size_t size = sizeof...(T);
typedef util::type_list<T...> types;
typedef typename util::tl_filter_not<types, util::tbind<std::is_same, anything>::type>::type
filtered_types;
static constexpr size_t filtered_size = filtered_types::size;
inline bool has_values() const { return false; }
};
template<typename... T>
......@@ -153,6 +174,15 @@ struct static_types_array
template<typename... T>
types_array<T...> static_types_array<T...>::arr;
template<typename TypeList>
struct static_types_array_from_type_list;
template<typename... T>
struct static_types_array_from_type_list<util::type_list<T...>>
{
typedef static_types_array<T...> type;
};
} } // namespace cppa::detail
#endif // TYPES_ARRAY_HPP
......@@ -40,6 +40,7 @@
#include "cppa/anything.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/tuple_view.hpp"
#include "cppa/type_value_pair.hpp"
#include "cppa/uniform_type_info.hpp"
#include "cppa/util/tbind.hpp"
......@@ -47,6 +48,7 @@
#include "cppa/util/arg_match_t.hpp"
#include "cppa/util/fixed_vector.hpp"
#include "cppa/util/is_primitive.hpp"
#include "cppa/util/static_foreach.hpp"
#include "cppa/detail/boxed.hpp"
#include "cppa/detail/tdata.hpp"
......@@ -78,51 +80,23 @@ class pattern
typedef typename util::tl_filter_not<types, util::tbind<std::is_same, anything>::type>::type
filtered_types;
typedef util::fixed_vector<size_t, filtered_types::size> mapping_vector;
class const_iterator
{
pattern const* m_ptr;
size_t m_pos;
public:
static constexpr size_t filtered_size = filtered_types::size;
const_iterator(const_iterator const&) = default;
const_iterator& operator=(const_iterator const&) = default;
const_iterator(pattern const* ptr) : m_ptr(ptr), m_pos(0) { }
inline void next() { ++m_pos; }
inline bool at_end() { return m_pos == sizeof...(Types); }
inline uniform_type_info const* type() const
{
return m_ptr->m_utis[m_pos];
}
typedef util::fixed_vector<size_t, filtered_types::size> mapping_vector;
inline bool has_value() const
{
return m_ptr->m_data_ptr[m_pos] != nullptr;
}
typedef type_value_pair const* const_iterator;
inline void const* value() const
{
return m_ptr->m_data_ptr[m_pos];
}
const_iterator begin() const { return m_ptrs; }
};
const_iterator end() const { return m_ptrs + size; }
const_iterator begin() const
{
return {this};
}
pattern()
pattern() : m_has_values(false)
{
auto& arr = detail::static_types_array<Types...>::arr;
for (size_t i = 0; i < size; ++i)
{
m_data_ptr[i] = nullptr;
m_ptrs[i].first = arr[i];
m_ptrs[i].second = nullptr;
}
}
......@@ -131,34 +105,55 @@ class pattern
{
using std::is_same;
using namespace util;
static constexpr bool all_boxed =
util::tl_forall<type_list<Arg0, Args...>,
detail::is_boxed >::value;
m_has_values = !all_boxed;
typedef typename type_list<Arg0, Args...>::back arg_n;
static constexpr bool ignore_arg_n = is_same<arg_n, arg_match_t>::value;
bool invalid_args[] = { detail::is_boxed<Arg0>::value,
detail::is_boxed<Args>::value... };
// ignore extra arg_match_t argument
static constexpr size_t args_size = sizeof...(Args)
+ (ignore_arg_n ? 0 : 1);
static_assert(args_size <= size, "too many arguments");
for (size_t i = 0; i < args_size; ++i)
{
m_data_ptr[i] = invalid_args[i] ? nullptr : m_data.at(i);
}
auto& arr = detail::static_types_array<Types...>::arr;
functor f(*this, arr);
util::static_foreach<0, args_size>::_(m_data, f);
for (size_t i = args_size; i < size; ++i)
{
m_data_ptr[i] = nullptr;
m_ptrs[i].first = arr[i];
m_ptrs[i].second = nullptr;
}
}
inline bool has_values() const { return m_has_values; }
private:
detail::tdata<Types...> m_data;
static detail::types_array<Types...> m_utis;
void const* m_data_ptr[size];
struct functor;
};
friend class functor;
template<typename... Types>
detail::types_array<Types...> pattern<Types...>::m_utis;
struct functor
{
pattern& p;
detail::types_array<Types...>& arr;
size_t i;
functor(pattern& pp, detail::types_array<Types...>& tarr)
: p(pp), arr(tarr), i(0) { }
template<typename T>
void operator()(option<T> const& what)
{
p.m_ptrs[i].first = arr[i];
p.m_ptrs[i].second = (what) ? &(*what) : nullptr;
++i;
}
};
detail::tdata<option<Types>...> m_data;
bool m_has_values;
type_value_pair m_ptrs[size];
};
template<class ExtendedType, class BasicType>
ExtendedType* extend_pattern(BasicType const* p)
......@@ -167,11 +162,19 @@ ExtendedType* extend_pattern(BasicType const* p)
detail::tdata_set(et->m_data, p->m_data);
for (size_t i = 0; i < BasicType::size; ++i)
{
if (p->m_data_ptr[i] != nullptr)
et->m_ptrs[i].first = p->m_ptrs[i].first;
if (p->m_ptrs[i].second != nullptr)
{
et->m_data_ptr[i] = et->m_data.at(i);
et->m_ptrs[i].second = et->m_data.at(i);
}
}
typedef typename ExtendedType::types extended_types;
typedef typename detail::static_types_array_from_type_list<extended_types>::type tarr;
auto& arr = tarr::arr;
for (auto i = BasicType::size; i < ExtendedType::size; ++i)
{
et->m_ptrs[i].first = arr[i];
}
return et;
}
......
......@@ -52,34 +52,51 @@ class process_information : public ref_counted,
public:
/**
* @brief @c libcppa uses 160 bit hashes (20 bytes).
*/
static constexpr size_t node_id_size = 20;
/**
* @brief Represents a 160 bit hash.
*/
typedef std::array<std::uint8_t, node_id_size> node_id_type;
//process_information();
process_information(std::uint32_t process_id, node_id_type const& node_id);
/**
* @brief Copy constructor.
*/
process_information(process_information const&);
/**
* @brief Creates @c this from @p process_id and @p hash.
* @param process_id System-wide unique process identifier.
* @param hash Unique node id as hexadecimal string representation.
*/
process_information(std::uint32_t process_id, std::string const& hash);
process_information(process_information const& other);
/**
* @brief Creates @c this from @p process_id and @p hash.
* @param process_id System-wide unique process identifier.
* @param hash Unique node id.
*/
process_information(std::uint32_t process_id, node_id_type const& node_id);
/**
* @brief Identifies the running process.
* @returns A system-wide unique process identifier.
*/
inline std::uint32_t process_id() const { return m_process_id; }
/**
* @brief Identifies the host system.
*
* A hash build from the MAC address of the first network device
* and the serial number from the root HD (mounted in "/" or "C:").
* @returns A hash build from the MAC address of the first network device
* and the UUID of the root partition (mounted in "/" or "C:").
*/
inline node_id_type const& node_id() const { return m_node_id; }
/**
* @brief Returns the proccess_information for the running process.
* @returns
* @returns A pointer to the singleton of this process.
*/
static intrusive_ptr<process_information> const& get();
......@@ -108,7 +125,10 @@ inline bool equal(process_information::node_id_type const& node_id,
std::string to_string(process_information const& what);
/**
* @brief Converts {@link node_id} to an hexadecimal string.
* @brief Converts a {@link process_information::node_id_type node_id}
* to a hexadecimal string.
* @param node_id A unique node identifier.
* @returns A hexadecimal representation of @p node_id.
*/
std::string to_string(process_information::node_id_type const& node_id);
......
......@@ -38,18 +38,73 @@
namespace cppa {
#ifdef CPPA_DOCUMENTATION
/**
* @brief Dequeues the next message from the mailbox that's matched
* by @p bhvr and executes the corresponding callback.
* @param bhvr Denotes the actor's response the next incoming message.
*/
inline void receive(invoke_rules& bhvr)
{
self->dequeue(bhvr);
}
void receive(behavior& bhvr);
/**
* @brief Receives messages in an endless loop.
*
* Semantically equal to: <tt>for (;;) { receive(bhvr); }</tt>
* @param bhvr Denotes the actor's response the next incoming message.
*/
void receive_loop(behavior& bhvr);
/**
* @brief Receives messages as long as @p stmt returns true.
*
* Semantically equal to: <tt>while (stmt()) { receive(...); }</tt>.
*
* <b>Usage example:</b>
* @code
* int i = 0;
* receive_while([&]() { return (++i <= 10); })
* (
* on<int>() >> int_fun,
* on<float>() >> float_fun
* );
* @endcode
* @param stmt Lambda expression, functor or function returning a @c bool.
* @returns A functor implementing the loop.
*/
template<typename Statement>
auto receive_while(Statement&& stmt);
/**
* @brief Receives messages until @p stmt returns true.
*
* Semantically equal to: <tt>do { receive(...); } while (stmt() == false);</tt>
*
* <b>Usage example:</b>
* @code
* int i = 0;
* do_receive
* (
* on<int>() >> int_fun,
* on<float>() >> float_fun
* )
* .until([&]() { return (++i >= 10); };
* @endcode
* @param bhvr Denotes the actor's response the next incoming message.
* @returns A functor providing the @c until member function.
*/
auto do_receive(behavior& bhvr);
#else // CPPA_DOCUMENTATION
inline void receive(invoke_rules& bhvr) { self->dequeue(bhvr); }
inline void receive(timed_invoke_rules& bhvr) { self->dequeue(bhvr); }
inline void receive(timed_invoke_rules& bhvr)
inline void receive(behavior& bhvr)
{
self->dequeue(bhvr);
if (bhvr.is_left()) self->dequeue(bhvr.left());
else self->dequeue(bhvr.right());
}
inline void receive(timed_invoke_rules&& bhvr)
......@@ -79,58 +134,29 @@ void receive(invoke_rules& bhvr, Head&& head, Tail&&... tail)
std::forward<Tail>(tail)...);
}
inline void receive(behavior& bhvr)
{
if (bhvr.is_left()) receive(bhvr.left());
else receive(bhvr.right());
}
/**
* @brief Receives messages in an endless loop.
*
* Semantically equal to: <tt>for (;;) { receive(rules); }</tt>
* @param rules Invoke rules to receive and handle messages.
*/
void receive_loop(invoke_rules& rules);
/**
* @copydoc receive_loop(invoke_rules&)
* Support for invoke rules with timeout.
*/
void receive_loop(timed_invoke_rules& rules);
/**
* @copydoc receive_loop(invoke_rules&)
* Support for rvalue references.
*/
inline void receive_loop(behavior& bhvr)
{
if (bhvr.is_left()) receive_loop(bhvr.left());
else receive_loop(bhvr.right());
}
inline void receive_loop(invoke_rules&& rules)
{
invoke_rules tmp(std::move(rules));
receive_loop(tmp);
}
/**
* @copydoc receive_loop(invoke_rules&)
* Support for rvalue references and timeout.
*/
inline void receive_loop(timed_invoke_rules&& rules)
{
timed_invoke_rules tmp(std::move(rules));
receive_loop(tmp);
}
/**
* @brief Receives messages in an endless loop.
*
* This function overload provides a simple way to define a receive loop
* with on-the-fly {@link invoke_rules}.
*
* @b Example:
* @code
* receive_loop(on<int>() >> int_fun, on<float>() >> float_fun);
* @endcode
* @see receive_loop(invoke_rules&)
*/
template<typename Head, typename... Tail>
void receive_loop(invoke_rules& rules, Head&& head, Tail&&... tail)
{
......@@ -138,20 +164,6 @@ void receive_loop(invoke_rules& rules, Head&& head, Tail&&... tail)
std::forward<Tail>(tail)...);
}
/**
* @brief Receives messages in an endless loop.
*
* This function overload provides a simple way to define a receive loop
* with on-the-fly {@link invoke_rules}.
*
* @b Example:
* @code
* receive_loop(on<int>() >> int_fun, on<float>() >> float_fun);
* @endcode
* @see receive_loop(invoke_rules&)
*
* Support for rvalue references.
*/
template<typename Head, typename... Tail>
void receive_loop(invoke_rules&& rules, Head&& head, Tail&&... tail)
{
......@@ -160,23 +172,6 @@ void receive_loop(invoke_rules&& rules, Head&& head, Tail&&... tail)
std::forward<Tail>(tail)...);
}
/**
* @brief Receives messages as long as @p stmt returns true.
*
* Semantically equal to: <tt>while (stmt()) { receive(...); }</tt>.
*
* <b>Usage example:</b>
* @code
* int i = 0;
* receive_while([&]() { return (++i <= 10); })
* (
* on<int>() >> int_fun,
* on<float>() >> float_fun
* );
* @endcode
* @param stmt Lambda expression, functor or function returning a @c bool.
* @returns A functor implementing the loop.
*/
template<typename Statement>
detail::receive_while_helper<Statement>
receive_while(Statement&& stmt)
......@@ -186,30 +181,14 @@ receive_while(Statement&& stmt)
return std::move(stmt);
}
/**
* @brief Receives messages until @p stmt returns true.
*
* Semantically equal to: <tt>do { receive(...); } while (stmt() == false);</tt>
*
* <b>Usage example:</b>
* @code
* int i = 0;
* do_receive
* (
* on<int>() >> int_fun,
* on<float>() >> float_fun
* )
* .until([&]() { return (++i >= 10); };
* @endcode
* @param args Invoke rules to handle received messages.
* @returns A functor providing the @c until member function.
*/
template<typename... Args>
detail::do_receive_helper do_receive(Args&&... args)
{
return detail::do_receive_helper(std::forward<Args>(args)...);
}
#endif // CPPA_DOCUMENTATION
} // namespace cppa
#endif // RECEIVE_HPP
......@@ -33,13 +33,35 @@
namespace cppa {
/**
* @brief A base class for context-switching or thread-mapped actor
* implementations.
*
* This abstract class provides a class-based way to define context-switching
* or thread-mapped actors. In general,
* you always should use event-based actors. However, if you need to call
* blocking functions, or need to have your own thread for other reasons,
* this class can be used to define a class-based actor.
*/
class scheduled_actor
{
public:
virtual ~scheduled_actor();
/**
* @brief Can be overridden to perform cleanup code after an actor
* finished execution.
* @warning Must not call any function manipulating the actor's state such
* as join, leave, link, or monitor.
*/
virtual void on_exit();
/**
* @brief Implements the behavior of a context-switching or thread-mapped
* actor.
*/
virtual void act() = 0;
};
......
......@@ -112,7 +112,8 @@ class scheduler
Duration const& rel_time, Data const&... data)
{
static_assert(sizeof...(Data) > 0, "no message to send");
any_tuple tup = make_tuple(util::duration(rel_time), to, data...);
any_tuple data_tup = make_tuple(data...);
any_tuple tup = make_tuple(util::duration(rel_time), to, data_tup);
future_send_helper()->enqueue(self, std::move(tup));
}
......
......@@ -33,10 +33,23 @@
namespace cppa {
/**
* @brief Denotes whether a user wants an actor to take part in
* cooperative scheduling or not.
*/
enum scheduling_hint
{
/**
* @brief Indicates that an actor takes part in cooperative scheduling.
*/
scheduled,
/**
* @brief Indicates that an actor should run in its own thread.
*/
detached
};
} // namespace cppa
......
......@@ -84,12 +84,6 @@ class self_type : public convertible<self_type, actor*>
return get_impl();
}
// backward compatibility
inline local_actor* operator()() const
{
return get_impl();
}
// @pre get_unchecked() == nullptr
inline void set(local_actor* ptr) const
{
......
......@@ -86,6 +86,8 @@ class tuple
public:
typedef util::type_list<ElementTypes...> types;
static constexpr size_t num_elements = sizeof...(ElementTypes);
/**
......@@ -130,7 +132,7 @@ class tuple
util::fixed_vector<size_t, num_elements> const& mv)
{
return tuple(ptr_ctor(),
new detail::decorated_tuple<num_elements>(ptr, mv));
new detail::decorated_tuple<ElementTypes...>(ptr, mv));
}
/**
......
......@@ -51,7 +51,7 @@ option<ResultTuple> tuple_cast_impl(Tuple const& tup, pattern<P...> const& p)
{
typedef typename pattern<P...>::filtered_types filtered_types;
typename pattern<P...>::mapping_vector mv;
if (detail::matches(detail::pm_decorated(tup.begin(), &mv), p.begin()))
if (detail::matches(tup, p, &mv))
{
if (mv.size() == tup.size()) // perfect match
{
......@@ -59,7 +59,7 @@ option<ResultTuple> tuple_cast_impl(Tuple const& tup, pattern<P...> const& p)
}
else
{
typedef detail::decorated_tuple<filtered_types::size> decorated;
typedef typename detail::decorated_tuple_from_type_list<filtered_types>::type decorated;
return {ResultTuple::from(tup.vals(), mv)};
}
}
......@@ -87,11 +87,9 @@ option<ResultTuple> tuple_cast_impl(Tuple const& tup)
else
{
util::fixed_vector<size_t, ResultTuple::num_elements> mv;
if (detail::matches(detail::pm_decorated(tup.begin(), &mv),
detail::static_types_array<T...>::arr.begin()))
if (detail::matches(tup, detail::static_types_array<T...>::arr, &mv))
{
// never a perfect match
typedef detail::decorated_tuple<ResultTuple::num_elements> decorated;
return {ResultTuple::from(tup.vals(), mv)};
}
}
......
......@@ -68,6 +68,8 @@ class tuple_view
static constexpr size_t num_elements = sizeof...(ElementTypes);
typedef util::type_list<ElementTypes...> types;
static tuple_view from(std::vector< std::pair<uniform_type_info const*, void const*> > const& vec)
{
tuple_view result;
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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 TYPE_VALUE_PAIR_HPP
#define TYPE_VALUE_PAIR_HPP
#include "cppa/uniform_type_info.hpp"
namespace cppa {
typedef std::pair<uniform_type_info const*, void const*> type_value_pair;
} // namespace cppa
#endif // TYPE_VALUE_PAIR_HPP
......@@ -100,7 +100,7 @@ uniform_type_info const* uniform_typeid(std::type_info const&);
* Depending on your platform, the error message looks somewhat like this:
*
* <tt>
* terminate called after throwing an instance of 'std::runtime_error'
* terminate called after throwing an instance of std::runtime_error
* <br>
* what(): uniform_type_info::by_type_info(): foo is an unknown typeid name
* </tt>
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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 STATIC_FOREACH_HPP
#define STATIC_FOREACH_HPP
namespace cppa { namespace util {
template<size_t Begin, size_t End>
struct static_foreach
{
template<typename Container, typename Fun>
static inline void _(Container const& c, Fun& f)
{
f(get<Begin>(c));
static_foreach<Begin+1, End>::_(c, f);
}
};
template<size_t X>
struct static_foreach<X, X>
{
template<typename Container, typename Fun>
static inline void _(Container const&, Fun&) { }
};
} } // namespace cppa::util
#endif // STATIC_FOREACH_HPP
......@@ -129,7 +129,7 @@ int main(int, char**)
on<baz>() >> []()
{
// prints: @<> ( { baz ( foo ( 1, 2 ), bar ( foo ( 3, 4 ), 5 ) ) } )
cout << to_string(last_received()) << endl;
cout << to_string(self->last_dequeued()) << endl;
}
);
......
......@@ -207,8 +207,8 @@ int main()
{
// prints the tree in its serialized format:
// @<> ( { tree ( 0, { 10, { 11, { }, 12, { }, 13, { } }, 20, { 21, { }, 22, { } } } ) } )
cout << "to_string(last_received()): "
<< to_string(last_received())
cout << "to_string(self->last_dequeued()): "
<< to_string(self->last_dequeued())
<< endl;
// prints the tree using the print member function:
// 0 { 10 { 11, 12, 13 } , 20 { 21, 22 } }
......@@ -225,7 +225,7 @@ int main()
// tree ( 0, { 10, { 11, { }, 12, { }, 13, { } }, 20, { 21, { }, 22, { } } } )
// )
// } )
cout << "to_string: " << to_string(last_received()) << endl;
cout << "to_string: " << to_string(self->last_dequeued()) << endl;
}
);
......
......@@ -42,7 +42,7 @@ bool abstract_tuple::equals(const abstract_tuple &other) const
if (uti != other.type_at(i)) return false;
auto lhs = at(i);
auto rhs = other.at(i);
// compare first addresses, then values
// compare addresses first, then values
if (lhs != rhs && !(uti->equals(lhs, rhs))) return false;
}
return true;
......
......@@ -34,6 +34,7 @@
namespace {
/*
struct offset_decorator : cppa::detail::abstract_tuple
{
......@@ -76,6 +77,7 @@ struct offset_decorator : cppa::detail::abstract_tuple
ptr_type m_decorated;
};
*/
inline cppa::detail::empty_tuple* s_empty_tuple()
{
......@@ -109,11 +111,9 @@ any_tuple& any_tuple::operator=(any_tuple&& other)
return *this;
}
any_tuple any_tuple::tail(size_t offset) const
std::type_info const& any_tuple::impl_type() const
{
if (offset == 0) return *this;
if (size() <= offset) return any_tuple(s_empty_tuple());
return any_tuple(new offset_decorator(m_vals, offset));
return m_vals->impl_type();
}
size_t any_tuple::size() const
......
......@@ -103,7 +103,7 @@ void converted_thread_context::dequeue(timed_invoke_rules& rules) /*override*/
converted_thread_context::throw_on_exit_result
converted_thread_context::throw_on_exit(any_tuple const& msg)
{
if (matches(msg.begin(), m_exit_msg_pattern.begin()))
if (matches(msg, m_exit_msg_pattern))
{
auto reason = msg.get_as<std::uint32_t>(1);
if (reason != exit_reason::normal)
......
......@@ -63,4 +63,9 @@ bool empty_tuple::equals(const abstract_tuple& other) const
return other.size() == 0;
}
std::type_info const& empty_tuple::impl_type() const
{
return typeid(empty_tuple);
}
} } // namespace cppa::detail
......@@ -102,4 +102,9 @@ uniform_type_info const* object_array::type_at(size_t pos) const
return m_elements[pos].type();
}
std::type_info const& object_array::impl_type() const
{
return typeid(object_array);
}
} } // namespace cppa::detail
......@@ -148,7 +148,8 @@ void scheduler_helper::time_emitter(scheduler_helper::ptr_type m_self)
ptr->msg.at(1)));
if (*whom)
{
auto msg = ptr->msg.tail(2);
any_tuple msg = *(reinterpret_cast<any_tuple const*>(
ptr->msg.at(2)));
(*whom)->enqueue(ptr->sender.get(), std::move(msg));
}
messages.erase(it);
......
......@@ -31,7 +31,7 @@ void ping()
void pong(actor_ptr ping_actor)
{
link(ping_actor);
self->link_to(ping_actor);
// kickoff
send(ping_actor, atom("pong"), 0);
receive_loop
......@@ -40,7 +40,7 @@ void pong(actor_ptr ping_actor)
{
// terminate with non-normal exit reason
// to force ping actor to quit
quit(exit_reason::user_defined);
self->quit(exit_reason::user_defined);
},
on<atom("ping"), int>() >> [](int value)
{
......
......@@ -53,6 +53,7 @@ size_t test__local_group()
after(std::chrono::seconds(2)) >> [&]()
{
CPPA_CHECK(false);
result = 10;
}
)
.until([&result]() { return result == 10; });
......
......@@ -29,7 +29,7 @@ std::string plot(Arr const& arr)
{
std::ostringstream oss;
oss << "{ ";
for (size_t i = 0; i < arr.size(); ++i)
for (size_t i = 0; i < Arr::size; ++i)
{
if (i > 0) oss << ", ";
oss << "arr[" << i << "] = " << ((arr[i]) ? arr[i]->name() : "anything");
......@@ -63,9 +63,9 @@ size_t test__pattern()
{
CPPA_TEST(test__pattern);
match_test(make_tuple(1,2,3));
match_test(std::list<int>{1, 2, 3});
match_test("abc");
//match_test(make_tuple(1,2,3));
//match_test(std::list<int>{1, 2, 3});
//match_test("abc");
pattern<int, anything, int> i3;
any_tuple i3_any_tup = make_tuple(1, 2, 3);
......
......@@ -255,18 +255,15 @@ class testee_actor : public scheduled_actor
// receives one timeout and quits
void testee1()
{
receive_loop
receive
(
after(std::chrono::milliseconds(10)) >> []()
{
quit(exit_reason::user_defined);
}
after(std::chrono::milliseconds(10)) >> []() { }
);
}
void testee2(actor_ptr other)
{
link(other);
self->link_to(other);
send(other, std::uint32_t(1));
receive_loop
(
......@@ -370,13 +367,14 @@ size_t test__spawn()
auto report_unexpected = [&]()
{
cerr << "unexpected message: " << to_string(last_received()) << endl;
cerr << "unexpected message: "
<< to_string(self->last_dequeued()) << endl;
CPPA_CHECK(false);
};
trap_exit(true);
self->trap_exit(true);
auto pong_actor = spawn(pong, spawn(ping));
monitor(pong_actor);
link(pong_actor);
self->link_to(pong_actor);
// monitor(spawn(testee2, spawn(testee1)));
int i = 0;
int flags = 0;
......
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