From 2c3565df6168495b504afb6f3b3190e5aa1ce87c Mon Sep 17 00:00:00 2001 From: lisyarus Date: Sat, 25 Jan 2025 20:35:37 +0300 Subject: [PATCH] 32-bit compilation fixes: * Use uint64_t instead of size_t as hash return value * Expect alignof(uint64_t) <= 8 instead of == 8 --- .../ecs/detail/ordered_component_hash.hpp | 6 +- .../psemek/ecs/detail/table_container.hpp | 4 +- .../ecs/detail/unordered_component_hash.hpp | 6 +- libs/ecs/include/psemek/ecs/handle.hpp | 4 +- libs/gfx/include/psemek/gfx/program.hpp | 7 +- libs/math/include/psemek/math/point.hpp | 6 +- libs/math/include/psemek/math/simplex.hpp | 4 +- libs/math/include/psemek/math/vector.hpp | 4 +- libs/sir/include/psemek/sir/platform.hpp | 6 +- libs/util/include/psemek/util/big_int.hpp | 197 ++++++++++++++++++ .../include/psemek/util/dynamic_bitset.hpp | 4 +- libs/util/include/psemek/util/ecs.hpp | 4 +- libs/util/include/psemek/util/hash.hpp | 27 +-- libs/util/include/psemek/util/hash_table.hpp | 24 +-- libs/util/include/psemek/util/hstring.hpp | 3 +- libs/util/include/psemek/util/uuid.hpp | 7 +- libs/util/source/big_int.cpp | 110 ++++++++++ libs/util/tests/big_int.cpp | 179 ++++++++++++++++ tools/noise-generator/generator.cpp | 2 +- 19 files changed, 545 insertions(+), 59 deletions(-) create mode 100644 libs/util/include/psemek/util/big_int.hpp create mode 100644 libs/util/source/big_int.cpp create mode 100644 libs/util/tests/big_int.cpp diff --git a/libs/ecs/include/psemek/ecs/detail/ordered_component_hash.hpp b/libs/ecs/include/psemek/ecs/detail/ordered_component_hash.hpp index ef5a9be5..0121e916 100644 --- a/libs/ecs/include/psemek/ecs/detail/ordered_component_hash.hpp +++ b/libs/ecs/include/psemek/ecs/detail/ordered_component_hash.hpp @@ -9,7 +9,7 @@ namespace psemek::ecs::detail template struct ordered_component_hasher { - std::size_t result = 0xb6113227befa663bull; + std::uint64_t result = 0xb6113227befa663bull; void operator()(util::uuid const & uuid) { @@ -22,7 +22,7 @@ namespace psemek::ecs::detail }; template - std::size_t ordered_component_hash(UUIDs const & uuids) + std::uint64_t ordered_component_hash(UUIDs const & uuids) { ordered_component_hasher hasher; for (auto const & uuid : uuids) @@ -31,7 +31,7 @@ namespace psemek::ecs::detail } template - std::size_t ordered_component_hash(WithUUIDs const & with_uuids, WithoutUUIDs const & without_uuids) + std::uint64_t ordered_component_hash(WithUUIDs const & with_uuids, WithoutUUIDs const & without_uuids) { return ordered_component_hash(with_uuids) ^ ordered_component_hash(without_uuids); } diff --git a/libs/ecs/include/psemek/ecs/detail/table_container.hpp b/libs/ecs/include/psemek/ecs/detail/table_container.hpp index de660612..71205444 100644 --- a/libs/ecs/include/psemek/ecs/detail/table_container.hpp +++ b/libs/ecs/include/psemek/ecs/detail/table_container.hpp @@ -9,12 +9,12 @@ namespace psemek::ecs::detail struct table_hashset_hash { - std::size_t operator()(util::span const & uuids) const + std::uint64_t operator()(util::span const & uuids) const { return unordered_component_hash(uuids); } - std::size_t operator()(std::unique_ptr const & table) const + std::uint64_t operator()(std::unique_ptr
const & table) const { return table->hash(); } diff --git a/libs/ecs/include/psemek/ecs/detail/unordered_component_hash.hpp b/libs/ecs/include/psemek/ecs/detail/unordered_component_hash.hpp index ad756cc5..659ec796 100644 --- a/libs/ecs/include/psemek/ecs/detail/unordered_component_hash.hpp +++ b/libs/ecs/include/psemek/ecs/detail/unordered_component_hash.hpp @@ -9,7 +9,7 @@ namespace psemek::ecs::detail template struct unordered_component_hasher { - std::size_t result = 0xcd5694d2b3f3443eull; + std::uint64_t result = 0xcd5694d2b3f3443eull; void operator()(util::uuid const & uuid) { @@ -21,7 +21,7 @@ namespace psemek::ecs::detail }; template - std::size_t unordered_component_hash(UUIDs const & uuids) + std::uint64_t unordered_component_hash(UUIDs const & uuids) { unordered_component_hasher hasher; for (auto const & uuid : uuids) @@ -30,7 +30,7 @@ namespace psemek::ecs::detail } template - std::size_t unordered_component_hash(WithUUIDs const & with_uuids, WithoutUUIDs const & without_uuids) + std::uint64_t unordered_component_hash(WithUUIDs const & with_uuids, WithoutUUIDs const & without_uuids) { return unordered_component_hash(with_uuids) ^ unordered_component_hash(without_uuids); } diff --git a/libs/ecs/include/psemek/ecs/handle.hpp b/libs/ecs/include/psemek/ecs/handle.hpp index dc596300..ef2c054d 100644 --- a/libs/ecs/include/psemek/ecs/handle.hpp +++ b/libs/ecs/include/psemek/ecs/handle.hpp @@ -40,9 +40,9 @@ namespace std template <> struct hash<::psemek::ecs::handle> { - size_t operator()(::psemek::ecs::handle const & h) const noexcept + uint64_t operator()(::psemek::ecs::handle const & h) const noexcept { - return (static_cast(h.id) << 32) | h.epoch; + return (static_cast(h.id) << 32) | h.epoch; } }; diff --git a/libs/gfx/include/psemek/gfx/program.hpp b/libs/gfx/include/psemek/gfx/program.hpp index eda16191..08136ce8 100644 --- a/libs/gfx/include/psemek/gfx/program.hpp +++ b/libs/gfx/include/psemek/gfx/program.hpp @@ -7,8 +7,7 @@ #include #include #include - -#include +#include #include @@ -121,8 +120,8 @@ namespace psemek::gfx private: GLuint program_ = 0; - mutable boost::container::flat_map> uniforms_; - mutable boost::container::flat_map> uniform_blocks_; + mutable util::hash_map> uniforms_; + mutable util::hash_map> uniform_blocks_; program(std::nullptr_t) {} diff --git a/libs/math/include/psemek/math/point.hpp b/libs/math/include/psemek/math/point.hpp index aa0722f3..461d6cec 100644 --- a/libs/math/include/psemek/math/point.hpp +++ b/libs/math/include/psemek/math/point.hpp @@ -222,10 +222,10 @@ namespace std template struct hash<::psemek::math::point> { - std::size_t operator()(::psemek::math::point const & v) const noexcept + std::uint64_t operator()(::psemek::math::point const & v) const noexcept { - std::hash h; - std::size_t r = 0; + hash h; + std::uint64_t r = 0; for (std::size_t i = 0; i < N; ++i) ::psemek::util::hash_combine(r, h(v[i])); return r; diff --git a/libs/math/include/psemek/math/simplex.hpp b/libs/math/include/psemek/math/simplex.hpp index 49853fdc..3094ea5b 100644 --- a/libs/math/include/psemek/math/simplex.hpp +++ b/libs/math/include/psemek/math/simplex.hpp @@ -139,9 +139,9 @@ namespace std template struct hash<::psemek::math::simplex> { - std::size_t operator()(::psemek::math::simplex const & simplex) const + std::uint64_t operator()(::psemek::math::simplex const & simplex) const { - std::size_t result = 0; + std::uint64_t result = 0; std::hash h; for (auto const & p : simplex.points) ::psemek::util::hash_combine(result, h(p)); diff --git a/libs/math/include/psemek/math/vector.hpp b/libs/math/include/psemek/math/vector.hpp index 731f53e8..5573b748 100644 --- a/libs/math/include/psemek/math/vector.hpp +++ b/libs/math/include/psemek/math/vector.hpp @@ -472,10 +472,10 @@ namespace std template struct hash<::psemek::math::vector> { - std::size_t operator()(::psemek::math::vector const & v) const noexcept + std::uint64_t operator()(::psemek::math::vector const & v) const noexcept { std::hash h; - std::size_t r = 0; + std::uint64_t r = 0; for (std::size_t i = 0; i < N; ++i) ::psemek::util::hash_combine(r, h(v[i])); return r; diff --git a/libs/sir/include/psemek/sir/platform.hpp b/libs/sir/include/psemek/sir/platform.hpp index 8b4678bb..ae5f50f6 100644 --- a/libs/sir/include/psemek/sir/platform.hpp +++ b/libs/sir/include/psemek/sir/platform.hpp @@ -19,14 +19,14 @@ namespace psemek::sir static_assert(alignof(std::uint8_t) == 1); static_assert(alignof(std::uint16_t) == 2); static_assert(alignof(std::uint32_t) == 4); - static_assert(alignof(std::uint64_t) == 8); + static_assert(alignof(std::uint64_t) <= 8); static_assert(alignof(std::int8_t) == 1); static_assert(alignof(std::int16_t) == 2); static_assert(alignof(std::int32_t) == 4); - static_assert(alignof(std::int64_t) == 8); + static_assert(alignof(std::int64_t) <= 8); static_assert(sizeof(float) == 4); static_assert(alignof(float) == 4); static_assert(sizeof(double) == 8); - static_assert(alignof(double) == 8); + static_assert(alignof(double) <= 8); } diff --git a/libs/util/include/psemek/util/big_int.hpp b/libs/util/include/psemek/util/big_int.hpp new file mode 100644 index 00000000..bd537a53 --- /dev/null +++ b/libs/util/include/psemek/util/big_int.hpp @@ -0,0 +1,197 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include + +namespace psemek::util +{ + + struct big_int + { + using digit = std::uint32_t; + + big_int() = default; + + template + big_int(T value); + + big_int(big_int const &) = delete; + + big_int(big_int && other); + + static big_int from_digits(std::unique_ptr digits, std::uint32_t size, bool negative = false); + + template + static big_int from_digits(Iterator begin, Iterator end, bool negative = false); + + template + static big_int from_digits(Container && container, bool negative = false); + + big_int & operator = (big_int const &) = delete; + + big_int & operator = (big_int && other); + + util::span digits(); + util::span digits() const; + + bool negative() const; + + private: + static constexpr std::uint32_t sign_bit = std::uint32_t(1) << 31; + static constexpr std::uint32_t digit_size = sizeof(digit); + static constexpr std::uint32_t digit_bits = digit_size * 8; + static constexpr std::uint32_t digit_mask = digit(-1); + + std::unique_ptr digits_ = nullptr; + // Highest bit of size stores the overall big int sign + std::uint32_t size_ = 0; + std::uint32_t capacity_ = 0; + + void set_negative(bool negative) + { + size_ = size() | (negative ? sign_bit : 0); + } + + std::uint32_t size() const + { + return size_ & (~sign_bit); + } + + void set_size(std::uint32_t new_size) + { + size_ = new_size | (size_ & sign_bit); + } + + void canonicalize(); + + void ensure_capacity(std::uint32_t new_capacity); + + template + static T shift_by_digit(T value); + + template + static std::uint32_t size_for(T value); + + void add_positive(span digits); + }; + + template + big_int::big_int(T value) + { + auto size = size_for(value); + ensure_capacity(size); + set_size(size); + set_negative(value < 0); + for (digit & d : digits()) + { + d = value & digit_mask; + value = shift_by_digit(value); + } + + if (negative()) + { + for (digit & d : digits()) + d = ~d; + digit const one = 1; + add_positive(make_singleton_span(one)); + } + } + + inline big_int::big_int(big_int && other) + : digits_(std::move(other.digits_)) + , size_(other.size_) + , capacity_(other.capacity_) + { + other.size_ = 0; + other.capacity_ = 0; + } + + inline big_int big_int::from_digits(std::unique_ptr digits, std::uint32_t size, bool negative) + { + big_int result; + result.digits_ = std::move(digits); + result.size_ = size; + result.capacity_ = size; + result.set_negative(negative); + result.canonicalize(); + return result; + } + + template + big_int big_int::from_digits(Iterator begin, Iterator end, bool negative) + { + auto size = std::distance(begin, end); + auto digits = std::make_unique(size); + std::copy(begin, end, digits.get()); + return from_digits(std::move(digits), size, negative); + } + + template + big_int big_int::from_digits(Container && container, bool negative) + { + return from_digits(util::xbegin(container), util::xend(container), negative); + } + + inline util::span big_int::digits() + { + return {digits_.get(), size()}; + } + + inline util::span big_int::digits() const + { + return {digits_.get(), size()}; + } + + inline bool big_int::negative() const + { + return (size_ & sign_bit) == sign_bit; + } + + template + T big_int::shift_by_digit(T value) + { + if constexpr (sizeof(value) <= digit_size) + { + if (value < 0) + return -1; + else + return 0; + } + else + { + return value >> digit_bits; + } + } + + template + std::uint32_t big_int::size_for(T value) + { + std::uint32_t result_bits = 0; + + if (value >= 0) + { + while (value > 0) + { + value = shift_by_digit(value); + result_bits += digit_bits; + } + } + else + { + result_bits = 1; + while ((value >> (digit_bits - 1)) != T(-1)) + { + value = shift_by_digit(value); + result_bits += digit_bits; + } + } + + return (result_bits + (digit_bits - 1)) / digit_bits; + } + +} diff --git a/libs/util/include/psemek/util/dynamic_bitset.hpp b/libs/util/include/psemek/util/dynamic_bitset.hpp index 2c7438cd..20f35f2a 100644 --- a/libs/util/include/psemek/util/dynamic_bitset.hpp +++ b/libs/util/include/psemek/util/dynamic_bitset.hpp @@ -97,9 +97,9 @@ namespace std template <> struct hash<::psemek::util::dynamic_bitset> { - std::size_t operator()(::psemek::util::dynamic_bitset const & b) const + std::uint64_t operator()(::psemek::util::dynamic_bitset const & b) const { - std::size_t result = 0x23d2ef655094f9aeull; + std::uint64_t result = static_cast(0x23d2ef655094f9aeull); for (auto value : b.storage()) ::psemek::util::hash_combine(result, value); return result; diff --git a/libs/util/include/psemek/util/ecs.hpp b/libs/util/include/psemek/util/ecs.hpp index 3109b272..3fa4ceaf 100644 --- a/libs/util/include/psemek/util/ecs.hpp +++ b/libs/util/include/psemek/util/ecs.hpp @@ -962,7 +962,7 @@ namespace std template <> struct hash<::psemek::util::ecs::species_handle> { - std::size_t operator()(::psemek::util::ecs::species_handle h) const + std::uint64_t operator()(::psemek::util::ecs::species_handle h) const { return std::hash<::psemek::util::ecs_detail::species_handle>()(h.value); } @@ -971,7 +971,7 @@ namespace std template <> struct hash<::psemek::util::ecs::entity_handle> { - std::size_t operator()(::psemek::util::ecs::entity_handle h) const + std::uint64_t operator()(::psemek::util::ecs::entity_handle h) const { return std::hash<::psemek::util::ecs_detail::entity_handle>()(h.value); } diff --git a/libs/util/include/psemek/util/hash.hpp b/libs/util/include/psemek/util/hash.hpp index 3bbfcdd3..3e53bf22 100644 --- a/libs/util/include/psemek/util/hash.hpp +++ b/libs/util/include/psemek/util/hash.hpp @@ -2,22 +2,23 @@ #include #include +#include namespace psemek::util { - constexpr void hash_combine(std::size_t & seed, std::size_t value) + constexpr void hash_combine(std::uint64_t & seed, std::uint64_t value) { - constexpr std::size_t k = 0x9ddfea08eb382d69ULL; - std::size_t a = (value ^ seed) * k; + constexpr std::uint64_t k = 0x9ddfea08eb382d69ULL; + std::uint64_t a = (value ^ seed) * k; a ^= (a >> 47); - std::size_t b = (seed ^ a) * k; + std::uint64_t b = (seed ^ a) * k; b ^= (b >> 47); seed = b * k; } template ())>>> - constexpr void hash_sequence(std::size_t & seed, Iterator begin, Iterator end, Hash hash = Hash{}) + constexpr void hash_sequence(std::uint64_t & seed, Iterator begin, Iterator end, Hash hash = Hash{}) { for (; begin != end; ++begin) { @@ -30,17 +31,17 @@ namespace psemek::util struct is_transparent{}; template - std::size_t operator() (T const & x) const + std::uint64_t operator() (T const & x) const { return std::hash{}(x); } }; template - constexpr std::size_t hash_all(T const & ... x) + constexpr std::uint64_t hash_all(T const & ... x) { any_hash hash; - std::size_t seed = 0; + std::uint64_t seed = 0; (hash_combine(seed, hash(x)), ...); return seed; } @@ -54,9 +55,9 @@ namespace std struct hash> : std::pair, std::hash> { - std::size_t operator()(std::pair const & x) const + std::uint64_t operator()(std::pair const & x) const { - std::size_t seed = 0; + std::uint64_t seed = 0; ::psemek::util::hash_combine(seed, this->first(x.first)); ::psemek::util::hash_combine(seed, this->second(x.second)); return seed; @@ -67,16 +68,16 @@ namespace std struct hash> : std::tuple...> { - std::size_t operator()(std::tuple const & t) const + std::uint64_t operator()(std::tuple const & t) const { return hash_impl(t, std::make_index_sequence{}); } private: template - std::size_t hash_impl(std::tuple const & t, std::index_sequence) const + std::uint64_t hash_impl(std::tuple const & t, std::index_sequence) const { - std::size_t result = 0; + std::uint64_t result = 0; (::psemek::util::hash_combine(result, std::get(*this)(std::get(t))), ...); return result; } diff --git a/libs/util/include/psemek/util/hash_table.hpp b/libs/util/include/psemek/util/hash_table.hpp index dc94a29f..f1f13951 100644 --- a/libs/util/include/psemek/util/hash_table.hpp +++ b/libs/util/include/psemek/util/hash_table.hpp @@ -13,14 +13,14 @@ namespace psemek::util namespace detail { - constexpr std::size_t stored_value_mask = 1ull << 63; - constexpr std::size_t tombstone_mask = 1ull << 62; - constexpr std::size_t hash_value_mask = ~(stored_value_mask | tombstone_mask); + constexpr std::uint64_t stored_value_mask = 1ull << 63; + constexpr std::uint64_t tombstone_mask = 1ull << 62; + constexpr std::uint64_t hash_value_mask = ~(stored_value_mask | tombstone_mask); template struct hash_table_entry { - std::size_t hash = 0; + std::uint64_t hash = 0; alignas(T) char storage[sizeof(T)] = {0}; bool has_value() const @@ -44,13 +44,13 @@ namespace psemek::util } template - void set_value(H && value, std::size_t hash) + void set_value(H && value, std::uint64_t hash) { new (storage_ptr()) T{std::forward(value)}; this->hash = (hash & hash_value_mask) | stored_value_mask; } - bool hash_equal(std::size_t hash) const + bool hash_equal(std::uint64_t hash) const { return (hash & hash_value_mask) == (this->hash & hash_value_mask); } @@ -211,7 +211,7 @@ namespace psemek::util std::pair, bool> insert(H && value) { ensure_capacity_for(size_ + 1); - std::size_t hash = this->hash()(this->key_projector()(value)); + std::uint64_t hash = this->hash()(this->key_projector()(value)); return insert_impl(std::forward(value), hash); } @@ -220,7 +220,7 @@ namespace psemek::util { if (size_ == 0) return end(); - std::size_t hash = this->hash()(key); + std::uint64_t hash = this->hash()(key); return find_impl(key, hash); } @@ -320,13 +320,13 @@ namespace psemek::util reallocate(capacity()); } - std::size_t probe_index(std::size_t hash, std::size_t i) const + std::size_t probe_index(std::uint64_t hash, std::size_t i) const { - return (hash + (i * (i + 1)) / 2) % storage_.capacity; + return (static_cast(hash) + (i * (i + 1)) / 2) % storage_.capacity; } template - std::pair, bool> insert_impl(H && value, std::size_t hash) + std::pair, bool> insert_impl(H && value, std::uint64_t hash) { std::size_t i = 0; while (true) @@ -349,7 +349,7 @@ namespace psemek::util } template - hash_table_iterator find_impl(Key const & key, std::size_t hash) const + hash_table_iterator find_impl(Key const & key, std::uint64_t hash) const { std::size_t i = 0; while (true) diff --git a/libs/util/include/psemek/util/hstring.hpp b/libs/util/include/psemek/util/hstring.hpp index 6371b3bc..6a67edca 100644 --- a/libs/util/include/psemek/util/hstring.hpp +++ b/libs/util/include/psemek/util/hstring.hpp @@ -3,6 +3,7 @@ #include #include #include +#include namespace psemek::util { @@ -87,7 +88,7 @@ namespace std template <> struct hash<::psemek::util::hstring> { - std::size_t operator()(::psemek::util::hstring const & str) const + std::uint64_t operator()(::psemek::util::hstring const & str) const { return std::hash()(str.view()); } diff --git a/libs/util/include/psemek/util/uuid.hpp b/libs/util/include/psemek/util/uuid.hpp index e4b6881b..9170f956 100644 --- a/libs/util/include/psemek/util/uuid.hpp +++ b/libs/util/include/psemek/util/uuid.hpp @@ -2,7 +2,6 @@ #include -#include #include #include #include @@ -29,7 +28,7 @@ namespace psemek::util }; static_assert(sizeof(uuid) == 16); - static_assert(alignof(uuid) == 8); + static_assert(alignof(uuid) <= 8); constexpr bool is_rfc_4122(uuid const & uuid) { @@ -72,9 +71,9 @@ namespace std template <> struct hash<::psemek::util::uuid> { - std::size_t operator()(::psemek::util::uuid const & uuid) const noexcept + std::uint64_t operator()(::psemek::util::uuid const & uuid) const noexcept { - std::size_t result = uuid[0]; + std::uint64_t result = uuid[0]; ::psemek::util::hash_combine(result, uuid[1]); return result; } diff --git a/libs/util/source/big_int.cpp b/libs/util/source/big_int.cpp new file mode 100644 index 00000000..588fdad7 --- /dev/null +++ b/libs/util/source/big_int.cpp @@ -0,0 +1,110 @@ +#include + +#include + +namespace psemek::util +{ + + namespace + { + + struct adder + { + std::uint32_t sum = 0; + std::uint32_t carry = 0; + + void add(std::uint32_t x) + { + auto result = static_cast(sum) + x; + sum = result & std::uint32_t(-1); + carry += result >> 32; + } + }; + + } + + void big_int::canonicalize() + { + auto size = this->size(); + auto negative = this->negative(); + + while (size > 0 && digits_[size - 1] == 0) + --size; + + set_size(size); + set_negative(size > 0 && negative); + } + + void big_int::ensure_capacity(std::uint32_t new_capacity) + { + if (new_capacity == 0) + { + digits_ = nullptr; + size_ = 0; + capacity_ = 0; + } + else if (new_capacity > capacity_) + { + new_capacity = std::max({static_cast(1.6 * size()), static_cast(16), new_capacity}); + + auto new_digits = std::make_unique(new_capacity); + + std::size_t i = 0; + for (; i < size(); ++i) + new_digits[i] = digits_[i]; + for (; i < new_capacity; ++i) + new_digits[i] = 0; + + digits_ = std::move(new_digits); + capacity_ = new_capacity; + } + } + + void big_int::add_positive(span digits) + { + digit carry = 0; + + std::size_t i = 0; + std::size_t min_size = std::min(size(), digits.size()); + + for (; i < min_size; ++i) + { + adder adder{digits_[i]}; + adder.add(digits[i]); + adder.add(carry); + std::tie(digits_[i], carry) = {adder.sum, adder.carry}; + } + + if (i < digits.size()) + { + ensure_capacity(digits.size()); + for (; i < digits.size(); ++i) + { + adder adder{digits[i]}; + adder.add(carry); + std::tie(digits_[i], carry) = {adder.sum, adder.carry}; + } + set_size(digits.size()); + } + + if (i < size()) + { + for (; i < size() && carry != 0; ++i) + { + adder adder{digits_[i]}; + adder.add(carry); + std::tie(digits_[i], carry) = {adder.sum, adder.carry}; + } + } + + if (carry != 0) + { + ensure_capacity(size() + 1); + digits_[size()] = carry; + set_size(size() + 1); + } + + canonicalize(); + } + +} diff --git a/libs/util/tests/big_int.cpp b/libs/util/tests/big_int.cpp new file mode 100644 index 00000000..aa8f57ca --- /dev/null +++ b/libs/util/tests/big_int.cpp @@ -0,0 +1,179 @@ +#include + +#include +#include +#include + +using namespace psemek; +using namespace psemek::util; + +namespace +{ + + void check_digits(big_int const & bi, std::vector const & digits_expected) + { + span digits_actual = bi.digits(); + expect_equal(digits_actual.size(), digits_expected.size()); + for (std::size_t i = 0; i < digits_actual.size(); ++i) + expect_equal(digits_actual[i], digits_expected[i]); + } + +} + +test_case(util_big__int_init_small) +{ + { + big_int x; + expect(!x.negative()); + check_digits(x, {}); + } + + { + big_int x(1); + expect(!x.negative()); + check_digits(x, {1}); + } + + { + big_int x(173); + expect(!x.negative()); + check_digits(x, {173}); + } + + { + big_int x(1u << 31); + expect(!x.negative()); + check_digits(x, {1u << 31}); + } + + { + big_int x(1ull << 32); + expect(!x.negative()); + check_digits(x, {0, 1}); + } + + { + big_int x(1ull << 63); + expect(!x.negative()); + check_digits(x, {0, 1u << 31}); + } + + { + big_int x(static_cast(-1)); + expect(!x.negative()); + check_digits(x, {-1, -1}); + } + + { + big_int x(-1); + expect(x.negative()); + check_digits(x, {1}); + } + + { + big_int x(-279); + expect(x.negative()); + check_digits(x, {279}); + } + + { + big_int x((-1) << 31); + expect(x.negative()); + check_digits(x, {1u << 31}); + } + + { + big_int x((-1ll) << 32); + expect(x.negative()); + check_digits(x, {0, 1u}); + } + + { + big_int x((-1ll) << 63); + expect(x.negative()); + check_digits(x, {0, 1u << 31}); + } + + { + big_int x(((-1ll) << 62) + ((-1ll) << 15)); + expect(x.negative()); + check_digits(x, {1u << 15, 1u << 30}); + } +} + +test_case(util_big__int_init_from__digits) +{ + random::generator rng; + + { + big_int x = big_int::from_digits(std::vector{}); + expect(!x.negative()); + check_digits(x, {}); + } + + { + big_int x = big_int::from_digits(std::vector{5724}); + expect(!x.negative()); + check_digits(x, {5724}); + } + + { + big_int x = big_int::from_digits(std::vector{1234, 5678}); + expect(!x.negative()); + check_digits(x, {1234, 5678}); + } + + { + big_int x = big_int::from_digits(std::vector{1234, 5678, 0, 0}); + expect(!x.negative()); + check_digits(x, {1234, 5678}); + } + + { + std::vector digits(64); + for (auto & digit : digits) + digit = random::uniform(rng); + if (digits.back() == 0) + digits.back() = 1; + + big_int x = big_int::from_digits(digits); + expect(!x.negative()); + check_digits(x, digits); + } + + { + big_int x = big_int::from_digits(std::vector{}, true); + expect(!x.negative()); + check_digits(x, {}); + } + + { + big_int x = big_int::from_digits(std::vector{5724}, true); + expect(x.negative()); + check_digits(x, {5724}); + } + + { + big_int x = big_int::from_digits(std::vector{1234, 5678}, true); + expect(x.negative()); + check_digits(x, {1234, 5678}); + } + + { + big_int x = big_int::from_digits(std::vector{1234, 5678, 0, 0}, true); + expect(x.negative()); + check_digits(x, {1234, 5678}); + } + + { + std::vector digits(64); + for (auto & digit : digits) + digit = random::uniform(rng); + if (digits.back() == 0) + digits.back() = 1; + + big_int x = big_int::from_digits(digits, true); + expect(x.negative()); + check_digits(x, digits); + } +} diff --git a/tools/noise-generator/generator.cpp b/tools/noise-generator/generator.cpp index d68d667b..af22b91a 100644 --- a/tools/noise-generator/generator.cpp +++ b/tools/noise-generator/generator.cpp @@ -166,7 +166,7 @@ std::optional parse_seed(std::string const & str, int base) { try { - std::uint64_t unused; + std::size_t unused; return std::stoull(str, &unused, base); } catch (...)