Work in progress for etl::bitset::extract

This commit is contained in:
John Wellbelove 2023-12-02 17:46:38 +00:00
parent 3d3f87564d
commit 18a1c76ec6
4 changed files with 183 additions and 76 deletions

View File

@ -401,12 +401,62 @@ namespace etl
return v;
}
//*************************************************************************
/// Extract an value from multiple elements.
//*************************************************************************
template <typename T>
ETL_CONSTEXPR14
typename etl::make_unsigned<T>::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<T>::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 <typename T>
ETL_CONSTEXPR14
T extract_from_buffer(const_pointer pbuffer, size_t position, size_t length) const ETL_NOEXCEPT
typename etl::make_unsigned<T>::type extract_from_buffer(const_pointer pbuffer, size_t position, size_t length) const ETL_NOEXCEPT
{
typedef typename etl::make_unsigned<T>::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<T>(pbuffer, element_index, active_bits_in_msb, length);
}
return static_cast<T>(value);
return value;
}
//*************************************************************************
@ -466,7 +492,7 @@ namespace etl
//*************************************************************************
template <typename T, size_t Position, size_t Length>
ETL_CONSTEXPR14
typename etl::enable_if<value_is_in_one_element<Position, Length, Bits_Per_Element>::value, T>::type
typename etl::enable_if<value_is_in_one_element<Position, Length, Bits_Per_Element>::value, typename etl::make_unsigned<T>::type>::type
extract_from_buffer(const_pointer pbuffer) const
{
typedef typename etl::make_unsigned<T>::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<unsigned_t>(pbuffer[Element_Index] >> Shift) & Mask;
return static_cast<T>(value);
return static_cast<unsigned_t>(pbuffer[Element_Index] >> Shift) & Mask;
}
//*************************************************************************
@ -485,13 +509,11 @@ namespace etl
//*************************************************************************
template <typename T, size_t Position, size_t Length>
ETL_CONSTEXPR14
typename etl::enable_if<!value_is_in_one_element<Position, Length, Bits_Per_Element>::value, T>::type
typename etl::enable_if<!value_is_in_one_element<Position, Length, Bits_Per_Element>::value, typename etl::make_unsigned<T>::type>::type
extract_from_buffer(const_pointer pbuffer) const
{
typedef typename etl::make_unsigned<T>::type unsigned_t;
unsigned_t value(0);
const int Msb_Element_Index = (Position + Length - 1) >> etl::log2<Bits_Per_Element>::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<T>(value);
return extract_from_multiple_elements<T>(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<T>(buffer, position, length);
typedef typename etl::make_unsigned<T>::type unsigned_t;
unsigned_t value = ibitset.template extract_from_buffer<T>(buffer, position, length);;
if ((length != etl::integral_limits<T>::bits) && etl::integral_limits<T>::is_signed)
{
value = etl::sign_extend<T>(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<T, Position, Length>(buffer);
typedef typename etl::make_unsigned<T>::type unsigned_t;
unsigned_t value = ibitset.template extract_from_buffer<T, Position, Length>(buffer);
if ETL_IF_CONSTEXPR((Length != etl::integral_limits<T>::bits) && etl::integral_limits<T>::is_signed)
{
value = etl::sign_extend<T, Length>(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<T>(pbuffer, position, length);
return ibitset.template extract_from_buffer<T>(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<T, Position, Length>(pbuffer);
return ibitset.template extract_from_buffer<T, Position, Length>(pbuffer);
}
//*************************************************************************

View File

@ -165,7 +165,7 @@ etl_version=$(echo $etl_version_raw | sed -e 's/\r//g') # Remove trailing \r
# Get the compiler versions
#******************************************************************************
gcc_compiler=$(g++ --version | grep g++)
clang_compiler=$(clang++ --version | grep clang++)
clang_compiler=$(clang++ --version | grep clang)
#******************************************************************************
# GCC

View File

@ -2172,6 +2172,83 @@ namespace
//uint8_t v1 = b.extract<uint8_t, 27, 6>();
}
//*************************************************************************
TEST(test_extract_6_bit_int8_t_with_run_time_parameters)
{
ETL_CONSTEXPR14 etl::bitset<32> b(0x12345678UL);
auto v = b.extract<int8_t>(1, 6);
CHECK_EQUAL_HEX(int8_t(0xF8), (b.extract<int8_t>(0, 6)));
CHECK_EQUAL_HEX(int8_t(0xFC), (b.extract<int8_t>(1, 6)));
CHECK_EQUAL_HEX(int8_t(0x1E), (b.extract<int8_t>(2, 6)));
CHECK_EQUAL_HEX(int8_t(0x0F), (b.extract<int8_t>(3, 6)));
CHECK_EQUAL_HEX(int8_t(0xE7), (b.extract<int8_t>(4, 6)));
CHECK_EQUAL_HEX(int8_t(0xF3), (b.extract<int8_t>(5, 6)));
CHECK_EQUAL_HEX(int8_t(0x19), (b.extract<int8_t>(6, 6)));
CHECK_EQUAL_HEX(int8_t(0xEC), (b.extract<int8_t>(7, 6)));
CHECK_EQUAL_HEX(int8_t(0x16), (b.extract<int8_t>(8, 6)));
CHECK_EQUAL_HEX(int8_t(0xEB), (b.extract<int8_t>(9, 6)));
CHECK_EQUAL_HEX(int8_t(0x15), (b.extract<int8_t>(10, 6)));
CHECK_EQUAL_HEX(int8_t(0x0A), (b.extract<int8_t>(11, 6)));
CHECK_EQUAL_HEX(int8_t(0x05), (b.extract<int8_t>(12, 6)));
CHECK_EQUAL_HEX(int8_t(0xE2), (b.extract<int8_t>(13, 6)));
CHECK_EQUAL_HEX(int8_t(0x11), (b.extract<int8_t>(14, 6)));
CHECK_EQUAL_HEX(int8_t(0xE8), (b.extract<int8_t>(15, 6)));
CHECK_EQUAL_HEX(int8_t(0xF4), (b.extract<int8_t>(16, 6)));
CHECK_EQUAL_HEX(int8_t(0x1A), (b.extract<int8_t>(17, 6)));
CHECK_EQUAL_HEX(int8_t(0x0D), (b.extract<int8_t>(18, 6)));
CHECK_EQUAL_HEX(int8_t(0x06), (b.extract<int8_t>(19, 6)));
CHECK_EQUAL_HEX(int8_t(0xE3), (b.extract<int8_t>(20, 6)));
CHECK_EQUAL_HEX(int8_t(0x11), (b.extract<int8_t>(21, 6)));
CHECK_EQUAL_HEX(int8_t(0x08), (b.extract<int8_t>(22, 6)));
CHECK_EQUAL_HEX(int8_t(0xE4), (b.extract<int8_t>(23, 6)));
CHECK_EQUAL_HEX(int8_t(0x12), (b.extract<int8_t>(24, 6)));
CHECK_EQUAL_HEX(int8_t(0x09), (b.extract<int8_t>(25, 6)));
CHECK_EQUAL_HEX(int8_t(0x04), (b.extract<int8_t>(26, 6)));
CHECK_THROW(b.extract<int8_t>(26, 7), etl::bitset_overflow);
CHECK_THROW(b.extract<int8_t>(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<int8_t, 0, 6>()));
CHECK_EQUAL_HEX(int8_t(0xFC), (b.extract<int8_t, 1, 6>()));
CHECK_EQUAL_HEX(int8_t(0x1E), (b.extract<int8_t, 2, 6>()));
CHECK_EQUAL_HEX(int8_t(0x0F), (b.extract<int8_t, 3, 6>()));
CHECK_EQUAL_HEX(int8_t(0xE7), (b.extract<int8_t, 4, 6>()));
CHECK_EQUAL_HEX(int8_t(0xF3), (b.extract<int8_t, 5, 6>()));
CHECK_EQUAL_HEX(int8_t(0x19), (b.extract<int8_t, 6, 6>()));
CHECK_EQUAL_HEX(int8_t(0xEC), (b.extract<int8_t, 7, 6>()));
CHECK_EQUAL_HEX(int8_t(0x16), (b.extract<int8_t, 8, 6>()));
CHECK_EQUAL_HEX(int8_t(0xEB), (b.extract<int8_t, 9, 6>()));
CHECK_EQUAL_HEX(int8_t(0x15), (b.extract<int8_t, 10, 6>()));
CHECK_EQUAL_HEX(int8_t(0x0A), (b.extract<int8_t, 11, 6>()));
CHECK_EQUAL_HEX(int8_t(0x05), (b.extract<int8_t, 12, 6>()));
CHECK_EQUAL_HEX(int8_t(0xE2), (b.extract<int8_t, 13, 6>()));
CHECK_EQUAL_HEX(int8_t(0x11), (b.extract<int8_t, 14, 6>()));
CHECK_EQUAL_HEX(int8_t(0xE8), (b.extract<int8_t, 15, 6>()));
CHECK_EQUAL_HEX(int8_t(0xF4), (b.extract<int8_t, 16, 6>()));
CHECK_EQUAL_HEX(int8_t(0x1A), (b.extract<int8_t, 17, 6>()));
CHECK_EQUAL_HEX(int8_t(0x0D), (b.extract<int8_t, 18, 6>()));
CHECK_EQUAL_HEX(int8_t(0x06), (b.extract<int8_t, 19, 6>()));
CHECK_EQUAL_HEX(int8_t(0xE3), (b.extract<int8_t, 20, 6>()));
CHECK_EQUAL_HEX(int8_t(0x11), (b.extract<int8_t, 21, 6>()));
CHECK_EQUAL_HEX(int8_t(0x08), (b.extract<int8_t, 22, 6>()));
CHECK_EQUAL_HEX(int8_t(0xE4), (b.extract<int8_t, 23, 6>()));
CHECK_EQUAL_HEX(int8_t(0x12), (b.extract<int8_t, 24, 6>()));
CHECK_EQUAL_HEX(int8_t(0x09), (b.extract<int8_t, 25, 6>()));
CHECK_EQUAL_HEX(int8_t(0x04), (b.extract<int8_t, 26, 6>()));
// The lines below should static assert.
//int8_t v1 = b.extract<int8_t, 26, 7>();
//int8_t v1 = b.extract<int8_t, 27, 6>();
}
//*************************************************************************
TEST(test_extract_uint8_t_with_run_time_parameters)
{

View File

@ -3400,14 +3400,30 @@
<None Include="..\..\scripts\update_version.py">
<Filter>Tests\Scripts</Filter>
</None>
<None Include="..\..\.github\workflows\clang-c++11.yml" />
<None Include="..\..\.github\workflows\clang-c++14.yml" />
<None Include="..\..\.github\workflows\clang-c++17.yml" />
<None Include="..\..\.github\workflows\clang-c++20.yml" />
<None Include="..\..\.github\workflows\gcc-c++11.yml" />
<None Include="..\..\.github\workflows\gcc-c++14.yml" />
<None Include="..\..\.github\workflows\gcc-c++17.yml" />
<None Include="..\..\.github\workflows\gcc-c++20.yml" />
<None Include="..\..\.github\workflows\clang-c++11.yml">
<Filter>Resource Files\CI\Github</Filter>
</None>
<None Include="..\..\.github\workflows\clang-c++14.yml">
<Filter>Resource Files\CI\Github</Filter>
</None>
<None Include="..\..\.github\workflows\clang-c++17.yml">
<Filter>Resource Files\CI\Github</Filter>
</None>
<None Include="..\..\.github\workflows\clang-c++20.yml">
<Filter>Resource Files\CI\Github</Filter>
</None>
<None Include="..\..\.github\workflows\gcc-c++11.yml">
<Filter>Resource Files\CI\Github</Filter>
</None>
<None Include="..\..\.github\workflows\gcc-c++14.yml">
<Filter>Resource Files\CI\Github</Filter>
</None>
<None Include="..\..\.github\workflows\gcc-c++17.yml">
<Filter>Resource Files\CI\Github</Filter>
</None>
<None Include="..\..\.github\workflows\gcc-c++20.yml">
<Filter>Resource Files\CI\Github</Filter>
</None>
</ItemGroup>
<ItemGroup>
<Text Include="..\..\support\Release notes.txt">