Commit 49851bd0 authored by Dominik Charousset's avatar Dominik Charousset

`optional_variant<...>` => `variant<none_t, ...>`

This patch removes the weird `optional_variant` class from libcppa in favor of
a more general `variant` implementation that simply uses a `none_t` to indicate
a non-existing value.
parent bea4b168
...@@ -39,7 +39,6 @@ ...@@ -39,7 +39,6 @@
#include "cppa/to_string.hpp" #include "cppa/to_string.hpp"
#include "cppa/any_tuple.hpp" #include "cppa/any_tuple.hpp"
#include "cppa/cow_tuple.hpp" #include "cppa/cow_tuple.hpp"
#include "cppa/tuple_cast.hpp"
#include "cppa/singletons.hpp" #include "cppa/singletons.hpp"
#include "cppa/typed_actor.hpp" #include "cppa/typed_actor.hpp"
#include "cppa/exit_reason.hpp" #include "cppa/exit_reason.hpp"
......
...@@ -21,11 +21,12 @@ ...@@ -21,11 +21,12 @@
#define CPPA_DETAIL_BEHAVIOR_IMPL_HPP #define CPPA_DETAIL_BEHAVIOR_IMPL_HPP
#include "cppa/atom.hpp" #include "cppa/atom.hpp"
#include "cppa/variant.hpp"
#include "cppa/optional.hpp" #include "cppa/optional.hpp"
#include "cppa/any_tuple.hpp" #include "cppa/any_tuple.hpp"
#include "cppa/ref_counted.hpp" #include "cppa/ref_counted.hpp"
#include "cppa/skip_message.hpp"
#include "cppa/intrusive_ptr.hpp" #include "cppa/intrusive_ptr.hpp"
#include "cppa/optional_variant.hpp"
#include "cppa/timeout_definition.hpp" #include "cppa/timeout_definition.hpp"
#include "cppa/util/duration.hpp" #include "cppa/util/duration.hpp"
...@@ -47,9 +48,14 @@ template<class T> struct is_message_id_wrapper { ...@@ -47,9 +48,14 @@ template<class T> struct is_message_id_wrapper {
static constexpr bool value = sizeof(test<T>(0)) == 1; static constexpr bool value = sizeof(test<T>(0)) == 1;
}; };
struct optional_any_tuple_visitor { struct optional_any_tuple_visitor : static_visitor<bhvr_invoke_result> {
inline bhvr_invoke_result operator()() const { return any_tuple{}; } //inline bhvr_invoke_result operator()() const { return any_tuple{}; }
inline bhvr_invoke_result operator()(none_t&) const { return none; }
inline bhvr_invoke_result operator()(const none_t&) const { return none; } inline bhvr_invoke_result operator()(const none_t&) const { return none; }
inline bhvr_invoke_result operator()(skip_message_t&) const { return none; }
inline bhvr_invoke_result operator()(const skip_message_t&) const { return none; }
inline bhvr_invoke_result operator()(unit_t&) const { return any_tuple{}; }
inline bhvr_invoke_result operator()(const unit_t&) const { return any_tuple{}; }
template<typename T> template<typename T>
inline bhvr_invoke_result operator()(T& value, typename std::enable_if<not is_message_id_wrapper<T>::value>::type* = 0) const { inline bhvr_invoke_result operator()(T& value, typename std::enable_if<not is_message_id_wrapper<T>::value>::type* = 0) const {
return make_any_tuple(std::move(value)); return make_any_tuple(std::move(value));
...@@ -137,9 +143,9 @@ class behavior_impl : public ref_counted { ...@@ -137,9 +143,9 @@ class behavior_impl : public ref_counted {
}; };
struct dummy_match_expr { struct dummy_match_expr {
inline optional_variant<void> invoke(const any_tuple&) const { return none; } inline variant<none_t> invoke(const any_tuple&) const { return none; }
inline bool can_invoke(const any_tuple&) const { return false; } inline bool can_invoke(const any_tuple&) const { return false; }
inline optional_variant<void> operator()(const any_tuple&) const { return none; } inline variant<none_t> operator()(const any_tuple&) const { return none; }
}; };
template<class MatchExpr, typename F> template<class MatchExpr, typename F>
...@@ -158,11 +164,13 @@ class default_behavior_impl : public behavior_impl { ...@@ -158,11 +164,13 @@ class default_behavior_impl : public behavior_impl {
: super(tout), m_expr(std::forward<Expr>(expr)), m_fun(f) { } : super(tout), m_expr(std::forward<Expr>(expr)), m_fun(f) { }
bhvr_invoke_result invoke(any_tuple& tup) { bhvr_invoke_result invoke(any_tuple& tup) {
return eval_res(m_expr(tup)); auto res = m_expr(tup);
return apply_visitor(optional_any_tuple_visitor{}, res);
} }
bhvr_invoke_result invoke(const any_tuple& tup) { bhvr_invoke_result invoke(const any_tuple& tup) {
return eval_res(m_expr(tup)); auto res = m_expr(tup);
return apply_visitor(optional_any_tuple_visitor{}, res);
} }
bool defined_at(const any_tuple& tup) { bool defined_at(const any_tuple& tup) {
...@@ -177,24 +185,6 @@ class default_behavior_impl : public behavior_impl { ...@@ -177,24 +185,6 @@ class default_behavior_impl : public behavior_impl {
private: private:
template<typename... Ts>
typename std::enable_if<has_skip_message<Ts...>::value, bhvr_invoke_result>::type
eval_res(optional_variant<Ts...>&& res) {
if (res) {
if (res.template is<skip_message_t>()) {
return none;
}
return apply_visitor(optional_any_tuple_visitor{}, res);
}
return none;
}
template<typename... Ts>
typename std::enable_if<!has_skip_message<Ts...>::value, bhvr_invoke_result>::type
eval_res(optional_variant<Ts...>&& res) {
return apply_visitor(optional_any_tuple_visitor{}, res);
}
MatchExpr m_expr; MatchExpr m_expr;
F m_fun; F m_fun;
......
...@@ -17,68 +17,57 @@ ...@@ -17,68 +17,57 @@
\******************************************************************************/ \******************************************************************************/
#ifndef CPPA_DETAIL_OPTIONAL_VARIANT_DATA #ifndef CPPA_DETAIL_VARIANT_DATA_HPP
#define CPPA_DETAIL_OPTIONAL_VARIANT_DATA #define CPPA_DETAIL_VARIANT_DATA_HPP
#include <stdexcept> #include <stdexcept>
#include <type_traits> #include <type_traits>
#include "cppa/unit.hpp" #include "cppa/unit.hpp"
#include "cppa/none.hpp" #include "cppa/none.hpp"
#include "cppa/lift_void.hpp"
#define CPPA_OPTIONAL_VARIANT_DATA_CONCAT(x, y) x ## y #define CPPA_VARIANT_DATA_CONCAT(x, y) x ## y
#define CPPA_OPTIONAL_VARIANT_DATA_GETTER(pos) \ #define CPPA_VARIANT_DATA_GETTER(pos) \
inline CPPA_OPTIONAL_VARIANT_DATA_CONCAT(T, pos) & \ inline CPPA_VARIANT_DATA_CONCAT(T, pos) & \
get(std::integral_constant<int, pos >) { \ get(std::integral_constant<int, pos >) { \
return CPPA_OPTIONAL_VARIANT_DATA_CONCAT(v, pos) ; \ return CPPA_VARIANT_DATA_CONCAT(v, pos) ; \
} \ } \
inline const CPPA_OPTIONAL_VARIANT_DATA_CONCAT(T, pos) & \ inline const CPPA_VARIANT_DATA_CONCAT(T, pos) & \
get(std::integral_constant<int, pos >) const { \ get(std::integral_constant<int, pos >) const { \
return CPPA_OPTIONAL_VARIANT_DATA_CONCAT(v, pos) ; \ return CPPA_VARIANT_DATA_CONCAT(v, pos) ; \
} }
namespace cppa { namespace cppa {
namespace detail { namespace detail {
template<typename T>
struct lift_void { typedef T type; };
template<>
struct lift_void<void> { typedef unit_t type; };
template<typename T>
struct unlift_void { typedef T type; };
template<>
struct unlift_void<unit_t> { typedef void type; };
template<typename T0, typename T1 = unit_t, template<typename T0, typename T1 = unit_t,
typename T2 = unit_t, typename T3 = unit_t, typename T2 = unit_t, typename T3 = unit_t,
typename T4 = unit_t, typename T5 = unit_t, typename T4 = unit_t, typename T5 = unit_t,
typename T6 = unit_t, typename T7 = unit_t, typename T6 = unit_t, typename T7 = unit_t,
typename T8 = unit_t, typename T9 = unit_t> typename T8 = unit_t, typename T9 = unit_t>
struct optional_variant_data { struct variant_data {
union { union {
T0 v0; T1 v1; T2 v2; T3 v3; T4 v4; T0 v0; T1 v1; T2 v2; T3 v3; T4 v4;
T5 v5; T6 v6; T7 v7; T8 v8; T9 v9; T5 v5; T6 v6; T7 v7; T8 v8; T9 v9;
}; };
optional_variant_data() { } variant_data() { }
~optional_variant_data() { } ~variant_data() { }
CPPA_OPTIONAL_VARIANT_DATA_GETTER(0) CPPA_VARIANT_DATA_GETTER(0)
CPPA_OPTIONAL_VARIANT_DATA_GETTER(1) CPPA_VARIANT_DATA_GETTER(1)
CPPA_OPTIONAL_VARIANT_DATA_GETTER(2) CPPA_VARIANT_DATA_GETTER(2)
CPPA_OPTIONAL_VARIANT_DATA_GETTER(3) CPPA_VARIANT_DATA_GETTER(3)
CPPA_OPTIONAL_VARIANT_DATA_GETTER(4) CPPA_VARIANT_DATA_GETTER(4)
CPPA_OPTIONAL_VARIANT_DATA_GETTER(5) CPPA_VARIANT_DATA_GETTER(5)
CPPA_OPTIONAL_VARIANT_DATA_GETTER(6) CPPA_VARIANT_DATA_GETTER(6)
CPPA_OPTIONAL_VARIANT_DATA_GETTER(7) CPPA_VARIANT_DATA_GETTER(7)
CPPA_OPTIONAL_VARIANT_DATA_GETTER(8) CPPA_VARIANT_DATA_GETTER(8)
CPPA_OPTIONAL_VARIANT_DATA_GETTER(9) CPPA_VARIANT_DATA_GETTER(9)
private: private:
...@@ -89,7 +78,7 @@ struct optional_variant_data { ...@@ -89,7 +78,7 @@ struct optional_variant_data {
}; };
struct optional_variant_data_destructor { struct variant_data_destructor {
inline void operator()() const { } inline void operator()() const { }
inline void operator()(const none_t&) const { } inline void operator()(const none_t&) const { }
template<typename T> template<typename T>
...@@ -99,4 +88,4 @@ struct optional_variant_data_destructor { ...@@ -99,4 +88,4 @@ struct optional_variant_data_destructor {
} // namespace detail } // namespace detail
} // namespace cppa } // namespace cppa
#endif // CPPA_DETAIL_OPTIONAL_VARIANT_DATA #endif // CPPA_DETAIL_VARIANT_DATA_HPP
...@@ -658,28 +658,6 @@ struct ge_invoke_helper { ...@@ -658,28 +658,6 @@ struct ge_invoke_helper {
} }
}; };
template<typename TupleTypes, operator_id OP, typename First, typename Second>
typename ge_result<
OP, First, Second,
typename detail::tdata_from_type_list<
typename util::tl_filter_not<TupleTypes, is_anything>::type
>::type
>::type
ge_invoke_any(const guard_expr<OP, First, Second>& ge,
const any_tuple& tup) {
using namespace util;
typename std::conditional<
std::is_same<typename TupleTypes::back, anything>::value,
TupleTypes,
wrapped<typename tl_push_back<TupleTypes, anything>::type>
>::type
cast_token;
auto x = tuple_cast(tup, cast_token);
CPPA_REQUIRE(static_cast<bool>(x) == true);
ge_invoke_helper<guard_expr<OP, First, Second> > f{ge};
return util::apply_args(f, *x, util::get_indices(*x));
}
template<operator_id OP, typename First, typename Second> template<operator_id OP, typename First, typename Second>
template<typename... Ts> template<typename... Ts>
bool guard_expr<OP, First, Second>::operator()(const Ts&... args) const { bool guard_expr<OP, First, Second>::operator()(const Ts&... args) const {
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011 - 2014 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the Boost Software License, Version 1.0. See *
* accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt *
\******************************************************************************/
#ifndef CPPA_LIFT_VOID_HPP
#define CPPA_LIFT_VOID_HPP
#include "cppa/unit.hpp"
namespace cppa {
template<typename T>
struct lift_void {
using type = T;
};
template<>
struct lift_void<void> {
using type = unit_t;
};
template<typename T>
struct unlift_void {
using type = T;
};
template<>
struct unlift_void<unit_t> {
using type = void;
};
} // namespace cppa
#endif // CPPA_LIFT_VOID_HPP
...@@ -87,7 +87,7 @@ class match_each_helper { ...@@ -87,7 +87,7 @@ class match_each_helper {
auto expr = match_expr_collect(std::forward<Ts>(args)...); auto expr = match_expr_collect(std::forward<Ts>(args)...);
for (; i != e; ++i) { for (; i != e; ++i) {
auto res = expr(p(*i)); auto res = expr(p(*i));
if (!res) return i; if (get<none_t>(&res)) return i;
} }
return e; return e;
} }
......
...@@ -20,9 +20,11 @@ ...@@ -20,9 +20,11 @@
#ifndef CPPA_MATCH_EXPR_HPP #ifndef CPPA_MATCH_EXPR_HPP
#define CPPA_MATCH_EXPR_HPP #define CPPA_MATCH_EXPR_HPP
#include "cppa/unit.hpp"
#include "cppa/variant.hpp"
#include "cppa/optional.hpp" #include "cppa/optional.hpp"
#include "cppa/lift_void.hpp"
#include "cppa/guard_expr.hpp" #include "cppa/guard_expr.hpp"
#include "cppa/optional_variant.hpp"
#include "cppa/tpartial_function.hpp" #include "cppa/tpartial_function.hpp"
#include "cppa/util/call.hpp" #include "cppa/util/call.hpp"
...@@ -471,6 +473,26 @@ struct has_bool_result { ...@@ -471,6 +473,26 @@ struct has_bool_result {
typedef std::integral_constant<bool, value> token_type; typedef std::integral_constant<bool, value> token_type;
}; };
template<typename T>
inline bool unroll_expr_result_valid(const T&) {
return true;
}
template<typename T>
inline bool unroll_expr_result_valid(const optional<T>& opt) {
return static_cast<bool>(opt);
}
template<typename T>
inline T& unroll_expr_result_unbox(T& value) {
return value;
}
template<typename T>
inline T& unroll_expr_result_unbox(optional<T>& opt) {
return *opt;
}
template<typename Result, class PPFPs, typename PtrType, class Tuple> template<typename Result, class PPFPs, typename PtrType, class Tuple>
Result unroll_expr(PPFPs&, std::uint64_t, minus1l, const std::type_info&, Result unroll_expr(PPFPs&, std::uint64_t, minus1l, const std::type_info&,
bool, PtrType*, Tuple&) { bool, PtrType*, Tuple&) {
...@@ -488,7 +510,7 @@ Result unroll_expr(PPFPs& fs, ...@@ -488,7 +510,7 @@ Result unroll_expr(PPFPs& fs,
/* recursively evaluate sub expressions */ { /* recursively evaluate sub expressions */ {
Result res = unroll_expr<Result>(fs, bitmask, long_constant<N-1>{}, Result res = unroll_expr<Result>(fs, bitmask, long_constant<N-1>{},
type_token, is_dynamic, ptr, tup); type_token, is_dynamic, ptr, tup);
if (res) return res; if (!get<none_t>(&res)) return res;
} }
if ((bitmask & (0x01 << N)) == 0) return none; if ((bitmask & (0x01 << N)) == 0) return none;
auto& f = get<N>(fs); auto& f = get<N>(fs);
...@@ -498,10 +520,13 @@ Result unroll_expr(PPFPs& fs, ...@@ -498,10 +520,13 @@ Result unroll_expr(PPFPs& fs,
typename policy::tuple_type targs; typename policy::tuple_type targs;
if (policy::prepare_invoke(targs, type_token, is_dynamic, ptr, tup)) { if (policy::prepare_invoke(targs, type_token, is_dynamic, ptr, tup)) {
auto is = util::get_indices(targs); auto is = util::get_indices(targs);
return util::apply_args_prefixed(f.first, auto res = util::apply_args_prefixed(f.first,
deduce_const(tup, targs), deduce_const(tup, targs),
is, is,
f.second); f.second);
if (unroll_expr_result_valid(res)) {
return std::move(unroll_expr_result_unbox(res));
}
} }
return none; return none;
} }
...@@ -616,6 +641,14 @@ struct get_case_result { ...@@ -616,6 +641,14 @@ struct get_case_result {
namespace cppa { namespace cppa {
template<class List>
struct match_result_from_type_list;
template<typename... Ts>
struct match_result_from_type_list<util::type_list<Ts...>> {
typedef variant<none_t, typename lift_void<Ts>::type...> type;
};
/** /**
* @brief A match expression encapsulating cases <tt>Cs...</tt>, whereas * @brief A match expression encapsulating cases <tt>Cs...</tt>, whereas
* each case is a @p detail::projection_partial_function_pair. * each case is a @p detail::projection_partial_function_pair.
...@@ -629,7 +662,7 @@ class match_expr { ...@@ -629,7 +662,7 @@ class match_expr {
typedef util::type_list<Cs...> cases_list; typedef util::type_list<Cs...> cases_list;
typedef typename optional_variant_from_type_list< typedef typename match_result_from_type_list<
typename util::tl_distinct< typename util::tl_distinct<
typename util::tl_map< typename util::tl_map<
cases_list, cases_list,
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "cppa/none.hpp" #include "cppa/none.hpp"
#include "cppa/unit.hpp" #include "cppa/unit.hpp"
#include "cppa/optional.hpp" #include "cppa/optional.hpp"
#include "cppa/lift_void.hpp"
#include "cppa/util/call.hpp" #include "cppa/util/call.hpp"
#include "cppa/util/type_list.hpp" #include "cppa/util/type_list.hpp"
...@@ -41,21 +42,29 @@ struct tpartial_function_helper { ...@@ -41,21 +42,29 @@ struct tpartial_function_helper {
if (fun.defined_at(args...)) return fun.invoke(args...); if (fun.defined_at(args...)) return fun.invoke(args...);
return none; return none;
} }
template<class Expr, class Tuple, class Indices>
inline Result lifted_result(Expr& expr, Tuple& tup, Indices& indices) {
return util::apply_args(expr, tup, indices);
}
}; };
template<typename... Ts> template<typename... Ts>
struct tpartial_function_helper<void, Ts...> { struct tpartial_function_helper<unit_t, Ts...> {
template<typename Fun> template<typename Fun>
inline optional<void> operator()(const Fun& fun, Ts... args) { inline optional<unit_t> operator()(const Fun& fun, Ts... args) {
if (fun.defined_at(args...)) { if (fun.defined_at(args...)) {
fun.invoke(args...); fun.invoke(args...);
return unit; return unit;
} }
return none; return none;
} }
template<class Expr, class Tuple, class Indices>
inline unit_t lifted_result(Expr& expr, Tuple& tup, Indices& indices) {
util::apply_args(expr, tup, indices);
return unit;
}
}; };
template<class Expr, class Guard, typename Result, typename... Ts> template<class Expr, class Guard, typename Result, typename... Ts>
class tpartial_function { class tpartial_function {
...@@ -80,7 +89,7 @@ class tpartial_function { ...@@ -80,7 +89,7 @@ class tpartial_function {
static constexpr bool manipulates_args = static constexpr bool manipulates_args =
util::tl_exists<arg_types, util::is_mutable_ref>::value; util::tl_exists<arg_types, util::is_mutable_ref>::value;
typedef Result result_type; typedef typename lift_void<Result>::type result_type;
template<typename Fun, typename... G> template<typename Fun, typename... G>
tpartial_function(Fun&& fun, G&&... guard_args) tpartial_function(Fun&& fun, G&&... guard_args)
...@@ -105,7 +114,8 @@ class tpartial_function { ...@@ -105,7 +114,8 @@ class tpartial_function {
result_type invoke(Ts... args) const { result_type invoke(Ts... args) const {
auto targs = std::forward_as_tuple(args...); auto targs = std::forward_as_tuple(args...);
auto indices = util::get_right_indices<num_expr_args>(targs); auto indices = util::get_right_indices<num_expr_args>(targs);
return util::apply_args(m_expr, targs, indices); tpartial_function_helper<result_type, Ts...> helper;
return helper.lifted_result(m_expr, targs, indices);
} }
inline optional<result_type> operator()(Ts... args) const { inline optional<result_type> operator()(Ts... args) const {
......
...@@ -73,8 +73,11 @@ struct valid_input_predicate { ...@@ -73,8 +73,11 @@ struct valid_input_predicate {
template<typename Expr> template<typename Expr>
struct inner { struct inner {
typedef typename Expr::input_types input_types; typedef typename Expr::input_types input_types;
typedef typename unbox_typed_continue_helper< typedef typename util::tl_map<
typename Expr::output_types typename unbox_typed_continue_helper<
typename Expr::output_types
>::type,
unlift_void
>::type >::type
output_types; output_types;
// get matching elements for input type // get matching elements for input type
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <type_traits> #include <type_traits>
#include "cppa/cppa_fwd.hpp" #include "cppa/cppa_fwd.hpp"
#include "cppa/optional.hpp"
#include "cppa/util/type_list.hpp" #include "cppa/util/type_list.hpp"
#include "cppa/util/type_traits.hpp" #include "cppa/util/type_traits.hpp"
......
...@@ -17,40 +17,28 @@ ...@@ -17,40 +17,28 @@
\******************************************************************************/ \******************************************************************************/
#ifndef CPPA_OPTIONAL_VARIANT_HPP #ifndef CPPA_VARIANT_HPP
#define CPPA_OPTIONAL_VARIANT_HPP #define CPPA_VARIANT_HPP
#include <ostream> #include "cppa/lift_void.hpp"
#include <stdexcept>
#include <type_traits>
#include "cppa/none.hpp"
#include "cppa/unit.hpp"
#include "cppa/optional.hpp"
#include "cppa/skip_message.hpp"
#include "cppa/util/type_list.hpp" #include "cppa/util/type_list.hpp"
#include "cppa/util/type_traits.hpp" #include "cppa/util/type_traits.hpp"
#include "cppa/detail/optional_variant_data.hpp" #include "cppa/detail/variant_data.hpp"
#define CPPA_OPTIONAL_VARIANT_CASE(x) \ #define CPPA_VARIANT_CASE(x) \
case x: return do_visit(from, visitor, \ case x: return do_visit(from, visitor, \
make_bool_token<void_pos == x >(), \ std::integral_constant<bool, void_pos == x >(), \
make_int_token< x >()) \ std::integral_constant<int, x >()) \
namespace cppa {
template<int Value>
constexpr std::integral_constant<int, Value> make_int_token() { return {}; }
template<bool Value> namespace cppa {
constexpr std::integral_constant<bool, Value> make_bool_token() { return {}; }
template<typename T> template<typename T>
struct optional_variant_copy_helper { struct variant_copy_helper {
T& lhs; T& lhs;
optional_variant_copy_helper(T& lhs_ref) : lhs(lhs_ref) { } variant_copy_helper(T& lhs_ref) : lhs(lhs_ref) { }
template<typename U> template<typename U>
inline void operator()(const U& rhs) const { inline void operator()(const U& rhs) const {
lhs = rhs; lhs = rhs;
...@@ -64,9 +52,9 @@ struct optional_variant_copy_helper { ...@@ -64,9 +52,9 @@ struct optional_variant_copy_helper {
}; };
template<typename T> template<typename T>
struct optional_variant_move_helper { struct variant_move_helper {
T& lhs; T& lhs;
optional_variant_move_helper(T& lhs_ref) : lhs(lhs_ref) { } variant_move_helper(T& lhs_ref) : lhs(lhs_ref) { }
template<typename U> template<typename U>
inline void operator()(U& rhs) const { inline void operator()(U& rhs) const {
lhs = std::move(rhs); lhs = std::move(rhs);
...@@ -80,29 +68,32 @@ struct optional_variant_move_helper { ...@@ -80,29 +68,32 @@ struct optional_variant_move_helper {
}; };
template<typename... Ts> template<typename... Ts>
class optional_variant; class variant;
template<typename T> template<typename T>
struct is_optional_variant { struct is_variant {
static constexpr bool value = false; static constexpr bool value = false;
}; };
template<typename... Ts> template<typename... Ts>
struct is_optional_variant<optional_variant<Ts...>> { struct is_variant<variant<Ts...>> {
static constexpr bool value = true; static constexpr bool value = true;
}; };
/** /**
* @brief A optional_variant is either invalid or holds * @brief A variant represents always a valid value of one of
a value of one of the types <tt>Ts</tt>. * the types @p Ts.
*/ */
template<typename... Ts> template<typename... Ts>
class optional_variant { class variant {
public: public:
typedef util::type_list<Ts...> types; typedef util::type_list<Ts...> types;
static_assert(!util::tl_exists<types, std::is_reference>::value,
"Cannot create a variant of references");
static constexpr int void_pos = util::tl_find<types, void>::value; static constexpr int void_pos = util::tl_find<types, void>::value;
/** /**
...@@ -110,65 +101,56 @@ class optional_variant { ...@@ -110,65 +101,56 @@ class optional_variant {
*/ */
template<typename T> template<typename T>
inline bool is() const { inline bool is() const {
return m_type != -1 && m_type == util::tl_find<types, T>::value; return m_type == util::tl_find<types, T>::value;
}
template<int Pos>
inline bool is(std::integral_constant<int, Pos>) const {
return m_type == Pos;
} }
template<typename U> template<typename U>
optional_variant& operator=(U&& arg) { variant& operator=(U&& arg) {
destroy_data(); destroy_data();
set(std::forward<U>(arg)); set(std::forward<U>(arg));
return *this; return *this;
} }
optional_variant& operator=(const optional_variant& other) { variant& operator=(const variant& other) {
destroy_data(); destroy_data();
optional_variant_copy_helper<optional_variant> helper{*this}; variant_copy_helper<variant> helper{*this};
other.apply(helper); other.apply(helper);
return *this; return *this;
} }
optional_variant& operator=(optional_variant&& other) { variant& operator=(variant&& other) {
destroy_data(); destroy_data();
optional_variant_move_helper<optional_variant> helper{*this}; variant_move_helper<variant> helper{*this};
other.apply(helper); other.apply(helper);
return *this; return *this;
} }
optional_variant() : m_type(-1) { } variant() : m_type(0) { }
template<typename U> template<typename U>
optional_variant(U&& arg) { variant(U&& arg) {
set(std::forward<U>(arg)); set(std::forward<U>(arg));
} }
optional_variant(const optional_variant& other) : m_type(-1) { variant(const variant& other) : m_type(0) {
optional_variant_copy_helper<optional_variant> helper{*this}; variant_copy_helper<variant> helper{*this};
other.apply(helper); other.apply(helper);
} }
optional_variant(optional_variant&& other) : m_type(-1) { variant(variant&& other) : m_type(0) {
optional_variant_move_helper<optional_variant> helper{*this}; variant_move_helper<variant> helper{*this};
other.apply(helper); other.apply(helper);
} }
~optional_variant() { ~variant() {
destroy_data(); destroy_data();
} }
/**
* @brief Checks whether this optional_variant is valid.
*/
inline explicit operator bool() const {
return m_type != -1;
}
/**
* @brief Checks whether this optional_variant is invalid.
*/
inline bool operator!() const {
return m_type == -1;
}
/** @cond PRIVATE */ /** @cond PRIVATE */
template<int Pos> template<int Pos>
...@@ -238,209 +220,119 @@ class optional_variant { ...@@ -238,209 +220,119 @@ class optional_variant {
static auto do_apply(Self& from, Visitor& visitor) -> decltype(visitor(none_t{})) { static auto do_apply(Self& from, Visitor& visitor) -> decltype(visitor(none_t{})) {
switch (from.m_type) { switch (from.m_type) {
default: throw std::runtime_error("invalid type found"); default: throw std::runtime_error("invalid type found");
case -1: return visitor(none_t{}); CPPA_VARIANT_CASE(0);
CPPA_OPTIONAL_VARIANT_CASE(0); CPPA_VARIANT_CASE(1);
CPPA_OPTIONAL_VARIANT_CASE(1); CPPA_VARIANT_CASE(2);
CPPA_OPTIONAL_VARIANT_CASE(2); CPPA_VARIANT_CASE(3);
CPPA_OPTIONAL_VARIANT_CASE(3); CPPA_VARIANT_CASE(4);
CPPA_OPTIONAL_VARIANT_CASE(4); CPPA_VARIANT_CASE(5);
CPPA_OPTIONAL_VARIANT_CASE(5); CPPA_VARIANT_CASE(6);
CPPA_OPTIONAL_VARIANT_CASE(6); CPPA_VARIANT_CASE(7);
CPPA_OPTIONAL_VARIANT_CASE(7); CPPA_VARIANT_CASE(8);
CPPA_OPTIONAL_VARIANT_CASE(8); CPPA_VARIANT_CASE(9);
CPPA_OPTIONAL_VARIANT_CASE(9);
} }
} }
inline void destroy_data() { inline void destroy_data() {
detail::optional_variant_data_destructor f; detail::variant_data_destructor f;
apply(f); apply(f);
} }
template<typename U> template<typename U>
typename std::enable_if< typename std::enable_if<
!std::is_same<typename util::rm_const_and_ref<U>::type, none_t>::value !is_variant<typename util::rm_const_and_ref<U>::type>::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 >::type
set(U&& arg) { set(U&& arg) {
typedef typename util::rm_const_and_ref<U>::type stripped_type; using type = typename util::rm_const_and_ref<U>::type;
typedef typename detail::unlift_void<stripped_type>::type type;
static constexpr int type_id = util::tl_find<types, type>::value; static constexpr int type_id = util::tl_find<types, type>::value;
static_assert(type_id != -1, "invalid type");
m_type = type_id; m_type = type_id;
auto& ref = m_data.get(make_int_token<type_id>()); auto& ref = m_data.get(std::integral_constant<int, type_id>());
new (&ref) stripped_type (std::forward<U>(arg)); new (&ref) type (std::forward<U>(arg));
} }
inline void set(const optional_variant& other) { inline void set(const variant& other) {
optional_variant_copy_helper<optional_variant> helper{*this}; variant_copy_helper<variant> helper{*this};
other.apply(helper); other.apply(helper);
} }
inline void set(optional_variant&& other) { inline void set(variant&& other) {
optional_variant_move_helper<optional_variant> helper{*this}; variant_move_helper<variant> helper{*this};
other.apply(helper); 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; int m_type;
detail::optional_variant_data<typename detail::lift_void<Ts>::type...> m_data; detail::variant_data<typename lift_void<Ts>::type...> m_data;
}; };
/** /**
* @relates optional_variant * @relates variant
*/ */
template<typename T, typename... Us> template<typename T, typename... Us>
const T& get(const optional_variant<Us...>& value) { const T& get(const variant<Us...>& value) {
std::integral_constant<int, util::tl_find<util::type_list<Us...>, T>::value> token; std::integral_constant<int, util::tl_find<util::type_list<Us...>, T>::value> token;
return value.get(token); return value.get(token);
} }
/** /**
* @relates optional_variant * @relates variant
*/ */
template<typename T, typename... Us> template<typename T, typename... Us>
T& get_ref(optional_variant<Us...>& value) { T& get(variant<Us...>& value) {
std::integral_constant<int, util::tl_find<util::type_list<Us...>, T>::value> token; std::integral_constant<int, util::tl_find<util::type_list<Us...>, T>::value> token;
return value.get(token); return value.get(token);
} }
/** /**
* @relates optional_variant * @relates variant
*/ */
template<typename Visitor, typename... Ts> template<typename T, typename... Us>
auto apply_visitor(Visitor& visitor, const optional_variant<Ts...>& data) -> decltype(visitor(none_t{})) { const T* get(const variant<Us...>* value) {
return data.apply(visitor); std::integral_constant<int, util::tl_find<util::type_list<Us...>, T>::value> token;
return value && value->is(token) ? &value->get(token) : nullptr;
} }
/** /**
* @relates optional_variant * @relates variant
*/ */
template<typename Visitor, typename... Ts> template<typename T, typename... Us>
auto apply_visitor(const Visitor& visitor, const optional_variant<Ts...>& data) -> decltype(visitor(none_t{})) { T* get(variant<Us...>* value) {
return data.apply(visitor); std::integral_constant<int, util::tl_find<util::type_list<Us...>, T>::value> token;
return value && value->is(token) ? &value->get(token) : nullptr;
} }
template<typename Result>
struct static_visitor {
using result_type = Result;
};
/** /**
* @relates optional_variant * @relates variant
*/ */
template<typename Visitor, typename... Ts> template<typename Visitor, typename... Ts>
auto apply_visitor(Visitor& visitor, optional_variant<Ts...>& data) -> decltype(visitor(none_t{})) { typename Visitor::result_type apply_visitor(const Visitor& visitor,
const variant<Ts...>& data) {
return data.apply(visitor); return data.apply(visitor);
} }
/** /**
* @relates optional_variant * @relates variant
*/ */
template<typename Visitor, typename... Ts> template<typename Visitor, typename... Ts>
auto apply_visitor(const Visitor& visitor, optional_variant<Ts...>& data) -> decltype(visitor(none_t{})) { typename Visitor::result_type apply_visitor(Visitor& visitor,
variant<Ts...>& data) {
return data.apply(visitor); 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 detail {
template<typename T>
struct optional_variant_cmp_helper {
const T& lhs;
optional_variant_cmp_helper(const T& value) : lhs{value} { }
// variant is comparable
template<typename U>
typename std::enable_if<util::is_comparable<T, U>::value, bool>::type
operator()(const U& rhs) const { return lhs == rhs; }
// variant is not comparable
template<typename U>
typename std::enable_if<!util::is_comparable<T, U>::value, bool>::type
operator()(const U&) const { return false; }
// variant is void
bool operator()() const { return false; }
// variant is undefined
bool operator()(const none_t&) const { return false; }
};
} // namespace detail
/**
* @relates optional_variant
*/
template<typename T, typename... Ts>
bool operator==(const T& lhs, const optional_variant<Ts...>& rhs) {
return apply_visitor(detail::optional_variant_cmp_helper<T>{lhs}, rhs);
}
/** /**
* @relates optional_variant * @relates variant
*/ */
template<typename T, typename... Ts> template<typename Visitor, typename... Ts>
bool operator==(const optional_variant<Ts...>& lhs, const T& rhs) { typename Visitor::result_type apply_visitor(const Visitor& visitor,
return rhs == lhs; variant<Ts...>& data) {
} return data.apply(visitor);
namespace detail {
struct optional_variant_ostream_helper {
std::ostream& lhs;
inline optional_variant_ostream_helper(std::ostream& os) : lhs(os) { }
template<typename T>
std::ostream& operator()(const T& value) const {
return lhs << value;
}
inline std::ostream& operator()(const none_t&) const {
return lhs << "<none>";
}
inline std::ostream& operator()() const {
return lhs << "<void>";
}
template<typename T0>
std::ostream& operator()(const cow_tuple<T0>& value) const {
return lhs << get<0>(value);
}
template<typename T0, typename T1, typename... Ts>
std::ostream& operator()(const cow_tuple<T0, T1, Ts...>& value) const {
lhs << get<0>(value) << " ";
return (*this)(value.drop_left());
}
};
} // namespace detail
/**
* @relates optional_variant
*/
template<typename T0, typename... Ts>
std::ostream& operator<<(std::ostream& lhs, const optional_variant<T0, Ts...>& rhs) {
return apply_visitor(detail::optional_variant_ostream_helper{lhs}, rhs);
}
template<typename T, typename... Ts>
optional_variant<T, typename util::rm_const_and_ref<Ts>::type...>
make_optional_variant(T value, Ts&&... args) {
return {std::move(value), std::forward<Ts>(args)...};
}
template<typename... Ts>
inline optional_variant<Ts...> make_optional_variant(optional_variant<Ts...> value) {
return value;
} }
} // namespace cppa } // namespace cppa
#endif // CPPA_OPTIONAL_VARIANT_HPP #endif // CPPA_VARIANT_HPP
...@@ -12,7 +12,6 @@ endmacro() ...@@ -12,7 +12,6 @@ endmacro()
add_unit_test(ripemd_160) add_unit_test(ripemd_160)
add_unit_test(atom) add_unit_test(atom)
add_unit_test(optional_variant)
add_unit_test(metaprogramming) add_unit_test(metaprogramming)
add_unit_test(intrusive_containers) add_unit_test(intrusive_containers)
add_unit_test(serialization) add_unit_test(serialization)
......
...@@ -142,8 +142,33 @@ inline void cppa_check_value(V1 v1, ...@@ -142,8 +142,33 @@ inline void cppa_check_value(V1 v1,
CPPA_PRINT("passed"); \ CPPA_PRINT("passed"); \
} ((void) 0) } ((void) 0)
namespace cppa {
inline bool is_false_or_none(bool value) {
return !value;
}
template<typename... Ts>
inline bool is_false_or_none(const variant<none_t, Ts...>& res) {
return get<none_t>(&res) != nullptr;
}
template<typename T>
inline bool is_false_or_none(const optional<T>& res) {
return !static_cast<bool>(res);
}
} // namespace cppa
#define CPPA_CHECK(line_of_code) \ #define CPPA_CHECK(line_of_code) \
if (!(line_of_code)) { \ if (cppa::is_false_or_none(line_of_code)) { \
CPPA_PRINTERR(#line_of_code); \
cppa_inc_error_count(); \
} \
else { CPPA_PRINT("passed"); } CPPA_VOID_STMT
#define CPPA_CHECK_NOT(line_of_code) \
if (!cppa::is_false_or_none(line_of_code)) { \
CPPA_PRINTERR(#line_of_code); \ CPPA_PRINTERR(#line_of_code); \
cppa_inc_error_count(); \ cppa_inc_error_count(); \
} \ } \
......
...@@ -169,7 +169,7 @@ void test_gref() { ...@@ -169,7 +169,7 @@ void test_gref() {
); );
any_tuple expr19_tup = make_cow_tuple("hello guard!"); any_tuple expr19_tup = make_cow_tuple("hello guard!");
auto res19 = expr19(expr19_tup); auto res19 = expr19(expr19_tup);
CPPA_CHECK(res19.is<int>() && get<int>(res19) == 2); CPPA_CHECK(get<int>(&res19) && get<int>(res19) == 2);
partial_function expr20 = expr19; partial_function expr20 = expr19;
enable_case1 = false; enable_case1 = false;
CPPA_CHECK(expr20(expr19_tup) == make_any_tuple(1)); CPPA_CHECK(expr20(expr19_tup) == make_any_tuple(1));
...@@ -188,32 +188,32 @@ void test_match_function() { ...@@ -188,32 +188,32 @@ void test_match_function() {
CPPA_CHECK_EQUAL(i, 5); CPPA_CHECK_EQUAL(i, 5);
} }
); );
CPPA_CHECK(res0); CPPA_CHECK(!get<none_t>(&res0));
auto res1 = match("value=42") ( auto res1 = match("value=42") (
on(kvp_split).when(_x1.not_empty()) >> [&](const vector<string>& vec) { on(kvp_split).when(_x1.not_empty()) >> [&](const vector<string>& vec) {
CPPA_CHECK_EQUAL("value", vec[0]); CPPA_CHECK_EQUAL("value", vec[0]);
CPPA_CHECK_EQUAL("42", vec[1]); CPPA_CHECK_EQUAL("42", vec[1]);
} }
); );
CPPA_CHECK(res1); CPPA_CHECK(!get<none_t>(&res1));
auto res2 = match("42") ( auto res2 = match("42") (
on(toint) >> [&](int i) { on(toint) >> [&](int i) {
CPPA_CHECK_EQUAL(42, i); CPPA_CHECK_EQUAL(42, i);
} }
); );
CPPA_CHECK(res2); CPPA_CHECK(!get<none_t>(&res2));
auto res3 = match("abc") ( auto res3 = match("abc") (
on<string>().when(_x1 == "abc") >> [&] { } on<string>().when(_x1 == "abc") >> [&] { }
); );
CPPA_CHECK(res3); CPPA_CHECK(!get<none_t>(&res3));
CPPA_CHECK(res3.is<void>()); CPPA_CHECK(get<unit_t>(&res3));
// match vectors // match vectors
auto res4 = match(std::vector<int>{1, 2, 3}) ( auto res4 = match(std::vector<int>{1, 2, 3}) (
on<int, int, int>().when( _x1 + _x2 + _x3 == 6 on<int, int, int>().when( _x1 + _x2 + _x3 == 6
&& _x2(is_even) && _x2(is_even)
&& _x3 % 2 == 1 ) >> [&] { } && _x3 % 2 == 1 ) >> [&] { }
); );
CPPA_CHECK(res4); CPPA_CHECK(!get<none_t>(&res4));
vector<string> vec{"a", "b", "c"}; vector<string> vec{"a", "b", "c"};
auto res5 = match(vec) ( auto res5 = match(vec) (
on("a", "b", val<string>) >> [](string&) -> string { on("a", "b", val<string>) >> [](string&) -> string {
...@@ -342,7 +342,7 @@ void test_pattern_matching() { ...@@ -342,7 +342,7 @@ void test_pattern_matching() {
return f; return f;
} }
); );
CPPA_CHECK(res && res.is<float>() && util::safe_equal(get<float>(res), 4.2f)); CPPA_CHECK(get<float>(&res) && util::safe_equal(get<float>(res), 4.2f));
auto res2 = match(make_any_tuple(23, 4.2f)) ( auto res2 = match(make_any_tuple(23, 4.2f)) (
on(42, arg_match) >> [](double d) { on(42, arg_match) >> [](double d) {
return d; return d;
...@@ -351,7 +351,7 @@ void test_pattern_matching() { ...@@ -351,7 +351,7 @@ void test_pattern_matching() {
return f; return f;
} }
); );
CPPA_CHECK(!res2); CPPA_CHECK(get<none_t>(&res2));
} }
inline void make_dynamically_typed_impl(detail::object_array&) { } inline void make_dynamically_typed_impl(detail::object_array&) { }
...@@ -377,7 +377,7 @@ void test_wildcards() { ...@@ -377,7 +377,7 @@ void test_wildcards() {
CPPA_CHECK_EQUAL(b, 2); CPPA_CHECK_EQUAL(b, 2);
} }
); );
CPPA_CHECK(not expr0(1)); CPPA_CHECK_NOT(expr0(1));
CPPA_CHECK(expr0(1, 2)); CPPA_CHECK(expr0(1, 2));
CPPA_CHECK(expr0(0, 1, 2)); CPPA_CHECK(expr0(0, 1, 2));
partial_function pf0 = expr0; partial_function pf0 = expr0;
......
#include <iostream>
#include <functional>
#include "test.hpp"
#include "cppa/cppa.hpp"
#include "cppa/optional_variant.hpp"
using namespace std;
using namespace cppa;
namespace { std::atomic<size_t> some_struct_instances; }
struct some_struct {
some_struct() { ++some_struct_instances; }
some_struct(const some_struct&) { ++some_struct_instances; }
~some_struct() { --some_struct_instances; }
};
struct int_visitor {
int operator()(none_t) const { return -1; }
int operator()(int i) const { return i; }
int operator()(const some_struct&) const { return 0; }
};
using dlimits = std::numeric_limits<double>;
struct double_visitor {
double operator()(none_t) const { return dlimits::signaling_NaN(); }
double operator()() const { return dlimits::quiet_NaN(); }
template<typename T>
double operator()(T value) const { return value; }
};
int main() {
CPPA_TEST(test_optional_variant);
/* run tets using primitive types */ {
using tri_type = optional_variant<void, int, double, float>;
tri_type t0;
tri_type t1{unit};
tri_type t2{0};
tri_type t3{0.0};
tri_type t4{0.0f};
CPPA_CHECK(!t0);
CPPA_CHECK(t1 && t1.is<void>());
CPPA_CHECK(t2.is<int>());
CPPA_CHECK(!t2.is<double>());
CPPA_CHECK(!t2.is<float>());
CPPA_CHECK_EQUAL(get<int>(t2), 0);
get_ref<int>(t2) = 42;
CPPA_CHECK_EQUAL(get<int>(t2), 42);
CPPA_CHECK(!t3.is<int>());
CPPA_CHECK(t3.is<double>());
CPPA_CHECK(!t3.is<float>());
CPPA_CHECK_EQUAL(get<double>(t3), 0.0);
get_ref<double>(t3) = 4.2;
CPPA_CHECK_EQUAL(get<double>(t3), 4.2);
CPPA_CHECK(!t4.is<int>());
CPPA_CHECK(!t4.is<double>());
CPPA_CHECK(t4.is<float>());
CPPA_CHECK_EQUAL(get<float>(t4), 0.0f);
get_ref<float>(t4) = 2.3f;
CPPA_CHECK_EQUAL(get<float>(t4), 2.3f);
double_visitor dv;
auto v = apply_visitor(dv, t0);
CPPA_CHECK(v != v); // only true if v is NaN
v = apply_visitor(dv, t1);
CPPA_CHECK(v != v); // only true if v is NaN
CPPA_CHECK_EQUAL(apply_visitor(dv, t2), 42.0);
CPPA_CHECK_EQUAL(apply_visitor(dv, t3), 4.2);
// converting 2.3f to double is not exactly 2.3
CPPA_CHECK_EQUAL(apply_visitor(dv, t4), static_cast<double>(2.3f));
t4 = 1;
CPPA_CHECK(t4 && t4.is<int>() && get<int>(t4) == 1);
t4 = none_t{};
CPPA_CHECK(!t4);
}
/* run tests using user-defined types */ {
using tri_type = optional_variant<int, some_struct>;
tri_type t0;
tri_type t1{42};
CPPA_CHECK_EQUAL(some_struct_instances.load(), 0);
tri_type t2{some_struct{}};
CPPA_CHECK_EQUAL(some_struct_instances.load(), 1);
CPPA_CHECK(!t0);
CPPA_CHECK(t1 && t1.is<int>() && get<int>(t1) == 42);
CPPA_CHECK(t2 && t2.is<some_struct>());
int_visitor iVisit;
CPPA_CHECK_EQUAL(apply_visitor(iVisit, t0), -1);
CPPA_CHECK_EQUAL(apply_visitor(iVisit, t1), 42);
CPPA_CHECK_EQUAL(apply_visitor(iVisit, t2), 0);
}
CPPA_CHECK_EQUAL(some_struct_instances.load(), 0);
return CPPA_TEST_RESULT();
}
...@@ -169,9 +169,9 @@ struct server : event_based_actor { ...@@ -169,9 +169,9 @@ struct server : event_based_actor {
}; };
void compile_time_optional_variant_check(event_based_actor* self) { void compile_time_variant_check(event_based_actor* self) {
typedef optional_variant<std::tuple<int, float>, typedef variant<std::tuple<int, float>,
std::tuple<float, int, int>> std::tuple<float, int, int>>
msg_type; msg_type;
self->sync_send(self, atom("msg")).then([](msg_type) {}); self->sync_send(self, atom("msg")).then([](msg_type) {});
} }
...@@ -343,6 +343,6 @@ int main() { ...@@ -343,6 +343,6 @@ int main() {
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
shutdown(); shutdown();
// shutdown warning about unused function (only performs compile-time check) // shutdown warning about unused function (only performs compile-time check)
static_cast<void>(compile_time_optional_variant_check); static_cast<void>(compile_time_variant_check);
return CPPA_TEST_RESULT(); return CPPA_TEST_RESULT();
} }
...@@ -39,15 +39,21 @@ using namespace cppa::placeholders; ...@@ -39,15 +39,21 @@ using namespace cppa::placeholders;
#define CPPA_CHECK_INVOKED(FunName, Args) \ #define CPPA_CHECK_INVOKED(FunName, Args) \
invoked.clear(); \ invoked.clear(); \
if ( !( FunName Args ) || invoked != #FunName ) { \ { \
CPPA_FAILURE("invocation of " #FunName " failed"); \ auto res = FunName Args ; \
} else { CPPA_CHECKPOINT(); } static_cast<void>(42) if (get<none_t>(&res) || invoked != #FunName ) { \
CPPA_FAILURE("invocation of " #FunName " failed"); \
} else { CPPA_CHECKPOINT(); } \
} static_cast<void>(42)
#define CPPA_CHECK_NOT_INVOKED(FunName, Args) \ #define CPPA_CHECK_NOT_INVOKED(FunName, Args) \
invoked.clear(); \ invoked.clear(); \
if ( FunName Args || invoked == #FunName ) { \ { \
CPPA_FAILURE(#FunName " erroneously invoked"); \ auto res = FunName Args ; \
} else { CPPA_CHECKPOINT(); } static_cast<void>(42) if (!get<none_t>(&res) || invoked == #FunName ) { \
CPPA_FAILURE(#FunName " erroneously invoked"); \
} else { CPPA_CHECKPOINT(); } \
} static_cast<void>(42)
namespace { namespace {
......
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