1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 18:27:35 +00:00

AK: Add support for Little/BigEndian<UFixedBigInteger<M>>

This commit is contained in:
Ali Mohammad Pur 2023-06-12 13:37:50 +03:30 committed by Ali Mohammad Pur
parent 94f5389934
commit 4f0f1c7c72
2 changed files with 85 additions and 0 deletions

View file

@ -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>