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 @@
#include "cppa/to_string.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/cow_tuple.hpp"
#include "cppa/tuple_cast.hpp"
#include "cppa/singletons.hpp"
#include "cppa/typed_actor.hpp"
#include "cppa/exit_reason.hpp"
......
......@@ -21,11 +21,12 @@
#define CPPA_DETAIL_BEHAVIOR_IMPL_HPP
#include "cppa/atom.hpp"
#include "cppa/variant.hpp"
#include "cppa/optional.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/ref_counted.hpp"
#include "cppa/skip_message.hpp"
#include "cppa/intrusive_ptr.hpp"
#include "cppa/optional_variant.hpp"
#include "cppa/timeout_definition.hpp"
#include "cppa/util/duration.hpp"
......@@ -47,9 +48,14 @@ template<class T> struct is_message_id_wrapper {
static constexpr bool value = sizeof(test<T>(0)) == 1;
};
struct optional_any_tuple_visitor {
inline bhvr_invoke_result operator()() const { return any_tuple{}; }
struct optional_any_tuple_visitor : static_visitor<bhvr_invoke_result> {
//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()(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>
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));
......@@ -137,9 +143,9 @@ class behavior_impl : public ref_counted {
};
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 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>
......@@ -158,11 +164,13 @@ class default_behavior_impl : public behavior_impl {
: super(tout), m_expr(std::forward<Expr>(expr)), m_fun(f) { }
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) {
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) {
......@@ -177,24 +185,6 @@ class default_behavior_impl : public behavior_impl {
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;
F m_fun;
......
......@@ -17,68 +17,57 @@
\******************************************************************************/
#ifndef CPPA_DETAIL_OPTIONAL_VARIANT_DATA
#define CPPA_DETAIL_OPTIONAL_VARIANT_DATA
#ifndef CPPA_DETAIL_VARIANT_DATA_HPP
#define CPPA_DETAIL_VARIANT_DATA_HPP
#include <stdexcept>
#include <type_traits>
#include "cppa/unit.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) \
inline CPPA_OPTIONAL_VARIANT_DATA_CONCAT(T, pos) & \
#define CPPA_VARIANT_DATA_GETTER(pos) \
inline CPPA_VARIANT_DATA_CONCAT(T, 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 { \
return CPPA_OPTIONAL_VARIANT_DATA_CONCAT(v, pos) ; \
return CPPA_VARIANT_DATA_CONCAT(v, pos) ; \
}
namespace cppa {
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,
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 {
struct variant_data {
union {
T0 v0; T1 v1; T2 v2; T3 v3; T4 v4;
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_OPTIONAL_VARIANT_DATA_GETTER(1)
CPPA_OPTIONAL_VARIANT_DATA_GETTER(2)
CPPA_OPTIONAL_VARIANT_DATA_GETTER(3)
CPPA_OPTIONAL_VARIANT_DATA_GETTER(4)
CPPA_OPTIONAL_VARIANT_DATA_GETTER(5)
CPPA_OPTIONAL_VARIANT_DATA_GETTER(6)
CPPA_OPTIONAL_VARIANT_DATA_GETTER(7)
CPPA_OPTIONAL_VARIANT_DATA_GETTER(8)
CPPA_OPTIONAL_VARIANT_DATA_GETTER(9)
CPPA_VARIANT_DATA_GETTER(0)
CPPA_VARIANT_DATA_GETTER(1)
CPPA_VARIANT_DATA_GETTER(2)
CPPA_VARIANT_DATA_GETTER(3)
CPPA_VARIANT_DATA_GETTER(4)
CPPA_VARIANT_DATA_GETTER(5)
CPPA_VARIANT_DATA_GETTER(6)
CPPA_VARIANT_DATA_GETTER(7)
CPPA_VARIANT_DATA_GETTER(8)
CPPA_VARIANT_DATA_GETTER(9)
private:
......@@ -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 none_t&) const { }
template<typename T>
......@@ -99,4 +88,4 @@ struct optional_variant_data_destructor {
} // namespace detail
} // namespace cppa
#endif // CPPA_DETAIL_OPTIONAL_VARIANT_DATA
#endif // CPPA_DETAIL_VARIANT_DATA_HPP
......@@ -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<typename... Ts>
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 {
auto expr = match_expr_collect(std::forward<Ts>(args)...);
for (; i != e; ++i) {
auto res = expr(p(*i));
if (!res) return i;
if (get<none_t>(&res)) return i;
}
return e;
}
......
......@@ -20,9 +20,11 @@
#ifndef CPPA_MATCH_EXPR_HPP
#define CPPA_MATCH_EXPR_HPP
#include "cppa/unit.hpp"
#include "cppa/variant.hpp"
#include "cppa/optional.hpp"
#include "cppa/lift_void.hpp"
#include "cppa/guard_expr.hpp"
#include "cppa/optional_variant.hpp"
#include "cppa/tpartial_function.hpp"
#include "cppa/util/call.hpp"
......@@ -471,6 +473,26 @@ struct has_bool_result {
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>
Result unroll_expr(PPFPs&, std::uint64_t, minus1l, const std::type_info&,
bool, PtrType*, Tuple&) {
......@@ -488,7 +510,7 @@ Result unroll_expr(PPFPs& fs,
/* recursively evaluate sub expressions */ {
Result res = unroll_expr<Result>(fs, bitmask, long_constant<N-1>{},
type_token, is_dynamic, ptr, tup);
if (res) return res;
if (!get<none_t>(&res)) return res;
}
if ((bitmask & (0x01 << N)) == 0) return none;
auto& f = get<N>(fs);
......@@ -498,10 +520,13 @@ Result unroll_expr(PPFPs& fs,
typename policy::tuple_type targs;
if (policy::prepare_invoke(targs, type_token, is_dynamic, ptr, tup)) {
auto is = util::get_indices(targs);
return util::apply_args_prefixed(f.first,
deduce_const(tup, targs),
is,
f.second);
auto res = util::apply_args_prefixed(f.first,
deduce_const(tup, targs),
is,
f.second);
if (unroll_expr_result_valid(res)) {
return std::move(unroll_expr_result_unbox(res));
}
}
return none;
}
......@@ -616,6 +641,14 @@ struct get_case_result {
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
* each case is a @p detail::projection_partial_function_pair.
......@@ -629,7 +662,7 @@ class match_expr {
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_map<
cases_list,
......
......@@ -26,6 +26,7 @@
#include "cppa/none.hpp"
#include "cppa/unit.hpp"
#include "cppa/optional.hpp"
#include "cppa/lift_void.hpp"
#include "cppa/util/call.hpp"
#include "cppa/util/type_list.hpp"
......@@ -41,21 +42,29 @@ struct tpartial_function_helper {
if (fun.defined_at(args...)) return fun.invoke(args...);
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>
struct tpartial_function_helper<void, Ts...> {
struct tpartial_function_helper<unit_t, Ts...> {
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...)) {
fun.invoke(args...);
return unit;
}
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>
class tpartial_function {
......@@ -80,7 +89,7 @@ class tpartial_function {
static constexpr bool manipulates_args =
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>
tpartial_function(Fun&& fun, G&&... guard_args)
......@@ -105,7 +114,8 @@ class tpartial_function {
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);
tpartial_function_helper<result_type, Ts...> helper;
return helper.lifted_result(m_expr, targs, indices);
}
inline optional<result_type> operator()(Ts... args) const {
......
......@@ -73,8 +73,11 @@ struct valid_input_predicate {
template<typename Expr>
struct inner {
typedef typename Expr::input_types input_types;
typedef typename unbox_typed_continue_helper<
typename Expr::output_types
typedef typename util::tl_map<
typename unbox_typed_continue_helper<
typename Expr::output_types
>::type,
unlift_void
>::type
output_types;
// get matching elements for input type
......
......@@ -25,6 +25,7 @@
#include <type_traits>
#include "cppa/cppa_fwd.hpp"
#include "cppa/optional.hpp"
#include "cppa/util/type_list.hpp"
#include "cppa/util/type_traits.hpp"
......
......@@ -17,40 +17,28 @@
\******************************************************************************/
#ifndef CPPA_OPTIONAL_VARIANT_HPP
#define CPPA_OPTIONAL_VARIANT_HPP
#ifndef CPPA_VARIANT_HPP
#define CPPA_VARIANT_HPP
#include <ostream>
#include <stdexcept>
#include <type_traits>
#include "cppa/none.hpp"
#include "cppa/unit.hpp"
#include "cppa/optional.hpp"
#include "cppa/skip_message.hpp"
#include "cppa/lift_void.hpp"
#include "cppa/util/type_list.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, \
make_bool_token<void_pos == x >(), \
make_int_token< x >()) \
namespace cppa {
std::integral_constant<bool, void_pos == x >(), \
std::integral_constant<int, x >()) \
template<int Value>
constexpr std::integral_constant<int, Value> make_int_token() { return {}; }
template<bool Value>
constexpr std::integral_constant<bool, Value> make_bool_token() { return {}; }
namespace cppa {
template<typename T>
struct optional_variant_copy_helper {
struct variant_copy_helper {
T& lhs;
optional_variant_copy_helper(T& lhs_ref) : lhs(lhs_ref) { }
variant_copy_helper(T& lhs_ref) : lhs(lhs_ref) { }
template<typename U>
inline void operator()(const U& rhs) const {
lhs = rhs;
......@@ -64,9 +52,9 @@ struct optional_variant_copy_helper {
};
template<typename T>
struct optional_variant_move_helper {
struct variant_move_helper {
T& lhs;
optional_variant_move_helper(T& lhs_ref) : lhs(lhs_ref) { }
variant_move_helper(T& lhs_ref) : lhs(lhs_ref) { }
template<typename U>
inline void operator()(U& rhs) const {
lhs = std::move(rhs);
......@@ -80,29 +68,32 @@ struct optional_variant_move_helper {
};
template<typename... Ts>
class optional_variant;
class variant;
template<typename T>
struct is_optional_variant {
struct is_variant {
static constexpr bool value = false;
};
template<typename... Ts>
struct is_optional_variant<optional_variant<Ts...>> {
struct is_variant<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>.
* @brief A variant represents always a valid value of one of
* the types @p Ts.
*/
template<typename... Ts>
class optional_variant {
class variant {
public:
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;
/**
......@@ -110,65 +101,56 @@ class optional_variant {
*/
template<typename T>
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>
optional_variant& operator=(U&& arg) {
variant& operator=(U&& arg) {
destroy_data();
set(std::forward<U>(arg));
return *this;
}
optional_variant& operator=(const optional_variant& other) {
variant& operator=(const variant& other) {
destroy_data();
optional_variant_copy_helper<optional_variant> helper{*this};
variant_copy_helper<variant> helper{*this};
other.apply(helper);
return *this;
}
optional_variant& operator=(optional_variant&& other) {
variant& operator=(variant&& other) {
destroy_data();
optional_variant_move_helper<optional_variant> helper{*this};
variant_move_helper<variant> helper{*this};
other.apply(helper);
return *this;
}
optional_variant() : m_type(-1) { }
variant() : m_type(0) { }
template<typename U>
optional_variant(U&& arg) {
variant(U&& arg) {
set(std::forward<U>(arg));
}
optional_variant(const optional_variant& other) : m_type(-1) {
optional_variant_copy_helper<optional_variant> helper{*this};
variant(const variant& other) : m_type(0) {
variant_copy_helper<variant> helper{*this};
other.apply(helper);
}
optional_variant(optional_variant&& other) : m_type(-1) {
optional_variant_move_helper<optional_variant> helper{*this};
variant(variant&& other) : m_type(0) {
variant_move_helper<variant> helper{*this};
other.apply(helper);
}
~optional_variant() {
~variant() {
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 */
template<int Pos>
......@@ -238,209 +220,119 @@ class optional_variant {
static auto do_apply(Self& from, Visitor& visitor) -> decltype(visitor(none_t{})) {
switch (from.m_type) {
default: throw std::runtime_error("invalid type found");
case -1: return visitor(none_t{});
CPPA_OPTIONAL_VARIANT_CASE(0);
CPPA_OPTIONAL_VARIANT_CASE(1);
CPPA_OPTIONAL_VARIANT_CASE(2);
CPPA_OPTIONAL_VARIANT_CASE(3);
CPPA_OPTIONAL_VARIANT_CASE(4);
CPPA_OPTIONAL_VARIANT_CASE(5);
CPPA_OPTIONAL_VARIANT_CASE(6);
CPPA_OPTIONAL_VARIANT_CASE(7);
CPPA_OPTIONAL_VARIANT_CASE(8);
CPPA_OPTIONAL_VARIANT_CASE(9);
CPPA_VARIANT_CASE(0);
CPPA_VARIANT_CASE(1);
CPPA_VARIANT_CASE(2);
CPPA_VARIANT_CASE(3);
CPPA_VARIANT_CASE(4);
CPPA_VARIANT_CASE(5);
CPPA_VARIANT_CASE(6);
CPPA_VARIANT_CASE(7);
CPPA_VARIANT_CASE(8);
CPPA_VARIANT_CASE(9);
}
}
inline void destroy_data() {
detail::optional_variant_data_destructor f;
detail::variant_data_destructor f;
apply(f);
}
template<typename U>
typename std::enable_if<
!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
!is_variant<typename util::rm_const_and_ref<U>::type>::value
>::type
set(U&& arg) {
typedef typename util::rm_const_and_ref<U>::type stripped_type;
typedef typename detail::unlift_void<stripped_type>::type type;
using type = typename util::rm_const_and_ref<U>::type;
static constexpr int type_id = util::tl_find<types, type>::value;
static_assert(type_id != -1, "invalid type");
m_type = type_id;
auto& ref = m_data.get(make_int_token<type_id>());
new (&ref) stripped_type (std::forward<U>(arg));
auto& ref = m_data.get(std::integral_constant<int, type_id>());
new (&ref) type (std::forward<U>(arg));
}
inline void set(const optional_variant& other) {
optional_variant_copy_helper<optional_variant> helper{*this};
inline void set(const variant& other) {
variant_copy_helper<variant> helper{*this};
other.apply(helper);
}
inline void set(optional_variant&& other) {
optional_variant_move_helper<optional_variant> helper{*this};
inline void set(variant&& other) {
variant_move_helper<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;
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>
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;
return value.get(token);
}
/**
* @relates optional_variant
* @relates variant
*/
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;
return value.get(token);
}
/**
* @relates optional_variant
* @relates variant
*/
template<typename Visitor, typename... Ts>
auto apply_visitor(Visitor& visitor, const optional_variant<Ts...>& data) -> decltype(visitor(none_t{})) {
return data.apply(visitor);
template<typename T, typename... Us>
const T* get(const variant<Us...>* value) {
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>
auto apply_visitor(const Visitor& visitor, const optional_variant<Ts...>& data) -> decltype(visitor(none_t{})) {
return data.apply(visitor);
template<typename T, typename... Us>
T* get(variant<Us...>* value) {
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>
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);
}
/**
* @relates optional_variant
* @relates variant
*/
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);
}
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>
bool operator==(const optional_variant<Ts...>& lhs, const T& rhs) {
return rhs == lhs;
}
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;
template<typename Visitor, typename... Ts>
typename Visitor::result_type apply_visitor(const Visitor& visitor,
variant<Ts...>& data) {
return data.apply(visitor);
}
} // namespace cppa
#endif // CPPA_OPTIONAL_VARIANT_HPP
#endif // CPPA_VARIANT_HPP
......@@ -12,7 +12,6 @@ endmacro()
add_unit_test(ripemd_160)
add_unit_test(atom)
add_unit_test(optional_variant)
add_unit_test(metaprogramming)
add_unit_test(intrusive_containers)
add_unit_test(serialization)
......
......@@ -142,8 +142,33 @@ inline void cppa_check_value(V1 v1,
CPPA_PRINT("passed"); \
} ((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) \
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_inc_error_count(); \
} \
......
......@@ -169,7 +169,7 @@ void test_gref() {
);
any_tuple expr19_tup = make_cow_tuple("hello guard!");
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;
enable_case1 = false;
CPPA_CHECK(expr20(expr19_tup) == make_any_tuple(1));
......@@ -188,32 +188,32 @@ void test_match_function() {
CPPA_CHECK_EQUAL(i, 5);
}
);
CPPA_CHECK(res0);
CPPA_CHECK(!get<none_t>(&res0));
auto res1 = match("value=42") (
on(kvp_split).when(_x1.not_empty()) >> [&](const vector<string>& vec) {
CPPA_CHECK_EQUAL("value", vec[0]);
CPPA_CHECK_EQUAL("42", vec[1]);
}
);
CPPA_CHECK(res1);
CPPA_CHECK(!get<none_t>(&res1));
auto res2 = match("42") (
on(toint) >> [&](int i) {
CPPA_CHECK_EQUAL(42, i);
}
);
CPPA_CHECK(res2);
CPPA_CHECK(!get<none_t>(&res2));
auto res3 = match("abc") (
on<string>().when(_x1 == "abc") >> [&] { }
);
CPPA_CHECK(res3);
CPPA_CHECK(res3.is<void>());
CPPA_CHECK(!get<none_t>(&res3));
CPPA_CHECK(get<unit_t>(&res3));
// match vectors
auto res4 = match(std::vector<int>{1, 2, 3}) (
on<int, int, int>().when( _x1 + _x2 + _x3 == 6
&& _x2(is_even)
&& _x3 % 2 == 1 ) >> [&] { }
);
CPPA_CHECK(res4);
CPPA_CHECK(!get<none_t>(&res4));
vector<string> vec{"a", "b", "c"};
auto res5 = match(vec) (
on("a", "b", val<string>) >> [](string&) -> string {
......@@ -342,7 +342,7 @@ void test_pattern_matching() {
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)) (
on(42, arg_match) >> [](double d) {
return d;
......@@ -351,7 +351,7 @@ void test_pattern_matching() {
return f;
}
);
CPPA_CHECK(!res2);
CPPA_CHECK(get<none_t>(&res2));
}
inline void make_dynamically_typed_impl(detail::object_array&) { }
......@@ -377,7 +377,7 @@ void test_wildcards() {
CPPA_CHECK_EQUAL(b, 2);
}
);
CPPA_CHECK(not expr0(1));
CPPA_CHECK_NOT(expr0(1));
CPPA_CHECK(expr0(1, 2));
CPPA_CHECK(expr0(0, 1, 2));
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 {
};
void compile_time_optional_variant_check(event_based_actor* self) {
typedef optional_variant<std::tuple<int, float>,
std::tuple<float, int, int>>
void compile_time_variant_check(event_based_actor* self) {
typedef variant<std::tuple<int, float>,
std::tuple<float, int, int>>
msg_type;
self->sync_send(self, atom("msg")).then([](msg_type) {});
}
......@@ -343,6 +343,6 @@ int main() {
CPPA_CHECKPOINT();
shutdown();
// 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();
}
......@@ -39,15 +39,21 @@ using namespace cppa::placeholders;
#define CPPA_CHECK_INVOKED(FunName, Args) \
invoked.clear(); \
if ( !( FunName Args ) || invoked != #FunName ) { \
CPPA_FAILURE("invocation of " #FunName " failed"); \
} else { CPPA_CHECKPOINT(); } static_cast<void>(42)
{ \
auto res = FunName Args ; \
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) \
invoked.clear(); \
if ( FunName Args || invoked == #FunName ) { \
CPPA_FAILURE(#FunName " erroneously invoked"); \
} else { CPPA_CHECKPOINT(); } static_cast<void>(42)
{ \
auto res = FunName Args ; \
if (!get<none_t>(&res) || invoked == #FunName ) { \
CPPA_FAILURE(#FunName " erroneously invoked"); \
} else { CPPA_CHECKPOINT(); } \
} static_cast<void>(42)
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