From 191414c8320ba8bb0307dd6acbeca081a284b356 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 24 Feb 2020 19:29:00 -0800 Subject: [PATCH] util: add ConvertTo*Endian48 --- .../include/vapours/util/util_endian.hpp | 57 +++++++++++++++++-- 1 file changed, 51 insertions(+), 6 deletions(-) diff --git a/libraries/libvapours/include/vapours/util/util_endian.hpp b/libraries/libvapours/include/vapours/util/util_endian.hpp index c91b72558..7f7e11bee 100644 --- a/libraries/libvapours/include/vapours/util/util_endian.hpp +++ b/libraries/libvapours/include/vapours/util/util_endian.hpp @@ -71,6 +71,19 @@ namespace ams::util { } } + constexpr ALWAYS_INLINE u64 SwapBytes48(const u64 u) { + using U = u64; + static_assert(BITSIZEOF(u8) == 8); + constexpr U ByteMask = 0xFFu; + AMS_ASSERT((u & UINT64_C(0xFFFF000000000000)) == 0); + return ((u & (ByteMask << 40)) >> 40) | + ((u & (ByteMask << 32)) >> 24) | + ((u & (ByteMask << 24)) >> 8) | + ((u & (ByteMask << 16)) << 8) | + ((u & (ByteMask << 8)) << 24) | + ((u & (ByteMask << 0)) << 40); + } + template /* requires integral */ constexpr ALWAYS_INLINE void SwapBytes(T *ptr) { using U = typename std::make_unsigned::type; @@ -78,23 +91,55 @@ namespace ams::util { *ptr = static_cast(SwapBytes(static_cast(*ptr))); } - template + template /* requires integral */ constexpr ALWAYS_INLINE T ConvertToBigEndian(const T val) { + using U = typename std::make_unsigned::type; + if constexpr (IsBigEndian()) { - return val; + return static_cast(static_cast(val)); } else { static_assert(IsLittleEndian()); - return SwapBytes(val); + return static_cast(SwapBytes(static_cast(val))); } } - template + template /* requires integral */ constexpr ALWAYS_INLINE T ConvertToLittleEndian(const T val) { + using U = typename std::make_unsigned::type; + if constexpr (IsBigEndian()) { - return SwapBytes(val); + return static_cast(SwapBytes(static_cast(val))); } else { static_assert(IsLittleEndian()); - return val; + return static_cast(static_cast(val)); + } + } + + template /* requires integral */ + constexpr ALWAYS_INLINE T ConvertToBigEndian48(const T val) { + using U = typename std::make_unsigned::type; + static_assert(sizeof(T) == sizeof(u64)); + + if constexpr (IsBigEndian()) { + AMS_ASSERT((static_cast(val) & UINT64_C(0xFFFF000000000000)) == 0); + return static_cast(static_cast(val)); + } else { + static_assert(IsLittleEndian()); + return static_cast(SwapBytes48(static_cast(val))); + } + } + + template /* requires integral */ + constexpr ALWAYS_INLINE T ConvertToLittleEndian48(const T val) { + using U = typename std::make_unsigned::type; + static_assert(sizeof(T) == sizeof(u64)); + + if constexpr (IsBigEndian()) { + return static_cast(SwapBytes48(static_cast(val))); + } else { + static_assert(IsLittleEndian()); + AMS_ASSERT((static_cast(val) & UINT64_C(0xFFFF000000000000)) == 0); + return static_cast(static_cast(val)); } }