Skip to content
Permalink
Browse files

api: fixed zero producing warnings for primitive types.

We also stop using empty() and ! as a basis for checking for zero-ness,
and instead we simply compare the current parameter with the zero value
of the type. This does requires that the type is default-constructible,
which is, I think, reasonable, because a type that does not have
a default-constructor cannot be guantanteed to define what a
"zero-value" of itself means, if any.

It is probably fine to make that assumption and document it as such, as
the obvious workaround is to cr_assert the appropriate boolean
condition.
  • Loading branch information
Snaipe committed Jan 4, 2020
1 parent 8a64683 commit 4b5174ebda04ab76fe65eec25b5b6ea0809055e7
Showing with 303 additions and 134 deletions.
  1. +2 −23 include/criterion/internal/assert/op.hxx
  2. +24 −0 include/criterion/new/assert.h
  3. +220 −110 test/cram/asserts.t
  4. +32 −0 test/full/failmessages.c
  5. +25 −1 test/full/failmessages.cc
@@ -30,32 +30,11 @@
namespace criterion { namespace internal { namespace operators {
/* *INDENT-ON* */

#define CRI_DEFINE_MEMBER_DETECTOR(Member) \
template <class T> \
class HasMember_ ## Member { \
private: \
using yes = char[2]; \
using no = char[1]; \
struct fallback { int Member; }; \
struct derived : T, fallback {}; \
template <class U> static no &test(decltype (U::Member) *); \
template <typename U> static yes &test(U *); \
public: \
static constexpr bool result = sizeof (test<derived>(nullptr)) == sizeof (yes); \
}; \
template <class T> \
struct has_member_ ## Member : public std::integral_constant<bool, HasMember_ ## Member<T>::result> {}

CRI_DEFINE_MEMBER_DETECTOR(empty);

template <typename T>
bool zero(const T *t) { return !t; }
bool zero(const T &t) { return t == T{}; }

template <typename T>
bool zero(const typename std::enable_if<!std::is_pointer<T>::value, T>::type &t) { return !t; }

template <typename T, typename = typename has_member_empty<T>::type>
bool zero(const T &t) { return t.empty(); }
bool zero(const T *t) { return !t; }

template <> inline bool zero<>(const char *t) { return !*t; }
template <> inline bool zero<>(const wchar_t *t) { return !*t; }
@@ -253,6 +253,30 @@
*/
#define ge(Tag, Actual, Reference)

/**
* Evaluates to true if `Value` is equal to the "zero value" of its type.
*
* The zero value for primitive types and pointer types is the constant 0.
*
* The zero value for c-strings (char *, wchar_t *) is the empty string,
* "" and L"" respectively.
*
* User-defined types may be used, but what a zero value of these types
* mean depend on the language used.
*
* In C, the function `bool cr_user_<type>_zero(const <type> *t)` must be
* defined, and will be invoked to check that `t` is a zero value.
*
* In C++, the type corresponding to the passed tag, or the inferred type of
* Value if the tag is unspecified, must be default-constructible. The
* zero value of that type is the default construction of that type, and
* the value is compared against it with ==.
*
* @param[in] "Tag (optional)" The type tag of the parameter
* @param[in] Value the value to compare for zeroness
*/
#define zero(Tag, Value)

/**
* Evaluates to true if the IEEE 754 floating point numbers `Actual` and
* `Expected` are almost equal, by being within `Ulp` units from each other.

0 comments on commit 4b5174e

Please sign in to comment.
You can’t perform that action at this time.