Commit cfc21345 by Jamie Madill Committed by Commit Bot

Add first() and last() to BitSetArray.

These helper functions return the bounds of the 1 bits in the array. Also required implementing ScanReverse the same way we implemented ScanForward. Bug: angleproject:5736 Change-Id: Ied945c57cd85ca7bc91dcc7a1168a74b3a59fce4 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2842347Reviewed-by: 's avatarMohan Maiya <m.maiya@samsung.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCharlie Lao <cclao@google.com> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 6297ccf3
......@@ -92,6 +92,7 @@ class BitSetT final
};
using value_type = BitsT;
using param_type = ParamT;
constexpr BitSetT();
constexpr explicit BitSetT(BitsT value);
......@@ -492,6 +493,9 @@ class BitSetArray final
BitSetArray();
BitSetArray(const BitSetArray<N> &other);
using value_type = BaseBitSet::value_type;
using param_type = BaseBitSet::param_type;
class Reference final
{
public:
......@@ -660,8 +664,10 @@ class BitSetArray final
std::size_t count() const;
bool intersects(const BitSetArray &other) const;
BitSetArray<N> &flip();
param_type first() const;
param_type last() const;
BaseBitSet::value_type bits(size_t index) const;
value_type bits(size_t index) const;
private:
static constexpr std::size_t kDefaultBitSetSizeMinusOne = priv::kDefaultBitSetSize - 1;
......@@ -965,7 +971,7 @@ bool BitSetArray<N>::intersects(const BitSetArray<N> &other) const
{
for (std::size_t index = 0; index < kArraySize; index++)
{
if (mBaseBitSetArray[index].bits() & other.mBaseBitSetArray[index].bits())
if ((mBaseBitSetArray[index].bits() & other.mBaseBitSetArray[index].bits()) != 0)
{
return true;
}
......@@ -987,7 +993,39 @@ BitSetArray<N> &BitSetArray<N>::flip()
}
template <std::size_t N>
typename BitSetArray<N>::BaseBitSet::value_type BitSetArray<N>::bits(size_t index) const
typename BitSetArray<N>::param_type BitSetArray<N>::first() const
{
ASSERT(any());
for (size_t arrayIndex = 0; arrayIndex < kArraySize; ++arrayIndex)
{
const BaseBitSet &baseBitSet = mBaseBitSetArray[arrayIndex];
if (baseBitSet.any())
{
return baseBitSet.first() + arrayIndex * priv::kDefaultBitSetSize;
}
}
UNREACHABLE();
return 0;
}
template <std::size_t N>
typename BitSetArray<N>::param_type BitSetArray<N>::last() const
{
ASSERT(any());
for (size_t arrayIndex = kArraySize; arrayIndex > 0; --arrayIndex)
{
const BaseBitSet &baseBitSet = mBaseBitSetArray[arrayIndex - 1];
if (baseBitSet.any())
{
return baseBitSet.last() + (arrayIndex - 1) * priv::kDefaultBitSetSize;
}
}
UNREACHABLE();
return 0;
}
template <std::size_t N>
typename BitSetArray<N>::value_type BitSetArray<N>::bits(size_t index) const
{
return mBaseBitSetArray[index].bits();
}
......
......@@ -411,6 +411,10 @@ TYPED_TEST(BitSetArrayTest, BasicTest)
{
EXPECT_EQ(bit, 45u);
}
EXPECT_EQ(mBits.first(), 45u);
EXPECT_EQ(mBits.last(), 45u);
mBits.reset(45);
// Set every bit to 1.
......@@ -521,6 +525,12 @@ TYPED_TEST(BitSetArrayTest, BasicTest)
testBitSet2.set(bit);
}
EXPECT_EQ(testBitSet1.first(), 0u);
EXPECT_EQ(testBitSet1.last(), 60u);
EXPECT_EQ(testBitSet2.first(), 5u);
EXPECT_EQ(testBitSet2.last(), 63u);
actualValues.clear();
for (auto bit : (testBitSet1 & testBitSet2))
{
......
......@@ -1128,6 +1128,39 @@ inline unsigned long ScanForward(uint64_t bits)
ASSERT(ret != 0u);
return firstBitIndex;
}
// Return the index of the most significant bit set. Indexing is such that bit 0 is the least
// significant bit.
inline unsigned long ScanReverse(uint32_t bits)
{
ASSERT(bits != 0u);
unsigned long lastBitIndex = 0ul;
unsigned char ret = _BitScanReverse(&lastBitIndex, bits);
ASSERT(ret != 0u);
return lastBitIndex;
}
inline unsigned long ScanReverse(uint64_t bits)
{
ASSERT(bits != 0u);
unsigned long lastBitIndex = 0ul;
# if defined(ANGLE_IS_64_BIT_CPU)
unsigned char ret = _BitScanReverse64(&lastBitIndex, bits);
# else
unsigned char ret;
if (static_cast<uint32_t>(bits >> 32) == 0)
{
ret = _BitScanReverse(&lastBitIndex, static_cast<uint32_t>(bits));
}
else
{
ret = _BitScanReverse(&lastBitIndex, static_cast<uint32_t>(bits >> 32));
lastBitIndex += 32ul;
}
# endif // defined(ANGLE_IS_64_BIT_CPU)
ASSERT(ret != 0u);
return lastBitIndex;
}
#endif // defined(ANGLE_PLATFORM_WINDOWS)
#if defined(ANGLE_PLATFORM_POSIX)
......@@ -1148,6 +1181,25 @@ inline unsigned long ScanForward(uint64_t bits)
: __builtin_ctz(static_cast<uint32_t>(bits)));
# endif // defined(ANGLE_IS_64_BIT_CPU)
}
inline unsigned long ScanReverse(uint32_t bits)
{
ASSERT(bits != 0u);
return static_cast<unsigned long>(sizeof(uint32_t) * CHAR_BIT - 1 - __builtin_clz(bits));
}
inline unsigned long ScanReverse(uint64_t bits)
{
ASSERT(bits != 0u);
# if defined(ANGLE_IS_64_BIT_CPU)
return static_cast<unsigned long>(sizeof(uint64_t) * CHAR_BIT - 1 - __builtin_clzll(bits));
# else
int tempResult = static_cast<uint32_t>(bits >> 32) == 0
? __builtin_clzll(static_cast<int32_t>(bits))
: (__builtin_clzll(static_cast<int32_t>(bits >> 32)) + 32);
return static_cast<unsigned long>(sizeof(uint64_t) * CHAR_BIT - 1 - tempResult);
# endif // defined(ANGLE_IS_64_BIT_CPU)
}
#endif // defined(ANGLE_PLATFORM_POSIX)
inline unsigned long ScanForward(uint8_t bits)
......@@ -1160,21 +1212,14 @@ inline unsigned long ScanForward(uint16_t bits)
return ScanForward(static_cast<uint32_t>(bits));
}
// Return the index of the most significant bit set. Indexing is such that bit 0 is the least
// significant bit.
inline unsigned long ScanReverse(unsigned long bits)
inline unsigned long ScanReverse(uint8_t bits)
{
ASSERT(bits != 0u);
#if defined(ANGLE_PLATFORM_WINDOWS)
unsigned long lastBitIndex = 0ul;
unsigned char ret = _BitScanReverse(&lastBitIndex, bits);
ASSERT(ret != 0u);
return lastBitIndex;
#elif defined(ANGLE_PLATFORM_POSIX)
return static_cast<unsigned long>(sizeof(unsigned long) * CHAR_BIT - 1 - __builtin_clzl(bits));
#else
# error Please implement bit-scan-reverse for your platform!
#endif
return ScanReverse(static_cast<uint32_t>(bits));
}
inline unsigned long ScanReverse(uint16_t bits)
{
return ScanReverse(static_cast<uint32_t>(bits));
}
// Returns -1 on 0, otherwise the index of the least significant 1 bit as in GLSL.
......
......@@ -294,9 +294,13 @@ TEST(MathUtilTest, ScanForward)
// Test ScanReverse, which scans for the most significant 1 bit from a non-zero integer.
TEST(MathUtilTest, ScanReverse)
{
EXPECT_EQ(0ul, gl::ScanReverse(1ul));
EXPECT_EQ(16ul, gl::ScanReverse(0x00010030ul));
EXPECT_EQ(31ul, gl::ScanReverse(0x80000000ul));
EXPECT_EQ(0ul, gl::ScanReverse(1u));
EXPECT_EQ(16ul, gl::ScanReverse(static_cast<uint64_t>(0x00010030ull)));
EXPECT_EQ(31ul, gl::ScanReverse(static_cast<uint64_t>(0x80000000ull)));
EXPECT_EQ(32ul, gl::ScanReverse(static_cast<uint64_t>(0x100000000ull)));
EXPECT_EQ(48ul, gl::ScanReverse(static_cast<uint64_t>(0x0001080000000000ull)));
EXPECT_EQ(63ul, gl::ScanReverse(static_cast<uint64_t>(0x8000000000000000ull)));
}
// Test FindLSB, which finds the least significant 1 bit.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment