Commit 8a14da68 authored by Dominik Charousset's avatar Dominik Charousset

added partial_function::or_else

this feature allows users to define the behavior of an actor by
concatenating partial functions
parent 85f7e0ff
......@@ -95,6 +95,7 @@ set(LIBCPPA_SRC
src/any_tuple.cpp
src/atom.cpp
src/attachable.cpp
src/behavior.cpp
src/behavior_stack.cpp
src/binary_deserializer.cpp
src/binary_serializer.cpp
......
......@@ -209,6 +209,7 @@ src/actor_registry.cpp
src/any_tuple.cpp
src/atom.cpp
src/attachable.cpp
src/behavior.cpp
src/behavior_stack.cpp
src/binary_deserializer.cpp
src/binary_serializer.cpp
......
......@@ -35,7 +35,6 @@
#include <type_traits>
#include "cppa/match_expr.hpp"
#include "cppa/partial_function.hpp"
#include "cppa/timeout_definition.hpp"
#include "cppa/util/tbind.hpp"
......@@ -47,12 +46,14 @@
namespace cppa {
class partial_function;
/**
* @brief Describes the behavior of an actor.
*/
class behavior {
typedef partial_function super;
friend class partial_function;
public:
......@@ -64,9 +65,9 @@ class behavior {
behavior& operator=(behavior&&) = default;
behavior& operator=(const behavior&) = default;
inline behavior(partial_function fun) : m_impl(std::move(fun.m_impl)) { }
behavior(const partial_function& fun);
inline behavior(partial_function::impl_ptr ptr) : m_impl(std::move(ptr)) { }
inline behavior(impl_ptr ptr) : m_impl(std::move(ptr)) { }
template<typename F>
behavior(const timeout_definition<F>& arg)
......@@ -109,17 +110,6 @@ class behavior {
};
template<typename Arg0, typename... Args>
typename util::if_else<
util::disjunction<
is_timeout_definition<Arg0>,
is_timeout_definition<Args>...>,
behavior,
util::wrapped<partial_function> >::type
match_expr_convert(const Arg0& arg0, const Args&... args) {
return {match_expr_concat(arg0, args...)};
}
template<typename... Lhs, typename F>
inline behavior operator,(const match_expr<Lhs...>& lhs,
const timeout_definition<F>& rhs) {
......
......@@ -32,6 +32,9 @@
#define BEHAVIOR_IMPL_HPP
#include "cppa/ref_counted.hpp"
#include "cppa/intrusive_ptr.hpp"
#include "cppa/timeout_definition.hpp"
#include "cppa/util/duration.hpp"
namespace cppa { namespace detail {
......@@ -56,6 +59,38 @@ class behavior_impl : public ref_counted {
return m_timeout;
}
typedef intrusive_ptr<behavior_impl> pointer;
virtual pointer copy(const generic_timeout_definition& tdef) const = 0;
inline pointer or_else(const pointer& other) {
CPPA_REQUIRE(other != nullptr);
struct combinator : behavior_impl {
pointer first;
pointer second;
bool invoke(any_tuple& arg) {
return first->invoke(arg) || second->invoke(arg);
}
bool invoke(const any_tuple& arg) {
return first->invoke(arg) || second->invoke(arg);
}
bool defined_at(const any_tuple& arg) {
return first->defined_at(arg) || second->defined_at(arg);
}
void handle_timeout() {
// the second behavior overrides the timeout handling of
// first behavior
return second->handle_timeout();
}
pointer copy(const generic_timeout_definition& tdef) const {
return new combinator(first, second->copy(tdef));
}
combinator(const pointer& p0, const pointer& p1)
: behavior_impl(p1->timeout()), first(p0), second(p1) { }
};
return new combinator(this, other);
}
private:
util::duration m_timeout;
......@@ -94,6 +129,11 @@ class default_behavior_impl : public behavior_impl {
return m_expr.can_invoke(tup);
}
typename behavior_impl::pointer copy(const generic_timeout_definition& tdef) const {
return new default_behavior_impl<MatchExpr,std::function<void()> >(m_expr, tdef);
}
void handle_timeout() { m_fun(); }
private:
......
......@@ -33,7 +33,6 @@
#include "cppa/option.hpp"
#include "cppa/guard_expr.hpp"
#include "cppa/partial_function.hpp"
#include "cppa/tpartial_function.hpp"
#include "cppa/util/rm_ref.hpp"
......@@ -49,6 +48,7 @@
#include "cppa/detail/projection.hpp"
#include "cppa/detail/value_guard.hpp"
#include "cppa/detail/pseudo_tuple.hpp"
#include "cppa/detail/behavior_impl.hpp"
namespace cppa { namespace detail {
......@@ -733,14 +733,14 @@ class match_expr {
bool defined_at(const any_tuple& tup) {
return pfun.can_invoke(tup);
}
typedef typename detail::behavior_impl::pointer pointer;
pointer copy(const generic_timeout_definition& tdef) const {
return new_default_behavior_impl(pfun, tdef.timeout, tdef.handler);
}
};
inline partial_function as_partial_function() const {
return {partial_function::impl_ptr{new pfun_impl(*this)}};
}
inline operator partial_function() const {
return as_partial_function();
intrusive_ptr<detail::behavior_impl> as_behavior_impl() const {
return new pfun_impl(*this);
}
private:
......
......@@ -36,6 +36,7 @@
#include <memory>
#include <utility>
#include "cppa/behavior.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/ref_counted.hpp"
#include "cppa/intrusive_ptr.hpp"
......@@ -67,6 +68,10 @@ class partial_function {
partial_function& operator=(partial_function&&) = default;
partial_function& operator=(const partial_function&) = default;
template<typename... Cases>
partial_function(const match_expr<Cases...>& mexpr)
: m_impl(mexpr.as_behavior_impl()) { }
partial_function(impl_ptr ptr);
inline bool undefined() const {
......@@ -82,12 +87,54 @@ class partial_function {
return (m_impl) && m_impl->invoke(std::forward<T>(arg));
}
inline partial_function or_else(const partial_function& other) const {
return m_impl->or_else(other.m_impl);
}
inline behavior or_else(const behavior& other) const {
return behavior{m_impl->or_else(other.m_impl)};
}
template<typename F>
inline behavior or_else(const timeout_definition<F>& tdef) const {
generic_timeout_definition gtd{tdef.timeout, tdef.handler};
return behavior{m_impl->copy(gtd)};
}
template<typename... Cases>
inline partial_function or_else(const match_expr<Cases...>& mexpr) const {
return m_impl->or_else(mexpr.as_behavior_impl());
}
template<typename Arg0, typename Arg1, typename... Args>
typename util::if_else<
util::disjunction<
is_timeout_definition<Arg0>,
is_timeout_definition<Arg1>,
is_timeout_definition<Args>...>,
behavior,
util::wrapped<partial_function> >::type
or_else(const Arg0& arg0, const Arg1& arg1, const Args&... args) const {
return m_impl->or_else(match_expr_concat(arg0, arg1, args...));
}
private:
impl_ptr m_impl;
};
template<typename Arg0, typename... Args>
typename util::if_else<
util::disjunction<
is_timeout_definition<Arg0>,
is_timeout_definition<Args>...>,
behavior,
util::wrapped<partial_function> >::type
match_expr_convert(const Arg0& arg0, const Args&... args) {
return {match_expr_concat(arg0, args...)};
}
} // namespace cppa
#endif // CPPA_PARTIAL_FUNCTION_HPP
......@@ -31,6 +31,8 @@
#ifndef TIMEOUT_DEFINITION_HPP
#define TIMEOUT_DEFINITION_HPP
#include <functional>
#include "cppa/util/duration.hpp"
namespace cppa {
......@@ -47,6 +49,8 @@ struct is_timeout_definition : std::false_type { };
template<typename F>
struct is_timeout_definition<timeout_definition<F> > : std::true_type { };
typedef timeout_definition<std::function<void()> > generic_timeout_definition;
} // namespace cppa
#endif // TIMEOUT_DEFINITION_HPP
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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/>. *
\******************************************************************************/
#include "cppa/behavior.hpp"
#include "cppa/partial_function.hpp"
namespace cppa {
behavior::behavior(const partial_function& fun) : m_impl(fun.m_impl) { }
} // namespace cppa
......@@ -31,7 +31,6 @@
#include "cppa/to_string.hpp"
#include "cppa/config.hpp"
#include "cppa/behavior.hpp"
#include "cppa/partial_function.hpp"
namespace cppa {
......
......@@ -391,5 +391,30 @@ int main() {
cout << "success: " << success << endl;
cout << "check combined partial function matching" << endl;
std::string last_invoked_fun;
auto check = [&](partial_function& pf, const any_tuple& tup, const string& str) {
last_invoked_fun = "";
pf(tup);
CPPA_CHECK_EQUAL(str, last_invoked_fun);
};
partial_function pf0 = (
on<int,int>() >> [&] { last_invoked_fun = "<int,int>@1"; },
on<float>() >> [&] { last_invoked_fun = "<float>@2"; }
);
auto pf1 = pf0.or_else(
on<int,int>() >> [&] { last_invoked_fun = "<int,int>@3"; },
on<string>() >> [&] { last_invoked_fun = "<string>@4"; }
);
check(pf0, make_any_tuple(1, 2), "<int,int>@1");
check(pf1, make_any_tuple(1, 2), "<int,int>@1");
check(pf0, make_any_tuple("hi"), "");
check(pf1, make_any_tuple("hi"), "<string>@4");
return CPPA_TEST_RESULT;
}
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