2013-09-19 04:26:13 +01:00
|
|
|
// Copyright (c) 2012- PPSSPP Project / Dolphin Project.
|
|
|
|
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
|
|
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
|
|
|
|
// Official git repository and contact information can be found at
|
|
|
|
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2015-06-21 13:12:49 +01:00
|
|
|
#if defined(_MSC_VER)
|
2016-09-18 01:38:01 +01:00
|
|
|
#include <cstdlib>
|
2013-09-19 04:26:13 +01:00
|
|
|
#endif
|
2020-07-14 21:21:35 +01:00
|
|
|
#include <bit>
|
2016-05-09 04:21:44 +01:00
|
|
|
#include <cstring>
|
2020-07-14 21:21:35 +01:00
|
|
|
#include <type_traits>
|
2015-06-21 13:12:49 +01:00
|
|
|
#include "common/common_types.h"
|
|
|
|
|
2015-03-06 06:46:45 +00:00
|
|
|
namespace Common {
|
|
|
|
|
|
|
|
#ifdef _MSC_VER
|
2019-04-12 01:42:40 +01:00
|
|
|
[[nodiscard]] inline u16 swap16(u16 data) noexcept {
|
2019-04-12 01:26:37 +01:00
|
|
|
return _byteswap_ushort(data);
|
2016-09-18 01:38:01 +01:00
|
|
|
}
|
2019-04-12 01:42:40 +01:00
|
|
|
[[nodiscard]] inline u32 swap32(u32 data) noexcept {
|
2019-04-12 01:26:37 +01:00
|
|
|
return _byteswap_ulong(data);
|
2016-09-18 01:38:01 +01:00
|
|
|
}
|
2019-04-12 01:42:40 +01:00
|
|
|
[[nodiscard]] inline u64 swap64(u64 data) noexcept {
|
2019-04-12 01:26:37 +01:00
|
|
|
return _byteswap_uint64(data);
|
2016-09-18 01:38:01 +01:00
|
|
|
}
|
2019-04-12 01:26:37 +01:00
|
|
|
#elif defined(__clang__) || defined(__GNUC__)
|
|
|
|
#if defined(__Bitrig__) || defined(__OpenBSD__)
|
2018-03-27 10:54:29 +01:00
|
|
|
// redefine swap16, swap32, swap64 as inline functions
|
|
|
|
#undef swap16
|
|
|
|
#undef swap32
|
|
|
|
#undef swap64
|
2019-04-12 01:26:37 +01:00
|
|
|
#endif
|
2019-04-12 01:42:40 +01:00
|
|
|
[[nodiscard]] inline u16 swap16(u16 data) noexcept {
|
2019-04-12 01:26:37 +01:00
|
|
|
return __builtin_bswap16(data);
|
2016-09-18 01:38:01 +01:00
|
|
|
}
|
2019-04-12 01:42:40 +01:00
|
|
|
[[nodiscard]] inline u32 swap32(u32 data) noexcept {
|
2019-04-12 01:26:37 +01:00
|
|
|
return __builtin_bswap32(data);
|
2016-09-18 01:38:01 +01:00
|
|
|
}
|
2019-04-12 01:42:40 +01:00
|
|
|
[[nodiscard]] inline u64 swap64(u64 data) noexcept {
|
2019-04-12 01:26:37 +01:00
|
|
|
return __builtin_bswap64(data);
|
2016-09-18 01:38:01 +01:00
|
|
|
}
|
2015-03-06 06:46:45 +00:00
|
|
|
#else
|
common/swap: Improve codegen of the default swap fallbacks
Uses arithmetic that can be identified more trivially by compilers for
optimizations. e.g. Rather than shifting the halves of the value and
then swapping and combining them, we can swap them in place.
e.g. for the original swap32 code on x86-64, clang 8.0 would generate:
mov ecx, edi
rol cx, 8
shl ecx, 16
shr edi, 16
rol di, 8
movzx eax, di
or eax, ecx
ret
while GCC 8.3 would generate the ideal:
mov eax, edi
bswap eax
ret
now both generate the same optimal output.
MSVC used to generate the following with the old code:
mov eax, ecx
rol cx, 8
shr eax, 16
rol ax, 8
movzx ecx, cx
movzx eax, ax
shl ecx, 16
or eax, ecx
ret 0
Now MSVC also generates a similar, but equally optimal result as clang/GCC:
bswap ecx
mov eax, ecx
ret 0
====
In the swap64 case, for the original code, clang 8.0 would generate:
mov eax, edi
bswap eax
shl rax, 32
shr rdi, 32
bswap edi
or rax, rdi
ret
(almost there, but still missing the mark)
while, again, GCC 8.3 would generate the more ideal:
mov rax, rdi
bswap rax
ret
now clang also generates the optimal sequence for this fallback as well.
This is a case where MSVC unfortunately falls short, despite the new
code, this one still generates a doozy of an output.
mov r8, rcx
mov r9, rcx
mov rax, 71776119061217280
mov rdx, r8
and r9, rax
and edx, 65280
mov rax, rcx
shr rax, 16
or r9, rax
mov rax, rcx
shr r9, 16
mov rcx, 280375465082880
and rax, rcx
mov rcx, 1095216660480
or r9, rax
mov rax, r8
and rax, rcx
shr r9, 16
or r9, rax
mov rcx, r8
mov rax, r8
shr r9, 8
shl rax, 16
and ecx, 16711680
or rdx, rax
mov eax, -16777216
and rax, r8
shl rdx, 16
or rdx, rcx
shl rdx, 16
or rax, rdx
shl rax, 8
or rax, r9
ret 0
which is pretty unfortunate.
2019-04-12 02:20:22 +01:00
|
|
|
// Generic implementation.
|
2019-04-12 01:42:40 +01:00
|
|
|
[[nodiscard]] inline u16 swap16(u16 data) noexcept {
|
2016-09-18 01:38:01 +01:00
|
|
|
return (data >> 8) | (data << 8);
|
|
|
|
}
|
2019-04-12 01:42:40 +01:00
|
|
|
[[nodiscard]] inline u32 swap32(u32 data) noexcept {
|
common/swap: Improve codegen of the default swap fallbacks
Uses arithmetic that can be identified more trivially by compilers for
optimizations. e.g. Rather than shifting the halves of the value and
then swapping and combining them, we can swap them in place.
e.g. for the original swap32 code on x86-64, clang 8.0 would generate:
mov ecx, edi
rol cx, 8
shl ecx, 16
shr edi, 16
rol di, 8
movzx eax, di
or eax, ecx
ret
while GCC 8.3 would generate the ideal:
mov eax, edi
bswap eax
ret
now both generate the same optimal output.
MSVC used to generate the following with the old code:
mov eax, ecx
rol cx, 8
shr eax, 16
rol ax, 8
movzx ecx, cx
movzx eax, ax
shl ecx, 16
or eax, ecx
ret 0
Now MSVC also generates a similar, but equally optimal result as clang/GCC:
bswap ecx
mov eax, ecx
ret 0
====
In the swap64 case, for the original code, clang 8.0 would generate:
mov eax, edi
bswap eax
shl rax, 32
shr rdi, 32
bswap edi
or rax, rdi
ret
(almost there, but still missing the mark)
while, again, GCC 8.3 would generate the more ideal:
mov rax, rdi
bswap rax
ret
now clang also generates the optimal sequence for this fallback as well.
This is a case where MSVC unfortunately falls short, despite the new
code, this one still generates a doozy of an output.
mov r8, rcx
mov r9, rcx
mov rax, 71776119061217280
mov rdx, r8
and r9, rax
and edx, 65280
mov rax, rcx
shr rax, 16
or r9, rax
mov rax, rcx
shr r9, 16
mov rcx, 280375465082880
and rax, rcx
mov rcx, 1095216660480
or r9, rax
mov rax, r8
and rax, rcx
shr r9, 16
or r9, rax
mov rcx, r8
mov rax, r8
shr r9, 8
shl rax, 16
and ecx, 16711680
or rdx, rax
mov eax, -16777216
and rax, r8
shl rdx, 16
or rdx, rcx
shl rdx, 16
or rax, rdx
shl rax, 8
or rax, r9
ret 0
which is pretty unfortunate.
2019-04-12 02:20:22 +01:00
|
|
|
return ((data & 0xFF000000U) >> 24) | ((data & 0x00FF0000U) >> 8) |
|
|
|
|
((data & 0x0000FF00U) << 8) | ((data & 0x000000FFU) << 24);
|
2016-09-18 01:38:01 +01:00
|
|
|
}
|
2019-04-12 01:42:40 +01:00
|
|
|
[[nodiscard]] inline u64 swap64(u64 data) noexcept {
|
common/swap: Improve codegen of the default swap fallbacks
Uses arithmetic that can be identified more trivially by compilers for
optimizations. e.g. Rather than shifting the halves of the value and
then swapping and combining them, we can swap them in place.
e.g. for the original swap32 code on x86-64, clang 8.0 would generate:
mov ecx, edi
rol cx, 8
shl ecx, 16
shr edi, 16
rol di, 8
movzx eax, di
or eax, ecx
ret
while GCC 8.3 would generate the ideal:
mov eax, edi
bswap eax
ret
now both generate the same optimal output.
MSVC used to generate the following with the old code:
mov eax, ecx
rol cx, 8
shr eax, 16
rol ax, 8
movzx ecx, cx
movzx eax, ax
shl ecx, 16
or eax, ecx
ret 0
Now MSVC also generates a similar, but equally optimal result as clang/GCC:
bswap ecx
mov eax, ecx
ret 0
====
In the swap64 case, for the original code, clang 8.0 would generate:
mov eax, edi
bswap eax
shl rax, 32
shr rdi, 32
bswap edi
or rax, rdi
ret
(almost there, but still missing the mark)
while, again, GCC 8.3 would generate the more ideal:
mov rax, rdi
bswap rax
ret
now clang also generates the optimal sequence for this fallback as well.
This is a case where MSVC unfortunately falls short, despite the new
code, this one still generates a doozy of an output.
mov r8, rcx
mov r9, rcx
mov rax, 71776119061217280
mov rdx, r8
and r9, rax
and edx, 65280
mov rax, rcx
shr rax, 16
or r9, rax
mov rax, rcx
shr r9, 16
mov rcx, 280375465082880
and rax, rcx
mov rcx, 1095216660480
or r9, rax
mov rax, r8
and rax, rcx
shr r9, 16
or r9, rax
mov rcx, r8
mov rax, r8
shr r9, 8
shl rax, 16
and ecx, 16711680
or rdx, rax
mov eax, -16777216
and rax, r8
shl rdx, 16
or rdx, rcx
shl rdx, 16
or rax, rdx
shl rax, 8
or rax, r9
ret 0
which is pretty unfortunate.
2019-04-12 02:20:22 +01:00
|
|
|
return ((data & 0xFF00000000000000ULL) >> 56) | ((data & 0x00FF000000000000ULL) >> 40) |
|
|
|
|
((data & 0x0000FF0000000000ULL) >> 24) | ((data & 0x000000FF00000000ULL) >> 8) |
|
|
|
|
((data & 0x00000000FF000000ULL) << 8) | ((data & 0x0000000000FF0000ULL) << 24) |
|
|
|
|
((data & 0x000000000000FF00ULL) << 40) | ((data & 0x00000000000000FFULL) << 56);
|
2016-09-18 01:38:01 +01:00
|
|
|
}
|
2015-03-06 06:46:45 +00:00
|
|
|
#endif
|
|
|
|
|
2019-04-12 01:42:40 +01:00
|
|
|
[[nodiscard]] inline float swapf(float f) noexcept {
|
2016-09-18 01:38:01 +01:00
|
|
|
static_assert(sizeof(u32) == sizeof(float), "float must be the same size as uint32_t.");
|
2016-05-09 04:21:44 +01:00
|
|
|
|
|
|
|
u32 value;
|
|
|
|
std::memcpy(&value, &f, sizeof(u32));
|
2015-03-06 06:46:45 +00:00
|
|
|
|
2016-05-09 04:21:44 +01:00
|
|
|
value = swap32(value);
|
|
|
|
std::memcpy(&f, &value, sizeof(u32));
|
2015-03-06 06:46:45 +00:00
|
|
|
|
2016-05-09 04:21:44 +01:00
|
|
|
return f;
|
2015-03-06 06:46:45 +00:00
|
|
|
}
|
|
|
|
|
2019-04-12 01:42:40 +01:00
|
|
|
[[nodiscard]] inline double swapd(double f) noexcept {
|
2016-09-18 01:38:01 +01:00
|
|
|
static_assert(sizeof(u64) == sizeof(double), "double must be the same size as uint64_t.");
|
2016-05-09 04:21:44 +01:00
|
|
|
|
|
|
|
u64 value;
|
|
|
|
std::memcpy(&value, &f, sizeof(u64));
|
2015-03-06 06:46:45 +00:00
|
|
|
|
2016-05-09 04:21:44 +01:00
|
|
|
value = swap64(value);
|
|
|
|
std::memcpy(&f, &value, sizeof(u64));
|
2015-03-06 06:46:45 +00:00
|
|
|
|
2016-05-09 04:21:44 +01:00
|
|
|
return f;
|
2015-03-06 06:46:45 +00:00
|
|
|
}
|
|
|
|
|
2016-09-18 01:38:01 +01:00
|
|
|
} // Namespace Common
|
2015-03-06 06:46:45 +00:00
|
|
|
|
2013-09-19 04:26:13 +01:00
|
|
|
template <typename T, typename F>
|
|
|
|
struct swap_struct_t {
|
2018-07-19 14:32:13 +01:00
|
|
|
using swapped_t = swap_struct_t;
|
2013-09-19 04:26:13 +01:00
|
|
|
|
|
|
|
protected:
|
2019-01-25 17:16:00 +00:00
|
|
|
T value;
|
2013-09-19 04:26:13 +01:00
|
|
|
|
2014-04-01 23:20:08 +01:00
|
|
|
static T swap(T v) {
|
|
|
|
return F::swap(v);
|
|
|
|
}
|
2016-09-18 01:38:01 +01:00
|
|
|
|
2013-09-19 04:26:13 +01:00
|
|
|
public:
|
2018-07-19 14:35:50 +01:00
|
|
|
T swap() const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return swap(value);
|
|
|
|
}
|
2015-09-11 13:54:33 +01:00
|
|
|
swap_struct_t() = default;
|
2016-09-19 02:01:46 +01:00
|
|
|
swap_struct_t(const T& v) : value(swap(v)) {}
|
2014-04-01 23:20:08 +01:00
|
|
|
|
|
|
|
template <typename S>
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t& operator=(const S& source) {
|
2018-07-19 14:35:13 +01:00
|
|
|
value = swap(static_cast<T>(source));
|
2014-04-01 23:20:08 +01:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2016-09-18 01:38:01 +01:00
|
|
|
operator s8() const {
|
2018-07-19 14:35:13 +01:00
|
|
|
return static_cast<s8>(swap());
|
2016-09-18 01:38:01 +01:00
|
|
|
}
|
|
|
|
operator u8() const {
|
2018-07-19 14:35:13 +01:00
|
|
|
return static_cast<u8>(swap());
|
2016-09-18 01:38:01 +01:00
|
|
|
}
|
|
|
|
operator s16() const {
|
2018-07-19 14:35:13 +01:00
|
|
|
return static_cast<s16>(swap());
|
2016-09-18 01:38:01 +01:00
|
|
|
}
|
|
|
|
operator u16() const {
|
2018-07-19 14:35:13 +01:00
|
|
|
return static_cast<u16>(swap());
|
2016-09-18 01:38:01 +01:00
|
|
|
}
|
|
|
|
operator s32() const {
|
2018-07-19 14:35:13 +01:00
|
|
|
return static_cast<s32>(swap());
|
2016-09-18 01:38:01 +01:00
|
|
|
}
|
|
|
|
operator u32() const {
|
2018-07-19 14:35:13 +01:00
|
|
|
return static_cast<u32>(swap());
|
2016-09-18 01:38:01 +01:00
|
|
|
}
|
|
|
|
operator s64() const {
|
2018-07-19 14:35:13 +01:00
|
|
|
return static_cast<s64>(swap());
|
2016-09-18 01:38:01 +01:00
|
|
|
}
|
|
|
|
operator u64() const {
|
2018-07-19 14:35:13 +01:00
|
|
|
return static_cast<u64>(swap());
|
2016-09-18 01:38:01 +01:00
|
|
|
}
|
|
|
|
operator float() const {
|
2018-07-19 14:35:13 +01:00
|
|
|
return static_cast<float>(swap());
|
2016-09-18 01:38:01 +01:00
|
|
|
}
|
|
|
|
operator double() const {
|
2018-07-19 14:35:13 +01:00
|
|
|
return static_cast<double>(swap());
|
2016-09-18 01:38:01 +01:00
|
|
|
}
|
2014-04-01 23:20:08 +01:00
|
|
|
|
|
|
|
// +v
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t operator+() const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return +swap();
|
|
|
|
}
|
|
|
|
// -v
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t operator-() const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return -swap();
|
|
|
|
}
|
|
|
|
|
|
|
|
// v / 5
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t operator/(const swapped_t& i) const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return swap() / i.swap();
|
|
|
|
}
|
|
|
|
template <typename S>
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t operator/(const S& i) const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return swap() / i;
|
|
|
|
}
|
|
|
|
|
|
|
|
// v * 5
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t operator*(const swapped_t& i) const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return swap() * i.swap();
|
|
|
|
}
|
|
|
|
template <typename S>
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t operator*(const S& i) const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return swap() * i;
|
|
|
|
}
|
|
|
|
|
|
|
|
// v + 5
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t operator+(const swapped_t& i) const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return swap() + i.swap();
|
|
|
|
}
|
|
|
|
template <typename S>
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t operator+(const S& i) const {
|
2018-07-19 14:35:13 +01:00
|
|
|
return swap() + static_cast<T>(i);
|
2014-04-01 23:20:08 +01:00
|
|
|
}
|
|
|
|
// v - 5
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t operator-(const swapped_t& i) const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return swap() - i.swap();
|
|
|
|
}
|
|
|
|
template <typename S>
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t operator-(const S& i) const {
|
2018-07-19 14:35:13 +01:00
|
|
|
return swap() - static_cast<T>(i);
|
2014-04-01 23:20:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// v += 5
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t& operator+=(const swapped_t& i) {
|
2014-04-01 23:20:08 +01:00
|
|
|
value = swap(swap() + i.swap());
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
template <typename S>
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t& operator+=(const S& i) {
|
2018-07-19 14:35:13 +01:00
|
|
|
value = swap(swap() + static_cast<T>(i));
|
2014-04-01 23:20:08 +01:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
// v -= 5
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t& operator-=(const swapped_t& i) {
|
2014-04-01 23:20:08 +01:00
|
|
|
value = swap(swap() - i.swap());
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
template <typename S>
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t& operator-=(const S& i) {
|
2018-07-19 14:35:13 +01:00
|
|
|
value = swap(swap() - static_cast<T>(i));
|
2014-04-01 23:20:08 +01:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ++v
|
|
|
|
swapped_t& operator++() {
|
2016-09-18 01:38:01 +01:00
|
|
|
value = swap(swap() + 1);
|
2014-04-01 23:20:08 +01:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
// --v
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t& operator--() {
|
|
|
|
value = swap(swap() - 1);
|
2014-04-01 23:20:08 +01:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
// v++
|
|
|
|
swapped_t operator++(int) {
|
|
|
|
swapped_t old = *this;
|
2016-09-18 01:38:01 +01:00
|
|
|
value = swap(swap() + 1);
|
2014-04-01 23:20:08 +01:00
|
|
|
return old;
|
|
|
|
}
|
|
|
|
// v--
|
|
|
|
swapped_t operator--(int) {
|
|
|
|
swapped_t old = *this;
|
2016-09-18 01:38:01 +01:00
|
|
|
value = swap(swap() - 1);
|
2014-04-01 23:20:08 +01:00
|
|
|
return old;
|
|
|
|
}
|
|
|
|
// Comparaison
|
|
|
|
// v == i
|
2016-09-18 01:38:01 +01:00
|
|
|
bool operator==(const swapped_t& i) const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return swap() == i.swap();
|
|
|
|
}
|
|
|
|
template <typename S>
|
2016-09-18 01:38:01 +01:00
|
|
|
bool operator==(const S& i) const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return swap() == i;
|
|
|
|
}
|
|
|
|
|
|
|
|
// v != i
|
2016-09-18 01:38:01 +01:00
|
|
|
bool operator!=(const swapped_t& i) const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return swap() != i.swap();
|
|
|
|
}
|
|
|
|
template <typename S>
|
2016-09-18 01:38:01 +01:00
|
|
|
bool operator!=(const S& i) const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return swap() != i;
|
|
|
|
}
|
|
|
|
|
|
|
|
// v > i
|
2016-09-18 01:38:01 +01:00
|
|
|
bool operator>(const swapped_t& i) const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return swap() > i.swap();
|
|
|
|
}
|
|
|
|
template <typename S>
|
2016-09-18 01:38:01 +01:00
|
|
|
bool operator>(const S& i) const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return swap() > i;
|
|
|
|
}
|
|
|
|
|
|
|
|
// v < i
|
2016-09-18 01:38:01 +01:00
|
|
|
bool operator<(const swapped_t& i) const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return swap() < i.swap();
|
|
|
|
}
|
|
|
|
template <typename S>
|
2016-09-18 01:38:01 +01:00
|
|
|
bool operator<(const S& i) const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return swap() < i;
|
|
|
|
}
|
|
|
|
|
|
|
|
// v >= i
|
2016-09-18 01:38:01 +01:00
|
|
|
bool operator>=(const swapped_t& i) const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return swap() >= i.swap();
|
|
|
|
}
|
|
|
|
template <typename S>
|
2016-09-18 01:38:01 +01:00
|
|
|
bool operator>=(const S& i) const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return swap() >= i;
|
|
|
|
}
|
|
|
|
|
|
|
|
// v <= i
|
2016-09-18 01:38:01 +01:00
|
|
|
bool operator<=(const swapped_t& i) const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return swap() <= i.swap();
|
|
|
|
}
|
|
|
|
template <typename S>
|
2016-09-18 01:38:01 +01:00
|
|
|
bool operator<=(const S& i) const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return swap() <= i;
|
|
|
|
}
|
|
|
|
|
|
|
|
// logical
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t operator!() const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return !swap();
|
|
|
|
}
|
|
|
|
|
|
|
|
// bitmath
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t operator~() const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return ~swap();
|
|
|
|
}
|
|
|
|
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t operator&(const swapped_t& b) const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return swap() & b.swap();
|
|
|
|
}
|
|
|
|
template <typename S>
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t operator&(const S& b) const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return swap() & b;
|
|
|
|
}
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t& operator&=(const swapped_t& b) {
|
2014-04-01 23:20:08 +01:00
|
|
|
value = swap(swap() & b.swap());
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
template <typename S>
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t& operator&=(const S b) {
|
2014-04-01 23:20:08 +01:00
|
|
|
value = swap(swap() & b);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t operator|(const swapped_t& b) const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return swap() | b.swap();
|
|
|
|
}
|
|
|
|
template <typename S>
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t operator|(const S& b) const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return swap() | b;
|
|
|
|
}
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t& operator|=(const swapped_t& b) {
|
2014-04-01 23:20:08 +01:00
|
|
|
value = swap(swap() | b.swap());
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
template <typename S>
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t& operator|=(const S& b) {
|
2014-04-01 23:20:08 +01:00
|
|
|
value = swap(swap() | b);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t operator^(const swapped_t& b) const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return swap() ^ b.swap();
|
|
|
|
}
|
|
|
|
template <typename S>
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t operator^(const S& b) const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return swap() ^ b;
|
|
|
|
}
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t& operator^=(const swapped_t& b) {
|
2014-04-01 23:20:08 +01:00
|
|
|
value = swap(swap() ^ b.swap());
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
template <typename S>
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t& operator^=(const S& b) {
|
2014-04-01 23:20:08 +01:00
|
|
|
value = swap(swap() ^ b);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename S>
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t operator<<(const S& b) const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return swap() << b;
|
|
|
|
}
|
|
|
|
template <typename S>
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t& operator<<=(const S& b) const {
|
2014-04-01 23:20:08 +01:00
|
|
|
value = swap(swap() << b);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename S>
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t operator>>(const S& b) const {
|
2014-04-01 23:20:08 +01:00
|
|
|
return swap() >> b;
|
|
|
|
}
|
|
|
|
template <typename S>
|
2016-09-18 01:38:01 +01:00
|
|
|
swapped_t& operator>>=(const S& b) const {
|
2014-04-01 23:20:08 +01:00
|
|
|
value = swap(swap() >> b);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Member
|
|
|
|
/** todo **/
|
|
|
|
|
|
|
|
// Arithmetics
|
|
|
|
template <typename S, typename T2, typename F2>
|
2016-09-18 01:38:01 +01:00
|
|
|
friend S operator+(const S& p, const swapped_t v);
|
2014-04-01 23:20:08 +01:00
|
|
|
|
|
|
|
template <typename S, typename T2, typename F2>
|
2016-09-18 01:38:01 +01:00
|
|
|
friend S operator-(const S& p, const swapped_t v);
|
2014-04-01 23:20:08 +01:00
|
|
|
|
|
|
|
template <typename S, typename T2, typename F2>
|
2016-09-18 01:38:01 +01:00
|
|
|
friend S operator/(const S& p, const swapped_t v);
|
2014-04-01 23:20:08 +01:00
|
|
|
|
|
|
|
template <typename S, typename T2, typename F2>
|
2016-09-18 01:38:01 +01:00
|
|
|
friend S operator*(const S& p, const swapped_t v);
|
2014-04-01 23:20:08 +01:00
|
|
|
|
|
|
|
template <typename S, typename T2, typename F2>
|
2016-09-18 01:38:01 +01:00
|
|
|
friend S operator%(const S& p, const swapped_t v);
|
2014-04-01 23:20:08 +01:00
|
|
|
|
|
|
|
// Arithmetics + assignements
|
|
|
|
template <typename S, typename T2, typename F2>
|
2016-09-18 01:38:01 +01:00
|
|
|
friend S operator+=(const S& p, const swapped_t v);
|
2014-04-01 23:20:08 +01:00
|
|
|
|
|
|
|
template <typename S, typename T2, typename F2>
|
2016-09-18 01:38:01 +01:00
|
|
|
friend S operator-=(const S& p, const swapped_t v);
|
2014-04-01 23:20:08 +01:00
|
|
|
|
|
|
|
// Bitmath
|
|
|
|
template <typename S, typename T2, typename F2>
|
2016-09-18 01:38:01 +01:00
|
|
|
friend S operator&(const S& p, const swapped_t v);
|
2014-04-01 23:20:08 +01:00
|
|
|
|
|
|
|
// Comparison
|
|
|
|
template <typename S, typename T2, typename F2>
|
2016-09-18 01:38:01 +01:00
|
|
|
friend bool operator<(const S& p, const swapped_t v);
|
2014-04-01 23:20:08 +01:00
|
|
|
|
|
|
|
template <typename S, typename T2, typename F2>
|
2016-09-18 01:38:01 +01:00
|
|
|
friend bool operator>(const S& p, const swapped_t v);
|
2014-04-01 23:20:08 +01:00
|
|
|
|
|
|
|
template <typename S, typename T2, typename F2>
|
2016-09-18 01:38:01 +01:00
|
|
|
friend bool operator<=(const S& p, const swapped_t v);
|
2014-04-01 23:20:08 +01:00
|
|
|
|
|
|
|
template <typename S, typename T2, typename F2>
|
2016-09-18 01:38:01 +01:00
|
|
|
friend bool operator>=(const S& p, const swapped_t v);
|
2014-04-01 23:20:08 +01:00
|
|
|
|
|
|
|
template <typename S, typename T2, typename F2>
|
2016-09-18 01:38:01 +01:00
|
|
|
friend bool operator!=(const S& p, const swapped_t v);
|
2014-04-01 23:20:08 +01:00
|
|
|
|
|
|
|
template <typename S, typename T2, typename F2>
|
2016-09-18 01:38:01 +01:00
|
|
|
friend bool operator==(const S& p, const swapped_t v);
|
2013-09-19 04:26:13 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
// Arithmetics
|
|
|
|
template <typename S, typename T, typename F>
|
2016-09-18 01:38:01 +01:00
|
|
|
S operator+(const S& i, const swap_struct_t<T, F> v) {
|
2014-04-01 23:20:08 +01:00
|
|
|
return i + v.swap();
|
2013-09-19 04:26:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename S, typename T, typename F>
|
2016-09-18 01:38:01 +01:00
|
|
|
S operator-(const S& i, const swap_struct_t<T, F> v) {
|
2014-04-01 23:20:08 +01:00
|
|
|
return i - v.swap();
|
2013-09-19 04:26:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename S, typename T, typename F>
|
2016-09-18 01:38:01 +01:00
|
|
|
S operator/(const S& i, const swap_struct_t<T, F> v) {
|
2014-04-01 23:20:08 +01:00
|
|
|
return i / v.swap();
|
2013-09-19 04:26:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename S, typename T, typename F>
|
2016-09-18 01:38:01 +01:00
|
|
|
S operator*(const S& i, const swap_struct_t<T, F> v) {
|
2014-04-01 23:20:08 +01:00
|
|
|
return i * v.swap();
|
2013-09-19 04:26:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename S, typename T, typename F>
|
2016-09-18 01:38:01 +01:00
|
|
|
S operator%(const S& i, const swap_struct_t<T, F> v) {
|
2014-04-01 23:20:08 +01:00
|
|
|
return i % v.swap();
|
2013-09-19 04:26:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Arithmetics + assignements
|
|
|
|
template <typename S, typename T, typename F>
|
2016-09-18 01:38:01 +01:00
|
|
|
S& operator+=(S& i, const swap_struct_t<T, F> v) {
|
2014-04-01 23:20:08 +01:00
|
|
|
i += v.swap();
|
|
|
|
return i;
|
2013-09-19 04:26:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename S, typename T, typename F>
|
2016-09-18 01:38:01 +01:00
|
|
|
S& operator-=(S& i, const swap_struct_t<T, F> v) {
|
2014-04-01 23:20:08 +01:00
|
|
|
i -= v.swap();
|
|
|
|
return i;
|
2013-09-19 04:26:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Logical
|
|
|
|
template <typename S, typename T, typename F>
|
2016-09-18 01:38:01 +01:00
|
|
|
S operator&(const S& i, const swap_struct_t<T, F> v) {
|
2014-04-01 23:20:08 +01:00
|
|
|
return i & v.swap();
|
2013-09-19 04:26:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename S, typename T, typename F>
|
2016-09-18 01:38:01 +01:00
|
|
|
S operator&(const swap_struct_t<T, F> v, const S& i) {
|
2018-07-19 14:35:13 +01:00
|
|
|
return static_cast<S>(v.swap() & i);
|
2013-09-19 04:26:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Comparaison
|
|
|
|
template <typename S, typename T, typename F>
|
2016-09-18 01:38:01 +01:00
|
|
|
bool operator<(const S& p, const swap_struct_t<T, F> v) {
|
2014-04-01 23:20:08 +01:00
|
|
|
return p < v.swap();
|
2013-09-19 04:26:13 +01:00
|
|
|
}
|
|
|
|
template <typename S, typename T, typename F>
|
2016-09-18 01:38:01 +01:00
|
|
|
bool operator>(const S& p, const swap_struct_t<T, F> v) {
|
2014-04-01 23:20:08 +01:00
|
|
|
return p > v.swap();
|
2013-09-19 04:26:13 +01:00
|
|
|
}
|
|
|
|
template <typename S, typename T, typename F>
|
2016-09-18 01:38:01 +01:00
|
|
|
bool operator<=(const S& p, const swap_struct_t<T, F> v) {
|
2014-04-01 23:20:08 +01:00
|
|
|
return p <= v.swap();
|
2013-09-19 04:26:13 +01:00
|
|
|
}
|
|
|
|
template <typename S, typename T, typename F>
|
2016-09-18 01:38:01 +01:00
|
|
|
bool operator>=(const S& p, const swap_struct_t<T, F> v) {
|
2014-04-01 23:20:08 +01:00
|
|
|
return p >= v.swap();
|
2013-09-19 04:26:13 +01:00
|
|
|
}
|
|
|
|
template <typename S, typename T, typename F>
|
2016-09-18 01:38:01 +01:00
|
|
|
bool operator!=(const S& p, const swap_struct_t<T, F> v) {
|
2014-04-01 23:20:08 +01:00
|
|
|
return p != v.swap();
|
2013-09-19 04:26:13 +01:00
|
|
|
}
|
|
|
|
template <typename S, typename T, typename F>
|
2016-09-18 01:38:01 +01:00
|
|
|
bool operator==(const S& p, const swap_struct_t<T, F> v) {
|
2014-04-01 23:20:08 +01:00
|
|
|
return p == v.swap();
|
2013-09-19 04:26:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
struct swap_64_t {
|
2014-04-01 23:20:08 +01:00
|
|
|
static T swap(T x) {
|
2020-10-21 03:07:39 +01:00
|
|
|
return static_cast<T>(Common::swap64(x));
|
2014-04-01 23:20:08 +01:00
|
|
|
}
|
2013-09-19 04:26:13 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
struct swap_32_t {
|
2014-04-01 23:20:08 +01:00
|
|
|
static T swap(T x) {
|
2020-10-21 03:07:39 +01:00
|
|
|
return static_cast<T>(Common::swap32(x));
|
2014-04-01 23:20:08 +01:00
|
|
|
}
|
2013-09-19 04:26:13 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
struct swap_16_t {
|
2014-04-01 23:20:08 +01:00
|
|
|
static T swap(T x) {
|
2020-10-21 03:07:39 +01:00
|
|
|
return static_cast<T>(Common::swap16(x));
|
2014-04-01 23:20:08 +01:00
|
|
|
}
|
2013-09-19 04:26:13 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
struct swap_float_t {
|
2014-04-01 23:20:08 +01:00
|
|
|
static T swap(T x) {
|
2020-10-21 03:07:39 +01:00
|
|
|
return static_cast<T>(Common::swapf(x));
|
2014-04-01 23:20:08 +01:00
|
|
|
}
|
2013-09-19 04:26:13 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
struct swap_double_t {
|
2014-04-01 23:20:08 +01:00
|
|
|
static T swap(T x) {
|
2020-10-21 03:07:39 +01:00
|
|
|
return static_cast<T>(Common::swapd(x));
|
2014-04-01 23:20:08 +01:00
|
|
|
}
|
2013-09-19 04:26:13 +01:00
|
|
|
};
|
|
|
|
|
2018-09-22 00:53:14 +01:00
|
|
|
template <typename T>
|
|
|
|
struct swap_enum_t {
|
|
|
|
static_assert(std::is_enum_v<T>);
|
|
|
|
using base = std::underlying_type_t<T>;
|
|
|
|
|
|
|
|
public:
|
|
|
|
swap_enum_t() = default;
|
|
|
|
swap_enum_t(const T& v) : value(swap(v)) {}
|
|
|
|
|
|
|
|
swap_enum_t& operator=(const T& v) {
|
|
|
|
value = swap(v);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
operator T() const {
|
|
|
|
return swap(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
explicit operator base() const {
|
|
|
|
return static_cast<base>(swap(value));
|
|
|
|
}
|
2013-09-19 04:26:13 +01:00
|
|
|
|
2018-09-22 00:53:14 +01:00
|
|
|
protected:
|
|
|
|
T value{};
|
|
|
|
// clang-format off
|
|
|
|
using swap_t = std::conditional_t<
|
|
|
|
std::is_same_v<base, u16>, swap_16_t<u16>, std::conditional_t<
|
|
|
|
std::is_same_v<base, s16>, swap_16_t<s16>, std::conditional_t<
|
|
|
|
std::is_same_v<base, u32>, swap_32_t<u32>, std::conditional_t<
|
|
|
|
std::is_same_v<base, s32>, swap_32_t<s32>, std::conditional_t<
|
|
|
|
std::is_same_v<base, u64>, swap_64_t<u64>, std::conditional_t<
|
|
|
|
std::is_same_v<base, s64>, swap_64_t<s64>, void>>>>>>;
|
|
|
|
// clang-format on
|
|
|
|
static T swap(T x) {
|
|
|
|
return static_cast<T>(swap_t::swap(static_cast<base>(x)));
|
|
|
|
}
|
|
|
|
};
|
2013-09-19 04:26:13 +01:00
|
|
|
|
2019-01-25 17:09:12 +00:00
|
|
|
struct SwapTag {}; // Use the different endianness from the system
|
|
|
|
struct KeepTag {}; // Use the same endianness as the system
|
2013-09-19 04:26:13 +01:00
|
|
|
|
2019-01-25 17:09:12 +00:00
|
|
|
template <typename T, typename Tag>
|
|
|
|
struct AddEndian;
|
2013-09-19 04:26:13 +01:00
|
|
|
|
2019-01-25 17:09:12 +00:00
|
|
|
// KeepTag specializations
|
2013-09-19 04:26:13 +01:00
|
|
|
|
2018-09-22 00:53:14 +01:00
|
|
|
template <typename T>
|
2019-01-25 17:09:12 +00:00
|
|
|
struct AddEndian<T, KeepTag> {
|
|
|
|
using type = T;
|
|
|
|
};
|
2013-09-19 04:26:13 +01:00
|
|
|
|
2019-01-25 17:09:12 +00:00
|
|
|
// SwapTag specializations
|
2018-09-22 00:53:14 +01:00
|
|
|
|
2019-01-25 17:09:12 +00:00
|
|
|
template <>
|
|
|
|
struct AddEndian<u8, SwapTag> {
|
|
|
|
using type = u8;
|
|
|
|
};
|
2013-09-19 04:26:13 +01:00
|
|
|
|
2019-01-25 17:09:12 +00:00
|
|
|
template <>
|
|
|
|
struct AddEndian<u16, SwapTag> {
|
|
|
|
using type = swap_struct_t<u16, swap_16_t<u16>>;
|
|
|
|
};
|
2013-09-19 04:26:13 +01:00
|
|
|
|
2019-01-25 17:09:12 +00:00
|
|
|
template <>
|
|
|
|
struct AddEndian<u32, SwapTag> {
|
|
|
|
using type = swap_struct_t<u32, swap_32_t<u32>>;
|
|
|
|
};
|
2013-09-19 04:26:13 +01:00
|
|
|
|
2019-01-25 17:09:12 +00:00
|
|
|
template <>
|
|
|
|
struct AddEndian<u64, SwapTag> {
|
|
|
|
using type = swap_struct_t<u64, swap_64_t<u64>>;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <>
|
|
|
|
struct AddEndian<s8, SwapTag> {
|
|
|
|
using type = s8;
|
|
|
|
};
|
2013-09-19 04:26:13 +01:00
|
|
|
|
2019-01-25 17:09:12 +00:00
|
|
|
template <>
|
|
|
|
struct AddEndian<s16, SwapTag> {
|
|
|
|
using type = swap_struct_t<s16, swap_16_t<s16>>;
|
|
|
|
};
|
2013-09-19 04:26:13 +01:00
|
|
|
|
2019-01-25 17:09:12 +00:00
|
|
|
template <>
|
|
|
|
struct AddEndian<s32, SwapTag> {
|
|
|
|
using type = swap_struct_t<s32, swap_32_t<s32>>;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <>
|
|
|
|
struct AddEndian<s64, SwapTag> {
|
|
|
|
using type = swap_struct_t<s64, swap_64_t<s64>>;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <>
|
|
|
|
struct AddEndian<float, SwapTag> {
|
|
|
|
using type = swap_struct_t<float, swap_float_t<float>>;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <>
|
|
|
|
struct AddEndian<double, SwapTag> {
|
|
|
|
using type = swap_struct_t<double, swap_double_t<double>>;
|
|
|
|
};
|
2013-09-19 04:26:13 +01:00
|
|
|
|
2018-09-22 00:53:14 +01:00
|
|
|
template <typename T>
|
2019-01-25 17:09:12 +00:00
|
|
|
struct AddEndian<T, SwapTag> {
|
|
|
|
static_assert(std::is_enum_v<T>);
|
|
|
|
using type = swap_enum_t<T>;
|
|
|
|
};
|
2013-09-19 04:26:13 +01:00
|
|
|
|
2019-01-25 17:09:12 +00:00
|
|
|
// Alias LETag/BETag as KeepTag/SwapTag depending on the system
|
2020-07-14 21:21:35 +01:00
|
|
|
using LETag = std::conditional_t<std::endian::native == std::endian::little, KeepTag, SwapTag>;
|
|
|
|
using BETag = std::conditional_t<std::endian::native == std::endian::big, KeepTag, SwapTag>;
|
2013-09-19 04:26:13 +01:00
|
|
|
|
2019-01-25 17:09:12 +00:00
|
|
|
// Aliases for LE types
|
|
|
|
using u16_le = AddEndian<u16, LETag>::type;
|
|
|
|
using u32_le = AddEndian<u32, LETag>::type;
|
|
|
|
using u64_le = AddEndian<u64, LETag>::type;
|
|
|
|
|
|
|
|
using s16_le = AddEndian<s16, LETag>::type;
|
|
|
|
using s32_le = AddEndian<s32, LETag>::type;
|
|
|
|
using s64_le = AddEndian<s64, LETag>::type;
|
2013-09-19 04:26:13 +01:00
|
|
|
|
2018-09-22 00:53:14 +01:00
|
|
|
template <typename T>
|
2019-01-25 17:09:12 +00:00
|
|
|
using enum_le = std::enable_if_t<std::is_enum_v<T>, typename AddEndian<T, LETag>::type>;
|
2018-09-22 00:53:14 +01:00
|
|
|
|
2019-01-25 17:09:12 +00:00
|
|
|
using float_le = AddEndian<float, LETag>::type;
|
|
|
|
using double_le = AddEndian<double, LETag>::type;
|
2013-09-19 04:26:13 +01:00
|
|
|
|
2019-01-25 17:09:12 +00:00
|
|
|
// Aliases for BE types
|
|
|
|
using u16_be = AddEndian<u16, BETag>::type;
|
|
|
|
using u32_be = AddEndian<u32, BETag>::type;
|
|
|
|
using u64_be = AddEndian<u64, BETag>::type;
|
2013-09-19 04:26:13 +01:00
|
|
|
|
2019-01-25 17:09:12 +00:00
|
|
|
using s16_be = AddEndian<s16, BETag>::type;
|
|
|
|
using s32_be = AddEndian<s32, BETag>::type;
|
|
|
|
using s64_be = AddEndian<s64, BETag>::type;
|
2013-09-19 04:26:13 +01:00
|
|
|
|
2018-09-22 00:53:14 +01:00
|
|
|
template <typename T>
|
2019-01-25 17:09:12 +00:00
|
|
|
using enum_be = std::enable_if_t<std::is_enum_v<T>, typename AddEndian<T, BETag>::type>;
|
2015-03-06 06:46:45 +00:00
|
|
|
|
2019-01-25 17:09:12 +00:00
|
|
|
using float_be = AddEndian<float, BETag>::type;
|
|
|
|
using double_be = AddEndian<double, BETag>::type;
|