mirror of
https://github.com/biojppm/c4core.git
synced 2026-01-18 21:41:18 +01:00
charconv: add noexcept to overflows()
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
- [PR#148](https://github.com/biojppm/c4core/pull/148): Improvements in dump.hpp:
|
||||
- add traits class `c4::dump_directly<T>` to enable selection of faster path where the intermediate dump buffer is not used for strings which can be directly dumped to the sink
|
||||
- improve `c4::format_dump_resume()` to ensure the needed buffer size is still computed after buffer exhaustion
|
||||
- [PR#148](https://github.com/biojppm/c4core/pull/148): add `noexcept` to `c4::overflows`
|
||||
- [PR#148](https://github.com/biojppm/c4core/pull/148): Add support for mips, mipsel, mips64, mips64el CPU architectures
|
||||
- [PR#148](https://github.com/biojppm/c4core/pull/148): Add support for sparc, sparc64 CPU architectures
|
||||
- [PR#148](https://github.com/biojppm/c4core/pull/148) and [PR#12 cmake](https://github.com/biojppm/cmake/pull/12): Add support for loongarch, loongarch64 architectures
|
||||
|
||||
@@ -377,7 +377,7 @@ template<> struct charconv_digits_<4u, false> // uint32_t
|
||||
static constexpr csubstr max_value_dec() noexcept { return csubstr("4294967295"); }
|
||||
static constexpr bool is_oct_overflow(csubstr str) noexcept { return !((str.len < 11) || (str.len == 11 && str[0] <= '3')); }
|
||||
};
|
||||
template<> struct charconv_digits_<8u, true> // int32_t
|
||||
template<> struct charconv_digits_<8u, true> // int64_t
|
||||
{
|
||||
enum : size_t {
|
||||
maxdigits_bin = 1 + 2 + 64, // len=67: -9223372036854775808 -0b1000000000000000000000000000000000000000000000000000000000000000
|
||||
@@ -396,7 +396,7 @@ template<> struct charconv_digits_<8u, true> // int32_t
|
||||
static constexpr csubstr max_value_dec() noexcept { return csubstr("9223372036854775807"); }
|
||||
static constexpr bool is_oct_overflow(csubstr str) noexcept { return !((str.len < 22)); }
|
||||
};
|
||||
template<> struct charconv_digits_<8u, false>
|
||||
template<> struct charconv_digits_<8u, false> // uint64_t
|
||||
{
|
||||
enum : size_t {
|
||||
maxdigits_bin = 2 + 64, // len=66: 18446744073709551615 0b1111111111111111111111111111111111111111111111111111111111111111
|
||||
@@ -783,15 +783,18 @@ template<class T, NumberWriter<T> writer>
|
||||
size_t write_num_digits(substr buf, T v, size_t num_digits) noexcept
|
||||
{
|
||||
C4_STATIC_ASSERT(std::is_integral<T>::value);
|
||||
size_t ret = writer(buf, v);
|
||||
const size_t ret = writer(buf, v);
|
||||
if(ret >= num_digits)
|
||||
return ret;
|
||||
else if(ret >= buf.len || num_digits > buf.len)
|
||||
return num_digits;
|
||||
C4_ASSERT(num_digits >= ret);
|
||||
size_t delta = static_cast<size_t>(num_digits - ret); // NOLINT
|
||||
memmove(buf.str + delta, buf.str, ret);
|
||||
memset(buf.str, '0', delta);
|
||||
const size_t delta = static_cast<size_t>(num_digits - ret); // NOLINT
|
||||
C4_ASSERT(ret + delta <= buf.len);
|
||||
if(ret)
|
||||
memmove(buf.str + delta, buf.str, ret);
|
||||
if(delta)
|
||||
memset(buf.str, '0', delta);
|
||||
return num_digits;
|
||||
}
|
||||
} // namespace detail
|
||||
@@ -986,7 +989,9 @@ C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wswitch-default")
|
||||
namespace detail {
|
||||
inline size_t _itoa2buf(substr buf, size_t pos, csubstr val) noexcept
|
||||
{
|
||||
C4_ASSERT(pos < buf.len);
|
||||
C4_ASSERT(pos + val.len <= buf.len);
|
||||
C4_ASSERT(val.len > 0);
|
||||
memcpy(buf.str + pos, val.str, val.len);
|
||||
return pos + val.len;
|
||||
}
|
||||
@@ -1118,7 +1123,7 @@ C4_ALWAYS_INLINE size_t itoa(substr buf, T v) noexcept
|
||||
}
|
||||
// when T is the min value (eg i8: -128), negating it
|
||||
// will overflow, so treat the min as a special case
|
||||
else if(C4_LIKELY(v != std::numeric_limits<T>::min()))
|
||||
if(C4_LIKELY(v != std::numeric_limits<T>::min()))
|
||||
{
|
||||
v = -v;
|
||||
unsigned digits = digits_dec(v);
|
||||
@@ -1619,19 +1624,16 @@ C4_ALWAYS_INLINE size_t atou_first(csubstr str, T *v)
|
||||
namespace detail {
|
||||
inline bool check_overflow(csubstr str, csubstr limit) noexcept
|
||||
{
|
||||
if(str.len == limit.len)
|
||||
{
|
||||
for(size_t i = 0; i < limit.len; ++i)
|
||||
{
|
||||
if(str[i] < limit[i])
|
||||
return false;
|
||||
else if(str[i] > limit[i])
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
if(str.len != limit.len)
|
||||
return str.len > limit.len;
|
||||
for(size_t i = 0; i < limit.len; ++i)
|
||||
{
|
||||
if(str[i] < limit[i])
|
||||
return false;
|
||||
else if(str[i] > limit[i])
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // namespace detail
|
||||
/** @endcond */
|
||||
@@ -1715,7 +1717,7 @@ auto overflows(csubstr str) noexcept
|
||||
* @see doc_overflow_checked for format specifiers to enforce no-overflow reads
|
||||
*/
|
||||
template<class T>
|
||||
auto overflows(csubstr str)
|
||||
auto overflows(csubstr str) noexcept
|
||||
-> typename std::enable_if<std::is_signed<T>::value, bool>::type
|
||||
{
|
||||
C4_STATIC_ASSERT(std::is_integral<T>::value);
|
||||
@@ -1763,7 +1765,9 @@ auto overflows(csubstr str)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return detail::check_overflow(str.sub(1), detail::charconv_digits<T>::min_value_dec());
|
||||
}
|
||||
}
|
||||
else if(str.str[0] == '0')
|
||||
{
|
||||
@@ -1806,7 +1810,9 @@ auto overflows(csubstr str)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return detail::check_overflow(str, detail::charconv_digits<T>::max_value_dec());
|
||||
}
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
@@ -723,6 +723,107 @@ TEST_CASE_TEMPLATE("write_bin_digits", T, int8_t, uint8_t, int16_t, uint16_t, in
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// functions to suppress ubsan's warnings of signed integer overflow
|
||||
template<class T> C4_NO_UBSAN_IOVRFLW T add1(number_case<T> const& n)
|
||||
{
|
||||
T result = n.val + T(1);
|
||||
if(n.val == std::numeric_limits<T>::max())
|
||||
{
|
||||
CHECK_EQ(result, std::numeric_limits<T>::min());
|
||||
}
|
||||
if(n.has_valp1)
|
||||
{
|
||||
CHECK_EQ(result, n.valp1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
template<class T> C4_NO_UBSAN_IOVRFLW T add1(overflow64case<T> const& n)
|
||||
{
|
||||
return n.wrapped + T(1);
|
||||
}
|
||||
template<class T> C4_NO_UBSAN_IOVRFLW T add1(T val)
|
||||
{
|
||||
T result = val + T(1);
|
||||
if(val == std::numeric_limits<T>::max())
|
||||
{
|
||||
CHECK_EQ(result, std::numeric_limits<T>::min());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
template<class T> C4_NO_UBSAN_IOVRFLW T rem1(T val)
|
||||
{
|
||||
T result = val - T(1);
|
||||
if(val == std::numeric_limits<T>::min())
|
||||
{
|
||||
CHECK_EQ(result, std::numeric_limits<T>::max());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T> C4_NO_UBSAN_IOVRFLW constexpr T add1_(T val)
|
||||
{
|
||||
return val + T(1);
|
||||
}
|
||||
template<class T> C4_NO_UBSAN_IOVRFLW constexpr T rem1_(T val)
|
||||
{
|
||||
return val - T(1);
|
||||
}
|
||||
|
||||
template<class T> C4_NO_UBSAN_IOVRFLW constexpr T add_(T val, int n)
|
||||
{
|
||||
return val + (T)n;
|
||||
}
|
||||
template<class T> C4_NO_UBSAN_IOVRFLW constexpr T rem_(T val, int n)
|
||||
{
|
||||
return val - (T)n;
|
||||
}
|
||||
|
||||
// testing that signed overflow behaviors as expected (despite it
|
||||
// being undefined behavior)
|
||||
TEST_CASE("overflow.assumptions")
|
||||
{
|
||||
CHECK_EQ(rem1_(std::numeric_limits<int8_t>::min()), std::numeric_limits<int8_t>::max());
|
||||
CHECK_EQ(add1_(std::numeric_limits<int8_t>::max()), std::numeric_limits<int8_t>::min());
|
||||
CHECK_EQ(rem1_(std::numeric_limits<int16_t>::min()), std::numeric_limits<int16_t>::max());
|
||||
CHECK_EQ(add1_(std::numeric_limits<int16_t>::max()), std::numeric_limits<int16_t>::min());
|
||||
CHECK_EQ(rem1_(std::numeric_limits<int32_t>::min()), std::numeric_limits<int32_t>::max());
|
||||
CHECK_EQ(add1_(std::numeric_limits<int32_t>::max()), std::numeric_limits<int32_t>::min());
|
||||
CHECK_EQ(rem1_(std::numeric_limits<int64_t>::min()), std::numeric_limits<int64_t>::max());
|
||||
CHECK_EQ(add1_(std::numeric_limits<int64_t>::max()), std::numeric_limits<int64_t>::min());
|
||||
CHECK_EQ(rem1_(std::numeric_limits<uint8_t>::min()), std::numeric_limits<uint8_t>::max());
|
||||
CHECK_EQ(add1_(std::numeric_limits<uint8_t>::max()), std::numeric_limits<uint8_t>::min());
|
||||
CHECK_EQ(rem1_(std::numeric_limits<uint16_t>::min()), std::numeric_limits<uint16_t>::max());
|
||||
CHECK_EQ(add1_(std::numeric_limits<uint16_t>::max()), std::numeric_limits<uint16_t>::min());
|
||||
CHECK_EQ(rem1_(std::numeric_limits<uint32_t>::min()), std::numeric_limits<uint32_t>::max());
|
||||
CHECK_EQ(add1_(std::numeric_limits<uint32_t>::max()), std::numeric_limits<uint32_t>::min());
|
||||
CHECK_EQ(rem1_(std::numeric_limits<uint64_t>::min()), std::numeric_limits<uint64_t>::max());
|
||||
CHECK_EQ(add1_(std::numeric_limits<uint64_t>::max()), std::numeric_limits<uint64_t>::min());
|
||||
|
||||
for(int i : {1, 2, 3, 4, 5, 10})
|
||||
{
|
||||
INFO("i=" << i);
|
||||
CHECK_EQ(rem_(std::numeric_limits<int8_t>::min(), i), rem_(std::numeric_limits<int8_t>::max(), i-1));
|
||||
CHECK_EQ(add_(std::numeric_limits<int8_t>::max(), i), add_(std::numeric_limits<int8_t>::min(), i-1));
|
||||
CHECK_EQ(rem_(std::numeric_limits<int16_t>::min(), i), rem_(std::numeric_limits<int16_t>::max(), i-1));
|
||||
CHECK_EQ(add_(std::numeric_limits<int16_t>::max(), i), add_(std::numeric_limits<int16_t>::min(), i-1));
|
||||
CHECK_EQ(rem_(std::numeric_limits<int32_t>::min(), i), rem_(std::numeric_limits<int32_t>::max(), i-1));
|
||||
CHECK_EQ(add_(std::numeric_limits<int32_t>::max(), i), add_(std::numeric_limits<int32_t>::min(), i-1));
|
||||
CHECK_EQ(rem_(std::numeric_limits<int64_t>::min(), i), rem_(std::numeric_limits<int64_t>::max(), i-1));
|
||||
CHECK_EQ(add_(std::numeric_limits<int64_t>::max(), i), add_(std::numeric_limits<int64_t>::min(), i-1));
|
||||
CHECK_EQ(rem_(std::numeric_limits<uint8_t>::min(), i), rem_(std::numeric_limits<uint8_t>::max(), i-1));
|
||||
CHECK_EQ(add_(std::numeric_limits<uint8_t>::max(), i), add_(std::numeric_limits<uint8_t>::min(), i-1));
|
||||
CHECK_EQ(rem_(std::numeric_limits<uint16_t>::min(), i), rem_(std::numeric_limits<uint16_t>::max(), i-1));
|
||||
CHECK_EQ(add_(std::numeric_limits<uint16_t>::max(), i), add_(std::numeric_limits<uint16_t>::min(), i-1));
|
||||
CHECK_EQ(rem_(std::numeric_limits<uint32_t>::min(), i), rem_(std::numeric_limits<uint32_t>::max(), i-1));
|
||||
CHECK_EQ(add_(std::numeric_limits<uint32_t>::max(), i), add_(std::numeric_limits<uint32_t>::min(), i-1));
|
||||
CHECK_EQ(rem_(std::numeric_limits<uint64_t>::min(), i), rem_(std::numeric_limits<uint64_t>::max(), i-1));
|
||||
CHECK_EQ(add_(std::numeric_limits<uint64_t>::max(), i), add_(std::numeric_limits<uint64_t>::min(), i-1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
TEST_CASE_TEMPLATE("xtoa", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t)
|
||||
@@ -741,11 +842,9 @@ TEST_CASE_TEMPLATE("xtoa", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint3
|
||||
CHECK_EQ(retn, retb);
|
||||
REQUIRE_LE(retb, buf.len);
|
||||
CHECK_EQ(buf.first(retb), number.dec);
|
||||
#ifndef C4_UBSAN // the tests succeed, so UBSAN can take a hike.
|
||||
T after_roundtrip = number.val + T(1);
|
||||
T after_roundtrip = add1(number);
|
||||
CHECK(atox(buf.first(retb), &after_roundtrip));
|
||||
CHECK_EQ(after_roundtrip, number.val);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -769,11 +868,9 @@ TEST_CASE_TEMPLATE("xtoa_radix.dec", T, int8_t, uint8_t, int16_t, uint16_t, int3
|
||||
CHECK_EQ(retn, retb);
|
||||
REQUIRE_LE(retb, buf.len);
|
||||
CHECK_EQ(buf.first(retb), number.dec);
|
||||
#ifndef C4_UBSAN // the tests succeed, so UBSAN can take a hike.
|
||||
T after_roundtrip = number.val + T(1);
|
||||
T after_roundtrip = add1(number);
|
||||
CHECK(atox(buf.first(retb), &after_roundtrip));
|
||||
CHECK_EQ(after_roundtrip, number.val);
|
||||
#endif
|
||||
}
|
||||
const size_t adj = size_t(number.val < 0);
|
||||
REQUIRE_LT(adj, number.dec.len);
|
||||
@@ -790,11 +887,9 @@ TEST_CASE_TEMPLATE("xtoa_radix.dec", T, int8_t, uint8_t, int16_t, uint16_t, int3
|
||||
CHECK_EQ(retn, retb);
|
||||
REQUIRE_LE(retb, buf.len);
|
||||
CHECK(buf.first(retb).ends_with(number.dec.sub(number.val < 0)));
|
||||
#ifndef C4_UBSAN // the tests succeed, so UBSAN can take a hike.
|
||||
T after_roundtrip = number.val + T(1);
|
||||
T after_roundtrip = add1(number);
|
||||
CHECK(atox(buf.first(retb), &after_roundtrip));
|
||||
CHECK_EQ(after_roundtrip, number.val);
|
||||
#endif
|
||||
}
|
||||
for(size_t less_digits = 0; less_digits < dec_digits; ++less_digits)
|
||||
{
|
||||
@@ -808,11 +903,9 @@ TEST_CASE_TEMPLATE("xtoa_radix.dec", T, int8_t, uint8_t, int16_t, uint16_t, int3
|
||||
CHECK_EQ(retn, retb);
|
||||
REQUIRE_LE(retb, buf.len);
|
||||
CHECK(buf.first(retb).ends_with(number.dec.sub(number.val < 0)));
|
||||
#ifndef C4_UBSAN // the tests succeed, so UBSAN can take a hike.
|
||||
T after_roundtrip = number.val + T(1);
|
||||
T after_roundtrip = add1(number);
|
||||
CHECK(atox(buf.first(retb), &after_roundtrip));
|
||||
CHECK_EQ(after_roundtrip, number.val);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -833,11 +926,9 @@ TEST_CASE_TEMPLATE("xtoa_radix.hex", T, int8_t, uint8_t, int16_t, uint16_t, int3
|
||||
CHECK_EQ(retn, retb);
|
||||
REQUIRE_LE(retb, buf.len);
|
||||
CHECK_EQ(buf.first(retb), number.hex);
|
||||
#ifndef C4_UBSAN // the tests succeed, so UBSAN can take a hike.
|
||||
T after_roundtrip = number.val + T(1);
|
||||
T after_roundtrip = add1(number);
|
||||
CHECK(atox(buf.first(retb), &after_roundtrip));
|
||||
CHECK_EQ(after_roundtrip, number.val);
|
||||
#endif
|
||||
}
|
||||
const size_t adj = size_t(number.val < 0) + size_t(2); // 2 for 0x
|
||||
REQUIRE_LT(adj, number.hex.len);
|
||||
@@ -859,11 +950,9 @@ TEST_CASE_TEMPLATE("xtoa_radix.hex", T, int8_t, uint8_t, int16_t, uint16_t, int3
|
||||
if(number.val < 0)
|
||||
CHECK(buf.first(retb).begins_with('-'));
|
||||
CHECK(result.ends_with(ref));
|
||||
#ifndef C4_UBSAN // the tests succeed, so UBSAN can take a hike.
|
||||
T after_roundtrip = number.val + T(1);
|
||||
T after_roundtrip = add1(number);
|
||||
CHECK(atox(buf.first(retb), &after_roundtrip));
|
||||
CHECK_EQ(after_roundtrip, number.val);
|
||||
#endif
|
||||
}
|
||||
for(size_t less_digits = 0; less_digits < hex_digits; ++less_digits)
|
||||
{
|
||||
@@ -877,11 +966,9 @@ TEST_CASE_TEMPLATE("xtoa_radix.hex", T, int8_t, uint8_t, int16_t, uint16_t, int3
|
||||
CHECK_EQ(retn, retb);
|
||||
REQUIRE_LE(retb, buf.len);
|
||||
CHECK(buf.first(retb).ends_with(number.hex.sub(number.val < 0)));
|
||||
#ifndef C4_UBSAN // the tests succeed, so UBSAN can take a hike.
|
||||
T after_roundtrip = number.val + T(1);
|
||||
T after_roundtrip = add1(number);
|
||||
CHECK(atox(buf.first(retb), &after_roundtrip));
|
||||
CHECK_EQ(after_roundtrip, number.val);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -902,11 +989,9 @@ TEST_CASE_TEMPLATE("xtoa_radix.oct", T, int8_t, uint8_t, int16_t, uint16_t, int3
|
||||
CHECK_EQ(retn, retb);
|
||||
REQUIRE_LE(retb, buf.len);
|
||||
CHECK_EQ(buf.first(retb), number.oct);
|
||||
#ifndef C4_UBSAN // the tests succeed, so UBSAN can take a hike.
|
||||
T after_roundtrip = number.val + T(1);
|
||||
T after_roundtrip = add1(number);
|
||||
CHECK(atox(buf.first(retb), &after_roundtrip));
|
||||
CHECK_EQ(after_roundtrip, number.val);
|
||||
#endif
|
||||
}
|
||||
const size_t adj = size_t(number.val < 0) + size_t(2); // 2 for 0o
|
||||
REQUIRE_LT(adj, number.oct.len);
|
||||
@@ -928,11 +1013,9 @@ TEST_CASE_TEMPLATE("xtoa_radix.oct", T, int8_t, uint8_t, int16_t, uint16_t, int3
|
||||
if(number.val < 0)
|
||||
CHECK(buf.first(retb).begins_with('-'));
|
||||
CHECK(result.ends_with(ref));
|
||||
#ifndef C4_UBSAN // the tests succeed, so UBSAN can take a hike.
|
||||
T after_roundtrip = number.val + T(1);
|
||||
T after_roundtrip = add1(number);
|
||||
CHECK(atox(buf.first(retb), &after_roundtrip));
|
||||
CHECK_EQ(after_roundtrip, number.val);
|
||||
#endif
|
||||
}
|
||||
for(size_t less_digits = 0; less_digits < oct_digits; ++less_digits)
|
||||
{
|
||||
@@ -946,11 +1029,9 @@ TEST_CASE_TEMPLATE("xtoa_radix.oct", T, int8_t, uint8_t, int16_t, uint16_t, int3
|
||||
CHECK_EQ(retn, retb);
|
||||
REQUIRE_LE(retb, buf.len);
|
||||
CHECK(buf.first(retb).ends_with(number.oct.sub(number.val < 0)));
|
||||
#ifndef C4_UBSAN // the tests succeed, so UBSAN can take a hike.
|
||||
T after_roundtrip = number.val + T(1);
|
||||
T after_roundtrip = add1(number);
|
||||
CHECK(atox(buf.first(retb), &after_roundtrip));
|
||||
CHECK_EQ(after_roundtrip, number.val);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -971,11 +1052,9 @@ TEST_CASE_TEMPLATE("xtoa_radix.bin", T, int8_t, uint8_t, int16_t, uint16_t, int3
|
||||
CHECK_EQ(retn, retb);
|
||||
REQUIRE_LE(retb, buf.len);
|
||||
CHECK_EQ(buf.first(retb), number.bin);
|
||||
#ifndef C4_UBSAN // the tests succeed, so UBSAN can take a hike.
|
||||
T after_roundtrip = number.val + T(1);
|
||||
T after_roundtrip = add1(number);
|
||||
CHECK(atox(buf.first(retb), &after_roundtrip));
|
||||
CHECK_EQ(after_roundtrip, number.val);
|
||||
#endif
|
||||
}
|
||||
const size_t adj = size_t(number.val < 0) + size_t(2); // 2 for 0b
|
||||
REQUIRE_LT(adj, number.bin.len);
|
||||
@@ -996,11 +1075,9 @@ TEST_CASE_TEMPLATE("xtoa_radix.bin", T, int8_t, uint8_t, int16_t, uint16_t, int3
|
||||
INFO("result=" << result << " ref=" << ref);
|
||||
if(number.val < 0)
|
||||
CHECK(buf.first(retb).begins_with('-'));
|
||||
#ifndef C4_UBSAN // the tests succeed, so UBSAN can take a hike.
|
||||
T after_roundtrip = number.val + T(1);
|
||||
T after_roundtrip = add1(number);
|
||||
CHECK(atox(buf.first(retb), &after_roundtrip));
|
||||
CHECK_EQ(after_roundtrip, number.val);
|
||||
#endif
|
||||
}
|
||||
for(size_t less_digits = 0; less_digits < bin_digits; ++less_digits)
|
||||
{
|
||||
@@ -1014,11 +1091,9 @@ TEST_CASE_TEMPLATE("xtoa_radix.bin", T, int8_t, uint8_t, int16_t, uint16_t, int3
|
||||
CHECK_EQ(retn, retb);
|
||||
REQUIRE_LE(retb, buf.len);
|
||||
CHECK(buf.first(retb).ends_with(number.bin.sub(number.val < 0)));
|
||||
#ifndef C4_UBSAN // the tests succeed, so UBSAN can take a hike.
|
||||
T after_roundtrip = number.val + T(1);
|
||||
T after_roundtrip = add1(number);
|
||||
CHECK(atox(buf.first(retb), &after_roundtrip));
|
||||
CHECK_EQ(after_roundtrip, number.val);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1103,7 +1178,6 @@ TEST_CASE_TEMPLATE("overflows.in_range_does_not_overflow", T, int8_t, uint8_t, i
|
||||
TEST_CASE_TEMPLATE("read_dec", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t)
|
||||
{
|
||||
(void)invalid_cases;
|
||||
#ifndef C4_UBSAN // the tests succeed, so UBSAN can take a hike.
|
||||
char buf_[128] = {};
|
||||
substr buf = buf_;
|
||||
SUBCASE("numbers")
|
||||
@@ -1114,13 +1188,13 @@ TEST_CASE_TEMPLATE("read_dec", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, u
|
||||
continue;
|
||||
INFO(number);
|
||||
{
|
||||
T val = number.val + T(1);
|
||||
T val = add1(number);
|
||||
CHECK(read_dec(number.dec, &val));
|
||||
CHECK_EQ(val, number.val);
|
||||
}
|
||||
// capitalize
|
||||
{
|
||||
T val = number.val + T(1);
|
||||
T val = add1(number);
|
||||
csubstr cbuf = capitalize(buf, number.dec);
|
||||
CHECK(read_dec(cbuf, &val));
|
||||
CHECK_EQ(val, number.val);
|
||||
@@ -1128,7 +1202,7 @@ TEST_CASE_TEMPLATE("read_dec", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, u
|
||||
// zero-prefix
|
||||
for(size_t numz : {1u, 4u, 6u})
|
||||
{
|
||||
T val = number.val + T(1);
|
||||
T val = add1(number);
|
||||
substr buf2 = zpad(buf, number.dec, numz);
|
||||
INFO("zprefix=" << buf2);
|
||||
CHECK(read_dec(buf2, &val));
|
||||
@@ -1150,12 +1224,10 @@ TEST_CASE_TEMPLATE("read_dec", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, u
|
||||
CHECK(!read_dec(ic.dec, &val));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE_TEMPLATE("read_hex", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t)
|
||||
{
|
||||
#ifndef C4_UBSAN // the tests succeed, so UBSAN can take a hike.
|
||||
char buf_[128] = {};
|
||||
substr buf = buf_;
|
||||
SUBCASE("numbers")
|
||||
@@ -1167,14 +1239,14 @@ TEST_CASE_TEMPLATE("read_hex", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, u
|
||||
INFO(number);
|
||||
// must not accept 0x prefix
|
||||
{
|
||||
T val = number.val + T(1);
|
||||
T val = add1(number);
|
||||
CHECK(!read_hex(number.hex, &val));
|
||||
}
|
||||
// must accept without prefix
|
||||
csubstr hex = nopfx(number.hex);
|
||||
INFO("nopfx(hex)=" << hex);
|
||||
{
|
||||
T val = number.val + T(1);
|
||||
T val = add1(number);
|
||||
CHECK(read_hex(hex, &val));
|
||||
CHECK_EQ(val, number.val);
|
||||
}
|
||||
@@ -1183,14 +1255,14 @@ TEST_CASE_TEMPLATE("read_hex", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, u
|
||||
csubstr cbuf = capitalize(buf, hex);
|
||||
INFO("capitalized=" << buf);
|
||||
REQUIRE_EQ(cbuf.len, hex.len);
|
||||
T val = number.val + T(1);
|
||||
T val = add1(number);
|
||||
CHECK(read_hex(cbuf, &val));
|
||||
CHECK_EQ(val, number.val);
|
||||
}
|
||||
// zero-prefix
|
||||
for(size_t numz : {1u, 4u, 6u})
|
||||
{
|
||||
T val = number.val + T(1);
|
||||
T val = add1(number);
|
||||
substr zprefix = zpad(buf, hex, numz);
|
||||
INFO("zprefix='" << zprefix << "'");
|
||||
CHECK(read_hex(zprefix, &val));
|
||||
@@ -1233,12 +1305,10 @@ TEST_CASE_TEMPLATE("read_hex", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, u
|
||||
++icase;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE_TEMPLATE("read_oct", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t)
|
||||
{
|
||||
#ifndef C4_UBSAN // the tests succeed, so UBSAN can take a hike.
|
||||
char buf_[128] = {};
|
||||
substr buf = buf_;
|
||||
SUBCASE("numbers")
|
||||
@@ -1250,14 +1320,14 @@ TEST_CASE_TEMPLATE("read_oct", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, u
|
||||
INFO(number);
|
||||
// must not accept 0x prefix
|
||||
{
|
||||
T val = number.val + T(1);
|
||||
T val = add1(number);
|
||||
CHECK(!read_oct(number.oct, &val));
|
||||
}
|
||||
// must accept without prefix
|
||||
csubstr oct = nopfx(number.oct);
|
||||
INFO("nopfx(oct)=" << oct);
|
||||
{
|
||||
T val = number.val + T(1);
|
||||
T val = add1(number);
|
||||
CHECK(read_oct(oct, &val));
|
||||
CHECK_EQ(val, number.val);
|
||||
}
|
||||
@@ -1266,14 +1336,14 @@ TEST_CASE_TEMPLATE("read_oct", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, u
|
||||
csubstr cbuf = capitalize(buf, oct);
|
||||
INFO("capitalized=" << buf);
|
||||
REQUIRE_EQ(cbuf.len, oct.len);
|
||||
T val = number.val + T(1);
|
||||
T val = add1(number);
|
||||
CHECK(read_oct(cbuf, &val));
|
||||
CHECK_EQ(val, number.val);
|
||||
}
|
||||
// zero-prefix
|
||||
for(size_t numz : {1u, 4u, 6u})
|
||||
{
|
||||
T val = number.val + T(1);
|
||||
T val = add1(number);
|
||||
substr zprefix = zpad(buf, oct, numz);
|
||||
INFO("zprefix=" << zprefix);
|
||||
CHECK(read_oct(zprefix, &val));
|
||||
@@ -1316,12 +1386,10 @@ TEST_CASE_TEMPLATE("read_oct", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, u
|
||||
++icase;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE_TEMPLATE("read_bin", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t)
|
||||
{
|
||||
#ifndef C4_UBSAN // the tests succeed, so UBSAN can take a hike.
|
||||
char buf_[128] = {};
|
||||
substr buf = buf_;
|
||||
SUBCASE("numbers")
|
||||
@@ -1333,14 +1401,14 @@ TEST_CASE_TEMPLATE("read_bin", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, u
|
||||
INFO(number);
|
||||
// must not accept 0x prefix
|
||||
{
|
||||
T val = number.val + T(1);
|
||||
T val = add1(number);
|
||||
CHECK(!read_bin(number.bin, &val));
|
||||
}
|
||||
// must accept without prefix
|
||||
csubstr bin = nopfx(number.bin);
|
||||
INFO("nopfx(bin)=" << bin);
|
||||
{
|
||||
T val = number.val + T(1);
|
||||
T val = add1(number);
|
||||
CHECK(read_bin(bin, &val));
|
||||
CHECK_EQ(val, number.val);
|
||||
}
|
||||
@@ -1349,14 +1417,14 @@ TEST_CASE_TEMPLATE("read_bin", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, u
|
||||
csubstr cbuf = capitalize(buf, bin);
|
||||
INFO("capitalized=" << buf);
|
||||
REQUIRE_EQ(cbuf.len, bin.len);
|
||||
T val = number.val + T(1);
|
||||
T val = add1(number);
|
||||
CHECK(read_bin(cbuf, &val));
|
||||
CHECK_EQ(val, number.val);
|
||||
}
|
||||
// zero-prefix
|
||||
for(size_t numz : {1u, 4u, 6u})
|
||||
{
|
||||
T val = number.val + T(1);
|
||||
T val = add1(number);
|
||||
substr zprefix = zpad(buf, bin, numz);
|
||||
INFO("zprefix=" << zprefix);
|
||||
CHECK(read_bin(zprefix, &val));
|
||||
@@ -1399,7 +1467,6 @@ TEST_CASE_TEMPLATE("read_bin", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, u
|
||||
++icase;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1407,7 +1474,6 @@ TEST_CASE_TEMPLATE("read_bin", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, u
|
||||
|
||||
TEST_CASE_TEMPLATE("atox", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t)
|
||||
{
|
||||
#ifndef C4_UBSAN // the tests succeed, so UBSAN can take a hike.
|
||||
char buf_[128] = {};
|
||||
substr buf = buf_;
|
||||
SUBCASE("dec")
|
||||
@@ -1416,14 +1482,14 @@ TEST_CASE_TEMPLATE("atox", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint3
|
||||
{
|
||||
INFO(number);
|
||||
{
|
||||
T val = number.val + T(1);
|
||||
T val = add1(number);
|
||||
CHECK(atox(number.dec, &val));
|
||||
CHECK_EQ(val, number.val);
|
||||
}
|
||||
// zero-prefix
|
||||
for(size_t numz : {1u, 4u, 6u})
|
||||
{
|
||||
T val = number.val + T(1);
|
||||
T val = add1(number);
|
||||
substr zprefix = zpad(buf, number.dec, numz);
|
||||
INFO("zprefix=" << zprefix);
|
||||
CHECK(atox(zprefix, &val));
|
||||
@@ -1437,13 +1503,13 @@ TEST_CASE_TEMPLATE("atox", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint3
|
||||
{
|
||||
INFO(number);
|
||||
{
|
||||
T val = number.val + T(1);
|
||||
T val = add1(number);
|
||||
CHECK(atox(number.hex, &val));
|
||||
CHECK_EQ(val, number.val);
|
||||
}
|
||||
// capitalize
|
||||
{
|
||||
T val = number.val + T(1);
|
||||
T val = add1(number);
|
||||
csubstr cbuf = capitalize(buf, number.hex);
|
||||
CHECK(atox(cbuf, &val));
|
||||
CHECK_EQ(val, number.val);
|
||||
@@ -1451,7 +1517,7 @@ TEST_CASE_TEMPLATE("atox", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint3
|
||||
// zero-prefix
|
||||
for(size_t numz : {1u, 4u, 6u})
|
||||
{
|
||||
T val = number.val + T(1);
|
||||
T val = add1(number);
|
||||
substr zprefix = zpad(buf, number.hex, numz);
|
||||
INFO("zprefix=" << zprefix);
|
||||
CHECK(atox(zprefix, &val));
|
||||
@@ -1468,13 +1534,13 @@ TEST_CASE_TEMPLATE("atox", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint3
|
||||
{
|
||||
INFO(number);
|
||||
{
|
||||
T val = number.val + T(1);
|
||||
T val = add1(number);
|
||||
CHECK(atox(number.oct, &val));
|
||||
CHECK_EQ(val, number.val);
|
||||
}
|
||||
// capitalize
|
||||
{
|
||||
T val = number.val + T(1);
|
||||
T val = add1(number);
|
||||
csubstr cbuf = capitalize(buf, number.oct);
|
||||
CHECK(atox(cbuf, &val));
|
||||
CHECK_EQ(val, number.val);
|
||||
@@ -1482,7 +1548,7 @@ TEST_CASE_TEMPLATE("atox", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint3
|
||||
// zero-prefix
|
||||
for(size_t numz : {1u, 4u, 6u})
|
||||
{
|
||||
T val = number.val + T(1);
|
||||
T val = add1(number);
|
||||
substr zprefix = zpad(buf, number.oct, numz);
|
||||
INFO("zprefix=" << zprefix);
|
||||
CHECK(atox(zprefix, &val));
|
||||
@@ -1499,13 +1565,13 @@ TEST_CASE_TEMPLATE("atox", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint3
|
||||
{
|
||||
INFO(number);
|
||||
{
|
||||
T val = number.val + T(1);
|
||||
T val = add1(number);
|
||||
CHECK(atox(number.bin, &val));
|
||||
CHECK_EQ(val, number.val);
|
||||
}
|
||||
// capitalize
|
||||
{
|
||||
T val = number.val + T(1);
|
||||
T val = add1(number);
|
||||
csubstr cbuf = capitalize(buf, number.bin);
|
||||
CHECK(atox(cbuf, &val));
|
||||
CHECK_EQ(val, number.val);
|
||||
@@ -1513,7 +1579,7 @@ TEST_CASE_TEMPLATE("atox", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint3
|
||||
// zero-prefix
|
||||
for(size_t numz : {1u, 4u, 6u})
|
||||
{
|
||||
T val = number.val + T(1);
|
||||
T val = add1(number);
|
||||
substr zprefix = zpad(buf, number.oct, numz);
|
||||
INFO("zprefix=" << zprefix);
|
||||
CHECK(atox(zprefix, &val));
|
||||
@@ -1524,12 +1590,10 @@ TEST_CASE_TEMPLATE("atox", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint3
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE_TEMPLATE("atox.fail", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t)
|
||||
{
|
||||
#ifndef C4_UBSAN // the tests succeed, so UBSAN can take a hike.
|
||||
char buf_[128] = {};
|
||||
substr buf = buf_;
|
||||
SUBCASE("dec")
|
||||
@@ -1608,7 +1672,6 @@ TEST_CASE_TEMPLATE("atox.fail", T, int8_t, uint8_t, int16_t, uint16_t, int32_t,
|
||||
++icase;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1616,6 +1679,9 @@ TEST_CASE_TEMPLATE("atox.fail", T, int8_t, uint8_t, int16_t, uint16_t, int32_t,
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template<class T>
|
||||
void test_overflows(std::initializer_list<const char *> args)
|
||||
{
|
||||
@@ -1649,7 +1715,6 @@ auto test_no_overflow_zeroes()
|
||||
// test overflow in sizes smaller than 64 bit by upcasting
|
||||
TEST_CASE_TEMPLATE("atox.overflow", T, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t)
|
||||
{
|
||||
#ifndef C4_UBSAN // the tests succeed, so UBSAN can take a hike.
|
||||
char buf_[128];
|
||||
substr buf = buf_;
|
||||
auto do_test = [](bool is_overflow, number_case<T> const& num, csubstr exceeded, number_case<T> const& wrapped){
|
||||
@@ -1664,7 +1729,7 @@ TEST_CASE_TEMPLATE("atox.overflow", T, int8_t, uint8_t, int16_t, uint16_t, int32
|
||||
else
|
||||
CHECK_EQ(&num, &wrapped);
|
||||
{
|
||||
T val = num.val + T(1);
|
||||
T val = add1(num);
|
||||
CHECK(atox(exceeded, &val));
|
||||
CHECK_EQ(val, wrapped.val);
|
||||
}
|
||||
@@ -1673,7 +1738,7 @@ TEST_CASE_TEMPLATE("atox.overflow", T, int8_t, uint8_t, int16_t, uint16_t, int32
|
||||
INFO(buf2);
|
||||
CHECK_EQ(is_overflow, overflows<T>(buf2));
|
||||
{
|
||||
T val = num.val + T(1);
|
||||
T val = add1(num);
|
||||
CHECK(atox(buf2, &val));
|
||||
CHECK_EQ(val, wrapped.val);
|
||||
}
|
||||
@@ -1683,14 +1748,14 @@ TEST_CASE_TEMPLATE("atox.overflow", T, int8_t, uint8_t, int16_t, uint16_t, int32
|
||||
buf2 = zpad(buf2_, exceeded, numz);
|
||||
CHECK_EQ(is_overflow, overflows<T>(buf2));
|
||||
{
|
||||
T val = num.val + T(1);
|
||||
T val = add1(num);
|
||||
CHECK(atox(buf2, &val));
|
||||
CHECK_EQ(val, wrapped.val);
|
||||
}
|
||||
buf2.toupper();
|
||||
CHECK_EQ(is_overflow, overflows<T>(buf2));
|
||||
{
|
||||
T val = num.val + T(1);
|
||||
T val = add1(num);
|
||||
CHECK(atox(buf2, &val));
|
||||
CHECK_EQ(val, wrapped.val);
|
||||
}
|
||||
@@ -1776,17 +1841,15 @@ TEST_CASE_TEMPLATE("atox.overflow", T, int8_t, uint8_t, int16_t, uint16_t, int32
|
||||
do_test_overflow(T(4), T(2));
|
||||
do_test_overflow(T(5), T(2));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE_TEMPLATE("atox.overflow64", T, int64_t, uint64_t)
|
||||
{
|
||||
#ifndef C4_UBSAN // the tests succeed, so UBSAN can take a hike.
|
||||
char buf_[128] = {};
|
||||
substr buf = buf_;
|
||||
auto test_atox = [](csubstr s, overflow64case<T> const& c){
|
||||
INFO("s=" << s);
|
||||
T val = c.wrapped + T(1);
|
||||
T val = add1(c);
|
||||
if(std::is_signed<T>::value || !s.begins_with('-'))
|
||||
{
|
||||
CHECK(atox(s, &val));
|
||||
@@ -1885,7 +1948,6 @@ TEST_CASE_TEMPLATE("atox.overflow64", T, int64_t, uint64_t)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1983,26 +2045,43 @@ void test_overflows_bin()
|
||||
|
||||
// TODO: test_overflows_oct
|
||||
|
||||
template<class T>
|
||||
void expect_overflows_unsigned(int radix, uint64_t val, bool expected)
|
||||
{
|
||||
char bufc[100] = {0};
|
||||
substr s(bufc, sizeof(bufc));
|
||||
size_t sz = utoa<uint64_t>(s, val, (uint64_t)radix);
|
||||
INFO("radix=" << radix << " val=" << val);
|
||||
REQUIRE_LE(sz, s.size());
|
||||
s = s.first(sz);
|
||||
INFO("s=" << s);
|
||||
CHECK_EQ(overflows<T>(s), expected);
|
||||
};
|
||||
|
||||
template<class T>
|
||||
void expect_overflows_signed(int radix, int64_t val, bool expected)
|
||||
{
|
||||
char bufc[100] = {0};
|
||||
substr s(bufc, sizeof(bufc));
|
||||
size_t sz = itoa<int64_t>(s, val, (int64_t)radix);
|
||||
INFO("radix=" << radix << " val=" << val);
|
||||
REQUIRE_LE(sz, s.size());
|
||||
s = s.first(sz);
|
||||
INFO("s=" << s);
|
||||
CHECK_EQ(overflows<T>(s), expected);
|
||||
};
|
||||
|
||||
template<class T>
|
||||
typename std::enable_if<std::is_unsigned<T>::value, void>::type
|
||||
test_overflows()
|
||||
{
|
||||
const uint64_t max = (uint64_t) std::numeric_limits<T>::max();
|
||||
const uint64_t min = (uint64_t) std::numeric_limits<T>::min();
|
||||
for(int radix : { 2, 8, 10, 16 })
|
||||
{
|
||||
char bufc[100] = {0};
|
||||
substr s(bufc);
|
||||
INFO("radix=" << radix << " num=" << s);
|
||||
|
||||
uint64_t max = (uint64_t) std::numeric_limits<T>::max();
|
||||
size_t sz = utoa<uint64_t>(s, max, (uint64_t)radix);
|
||||
REQUIRE_LE(sz, s.size());
|
||||
CHECK(!overflows<T>(s.first(sz)));
|
||||
memset(s.str, 0, s.len);
|
||||
sz = utoa<uint64_t>(s, max + 1, (uint64_t)radix);
|
||||
REQUIRE_LE(sz, s.size());
|
||||
CHECK(overflows<T>(s.first(sz)));
|
||||
expect_overflows_unsigned<T>(radix, max, false);
|
||||
expect_overflows_unsigned<T>(radix, add1(max), true);
|
||||
}
|
||||
|
||||
test_overflows_hex<T>();
|
||||
test_overflows_bin<T>();
|
||||
// TODO: octal
|
||||
@@ -2012,31 +2091,15 @@ template<class T>
|
||||
typename std::enable_if<std::is_signed<T>::value, void>::type
|
||||
test_overflows()
|
||||
{
|
||||
const int64_t max = (int64_t) std::numeric_limits<T>::max();
|
||||
const int64_t min = (int64_t) std::numeric_limits<T>::min();
|
||||
for(int radix : { 2, 8, 10, 16 })
|
||||
{
|
||||
char bufc[100] = {0};
|
||||
substr s(bufc);
|
||||
INFO("radix=" << radix << " num=" << s);
|
||||
|
||||
int64_t max = (int64_t) std::numeric_limits<T>::max();
|
||||
size_t sz = itoa<int64_t>(s, max, (int64_t)radix);
|
||||
REQUIRE_LE(sz, s.size());
|
||||
CHECK(!overflows<T>(s.first(sz)));
|
||||
memset(s.str, 0, s.len);
|
||||
sz = itoa<int64_t>(s, max + 1, (int64_t)radix);
|
||||
REQUIRE_LE(sz, s.size());
|
||||
CHECK(overflows<T>(s.first(sz)));
|
||||
|
||||
int64_t min = (int64_t) std::numeric_limits<T>::min();
|
||||
sz = itoa<int64_t>(s, min, (int64_t)radix);
|
||||
REQUIRE_LE(sz, s.size());
|
||||
CHECK(!overflows<T>(s.first(sz)));
|
||||
memset(s.str, 0, s.len);
|
||||
sz = itoa<int64_t>(s, min - 1, (int64_t)radix);
|
||||
REQUIRE_LE(sz, s.size());
|
||||
CHECK(overflows<T>(s.first(sz)));
|
||||
expect_overflows_signed<T>(radix, max, false);
|
||||
expect_overflows_signed<T>(radix, add1(max), true);
|
||||
expect_overflows_signed<T>(radix, min, false);
|
||||
expect_overflows_signed<T>(radix, rem1(min), true);
|
||||
}
|
||||
|
||||
test_overflows_hex<T>();
|
||||
test_overflows_bin<T>();
|
||||
// TODO: octal
|
||||
@@ -2044,14 +2107,11 @@ test_overflows()
|
||||
|
||||
TEST_CASE_TEMPLATE("overflows.8bit_32bit", T, uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t)
|
||||
{
|
||||
#ifndef C4_UBSAN // the tests succeed, so UBSAN can take a hike.
|
||||
test_overflows<T>();
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("overflows.u64")
|
||||
{
|
||||
#ifndef C4_UBSAN // the tests succeed, so UBSAN can take a hike.
|
||||
CHECK(!overflows<uint64_t>("18446744073709551614"));
|
||||
CHECK(!overflows<uint64_t>("18446744073709551615"));
|
||||
CHECK(overflows<uint64_t>("18446744073709551616"));
|
||||
@@ -2073,12 +2133,10 @@ TEST_CASE("overflows.u64")
|
||||
test_overflows_hex<uint64_t>();
|
||||
test_overflows_bin<uint64_t>();
|
||||
// TODO: octal
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("overflows.i64")
|
||||
{
|
||||
#ifndef C4_UBSAN // the tests succeed, so UBSAN can take a hike.
|
||||
CHECK(!overflows<int64_t>("9223372036854775806"));
|
||||
CHECK(!overflows<int64_t>("9223372036854775807"));
|
||||
CHECK(overflows<int64_t>("9223372036854775808"));
|
||||
@@ -2102,7 +2160,6 @@ TEST_CASE("overflows.i64")
|
||||
|
||||
test_overflows_hex<int64_t>();
|
||||
test_overflows_bin<int64_t>();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user