Line data Source code
1 : /* ✔ */ 2 : 3 : #pragma once 4 : 5 : #include <AH/Error/Error.hpp> 6 : #include <AH/Settings/NamespaceSettings.hpp> 7 : #include <stdint.h> 8 : 9 : BEGIN_AH_NAMESPACE 10 : 11 : /// @addtogroup AH_Containers 12 : /// @{ 13 : 14 : /** 15 : * @brief A class for arrays of bits. 16 : * 17 : * @tparam N 18 : * The number of bits. 19 : */ 20 : template <uint16_t N> 21 : class BitArray { 22 : public: 23 : /** 24 : * @brief Get the value of the given bit. 25 : * 26 : * @param bitIndex 27 : * The (zero-based) index of the bit to read. 28 : */ 29 65 : bool get(uint16_t bitIndex) const { 30 65 : return buffer[getBufferIndex(bitIndex)] & getBufferMask(bitIndex); 31 : } 32 : 33 : /** 34 : * @brief Set the value of the given bit to 1. 35 : * 36 : * @param bitIndex 37 : * The (zero-based) index of the bit to set. 38 : */ 39 3 : void set(uint16_t bitIndex) { 40 3 : buffer[getBufferIndex(bitIndex)] |= getBufferMask(bitIndex); 41 3 : } 42 : 43 : /** 44 : * @brief Clear the value of the given bit to 0. 45 : * 46 : * @param bitIndex 47 : * The (zero-based) index of the bit to clear. 48 : */ 49 2 : void clear(uint16_t bitIndex) { 50 2 : buffer[getBufferIndex(bitIndex)] &= ~getBufferMask(bitIndex); 51 2 : } 52 : 53 : /** 54 : * @brief Set the value of the given bit to the given state. 55 : * 56 : * @param bitIndex 57 : * The (zero-based) index of the bit to set. 58 : * @param state 59 : * The value to set the bit to. 60 : */ 61 2 : void set(uint16_t bitIndex, bool state) { 62 2 : state ? set(bitIndex) : clear(bitIndex); 63 2 : } 64 : 65 : /** 66 : * @brief Check the given byte index, and return it if it is within the 67 : * bounds of the array, otherwise, throw an error, and return 68 : * the last valid index. 69 : * 70 : * @param byteIndex 71 : * The index to check. 72 : */ 73 70 : uint16_t safeIndex(uint16_t byteIndex) const { 74 70 : if (byteIndex >= getBufferLength()) { 75 1 : ERROR(F("Error: index out of bounds (") 76 : << byteIndex << F(", length is ") << getBufferLength() 77 : << ')', 78 : 0xFFFF); 79 : return getBufferLength() - 1; // LCOV_EXCL_LINE 80 : } 81 69 : return byteIndex; 82 : } 83 : 84 : /** 85 : * @brief Get the byte at the given index. 86 : * 87 : * This function can be used to quickly access all of the bits, to send 88 : * them out to a shift register, for example. 89 : * 90 : * @note No bounds checking is performed. 91 : * 92 : * @param byteIndex 93 : * The index of the byte within the array. 94 : */ 95 : const uint8_t &getByte(uint16_t byteIndex) const { 96 : return buffer[byteIndex]; 97 : // return buffer[safeIndex(byteIndex)]; 98 : } 99 : /// @copydoc AH::BitArray::getByte(uint16_t) const 100 : uint8_t &getByte(uint16_t byteIndex) { 101 : return buffer[byteIndex]; 102 : // return buffer[safeIndex(byteIndex)]; 103 : } 104 : 105 : /** 106 : * @brief Set the byte at the given index. 107 : * 108 : * This function can be used to quickly write all of the bits, when reading 109 : * them in from an I/O expander, for example. 110 : * 111 : * @note No bounds checking is performed. 112 : * 113 : * @param byteIndex 114 : * The index of the byte within the array. 115 : * @param value 116 : * The byte to write. 117 : */ 118 : void setByte(uint16_t byteIndex, uint8_t value) { 119 : buffer[byteIndex] = value; 120 : } 121 : 122 : /** 123 : * @brief Get the buffer length in bytes. 124 : */ 125 71 : uint16_t getBufferLength() const { return bufferLength; } 126 : 127 : private: 128 70 : uint16_t getBufferIndex(uint16_t bitIndex) const { 129 70 : return safeIndex(bitIndex / 8); 130 : } 131 69 : uint8_t getBufferBit(uint16_t bitIndex) const { return bitIndex % 8; } 132 69 : uint8_t getBufferMask(uint16_t bitIndex) const { 133 69 : return 1 << getBufferBit(bitIndex); 134 : } 135 : 136 : constexpr static uint16_t bufferLength = (uint16_t)((N + 7) / 8); 137 : uint8_t buffer[bufferLength] = {}; 138 : }; 139 : 140 : /// @} 141 : 142 : END_AH_NAMESPACE