endian.hpp: minor simplification

And stop pretending...
This commit is contained in:
Nekotekina 2020-12-11 21:06:19 +03:00
parent 7a015b6fc0
commit 33c3977036
2 changed files with 26 additions and 44 deletions

View file

@ -1,5 +1,7 @@
// No BOM and only basic ASCII in this file, or a neko will die // No BOM and only basic ASCII in this file, or a neko will die
#include "stdafx.h" #include "stdafx.h"
static_assert(std::endian::native == std::endian::little || std::endian::native == std::endian::big);
static_assert(be_t<u16>(1) + be_t<u32>(2) + be_t<u64>(3) == 6); static_assert(be_t<u16>(1) + be_t<u32>(2) + be_t<u64>(3) == 6);
static_assert(le_t<u16>(1) + le_t<u32>(2) + le_t<u64>(3) == 6); static_assert(le_t<u16>(1) + le_t<u32>(2) + le_t<u64>(3) == 6);

View file

@ -1,43 +1,20 @@
#pragma once // No BOM and only basic ASCII in this header, or a neko will die #pragma once // No BOM and only basic ASCII in this header, or a neko will die
#include <cstdint>
#include "Utilities/types.h" #include "Utilities/types.h"
#if __has_include(<bit>)
#include <bit>
#else
#include <type_traits>
#endif
namespace stx namespace stx
{ {
static_assert(std::endian::native == std::endian::little || std::endian::native == std::endian::big);
#ifdef _MSC_VER
template<class T, std::size_t... N>
static constexpr T bswap_impl(T i, std::index_sequence<N...>)
{
return static_cast<T>(((((i >> (N * 8)) & T{UINT8_MAX}) << ((sizeof(T) - 1 - N) * 8)) | ...));
};
template<class T, class U = typename std::make_unsigned<T>::type>
static constexpr U bswap(T i)
{
return bswap_impl<U>(i, std::make_index_sequence<sizeof(T)>{});
}
#endif
template <typename T, std::size_t Align = alignof(T), std::size_t Size = sizeof(T)> template <typename T, std::size_t Align = alignof(T), std::size_t Size = sizeof(T)>
struct se_storage struct se_storage
{ {
struct type8 struct type8
{ {
alignas(Align > alignof(T) ? alignof(T) : Align) unsigned char data[sizeof(T)]; alignas(Align > alignof(T) ? alignof(T) : Align) uchar data[sizeof(T)];
}; };
struct type64 struct type64
{ {
alignas(8) std::uint64_t data[sizeof(T) < 8 ? 1 : sizeof(T) / 8]; alignas(8) u64 data[sizeof(T) < 8 ? 1 : sizeof(T) / 8];
}; };
using type = std::conditional_t<(Align >= 8 && sizeof(T) % 8 == 0), type64, type8>; using type = std::conditional_t<(Align >= 8 && sizeof(T) % 8 == 0), type64, type8>;
@ -47,18 +24,18 @@ namespace stx
}; };
template <typename T> template <typename T>
struct se_storage<T, alignof(std::uint16_t), 2> struct se_storage<T, 2, 2>
{ {
using type = std::uint16_t; using type = u16;
static constexpr std::uint16_t swap(std::uint16_t src) noexcept static constexpr u16 swap(u16 src) noexcept
{ {
#if defined(__GNUG__) #if defined(__GNUG__)
return __builtin_bswap16(src); return __builtin_bswap16(src);
#else #else
if (std::is_constant_evaluated()) if (std::is_constant_evaluated())
{ {
return stx::bswap(src); return (src >> 8) | (src << 8);
} }
return _byteswap_ushort(src); return _byteswap_ushort(src);
@ -67,18 +44,19 @@ namespace stx
}; };
template <typename T> template <typename T>
struct se_storage<T, alignof(std::uint32_t), 4> struct se_storage<T, 4, 4>
{ {
using type = std::uint32_t; using type = u32;
static constexpr std::uint32_t swap(std::uint32_t src) noexcept static constexpr u32 swap(u32 src) noexcept
{ {
#if defined(__GNUG__) #if defined(__GNUG__)
return __builtin_bswap32(src); return __builtin_bswap32(src);
#else #else
if (std::is_constant_evaluated()) if (std::is_constant_evaluated())
{ {
return stx::bswap(src); const u32 v0 = ((src << 8) & 0xff00ff00) | ((src >> 8) & 0x00ff00ff);
return (v0 << 16) | (v0 >> 16);
} }
return _byteswap_ulong(src); return _byteswap_ulong(src);
@ -87,18 +65,20 @@ namespace stx
}; };
template <typename T> template <typename T>
struct se_storage<T, alignof(std::uint64_t), 8> struct se_storage<T, 8, 8>
{ {
using type = std::uint64_t; using type = u64;
static constexpr std::uint64_t swap(std::uint64_t src) noexcept static constexpr u64 swap(u64 src) noexcept
{ {
#if defined(__GNUG__) #if defined(__GNUG__)
return __builtin_bswap64(src); return __builtin_bswap64(src);
#else #else
if (std::is_constant_evaluated()) if (std::is_constant_evaluated())
{ {
return stx::bswap(src); const u64 v0 = ((src << 8) & 0xff00ff00ff00ff00) | ((src >> 8) & 0x00ff00ff00ff00ff);
const u64 v1 = ((v0 << 16) & 0xffff0000ffff0000) | ((v0 >> 16) & 0x0000ffff0000ffff);
return (v1 << 32) | (v1 >> 32);
} }
return _byteswap_uint64(src); return _byteswap_uint64(src);
@ -116,15 +96,15 @@ namespace stx
} }
else if constexpr (sizeof(T) == 2) else if constexpr (sizeof(T) == 2)
{ {
return std::bit_cast<type>(se_storage<std::uint16_t>::swap(std::bit_cast<std::uint16_t>(src))); return std::bit_cast<type>(se_storage<u16>::swap(std::bit_cast<u16>(src)));
} }
else if constexpr (sizeof(T) == 4) else if constexpr (sizeof(T) == 4)
{ {
return std::bit_cast<type>(se_storage<std::uint32_t>::swap(std::bit_cast<std::uint32_t>(src))); return std::bit_cast<type>(se_storage<u32>::swap(std::bit_cast<u32>(src)));
} }
else if constexpr (sizeof(T) == 8) else if constexpr (sizeof(T) == 8)
{ {
return std::bit_cast<type>(se_storage<std::uint64_t>::swap(std::bit_cast<std::uint64_t>(src))); return std::bit_cast<type>(se_storage<u64>::swap(std::bit_cast<u64>(src)));
} }
else if constexpr (sizeof(T) % 8 == 0) else if constexpr (sizeof(T) % 8 == 0)
{ {
@ -134,7 +114,7 @@ namespace stx
// Swap u64 blocks // Swap u64 blocks
for (std::size_t i = 0; i < sizeof(T) / 8; i++) for (std::size_t i = 0; i < sizeof(T) / 8; i++)
{ {
dst.data[i] = se_storage<std::uint64_t>::swap(tmp.data[sizeof(T) / 8 - 1 - i]); dst.data[i] = se_storage<u64>::swap(tmp.data[sizeof(T) / 8 - 1 - i]);
} }
return std::bit_cast<type>(dst); return std::bit_cast<type>(dst);
@ -182,13 +162,13 @@ namespace stx
static constexpr auto int_or_enum() static constexpr auto int_or_enum()
{ {
if constexpr (std::is_enum_v<simple_t<type>>) if constexpr (std::is_enum_v<type>)
{ {
return std::underlying_type_t<simple_t<type>>{}; return std::underlying_type_t<type>{};
} }
else else
{ {
return simple_t<type>{}; return type{};
} }
} }