Commit 03b3b68b authored by neverlord's avatar neverlord

documentation and minor API changes

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