mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	common/bitfield: make it endianness-aware
This commit is contained in:
		
							parent
							
								
									71530781f3
								
							
						
					
					
						commit
						6b81ceb060
					
				| @ -34,6 +34,7 @@ | ||||
| #include <limits> | ||||
| #include <type_traits> | ||||
| #include "common/common_funcs.h" | ||||
| #include "common/swap.h" | ||||
| 
 | ||||
| /*
 | ||||
|  * Abstract bitfield class | ||||
| @ -108,7 +109,7 @@ | ||||
|  * symptoms. | ||||
|  */ | ||||
| #pragma pack(1) | ||||
| template <std::size_t Position, std::size_t Bits, typename T> | ||||
| template <std::size_t Position, std::size_t Bits, typename T, typename EndianTag = LETag> | ||||
| struct BitField { | ||||
| private: | ||||
|     // We hide the copy assigment operator here, because the default copy
 | ||||
| @ -127,6 +128,8 @@ private: | ||||
|     // We store the value as the unsigned type to avoid undefined behaviour on value shifting
 | ||||
|     using StorageType = std::make_unsigned_t<UnderlyingType>; | ||||
| 
 | ||||
|     using StorageTypeWithEndian = typename AddEndian<StorageType, EndianTag>::type; | ||||
| 
 | ||||
| public: | ||||
|     /// Constants to allow limited introspection of fields if needed
 | ||||
|     static constexpr std::size_t position = Position; | ||||
| @ -172,7 +175,7 @@ public: | ||||
|     } | ||||
| 
 | ||||
|     constexpr FORCE_INLINE void Assign(const T& value) { | ||||
|         storage = (storage & ~mask) | FormatValue(value); | ||||
|         storage = (static_cast<StorageType>(storage) & ~mask) | FormatValue(value); | ||||
|     } | ||||
| 
 | ||||
|     constexpr T Value() const { | ||||
| @ -184,7 +187,7 @@ public: | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     StorageType storage; | ||||
|     StorageTypeWithEndian storage; | ||||
| 
 | ||||
|     static_assert(bits + position <= 8 * sizeof(T), "Bitfield out of range"); | ||||
| 
 | ||||
| @ -195,3 +198,6 @@ private: | ||||
|     static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable in a BitField"); | ||||
| }; | ||||
| #pragma pack() | ||||
| 
 | ||||
| template <std::size_t Position, std::size_t Bits, typename T> | ||||
| using BitFieldBE = BitField<Position, Bits, T, BETag>; | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| add_executable(tests | ||||
|     common/bit_field.cpp | ||||
|     common/param_package.cpp | ||||
|     common/ring_buffer.cpp | ||||
|     core/arm/arm_test_common.cpp | ||||
|  | ||||
							
								
								
									
										90
									
								
								src/tests/common/bit_field.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								src/tests/common/bit_field.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,90 @@ | ||||
| // Copyright 2019 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <array> | ||||
| #include <cstring> | ||||
| #include <type_traits> | ||||
| #include <catch2/catch.hpp> | ||||
| #include "common/bit_field.h" | ||||
| 
 | ||||
| TEST_CASE("BitField", "[common]") { | ||||
|     enum class TestEnum : u32 { | ||||
|         A = 0b10111101, | ||||
|         B = 0b10101110, | ||||
|         C = 0b00001111, | ||||
|     }; | ||||
| 
 | ||||
|     union LEBitField { | ||||
|         u32_le raw; | ||||
|         BitField<0, 6, u32> a; | ||||
|         BitField<6, 4, s32> b; | ||||
|         BitField<10, 8, TestEnum> c; | ||||
|         BitField<18, 14, u32> d; | ||||
|     } le_bitfield; | ||||
| 
 | ||||
|     union BEBitField { | ||||
|         u32_be raw; | ||||
|         BitFieldBE<0, 6, u32> a; | ||||
|         BitFieldBE<6, 4, s32> b; | ||||
|         BitFieldBE<10, 8, TestEnum> c; | ||||
|         BitFieldBE<18, 14, u32> d; | ||||
|     } be_bitfield; | ||||
| 
 | ||||
|     static_assert(sizeof(LEBitField) == sizeof(u32)); | ||||
|     static_assert(sizeof(BEBitField) == sizeof(u32)); | ||||
|     static_assert(std::is_trivially_copyable_v<LEBitField>); | ||||
|     static_assert(std::is_trivially_copyable_v<BEBitField>); | ||||
| 
 | ||||
|     std::array<u8, 4> raw{{ | ||||
|         0b01101100, | ||||
|         0b11110110, | ||||
|         0b10111010, | ||||
|         0b11101100, | ||||
|     }}; | ||||
| 
 | ||||
|     std::memcpy(&le_bitfield, &raw, sizeof(raw)); | ||||
|     std::memcpy(&be_bitfield, &raw, sizeof(raw)); | ||||
| 
 | ||||
|     // bit fields: 11101100101110'10111101'1001'101100
 | ||||
|     REQUIRE(le_bitfield.raw == 0b11101100'10111010'11110110'01101100); | ||||
|     REQUIRE(le_bitfield.a == 0b101100); | ||||
|     REQUIRE(le_bitfield.b == -7); // 1001 as two's complement
 | ||||
|     REQUIRE(le_bitfield.c == TestEnum::A); | ||||
|     REQUIRE(le_bitfield.d == 0b11101100101110); | ||||
| 
 | ||||
|     le_bitfield.a.Assign(0b000111); | ||||
|     le_bitfield.b.Assign(-1); | ||||
|     le_bitfield.c.Assign(TestEnum::C); | ||||
|     le_bitfield.d.Assign(0b01010101010101); | ||||
|     std::memcpy(&raw, &le_bitfield, sizeof(raw)); | ||||
|     // bit fields: 01010101010101'00001111'1111'000111
 | ||||
|     REQUIRE(le_bitfield.raw == 0b01010101'01010100'00111111'11000111); | ||||
|     REQUIRE(raw == std::array<u8, 4>{{ | ||||
|                        0b11000111, | ||||
|                        0b00111111, | ||||
|                        0b01010100, | ||||
|                        0b01010101, | ||||
|                    }}); | ||||
| 
 | ||||
|     // bit fields: 01101100111101'10101110'1011'101100
 | ||||
|     REQUIRE(be_bitfield.raw == 0b01101100'11110110'10111010'11101100); | ||||
|     REQUIRE(be_bitfield.a == 0b101100); | ||||
|     REQUIRE(be_bitfield.b == -5); // 1011 as two's complement
 | ||||
|     REQUIRE(be_bitfield.c == TestEnum::B); | ||||
|     REQUIRE(be_bitfield.d == 0b01101100111101); | ||||
| 
 | ||||
|     be_bitfield.a.Assign(0b000111); | ||||
|     be_bitfield.b.Assign(-1); | ||||
|     be_bitfield.c.Assign(TestEnum::C); | ||||
|     be_bitfield.d.Assign(0b01010101010101); | ||||
|     std::memcpy(&raw, &be_bitfield, sizeof(raw)); | ||||
|     // bit fields: 01010101010101'00001111'1111'000111
 | ||||
|     REQUIRE(be_bitfield.raw == 0b01010101'01010100'00111111'11000111); | ||||
|     REQUIRE(raw == std::array<u8, 4>{{ | ||||
|                        0b01010101, | ||||
|                        0b01010100, | ||||
|                        0b00111111, | ||||
|                        0b11000111, | ||||
|                    }}); | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Weiyi Wang
						Weiyi Wang