mirror of
https://github.com/luxfi/intx.git
synced 2026-10-30 16:22:26 +00:00
377 lines
10 KiB
C++
377 lines
10 KiB
C++
// intx: extended precision integer library.
|
|
// Copyright 2019 Pawel Bylica.
|
|
// Licensed under the Apache License, Version 2.0.
|
|
|
|
#include "test_suite.hpp"
|
|
|
|
using namespace intx;
|
|
|
|
TYPED_TEST(uint_test, numeric_limits)
|
|
{
|
|
static_assert(std::numeric_limits<uint256>::digits10 == 77);
|
|
static_assert(std::numeric_limits<uint512>::digits10 == 154);
|
|
|
|
static_assert(!std::numeric_limits<TypeParam>::is_signed);
|
|
static_assert(std::numeric_limits<TypeParam>::is_integer);
|
|
static_assert(std::numeric_limits<TypeParam>::is_exact);
|
|
static_assert(std::numeric_limits<TypeParam>::radix == 2);
|
|
|
|
static_assert(std::numeric_limits<TypeParam>::min() == 0);
|
|
static_assert(std::numeric_limits<TypeParam>::max() == TypeParam{0} - 1);
|
|
|
|
EXPECT_EQ(std::numeric_limits<TypeParam>::min(), 0);
|
|
EXPECT_EQ(std::numeric_limits<TypeParam>::max(), TypeParam{0} - 1);
|
|
}
|
|
|
|
TYPED_TEST(uint_test, comparison)
|
|
{
|
|
constexpr auto half_words_count = TypeParam::num_words / 2;
|
|
|
|
auto z00 = TypeParam{0};
|
|
auto z01 = TypeParam{1};
|
|
auto z10 = TypeParam{0};
|
|
z10[half_words_count] = 1;
|
|
auto z11 = TypeParam{1};
|
|
z11[half_words_count] = 1;
|
|
|
|
EXPECT_EQ(z00, z00);
|
|
EXPECT_EQ(z01, z01);
|
|
EXPECT_EQ(z10, z10);
|
|
EXPECT_EQ(z11, z11);
|
|
|
|
EXPECT_NE(z00, z01);
|
|
EXPECT_NE(z00, z10);
|
|
EXPECT_NE(z00, z11);
|
|
EXPECT_NE(z10, z00);
|
|
EXPECT_NE(z10, z01);
|
|
EXPECT_NE(z10, z11);
|
|
|
|
EXPECT_LT(z00, z01);
|
|
EXPECT_LT(z00, z10);
|
|
EXPECT_LT(z00, z11);
|
|
EXPECT_LT(z01, z10);
|
|
EXPECT_LT(z01, z11);
|
|
EXPECT_LT(z10, z11);
|
|
|
|
EXPECT_LE(z00, z00);
|
|
EXPECT_LE(z00, z01);
|
|
EXPECT_LE(z00, z10);
|
|
EXPECT_LE(z00, z11);
|
|
EXPECT_LE(z01, z01);
|
|
EXPECT_LE(z01, z10);
|
|
EXPECT_LE(z01, z11);
|
|
EXPECT_LE(z10, z10);
|
|
EXPECT_LE(z10, z11);
|
|
EXPECT_LE(z11, z11);
|
|
|
|
EXPECT_GT(z01, z00);
|
|
EXPECT_GT(z10, z00);
|
|
EXPECT_GT(z11, z00);
|
|
EXPECT_GT(z10, z01);
|
|
EXPECT_GT(z11, z01);
|
|
EXPECT_GT(z11, z10);
|
|
|
|
EXPECT_GE(z00, z00);
|
|
EXPECT_GE(z01, z00);
|
|
EXPECT_GE(z10, z00);
|
|
EXPECT_GE(z11, z00);
|
|
EXPECT_GE(z01, z01);
|
|
EXPECT_GE(z10, z01);
|
|
EXPECT_GE(z11, z01);
|
|
EXPECT_GE(z10, z10);
|
|
EXPECT_GE(z11, z10);
|
|
EXPECT_GE(z11, z11);
|
|
}
|
|
|
|
TYPED_TEST(uint_test, negation_overflow)
|
|
{
|
|
auto x = -TypeParam{1};
|
|
auto z = TypeParam{0};
|
|
EXPECT_NE(x, z);
|
|
EXPECT_EQ(x, ~z);
|
|
|
|
auto m = TypeParam{1} << (sizeof(TypeParam) * 8 - 1); // Minimal signed value.
|
|
EXPECT_EQ(-m, m);
|
|
}
|
|
|
|
TYPED_TEST(uint_test, count_significant_words_64)
|
|
{
|
|
TypeParam x;
|
|
EXPECT_EQ(count_significant_words(x), 0u);
|
|
|
|
x = 1;
|
|
for (size_t s = 0; s < sizeof(TypeParam) * 8; ++s)
|
|
EXPECT_EQ(count_significant_words(x << s), s / 64 + 1);
|
|
}
|
|
|
|
TYPED_TEST(uint_test, count_significant_bytes)
|
|
{
|
|
static_assert(count_significant_bytes(TypeParam{0}) == 0);
|
|
static_assert(count_significant_bytes(TypeParam{1}) == 1);
|
|
static_assert(count_significant_bytes(TypeParam{0x80}) == 1);
|
|
static_assert(count_significant_bytes(TypeParam{0x100000000000000}) == 8);
|
|
static_assert(
|
|
count_significant_bytes(TypeParam{1} << (TypeParam::num_bits - 8)) == sizeof(TypeParam));
|
|
static_assert(
|
|
count_significant_bytes(TypeParam{1} << (TypeParam::num_bits - 1)) == sizeof(TypeParam));
|
|
|
|
TypeParam x;
|
|
EXPECT_EQ(count_significant_bytes(x), 0u);
|
|
x = 1;
|
|
EXPECT_EQ(count_significant_bytes(x), 1u);
|
|
x <<= TypeParam::num_bits - 1;
|
|
EXPECT_EQ(count_significant_bytes(x), sizeof(TypeParam));
|
|
}
|
|
|
|
TYPED_TEST(uint_test, bswap)
|
|
{
|
|
auto x = TypeParam{1};
|
|
EXPECT_EQ(bswap(x), x << ((sizeof(x) - 1) * 8));
|
|
}
|
|
|
|
TYPED_TEST(uint_test, endianness)
|
|
{
|
|
constexpr auto s = sizeof(TypeParam);
|
|
|
|
uint8_t data[s];
|
|
const auto x = TypeParam{1};
|
|
|
|
le::store(data, x);
|
|
EXPECT_EQ(data[0], 1);
|
|
EXPECT_EQ(data[s - 1], 0);
|
|
EXPECT_EQ(le::load<TypeParam>(data), x);
|
|
|
|
be::store(data, x);
|
|
EXPECT_EQ(data[0], 0);
|
|
EXPECT_EQ(data[s - 1], 1);
|
|
EXPECT_EQ(be::load<TypeParam>(data), x);
|
|
|
|
be::unsafe::store(data, x);
|
|
EXPECT_EQ(data[0], 0);
|
|
EXPECT_EQ(data[s - 1], 1);
|
|
EXPECT_EQ(be::unsafe::load<TypeParam>(data), x);
|
|
}
|
|
|
|
TYPED_TEST(uint_test, be_zext)
|
|
{
|
|
const uint8_t data[] = {0x01, 0x02, 0x03};
|
|
const auto x = be::load<TypeParam>(data);
|
|
EXPECT_EQ(x, 0x010203);
|
|
}
|
|
|
|
TYPED_TEST(uint_test, be_load)
|
|
{
|
|
constexpr auto size = sizeof(TypeParam);
|
|
uint8_t data[size]{};
|
|
data[0] = 0x80;
|
|
data[size - 1] = 3;
|
|
const auto x = be::load<TypeParam>(data);
|
|
EXPECT_EQ(x, (TypeParam{1} << (TypeParam::num_bits - 1)) | 3);
|
|
}
|
|
|
|
TYPED_TEST(uint_test, be_load_span_fixed)
|
|
{
|
|
constexpr auto size = sizeof(TypeParam);
|
|
uint8_t data[size]{};
|
|
data[0] = 0x80;
|
|
data[size - 2] = 5;
|
|
data[size - 1] = 3;
|
|
|
|
const std::span<const uint8_t, size> span_full{data};
|
|
const auto x = be::load<TypeParam>(span_full);
|
|
EXPECT_EQ(x, (TypeParam{1} << (TypeParam::num_bits - 1)) | 0x0503);
|
|
|
|
const std::span<const uint8_t, size - 1> span_partial{data, size - 1};
|
|
const auto y = be::load<TypeParam>(span_partial);
|
|
EXPECT_EQ(y, TypeParam{1} << (TypeParam::num_bits - 9) | 0x05);
|
|
|
|
const std::span<const uint8_t, 0> span_empty{data, 0};
|
|
const auto z = be::load<TypeParam>(span_empty);
|
|
EXPECT_EQ(z, 0);
|
|
}
|
|
|
|
TYPED_TEST(uint_test, be_load_span_dynamic)
|
|
{
|
|
constexpr auto size = sizeof(TypeParam);
|
|
uint8_t data[size]{};
|
|
data[0] = 0x80;
|
|
data[size - 2] = 5;
|
|
data[size - 1] = 3;
|
|
|
|
const std::span<const uint8_t> span_full{data};
|
|
const auto x = be::load<TypeParam>(span_full);
|
|
EXPECT_EQ(x, (TypeParam{1} << (TypeParam::num_bits - 1)) | 0x0503);
|
|
|
|
const std::span<const uint8_t> span_partial{data, size - 1};
|
|
const auto y = be::load<TypeParam>(span_partial);
|
|
EXPECT_EQ(y, TypeParam{1} << (TypeParam::num_bits - 9) | 0x05);
|
|
|
|
const std::span<const uint8_t> span_empty{data, 0};
|
|
const auto z = be::load<TypeParam>(span_empty);
|
|
EXPECT_EQ(z, 0);
|
|
}
|
|
|
|
TYPED_TEST(uint_test, be_store)
|
|
{
|
|
const auto x = TypeParam{0x0201};
|
|
uint8_t data[sizeof(x)];
|
|
be::store(data, x);
|
|
EXPECT_EQ(data[sizeof(x) - 1], 1);
|
|
EXPECT_EQ(data[sizeof(x) - 2], 2);
|
|
EXPECT_EQ(data[sizeof(x) - 3], 0);
|
|
EXPECT_EQ(data[0], 0);
|
|
}
|
|
|
|
TYPED_TEST(uint_test, be_store_span_fixed)
|
|
{
|
|
const auto x = TypeParam{0x0201};
|
|
uint8_t data[sizeof(x)];
|
|
const std::span<uint8_t, sizeof(x)> span_full{data};
|
|
be::store(span_full, x);
|
|
EXPECT_EQ(data[sizeof(x) - 1], 1);
|
|
EXPECT_EQ(data[sizeof(x) - 2], 2);
|
|
EXPECT_EQ(data[sizeof(x) - 3], 0);
|
|
EXPECT_EQ(data[0], 0);
|
|
}
|
|
|
|
TYPED_TEST(uint_test, be_trunc)
|
|
{
|
|
constexpr auto x = TypeParam{0xee48656c6c6f20536f6c617269732121_u128};
|
|
uint8_t out[15];
|
|
be::trunc(out, x);
|
|
const auto str = std::string{reinterpret_cast<char*>(out), sizeof(out)};
|
|
EXPECT_EQ(str, "Hello Solaris!!");
|
|
}
|
|
|
|
TYPED_TEST(uint_test, be_trunc_span_fixed)
|
|
{
|
|
constexpr auto x = TypeParam{0xee48656c6c6f20536f6c617269732121_u128};
|
|
uint8_t out[15];
|
|
const std::span<uint8_t, 15> span_15{out};
|
|
be::trunc(span_15, x);
|
|
auto str = std::string_view{reinterpret_cast<char*>(out), span_15.size()};
|
|
EXPECT_EQ(str, "Hello Solaris!!");
|
|
const std::span<uint8_t, 3> span_3{out, 3};
|
|
be::trunc(span_3, x);
|
|
str = std::string_view{reinterpret_cast<char*>(out), span_3.size()};
|
|
EXPECT_EQ(str, "s!!");
|
|
const std::span<uint8_t, 0> span_0{out, 0};
|
|
be::trunc(span_0, x);
|
|
str = std::string_view{reinterpret_cast<char*>(out), sizeof(out)};
|
|
EXPECT_EQ(str, "s!!lo Solaris!!");
|
|
}
|
|
|
|
TYPED_TEST(uint_test, be_trunc_span_dynamic)
|
|
{
|
|
constexpr auto x = TypeParam{0xee48656c6c6f20536f6c617269732121_u128};
|
|
uint8_t out[15];
|
|
const std::span<uint8_t> span_15{out};
|
|
be::trunc(span_15, x);
|
|
auto str = std::string_view{reinterpret_cast<char*>(out), span_15.size()};
|
|
EXPECT_EQ(str, "Hello Solaris!!");
|
|
const std::span<uint8_t> span_3{out, 3};
|
|
be::trunc(span_3, x);
|
|
str = std::string_view{reinterpret_cast<char*>(out), span_3.size()};
|
|
EXPECT_EQ(str, "s!!");
|
|
const std::span<uint8_t> span_0{out, 0};
|
|
be::trunc(span_0, x);
|
|
str = std::string_view{reinterpret_cast<char*>(out), sizeof(out)};
|
|
EXPECT_EQ(str, "s!!lo Solaris!!");
|
|
}
|
|
|
|
template <size_t M>
|
|
struct storage
|
|
{
|
|
uint8_t bytes[M];
|
|
};
|
|
|
|
TYPED_TEST(uint_test, typed_store)
|
|
{
|
|
const auto x = TypeParam{2};
|
|
const auto s = be::store<storage<sizeof(x)>>(x);
|
|
EXPECT_EQ(s.bytes[sizeof(x) - 1], 2);
|
|
}
|
|
|
|
TYPED_TEST(uint_test, typed_trunc)
|
|
{
|
|
const auto x = TypeParam{0xaabb};
|
|
const auto s = be::trunc<storage<9>>(x);
|
|
EXPECT_EQ(s.bytes[8], 0xbb);
|
|
EXPECT_EQ(s.bytes[7], 0xaa);
|
|
EXPECT_EQ(s.bytes[6], 0);
|
|
EXPECT_EQ(s.bytes[0], 0);
|
|
}
|
|
|
|
TYPED_TEST(uint_test, typed_load_zext)
|
|
{
|
|
const auto s = storage<1>({0xed});
|
|
const auto x = be::load<TypeParam>(s);
|
|
EXPECT_EQ(x, 0xed);
|
|
}
|
|
|
|
TYPED_TEST(uint_test, typed_load)
|
|
{
|
|
const auto s = storage<sizeof(TypeParam)>({0x88});
|
|
const auto x = be::load<TypeParam>(s);
|
|
EXPECT_EQ(x, TypeParam{0x88} << (TypeParam::num_bits - 8));
|
|
}
|
|
|
|
|
|
TYPED_TEST(uint_test, convert_to_bool)
|
|
{
|
|
constexpr auto half_bits_count = sizeof(TypeParam) * 4;
|
|
EXPECT_TRUE((TypeParam{1}));
|
|
EXPECT_TRUE((TypeParam{1} << half_bits_count));
|
|
EXPECT_TRUE((TypeParam{1} << half_bits_count) + 1);
|
|
EXPECT_TRUE((TypeParam{2}));
|
|
EXPECT_TRUE((TypeParam{2} << half_bits_count));
|
|
EXPECT_TRUE((TypeParam{2} << half_bits_count) + 2);
|
|
EXPECT_FALSE((TypeParam{0}));
|
|
}
|
|
|
|
TYPED_TEST(uint_test, string_conversions)
|
|
{
|
|
auto values = {
|
|
TypeParam{1} << (sizeof(TypeParam) * 8 - 1),
|
|
TypeParam{0},
|
|
TypeParam{1} << (sizeof(TypeParam) * 4 - 1),
|
|
(TypeParam{1} << (sizeof(TypeParam) * 4 - 1)) | 1,
|
|
~TypeParam{1},
|
|
~TypeParam{0},
|
|
};
|
|
|
|
for (auto v : values)
|
|
{
|
|
auto s = to_string(v);
|
|
auto x = from_string<TypeParam>(s);
|
|
EXPECT_EQ(x, v);
|
|
}
|
|
}
|
|
|
|
TYPED_TEST(uint_test, to_string_base)
|
|
{
|
|
auto x = TypeParam{1024};
|
|
EXPECT_THROW_MESSAGE(to_string(x, 1), std::invalid_argument, "invalid base");
|
|
EXPECT_THROW_MESSAGE(to_string(x, 37), std::invalid_argument, "invalid base");
|
|
EXPECT_EQ(to_string(x, 10), "1024");
|
|
EXPECT_EQ(to_string(x, 16), "400");
|
|
EXPECT_EQ(to_string(x, 36), "sg");
|
|
EXPECT_EQ(to_string(x, 2), "10000000000");
|
|
EXPECT_EQ(to_string(x, 8), "2000");
|
|
}
|
|
|
|
TYPED_TEST(uint_test, as_bytes)
|
|
{
|
|
constexpr auto x = to_little_endian(TypeParam{0xa05});
|
|
const auto b = as_bytes(x);
|
|
EXPECT_EQ(b[0], 5);
|
|
EXPECT_EQ(b[1], 0xa);
|
|
|
|
auto y = x;
|
|
auto d = as_bytes(y);
|
|
d[0] = 3;
|
|
d[1] = 0xc;
|
|
y = to_little_endian(y);
|
|
EXPECT_EQ(y, 0xc03);
|
|
}
|