diff --git a/include/etl/bitset.h b/include/etl/bitset.h index 2093d26b..871ed2b5 100644 --- a/include/etl/bitset.h +++ b/include/etl/bitset.h @@ -51,6 +51,7 @@ SOFTWARE. #include "static_assert.h" #include "error_handler.h" #include "span.h" +#include "string.h" #include "private/minmax_push.h" @@ -120,6 +121,20 @@ namespace etl } }; + //*************************************************************************** + /// Bitset overflow exception. + ///\ingroup bitset + //*************************************************************************** + class bitset_overflow : public bitset_exception + { + public: + + bitset_overflow(string_type file_name_, numeric_type line_number_) + : bitset_exception(ETL_ERROR_TEXT("bitset:overflow", ETL_BITSET_FILE_ID"C"), file_name_, line_number_) + { + } + }; + //************************************************************************* /// The base class for etl::bitset ///\ingroup bitset @@ -260,7 +275,11 @@ namespace etl size_t index; element_t mask; - if (SIZE == 1) + if (SIZE == 0) + { + return false; + } + else if (SIZE == 1) { index = 0; mask = element_t(1) << position; @@ -297,7 +316,10 @@ namespace etl size_t index; element_t bit; - if (SIZE == 1) + if (SIZE == 0) { + return *this; + } + else if (SIZE == 1) { index = 0; bit = element_t(1) << position; @@ -412,6 +434,11 @@ namespace etl typename etl::enable_if::value, T>::type value() const { + for (size_t i = sizeof(long long) / sizeof(element_t); i < SIZE; ++i) + { + ETL_ASSERT_AND_RETURN_VALUE(!(pdata[i]), ETL_ERROR(etl::bitset_overflow), T(0)); + } + T v = T(0); const bool OK = (sizeof(T) * CHAR_BIT) >= (SIZE * BITS_PER_ELEMENT); @@ -432,6 +459,22 @@ namespace etl return v; } + //************************************************************************* + /// Put to a unsigned long. + //************************************************************************* + unsigned long to_ulong() const + { + return value(); + } + + //************************************************************************* + /// Put to a unsigned long long. + //************************************************************************* + unsigned long long to_ullong() const + { + return value(); + } + //************************************************************************* /// Resets the bitset. //************************************************************************* @@ -453,7 +496,11 @@ namespace etl size_t index; element_t bit; - if (SIZE == 1) + if (SIZE == 0) + { + return *this; + } + else if (SIZE == 1) { index = 0; bit = element_t(1) << position; @@ -493,8 +540,12 @@ namespace etl { size_t index; element_t bit; - - if (SIZE == 1) + + if (SIZE == 0) + { + return *this; + } + else if (SIZE == 1) { index = 0; bit = element_t(1) << position; @@ -516,6 +567,11 @@ namespace etl //************************************************************************* bool all() const { + if (SIZE == 0UL) + { + return true; + } + // All but the last. for (size_t i = 0UL; i < (SIZE - 1); ++i) { @@ -580,7 +636,11 @@ namespace etl size_t index; size_t bit; - if (SIZE == 1) + if (SIZE == 0) + { + return ibitset::npos; + } + else if (SIZE == 1) { index = 0; bit = position; @@ -692,23 +752,37 @@ namespace etl //************************************************************************* ibitset& operator<<=(size_t shift) { - if (SIZE == 1) + if (SIZE != 0UL) { - pdata[0] <<= shift; - } - else - { - size_t source = NBITS - shift - 1; - size_t destination = NBITS - 1; - - for (size_t i = 0UL; i < (NBITS - shift); ++i) + // Just one element? + if (SIZE == 1UL) { - set(destination--, test(source--)); + pdata[0] <<= shift; } - - for (size_t i = 0UL; i < shift; ++i) + else if (shift == BITS_PER_ELEMENT) { - reset(destination--); + for (size_t i = (SIZE - 1); i > 0U; --i) + { + pdata[i] = pdata[i - 1]; + } + + pdata[0] = 0; + } + else + { + // TODO Optimise. + size_t source = NBITS - shift - 1; + size_t destination = NBITS - 1; + + for (size_t i = 0UL; i < (NBITS - shift); ++i) + { + set(destination--, test(source--)); + } + + for (size_t i = 0UL; i < shift; ++i) + { + reset(destination--); + } } } @@ -720,23 +794,38 @@ namespace etl //************************************************************************* ibitset& operator>>=(size_t shift) { - if (SIZE == 1) + if (SIZE != 0UL) { - pdata[0] >>= shift; - } - else - { - size_t source = shift; - size_t destination = 0; - - for (size_t i = 0UL; i < (NBITS - shift); ++i) + // Just one element? + if (SIZE == 1UL) { - set(destination++, test(source++)); + pdata[0] >>= shift; } - - for (size_t i = 0UL; i < shift; ++i) + // Shift is the size of an element? + else if (shift == BITS_PER_ELEMENT) { - reset(destination++); + for (size_t i = 0UL; i < (SIZE - 1); ++i) + { + pdata[i] = pdata[i + 1]; + } + + pdata[SIZE - 1] = 0; + } + else + { + // TODO Optimise. + size_t source = shift; + size_t destination = 0UL; + + for (size_t i = 0UL; i < (NBITS - shift); ++i) + { + set(destination++, test(source++)); + } + + for (size_t i = 0UL; i < shift; ++i) + { + reset(destination++); + } } } @@ -825,6 +914,8 @@ namespace etl { pdata[i] = ~pdata[i]; } + + pdata[SIZE - 1] &= TOP_MASK; } //************************************************************************* @@ -1055,6 +1146,30 @@ namespace etl return *this; } + //************************************************************************* + /// Returns a string representing the bitset. + //************************************************************************* +#if ETL_CPP11_SUPPORTED + template > +#else + template +#endif + TString to_string(typename TString::value_type zero = typename TString::value_type('0'), typename TString::value_type one = typename TString::value_type('1')) const + { + TString result; + + result.resize(MAXN, '\0'); + + ETL_ASSERT_AND_RETURN_VALUE((result.size() == MAXN), ETL_ERROR(etl::bitset_overflow), result); + + for (size_t i = MAXN; i > 0; --i) + { + result[MAXN - i] = test(i - 1) ? one : zero; + } + + return result; + } + //************************************************************************* /// operator = //************************************************************************* @@ -1159,7 +1274,7 @@ namespace etl private: - element_t data[ARRAY_SIZE]; + element_t data[ARRAY_SIZE > 0U ? ARRAY_SIZE : 1U]; }; //*************************************************************************** diff --git a/include/etl/profiles/determine_compiler_language_support.h b/include/etl/profiles/determine_compiler_language_support.h index a488f9fd..8c6aa954 100644 --- a/include/etl/profiles/determine_compiler_language_support.h +++ b/include/etl/profiles/determine_compiler_language_support.h @@ -145,7 +145,7 @@ SOFTWARE. #endif // NAN not defined or Rowley CrossWorks -#if !defined(NAN) || defined(__CROSSWORKS_ARM) || defined(ETL_COMPILER_ARM5) +#if !defined(NAN) || defined(__CROSSWORKS_ARM) || defined(ETL_COMPILER_ARM5) || defined(ARDUINO) #define ETL_NO_CPP_NAN_SUPPORT #endif diff --git a/test/test_bitset.cpp b/test/test_bitset.cpp index 744224d1..d22ffb35 100644 --- a/test/test_bitset.cpp +++ b/test/test_bitset.cpp @@ -749,6 +749,26 @@ namespace CHECK(data2 == shift11); } + //************************************************************************* + TEST(test_shift_left_operator_shift_element_size) + { + etl::bitset<60> data(0x12345678UL); + etl::bitset<60> shift(0x1234567800UL); + + data <<= 8U; + CHECK_EQUAL(shift.value(), data.value()); + } + + //************************************************************************* + TEST(test_shift_left_operator_overflow) + { + etl::bitset<31> data(0x7FFFFFFFUL); + etl::bitset<31> shifted(0x7FFFFFFEUL); + + data <<= 1U; + CHECK(data == shifted); + } + //************************************************************************* TEST(test_shift_left_copy_operator) { @@ -790,6 +810,16 @@ namespace CHECK(data2 == shift11); } + //************************************************************************* + TEST(test_shift_right_operator_shift_element_size) + { + etl::bitset<60> data(0x12345678UL); + etl::bitset<60> shift(0x123456UL); + + data >>= 8U; + CHECK_EQUAL(shift.value(), data.value()); + } + //************************************************************************* TEST(test_shift_right_copy_operator) { @@ -1091,5 +1121,50 @@ namespace CHECK_EQUAL(0x34U, s[2]); CHECK_EQUAL(0x12U, s[3]); } + + //************************************************************************* + TEST(test_to_string) + { + etl::bitset<32> b(0x12345678UL); + + etl::string<32> text = b.to_string('.', '*'); + std::string stdtext = b.to_string('.', '*'); + + CHECK_THROW(etl::string<32> text1 = b.to_string>('.', '*'), etl::bitset_overflow); + CHECK_EQUAL("...*..*...**.*...*.*.**..****...", text.c_str()); + CHECK_EQUAL("...*..*...**.*...*.*.**..****...", stdtext.c_str()); + } + + //************************************************************************* + TEST(test_issue_497_count_inverted_bits) + { + etl::bitset<5U> bits; + std::bitset<5U> stdbits; + etl::bitset<5U> negbits = ~bits; + std::bitset<5U> stdnegbits = ~stdbits; + + CHECK_EQUAL(stdbits.count(), bits.count()); + CHECK_EQUAL(stdbits.all(), bits.all()); + CHECK_EQUAL(stdnegbits.count(), negbits.count()); + CHECK_EQUAL(stdnegbits.all(), negbits.all()); + } + + //************************************************************************* + TEST(test_issue_497_shifted_zero_sized_bitset) + { + etl::bitset<0> bits; + std::bitset<0> stdbits; + + CHECK_EQUAL(stdbits.size(), bits.size()); + CHECK_EQUAL(stdbits.none(), bits.none()); + CHECK_EQUAL(stdbits.all(), bits.all()); + CHECK_EQUAL(stdbits.any(), bits.any()); + + CHECK_EQUAL(stdbits.count(), bits.count()); + CHECK_EQUAL(stdbits.to_ulong(), bits.to_ulong()); + CHECK_EQUAL(stdbits.to_ullong(), bits.to_ullong()); + + etl::bitset<0> shiftbits = bits << 1; // No exception. + } }; }