From 9064eecee2b11e2faab861856dd6d3497f1d9405 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sat, 2 Dec 2023 17:46:38 +0000 Subject: [PATCH] Work in progress for etl::bitset::extract --- include/etl/private/bitset_new.h | 148 ++++++++++-------- test/test_bitset_new_default_element_type.cpp | 77 +++++++++ test/vs2022/etl.vcxproj.filters | 32 +++- 3 files changed, 182 insertions(+), 75 deletions(-) diff --git a/include/etl/private/bitset_new.h b/include/etl/private/bitset_new.h index 4dbfbef8..65128c75 100644 --- a/include/etl/private/bitset_new.h +++ b/include/etl/private/bitset_new.h @@ -401,12 +401,62 @@ namespace etl return v; } + //************************************************************************* + /// Extract an value from multiple elements. + //************************************************************************* + template + ETL_CONSTEXPR14 + typename etl::make_unsigned::type extract_from_multiple_elements(const element_type* pbuffer, + int element_index, + size_t active_bits_in_msb, + size_t length) const ETL_NOEXCEPT + { + typedef typename etl::make_unsigned::type unsigned_t; + + unsigned_t value(0); + + // Extract the first element, if partially filled. + if (active_bits_in_msb < Bits_Per_Element) + { + element_type mask = ~(~element_type(0) << active_bits_in_msb); + value = pbuffer[element_index] & mask; + length -= active_bits_in_msb; + if (length >= Bits_Per_Element) + { + value = value << Bits_Per_Element; + } + --element_index; + } + + // Loop through the fully filled elements + while (length >= Bits_Per_Element) + { + value |= pbuffer[element_index]; + length -= Bits_Per_Element; + if (length >= Bits_Per_Element) + { + value = value << Bits_Per_Element; + } + --element_index; + } + + // Extract the last element, if partially filled. + if (length != 0) + { + value = value << length; + element_type mask = ~(~element_type(0) << length); + value |= (pbuffer[element_index] >> (Bits_Per_Element - length)) & mask; + } + + return value; + } + //************************************************************************* /// Extract an integral value from an arbitary position and length. //************************************************************************* template ETL_CONSTEXPR14 - T extract_from_buffer(const_pointer pbuffer, size_t position, size_t length) const ETL_NOEXCEPT + typename etl::make_unsigned::type extract_from_buffer(const_pointer pbuffer, size_t position, size_t length) const ETL_NOEXCEPT { typedef typename etl::make_unsigned::type unsigned_t; @@ -428,37 +478,13 @@ namespace etl // Get the number of active bits in the msb element size_t active_bits_in_msb = (position + length) - (Msb_Element_Index * Bits_Per_Element); - // Extract the first element if partially filled. // Start with index of the element containing the msb. int element_index = Msb_Element_Index; - if (active_bits_in_msb < Bits_Per_Element) - { - element_type mask = ~(~element_type(0) << active_bits_in_msb); - value |= pbuffer[element_index] & mask; - length -= active_bits_in_msb; - --element_index; - } - - // Loop through the fully filled elements - while (length >= Bits_Per_Element) - { - value <<= Bits_Per_Element; - value |= pbuffer[element_index]; - length -= Bits_Per_Element; - --element_index; - } - - // Check if the last element is partially filled and extract. - if (length != 0) - { - value <<= length; - element_type mask = ~(~element_type(0) << length); - value |= (pbuffer[element_index] >> (Bits_Per_Element - length)) & mask; - } + value = extract_from_multiple_elements(pbuffer, element_index, active_bits_in_msb, length); } - return static_cast(value); + return value; } //************************************************************************* @@ -466,7 +492,7 @@ namespace etl //************************************************************************* template ETL_CONSTEXPR14 - typename etl::enable_if::value, T>::type + typename etl::enable_if::value, typename etl::make_unsigned::type>::type extract_from_buffer(const_pointer pbuffer) const { typedef typename etl::make_unsigned::type unsigned_t; @@ -475,9 +501,7 @@ namespace etl const unsigned_t Mask = ~(~0 << Length); const unsigned_t Shift = Position % Bits_Per_Element; - unsigned_t value = static_cast(pbuffer[Element_Index] >> Shift) & Mask; - - return static_cast(value); + return static_cast(pbuffer[Element_Index] >> Shift) & Mask; } //************************************************************************* @@ -485,13 +509,11 @@ namespace etl //************************************************************************* template ETL_CONSTEXPR14 - typename etl::enable_if::value, T>::type + typename etl::enable_if::value, typename etl::make_unsigned::type>::type extract_from_buffer(const_pointer pbuffer) const { typedef typename etl::make_unsigned::type unsigned_t; - - unsigned_t value(0); - + const int Msb_Element_Index = (Position + Length - 1) >> etl::log2::value; // Start with index of the element containing the msb. @@ -501,35 +523,9 @@ namespace etl size_t length = Length; // Get the number of active bits in the first element - size_t active_bits_in_element = ((Position + Length - 1) % Bits_Per_Element) + 1; + size_t active_bits_in_msb = ((Position + Length - 1) % Bits_Per_Element) + 1; - // Extract the first element if partially filled. - if (active_bits_in_element < Bits_Per_Element) - { - element_type mask = ~(~element_type(0) << active_bits_in_element); - value |= pbuffer[element_index] & mask; - length -= active_bits_in_element; - --element_index; - } - - // Loop through the fully filled elements - while (length >= Bits_Per_Element) - { - value <<= Bits_Per_Element; - value |= pbuffer[element_index]; - length -= Bits_Per_Element; - --element_index; - } - - // Check if the last element is partially filled and extract. - if (length != 0) - { - value <<= length; - element_type mask = ~(~element_type(0) << length); - value |= (pbuffer[element_index] >> (Bits_Per_Element - length)) & mask; - } - - return static_cast(value); + return extract_from_multiple_elements(pbuffer, element_index, active_bits_in_msb, length); } //************************************************************************* @@ -2208,7 +2204,16 @@ namespace etl { ETL_ASSERT_OR_RETURN_VALUE((position + length) <= Active_Bits, ETL_ERROR(bitset_overflow), 0); - return ibitset.extract_from_buffer(buffer, position, length); + typedef typename etl::make_unsigned::type unsigned_t; + + unsigned_t value = ibitset.template extract_from_buffer(buffer, position, length);; + + if ((length != etl::integral_limits::bits) && etl::integral_limits::is_signed) + { + value = etl::sign_extend(value, length); + } + + return value; } //************************************************************************* @@ -2221,7 +2226,16 @@ namespace etl { ETL_STATIC_ASSERT((Position + Length) <= Active_Bits, "Position/Length overflows bitset"); - return ibitset.extract_from_buffer(buffer); + typedef typename etl::make_unsigned::type unsigned_t; + + unsigned_t value = ibitset.template extract_from_buffer(buffer); + + if ETL_IF_CONSTEXPR((Length != etl::integral_limits::bits) && etl::integral_limits::is_signed) + { + value = etl::sign_extend(value); + } + + return value; } //************************************************************************* @@ -3981,7 +3995,7 @@ namespace etl { ETL_ASSERT_OR_RETURN_VALUE((position + length) <= Active_Bits, ETL_ERROR(bitset_overflow), 0); - return ibitset.extract_from_buffer(pbuffer, position, length); + return ibitset.template extract_from_buffer(pbuffer, position, length); } //************************************************************************* @@ -3994,7 +4008,7 @@ namespace etl { ETL_STATIC_ASSERT((Position + Length) <= Active_Bits, "Position/Length overflows bitset"); - return ibitset.extract_from_buffer(pbuffer); + return ibitset.template extract_from_buffer(pbuffer); } //************************************************************************* diff --git a/test/test_bitset_new_default_element_type.cpp b/test/test_bitset_new_default_element_type.cpp index 199e18a0..a0980425 100644 --- a/test/test_bitset_new_default_element_type.cpp +++ b/test/test_bitset_new_default_element_type.cpp @@ -2172,6 +2172,83 @@ namespace //uint8_t v1 = b.extract(); } + //************************************************************************* + TEST(test_extract_6_bit_int8_t_with_run_time_parameters) + { + ETL_CONSTEXPR14 etl::bitset<32> b(0x12345678UL); + + auto v = b.extract(1, 6); + + CHECK_EQUAL_HEX(int8_t(0xF8), (b.extract(0, 6))); + CHECK_EQUAL_HEX(int8_t(0xFC), (b.extract(1, 6))); + CHECK_EQUAL_HEX(int8_t(0x1E), (b.extract(2, 6))); + CHECK_EQUAL_HEX(int8_t(0x0F), (b.extract(3, 6))); + CHECK_EQUAL_HEX(int8_t(0xE7), (b.extract(4, 6))); + CHECK_EQUAL_HEX(int8_t(0xF3), (b.extract(5, 6))); + CHECK_EQUAL_HEX(int8_t(0x19), (b.extract(6, 6))); + CHECK_EQUAL_HEX(int8_t(0xEC), (b.extract(7, 6))); + CHECK_EQUAL_HEX(int8_t(0x16), (b.extract(8, 6))); + CHECK_EQUAL_HEX(int8_t(0xEB), (b.extract(9, 6))); + CHECK_EQUAL_HEX(int8_t(0x15), (b.extract(10, 6))); + CHECK_EQUAL_HEX(int8_t(0x0A), (b.extract(11, 6))); + CHECK_EQUAL_HEX(int8_t(0x05), (b.extract(12, 6))); + CHECK_EQUAL_HEX(int8_t(0xE2), (b.extract(13, 6))); + CHECK_EQUAL_HEX(int8_t(0x11), (b.extract(14, 6))); + CHECK_EQUAL_HEX(int8_t(0xE8), (b.extract(15, 6))); + CHECK_EQUAL_HEX(int8_t(0xF4), (b.extract(16, 6))); + CHECK_EQUAL_HEX(int8_t(0x1A), (b.extract(17, 6))); + CHECK_EQUAL_HEX(int8_t(0x0D), (b.extract(18, 6))); + CHECK_EQUAL_HEX(int8_t(0x06), (b.extract(19, 6))); + CHECK_EQUAL_HEX(int8_t(0xE3), (b.extract(20, 6))); + CHECK_EQUAL_HEX(int8_t(0x11), (b.extract(21, 6))); + CHECK_EQUAL_HEX(int8_t(0x08), (b.extract(22, 6))); + CHECK_EQUAL_HEX(int8_t(0xE4), (b.extract(23, 6))); + CHECK_EQUAL_HEX(int8_t(0x12), (b.extract(24, 6))); + CHECK_EQUAL_HEX(int8_t(0x09), (b.extract(25, 6))); + CHECK_EQUAL_HEX(int8_t(0x04), (b.extract(26, 6))); + + CHECK_THROW(b.extract(26, 7), etl::bitset_overflow); + CHECK_THROW(b.extract(27, 6), etl::bitset_overflow); + } + + //************************************************************************* + TEST(test_extract_6_bit_int8_t_with_template_parameters) + { + ETL_CONSTEXPR14 etl::bitset<32> b(0x12345678UL); + + CHECK_EQUAL_HEX(int8_t(0xF8), (b.extract())); + CHECK_EQUAL_HEX(int8_t(0xFC), (b.extract())); + CHECK_EQUAL_HEX(int8_t(0x1E), (b.extract())); + CHECK_EQUAL_HEX(int8_t(0x0F), (b.extract())); + CHECK_EQUAL_HEX(int8_t(0xE7), (b.extract())); + CHECK_EQUAL_HEX(int8_t(0xF3), (b.extract())); + CHECK_EQUAL_HEX(int8_t(0x19), (b.extract())); + CHECK_EQUAL_HEX(int8_t(0xEC), (b.extract())); + CHECK_EQUAL_HEX(int8_t(0x16), (b.extract())); + CHECK_EQUAL_HEX(int8_t(0xEB), (b.extract())); + CHECK_EQUAL_HEX(int8_t(0x15), (b.extract())); + CHECK_EQUAL_HEX(int8_t(0x0A), (b.extract())); + CHECK_EQUAL_HEX(int8_t(0x05), (b.extract())); + CHECK_EQUAL_HEX(int8_t(0xE2), (b.extract())); + CHECK_EQUAL_HEX(int8_t(0x11), (b.extract())); + CHECK_EQUAL_HEX(int8_t(0xE8), (b.extract())); + CHECK_EQUAL_HEX(int8_t(0xF4), (b.extract())); + CHECK_EQUAL_HEX(int8_t(0x1A), (b.extract())); + CHECK_EQUAL_HEX(int8_t(0x0D), (b.extract())); + CHECK_EQUAL_HEX(int8_t(0x06), (b.extract())); + CHECK_EQUAL_HEX(int8_t(0xE3), (b.extract())); + CHECK_EQUAL_HEX(int8_t(0x11), (b.extract())); + CHECK_EQUAL_HEX(int8_t(0x08), (b.extract())); + CHECK_EQUAL_HEX(int8_t(0xE4), (b.extract())); + CHECK_EQUAL_HEX(int8_t(0x12), (b.extract())); + CHECK_EQUAL_HEX(int8_t(0x09), (b.extract())); + CHECK_EQUAL_HEX(int8_t(0x04), (b.extract())); + + // The lines below should static assert. + //int8_t v1 = b.extract(); + //int8_t v1 = b.extract(); + } + //************************************************************************* TEST(test_extract_uint8_t_with_run_time_parameters) { diff --git a/test/vs2022/etl.vcxproj.filters b/test/vs2022/etl.vcxproj.filters index cea19458..5430cd00 100644 --- a/test/vs2022/etl.vcxproj.filters +++ b/test/vs2022/etl.vcxproj.filters @@ -3400,14 +3400,30 @@ Tests\Scripts - - - - - - - - + + Resource Files\CI\Github + + + Resource Files\CI\Github + + + Resource Files\CI\Github + + + Resource Files\CI\Github + + + Resource Files\CI\Github + + + Resource Files\CI\Github + + + Resource Files\CI\Github + + + Resource Files\CI\Github +