Merge pull request #4658 from lioncash/bits
Common: Add bit utility header
This commit is contained in:
commit
28f0d8e8a7
|
@ -0,0 +1,102 @@
|
||||||
|
// Copyright 2017 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <climits>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace Common
|
||||||
|
{
|
||||||
|
///
|
||||||
|
/// Retrieves the size of a type in bits.
|
||||||
|
///
|
||||||
|
/// @tparam T Type to get the size of.
|
||||||
|
///
|
||||||
|
/// @return the size of the type in bits.
|
||||||
|
///
|
||||||
|
template <typename T>
|
||||||
|
constexpr size_t BitSize() noexcept
|
||||||
|
{
|
||||||
|
return sizeof(T) * CHAR_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Extracts a bit from a value.
|
||||||
|
///
|
||||||
|
/// @param src The value to extract a bit from.
|
||||||
|
/// @param bit The bit to extract.
|
||||||
|
///
|
||||||
|
/// @tparam T The type of the value.
|
||||||
|
///
|
||||||
|
/// @return The extracted bit.
|
||||||
|
///
|
||||||
|
template <typename T>
|
||||||
|
constexpr T ExtractBit(const T src, const size_t bit) noexcept
|
||||||
|
{
|
||||||
|
return (src >> bit) & static_cast<T>(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Extracts a bit from a value.
|
||||||
|
///
|
||||||
|
/// @param src The value to extract a bit from.
|
||||||
|
///
|
||||||
|
/// @tparam bit The bit to extract.
|
||||||
|
/// @tparam T The type of the value.
|
||||||
|
///
|
||||||
|
/// @return The extracted bit.
|
||||||
|
///
|
||||||
|
template <size_t bit, typename T>
|
||||||
|
constexpr T ExtractBit(const T src) noexcept
|
||||||
|
{
|
||||||
|
static_assert(bit < BitSize<T>(), "Specified bit must be within T's bit width.");
|
||||||
|
|
||||||
|
return ExtractBit(src, bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Extracts a range of bits from a value.
|
||||||
|
///
|
||||||
|
/// @param src The value to extract the bits from.
|
||||||
|
/// @param begin The beginning of the bit range. This is inclusive.
|
||||||
|
/// @param end The ending of the bit range. This is inclusive.
|
||||||
|
///
|
||||||
|
/// @tparam T The type of the value.
|
||||||
|
/// @tparam Result The returned result type. This is the unsigned analog
|
||||||
|
/// of a signed type if a signed type is passed as T.
|
||||||
|
///
|
||||||
|
/// @return The extracted bits.
|
||||||
|
///
|
||||||
|
template <typename T, typename Result = std::make_unsigned_t<T>>
|
||||||
|
constexpr Result ExtractBits(const T src, const size_t begin, const size_t end) noexcept
|
||||||
|
{
|
||||||
|
return static_cast<Result>(((static_cast<Result>(src) << ((BitSize<T>() - 1) - end)) >>
|
||||||
|
(BitSize<T>() - end + begin - 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Extracts a range of bits from a value.
|
||||||
|
///
|
||||||
|
/// @param src The value to extract the bits from.
|
||||||
|
///
|
||||||
|
/// @tparam begin The beginning of the bit range. This is inclusive.
|
||||||
|
/// @tparam end The ending of the bit range. This is inclusive.
|
||||||
|
/// @tparam T The type of the value.
|
||||||
|
/// @tparam Result The returned result type. This is the unsigned analog
|
||||||
|
/// of a signed type if a signed type is passed as T.
|
||||||
|
///
|
||||||
|
/// @return The extracted bits.
|
||||||
|
///
|
||||||
|
template <size_t begin, size_t end, typename T, typename Result = std::make_unsigned_t<T>>
|
||||||
|
constexpr Result ExtractBits(const T src) noexcept
|
||||||
|
{
|
||||||
|
static_assert(begin < end, "Beginning bit must be less than the ending bit.");
|
||||||
|
static_assert(begin < BitSize<T>(), "Beginning bit is larger than T's bit width.");
|
||||||
|
static_assert(end < BitSize<T>(), "Ending bit is larger than T's bit width.");
|
||||||
|
|
||||||
|
return ExtractBits<T, Result>(src, begin, end);
|
||||||
|
}
|
||||||
|
} // namespace Common
|
|
@ -43,6 +43,7 @@
|
||||||
<ClInclude Include="Atomic_Win32.h" />
|
<ClInclude Include="Atomic_Win32.h" />
|
||||||
<ClInclude Include="BitField.h" />
|
<ClInclude Include="BitField.h" />
|
||||||
<ClInclude Include="BitSet.h" />
|
<ClInclude Include="BitSet.h" />
|
||||||
|
<ClInclude Include="BitUtils.h" />
|
||||||
<ClInclude Include="BlockingLoop.h" />
|
<ClInclude Include="BlockingLoop.h" />
|
||||||
<ClInclude Include="CDUtils.h" />
|
<ClInclude Include="CDUtils.h" />
|
||||||
<ClInclude Include="ChunkFile.h" />
|
<ClInclude Include="ChunkFile.h" />
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
<ClInclude Include="Atomic_Win32.h" />
|
<ClInclude Include="Atomic_Win32.h" />
|
||||||
<ClInclude Include="BitField.h" />
|
<ClInclude Include="BitField.h" />
|
||||||
<ClInclude Include="BitSet.h" />
|
<ClInclude Include="BitSet.h" />
|
||||||
|
<ClInclude Include="BitUtils.h" />
|
||||||
<ClInclude Include="BlockingLoop.h" />
|
<ClInclude Include="BlockingLoop.h" />
|
||||||
<ClInclude Include="CDUtils.h" />
|
<ClInclude Include="CDUtils.h" />
|
||||||
<ClInclude Include="ChunkFile.h" />
|
<ClInclude Include="ChunkFile.h" />
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
// Copyright 2017 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "Common/BitUtils.h"
|
||||||
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
|
TEST(BitUtils, BitSize)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(Common::BitSize<s8>(), 8);
|
||||||
|
EXPECT_EQ(Common::BitSize<s16>(), 16);
|
||||||
|
EXPECT_EQ(Common::BitSize<s32>(), 32);
|
||||||
|
EXPECT_EQ(Common::BitSize<s64>(), 64);
|
||||||
|
|
||||||
|
EXPECT_EQ(Common::BitSize<u8>(), 8);
|
||||||
|
EXPECT_EQ(Common::BitSize<u16>(), 16);
|
||||||
|
EXPECT_EQ(Common::BitSize<u32>(), 32);
|
||||||
|
EXPECT_EQ(Common::BitSize<u64>(), 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BitUtils, ExtractBit)
|
||||||
|
{
|
||||||
|
constexpr s32 zero = 0;
|
||||||
|
EXPECT_EQ(Common::ExtractBit<0>(zero), 0);
|
||||||
|
|
||||||
|
constexpr s32 one = 1;
|
||||||
|
EXPECT_EQ(Common::ExtractBit<0>(one), 1);
|
||||||
|
|
||||||
|
constexpr s32 negative_one = -1;
|
||||||
|
EXPECT_EQ(Common::ExtractBit<31>(negative_one), 1);
|
||||||
|
|
||||||
|
constexpr s32 one_hundred_twenty_eight = 0b10000000;
|
||||||
|
EXPECT_EQ(Common::ExtractBit<7>(one_hundred_twenty_eight), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BitUtils, ExtractBits)
|
||||||
|
{
|
||||||
|
// Note: Parenthesizing is necessary to prevent the macros from
|
||||||
|
// mangling the template function usages.
|
||||||
|
|
||||||
|
constexpr s32 two_hundred_four_signed = 0b0011001100;
|
||||||
|
EXPECT_EQ((Common::ExtractBits<2, 3>(two_hundred_four_signed)), 3);
|
||||||
|
EXPECT_EQ((Common::ExtractBits<2, 7>(two_hundred_four_signed)), 51);
|
||||||
|
EXPECT_EQ((Common::ExtractBits<3, 6>(two_hundred_four_signed)), 9);
|
||||||
|
|
||||||
|
constexpr u32 two_hundred_four_unsigned = 0b0011001100;
|
||||||
|
EXPECT_EQ((Common::ExtractBits<2, 3>(two_hundred_four_unsigned)), 3);
|
||||||
|
EXPECT_EQ((Common::ExtractBits<2, 7>(two_hundred_four_unsigned)), 51);
|
||||||
|
EXPECT_EQ((Common::ExtractBits<3, 6>(two_hundred_four_unsigned)), 9);
|
||||||
|
|
||||||
|
// Ensure bit extraction remains sign-independent even when signed types are used.
|
||||||
|
constexpr s32 negative_one = -1;
|
||||||
|
EXPECT_EQ((Common::ExtractBits<0, 31>(negative_one)), 0xFFFFFFFFU);
|
||||||
|
|
||||||
|
// Ensure bit extraction with type overriding works as expected
|
||||||
|
EXPECT_EQ((Common::ExtractBits<0, 31, s32, s32>(negative_one)), -1);
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
add_dolphin_test(BitFieldTest BitFieldTest.cpp)
|
add_dolphin_test(BitFieldTest BitFieldTest.cpp)
|
||||||
add_dolphin_test(BitSetTest BitSetTest.cpp)
|
add_dolphin_test(BitSetTest BitSetTest.cpp)
|
||||||
|
add_dolphin_test(BitUtilsTest BitUtilsTest.cpp)
|
||||||
add_dolphin_test(BlockingLoopTest BlockingLoopTest.cpp)
|
add_dolphin_test(BlockingLoopTest BlockingLoopTest.cpp)
|
||||||
add_dolphin_test(BusyLoopTest BusyLoopTest.cpp)
|
add_dolphin_test(BusyLoopTest BusyLoopTest.cpp)
|
||||||
add_dolphin_test(CommonFuncsTest CommonFuncsTest.cpp)
|
add_dolphin_test(CommonFuncsTest CommonFuncsTest.cpp)
|
||||||
|
|
Loading…
Reference in New Issue