mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-14 13:27:45 -07:00
BitUtils: Add C++14/C++17 compatible equivalent of std::bit_cast from C++2a
Given bit conversions between types are quite common in emulation (particularly when it comes to floating-point among other things) it makes sense to provide a utility function that keeps all the boilerplate contained; especially considering it makes it harder to accidentally misuse std::memcpy (such as accidentally transposing arguments, etc). Another benefit of this function is that it doesn't require separating declarations from assignments, allowing variables to be declared const. This makes the scenario of of uninitialized variables being used less likely to occur.
This commit is contained in:
parent
fd1ea63383
commit
b3292298c9
@ -6,6 +6,7 @@
|
||||
|
||||
#include <climits>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
|
||||
namespace Common
|
||||
@ -165,4 +166,37 @@ constexpr bool IsValidLowMask(const T mask) noexcept
|
||||
// and doesn't require special casing either edge case.
|
||||
return (mask & (mask + 1)) == 0;
|
||||
}
|
||||
|
||||
///
|
||||
/// Reinterpret objects of one type as another by bit-casting between object representations.
|
||||
///
|
||||
/// @remark This is the example implementation of std::bit_cast which is to be included
|
||||
/// in C++2a. See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0476r2.html
|
||||
/// for more details. The only difference is this variant is not constexpr,
|
||||
/// as the mechanism for bit_cast requires a compiler built-in to have that quality.
|
||||
///
|
||||
/// @param source The source object to convert to another representation.
|
||||
///
|
||||
/// @tparam To The type to reinterpret source as.
|
||||
/// @tparam From The initial type representation of source.
|
||||
///
|
||||
/// @return The representation of type From as type To.
|
||||
///
|
||||
/// @pre Both To and From types must be the same size
|
||||
/// @pre Both To and From types must satisfy the TriviallyCopyable concept.
|
||||
///
|
||||
template <typename To, typename From>
|
||||
inline To BitCast(const From& source) noexcept
|
||||
{
|
||||
static_assert(sizeof(From) == sizeof(To),
|
||||
"BitCast source and destination types must be equal in size.");
|
||||
static_assert(std::is_trivially_copyable<From>(),
|
||||
"BitCast source type must be trivially copyable.");
|
||||
static_assert(std::is_trivially_copyable<To>(),
|
||||
"BitCast destination type must be trivially copyable.");
|
||||
|
||||
std::aligned_storage_t<sizeof(To), alignof(To)> storage;
|
||||
std::memcpy(&storage, &source, sizeof(storage));
|
||||
return reinterpret_cast<To&>(storage);
|
||||
}
|
||||
} // namespace Common
|
||||
|
@ -127,3 +127,16 @@ TEST(BitUtils, IsValidLowMask)
|
||||
EXPECT_FALSE(Common::IsValidLowMask((u64) ~(0b10000)));
|
||||
EXPECT_FALSE(Common::IsValidLowMask((u64)(~((u64)(~0b0) >> 1) | 0b1111)));
|
||||
}
|
||||
|
||||
TEST(BitUtils, BitCast)
|
||||
{
|
||||
EXPECT_EQ(0x00000000U, Common::BitCast<u32>(0.0f));
|
||||
EXPECT_EQ(0x80000000U, Common::BitCast<u32>(-0.0f));
|
||||
EXPECT_EQ(0x3F800000U, Common::BitCast<u32>(1.0f));
|
||||
EXPECT_EQ(0xBF800000U, Common::BitCast<u32>(-1.0f));
|
||||
|
||||
EXPECT_EQ(0x0000000000000000ULL, Common::BitCast<u64>(0.0));
|
||||
EXPECT_EQ(0x8000000000000000ULL, Common::BitCast<u64>(-0.0));
|
||||
EXPECT_EQ(0x3FF0000000000000ULL, Common::BitCast<u64>(1.0));
|
||||
EXPECT_EQ(0xBFF0000000000000ULL, Common::BitCast<u64>(-1.0));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user