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
|