Commit 86c82bfc authored by Dominik Charousset's avatar Dominik Charousset

forward results of pattern matching callbacks

this patch enhances the pattern matching of libcppa, i.e., the result
of invoked callbacks is forwarded to the caller
parent 399b1b84
......@@ -24,7 +24,7 @@ if (CMAKE_CXX_FLAGS)
else (CMAKE_CXX_FLAGS)
set(CXXFLAGS_PROVIDED false)
set(CMAKE_CXX_FLAGS "-std=c++11 -Wextra -Wall -pedantic")
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -ftemplate-backtrace-limit=0")
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g")
......
......@@ -107,6 +107,7 @@ cppa/mailbox_based.hpp
cppa/mailbox_element.hpp
cppa/match.hpp
cppa/match_expr.hpp
cppa/match_hint.hpp
cppa/memory_cached.hpp
cppa/memory_managed.hpp
cppa/message_future.hpp
......@@ -155,6 +156,7 @@ cppa/tpartial_function.hpp
cppa/tuple_cast.hpp
cppa/type_lookup_table.hpp
cppa/uniform_type_info.hpp
cppa/unit.hpp
cppa/util/abstract_uniform_type_info.hpp
cppa/util/algorithm.hpp
cppa/util/arg_match_t.hpp
......@@ -184,7 +186,6 @@ cppa/util/type_list.hpp
cppa/util/type_pair.hpp
cppa/util/type_traits.hpp
cppa/util/upgrade_lock_guard.hpp
cppa/util/void_type.hpp
cppa/util/wrapped.hpp
cppa/weak_intrusive_ptr.hpp
cppa/weak_ptr_anchor.hpp
......
......@@ -179,6 +179,12 @@ struct cow_tuple_from_type_list< util::type_list<Ts...> > {
typedef cow_tuple<Ts...> type;
};
template<typename T>
struct is_cow_tuple { static constexpr bool value = false; };
template<typename... Ts>
struct is_cow_tuple<cow_tuple<Ts...>> { static constexpr bool value = true; };
/**
* @ingroup CopyOnWrite
* @brief Gets a const-reference to the <tt>N</tt>th element of @p tup.
......
......@@ -98,8 +98,9 @@ class behavior_impl : public ref_counted {
};
struct dummy_match_expr {
inline bool invoke(const any_tuple&) { return false; }
inline bool can_invoke(const any_tuple&) { return false; }
inline optional_variant<void> invoke(const any_tuple&) const { return none; }
inline bool can_invoke(const any_tuple&) const { return false; }
inline optional_variant<void> operator()(const any_tuple&) const { return none; }
};
template<class MatchExpr, typename F>
......@@ -118,11 +119,11 @@ class default_behavior_impl : public behavior_impl {
: super(tout), m_expr(std::forward<Expr>(expr)), m_fun(f) { }
bool invoke(any_tuple& tup) {
return m_expr.invoke(tup);
return eval_res(m_expr(tup));
}
bool invoke(const any_tuple& tup) {
return m_expr.invoke(tup);
return eval_res(m_expr(tup));
}
bool defined_at(const any_tuple& tup) {
......@@ -137,8 +138,26 @@ class default_behavior_impl : public behavior_impl {
private:
MatchExpr m_expr;
F m_fun;
template<typename T>
typename std::enable_if<T::has_match_hint == true, bool>::type
eval_res(const T& res) {
if (res) {
if (res.template is<match_hint>()) {
return get<match_hint>(res) == match_hint::handle;
}
return true;
}
return false;
}
template<typename T>
typename std::enable_if<T::has_match_hint == false, bool>::type
eval_res(const T& res) {
return static_cast<bool>(res);
}
MatchExpr m_expr;
F m_fun;
};
......
......@@ -33,11 +33,11 @@
#include <memory>
#include "cppa/unit.hpp"
#include "cppa/anything.hpp"
#include "cppa/serializer.hpp"
#include "cppa/deserializer.hpp"
#include "cppa/util/void_type.hpp"
#include "cppa/util/type_traits.hpp"
#include "cppa/util/abstract_uniform_type_info.hpp"
......
......@@ -34,6 +34,7 @@
#include <stdexcept>
#include <type_traits>
#include "cppa/unit.hpp"
#include "cppa/none.hpp"
#define CPPA_OPTIONAL_VARIANT_DATA_CONCAT(x, y) x ## y
......@@ -54,19 +55,19 @@ template<typename T>
struct lift_void { typedef T type; };
template<>
struct lift_void<void> { typedef util::void_type type; };
struct lift_void<void> { typedef unit_t type; };
template<typename T>
struct unlift_void { typedef T type; };
template<>
struct unlift_void<util::void_type> { typedef void type; };
struct unlift_void<unit_t> { typedef void type; };
template<typename T0, typename T1 = util::void_type,
typename T2 = util::void_type, typename T3 = util::void_type,
typename T4 = util::void_type, typename T5 = util::void_type,
typename T6 = util::void_type, typename T7 = util::void_type,
typename T8 = util::void_type, typename T9 = util::void_type>
template<typename T0, typename T1 = unit_t,
typename T2 = unit_t, typename T3 = unit_t,
typename T4 = unit_t, typename T5 = unit_t,
typename T6 = unit_t, typename T7 = unit_t,
typename T8 = unit_t, typename T9 = unit_t>
struct optional_variant_data {
union {
......
......@@ -68,6 +68,11 @@ struct collected_args_tuple {
type;
};
template<typename Fun>
struct is_void_fun {
static constexpr bool value = std::is_same<typename Fun::result_type, void>::value;
};
/**
* @brief Projection implemented by a set of functors.
*/
......@@ -90,6 +95,7 @@ class projection {
* @brief Invokes @p fun with a projection of <tt>args...</tt> and stores
* the result of @p fun in @p result.
*/
/*
template<class PartFun>
bool invoke(PartFun& fun, typename PartFun::result_type& result, Ts... args) const {
typename collected_args_tuple<ProjectionFuns, Ts...>::type pargs;
......@@ -102,35 +108,21 @@ class projection {
}
return false;
}
*/
/**
* @brief Invokes @p fun with a projection of <tt>args...</tt>.
*/
template<class PartFun>
bool operator()(PartFun& fun, Ts... args) const {
optional<typename PartFun::result_type> operator()(PartFun& fun, Ts... args) const {
typename collected_args_tuple<ProjectionFuns, Ts...>::type pargs;
auto indices = util::get_indices(pargs);
if (collect(pargs, m_funs, std::forward<Ts>(args)...)) {
if (is_defined_at(fun, pargs, indices)) {
util::apply_args(fun, pargs, indices);
return true;
return util::apply_args(fun, pargs, indices);
}
}
return false;
}
/**
* @brief Invokes @p fun with a projection of <tt>args...</tt> and stores
* the result of @p fun in @p result.
*/
template<class PartFun>
inline bool operator()(PartFun& fun, typename PartFun::result_type& result, Ts... args) const {
return invoke(fun, result, args...);
}
template<class PartFun>
inline bool operator()(PartFun& fun, const util::void_type&, Ts... args) const {
return (*this)(fun, args...);
return none;
}
private:
......@@ -151,7 +143,7 @@ class projection {
}
template<typename T>
static inline auto fetch(const util::void_type&, T&& arg)
static inline auto fetch(const unit_t&, T&& arg)
-> decltype(std::forward<T>(arg)) {
return std::forward<T>(arg);
}
......@@ -187,30 +179,11 @@ class projection<util::empty_type_list> {
projection(const projection&) = default;
template<class PartFun>
bool operator()(PartFun& fun) const {
if (fun.defined_at()) {
fun();
return true;
}
return false;
}
template<class PartFun>
bool operator()(PartFun& fun, const util::void_type&) const {
optional<typename PartFun::result_type> operator()(PartFun& fun) const {
if (fun.defined_at()) {
fun();
return true;
return fun();
}
return false;
}
template<class PartFun>
bool operator()(PartFun& fun, typename PartFun::result_type& res) const {
if (fun.defined_at()) {
res = fun();
return true;
}
return false;
return none;
}
};
......
......@@ -36,6 +36,7 @@
#include <type_traits>
#include "cppa/get.hpp"
#include "cppa/unit.hpp"
#include "cppa/optional.hpp"
#include "cppa/util/wrapped.hpp"
......@@ -100,7 +101,7 @@ struct boxed_or_void {
};
template<>
struct boxed_or_void<util::void_type> {
struct boxed_or_void<unit_t> {
static constexpr bool value = true;
};
......@@ -130,18 +131,18 @@ struct tdata<> {
typedef tdata super;
util::void_type head;
unit_t head;
typedef util::void_type head_type;
typedef unit_t head_type;
typedef tdata<> tail_type;
typedef util::void_type back_type;
typedef unit_t back_type;
typedef util::empty_type_list types;
static constexpr size_t num_elements = 0;
constexpr tdata() { }
// swallow any number of additional boxed or void_type arguments silently
// swallow any number of additional boxed or unit_t arguments silently
template<typename... Ts>
tdata(Ts&&...) {
typedef util::type_list<typename util::rm_const_and_ref<Ts>::type...> incoming;
......
......@@ -40,6 +40,8 @@
#include "cppa/cppa_fwd.hpp"
#include "cppa/atom.hpp"
#include "cppa/unit.hpp"
#include "cppa/none.hpp"
#include "cppa/process_information.hpp"
#include "cppa/util/buffer.hpp"
......@@ -68,9 +70,9 @@ using mapped_type_list = util::type_list<
io::connection_handle,
message_header,
std::nullptr_t,
unit_t,
util::buffer,
util::duration,
util::void_type,
double,
float,
long double,
......
......@@ -33,7 +33,7 @@
#include <type_traits>
#include "cppa/util/void_type.hpp"
#include "cppa/unit.hpp"
#include "cppa/util/type_list.hpp"
#include "cppa/util/type_traits.hpp"
......@@ -47,13 +47,13 @@ const T& vg_fwd(const T& arg, typename std::enable_if<not util::is_callable<T>::
return arg;
}
inline util::void_type vg_fwd(const anything&) {
return {};
inline unit_t vg_fwd(const anything&) {
return unit;
}
template<typename T>
util::void_type vg_fwd(const T&, typename std::enable_if<util::is_callable<T>::value>::type* = 0) {
return {};
unit_t vg_fwd(const T&, typename std::enable_if<util::is_callable<T>::value>::type* = 0) {
return unit;
}
template<typename T>
......@@ -65,9 +65,9 @@ struct vg_cmp {
};
template<>
struct vg_cmp<util::void_type> {
struct vg_cmp<unit_t> {
template<typename T>
inline static bool _(const util::void_type&, const T&) {
inline static bool _(const unit_t&, const T&) {
return true;
}
};
......@@ -102,7 +102,7 @@ class value_guard {
return vg_cmp<T>::_(lhs, rhs.get());
}
static inline bool _eval(const util::void_type&, const tdata<>&) {
static inline bool _eval(const unit_t&, const tdata<>&) {
return true;
}
......
......@@ -37,11 +37,11 @@
#include <functional>
#include <type_traits>
#include "cppa/unit.hpp"
#include "cppa/config.hpp"
#include "cppa/optional.hpp"
#include "cppa/util/call.hpp"
#include "cppa/util/void_type.hpp"
#include "cppa/util/type_traits.hpp"
#include "cppa/util/rebindable_reference.hpp"
......@@ -168,8 +168,8 @@ typename gcall3<Fun, T1, T2, T3>::result gcall(Fun fun, T1 t1, T2 t2, T3 t3) {
* The functor @p fun must return a boolean.
*/
template<typename Fun>
guard_expr<exec_xfun_op, Fun, util::void_type> ge_sub_function(Fun fun) {
return {fun, util::void_type{}};
guard_expr<exec_xfun_op, Fun, unit_t> ge_sub_function(Fun fun) {
return {fun, unit};
}
struct ge_search_container {
......@@ -449,7 +449,7 @@ struct ge_result_<guard_expr<OP, First, Second>, Tuple> {
};
template<typename Fun, class Tuple>
struct ge_result_<guard_expr<exec_xfun_op, Fun, util::void_type>, Tuple> {
struct ge_result_<guard_expr<exec_xfun_op, Fun, unit_t>, Tuple> {
typedef bool type;
};
......@@ -574,8 +574,8 @@ struct ge_eval_<logical_or_op, Tuple, First, Second> {
};
template<class Tuple, typename Fun>
struct ge_eval_<exec_xfun_op, Tuple, Fun, util::void_type> {
static inline bool _(const Tuple& tup, const Fun& fun, const util::void_type&) {
struct ge_eval_<exec_xfun_op, Tuple, Fun, unit_t> {
static inline bool _(const Tuple& tup, const Fun& fun, const unit_t&) {
return util::apply_args(fun, tup, util::get_indices(tup));
}
};
......
......@@ -37,6 +37,7 @@
#include <type_traits>
#include "cppa/any_tuple.hpp"
#include "cppa/match_hint.hpp"
#include "cppa/match_expr.hpp"
#include "cppa/partial_function.hpp"
......@@ -147,23 +148,15 @@ struct unwind_and_call {
typedef unwind_and_call<N+1, Size> next;
template<class Target, typename T, typename... Unwinded>
static inline bool _(Target& target, std::vector<T>& vec, Unwinded&&... args) {
return next::_(target, vec, std::forward<Unwinded>(args)..., vec[N]);
}
template<class Target, typename T, typename... Unwinded>
static inline bool _(Target& target, bool& sub_result, std::vector<T>& vec, Unwinded&&... args) {
return next::_(target, sub_result, vec, std::forward<Unwinded>(args)..., vec[N]);
static inline bool _(Target& target, bool& skipped, std::vector<T>& vec, Unwinded&&... args) {
return next::_(target, skipped, vec, std::forward<Unwinded>(args)..., vec[N]);
}
template<typename T, typename InputIterator, class MatchExpr>
static inline bool _(std::vector<T>& vec, InputIterator& pos, InputIterator end, MatchExpr& ex) {
bool match_returned_false = false;
if (run_case(vec, match_returned_false, pos, end, get<N>(ex.cases())) == 0) {
if (match_returned_false) {
return false;
}
return next::_(vec, pos, end, ex);
bool skipped = false;
if (run_case(vec, skipped, pos, end, get<N>(ex.cases())) == 0) {
return (skipped) ? false : next::_(vec, pos, end, ex);
}
return true;
}
......@@ -173,14 +166,25 @@ struct unwind_and_call {
template<size_t Size>
struct unwind_and_call<Size, Size> {
template<class Target, typename T, typename... Unwinded>
static inline bool _(Target& target, std::vector<T>&, Unwinded&&... args) {
return target.first(target.second, std::forward<Unwinded>(args)...);
template<typename T>
static inline bool eval_res(const optional<T>& res, bool&) {
return static_cast<bool>(res);
}
static inline bool eval_res(const optional<match_hint>& res, bool& skipped) {
if (res) {
if (*res == match_hint::skip) {
skipped = true;
return false;
}
return true;
}
return false;
}
template<class Target, typename T, typename... Unwinded>
static inline bool _(Target& target, bool& sub_result, std::vector<T>&, Unwinded&&... args) {
return target.first.invoke(target.second, sub_result, std::forward<Unwinded>(args)...);
static inline bool _(Target& target, bool& skipped, std::vector<T>&, Unwinded&&... args) {
return eval_res(target.first(target.second, std::forward<Unwinded>(args)...), skipped);
}
template<typename T, typename... Ts>
......@@ -188,33 +192,15 @@ struct unwind_and_call<Size, Size> {
};
template<bool EvaluateSubResult> // default = false
struct run_case_impl {
template<class Case, typename T>
static inline bool _(Case& target, std::vector<T>& vec, bool&) {
return unwind_and_call<0, util::tl_size<typename Case::pattern_type>::value>::_(target, vec);
}
};
template<>
struct run_case_impl<true> {
template<class Case, typename T>
static inline bool _(Case& target, std::vector<T>& vec, bool& match_returned_false) {
bool sub_result;
if (unwind_and_call<0, util::tl_size<typename Case::pattern_type>::value>::_(target, sub_result, vec)) {
if (sub_result == false) {
match_returned_false = true;
}
return true;
}
return false;
}
};
template<class Case, typename T>
inline bool run_case_impl(Case& target, std::vector<T>& vec, bool& skipped) {
return unwind_and_call<0, util::tl_size<typename Case::pattern_type>::value>::_(target, skipped, vec);
}
// Case is a projection_partial_function_pair
template<typename T, typename InputIterator, class Case>
size_t run_case(std::vector<T>& vec,
bool& match_returned_false,
bool& skipped,
InputIterator& pos,
const InputIterator& end,
Case& target) {
......@@ -234,7 +220,7 @@ size_t run_case(std::vector<T>& vec,
}
vec.emplace_back(*pos++);
}
if (run_case_impl<std::is_same<result_type, bool>::value>::_(target, vec, match_returned_false)) {
if (run_case_impl(target, vec, skipped)) {
if (vec.size() == num_args) {
vec.clear();
}
......@@ -242,7 +228,7 @@ size_t run_case(std::vector<T>& vec,
auto i = vec.begin();
vec.erase(i, i + num_args);
}
return match_returned_false ? 0 : num_args;
return skipped ? 0 : num_args;
}
return 0;
}
......
This diff is collapsed.
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* 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 2.1 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 CPPA_MATCH_HINT_HPP
#define CPPA_MATCH_HINT_HPP
namespace cppa {
/**
* @brief Optional return type for functors used in pattern matching
* expressions. This type is evaluated by the runtime system of libcppa
* and can be used to intentionally skip messages.
*/
enum class match_hint {
skip,
handle
};
} // namespace cppa
#endif // CPPA_MATCH_HINT_HPP
......@@ -142,9 +142,9 @@ class message_future {
template<typename... Fs>
behavior fs2bhvr(Fs... fs) {
auto handle_sync_timeout = []() -> bool {
auto handle_sync_timeout = []() -> match_hint {
self->handle_sync_timeout();
return false;
return match_hint::skip;
};
return {
on(atom("EXITED"), val<std::uint32_t>) >> skip_message,
......
......@@ -95,7 +95,7 @@ class object {
/**
* @brief Creates an empty object.
* @post {type() == *uniform_typeid<util::void_type>()}
* @post {type() == *uniform_typeid<unit_t>()}
*/
object();
......
......@@ -35,11 +35,13 @@
#include <memory>
#include <type_traits>
#include "cppa/unit.hpp"
#include "cppa/atom.hpp"
#include "cppa/anything.hpp"
#include "cppa/behavior.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/guard_expr.hpp"
#include "cppa/match_hint.hpp"
#include "cppa/match_expr.hpp"
#include "cppa/partial_function.hpp"
......@@ -65,7 +67,7 @@ template<typename T>
struct add_ptr_to_fun : add_ptr_to_fun_<std::is_function<T>::value, T> { };
template<bool ToVoid, typename T>
struct to_void_impl { typedef util::void_type type; };
struct to_void_impl { typedef unit_t type; };
template<typename T>
struct to_void_impl<false, T> { typedef typename add_ptr_to_fun<T>::type type; };
......@@ -138,19 +140,16 @@ struct rvalue_builder {
template<typename... Ts>
rvalue_builder(rvalue_builder_args_ctor, const Ts&... args)
: m_guard(args...)
, m_funs(args...) {
}
: m_guard(args...), m_funs(args...) { }
rvalue_builder(Guard arg0, fun_container arg1)
: m_guard(std::move(arg0)), m_funs(std::move(arg1)) {
}
: m_guard(std::move(arg0)), m_funs(std::move(arg1)) { }
template<typename NewGuard>
rvalue_builder<
guard_expr<
logical_and_op,
guard_expr<exec_xfun_op, Guard, util::void_type>,
guard_expr<exec_xfun_op, Guard, unit_t>,
NewGuard>,
Transformers,
Pattern>
......@@ -228,6 +227,11 @@ namespace cppa {
*/
constexpr anything any_vals = anything{};
/**
* @brief Returns {@link match_hint skipped}.
*/
match_hint skip_message();
#ifdef CPPA_DOCUMENTATION
/**
......@@ -244,11 +248,6 @@ constexpr __unspecified__ arg_match;
*/
constexpr __unspecified__ on_arg_match;
/**
* @brief Right-hand side expression to *not* match a particular pattern.
*/
constexpr __unspecified__ skip_message;
/**
* @brief A wildcard that matches any value of type @p T.
* @see {@link math_actor_example.cpp Math Actor Example}
......@@ -286,8 +285,6 @@ __unspecified__ on();
#else
bool skip_message();
template<typename T>
constexpr typename detail::boxed<T>::type val() {
return typename detail::boxed<T>::type();
......
......@@ -35,6 +35,7 @@
#include <utility>
#include "cppa/none.hpp"
#include "cppa/unit.hpp"
#include "cppa/config.hpp"
namespace cppa {
......@@ -122,6 +123,8 @@ class optional {
*/
inline bool operator!() const { return empty(); }
inline bool operator==(const none_t&) { return empty(); }
/**
* @brief Returns the value.
*/
......@@ -208,6 +211,8 @@ class optional<T&> {
inline bool operator!() const { return empty(); }
inline bool operator==(const none_t&) { return empty(); }
inline T& operator*() {
CPPA_REQUIRE(valid());
return *m_value;
......@@ -242,7 +247,9 @@ class optional<T&> {
template<>
class optional<void> {
optional() : m_valid(true) { }
public:
optional(const unit_t&) : m_valid(true) { }
optional(const none_t&) : m_valid(false) { }
......@@ -254,6 +261,10 @@ class optional<void> {
inline bool operator!() const { return empty(); }
inline bool operator==(const none_t&) { return empty(); }
inline const unit_t& operator*() const { return unit; }
private:
bool m_valid;
......
......@@ -35,9 +35,11 @@
#include <type_traits>
#include "cppa/none.hpp"
#include "cppa/unit.hpp"
#include "cppa/optional.hpp"
#include "cppa/match_hint.hpp"
#include "cppa/util/type_list.hpp"
#include "cppa/util/void_type.hpp"
#include "cppa/util/type_traits.hpp"
#include "cppa/detail/optional_variant_data.hpp"
......@@ -55,6 +57,45 @@ constexpr std::integral_constant<int, Value> make_int_token() { return {}; }
template<bool Value>
constexpr std::integral_constant<bool, Value> make_bool_token() { return {}; }
template<typename T>
struct optional_variant_copy_helper {
T& lhs;
optional_variant_copy_helper(T& lhs_ref) : lhs(lhs_ref) { }
template<typename U>
inline void operator()(const U& rhs) const {
lhs = rhs;
}
inline void operator()() const {
lhs = unit;
}
};
template<typename T>
struct optional_variant_move_helper {
T& lhs;
optional_variant_move_helper(T& lhs_ref) : lhs(lhs_ref) { }
template<typename U>
inline void operator()(const U& rhs) const {
lhs = std::move(rhs);
}
inline void operator()() const {
lhs = unit;
}
};
template<typename... Ts>
class optional_variant;
template<typename T>
struct is_optional_variant {
static constexpr bool value = false;
};
template<typename... Ts>
struct is_optional_variant<optional_variant<Ts...>> {
static constexpr bool value = true;
};
/**
* @brief A optional_variant is either invalid or holds
a value of one of the types <tt>Ts</tt>.
......@@ -68,6 +109,8 @@ class optional_variant {
static constexpr int void_pos = util::tl_find<types, void>::value;
static constexpr bool has_match_hint = util::tl_find<types, match_hint>::value != -1;
/**
* @brief Checks whether this objects holds a value of type @p T.
*/
......@@ -83,6 +126,20 @@ class optional_variant {
return *this;
}
optional_variant& operator=(const optional_variant& other) {
destroy_data();
optional_variant_copy_helper<optional_variant> helper{*this};
other.apply(helper);
return *this;
}
optional_variant& operator=(optional_variant&& other) {
destroy_data();
optional_variant_move_helper<optional_variant> helper{*this};
other.apply(helper);
return *this;
}
optional_variant() : m_type(-1) { }
template<typename U>
......@@ -90,6 +147,16 @@ class optional_variant {
set(std::forward<U>(arg));
}
optional_variant(const optional_variant& other) : m_type(-1) {
optional_variant_copy_helper<optional_variant> helper{*this};
other.apply(helper);
}
optional_variant(optional_variant&& other) : m_type(-1) {
optional_variant_move_helper<optional_variant> helper{*this};
other.apply(helper);
}
~optional_variant() {
destroy_data();
}
......@@ -197,7 +264,9 @@ class optional_variant {
template<typename U>
typename std::enable_if<
!std::is_same<typename util::rm_const_and_ref<U>::type, none_t>::value
!std::is_same<typename util::rm_const_and_ref<U>::type, none_t>::value
&& !is_optional_variant<typename util::rm_const_and_ref<U>::type>::value
&& !is_optional<typename util::rm_const_and_ref<U>::type>::value
>::type
set(U&& arg) {
typedef typename util::rm_const_and_ref<U>::type stripped_type;
......@@ -209,6 +278,28 @@ class optional_variant {
new (&ref) stripped_type (std::forward<U>(arg));
}
inline void set(const optional_variant& other) {
optional_variant_copy_helper<optional_variant> helper{*this};
other.apply(helper);
}
inline void set(optional_variant&& other) {
optional_variant_move_helper<optional_variant> helper{*this};
other.apply(helper);
}
template<typename T>
inline void set(const optional<T>& arg) {
if (arg) set(*arg);
else set(none);
}
template<typename T>
inline void set(optional<T>&& arg) {
if (arg) set(std::move(*arg));
else set(none);
}
inline void set(const none_t&) { m_type = -1; }
int m_type;
......@@ -250,6 +341,14 @@ auto apply_visitor(const Visitor& visitor, optional_variant<Ts...>& data) -> dec
return data.apply(visitor);
}
template<typename T>
struct optional_variant_from_type_list;
template<typename... Ts>
struct optional_variant_from_type_list<util::type_list<Ts...>> {
typedef optional_variant<Ts...> type;
};
} // namespace cppa
#endif // OPTIONAL_VARIANT_HPP
......@@ -34,6 +34,10 @@
#include <cstddef>
#include <type_traits>
#include "cppa/none.hpp"
#include "cppa/unit.hpp"
#include "cppa/optional.hpp"
#include "cppa/util/call.hpp"
#include "cppa/util/type_list.hpp"
#include "cppa/util/type_traits.hpp"
......@@ -41,6 +45,28 @@
namespace cppa {
template<typename Result, typename... Ts>
struct tpartial_function_helper {
template<typename Fun>
inline optional<Result> operator()(const Fun& fun, Ts... args) {
if (fun.defined_at(args...)) return fun.invoke(args...);
return none;
}
};
template<typename... Ts>
struct tpartial_function_helper<void, Ts...> {
template<typename Fun>
inline optional<void> operator()(const Fun& fun, Ts... args) {
if (fun.defined_at(args...)) {
fun.invoke(args...);
return unit;
}
return none;
}
};
template<class Expr, class Guard, typename Result, typename... Ts>
class tpartial_function {
......@@ -76,16 +102,24 @@ class tpartial_function {
tpartial_function(const tpartial_function&) = default;
bool defined_at(Ts... args) const {
inline bool defined_at(Ts... args) const {
return m_guard(args...);
}
result_type operator()(Ts... args) const {
/**
* @brief Invokes the function without evaluating the guard.
*/
result_type invoke(Ts... args) const {
auto targs = std::forward_as_tuple(args...);
auto indices = util::get_right_indices<num_expr_args>(targs);
return util::apply_args(m_expr, targs, indices);
}
inline optional<result_type> operator()(Ts... args) const {
tpartial_function_helper<result_type, Ts...> helper;
return helper(*this, args...);
}
private:
Guard m_guard;
......@@ -94,7 +128,7 @@ class tpartial_function {
};
template<class Expr, class Guard, typename Ts,
typename Result = util::void_type, size_t Step = 0>
typename Result = unit_t, size_t Step = 0>
struct get_tpartial_function;
template<class Expr, class Guard, typename... Ts, typename Result>
......@@ -104,7 +138,7 @@ struct get_tpartial_function<Expr, Guard, util::type_list<Ts...>, Result, 1> {
template<class Expr, class Guard, typename... Ts>
struct get_tpartial_function<Expr, Guard,
util::type_list<Ts...>, util::void_type, 0> {
util::type_list<Ts...>, unit_t, 0> {
typedef typename util::get_callable_trait<Expr>::type ctrait;
typedef typename ctrait::arg_types arg_types;
......
......@@ -28,19 +28,18 @@
\******************************************************************************/
#ifndef CPPA_UTIL_VOID_TYPE_HPP
#define CPPA_UTIL_VOID_TYPE_HPP
#ifndef CPPA_UNIT_HPP
#define CPPA_UNIT_HPP
namespace cppa { namespace util {
namespace cppa {
struct void_type {
constexpr void_type() { }
constexpr void_type(const void_type&) { }
// anything could be used to initialize a void...
template<typename Arg>
constexpr void_type(const Arg&) { }
struct unit_t {
constexpr unit_t() { }
template<typename T> constexpr unit_t(T&&) { }
};
} } // namespace cppa::util
static constexpr unit_t unit = unit_t{};
#endif // CPPA_UTIL_VOID_TYPE_HPP
} // namespace cppa
#endif // CPPA_UNIT_HPP
......@@ -31,12 +31,12 @@
#ifndef CPPA_LEFT_OR_RIGHT_HPP
#define CPPA_LEFT_OR_RIGHT_HPP
#include "cppa/util/void_type.hpp"
#include "cppa/unit.hpp"
namespace cppa { namespace util {
/**
* @brief Evaluates to @p Right if @p Left == void_type, @p Left otherwise.
* @brief Evaluates to @p Right if @p Left == unit_t, @p Left otherwise.
*/
template<typename Left, typename Right>
struct left_or_right {
......@@ -44,30 +44,30 @@ struct left_or_right {
};
template<typename Right>
struct left_or_right<util::void_type, Right> {
struct left_or_right<unit_t, Right> {
typedef Right type;
};
template<typename Right>
struct left_or_right<util::void_type&, Right> {
struct left_or_right<unit_t&, Right> {
typedef Right type;
};
template<typename Right>
struct left_or_right<const util::void_type&, Right> {
struct left_or_right<const unit_t&, Right> {
typedef Right type;
};
/**
* @brief Evaluates to @p Right if @p Left != void_type, @p void_type otherwise.
* @brief Evaluates to @p Right if @p Left != unit_t, @p unit_t otherwise.
*/
template<typename Left, typename Right>
struct if_not_left {
typedef void_type type;
typedef unit_t type;
};
template<typename Right>
struct if_not_left<util::void_type, Right> {
struct if_not_left<unit_t, Right> {
typedef Right type;
};
......
......@@ -34,9 +34,10 @@
#include <typeinfo>
#include <type_traits>
#include "cppa/unit.hpp"
#include "cppa/util/tbind.hpp"
#include "cppa/util/type_pair.hpp"
#include "cppa/util/void_type.hpp"
namespace cppa {
......@@ -135,7 +136,7 @@ struct tl_back;
template<template<typename...> class List>
struct tl_back<List<>> {
typedef void_type type;
typedef unit_t type;
};
template<template<typename...> class List, typename T0>
......@@ -212,7 +213,7 @@ struct tl_slice_impl<0, 0, PadType, empty_type_list, T...> {
};
template<class List, size_t ListSize, size_t First, size_t Last,
typename PadType = void_type>
typename PadType = unit_t>
struct tl_slice_ {
typedef typename tl_slice_impl<
First, (Last - First),
......@@ -274,8 +275,8 @@ struct tl_zip {
template<class ListA,
class ListB,
typename PadA = void_type,
typename PadB = void_type,
typename PadA = unit_t,
typename PadB = unit_t,
template<typename, typename> class Fun = to_type_pair>
struct tl_zip_all {
static constexpr size_t result_size = (tl_size<ListA>::value > tl_size<ListB>::value) ? tl_size<ListA>::value
......@@ -863,7 +864,7 @@ struct tl_pad_right_impl<List, true, OldSize, NewSize, FillType> {
* @brief Resizes the list to contain @p NewSize elements and uses
* @p FillType to initialize the new elements with.
*/
template<class List, size_t NewSize, typename FillType = void_type>
template<class List, size_t NewSize, typename FillType = unit_t>
struct tl_pad_right {
typedef typename tl_pad_right_impl<
List, (tl_size<List>::value < NewSize), tl_size<List>::value, NewSize, FillType
......@@ -893,7 +894,7 @@ struct tl_pad_left_impl<List, Size, Size, FillType> {
* @brief Resizes the list to contain @p NewSize elements and uses
* @p FillType to initialize prepended elements with.
*/
template<class List, size_t NewSize, typename FillType = void_type>
template<class List, size_t NewSize, typename FillType = unit_t>
struct tl_pad_left {
static constexpr size_t list_size = tl_size<List>::value;
//static_assert(NewSize >= tl_size<List>::value, "List too big");
......@@ -915,7 +916,7 @@ struct tl_is_zipped {
/**
* @brief Removes trailing @p What elements from the end.
*/
template<class List, typename What = void_type>
template<class List, typename What = unit_t>
struct tl_trim {
typedef typename std::conditional<
std::is_same<typename tl_back<List>::type, What>::value,
......
......@@ -445,12 +445,12 @@ struct map_to_result_type_impl {
template<typename C>
struct map_to_result_type_impl<false, C> {
typedef void_type type;
typedef unit_t type;
};
/**
* @brief Maps @p T to its result type if it's callable,
* {@link void_type} otherwise.
* {@link unit_t} otherwise.
*/
template<typename T>
struct map_to_result_type {
......
......@@ -30,19 +30,19 @@
#include <algorithm>
#include "cppa/unit.hpp"
#include "cppa/config.hpp"
#include "cppa/object.hpp"
#include "cppa/uniform_type_info.hpp"
#include "cppa/util/void_type.hpp"
#include "cppa/detail/types_array.hpp"
namespace {
cppa::util::void_type s_void;
cppa::unit_t s_unit;
inline const cppa::uniform_type_info* tvoid() {
return cppa::detail::static_types_array<cppa::util::void_type>::arr[0];
inline const cppa::uniform_type_info* unit_type() {
return cppa::detail::static_types_array<cppa::unit_t>::arr[0];
}
} // namespace <anonymous>
......@@ -60,20 +60,20 @@ object::object(void* val, const uniform_type_info* utype)
CPPA_REQUIRE(utype != nullptr);
}
object::object() : m_value(&s_void), m_type(tvoid()) {
object::object() : m_value(&s_unit), m_type(unit_type()) {
}
object::~object() {
if (m_value != &s_void) m_type->delete_instance(m_value);
if (m_value != &s_unit) m_type->delete_instance(m_value);
}
object::object(const object& other) {
m_type = other.m_type;
m_value = (other.m_value == &s_void) ? other.m_value
m_value = (other.m_value == &s_unit) ? other.m_value
: m_type->new_instance(other.m_value);
}
object::object(object&& other) : m_value(&s_void), m_type(tvoid()) {
object::object(object&& other) : m_value(&s_unit), m_type(unit_type()) {
swap(other);
}
......
......@@ -31,6 +31,8 @@
namespace cppa {
bool skip_message() { return false; }
match_hint skip_message() {
return match_hint::skip;
}
} // namespace cppa
......@@ -45,8 +45,6 @@
#include "cppa/any_tuple.hpp"
#include "cppa/message_header.hpp"
#include "cppa/util/void_type.hpp"
#include "cppa/detail/demangle.hpp"
#include "cppa/detail/to_uniform_name.hpp"
#include "cppa/detail/singleton_manager.hpp"
......
......@@ -52,7 +52,6 @@
#include "cppa/uniform_type_info.hpp"
#include "cppa/util/duration.hpp"
#include "cppa/util/void_type.hpp"
#include "cppa/detail/demangle.hpp"
#include "cppa/detail/actor_registry.hpp"
......
......@@ -68,9 +68,9 @@ namespace cppa { namespace detail {
{ "cppa::io::connection_handle", "@cn_hdl" },
{ "cppa::message_header", "@header" },
{ "cppa::nullptr_t", "@null" },
{ "cppa::unit_t", "@0" },
{ "cppa::util::buffer", "@buffer" },
{ "cppa::util::duration", "@duration" },
{ "cppa::util::void_type", "@0" },
{ "double", "double" },
{ "float", "float" },
{ "long double", "@ldouble" },
......@@ -126,7 +126,7 @@ const char* mapped_name_by_decorated_name(const char* cstr) {
namespace {
inline bool operator==(const util::void_type&, const util::void_type&) {
inline bool operator==(const unit_t&, const unit_t&) {
return true;
}
......@@ -154,9 +154,9 @@ inline void deserialize_impl(detail::handle<T>& hdl, deserializer* source) {
hdl = T::from_int(source->read<int32_t>());
}
inline void serialize_impl(const util::void_type&, serializer*) { }
inline void serialize_impl(const unit_t&, serializer*) { }
inline void deserialize_impl(util::void_type&, deserializer*) { }
inline void deserialize_impl(unit_t&, deserializer*) { }
void serialize_impl(const actor_ptr& ptr, serializer* sink) {
auto impl = sink->addressing();
......@@ -693,7 +693,7 @@ class utim_impl : public uniform_type_info_map {
intptr_t >(mapping);
// fill builtin types *in sorted order* (by uniform name)
size_t i = 0;
m_builtin_types[i++] = &m_type_void; // @0
m_builtin_types[i++] = &m_type_unit; // @0
m_builtin_types[i++] = &m_ac_hdl; // @ac_hdl
m_builtin_types[i++] = &m_type_actor; // @actor
m_builtin_types[i++] = &m_type_atom; // @atom
......@@ -824,7 +824,7 @@ class utim_impl : public uniform_type_info_map {
uti_impl<any_tuple> m_type_tuple;
uti_impl<util::duration> m_type_duration;
uti_impl<message_header> m_type_header;
uti_impl<util::void_type> m_type_void;
uti_impl<unit_t> m_type_unit;
uti_impl<atom_value> m_type_atom;
uti_impl<std::string> m_type_str;
uti_impl<std::u16string> m_type_u16str;
......
......@@ -442,17 +442,17 @@ int main() {
CPPA_CHECK(name == "foo" || name == "bar");
return name == "foo" || name == "bar";
},
on("-p", arg_match) >> [&](const string& port) -> bool {
on("-p", arg_match) >> [&](const string& port) -> match_hint {
auto i = toint(port);
if (i) {
CPPA_CHECK_EQUAL(*i, 2);
return true;
return match_hint::handle;
}
else return false;
else return match_hint::skip;
},
on_arg_match >> [](const string& arg) -> bool{
on_arg_match >> [](const string& arg) -> match_hint {
CPPA_FAILURE("unexpected string: " << arg);
return false;
return match_hint::skip;
}
);
CPPA_CHECK_EQUAL(success, true);
......@@ -491,9 +491,9 @@ int main() {
}
behavior bhvr1 = (
on<int>() >> [&](int i) -> bool {
on<int>() >> [&](int i) -> match_hint {
last_invoked_fun = "<int>@1";
return i != 42;
return (i == 42) ? match_hint::skip : match_hint::handle;
},
on<float>() >> [&] {
last_invoked_fun = "<float>@2";
......
......@@ -44,7 +44,7 @@ int main() {
using tri_type = optional_variant<void, int, double, float>;
tri_type t0;
tri_type t1{util::void_type{}};
tri_type t1{unit};
tri_type t2{0};
tri_type t3{0.0};
tri_type t4{0.0f};
......
......@@ -258,7 +258,7 @@ int main() {
self->on_sync_failure(CPPA_UNEXPECTED_MSG_CB());
timed_sync_send(c, std::chrono::milliseconds(500), atom("HiThere"))
.then(CPPA_FAILURE_CB("C replied to 'HiThere'!"))
.continue_with(CPPA_FAILURE_CB("bad continuation"));
.continue_with(CPPA_FAILURE_CB("continuation erroneously invoked"));
self->exec_behavior_stack();
CPPA_CHECK_EQUAL(timeout_occured, true);
self->on_sync_failure(CPPA_UNEXPECTED_MSG_CB());
......
......@@ -76,14 +76,16 @@ optional<int> str2int(const std::string& str) {
}
#define CPPA_CHECK_INVOKED(FunName, Args) \
if ( ( FunName Args ) == false || invoked != #FunName ) { \
invoked.clear(); \
if ( !( FunName Args ) || invoked != #FunName ) { \
CPPA_FAILURE("invocation of " #FunName " failed"); \
} invoked = ""
} else CPPA_CHECKPOINT()
#define CPPA_CHECK_NOT_INVOKED(FunName, Args) \
if ( ( FunName Args ) == true || invoked == #FunName ) { \
invoked.clear(); \
if ( FunName Args || invoked == #FunName ) { \
CPPA_FAILURE(#FunName " erroneously invoked"); \
} invoked = ""
} else CPPA_CHECKPOINT()
struct dummy_receiver : event_based_actor {
void init() {
......@@ -164,9 +166,9 @@ void check_guards() {
CPPA_CHECK_NOT_INVOKED(f02, (2, 1));
CPPA_CHECK_INVOKED(f02, (42, 21));
CPPA_CHECK(f02.invoke(make_cow_tuple(42, 21)));
CPPA_CHECK(f02(make_cow_tuple(42, 21)));
CPPA_CHECK_EQUAL(invoked, "f02");
invoked = "";
invoked.clear();
auto f03 = on(42, val<int>) >> [&](const int& a, int&) { invoked = "f03"; CPPA_CHECK_EQUAL(a, 42); };
CPPA_CHECK_NOT_INVOKED(f03, (0, 0));
......@@ -200,14 +202,14 @@ void check_guards() {
CPPA_CHECK_NOT_INVOKED(f07, (0));
CPPA_CHECK_NOT_INVOKED(f07, (1));
CPPA_CHECK_INVOKED(f07, (2));
CPPA_CHECK(f07.invoke(make_cow_tuple(2)));
CPPA_CHECK(f07(make_cow_tuple(2)));
int f08_val = 666;
auto f08 = on<int>() >> [&](int& mref) { mref = 8; invoked = "f08"; };
CPPA_CHECK_INVOKED(f08, (f08_val));
CPPA_CHECK_EQUAL(f08_val, 8);
any_tuple f08_any_val = make_cow_tuple(666);
CPPA_CHECK(f08.invoke(f08_any_val));
CPPA_CHECK(f08(f08_any_val));
CPPA_CHECK_EQUAL(f08_any_val.get_as<int>(0), 8);
int f09_val = 666;
......@@ -216,13 +218,13 @@ void check_guards() {
CPPA_CHECK_INVOKED(f09, ("0", f09_val));
CPPA_CHECK_EQUAL(f09_val, 9);
any_tuple f09_any_val = make_cow_tuple("0", 666);
CPPA_CHECK(f09.invoke(f09_any_val));
CPPA_CHECK(f09(f09_any_val));
CPPA_CHECK_EQUAL(f09_any_val.get_as<int>(1), 9);
f09_any_val.get_as_mutable<int>(1) = 666;
any_tuple f09_any_val_copy{f09_any_val};
CPPA_CHECK(f09_any_val.at(0) == f09_any_val_copy.at(0));
// detaches f09_any_val from f09_any_val_copy
CPPA_CHECK(f09.invoke(f09_any_val));
CPPA_CHECK(f09(f09_any_val));
CPPA_CHECK_EQUAL(f09_any_val.get_as<int>(1), 9);
CPPA_CHECK_EQUAL(f09_any_val_copy.get_as<int>(1), 666);
// no longer the same data
......
......@@ -74,7 +74,7 @@ int main() {
"@str", "@u16str", "@u32str", // strings
"@strmap", // string containers
"float", "double", "@ldouble", // floating points
"@0", // cppa::util::void_type
"@0", // cppa::util::unit_t
// default announced cppa types
"@ac_hdl", // io::accept_handle
"@cn_hdl", // io::connection_handle
......
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