From ecfbaec47e9551741260668ae59d41082fa716fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= <5415177+ZehMatt@users.noreply.github.com> Date: Mon, 13 Dec 2021 03:21:24 +0200 Subject: [PATCH] Cleanup and fix block size calculation --- src/openrct2/core/BitSet.hpp | 59 ++++++++++++++++++++++++------------ test/tests/BitSetTests.cpp | 18 ++++++----- 2 files changed, 49 insertions(+), 28 deletions(-) diff --git a/src/openrct2/core/BitSet.hpp b/src/openrct2/core/BitSet.hpp index 25d5eb1394..7b2c193293 100644 --- a/src/openrct2/core/BitSet.hpp +++ b/src/openrct2/core/BitSet.hpp @@ -31,15 +31,18 @@ namespace OpenRCT2 return v; return v + (byte_bits - (v % byte_bits)); } -#ifdef _DEBUG + static_assert(round_bits(1) == 8); static_assert(round_bits(4) == 8); static_assert(round_bits(8) == 8); static_assert(round_bits(9) == 16); -#endif + static_assert(round_bits(9) == 16); + static_assert(round_bits(17) == 24); + static_assert(round_bits(24) == 24); + static_assert(round_bits(31) == 32); // Returns the amount of bytes required for a single block. - static constexpr size_t storage_byte_size(size_t numBits) + static constexpr size_t storage_block_size(size_t numBits) { numBits = round_bits(numBits); if (numBits >= std::numeric_limits::digits) @@ -54,6 +57,17 @@ namespace OpenRCT2 return mask; } + static constexpr size_t storage_block_count(size_t numBits, size_t blockSize) + { + size_t numBlocks = 0; + while (numBits > 0) + { + numBlocks++; + numBits -= std::min(blockSize * byte_bits, numBits); + } + return numBlocks; + } + // TODO: Replace with std::popcount when C++20 is enabled. template static constexpr size_t popcount(const T val) { @@ -68,12 +82,15 @@ namespace OpenRCT2 return res; } -#ifdef _DEBUG - static_assert(storage_byte_size(1) == 1); - static_assert(storage_byte_size(4) == 1); - static_assert(storage_byte_size(8) == 1); - static_assert(storage_byte_size(9) == 2); -#endif + static_assert(storage_block_size(1) == sizeof(uint8_t)); + static_assert(storage_block_size(4) == sizeof(uint8_t)); + static_assert(storage_block_size(8) == sizeof(uint8_t)); + static_assert(storage_block_size(9) == sizeof(uint16_t)); + static_assert(storage_block_size(14) == sizeof(uint16_t)); + static_assert(storage_block_size(16) == sizeof(uint16_t)); + static_assert(storage_block_size(18) == sizeof(uint32_t)); + static_assert(storage_block_size(31) == sizeof(uint32_t)); + static_assert(storage_block_size(33) == sizeof(uintptr_t)); template struct storage_block_type; @@ -99,31 +116,33 @@ namespace OpenRCT2 template struct storage_block_type_aligned { - using value_type = typename storage_block_type::value_type; + using value_type = typename storage_block_type::value_type; }; } // namespace BitSet } // namespace Detail template class BitSet { - public: - static constexpr size_t storage_capacity_bits = Detail::BitSet::round_bits(TBitSize); - static constexpr size_t storage_capacity_bytes = storage_capacity_bits / Detail::BitSet::byte_bits; + static constexpr size_t byte_aligned_bitsize = Detail::BitSet::round_bits(TBitSize); - using storage_block_type = typename Detail::BitSet::storage_block_type_aligned::value_type; + using storage_block_type = typename Detail::BitSet::storage_block_type_aligned::value_type; + + static constexpr size_t block_byte_size = sizeof(storage_block_type); + static constexpr size_t block_type_bit_size = block_byte_size * Detail::BitSet::byte_bits; + static constexpr size_t block_count = Detail::BitSet::storage_block_count(byte_aligned_bitsize, block_byte_size); + static constexpr size_t capacity_bits = block_count * block_type_bit_size; static constexpr storage_block_type value_zero = storage_block_type{ 0u }; static constexpr storage_block_type value_one = storage_block_type{ 1u }; - static constexpr size_t block_type_bit_size = sizeof(storage_block_type) * Detail::BitSet::byte_bits; - static constexpr size_t block_count = storage_capacity_bits / block_type_bit_size; - static constexpr storage_block_type block_init_value{}; static constexpr storage_block_type block_mask_value = static_cast(~block_init_value); - static constexpr bool requires_trim = TBitSize != storage_capacity_bits; + static constexpr bool requires_trim = byte_aligned_bitsize != capacity_bits; - using storage_data = std::array; + public: + using block_type = storage_block_type; + using storage_data = std::array; // Proxy object to access the bits as single value. template class reference_base @@ -272,7 +291,7 @@ namespace OpenRCT2 constexpr size_t capacity() const noexcept { - return storage_capacity_bits; + return capacity_bits; } constexpr storage_data& data() noexcept diff --git a/test/tests/BitSetTests.cpp b/test/tests/BitSetTests.cpp index b978338780..33700ec0ea 100644 --- a/test/tests/BitSetTests.cpp +++ b/test/tests/BitSetTests.cpp @@ -16,9 +16,9 @@ TEST(BitTest, test_index_construction) { BitSet<64u> bits({ 0u, 2u, 4u, 6u, 8u, 10u }); #ifdef _M_X64 - static_assert(std::is_same_v); + static_assert(std::is_same_v); #else - static_assert(std::is_same_v); + static_assert(std::is_same_v); #endif constexpr auto size = sizeof(bits); static_assert(size == 8u); @@ -30,7 +30,7 @@ TEST(BitTest, test_index_construction) TEST(BitTest, test_basic) { BitSet<8u> bits; - static_assert(std::is_same_v); + static_assert(std::is_same_v); constexpr auto size = sizeof(bits); static_assert(size == sizeof(uint8_t)); @@ -49,7 +49,7 @@ TEST(BitTest, test_basic) TEST(BitTest, test_flip) { BitSet<8u> bits; - static_assert(std::is_same_v); + static_assert(std::is_same_v); constexpr auto size = sizeof(bits); static_assert(size == sizeof(uint8_t)); @@ -62,7 +62,7 @@ TEST(BitTest, test_flip) TEST(BitTest, test_trim8) { BitSet<5u> bits; - static_assert(std::is_same_v); + static_assert(std::is_same_v); constexpr auto size = sizeof(bits); static_assert(size == sizeof(uint8_t)); @@ -76,7 +76,7 @@ TEST(BitTest, test_trim8) TEST(BitTest, test_trim16) { BitSet<14u> bits; - static_assert(std::is_same_v); + static_assert(std::is_same_v); constexpr auto size = sizeof(bits); static_assert(size == sizeof(uint16_t)); @@ -95,13 +95,15 @@ TEST(BitTest, test_big) bits.flip(); #ifdef _M_X64 - static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(bits.data().size() == 4); ASSERT_EQ(bits.data()[0], ~0ULL); ASSERT_EQ(bits.data()[1], ~0ULL); ASSERT_EQ(bits.data()[2], ~0ULL); ASSERT_EQ(bits.data()[3], ~0ULL); #else - static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(bits.data().size() ==); ASSERT_EQ(bits.data()[0], ~0UL); ASSERT_EQ(bits.data()[1], ~0UL); ASSERT_EQ(bits.data()[2], ~0UL);