mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-29 16:21:29 +00:00
AK: Add support for Little/BigEndian<UFixedBigInteger<M>>
This commit is contained in:
parent
94f5389934
commit
4f0f1c7c72
Notes:
sideshowbarker
2024-07-17 18:06:52 +09:00
Author: https://github.com/alimpfard Commit: https://github.com/SerenityOS/serenity/commit/4f0f1c7c72 Pull-request: https://github.com/SerenityOS/serenity/pull/19623 Reviewed-by: https://github.com/ADKaster Reviewed-by: https://github.com/DanShaders
|
@ -11,6 +11,7 @@
|
|||
#include <AK/BuiltinWrappers.h>
|
||||
#include <AK/Checked.h>
|
||||
#include <AK/Concepts.h>
|
||||
#include <AK/Endian.h>
|
||||
#include <AK/Format.h>
|
||||
#include <AK/NumericLimits.h>
|
||||
#include <AK/StdLibExtraDetails.h>
|
||||
|
@ -513,6 +514,78 @@ struct NumericLimits<UFixedBigInt<bit_size>> {
|
|||
static constexpr bool is_signed() { return false; }
|
||||
};
|
||||
|
||||
template<size_t N>
|
||||
class LittleEndian<UFixedBigInt<N>> {
|
||||
template<size_t M>
|
||||
constexpr static auto byte_swap_if_not_little_endian(UFixedBigInt<M> value)
|
||||
{
|
||||
if constexpr (HostIsLittleEndian) {
|
||||
return value;
|
||||
} else {
|
||||
auto words = value.span();
|
||||
auto front_it = words.begin();
|
||||
auto ending_half_words = words.slice(ceil_div(words.size(), static_cast<size_t>(2)));
|
||||
for (size_t i = 0; i < ending_half_words.size(); ++i, ++front_it)
|
||||
*front_it = convert_between_host_and_little_endian(exchange(ending_half_words[ending_half_words.size() - i - 1], convert_between_host_and_little_endian(*front_it)));
|
||||
if (words.size() % 2)
|
||||
words[words.size() / 2] = convert_between_host_and_little_endian(*front_it);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr LittleEndian() = default;
|
||||
|
||||
constexpr LittleEndian(UFixedBigInt<N> value)
|
||||
: m_value(byte_swap_if_not_little_endian(value))
|
||||
{
|
||||
}
|
||||
|
||||
constexpr operator UFixedBigInt<N>() const { return byte_swap_if_not_little_endian(m_value); }
|
||||
|
||||
private:
|
||||
UFixedBigInt<N> m_value { 0 };
|
||||
};
|
||||
|
||||
template<size_t N>
|
||||
class BigEndian<UFixedBigInt<N>> {
|
||||
template<size_t M>
|
||||
constexpr static auto byte_swap_if_not_big_endian(UFixedBigInt<M> value)
|
||||
{
|
||||
if constexpr (!HostIsLittleEndian) {
|
||||
return value;
|
||||
} else {
|
||||
auto words = value.span();
|
||||
auto front_it = words.begin();
|
||||
auto ending_half_words = words.slice(ceil_div(words.size(), static_cast<size_t>(2)));
|
||||
for (size_t i = 0; i < ending_half_words.size(); ++i, ++front_it)
|
||||
*front_it = convert_between_host_and_big_endian(exchange(ending_half_words[ending_half_words.size() - i - 1], convert_between_host_and_big_endian(*front_it)));
|
||||
if (words.size() % 2)
|
||||
words[words.size() / 2] = convert_between_host_and_big_endian(*front_it);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr BigEndian() = default;
|
||||
|
||||
constexpr BigEndian(UFixedBigInt<N> value)
|
||||
: m_value(byte_swap_if_not_big_endian(value))
|
||||
{
|
||||
}
|
||||
|
||||
constexpr operator UFixedBigInt<N>() const { return byte_swap_if_not_big_endian(m_value); }
|
||||
|
||||
private:
|
||||
UFixedBigInt<N> m_value { 0 };
|
||||
};
|
||||
|
||||
template<size_t M>
|
||||
struct Traits<UFixedBigInt<M>> : public GenericTraits<UFixedBigInt<M>> {
|
||||
static constexpr bool is_trivially_serializable() { return true; }
|
||||
static constexpr bool is_trivial() { return true; }
|
||||
};
|
||||
|
||||
// ===== Formatting =====
|
||||
// FIXME: This does not work for size != 2 ** x
|
||||
template<Detail::NotBuiltInUFixedInt T>
|
||||
|
|
|
@ -185,3 +185,15 @@ TEST_CASE(mod_hardcoded)
|
|||
EXPECT_EQ(u256(u128 { 0x7f13e232d82a24c6ULL, 0x23d41447dd7f5bc6ULL }, u128 { 0xd89a3ed8b30527caULL, 0xa98ef2cc01e83685ULL }) % u256(u128 { 0x8d4f5b1983fc1f0eULL, 0xf54102ece15fb0faULL }, u128 { 0x17b8aec68556a16dULL, 0x4e1e5bea70cb9398ULL }), u256(u128 { 0x64752bffd031e6aaULL, 0x39520e6e1abff9d1ULL }, u128 { 0xa928e14ba857e4eeULL, 0x0d523af720510f55ULL }));
|
||||
EXPECT_EQ(u256(u128 { 0x49750d7f39d61607ULL, 0x58bdef1c3e00d18eULL }, u128 { 0xa651479cd1fd1933ULL, 0xd1834bc3d654b633ULL }) % u256(u128 { 0x1bda34f5ec68ef3bULL, 0x12c65ce5363a7616ULL }, u128 { 0x5a79c4d85da0071aULL, 0xffa6b6284559d1aaULL }), u256(u128 { 0x49750d7f39d61607ULL, 0x58bdef1c3e00d18eULL }, u128 { 0xa651479cd1fd1933ULL, 0xd1834bc3d654b633ULL }));
|
||||
}
|
||||
|
||||
TEST_CASE(endian_swap)
|
||||
{
|
||||
constexpr u128 const a { 0x1234567890abcdefULL, 0xfedcba0987654321ULL };
|
||||
constexpr u128 const a_swapped { 0x2143658709badcfeull, 0xefcdab9078563412ull };
|
||||
|
||||
static_assert(!AK::HostIsLittleEndian || bit_cast<u128>(BigEndian { a }) == a_swapped);
|
||||
static_assert(AK::HostIsLittleEndian || bit_cast<u128>(LittleEndian { a }) == a_swapped);
|
||||
|
||||
static_assert(!AK::HostIsLittleEndian || bit_cast<u128>(LittleEndian { a }) == a);
|
||||
static_assert(AK::HostIsLittleEndian || bit_cast<u128>(BigEndian { a }) == a);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue