diff --git a/include/etl/bitset.h b/include/etl/bitset.h index 2475fdb8..871ed2b5 100644 --- a/include/etl/bitset.h +++ b/include/etl/bitset.h @@ -275,7 +275,8 @@ namespace etl size_t index; element_t mask; - if (SIZE == 0) { + if (SIZE == 0) + { return false; } else if (SIZE == 1) @@ -433,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); @@ -453,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. //************************************************************************* @@ -518,7 +540,6 @@ namespace etl { size_t index; element_t bit; - if (SIZE == 0) { @@ -546,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) { @@ -726,26 +752,37 @@ namespace etl //************************************************************************* ibitset& operator<<=(size_t shift) { - if (SIZE == 0) { - return *this; - } - else 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--); + } } } @@ -757,26 +794,38 @@ namespace etl //************************************************************************* ibitset& operator>>=(size_t shift) { - if (SIZE == 0) { - return *this; - } - else 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++); + } } } @@ -824,46 +873,6 @@ namespace etl } #endif - //************************************************************************* - /// to_ulong - /// Returns an unsigned long represented by the bitset data. - //************************************************************************* - unsigned long to_ulong() const - { - for (size_t i = sizeof(long) / sizeof(element_t); i < SIZE; ++i) - ETL_ASSERT(!(pdata[i]), ETL_ERROR(etl::bitset_overflow)); - - unsigned long out = 0; - - for (size_t i = 0UL; i < SIZE; i++) - { - out += static_cast(pdata[i] & ((i < SIZE - 1) ? ALL_SET : TOP_MASK)) << (BITS_PER_ELEMENT * i); - } - - return out; - } - -#if ETL_CPP11_SUPPORTED - //************************************************************************* - /// to_ullong - /// Returns an unsigned long long represented by the bitset data. - //************************************************************************* - unsigned long long to_ullong() const - { - for (size_t i = sizeof(long long) / sizeof(element_t); i < SIZE; ++i) - ETL_ASSERT(!(pdata[i]), ETL_ERROR(etl::bitset_overflow)); - - unsigned long long out = 0; - - for (size_t i = 0ULL; i < SIZE; i++) - { - out += static_cast(pdata[i] & ((i < SIZE - 1) ? ALL_SET : TOP_MASK)) << (BITS_PER_ELEMENT * i); - } - - return out; - } -#endif - protected: //************************************************************************* @@ -903,8 +912,10 @@ namespace etl { for (size_t i = 0UL; i < SIZE; ++i) { - pdata[i] = ~pdata[i] & (i == SIZE - 1 ? TOP_MASK : ALL_SET); + pdata[i] = ~pdata[i]; } + + pdata[SIZE - 1] &= TOP_MASK; } //************************************************************************* @@ -1138,13 +1149,21 @@ namespace etl //************************************************************************* /// Returns a string representing the bitset. //************************************************************************* - template > - STRINGT to_string(typename STRINGT::value_type zero = typename STRINGT::value_type('0'), typename STRINGT::value_type one = typename STRINGT::value_type('1')) const +#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 { - STRINGT result; + TString result; - result.assign(MAXN, '\0'); - for (size_t i = MAXN; i > 0; --i) { + 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; } @@ -1255,7 +1274,7 @@ namespace etl private: - element_t data[ARRAY_SIZE]; + element_t data[ARRAY_SIZE > 0U ? ARRAY_SIZE : 1U]; }; //*************************************************************************** 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. + } }; }