Commit eb1cc7b1 authored by Dominik Charousset's avatar Dominik Charousset

Tighten overly fuzzy auto-unboxing of CAF_CHECK_*

Only consider values equal on type matches. For example,
CAF_CHECK_EQUAL(variant<int, unsigned>(42), 42u) no longer evaluates to
true. This also silences compiler warnings with unintentional signed vs
unsigned comparisons.
parent 948f2f8c
......@@ -328,25 +328,31 @@ struct sum_type_access<variant<Ts...>>
};
/// @relates variant
template <class T, template <class> class Predicate>
template <template <class> class Predicate>
struct variant_compare_helper {
using result_type = bool;
const T& lhs;
variant_compare_helper(const T& lhs_ref) : lhs(lhs_ref) {
// nop
template <class T>
bool operator()(const T& x, const T& y) const {
Predicate<T> f;
return f(x, y);
}
template <class U>
bool operator()(const U& rhs) const {
auto ptr = get_if<U>(&lhs);
return ptr && Predicate<U>{}(*ptr, rhs);
template <class T, class U>
bool operator()(const T&, const U&) const {
return false;
}
};
/// @relates variant
template <class... Ts>
bool operator==(const variant<Ts...>& x, const variant<Ts...>& y) {
variant_compare_helper<variant<Ts...>, std::equal_to> f{x};
return visit(f, y);
variant_compare_helper<std::equal_to> f;
return x.index() == y.index() && visit(f, x, y);
}
/// @relates variant
template <class... Ts>
bool operator!=(const variant<Ts...>& x, const variant<Ts...>& y) {
return !(x == y);
}
/// @relates variant
......@@ -358,8 +364,8 @@ bool operator<(const variant<Ts...>& x, const variant<Ts...>& y) {
return true;
if (x.index() != y.index())
return x.index() < y.index();
variant_compare_helper<variant<Ts...>, std::less> f{x};
return visit(f, y);
variant_compare_helper<std::less> f;
return visit(f, x, y);
}
/// @relates variant
......@@ -371,34 +377,20 @@ bool operator>(const variant<Ts...>& x, const variant<Ts...>& y) {
return true;
if (x.index() != y.index())
return x.index() > y.index();
variant_compare_helper<variant<Ts...>, std::greater> f{x};
return visit(f, y);
variant_compare_helper<std::greater> f;
return visit(f, x, y);
}
/// @relates variant
template <class... Ts>
bool operator<=(const variant<Ts...>& x, const variant<Ts...>& y) {
if (x.valueless_by_exception())
return true;
if (y.valueless_by_exception())
return false;
if (x.index() != y.index())
return x.index() < y.index();
variant_compare_helper<variant<Ts...>, std::less_equal> f{x};
return visit(f, y);
return !(x > y);
}
/// @relates variant
template <class... Ts>
bool operator>=(const variant<Ts...>& x, const variant<Ts...>& y) {
if (y.valueless_by_exception())
return true;
if (x.valueless_by_exception())
return false;
if (x.index() != y.index())
return x.index() >= y.index();
variant_compare_helper<variant<Ts...>, std::greater_equal> f{x};
return visit(f, y);
return !(x < y);
}
/// @relates variant
......
......@@ -146,7 +146,6 @@ CAF_TEST(constructors) {
CAF_CHECK_EQUAL(a, 42);
CAF_CHECK_EQUAL(b, atom("foo"));
CAF_CHECK_EQUAL(d, 123);
CAF_CHECK_EQUAL(d, 123.0); // the unit test framework supports fuzzy compare
CAF_CHECK_NOT_EQUAL(d, std::string{"123"});
}
......@@ -161,6 +160,18 @@ CAF_TEST(n_ary_visit) {
CAF_CHECK_EQUAL(visit(f, a, b, c, d), "(42, 'foo', \"bar\", 123)");
}
CAF_TEST(get_if) {
variant<int ,string, atom_value> b = atom("foo");
CAF_MESSAGE("test get_if directly");
CAF_CHECK_EQUAL(get_if<int>(&b), nullptr);
CAF_CHECK_EQUAL(get_if<string>(&b), nullptr);
CAF_CHECK_NOT_EQUAL(get_if<atom_value>(&b), nullptr);
CAF_MESSAGE("test get_if via unit test framework");
CAF_CHECK_NOT_EQUAL(b, 42);
CAF_CHECK_NOT_EQUAL(b, string{"foo"});
CAF_CHECK_EQUAL(b, atom("foo"));
}
CAF_TEST(less_than) {
using variant_type = variant<char, int>;
auto a = variant_type{'x'};
......@@ -181,3 +192,9 @@ CAF_TEST(less_than) {
CAF_CHECK(a >= b);
b = 'x';
}
CAF_TEST(equality) {
variant<uint16_t, int> x = 42;
variant<uint16_t, int> y = uint16_t{42};
CAF_CHECK_NOT_EQUAL(x, y);
}
......@@ -44,17 +44,42 @@ struct anything { };
anything any_vals;
template <class T>
bool operator==(anything, const T&) {
return true;
struct maybe {
maybe(T x) : val(std::move(x)) {
// nop
}
maybe(anything) {
// nop
}
caf::optional<T> val;
};
template <class T>
std::string to_string(const maybe<T>& x) {
return to_string(x.val);
}
template <class T>
bool operator==(const maybe<T>& x, const T& y) {
return x.val ? x.val == y : true;
}
template <class T>
bool operator==(const T& x, const maybe<T>& y) {
return y.val ? x == y.val : true;
}
template <class T>
bool operator==(const T&, anything) {
return true;
bool operator!=(const maybe<T>& x, const T& y) {
return !(x == y);
}
template <class T>
using maybe = caf::variant<anything, T>;
bool operator!=(const T& x, const maybe<T>& y) {
return !(x == y);
}
constexpr uint8_t no_flags = 0;
constexpr uint32_t no_payload = 0;
......@@ -66,33 +91,6 @@ constexpr auto config_serv_atom = caf::atom("ConfigServ");
} // namespace <anonymous>
namespace std {
ostream& operator<<(ostream& out, const caf::io::basp::message_type& x) {
return out << to_string(x);
}
template <class T>
ostream& operator<<(ostream& out, const maybe<T>& x) {
using std::to_string;
using caf::to_string;
using caf::io::basp::to_string;
if (caf::get_if<anything>(&x) != nullptr)
return out << "*";
return out << to_string(get<T>(x));
}
} // namespace std
namespace caf {
template <class T>
std::string to_string(const maybe<T>& x) {
return !get_if<anything>(&x) ? std::string{"*"} : deep_to_string(get<T>(x));
}
} // namespace caf
using namespace std;
using namespace caf;
using namespace caf::io;
......@@ -397,7 +395,7 @@ public:
ob.erase(ob.begin(), ob.begin() + basp::header_size);
}
CAF_CHECK_EQUAL(operation, hdr.operation);
CAF_CHECK_EQUAL(flags, static_cast<size_t>(hdr.flags));
CAF_CHECK_EQUAL(flags, static_cast<uint8_t>(hdr.flags));
CAF_CHECK_EQUAL(payload_len, hdr.payload_len);
CAF_CHECK_EQUAL(operation_data, hdr.operation_data);
CAF_CHECK_EQUAL(source_node, hdr.source_node);
......
......@@ -48,17 +48,42 @@ struct anything { };
anything any_vals;
template <class T>
bool operator==(anything, const T&) {
return true;
struct maybe {
maybe(T x) : val(std::move(x)) {
// nop
}
maybe(anything) {
// nop
}
caf::optional<T> val;
};
template <class T>
std::string to_string(const maybe<T>& x) {
return to_string(x.val);
}
template <class T>
bool operator==(const T&, anything) {
return true;
bool operator==(const maybe<T>& x, const T& y) {
return x.val ? x.val == y : true;
}
template <class T>
using maybe = caf::variant<anything, T>;
bool operator==(const T& x, const maybe<T>& y) {
return y.val ? x == y.val : true;
}
template <class T>
bool operator!=(const maybe<T>& x, const T& y) {
return !(x == y);
}
template <class T>
bool operator!=(const T& x, const maybe<T>& y) {
return !(x == y);
}
constexpr uint8_t no_flags = 0;
constexpr uint32_t no_payload = 0;
......@@ -70,15 +95,6 @@ constexpr auto config_serv_atom = caf::atom("ConfigServ");
} // namespace <anonymous>
namespace caf {
template <class T>
std::string to_string(const maybe<T>& x) {
return !get_if<anything>(&x) ? std::string{"*"} : deep_to_string(get<T>(x));
}
} // namespace caf
using namespace std;
using namespace caf;
using namespace caf::io;
......@@ -397,7 +413,7 @@ public:
CAF_MESSAGE("erase message from output queue");
oq.pop_front();
CAF_CHECK_EQUAL(operation, hdr.operation);
CAF_CHECK_EQUAL(flags, static_cast<size_t>(hdr.flags));
CAF_CHECK_EQUAL(flags, static_cast<uint8_t>(hdr.flags));
CAF_CHECK_EQUAL(payload_len, hdr.payload_len);
CAF_CHECK_EQUAL(operation_data, hdr.operation_data);
CAF_CHECK_EQUAL(source_node, hdr.source_node);
......
......@@ -65,6 +65,8 @@ struct compare_visitor {
};
struct equality_operator {
static constexpr bool default_value = false;
template <class T, class U,
detail::enable_if_t<((std::is_floating_point<T>::value
&& std::is_convertible<U, double>::value)
......@@ -95,11 +97,13 @@ struct equality_operator {
typename std::enable_if<!detail::is_comparable<T, U>::value,
int>::type = 0>
bool operator()(const T&, const U&) const {
return false;
return default_value;
}
};
struct inequality_operator {
static constexpr bool default_value = true;
template <class T, class U,
typename std::enable_if<(std::is_floating_point<T>::value
|| std::is_floating_point<U>::value)
......@@ -123,7 +127,18 @@ struct inequality_operator {
typename std::enable_if<!detail::is_comparable<T, U>::value,
int>::type = 0>
bool operator()(const T&, const U&) const {
return true;
return default_value;
}
};
template <class F, class T>
struct comparison_unbox_helper {
const F& f;
const T& rhs;
template <class U>
bool operator()(const U& lhs) const {
return f(lhs, rhs);
}
};
......@@ -149,15 +164,23 @@ private:
}
template <class T, class U>
bool cmp(const T& x, const U& y, std::true_type, bool) const {
compare_visitor<U, comparison> f{y};
return visit(f, x);
bool cmp(const T& x, const U& y, std::true_type, std::false_type) const {
Operator f;
auto inner_x = caf::get_if<U>(&x);
return inner_x ? f(*inner_x, y) : Operator::default_value;
}
template <class T, class U>
bool cmp(const T& x, const U& y, std::false_type, std::true_type) const {
compare_visitor<T, comparison> f{x};
return visit(f, y);
Operator f;
auto inner_y = caf::get_if<T>(&y);
return inner_y ? f(x, *inner_y) : Operator::default_value;
}
template <class T, class U>
bool cmp(const T& x, const U& y, std::true_type, std::true_type) const {
comparison_unbox_helper<comparison, U> f{*this, y};
return visit(f, x);
}
};
......
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