From f87dfd5b92ba76b7d2ee9b58b284b0b4fc2a25ed Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Tue, 9 Aug 2022 12:31:01 +0100 Subject: [PATCH] Optimised bitset shift operations --- include/etl/bitset.h | 51 ++++++++++++++++++++++++-------------------- test/test_bitset.cpp | 28 +++++++++++++++++------- 2 files changed, 48 insertions(+), 31 deletions(-) diff --git a/include/etl/bitset.h b/include/etl/bitset.h index 0b57fac9..65990fde 100644 --- a/include/etl/bitset.h +++ b/include/etl/bitset.h @@ -543,7 +543,7 @@ namespace etl pdata[i] = ~pdata[i]; } - pdata[Number_Of_Elements - 1U] &= Top_Mask; + adjust_top_bits(); return *this; } @@ -782,18 +782,14 @@ namespace etl } else if (shift == Bits_Per_Element) { - for (size_t i = (Number_Of_Elements - 1U); i > 0U; --i) - { - pdata[i] = pdata[i - 1]; - } - + etl::copy_backward(pdata, pdata + Number_Of_Elements - 1U, pdata + Number_Of_Elements); pdata[0] = 0; } else { // Where we are shifting from. - int src_index = int(Number_Of_Elements - (shift / Bits_Per_Element) - 1U); - size_t src_position = Bits_Per_Element - (shift % Bits_Per_Element); + int src_index = int(Number_Of_Elements - (shift / Bits_Per_Element) - 1U); + const size_t src_position = Bits_Per_Element - (shift % Bits_Per_Element); // Where we are shifting to. int dst_index = int(Number_Of_Elements - 1U); @@ -814,9 +810,12 @@ namespace etl // Now do the shifting. while (src_index >= 0) { + // Shift msb. element_t msb = element_t((pdata[src_index] & msb_mask) >> msb_shift); pdata[dst_index] = pdata[dst_index] | msb; --dst_index; + + // Shift lsb. element_t lsb = element_t((pdata[src_index] & lsb_mask) << lsb_shift); pdata[dst_index] = lsb; --src_index; @@ -836,7 +835,7 @@ namespace etl } // Truncate any bits shifted to the left. - pdata[Number_Of_Elements - 1U] &= Top_Mask; + adjust_top_bits(); } return *this; @@ -861,18 +860,14 @@ namespace etl // Shift is the size of an element? else if (shift == Bits_Per_Element) { - for (size_t i = 0UL; i < (Number_Of_Elements - 1U); ++i) - { - pdata[i] = pdata[i + 1]; - } - + etl::copy(pdata + 1, pdata + Number_Of_Elements, pdata); pdata[Number_Of_Elements - 1U] = 0; } else { // Where we are shifting from. - int src_index = int(shift / Bits_Per_Element); - size_t src_position = shift % Bits_Per_Element; + int src_index = int(shift / Bits_Per_Element); + const size_t src_position = shift % Bits_Per_Element; // Where we are shifting to. int dst_index = 0; @@ -891,8 +886,10 @@ namespace etl // Shift msb. element_t msb = element_t((pdata[src_index] & msb_mask) >> msb_shift); ++src_index; + // Shift lsb. element_t lsb = element_t((pdata[src_index] & lsb_mask) << lsb_shift); + // Combine them. pdata[dst_index] = lsb | msb; ++dst_index; @@ -969,10 +966,10 @@ namespace etl { reset(); - const size_t SHIFT = (integral_limits::bits <= (int)Bits_Per_Element) ? 0 : Bits_Per_Element; + const size_t Shift = (integral_limits::bits <= (int)Bits_Per_Element) ? 0 : Bits_Per_Element; // Can we do it in one hit? - if (SHIFT == 0) + if (Shift == 0) { pdata[0] = element_t(value); } @@ -983,11 +980,11 @@ namespace etl while ((value != 0) && (i < Number_Of_Elements)) { pdata[i++] = value & ALL_SET; - value = value >> SHIFT; + value = value >> Shift; } } - pdata[Number_Of_Elements - 1U] &= Top_Mask; + adjust_top_bits(); return *this; } @@ -1002,7 +999,7 @@ namespace etl pdata[i] = ~pdata[i]; } - pdata[Number_Of_Elements - 1U] &= Top_Mask; + adjust_top_bits(); } //************************************************************************* @@ -1021,8 +1018,8 @@ namespace etl , Number_Of_Elements(size_) , pdata(pdata_) { - size_t allocated_bits = Number_Of_Elements * Bits_Per_Element; - size_t top_mask_shift = ((Bits_Per_Element - (allocated_bits - Total_Bits)) % Bits_Per_Element); + const size_t allocated_bits = Number_Of_Elements * Bits_Per_Element; + const size_t top_mask_shift = ((Bits_Per_Element - (allocated_bits - Total_Bits)) % Bits_Per_Element); Top_Mask = element_t(top_mask_shift == 0 ? ALL_SET : ~(ALL_SET << top_mask_shift)); } @@ -1038,6 +1035,14 @@ namespace etl private: + //************************************************************************* + /// Correct the unused top bits after bit manipulation. + //************************************************************************* + void adjust_top_bits() + { + pdata[Number_Of_Elements - 1U] &= Top_Mask; + } + // Disable copy construction. ibitset(const ibitset&); diff --git a/test/test_bitset.cpp b/test/test_bitset.cpp index f7b06024..58be9f73 100644 --- a/test/test_bitset.cpp +++ b/test/test_bitset.cpp @@ -896,28 +896,34 @@ namespace //************************************************************************* TEST(test_shift_left_operator_all_shifts_full_size) { - constexpr uint64_t value = 0x01233456789ABCDEULL; + constexpr uint64_t value = 0x0123456789ABCDEFULL; - for (int shift = 0; shift <= 64; ++shift) + for (int shift = 0; shift < 64; ++shift) { etl::bitset<64> data(value); CHECK_EQUAL_HEX((value << shift), (data << shift).value()); } + + etl::bitset<64> data(value); + CHECK_EQUAL_HEX(0, (data << 64).value()); } //************************************************************************* TEST(test_shift_left_operator_all_shifts_partial_size) { - constexpr uint64_t value = 0x01233456789ABCDEULL; + constexpr uint64_t value = 0x0123456789ABCDEFULL; constexpr uint64_t mask = 0x0FFFFFFFFFFFFFFFULL; - for (int shift = 0; shift <= 64; ++shift) + for (int shift = 0; shift < 64; ++shift) { etl::bitset<60> data(value); CHECK_EQUAL_HEX(((value << shift) & mask), (data << shift).value()); } + + etl::bitset<64> data(value); + CHECK_EQUAL_HEX(0, (data << 64).value()); } //************************************************************************* @@ -945,28 +951,34 @@ namespace //************************************************************************* TEST(test_shift_right_operator_all_shifts_full_size) { - constexpr uint64_t value = 0x01233456789ABCDEULL; + constexpr uint64_t value = 0x0123456789ABCDEFULL; - for (int shift = 0; shift <= 64; ++shift) + for (int shift = 0; shift < 64; ++shift) { etl::bitset<64> data(value); CHECK_EQUAL_HEX((value >> shift), (data >> shift).value()); } + + etl::bitset<64> data(value); + CHECK_EQUAL_HEX(0, (data >> 64).value()); } //************************************************************************* TEST(test_shift_right_operator_all_shifts_partial_size) { - constexpr uint64_t value = 0x01233456789ABCDEULL; + constexpr uint64_t value = 0x0123456789ABCDEFULL; constexpr uint64_t mask = 0x0FFFFFFFFFFFFFFFULL; - for (int shift = 0; shift <= 64; ++shift) + for (int shift = 0; shift < 64; ++shift) { etl::bitset<60> data(value); CHECK_EQUAL_HEX(((value >> shift) & mask), (data >> shift).value()); } + + etl::bitset<64> data(value); + CHECK_EQUAL_HEX(0, (data >> 64).value()); } //*************************************************************************