зеркало из https://github.com/mozilla/gecko-dev.git
Bug 732875 - 2/8 - Let CheckedInt support the 3 families of integer types: stdint, standard integer types, and PR types - r=jwalden
This commit is contained in:
Родитель
c170d6091a
Коммит
534e463c32
|
@ -42,6 +42,8 @@
|
|||
|
||||
#include "prtypes.h"
|
||||
|
||||
#include <mozilla/Assertions.h>
|
||||
|
||||
#include <climits>
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -55,80 +57,121 @@ namespace CheckedInt_internal {
|
|||
* helps much with twice_bigger_type.
|
||||
*/
|
||||
|
||||
/*** Step 1: manually record information for all the types that we want to support
|
||||
/*** Step 1: manually record supported types
|
||||
***
|
||||
*** What's nontrivial here is that there are different families of integer types: plain integer types, stdint types,
|
||||
*** and PR types. It is merrily undefined which types from one family may be just typedefs for a type from another family.
|
||||
***
|
||||
*** For example, on GCC 4.6, aside from the 10 'standard types' (including long long types), the only other type
|
||||
*** that isn't just a typedef for some of them, is int8_t.
|
||||
***/
|
||||
|
||||
struct unsupported_type {};
|
||||
|
||||
template<typename T> struct integer_type_manually_recorded_info
|
||||
{
|
||||
enum { is_supported = 0 };
|
||||
typedef unsupported_type twice_bigger_type;
|
||||
typedef unsupported_type unsigned_type;
|
||||
template<typename integer_type> struct is_supported_pass_3 {
|
||||
enum { value = 0 };
|
||||
};
|
||||
template<typename integer_type> struct is_supported_pass_2 {
|
||||
enum { value = is_supported_pass_3<integer_type>::value };
|
||||
};
|
||||
template<typename integer_type> struct is_supported {
|
||||
enum { value = is_supported_pass_2<integer_type>::value };
|
||||
};
|
||||
|
||||
template<> struct is_supported<int8_t> { enum { value = 1 }; };
|
||||
template<> struct is_supported<uint8_t> { enum { value = 1 }; };
|
||||
template<> struct is_supported<int16_t> { enum { value = 1 }; };
|
||||
template<> struct is_supported<uint16_t> { enum { value = 1 }; };
|
||||
template<> struct is_supported<int32_t> { enum { value = 1 }; };
|
||||
template<> struct is_supported<uint32_t> { enum { value = 1 }; };
|
||||
template<> struct is_supported<int64_t> { enum { value = 1 }; };
|
||||
template<> struct is_supported<uint64_t> { enum { value = 1 }; };
|
||||
|
||||
#define CHECKEDINT_REGISTER_SUPPORTED_TYPE(T,_twice_bigger_type,_unsigned_type) \
|
||||
template<> struct integer_type_manually_recorded_info<T> \
|
||||
{ \
|
||||
enum { is_supported = 1 }; \
|
||||
typedef _twice_bigger_type twice_bigger_type; \
|
||||
typedef _unsigned_type unsigned_type; \
|
||||
static void TYPE_NOT_SUPPORTED_BY_CheckedInt() {} \
|
||||
};
|
||||
template<> struct is_supported_pass_2<char> { enum { value = 1 }; };
|
||||
template<> struct is_supported_pass_2<unsigned char> { enum { value = 1 }; };
|
||||
template<> struct is_supported_pass_2<short> { enum { value = 1 }; };
|
||||
template<> struct is_supported_pass_2<unsigned short> { enum { value = 1 }; };
|
||||
template<> struct is_supported_pass_2<int> { enum { value = 1 }; };
|
||||
template<> struct is_supported_pass_2<unsigned int> { enum { value = 1 }; };
|
||||
template<> struct is_supported_pass_2<long> { enum { value = 1 }; };
|
||||
template<> struct is_supported_pass_2<unsigned long> { enum { value = 1 }; };
|
||||
template<> struct is_supported_pass_2<long long> { enum { value = 1 }; };
|
||||
template<> struct is_supported_pass_2<unsigned long long> { enum { value = 1 }; };
|
||||
|
||||
// Type Twice Bigger Type Unsigned Type
|
||||
CHECKEDINT_REGISTER_SUPPORTED_TYPE(int8_t, int16_t, uint8_t)
|
||||
CHECKEDINT_REGISTER_SUPPORTED_TYPE(uint8_t, uint16_t, uint8_t)
|
||||
CHECKEDINT_REGISTER_SUPPORTED_TYPE(int16_t, int32_t, uint16_t)
|
||||
CHECKEDINT_REGISTER_SUPPORTED_TYPE(uint16_t, uint32_t, uint16_t)
|
||||
CHECKEDINT_REGISTER_SUPPORTED_TYPE(int32_t, int64_t, uint32_t)
|
||||
CHECKEDINT_REGISTER_SUPPORTED_TYPE(uint32_t, uint64_t, uint32_t)
|
||||
CHECKEDINT_REGISTER_SUPPORTED_TYPE(int64_t, unsupported_type, uint64_t)
|
||||
CHECKEDINT_REGISTER_SUPPORTED_TYPE(uint64_t, unsupported_type, uint64_t)
|
||||
template<> struct is_supported_pass_3<PRInt8> { enum { value = 1 }; };
|
||||
template<> struct is_supported_pass_3<PRUint8> { enum { value = 1 }; };
|
||||
template<> struct is_supported_pass_3<PRInt16> { enum { value = 1 }; };
|
||||
template<> struct is_supported_pass_3<PRUint16> { enum { value = 1 }; };
|
||||
template<> struct is_supported_pass_3<PRInt32> { enum { value = 1 }; };
|
||||
template<> struct is_supported_pass_3<PRUint32> { enum { value = 1 }; };
|
||||
template<> struct is_supported_pass_3<PRInt64> { enum { value = 1 }; };
|
||||
template<> struct is_supported_pass_3<PRUint64> { enum { value = 1 }; };
|
||||
|
||||
|
||||
/*** Step 2: record some info about a given integer type,
|
||||
*** including whether it is supported, whether a twice bigger integer type
|
||||
*** is supported, what that twice bigger type is, and some stuff as found
|
||||
*** in std::numeric_limits (which we don't use because PRInt.. types may
|
||||
*** not support it, if they are defined directly from compiler built-in types).
|
||||
*** We use function names min_value() and max_value() instead of min() and max()
|
||||
*** because of stupid min/max macros in Windows headers.
|
||||
/*** Step 2: some integer-traits kind of stuff. We're doing our own thing here rather than
|
||||
*** relying on std::numeric_limits mostly for historical reasons (we still support PR integer types
|
||||
*** which might still be different types e.g. typedefs for some built-in types). Eventually, a patch
|
||||
*** replacing some of that by std::numeric_limits should be welcome.
|
||||
***/
|
||||
|
||||
template<typename T> struct is_unsupported_type { enum { answer = 0 }; };
|
||||
template<> struct is_unsupported_type<unsupported_type> { enum { answer = 1 }; };
|
||||
template<int size, bool signedness> struct stdint_type_for_size_and_signedness {};
|
||||
template<> struct stdint_type_for_size_and_signedness<1, true> { typedef int8_t type; };
|
||||
template<> struct stdint_type_for_size_and_signedness<1, false> { typedef uint8_t type; };
|
||||
template<> struct stdint_type_for_size_and_signedness<2, true> { typedef int16_t type; };
|
||||
template<> struct stdint_type_for_size_and_signedness<2, false> { typedef uint16_t type; };
|
||||
template<> struct stdint_type_for_size_and_signedness<4, true> { typedef int32_t type; };
|
||||
template<> struct stdint_type_for_size_and_signedness<4, false> { typedef uint32_t type; };
|
||||
template<> struct stdint_type_for_size_and_signedness<8, true> { typedef int64_t type; };
|
||||
template<> struct stdint_type_for_size_and_signedness<8, false> { typedef uint64_t type; };
|
||||
|
||||
template<typename T> struct integer_traits
|
||||
template<typename integer_type> struct unsigned_type {
|
||||
typedef typename stdint_type_for_size_and_signedness<sizeof(integer_type), false>::type type;
|
||||
};
|
||||
|
||||
template<typename integer_type> struct is_signed {
|
||||
enum { value = integer_type(-1) <= integer_type(0) };
|
||||
};
|
||||
|
||||
template<typename integer_type, int size=sizeof(integer_type)>
|
||||
struct twice_bigger_type {
|
||||
typedef typename stdint_type_for_size_and_signedness<
|
||||
sizeof(integer_type) * 2,
|
||||
is_signed<integer_type>::value
|
||||
>::type type;
|
||||
};
|
||||
|
||||
template<typename integer_type>
|
||||
struct twice_bigger_type<integer_type, 8> {
|
||||
typedef unsupported_type type;
|
||||
};
|
||||
|
||||
template<typename integer_type> struct position_of_sign_bit
|
||||
{
|
||||
typedef typename integer_type_manually_recorded_info<T>::twice_bigger_type twice_bigger_type;
|
||||
typedef typename integer_type_manually_recorded_info<T>::unsigned_type unsigned_type;
|
||||
|
||||
enum {
|
||||
is_supported = integer_type_manually_recorded_info<T>::is_supported,
|
||||
twice_bigger_type_is_supported
|
||||
= is_unsupported_type<
|
||||
typename integer_type_manually_recorded_info<T>::twice_bigger_type
|
||||
>::answer ? 0 : 1,
|
||||
size = sizeof(T),
|
||||
position_of_sign_bit = CHAR_BIT * size - 1,
|
||||
is_signed = (T(-1) > T(0)) ? 0 : 1
|
||||
value = CHAR_BIT * sizeof(integer_type) - 1
|
||||
};
|
||||
};
|
||||
|
||||
static T min_value()
|
||||
template<typename integer_type> struct min_value
|
||||
{
|
||||
static integer_type value()
|
||||
{
|
||||
// bitwise ops may return a larger type, that's why we cast explicitly to T
|
||||
// in C++, left bit shifts on signed values is undefined by the standard unless the shifted value is representable.
|
||||
// notice that signed-to-unsigned conversions are always well-defined in the standard,
|
||||
// as the value congruent to 2^n as expected. By contrast, unsigned-to-signed is only well-defined if the value is
|
||||
// representable.
|
||||
return is_signed ? T(unsigned_type(1) << position_of_sign_bit) : T(0);
|
||||
return is_signed<integer_type>::value
|
||||
? integer_type(typename unsigned_type<integer_type>::type(1) << position_of_sign_bit<integer_type>::value)
|
||||
: integer_type(0);
|
||||
}
|
||||
};
|
||||
|
||||
static T max_value()
|
||||
template<typename integer_type> struct max_value
|
||||
{
|
||||
static integer_type value()
|
||||
{
|
||||
return ~min_value();
|
||||
return ~min_value<integer_type>::value();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -144,8 +187,7 @@ template<typename T> inline T has_sign_bit(T x)
|
|||
// notice that signed-to-unsigned conversions are always well-defined in the standard,
|
||||
// as the value congruent modulo 2^n as expected. By contrast, unsigned-to-signed is only well-defined if the value is
|
||||
// representable. Here the unsigned-to-signed conversion is OK because the value (the result of the shift) is 0 or 1.
|
||||
typedef typename integer_traits<T>::unsigned_type unsigned_T;
|
||||
return T(unsigned_T(x) >> integer_traits<T>::position_of_sign_bit);
|
||||
return T(typename unsigned_type<T>::type(x) >> position_of_sign_bit<T>::value);
|
||||
}
|
||||
|
||||
template<typename T> inline T binary_complement(T x)
|
||||
|
@ -154,8 +196,8 @@ template<typename T> inline T binary_complement(T x)
|
|||
}
|
||||
|
||||
template<typename T, typename U,
|
||||
bool is_T_signed = integer_traits<T>::is_signed,
|
||||
bool is_U_signed = integer_traits<U>::is_signed>
|
||||
bool is_T_signed = is_signed<T>::value,
|
||||
bool is_U_signed = is_signed<U>::value>
|
||||
struct is_in_range_impl {};
|
||||
|
||||
template<typename T, typename U>
|
||||
|
@ -163,8 +205,8 @@ struct is_in_range_impl<T, U, true, true>
|
|||
{
|
||||
static T run(U x)
|
||||
{
|
||||
return (x <= integer_traits<T>::max_value()) &&
|
||||
(x >= integer_traits<T>::min_value());
|
||||
return (x <= max_value<T>::value()) &&
|
||||
(x >= min_value<T>::value());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -173,7 +215,7 @@ struct is_in_range_impl<T, U, false, false>
|
|||
{
|
||||
static T run(U x)
|
||||
{
|
||||
return x <= integer_traits<T>::max_value();
|
||||
return x <= max_value<T>::value();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -185,7 +227,7 @@ struct is_in_range_impl<T, U, true, false>
|
|||
if (sizeof(T) > sizeof(U))
|
||||
return 1;
|
||||
else
|
||||
return x <= U(integer_traits<T>::max_value());
|
||||
return x <= U(max_value<T>::value());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -197,7 +239,7 @@ struct is_in_range_impl<T, U, false, true>
|
|||
if (sizeof(T) >= sizeof(U))
|
||||
return x >= 0;
|
||||
else
|
||||
return (x >= 0) && (x <= U(integer_traits<T>::max_value()));
|
||||
return (x >= 0) && (x <= U(max_value<T>::value()));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -208,27 +250,27 @@ template<typename T, typename U> inline T is_in_range(U x)
|
|||
|
||||
template<typename T> inline T is_add_valid(T x, T y, T result)
|
||||
{
|
||||
return integer_traits<T>::is_signed ?
|
||||
// addition is valid if the sign of x+y is equal to either that of x or that of y.
|
||||
// Beware! These bitwise operations can return a larger integer type, if T was a
|
||||
// small type like int8, so we explicitly cast to T.
|
||||
has_sign_bit(binary_complement(T((result^x) & (result^y))))
|
||||
:
|
||||
binary_complement(x) >= y;
|
||||
return is_signed<T>::value ?
|
||||
// addition is valid if the sign of x+y is equal to either that of x or that of y.
|
||||
// Beware! These bitwise operations can return a larger integer type, if T was a
|
||||
// small type like int8, so we explicitly cast to T.
|
||||
has_sign_bit(binary_complement(T((result^x) & (result^y))))
|
||||
:
|
||||
binary_complement(x) >= y;
|
||||
}
|
||||
|
||||
template<typename T> inline T is_sub_valid(T x, T y, T result)
|
||||
{
|
||||
return integer_traits<T>::is_signed ?
|
||||
// substraction is valid if either x and y have same sign, or x-y and x have same sign
|
||||
has_sign_bit(binary_complement(T((result^x) & (x^y))))
|
||||
:
|
||||
x >= y;
|
||||
return is_signed<T>::value ?
|
||||
// substraction is valid if either x and y have same sign, or x-y and x have same sign
|
||||
has_sign_bit(binary_complement(T((result^x) & (x^y))))
|
||||
:
|
||||
x >= y;
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
bool is_signed = integer_traits<T>::is_signed,
|
||||
bool twice_bigger_type_is_supported = integer_traits<T>::twice_bigger_type_is_supported>
|
||||
bool is_signed = is_signed<T>::value,
|
||||
bool twice_bigger_type_is_supported = is_supported<typename twice_bigger_type<T>::type>::value>
|
||||
struct is_mul_valid_impl {};
|
||||
|
||||
template<typename T, bool is_signed>
|
||||
|
@ -236,7 +278,7 @@ struct is_mul_valid_impl<T, is_signed, true>
|
|||
{
|
||||
static T run(T x, T y)
|
||||
{
|
||||
typedef typename integer_traits<T>::twice_bigger_type twice_bigger_type;
|
||||
typedef typename twice_bigger_type<T>::type twice_bigger_type;
|
||||
twice_bigger_type product = twice_bigger_type(x) * twice_bigger_type(y);
|
||||
return is_in_range<T>(product);
|
||||
}
|
||||
|
@ -247,21 +289,21 @@ struct is_mul_valid_impl<T, true, false>
|
|||
{
|
||||
static T run(T x, T y)
|
||||
{
|
||||
const T max_value = integer_traits<T>::max_value();
|
||||
const T min_value = integer_traits<T>::min_value();
|
||||
const T max = max_value<T>::value();
|
||||
const T min = min_value<T>::value();
|
||||
|
||||
if (x == 0 || y == 0) return true;
|
||||
|
||||
if (x > 0) {
|
||||
if (y > 0)
|
||||
return x <= max_value / y;
|
||||
return x <= max / y;
|
||||
else
|
||||
return y >= min_value / x;
|
||||
return y >= min / x;
|
||||
} else {
|
||||
if (y > 0)
|
||||
return x >= min_value / y;
|
||||
return x >= min / y;
|
||||
else
|
||||
return y >= max_value / x;
|
||||
return y >= max / x;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -271,9 +313,9 @@ struct is_mul_valid_impl<T, false, false>
|
|||
{
|
||||
static T run(T x, T y)
|
||||
{
|
||||
const T max_value = integer_traits<T>::max_value();
|
||||
const T max = max_value<T>::value();
|
||||
if (x == 0 || y == 0) return true;
|
||||
return x <= max_value / y;
|
||||
return x <= max / y;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -284,15 +326,15 @@ template<typename T> inline T is_mul_valid(T x, T y, T /*result not used*/)
|
|||
|
||||
template<typename T> inline T is_div_valid(T x, T y)
|
||||
{
|
||||
return integer_traits<T>::is_signed ?
|
||||
// keep in mind that min/-1 is invalid because abs(min)>max
|
||||
(y != 0) && (x != integer_traits<T>::min_value() || y != T(-1))
|
||||
:
|
||||
y != 0;
|
||||
return is_signed<T>::value ?
|
||||
// keep in mind that min/-1 is invalid because abs(min)>max
|
||||
(y != 0) && (x != min_value<T>::value() || y != T(-1))
|
||||
:
|
||||
y != 0;
|
||||
}
|
||||
|
||||
// this is just to shut up msvc warnings about negating unsigned ints.
|
||||
template<typename T, bool is_signed = integer_traits<T>::is_signed>
|
||||
template<typename T, bool is_signed = is_signed<T>::value>
|
||||
struct opposite_if_signed_impl
|
||||
{
|
||||
static T run(T x) { return -x; }
|
||||
|
@ -374,8 +416,7 @@ protected:
|
|||
template<typename U>
|
||||
CheckedInt(U value, T isValid) : mValue(value), mIsValid(isValid)
|
||||
{
|
||||
CheckedInt_internal::integer_type_manually_recorded_info<T>
|
||||
::TYPE_NOT_SUPPORTED_BY_CheckedInt();
|
||||
MOZ_STATIC_ASSERT(CheckedInt_internal::is_supported<T>::value, "This type is not supported by CheckedInt");
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -392,15 +433,13 @@ public:
|
|||
: mValue(T(value)),
|
||||
mIsValid(CheckedInt_internal::is_in_range<T>(value))
|
||||
{
|
||||
CheckedInt_internal::integer_type_manually_recorded_info<T>
|
||||
::TYPE_NOT_SUPPORTED_BY_CheckedInt();
|
||||
MOZ_STATIC_ASSERT(CheckedInt_internal::is_supported<T>::value, "This type is not supported by CheckedInt");
|
||||
}
|
||||
|
||||
/** Constructs a valid checked integer with initial value 0 */
|
||||
CheckedInt() : mValue(0), mIsValid(1)
|
||||
{
|
||||
CheckedInt_internal::integer_type_manually_recorded_info<T>
|
||||
::TYPE_NOT_SUPPORTED_BY_CheckedInt();
|
||||
MOZ_STATIC_ASSERT(CheckedInt_internal::is_supported<T>::value, "This type is not supported by CheckedInt");
|
||||
}
|
||||
|
||||
/** \returns the actual value */
|
||||
|
|
|
@ -45,12 +45,13 @@ namespace CheckedInt_test {
|
|||
using namespace mozilla::CheckedInt_internal;
|
||||
using mozilla::CheckedInt;
|
||||
|
||||
int g_integer_types_tested = 0;
|
||||
int g_tests_passed = 0;
|
||||
int g_tests_failed = 0;
|
||||
|
||||
void verify_impl_function(bool x, bool expected,
|
||||
const char* file, int line,
|
||||
int T_size, bool T_is_signed)
|
||||
int T_size, bool T_is_T_signed)
|
||||
{
|
||||
if (x == expected) {
|
||||
g_tests_passed++;
|
||||
|
@ -58,7 +59,7 @@ void verify_impl_function(bool x, bool expected,
|
|||
g_tests_failed++;
|
||||
std::cerr << "Test failed at " << file << ":" << line;
|
||||
std::cerr << " with T a ";
|
||||
if(T_is_signed)
|
||||
if(T_is_T_signed)
|
||||
std::cerr << "signed";
|
||||
else
|
||||
std::cerr << "unsigned";
|
||||
|
@ -67,7 +68,7 @@ void verify_impl_function(bool x, bool expected,
|
|||
}
|
||||
|
||||
#define VERIFY_IMPL(x, expected) \
|
||||
verify_impl_function((x), (expected), __FILE__, __LINE__, sizeof(T), integer_traits<T>::is_signed)
|
||||
verify_impl_function((x), (expected), __FILE__, __LINE__, sizeof(T), is_signed<T>::value)
|
||||
|
||||
#define VERIFY(x) VERIFY_IMPL(x, true)
|
||||
#define VERIFY_IS_FALSE(x) VERIFY_IMPL(x, false)
|
||||
|
@ -80,12 +81,11 @@ struct test_twice_bigger_type
|
|||
{
|
||||
static void run()
|
||||
{
|
||||
VERIFY(integer_traits<T>::twice_bigger_type_is_supported);
|
||||
VERIFY(sizeof(typename integer_traits<T>::twice_bigger_type)
|
||||
== 2 * sizeof(T));
|
||||
VERIFY(bool(integer_traits<
|
||||
typename integer_traits<T>::twice_bigger_type
|
||||
>::is_signed) == bool(integer_traits<T>::is_signed));
|
||||
VERIFY(is_supported<typename twice_bigger_type<T>::type>::value);
|
||||
VERIFY(sizeof(typename twice_bigger_type<T>::type)
|
||||
== 2 * sizeof(T));
|
||||
VERIFY(bool(is_signed<typename twice_bigger_type<T>::type>::value)
|
||||
== bool(is_signed<T>::value));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -94,7 +94,7 @@ struct test_twice_bigger_type<T, 8>
|
|||
{
|
||||
static void run()
|
||||
{
|
||||
VERIFY_IS_FALSE(integer_traits<T>::twice_bigger_type_is_supported);
|
||||
VERIFY_IS_FALSE(is_supported<typename twice_bigger_type<T>::type>::value);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -103,45 +103,44 @@ template<typename T>
|
|||
void test()
|
||||
{
|
||||
static bool already_run = false;
|
||||
if (already_run) {
|
||||
g_tests_failed++;
|
||||
std::cerr << "You already tested this type. Copy/paste typo??" << std::endl;
|
||||
// integer types from different families may just be typedefs for types from other families.
|
||||
// e.g. int32_t might be just a typedef for int. No point re-running the same tests then.
|
||||
if (already_run)
|
||||
return;
|
||||
}
|
||||
already_run = true;
|
||||
g_integer_types_tested++;
|
||||
|
||||
VERIFY(integer_traits<T>::is_supported);
|
||||
VERIFY(integer_traits<T>::size == sizeof(T));
|
||||
enum{ is_signed = integer_traits<T>::is_signed };
|
||||
VERIFY(bool(is_signed) == !bool(T(-1) > T(0)));
|
||||
VERIFY(is_supported<T>::value);
|
||||
enum{ is_T_signed = is_signed<T>::value };
|
||||
VERIFY(bool(is_T_signed) == !bool(T(-1) > T(0)));
|
||||
|
||||
test_twice_bigger_type<T>::run();
|
||||
|
||||
typedef typename integer_traits<T>::unsigned_type unsigned_T;
|
||||
typedef typename unsigned_type<T>::type unsigned_T;
|
||||
|
||||
VERIFY(sizeof(unsigned_T) == sizeof(T));
|
||||
VERIFY(integer_traits<unsigned_T>::is_signed == false);
|
||||
VERIFY(is_signed<unsigned_T>::value == false);
|
||||
|
||||
CheckedInt<T> max_value(integer_traits<T>::max_value());
|
||||
CheckedInt<T> min_value(integer_traits<T>::min_value());
|
||||
const CheckedInt<T> max(max_value<T>::value());
|
||||
const CheckedInt<T> min(min_value<T>::value());
|
||||
|
||||
// check min_value() and max_value(), since they are custom implementations and a mistake there
|
||||
// check min() and max(), since they are custom implementations and a mistake there
|
||||
// could potentially NOT be caught by any other tests... while making everything wrong!
|
||||
|
||||
T bit = 1;
|
||||
for(unsigned int i = 0; i < sizeof(T) * CHAR_BIT - 1; i++)
|
||||
{
|
||||
VERIFY((min_value.value() & bit) == 0);
|
||||
VERIFY((min.value() & bit) == 0);
|
||||
bit <<= 1;
|
||||
}
|
||||
VERIFY((min_value.value() & bit) == (is_signed ? bit : T(0)));
|
||||
VERIFY(max_value.value() == T(~(min_value.value())));
|
||||
VERIFY((min.value() & bit) == (is_T_signed ? bit : T(0)));
|
||||
VERIFY(max.value() == T(~(min.value())));
|
||||
|
||||
CheckedInt<T> zero(0);
|
||||
CheckedInt<T> one(1);
|
||||
CheckedInt<T> two(2);
|
||||
CheckedInt<T> three(3);
|
||||
CheckedInt<T> four(4);
|
||||
const CheckedInt<T> zero(0);
|
||||
const CheckedInt<T> one(1);
|
||||
const CheckedInt<T> two(2);
|
||||
const CheckedInt<T> three(3);
|
||||
const CheckedInt<T> four(4);
|
||||
|
||||
/* addition / substraction checks */
|
||||
|
||||
|
@ -153,77 +152,77 @@ void test()
|
|||
VERIFY_IS_VALID(one+one);
|
||||
VERIFY(one+one == two);
|
||||
|
||||
CheckedInt<T> max_value_minus_one = max_value - one;
|
||||
CheckedInt<T> max_value_minus_two = max_value - two;
|
||||
VERIFY_IS_VALID(max_value_minus_one);
|
||||
VERIFY_IS_VALID(max_value_minus_two);
|
||||
VERIFY_IS_VALID(max_value_minus_one + one);
|
||||
VERIFY_IS_VALID(max_value_minus_two + one);
|
||||
VERIFY_IS_VALID(max_value_minus_two + two);
|
||||
VERIFY(max_value_minus_one + one == max_value);
|
||||
VERIFY(max_value_minus_two + one == max_value_minus_one);
|
||||
VERIFY(max_value_minus_two + two == max_value);
|
||||
const CheckedInt<T> max_minus_one = max - one;
|
||||
const CheckedInt<T> max_minus_two = max - two;
|
||||
VERIFY_IS_VALID(max_minus_one);
|
||||
VERIFY_IS_VALID(max_minus_two);
|
||||
VERIFY_IS_VALID(max_minus_one + one);
|
||||
VERIFY_IS_VALID(max_minus_two + one);
|
||||
VERIFY_IS_VALID(max_minus_two + two);
|
||||
VERIFY(max_minus_one + one == max);
|
||||
VERIFY(max_minus_two + one == max_minus_one);
|
||||
VERIFY(max_minus_two + two == max);
|
||||
|
||||
VERIFY_IS_VALID(max_value + zero);
|
||||
VERIFY_IS_VALID(max_value - zero);
|
||||
VERIFY_IS_INVALID(max_value + one);
|
||||
VERIFY_IS_INVALID(max_value + two);
|
||||
VERIFY_IS_INVALID(max_value + max_value_minus_one);
|
||||
VERIFY_IS_INVALID(max_value + max_value);
|
||||
VERIFY_IS_VALID(max + zero);
|
||||
VERIFY_IS_VALID(max - zero);
|
||||
VERIFY_IS_INVALID(max + one);
|
||||
VERIFY_IS_INVALID(max + two);
|
||||
VERIFY_IS_INVALID(max + max_minus_one);
|
||||
VERIFY_IS_INVALID(max + max);
|
||||
|
||||
CheckedInt<T> min_value_plus_one = min_value + one;
|
||||
CheckedInt<T> min_value_plus_two = min_value + two;
|
||||
VERIFY_IS_VALID(min_value_plus_one);
|
||||
VERIFY_IS_VALID(min_value_plus_two);
|
||||
VERIFY_IS_VALID(min_value_plus_one - one);
|
||||
VERIFY_IS_VALID(min_value_plus_two - one);
|
||||
VERIFY_IS_VALID(min_value_plus_two - two);
|
||||
VERIFY(min_value_plus_one - one == min_value);
|
||||
VERIFY(min_value_plus_two - one == min_value_plus_one);
|
||||
VERIFY(min_value_plus_two - two == min_value);
|
||||
const CheckedInt<T> min_plus_one = min + one;
|
||||
const CheckedInt<T> min_plus_two = min + two;
|
||||
VERIFY_IS_VALID(min_plus_one);
|
||||
VERIFY_IS_VALID(min_plus_two);
|
||||
VERIFY_IS_VALID(min_plus_one - one);
|
||||
VERIFY_IS_VALID(min_plus_two - one);
|
||||
VERIFY_IS_VALID(min_plus_two - two);
|
||||
VERIFY(min_plus_one - one == min);
|
||||
VERIFY(min_plus_two - one == min_plus_one);
|
||||
VERIFY(min_plus_two - two == min);
|
||||
|
||||
CheckedInt<T> min_value_minus_one = min_value - one;
|
||||
VERIFY_IS_VALID(min_value + zero);
|
||||
VERIFY_IS_VALID(min_value - zero);
|
||||
VERIFY_IS_INVALID(min_value - one);
|
||||
VERIFY_IS_INVALID(min_value - two);
|
||||
VERIFY_IS_INVALID(min_value - min_value_minus_one);
|
||||
VERIFY_IS_VALID(min_value - min_value);
|
||||
const CheckedInt<T> min_minus_one = min - one;
|
||||
VERIFY_IS_VALID(min + zero);
|
||||
VERIFY_IS_VALID(min - zero);
|
||||
VERIFY_IS_INVALID(min - one);
|
||||
VERIFY_IS_INVALID(min - two);
|
||||
VERIFY_IS_INVALID(min - min_minus_one);
|
||||
VERIFY_IS_VALID(min - min);
|
||||
|
||||
CheckedInt<T> max_value_over_two = max_value / two;
|
||||
VERIFY_IS_VALID(max_value_over_two + max_value_over_two);
|
||||
VERIFY_IS_VALID(max_value_over_two + one);
|
||||
VERIFY((max_value_over_two + one) - one == max_value_over_two);
|
||||
VERIFY_IS_VALID(max_value_over_two - max_value_over_two);
|
||||
VERIFY(max_value_over_two - max_value_over_two == zero);
|
||||
const CheckedInt<T> max_over_two = max / two;
|
||||
VERIFY_IS_VALID(max_over_two + max_over_two);
|
||||
VERIFY_IS_VALID(max_over_two + one);
|
||||
VERIFY((max_over_two + one) - one == max_over_two);
|
||||
VERIFY_IS_VALID(max_over_two - max_over_two);
|
||||
VERIFY(max_over_two - max_over_two == zero);
|
||||
|
||||
CheckedInt<T> min_value_over_two = min_value / two;
|
||||
VERIFY_IS_VALID(min_value_over_two + min_value_over_two);
|
||||
VERIFY_IS_VALID(min_value_over_two + one);
|
||||
VERIFY((min_value_over_two + one) - one == min_value_over_two);
|
||||
VERIFY_IS_VALID(min_value_over_two - min_value_over_two);
|
||||
VERIFY(min_value_over_two - min_value_over_two == zero);
|
||||
const CheckedInt<T> min_over_two = min / two;
|
||||
VERIFY_IS_VALID(min_over_two + min_over_two);
|
||||
VERIFY_IS_VALID(min_over_two + one);
|
||||
VERIFY((min_over_two + one) - one == min_over_two);
|
||||
VERIFY_IS_VALID(min_over_two - min_over_two);
|
||||
VERIFY(min_over_two - min_over_two == zero);
|
||||
|
||||
VERIFY_IS_INVALID(min_value - one);
|
||||
VERIFY_IS_INVALID(min_value - two);
|
||||
VERIFY_IS_INVALID(min - one);
|
||||
VERIFY_IS_INVALID(min - two);
|
||||
|
||||
if (is_signed) {
|
||||
VERIFY_IS_INVALID(min_value + min_value);
|
||||
VERIFY_IS_INVALID(min_value_over_two + min_value_over_two + min_value_over_two);
|
||||
VERIFY_IS_INVALID(zero - min_value + min_value);
|
||||
VERIFY_IS_INVALID(one - min_value + min_value);
|
||||
if (is_T_signed) {
|
||||
VERIFY_IS_INVALID(min + min);
|
||||
VERIFY_IS_INVALID(min_over_two + min_over_two + min_over_two);
|
||||
VERIFY_IS_INVALID(zero - min + min);
|
||||
VERIFY_IS_INVALID(one - min + min);
|
||||
}
|
||||
|
||||
/* unary operator- checks */
|
||||
|
||||
CheckedInt<T> neg_one = -one;
|
||||
CheckedInt<T> neg_two = -two;
|
||||
const CheckedInt<T> neg_one = -one;
|
||||
const CheckedInt<T> neg_two = -two;
|
||||
|
||||
if (is_signed) {
|
||||
VERIFY_IS_VALID(-max_value);
|
||||
VERIFY_IS_VALID(-max_value - one);
|
||||
if (is_T_signed) {
|
||||
VERIFY_IS_VALID(-max);
|
||||
VERIFY_IS_VALID(-max - one);
|
||||
VERIFY_IS_VALID(neg_one);
|
||||
VERIFY_IS_VALID(-max_value + neg_one);
|
||||
VERIFY_IS_VALID(-max + neg_one);
|
||||
VERIFY_IS_VALID(neg_one + one);
|
||||
VERIFY(neg_one + one == zero);
|
||||
VERIFY_IS_VALID(neg_two);
|
||||
|
@ -248,77 +247,77 @@ void test()
|
|||
VERIFY_IS_VALID(two*two);
|
||||
VERIFY(two*two == four);
|
||||
|
||||
VERIFY_IS_INVALID(max_value * max_value);
|
||||
VERIFY_IS_INVALID(max_value_over_two * max_value);
|
||||
VERIFY_IS_INVALID(max_value_over_two * max_value_over_two);
|
||||
VERIFY_IS_INVALID(max * max);
|
||||
VERIFY_IS_INVALID(max_over_two * max);
|
||||
VERIFY_IS_INVALID(max_over_two * max_over_two);
|
||||
|
||||
CheckedInt<T> max_value_approx_sqrt(T(T(1) << (CHAR_BIT*sizeof(T)/2)));
|
||||
const CheckedInt<T> max_approx_sqrt(T(T(1) << (CHAR_BIT*sizeof(T)/2)));
|
||||
|
||||
VERIFY_IS_VALID(max_value_approx_sqrt);
|
||||
VERIFY_IS_VALID(max_value_approx_sqrt * two);
|
||||
VERIFY_IS_INVALID(max_value_approx_sqrt * max_value_approx_sqrt);
|
||||
VERIFY_IS_INVALID(max_value_approx_sqrt * max_value_approx_sqrt * max_value_approx_sqrt);
|
||||
VERIFY_IS_VALID(max_approx_sqrt);
|
||||
VERIFY_IS_VALID(max_approx_sqrt * two);
|
||||
VERIFY_IS_INVALID(max_approx_sqrt * max_approx_sqrt);
|
||||
VERIFY_IS_INVALID(max_approx_sqrt * max_approx_sqrt * max_approx_sqrt);
|
||||
|
||||
if (is_signed) {
|
||||
VERIFY_IS_INVALID(min_value * min_value);
|
||||
VERIFY_IS_INVALID(min_value_over_two * min_value);
|
||||
VERIFY_IS_INVALID(min_value_over_two * min_value_over_two);
|
||||
if (is_T_signed) {
|
||||
VERIFY_IS_INVALID(min * min);
|
||||
VERIFY_IS_INVALID(min_over_two * min);
|
||||
VERIFY_IS_INVALID(min_over_two * min_over_two);
|
||||
|
||||
CheckedInt<T> min_value_approx_sqrt = -max_value_approx_sqrt;
|
||||
const CheckedInt<T> min_approx_sqrt = -max_approx_sqrt;
|
||||
|
||||
VERIFY_IS_VALID(min_value_approx_sqrt);
|
||||
VERIFY_IS_VALID(min_value_approx_sqrt * two);
|
||||
VERIFY_IS_INVALID(min_value_approx_sqrt * max_value_approx_sqrt);
|
||||
VERIFY_IS_INVALID(min_value_approx_sqrt * min_value_approx_sqrt);
|
||||
VERIFY_IS_VALID(min_approx_sqrt);
|
||||
VERIFY_IS_VALID(min_approx_sqrt * two);
|
||||
VERIFY_IS_INVALID(min_approx_sqrt * max_approx_sqrt);
|
||||
VERIFY_IS_INVALID(min_approx_sqrt * min_approx_sqrt);
|
||||
}
|
||||
|
||||
// make sure to check all 4 paths in signed multiplication validity check.
|
||||
// test positive * positive
|
||||
VERIFY_IS_VALID(max_value * one);
|
||||
VERIFY(max_value * one == max_value);
|
||||
VERIFY_IS_INVALID(max_value * two);
|
||||
VERIFY_IS_VALID(max_value_over_two * two);
|
||||
VERIFY((max_value_over_two + max_value_over_two) == (max_value_over_two * two));
|
||||
VERIFY_IS_VALID(max * one);
|
||||
VERIFY(max * one == max);
|
||||
VERIFY_IS_INVALID(max * two);
|
||||
VERIFY_IS_VALID(max_over_two * two);
|
||||
VERIFY((max_over_two + max_over_two) == (max_over_two * two));
|
||||
|
||||
if (is_signed) {
|
||||
if (is_T_signed) {
|
||||
// test positive * negative
|
||||
VERIFY_IS_VALID(max_value * neg_one);
|
||||
VERIFY_IS_VALID(-max_value);
|
||||
VERIFY(max_value * neg_one == -max_value);
|
||||
VERIFY_IS_VALID(one * min_value);
|
||||
VERIFY_IS_INVALID(max_value * neg_two);
|
||||
VERIFY_IS_VALID(max_value_over_two * neg_two);
|
||||
VERIFY_IS_VALID(two * min_value_over_two);
|
||||
VERIFY_IS_VALID((max_value_over_two + one) * neg_two);
|
||||
VERIFY_IS_INVALID((max_value_over_two + two) * neg_two);
|
||||
VERIFY_IS_INVALID(two * (min_value_over_two - one));
|
||||
VERIFY_IS_VALID(max * neg_one);
|
||||
VERIFY_IS_VALID(-max);
|
||||
VERIFY(max * neg_one == -max);
|
||||
VERIFY_IS_VALID(one * min);
|
||||
VERIFY_IS_INVALID(max * neg_two);
|
||||
VERIFY_IS_VALID(max_over_two * neg_two);
|
||||
VERIFY_IS_VALID(two * min_over_two);
|
||||
VERIFY_IS_VALID((max_over_two + one) * neg_two);
|
||||
VERIFY_IS_INVALID((max_over_two + two) * neg_two);
|
||||
VERIFY_IS_INVALID(two * (min_over_two - one));
|
||||
|
||||
// test negative * positive
|
||||
VERIFY_IS_VALID(min_value * one);
|
||||
VERIFY_IS_VALID(min_value_plus_one * one);
|
||||
VERIFY_IS_INVALID(min_value * two);
|
||||
VERIFY_IS_VALID(min_value_over_two * two);
|
||||
VERIFY(min_value_over_two * two == min_value);
|
||||
VERIFY_IS_INVALID((min_value_over_two - one) * neg_two);
|
||||
VERIFY_IS_INVALID(neg_two * max_value);
|
||||
VERIFY_IS_VALID(min_value_over_two * two);
|
||||
VERIFY(min_value_over_two * two == min_value);
|
||||
VERIFY_IS_VALID(neg_two * max_value_over_two);
|
||||
VERIFY_IS_INVALID((min_value_over_two - one) * two);
|
||||
VERIFY_IS_VALID(neg_two * (max_value_over_two + one));
|
||||
VERIFY_IS_INVALID(neg_two * (max_value_over_two + two));
|
||||
VERIFY_IS_VALID(min * one);
|
||||
VERIFY_IS_VALID(min_plus_one * one);
|
||||
VERIFY_IS_INVALID(min * two);
|
||||
VERIFY_IS_VALID(min_over_two * two);
|
||||
VERIFY(min_over_two * two == min);
|
||||
VERIFY_IS_INVALID((min_over_two - one) * neg_two);
|
||||
VERIFY_IS_INVALID(neg_two * max);
|
||||
VERIFY_IS_VALID(min_over_two * two);
|
||||
VERIFY(min_over_two * two == min);
|
||||
VERIFY_IS_VALID(neg_two * max_over_two);
|
||||
VERIFY_IS_INVALID((min_over_two - one) * two);
|
||||
VERIFY_IS_VALID(neg_two * (max_over_two + one));
|
||||
VERIFY_IS_INVALID(neg_two * (max_over_two + two));
|
||||
|
||||
// test negative * negative
|
||||
VERIFY_IS_INVALID(min_value * neg_one);
|
||||
VERIFY_IS_VALID(min_value_plus_one * neg_one);
|
||||
VERIFY(min_value_plus_one * neg_one == max_value);
|
||||
VERIFY_IS_INVALID(min_value * neg_two);
|
||||
VERIFY_IS_INVALID(min_value_over_two * neg_two);
|
||||
VERIFY_IS_INVALID(neg_one * min_value);
|
||||
VERIFY_IS_VALID(neg_one * min_value_plus_one);
|
||||
VERIFY(neg_one * min_value_plus_one == max_value);
|
||||
VERIFY_IS_INVALID(neg_two * min_value);
|
||||
VERIFY_IS_INVALID(neg_two * min_value_over_two);
|
||||
VERIFY_IS_INVALID(min * neg_one);
|
||||
VERIFY_IS_VALID(min_plus_one * neg_one);
|
||||
VERIFY(min_plus_one * neg_one == max);
|
||||
VERIFY_IS_INVALID(min * neg_two);
|
||||
VERIFY_IS_INVALID(min_over_two * neg_two);
|
||||
VERIFY_IS_INVALID(neg_one * min);
|
||||
VERIFY_IS_VALID(neg_one * min_plus_one);
|
||||
VERIFY(neg_one * min_plus_one == max);
|
||||
VERIFY_IS_INVALID(neg_two * min);
|
||||
VERIFY_IS_INVALID(neg_two * min_over_two);
|
||||
}
|
||||
|
||||
/* division checks */
|
||||
|
@ -336,23 +335,23 @@ void test()
|
|||
VERIFY_IS_INVALID(one / zero);
|
||||
VERIFY_IS_INVALID(two / zero);
|
||||
VERIFY_IS_INVALID(neg_one / zero);
|
||||
VERIFY_IS_INVALID(max_value / zero);
|
||||
VERIFY_IS_INVALID(min_value / zero);
|
||||
VERIFY_IS_INVALID(max / zero);
|
||||
VERIFY_IS_INVALID(min / zero);
|
||||
|
||||
if (is_signed) {
|
||||
// check that min_value / -1 is invalid
|
||||
VERIFY_IS_INVALID(min_value / neg_one);
|
||||
if (is_T_signed) {
|
||||
// check that min / -1 is invalid
|
||||
VERIFY_IS_INVALID(min / neg_one);
|
||||
|
||||
// check that the test for div by -1 isn't banning other numerators than min_value
|
||||
// check that the test for div by -1 isn't banning other numerators than min
|
||||
VERIFY_IS_VALID(one / neg_one);
|
||||
VERIFY_IS_VALID(zero / neg_one);
|
||||
VERIFY_IS_VALID(neg_one / neg_one);
|
||||
VERIFY_IS_VALID(max_value / neg_one);
|
||||
VERIFY_IS_VALID(max / neg_one);
|
||||
}
|
||||
|
||||
/* check that invalidity is correctly preserved by arithmetic ops */
|
||||
|
||||
CheckedInt<T> some_invalid = max_value + max_value;
|
||||
const CheckedInt<T> some_invalid = max + max;
|
||||
VERIFY_IS_INVALID(some_invalid + zero);
|
||||
VERIFY_IS_INVALID(some_invalid - zero);
|
||||
VERIFY_IS_INVALID(zero + some_invalid);
|
||||
|
@ -413,19 +412,19 @@ void test()
|
|||
|
||||
#define VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(U) \
|
||||
{ \
|
||||
bool is_U_signed = integer_traits<U>::is_signed; \
|
||||
bool is_U_signed = is_signed<U>::value; \
|
||||
VERIFY_IS_VALID(CheckedInt<T>(U(0))); \
|
||||
VERIFY_IS_VALID(CheckedInt<T>(U(1))); \
|
||||
VERIFY_IS_VALID(CheckedInt<T>(U(100))); \
|
||||
if (is_U_signed) \
|
||||
VERIFY_IS_VALID_IF(CheckedInt<T>(U(-1)), is_signed); \
|
||||
VERIFY_IS_VALID_IF(CheckedInt<T>(U(-1)), is_T_signed); \
|
||||
if (sizeof(U) > sizeof(T)) \
|
||||
VERIFY_IS_INVALID(CheckedInt<T>(U(integer_traits<T>::max_value())+1)); \
|
||||
VERIFY_IS_VALID_IF(CheckedInt<T>(integer_traits<U>::max_value()), \
|
||||
(sizeof(T) > sizeof(U) || ((sizeof(T) == sizeof(U)) && (is_U_signed || !is_signed)))); \
|
||||
VERIFY_IS_VALID_IF(CheckedInt<T>(integer_traits<U>::min_value()), \
|
||||
VERIFY_IS_INVALID(CheckedInt<T>(U(max_value<T>::value())+1)); \
|
||||
VERIFY_IS_VALID_IF(CheckedInt<T>(max_value<U>::value()), \
|
||||
(sizeof(T) > sizeof(U) || ((sizeof(T) == sizeof(U)) && (is_U_signed || !is_T_signed)))); \
|
||||
VERIFY_IS_VALID_IF(CheckedInt<T>(min_value<U>::value()), \
|
||||
is_U_signed == false ? 1 : \
|
||||
bool(is_signed) == false ? 0 : \
|
||||
bool(is_T_signed) == false ? 0 : \
|
||||
sizeof(T) >= sizeof(U)); \
|
||||
}
|
||||
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int8_t)
|
||||
|
@ -437,6 +436,33 @@ void test()
|
|||
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int64_t)
|
||||
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint64_t)
|
||||
|
||||
typedef unsigned char unsigned_char;
|
||||
typedef unsigned short unsigned_short;
|
||||
typedef unsigned int unsigned_int;
|
||||
typedef unsigned long unsigned_long;
|
||||
typedef long long long_long;
|
||||
typedef unsigned long long unsigned_long_long;
|
||||
|
||||
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(char)
|
||||
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsigned_char)
|
||||
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(short)
|
||||
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsigned_short)
|
||||
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int)
|
||||
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsigned_int)
|
||||
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(long)
|
||||
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsigned_long)
|
||||
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(long_long)
|
||||
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsigned_long_long)
|
||||
|
||||
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRInt8)
|
||||
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRUint8)
|
||||
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRInt16)
|
||||
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRUint16)
|
||||
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRInt32)
|
||||
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRUint32)
|
||||
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRInt64)
|
||||
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRUint64)
|
||||
|
||||
/* Test increment/decrement operators */
|
||||
|
||||
CheckedInt<T> x, y;
|
||||
|
@ -456,13 +482,13 @@ void test()
|
|||
y = --x;
|
||||
VERIFY(x == zero);
|
||||
VERIFY(y == zero);
|
||||
x = max_value;
|
||||
x = max;
|
||||
VERIFY_IS_VALID(x++);
|
||||
x = max_value;
|
||||
x = max;
|
||||
VERIFY_IS_INVALID(++x);
|
||||
x = min_value;
|
||||
x = min;
|
||||
VERIFY_IS_VALID(x--);
|
||||
x = min_value;
|
||||
x = min;
|
||||
VERIFY_IS_INVALID(--x);
|
||||
}
|
||||
|
||||
|
@ -479,10 +505,31 @@ int main()
|
|||
CheckedInt_test::test<int64_t>();
|
||||
CheckedInt_test::test<uint64_t>();
|
||||
|
||||
CheckedInt_test::test<char>();
|
||||
CheckedInt_test::test<unsigned char>();
|
||||
CheckedInt_test::test<short>();
|
||||
CheckedInt_test::test<unsigned short>();
|
||||
CheckedInt_test::test<int>();
|
||||
CheckedInt_test::test<unsigned int>();
|
||||
CheckedInt_test::test<long>();
|
||||
CheckedInt_test::test<unsigned long>();
|
||||
CheckedInt_test::test<long long>();
|
||||
CheckedInt_test::test<unsigned long long>();
|
||||
|
||||
CheckedInt_test::test<PRInt8>();
|
||||
CheckedInt_test::test<PRUint8>();
|
||||
CheckedInt_test::test<PRInt16>();
|
||||
CheckedInt_test::test<PRUint16>();
|
||||
CheckedInt_test::test<PRInt32>();
|
||||
CheckedInt_test::test<PRUint32>();
|
||||
CheckedInt_test::test<PRInt64>();
|
||||
|
||||
std::cerr << CheckedInt_test::g_tests_failed << " tests failed, "
|
||||
<< CheckedInt_test::g_tests_passed << " tests passed out of "
|
||||
<< CheckedInt_test::g_tests_failed + CheckedInt_test::g_tests_passed
|
||||
<< " tests." << std::endl;
|
||||
<< " tests, covering " << CheckedInt_test::g_integer_types_tested
|
||||
<< " distinct integer types." << std::endl;
|
||||
|
||||
return CheckedInt_test::g_tests_failed > 0;
|
||||
return CheckedInt_test::g_tests_failed > 0
|
||||
|| CheckedInt_test::g_integer_types_tested < 8;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче