summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
authorGravatar bunnei2019-03-20 23:44:20 -0400
committerGravatar GitHub2019-03-20 23:44:20 -0400
commit3e930304fe6fb29a2421dd0fdfef6e66ebb213ad (patch)
tree3298c05a68692803d9124b919f7f3fe284d535c8 /src/common
parentMerge pull request #2262 from lioncash/enum (diff)
parentMake bitfield assignment operator public (diff)
downloadyuzu-3e930304fe6fb29a2421dd0fdfef6e66ebb213ad.tar.gz
yuzu-3e930304fe6fb29a2421dd0fdfef6e66ebb213ad.tar.xz
yuzu-3e930304fe6fb29a2421dd0fdfef6e66ebb213ad.zip
Merge pull request #2090 from FearlessTobi/port-4599
Port citra-emu/citra#4244 and citra-emu/citra#4599: Changes to BitField
Diffstat (limited to 'src/common')
-rw-r--r--src/common/bit_field.h14
-rw-r--r--src/common/swap.h174
2 files changed, 150 insertions, 38 deletions
diff --git a/src/common/bit_field.h b/src/common/bit_field.h
index 7433c39ba..8e35c463f 100644
--- a/src/common/bit_field.h
+++ b/src/common/bit_field.h
@@ -34,6 +34,7 @@
34#include <limits> 34#include <limits>
35#include <type_traits> 35#include <type_traits>
36#include "common/common_funcs.h" 36#include "common/common_funcs.h"
37#include "common/swap.h"
37 38
38/* 39/*
39 * Abstract bitfield class 40 * Abstract bitfield class
@@ -108,7 +109,7 @@
108 * symptoms. 109 * symptoms.
109 */ 110 */
110#pragma pack(1) 111#pragma pack(1)
111template <std::size_t Position, std::size_t Bits, typename T> 112template <std::size_t Position, std::size_t Bits, typename T, typename EndianTag = LETag>
112struct BitField { 113struct BitField {
113private: 114private:
114 // UnderlyingType is T for non-enum types and the underlying type of T if 115 // UnderlyingType is T for non-enum types and the underlying type of T if
@@ -121,7 +122,11 @@ private:
121 // We store the value as the unsigned type to avoid undefined behaviour on value shifting 122 // We store the value as the unsigned type to avoid undefined behaviour on value shifting
122 using StorageType = std::make_unsigned_t<UnderlyingType>; 123 using StorageType = std::make_unsigned_t<UnderlyingType>;
123 124
125 using StorageTypeWithEndian = typename AddEndian<StorageType, EndianTag>::type;
126
124public: 127public:
128 BitField& operator=(const BitField&) = default;
129
125 /// Constants to allow limited introspection of fields if needed 130 /// Constants to allow limited introspection of fields if needed
126 static constexpr std::size_t position = Position; 131 static constexpr std::size_t position = Position;
127 static constexpr std::size_t bits = Bits; 132 static constexpr std::size_t bits = Bits;
@@ -170,7 +175,7 @@ public:
170 } 175 }
171 176
172 constexpr FORCE_INLINE void Assign(const T& value) { 177 constexpr FORCE_INLINE void Assign(const T& value) {
173 storage = (storage & ~mask) | FormatValue(value); 178 storage = (static_cast<StorageType>(storage) & ~mask) | FormatValue(value);
174 } 179 }
175 180
176 constexpr T Value() const { 181 constexpr T Value() const {
@@ -182,7 +187,7 @@ public:
182 } 187 }
183 188
184private: 189private:
185 StorageType storage; 190 StorageTypeWithEndian storage;
186 191
187 static_assert(bits + position <= 8 * sizeof(T), "Bitfield out of range"); 192 static_assert(bits + position <= 8 * sizeof(T), "Bitfield out of range");
188 193
@@ -193,3 +198,6 @@ private:
193 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable in a BitField"); 198 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable in a BitField");
194}; 199};
195#pragma pack() 200#pragma pack()
201
202template <std::size_t Position, std::size_t Bits, typename T>
203using BitFieldBE = BitField<Position, Bits, T, BETag>;
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 @@
17 17
18#pragma once 18#pragma once
19 19
20#include <type_traits>
21
20#if defined(_MSC_VER) 22#if defined(_MSC_VER)
21#include <cstdlib> 23#include <cstdlib>
22#elif defined(__linux__) 24#elif defined(__linux__)
@@ -170,7 +172,7 @@ struct swap_struct_t {
170 using swapped_t = swap_struct_t; 172 using swapped_t = swap_struct_t;
171 173
172protected: 174protected:
173 T value = T(); 175 T value;
174 176
175 static T swap(T v) { 177 static T swap(T v) {
176 return F::swap(v); 178 return F::swap(v);
@@ -605,52 +607,154 @@ struct swap_double_t {
605 } 607 }
606}; 608};
607 609
608#if COMMON_LITTLE_ENDIAN 610template <typename T>
609using u16_le = u16; 611struct swap_enum_t {
610using u32_le = u32; 612 static_assert(std::is_enum_v<T>);
611using u64_le = u64; 613 using base = std::underlying_type_t<T>;
614
615public:
616 swap_enum_t() = default;
617 swap_enum_t(const T& v) : value(swap(v)) {}
618
619 swap_enum_t& operator=(const T& v) {
620 value = swap(v);
621 return *this;
622 }
623
624 operator T() const {
625 return swap(value);
626 }
627
628 explicit operator base() const {
629 return static_cast<base>(swap(value));
630 }
612 631
613using s16_le = s16; 632protected:
614using s32_le = s32; 633 T value{};
615using s64_le = s64; 634 // clang-format off
635 using swap_t = std::conditional_t<
636 std::is_same_v<base, u16>, swap_16_t<u16>, std::conditional_t<
637 std::is_same_v<base, s16>, swap_16_t<s16>, std::conditional_t<
638 std::is_same_v<base, u32>, swap_32_t<u32>, std::conditional_t<
639 std::is_same_v<base, s32>, swap_32_t<s32>, std::conditional_t<
640 std::is_same_v<base, u64>, swap_64_t<u64>, std::conditional_t<
641 std::is_same_v<base, s64>, swap_64_t<s64>, void>>>>>>;
642 // clang-format on
643 static T swap(T x) {
644 return static_cast<T>(swap_t::swap(static_cast<base>(x)));
645 }
646};
616 647
617using float_le = float; 648struct SwapTag {}; // Use the different endianness from the system
618using double_le = double; 649struct KeepTag {}; // Use the same endianness as the system
619 650
620using u64_be = swap_struct_t<u64, swap_64_t<u64>>; 651template <typename T, typename Tag>
621using s64_be = swap_struct_t<s64, swap_64_t<s64>>; 652struct AddEndian;
622 653
623using u32_be = swap_struct_t<u32, swap_32_t<u32>>; 654// KeepTag specializations
624using s32_be = swap_struct_t<s32, swap_32_t<s32>>;
625 655
626using u16_be = swap_struct_t<u16, swap_16_t<u16>>; 656template <typename T>
627using s16_be = swap_struct_t<s16, swap_16_t<s16>>; 657struct AddEndian<T, KeepTag> {
658 using type = T;
659};
628 660
629using float_be = swap_struct_t<float, swap_float_t<float>>; 661// SwapTag specializations
630using double_be = swap_struct_t<double, swap_double_t<double>>; 662
631#else 663template <>
664struct AddEndian<u8, SwapTag> {
665 using type = u8;
666};
667
668template <>
669struct AddEndian<u16, SwapTag> {
670 using type = swap_struct_t<u16, swap_16_t<u16>>;
671};
672
673template <>
674struct AddEndian<u32, SwapTag> {
675 using type = swap_struct_t<u32, swap_32_t<u32>>;
676};
632 677
633using u64_le = swap_struct_t<u64, swap_64_t<u64>>; 678template <>
634using s64_le = swap_struct_t<s64, swap_64_t<s64>>; 679struct AddEndian<u64, SwapTag> {
680 using type = swap_struct_t<u64, swap_64_t<u64>>;
681};
682
683template <>
684struct AddEndian<s8, SwapTag> {
685 using type = s8;
686};
635 687
636using u32_le = swap_struct_t<u32, swap_32_t<u32>>; 688template <>
637using s32_le = swap_struct_t<s32, swap_32_t<s32>>; 689struct AddEndian<s16, SwapTag> {
690 using type = swap_struct_t<s16, swap_16_t<s16>>;
691};
638 692
639using u16_le = swap_struct_t<u16, swap_16_t<u16>>; 693template <>
640using s16_le = swap_struct_t<s16, swap_16_t<s16>>; 694struct AddEndian<s32, SwapTag> {
695 using type = swap_struct_t<s32, swap_32_t<s32>>;
696};
697
698template <>
699struct AddEndian<s64, SwapTag> {
700 using type = swap_struct_t<s64, swap_64_t<s64>>;
701};
702
703template <>
704struct AddEndian<float, SwapTag> {
705 using type = swap_struct_t<float, swap_float_t<float>>;
706};
707
708template <>
709struct AddEndian<double, SwapTag> {
710 using type = swap_struct_t<double, swap_double_t<double>>;
711};
712
713template <typename T>
714struct AddEndian<T, SwapTag> {
715 static_assert(std::is_enum_v<T>);
716 using type = swap_enum_t<T>;
717};
641 718
642using float_le = swap_struct_t<float, swap_float_t<float>>; 719// Alias LETag/BETag as KeepTag/SwapTag depending on the system
643using double_le = swap_struct_t<double, swap_double_t<double>>; 720#if COMMON_LITTLE_ENDIAN
644 721
645using u16_be = u16; 722using LETag = KeepTag;
646using u32_be = u32; 723using BETag = SwapTag;
647using u64_be = u64;
648 724
649using s16_be = s16; 725#else
650using s32_be = s32;
651using s64_be = s64;
652 726
653using float_be = float; 727using BETag = KeepTag;
654using double_be = double; 728using LETag = SwapTag;
655 729
656#endif 730#endif
731
732// Aliases for LE types
733using u16_le = AddEndian<u16, LETag>::type;
734using u32_le = AddEndian<u32, LETag>::type;
735using u64_le = AddEndian<u64, LETag>::type;
736
737using s16_le = AddEndian<s16, LETag>::type;
738using s32_le = AddEndian<s32, LETag>::type;
739using s64_le = AddEndian<s64, LETag>::type;
740
741template <typename T>
742using enum_le = std::enable_if_t<std::is_enum_v<T>, typename AddEndian<T, LETag>::type>;
743
744using float_le = AddEndian<float, LETag>::type;
745using double_le = AddEndian<double, LETag>::type;
746
747// Aliases for BE types
748using u16_be = AddEndian<u16, BETag>::type;
749using u32_be = AddEndian<u32, BETag>::type;
750using u64_be = AddEndian<u64, BETag>::type;
751
752using s16_be = AddEndian<s16, BETag>::type;
753using s32_be = AddEndian<s32, BETag>::type;
754using s64_be = AddEndian<s64, BETag>::type;
755
756template <typename T>
757using enum_be = std::enable_if_t<std::is_enum_v<T>, typename AddEndian<T, BETag>::type>;
758
759using float_be = AddEndian<float, BETag>::type;
760using double_be = AddEndian<double, BETag>::type;