summaryrefslogtreecommitdiffstats
path: root/src/common/swap.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/common/swap.h174
1 files changed, 139 insertions, 35 deletions
diff --git a/src/common/swap.h b/src/common/swap.h
index 0e219747f..b3eab1324 100644
--- a/src/common/swap.h
+++ b/src/common/swap.h
@@ -17,6 +17,8 @@
#pragma once
+#include <type_traits>
+
#if defined(_MSC_VER)
#include <cstdlib>
#elif defined(__linux__)
@@ -170,7 +172,7 @@ struct swap_struct_t {
using swapped_t = swap_struct_t;
protected:
- T value = T();
+ T value;
static T swap(T v) {
return F::swap(v);
@@ -605,52 +607,154 @@ struct swap_double_t {
}
};
-#if COMMON_LITTLE_ENDIAN
-using u16_le = u16;
-using u32_le = u32;
-using u64_le = u64;
+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));
+ }
-using s16_le = s16;
-using s32_le = s32;
-using s64_le = s64;
+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)));
+ }
+};
-using float_le = float;
-using double_le = double;
+struct SwapTag {}; // Use the different endianness from the system
+struct KeepTag {}; // Use the same endianness as the system
-using u64_be = swap_struct_t<u64, swap_64_t<u64>>;
-using s64_be = swap_struct_t<s64, swap_64_t<s64>>;
+template <typename T, typename Tag>
+struct AddEndian;
-using u32_be = swap_struct_t<u32, swap_32_t<u32>>;
-using s32_be = swap_struct_t<s32, swap_32_t<s32>>;
+// KeepTag specializations
-using u16_be = swap_struct_t<u16, swap_16_t<u16>>;
-using s16_be = swap_struct_t<s16, swap_16_t<s16>>;
+template <typename T>
+struct AddEndian<T, KeepTag> {
+ using type = T;
+};
-using float_be = swap_struct_t<float, swap_float_t<float>>;
-using double_be = swap_struct_t<double, swap_double_t<double>>;
-#else
+// SwapTag specializations
+
+template <>
+struct AddEndian<u8, SwapTag> {
+ using type = u8;
+};
+
+template <>
+struct AddEndian<u16, SwapTag> {
+ using type = swap_struct_t<u16, swap_16_t<u16>>;
+};
+
+template <>
+struct AddEndian<u32, SwapTag> {
+ using type = swap_struct_t<u32, swap_32_t<u32>>;
+};
-using u64_le = swap_struct_t<u64, swap_64_t<u64>>;
-using s64_le = swap_struct_t<s64, swap_64_t<s64>>;
+template <>
+struct AddEndian<u64, SwapTag> {
+ using type = swap_struct_t<u64, swap_64_t<u64>>;
+};
+
+template <>
+struct AddEndian<s8, SwapTag> {
+ using type = s8;
+};
-using u32_le = swap_struct_t<u32, swap_32_t<u32>>;
-using s32_le = swap_struct_t<s32, swap_32_t<s32>>;
+template <>
+struct AddEndian<s16, SwapTag> {
+ using type = swap_struct_t<s16, swap_16_t<s16>>;
+};
-using u16_le = swap_struct_t<u16, swap_16_t<u16>>;
-using s16_le = swap_struct_t<s16, swap_16_t<s16>>;
+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>>;
+};
+
+template <typename T>
+struct AddEndian<T, SwapTag> {
+ static_assert(std::is_enum_v<T>);
+ using type = swap_enum_t<T>;
+};
-using float_le = swap_struct_t<float, swap_float_t<float>>;
-using double_le = swap_struct_t<double, swap_double_t<double>>;
+// Alias LETag/BETag as KeepTag/SwapTag depending on the system
+#if COMMON_LITTLE_ENDIAN
-using u16_be = u16;
-using u32_be = u32;
-using u64_be = u64;
+using LETag = KeepTag;
+using BETag = SwapTag;
-using s16_be = s16;
-using s32_be = s32;
-using s64_be = s64;
+#else
-using float_be = float;
-using double_be = double;
+using BETag = KeepTag;
+using LETag = SwapTag;
#endif
+
+// 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;
+
+template <typename T>
+using enum_le = std::enable_if_t<std::is_enum_v<T>, typename AddEndian<T, LETag>::type>;
+
+using float_le = AddEndian<float, LETag>::type;
+using double_le = AddEndian<double, LETag>::type;
+
+// 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;
+
+using s16_be = AddEndian<s16, BETag>::type;
+using s32_be = AddEndian<s32, BETag>::type;
+using s64_be = AddEndian<s64, BETag>::type;
+
+template <typename T>
+using enum_be = std::enable_if_t<std::is_enum_v<T>, typename AddEndian<T, BETag>::type>;
+
+using float_be = AddEndian<float, BETag>::type;
+using double_be = AddEndian<double, BETag>::type;