diff --git a/src/bitset.h b/src/bitset.h index 5d4fbcfe..0d65a51e 100644 --- a/src/bitset.h +++ b/src/bitset.h @@ -35,13 +35,20 @@ SOFTWARE. #include #include #include +#include #include "platform.h" #include "integral_limits.h" #include "algorithm.h" #include "nullptr.h" #include "log.h" -#include "ibitset.h" +#include "exception.h" +#include "integral_limits.h" +#include "binary.h" + +#ifdef ETL_COMPILER_MICROSOFT +#undef min +#endif #define ETL_NO_CHECKS #include "error_handler.h" @@ -58,6 +65,662 @@ SOFTWARE. namespace etl { + //*************************************************************************** + /// Exception base for bitset + ///\ingroup bitset + //*************************************************************************** + class bitset_exception : public etl::exception + { + public: + + bitset_exception(string_type what, string_type file_name, numeric_type line_number) + : exception(what, file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Bitset nullptr exception. + ///\ingroup bitset + //*************************************************************************** + class bitset_nullptr : public bitset_exception + { + public: + + bitset_nullptr(string_type file_name, numeric_type line_number) + : bitset_exception("bitset: nullptr", file_name, line_number) + { + } + }; + + //************************************************************************* + /// The base class for etl::bitset + ///\ingroup bitset + //************************************************************************* + class ibitset + { + protected: + + // The type used for each element in the array. +#if !defined(ETL_BITSET_ELEMENT_TYPE) + typedef uint_least8_t element_t; +#else + typedef ETL_BITSET_ELEMENT_TYPE element_t; +#endif + + public: + + static const element_t ALL_SET = etl::integral_limits::max; + static const element_t ALL_CLEAR = 0; + + static const size_t BITS_PER_ELEMENT = etl::integral_limits::bits; + + enum + { + npos = etl::integral_limits::max + }; + + //************************************************************************* + /// The reference type returned. + //************************************************************************* + class bit_reference + { + public: + + friend class ibitset; + + //******************************* + /// Conversion operator. + //******************************* + operator bool() const + { + return p_bitset->test(position); + } + + //******************************* + /// Assignment operator. + //******************************* + bit_reference& operator = (bool b) + { + p_bitset->set(position, b); + return *this; + } + + //******************************* + /// Assignment operator. + //******************************* + bit_reference& operator = (const bit_reference& r) + { + p_bitset->set(position, bool(r)); + return *this; + } + + //******************************* + /// Flip the bit. + //******************************* + bit_reference& flip() + { + p_bitset->flip(position); + return *this; + } + + //******************************* + /// Return the logical inverse of the bit. + //******************************* + bool operator~() const + { + return !p_bitset->test(position); + } + + private: + + //******************************* + /// Default constructor. + //******************************* + bit_reference() + : p_bitset(nullptr), + position(0) + { + } + + //******************************* + /// Constructor. + //******************************* + bit_reference(ibitset& r_bitset, size_t position) + : p_bitset(&r_bitset), + position(position) + { + } + + ibitset* p_bitset; ///< The bitset. + size_t position; ///< The position in the bitset. + }; + + //************************************************************************* + /// The size of the bitset. + //************************************************************************* + size_t size() const + { + return NBITS; + } + + //************************************************************************* + /// Count the number of bits set. + //************************************************************************* + size_t count() const + { + size_t n = 0; + + for (size_t i = 0; i < SIZE; ++i) + { + n += etl::count_bits(pdata[i]); + } + + return n; + } + + //************************************************************************* + /// Tests a bit at a position. + /// Positions greater than the number of configured bits will return false. + //************************************************************************* + bool test(size_t position) const + { + size_t index; + element_t mask; + + if (SIZE == 1) + { + index = 0; + mask = element_t(1) << position; + } + else + { + index = position >> etl::log2::value; + mask = element_t(1) << (position & (BITS_PER_ELEMENT - 1)); + } + + return (pdata[index] & mask) != 0; + } + + //************************************************************************* + /// Set the bit at the position. + //************************************************************************* + ibitset& set() + { + for (size_t i = 0; i < SIZE; ++i) + { + pdata[i] = ALL_SET; + } + + pdata[SIZE - 1] &= TOP_MASK; + + return *this; + } + + //************************************************************************* + /// Set the bit at the position. + //************************************************************************* + ibitset& set(size_t position, bool value = true) + { + size_t index; + element_t bit; + + if (SIZE == 1) + { + index = 0; + bit = element_t(1) << position; + } + else + { + index = position >> etl::log2::value; + bit = element_t(1) << (position & (BITS_PER_ELEMENT - 1)); + } + + if (value) + { + pdata[index] |= bit; + } + else + { + pdata[index] &= ~bit; + } + + return *this; + } + + //************************************************************************* + /// Set from a string. + //************************************************************************* + ibitset& set(const char* text) + { + reset(); + + size_t i = std::min(NBITS, strlen(text)); + + while (i > 0) + { + set(--i, *text++ == '1'); + } + + return *this; + } + + //************************************************************************* + /// Resets the bitset. + //************************************************************************* + ibitset& reset() + { + for (size_t i = 0; i < SIZE; ++i) + { + pdata[i] = ALL_CLEAR; + } + + return *this; + } + + //************************************************************************* + /// Reset the bit at the position. + //************************************************************************* + ibitset& reset(size_t position) + { + size_t index; + element_t bit; + + if (SIZE == 1) + { + index = 0; + bit = element_t(1) << position; + } + else + { + index = position >> etl::log2::value; + bit = element_t(1) << (position & (BITS_PER_ELEMENT - 1)); + } + + pdata[index] &= ~bit; + + return *this; + } + + //************************************************************************* + /// Flip all of the bits. + //************************************************************************* + ibitset& flip() + { + for (size_t i = 0; i < SIZE; ++i) + { + pdata[i] = ~pdata[i]; + } + + pdata[SIZE - 1] &= TOP_MASK; + + return *this; + } + + //************************************************************************* + /// Flip the bit at the position. + //************************************************************************* + ibitset& flip(size_t position) + { + if (position < NBITS) + { + size_t index; + element_t bit; + + if (SIZE == 1) + { + index = 0; + bit = element_t(1) << position; + } + else + { + index = position >> log2::value; + bit = element_t(1) << (position & (BITS_PER_ELEMENT - 1)); + } + + pdata[index] ^= bit; + } + + return *this; + } + + //************************************************************************* + // Are all the bits sets? + //************************************************************************* + bool all() const + { + // All but the last. + for (size_t i = 0; i < (SIZE - 1); ++i) + { + if (pdata[i] != ALL_SET) + { + return false; + } + } + + // The last. + if (pdata[SIZE - 1] != (ALL_SET & TOP_MASK)) + { + return false; + } + + return true; + } + + //************************************************************************* + /// Are any of the bits set? + //************************************************************************* + bool any() const + { + return !none(); + } + + //************************************************************************* + /// Are none of the bits set? + //************************************************************************* + bool none() const + { + for (size_t i = 0; i < SIZE; ++i) + { + if (pdata[i] != 0) + { + return false; + } + } + + return true; + } + + //************************************************************************* + /// Finds the first bit in the specified state. + ///\param state The state to search for. + ///\returns The position of the bit or SIZE if none were found. + //************************************************************************* + size_t find_first(bool state) const + { + return find_next(state, 0); + } + + //************************************************************************* + /// Finds the next bit in the specified state. + ///\param state The state to search for. + ///\param position The position to start from. + ///\returns The position of the bit or SIZE if none were found. + //************************************************************************* + size_t find_next(bool state, size_t position) const + { + // Where to start. + size_t index; + size_t bit; + + if (SIZE == 1) + { + index = 0; + bit = position; + } + else + { + index = position >> log2::value; + bit = position & (BITS_PER_ELEMENT - 1); + } + + element_t mask = 1 << bit; + + // For each element in the bitset... + while (index < SIZE) + { + element_t value = pdata[index]; + + // Needs checking? + if ((state && (value != ALL_CLEAR)) || + (!state && (value != ALL_SET))) + { + // For each bit in the element... + while ((bit < BITS_PER_ELEMENT) && (position < NBITS)) + { + // Equal to the required state? + if (((value & mask) != 0) == state) + { + return position; + } + + // Move on to the next bit. + mask <<= 1; + ++position; + ++bit; + } + } + else + { + position += BITS_PER_ELEMENT; + } + + // Start at the beginning for all other elements. + bit = 0; + mask = 1; + + ++index; + } + + return ibitset::npos; + } + + //************************************************************************* + /// Read [] operator. + //************************************************************************* + bool operator[] (size_t position) const + { + return test(position); + } + + //************************************************************************* + /// Write [] operator. + //************************************************************************* + bit_reference operator [] (size_t position) + { + return bit_reference(*this, position); + } + + //************************************************************************* + /// operator &= + //************************************************************************* + ibitset& operator &=(const ibitset& other) + { + for (size_t i = 0; i < SIZE; ++i) + { + pdata[i] &= other.pdata[i]; + } + + return *this; + } + + //************************************************************************* + /// operator |= + //************************************************************************* + ibitset& operator |=(const ibitset& other) + { + for (size_t i = 0; i < SIZE; ++i) + { + pdata[i] |= other.pdata[i]; + } + + return *this; + } + + //************************************************************************* + /// operator ^= + //************************************************************************* + ibitset& operator ^=(const ibitset& other) + { + for (size_t i = 0; i < SIZE; ++i) + { + pdata[i] ^= other.pdata[i]; + } + + return *this; + } + + //************************************************************************* + /// operator <<= + //************************************************************************* + ibitset& operator<<=(size_t shift) + { + if (SIZE == 1) + { + pdata[0] <<= shift; + } + else + { + size_t source = NBITS - shift - 1; + size_t destination = NBITS - 1; + + for (size_t i = 0; i < (NBITS - shift); ++i) + { + set(destination--, test(source--)); + } + + for (size_t i = 0; i < shift; ++i) + { + reset(destination--); + } + } + + return *this; + } + + //************************************************************************* + /// operator >>= + //************************************************************************* + ibitset& operator>>=(size_t shift) + { + if (SIZE == 1) + { + pdata[0] >>= shift; + } + else + { + size_t source = shift; + size_t destination = 0; + + for (size_t i = 0; i < (NBITS - shift); ++i) + { + set(destination++, test(source++)); + } + + for (size_t i = 0; i < shift; ++i) + { + reset(destination++); + } + } + + return *this; + } + + //************************************************************************* + /// operator = + //************************************************************************* + ibitset& operator =(const ibitset& other) + { + if (this != &other) + { + etl::copy_n(other.pdata, SIZE, pdata); + } + + return *this; + } + + //************************************************************************* + /// swap + //************************************************************************* + void swap(ibitset& other) + { + std::swap_ranges(pdata, pdata + SIZE, other.pdata); + } + + protected: + + //************************************************************************* + /// Initialise from an unsigned long long. + //************************************************************************* + ibitset& initialise(unsigned long long value) + { + reset(); + + 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) + { + pdata[0] = element_t(value); + } + else + { + size_t i = 0; + + while ((value != 0) && (i < SIZE)) + { + pdata[i++] = value & ALL_SET; + value = value >> SHIFT; + } + } + + pdata[SIZE - 1] &= TOP_MASK; + + return *this; + } + + //************************************************************************* + /// Invert + //************************************************************************* + void invert() + { + for (size_t i = 0; i < SIZE; ++i) + { + pdata[i] = ~pdata[i]; + } + } + + //************************************************************************* + /// Gets a reference to the specified bit. + //************************************************************************* + bit_reference get_bit_reference(size_t position) + { + return bit_reference(*this, position); + } + + //************************************************************************* + /// Constructor. + //************************************************************************* + ibitset(size_t nbits, size_t size, element_t* pdata) + : NBITS(nbits), + SIZE(size), + pdata(pdata) + { + size_t allocated_bits = SIZE * BITS_PER_ELEMENT; + size_t top_mask_shift = ((BITS_PER_ELEMENT - (allocated_bits - NBITS)) % BITS_PER_ELEMENT); + TOP_MASK = element_t(top_mask_shift == 0 ? ALL_SET : ~(ALL_SET << top_mask_shift)); + } + + //************************************************************************* + /// Compare bitsets. + //************************************************************************* + static bool is_equal(const ibitset& lhs, const ibitset&rhs) + { + return std::equal(lhs.pdata, lhs.pdata + lhs.SIZE, rhs.pdata); + } + + element_t TOP_MASK; + + private: + + // Disable copy construction. + ibitset(const ibitset&); + + const size_t NBITS; + const size_t SIZE; + element_t* pdata; + }; + //************************************************************************* /// The class emulates an array of bool elements, but optimized for space allocation. /// Will accommodate any number of bits. @@ -66,14 +729,14 @@ namespace etl ///\ingroup bitset //************************************************************************* template - class bitset : public ibitset + class bitset : public etl::ibitset { - static const size_t ARRAY_SIZE = (MAXN % BITS_PER_ELEMENT == 0) ? MAXN / BITS_PER_ELEMENT : MAXN / BITS_PER_ELEMENT + 1; + static const size_t ARRAY_SIZE = (MAXN % BITS_PER_ELEMENT == 0) ? MAXN / BITS_PER_ELEMENT : MAXN / BITS_PER_ELEMENT + 1; public: - static const size_t ALLOCATED_BITS = ARRAY_SIZE * BITS_PER_ELEMENT; + static const size_t ALLOCATED_BITS = ARRAY_SIZE * BITS_PER_ELEMENT; public: @@ -81,7 +744,7 @@ namespace etl /// Default constructor. //************************************************************************* bitset() - : ibitset(MAXN, ARRAY_SIZE, data) + : etl::ibitset(MAXN, ARRAY_SIZE, data) { reset(); } @@ -90,7 +753,7 @@ namespace etl /// Copy constructor. //************************************************************************* bitset(const bitset& other) - : ibitset(MAXN, ARRAY_SIZE, data) + : etl::ibitset(MAXN, ARRAY_SIZE, data) { etl::copy_n(other.data, ARRAY_SIZE, data); } @@ -99,7 +762,7 @@ namespace etl /// Construct from a value. //************************************************************************* bitset(unsigned long long value) - : ibitset(MAXN, ARRAY_SIZE, data) + : etl::ibitset(MAXN, ARRAY_SIZE, data) { initialise(value); } @@ -108,7 +771,7 @@ namespace etl /// Construct from a string. //************************************************************************* bitset(const char* text) - : ibitset(MAXN, ARRAY_SIZE, data) + : etl::ibitset(MAXN, ARRAY_SIZE, data) { set(text); } @@ -118,7 +781,7 @@ namespace etl //************************************************************************* bitset& set() { - ibitset::set(); + etl::ibitset::set(); return *this; } @@ -127,7 +790,7 @@ namespace etl //************************************************************************* bitset& set(size_t position, bool value = true) { - ibitset::set(position, value); + etl::ibitset::set(position, value); return *this; } @@ -137,7 +800,7 @@ namespace etl bitset& set(const char* text) { ETL_ASSERT(text != 0, ETL_ERROR(bitset_nullptr)); - ibitset::set(text); + etl::ibitset::set(text); return *this; } @@ -156,7 +819,7 @@ namespace etl //************************************************************************* bitset& reset(size_t position) { - ibitset::reset(position); + etl::ibitset::reset(position); return *this; } @@ -174,7 +837,7 @@ namespace etl //************************************************************************* bitset& flip(size_t position) { - ibitset::flip(position); + etl::ibitset::flip(position); return *this; } @@ -196,7 +859,7 @@ namespace etl //************************************************************************* bitset& operator &=(const bitset& other) { - ibitset::operator &=(other); + etl::ibitset::operator &=(other); return *this; } @@ -205,7 +868,7 @@ namespace etl //************************************************************************* bitset& operator |=(const bitset& other) { - ibitset::operator |=(other); + etl::ibitset::operator |=(other); return *this; } @@ -223,7 +886,7 @@ namespace etl //************************************************************************* bitset operator ~() const { - bitset temp(*this); + etl::bitset temp(*this); temp.invert(); @@ -235,7 +898,7 @@ namespace etl //************************************************************************* bitset operator<<(size_t shift) const { - bitset temp(*this); + etl::bitset temp(*this); temp <<= shift; @@ -247,7 +910,7 @@ namespace etl //************************************************************************* bitset& operator<<=(size_t shift) { - ibitset::operator <<=(shift); + etl::ibitset::operator <<=(shift); return *this; } @@ -268,7 +931,7 @@ namespace etl //************************************************************************* bitset& operator>>=(size_t shift) { - ibitset::operator >>=(shift); + etl::ibitset::operator >>=(shift); return *this; } @@ -277,7 +940,7 @@ namespace etl //************************************************************************* friend bool operator == (const bitset& lhs, const bitset& rhs) { - return ibitset::is_equal(lhs, rhs); + return etl::ibitset::is_equal(lhs, rhs); } private: @@ -341,4 +1004,8 @@ void swap(etl::bitset& lhs, etl::bitset& rhs) lhs.swap(rhs); } +#ifdef ETL_COMPILER_MICROSOFT +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + #endif