Containers (STL-compatible) StateMachines MessageBus and more for Embedded Systems. See www.etlcpp.com
Diff: bitset.h
- Revision:
- 0:b47c2a7920c2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bitset.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,1011 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef __ETL_BITSET__ +#define __ETL_BITSET__ + +#include <algorithm> +#include <iterator> +#include <string.h> +#include <stddef.h> +#include <stdint.h> + +#include "platform.h" +#include "integral_limits.h" +#include "algorithm.h" +#include "nullptr.h" +#include "log.h" +#include "exception.h" +#include "integral_limits.h" +#include "binary.h" + +#ifdef ETL_COMPILER_MICROSOFT +#undef min +#endif + +#include "error_handler.h" + +#if defined(ETL_COMPILER_KEIL) +#pragma diag_suppress 1300 +#endif + +//***************************************************************************** +///\defgroup bitset bitset +/// Similar to std::bitset but without requiring std::string. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + /// Exception base for bitset + ///\ingroup bitset + //*************************************************************************** + class bitset_exception : public etl::exception + { + public: + + bitset_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, 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<element_t>::max; + static const element_t ALL_CLEAR = 0; + + static const size_t BITS_PER_ELEMENT = etl::integral_limits<element_t>::bits; + + enum + { + npos = etl::integral_limits<size_t>::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(std::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 <b>false</b>. + //************************************************************************* + 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<BITS_PER_ELEMENT>::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<BITS_PER_ELEMENT>::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<BITS_PER_ELEMENT>::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<BITS_PER_ELEMENT>::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<BITS_PER_ELEMENT>::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<unsigned long long>::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. + /// Does not use std::string. + ///\tparam N The number of bits. + ///\ingroup bitset + //************************************************************************* + template <const size_t MAXN> + 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; + + public: + + static const size_t ALLOCATED_BITS = ARRAY_SIZE * BITS_PER_ELEMENT; + + public: + + //************************************************************************* + /// Default constructor. + //************************************************************************* + bitset() + : etl::ibitset(MAXN, ARRAY_SIZE, data) + { + reset(); + } + + //************************************************************************* + /// Copy constructor. + //************************************************************************* + bitset(const bitset<MAXN>& other) + : etl::ibitset(MAXN, ARRAY_SIZE, data) + { + etl::copy_n(other.data, ARRAY_SIZE, data); + } + + //************************************************************************* + /// Construct from a value. + //************************************************************************* + bitset(unsigned long long value) + : etl::ibitset(MAXN, ARRAY_SIZE, data) + { + initialise(value); + } + + //************************************************************************* + /// Construct from a string. + //************************************************************************* + bitset(const char* text) + : etl::ibitset(MAXN, ARRAY_SIZE, data) + { + set(text); + } + + //************************************************************************* + /// Set all of the bits. + //************************************************************************* + bitset<MAXN>& set() + { + etl::ibitset::set(); + return *this; + } + + //************************************************************************* + /// Set the bit at the position. + //************************************************************************* + bitset<MAXN>& set(size_t position, bool value = true) + { + etl::ibitset::set(position, value); + return *this; + } + + //************************************************************************* + /// Set from a string. + //************************************************************************* + bitset<MAXN>& set(const char* text) + { + ETL_ASSERT(text != 0, ETL_ERROR(bitset_nullptr)); + etl::ibitset::set(text); + + return *this; + } + + //************************************************************************* + /// Reset all of the bits. + //************************************************************************* + bitset<MAXN>& reset() + { + ibitset::reset(); + return *this; + } + + //************************************************************************* + /// Reset the bit at the position. + //************************************************************************* + bitset<MAXN>& reset(size_t position) + { + etl::ibitset::reset(position); + return *this; + } + + //************************************************************************* + /// Flip all of the bits. + //************************************************************************* + bitset<MAXN>& flip() + { + ibitset::flip(); + return *this; + } + + //************************************************************************* + /// Flip the bit at the position. + //************************************************************************* + bitset<MAXN>& flip(size_t position) + { + etl::ibitset::flip(position); + return *this; + } + + //************************************************************************* + /// operator = + //************************************************************************* + bitset<MAXN>& operator =(const bitset<MAXN>& other) + { + if (this != &other) + { + etl::copy_n(other.data, ARRAY_SIZE, data); + } + + return *this; + } + + //************************************************************************* + /// operator &= + //************************************************************************* + bitset<MAXN>& operator &=(const bitset<MAXN>& other) + { + etl::ibitset::operator &=(other); + return *this; + } + + //************************************************************************* + /// operator |= + //************************************************************************* + bitset<MAXN>& operator |=(const bitset<MAXN>& other) + { + etl::ibitset::operator |=(other); + return *this; + } + + //************************************************************************* + /// operator ^= + //************************************************************************* + bitset<MAXN>& operator ^=(const bitset<MAXN>& other) + { + ibitset::operator ^=(other); + return *this; + } + + //************************************************************************* + /// operator ~ + //************************************************************************* + bitset<MAXN> operator ~() const + { + etl::bitset<MAXN> temp(*this); + + temp.invert(); + + return temp; + } + + //************************************************************************* + /// operator << + //************************************************************************* + bitset<MAXN> operator<<(size_t shift) const + { + etl::bitset<MAXN> temp(*this); + + temp <<= shift; + + return temp; + } + + //************************************************************************* + /// operator <<= + //************************************************************************* + bitset<MAXN>& operator<<=(size_t shift) + { + etl::ibitset::operator <<=(shift); + return *this; + } + + //************************************************************************* + /// operator >> + //************************************************************************* + bitset<MAXN> operator>>(size_t shift) const + { + bitset<MAXN> temp(*this); + + temp >>= shift; + + return temp; + } + + //************************************************************************* + /// operator >>= + //************************************************************************* + bitset<MAXN>& operator>>=(size_t shift) + { + etl::ibitset::operator >>=(shift); + return *this; + } + + //************************************************************************* + /// operator == + //************************************************************************* + friend bool operator == (const bitset<MAXN>& lhs, const bitset<MAXN>& rhs) + { + return etl::ibitset::is_equal(lhs, rhs); + } + + private: + + element_t data[ARRAY_SIZE]; + }; + + //*************************************************************************** + /// operator & + ///\ingroup bitset + //*************************************************************************** + template <const size_t MAXN> + bitset<MAXN> operator & (const bitset<MAXN>& lhs, const bitset<MAXN>& rhs) + { + bitset<MAXN> temp(lhs); + temp &= rhs; + return temp; + } + + //*************************************************************************** + /// operator | + ///\ingroup bitset + //*************************************************************************** + template<const size_t MAXN> + bitset<MAXN> operator | (const bitset<MAXN>& lhs, const bitset<MAXN>& rhs) + { + bitset<MAXN> temp(lhs); + temp |= rhs; + return temp; + } + + //*************************************************************************** + /// operator ^ + ///\ingroup bitset + //*************************************************************************** + template<const size_t MAXN> + bitset<MAXN> operator ^ (const bitset<MAXN>& lhs, const bitset<MAXN>& rhs) + { + bitset<MAXN> temp(lhs); + temp ^= rhs; + return temp; + } + + //*************************************************************************** + /// operator != + ///\ingroup bitset + //*************************************************************************** + template<const size_t MAXN> + bool operator != (const bitset<MAXN>& lhs, const bitset<MAXN>& rhs) + { + return !(lhs == rhs); + } +} + +//************************************************************************* +/// swap +//************************************************************************* +template <const size_t MAXN> +void swap(etl::bitset<MAXN>& lhs, etl::bitset<MAXN>& rhs) +{ + lhs.swap(rhs); +} + +#ifdef ETL_COMPILER_MICROSOFT +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#endif +