C/C++ API Reference
Loading...
Searching...
No Matches
bitset.h
1// Copyright 2025 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14#pragma once
15
16#include <cstddef>
17#include <cstdint>
18
19#include "lib/stdcompat/bit.h"
20
21namespace pw {
22
24
33template <size_t kBits>
34class BitSet {
35 public:
38 using value_type = std::conditional_t<
39 kBits <= 8,
40 uint8_t,
41 std::conditional_t<kBits <= 16,
42 uint16_t,
43 std::conditional_t<kBits <= 32, uint32_t, uint64_t>>>;
44
47 template <unsigned long long kValue>
48 static constexpr BitSet Of() {
49 static_assert(cpp20::countl_zero(kValue) >= sizeof(kValue) * 8 - kBits,
50 "The value must fit within the BitSet");
51 return BitSet(static_cast<value_type>(kValue));
52 }
53
56 template <typename... Args,
57 typename = std::enable_if_t<(std::is_same_v<Args, bool> && ...)>>
58 static constexpr BitSet LittleEndian(Args... bits_least_to_most_significant) {
59 static_assert(sizeof...(Args) == kBits,
60 "One bool argument must be provided for each bit");
61 return BitSet(LittleBoolsToBits(bits_least_to_most_significant...));
62 }
63
64 constexpr BitSet() : BitSet(0) {}
65
66 constexpr BitSet(const BitSet&) = default;
67 constexpr BitSet& operator=(const BitSet&) = default;
68
69 template <size_t kOtherBits, typename = std::enable_if_t<kBits >= kOtherBits>>
70 constexpr BitSet(const BitSet<kOtherBits>& other) : bits_{other.bits_} {}
71
72 template <size_t kOtherBits, typename = std::enable_if_t<kBits >= kOtherBits>>
73 constexpr BitSet& operator=(const BitSet& other) {
74 bits_ = other.bits_;
75 }
76
77 // Observers
78
79 [[nodiscard]] constexpr bool operator==(const BitSet& other) const {
80 return bits_ == other.bits_;
81 }
82 [[nodiscard]] constexpr bool operator!=(const BitSet& other) const {
83 return bits_ != other.bits_;
84 }
85
86 template <size_t kBit>
87 [[nodiscard]] constexpr bool test() const {
88 CheckBitIndices<kBit>();
89 return (bits_ & (value_type{1} << kBit)) != 0;
90 }
91
92 [[nodiscard]] constexpr bool all() const {
93 if constexpr (kBits == 0) {
94 return true;
95 }
96 return bits_ == kAllSet;
97 }
98
99 [[nodiscard]] constexpr bool any() const { return bits_ != 0; }
100 [[nodiscard]] constexpr bool none() const { return bits_ == 0; }
101
102 [[nodiscard]] constexpr size_t count() const {
103 return static_cast<size_t>(cpp20::popcount(bits_));
104 }
105 [[nodiscard]] constexpr size_t size() const { return kBits; }
106
107 // Modifiers
108
109 constexpr BitSet& set() {
110 bits_ = kAllSet;
111 return *this;
112 }
113
114 template <size_t... kBitsToSet>
115 constexpr BitSet& set() {
116 CheckBitIndices<kBitsToSet...>();
117 bits_ |= ((value_type{1} << kBitsToSet) | ...);
118 return *this;
119 }
120
121 constexpr BitSet& reset() {
122 bits_ = 0;
123 return *this;
124 }
125
126 template <size_t... kBitsToReset>
127 constexpr BitSet& reset() {
128 CheckBitIndices<kBitsToReset...>();
129 bits_ &= ~((value_type{1} << kBitsToReset) | ...);
130 return *this;
131 }
132
133 constexpr BitSet& flip() {
134 bits_ ^= kAllSet;
135 return *this;
136 }
137
138 template <size_t... kBitsToFlip>
139 constexpr BitSet& flip() {
140 CheckBitIndices<kBitsToFlip...>();
141 bits_ ^= ((value_type{1} << kBitsToFlip) | ...);
142 return *this;
143 }
144
145 // Bitwise operators
146
147 constexpr BitSet& operator&=(const BitSet& other) {
148 bits_ &= other.bits_;
149 return *this;
150 }
151 constexpr BitSet& operator|=(const BitSet& other) {
152 bits_ |= other.bits_;
153 return *this;
154 }
155 constexpr BitSet& operator^=(const BitSet& other) {
156 bits_ ^= other.bits_;
157 return *this;
158 }
159
160 constexpr BitSet& operator<<=(size_t pos) {
161 bits_ = (bits_ << pos) & kAllSet;
162 return *this;
163 }
164
165 constexpr BitSet& operator>>=(size_t pos) {
166 bits_ >>= pos;
167 return *this;
168 }
169
170 constexpr BitSet operator~() const {
171 return BitSet(static_cast<value_type>(~bits_ & kAllSet));
172 }
173
174 friend constexpr BitSet operator&(const BitSet& lhs, const BitSet& rhs) {
175 return BitSet(lhs.bits_ & rhs.bits_);
176 }
177 friend constexpr BitSet operator|(const BitSet& lhs, const BitSet& rhs) {
178 return BitSet(lhs.bits_ | rhs.bits_);
179 }
180 friend constexpr BitSet operator^(const BitSet& lhs, const BitSet& rhs) {
181 return BitSet(lhs.bits_ ^ rhs.bits_);
182 }
183
184 friend constexpr BitSet operator<<(const BitSet& bs, size_t pos) {
185 return BitSet((bs.bits_ << pos) & kAllSet);
186 }
187
188 friend constexpr BitSet operator>>(const BitSet& bs, size_t pos) {
189 return BitSet(bs.bits_ >> pos);
190 }
191
193 constexpr value_type to_integer() const { return bits_; }
194
195 private:
196 static_assert(kBits <= 64, "BitSet currently only supports up to 64 bits");
197
198 template <size_t>
199 friend class BitSet;
200
201 template <size_t... kIndices>
202 static constexpr void CheckBitIndices() {
203 static_assert(((kIndices < kBits) && ...),
204 "The specified bit index is out of range of this BitSet");
205 }
206
207 static constexpr value_type LittleBoolsToBits() { return 0; }
208
209 template <typename... Args,
210 typename = std::enable_if_t<(std::is_same_v<Args, bool> && ...)>>
211 static constexpr value_type LittleBoolsToBits(bool first, Args... bits) {
212 return (first ? (value_type{1} << (kBits - sizeof...(Args) - 1)) : 0) |
213 LittleBoolsToBits(bits...);
214 }
215
216 explicit constexpr BitSet(value_type bits) : bits_(bits) {}
217
218 static constexpr value_type kAllSet =
219 static_cast<value_type>(~value_type{0}) >>
220 (sizeof(value_type) * 8 - kBits);
221
222 value_type bits_;
223};
224
226
227// Specialization of `BitSet` for zero bits.
228//
229// This specialization provides a zero-size bitset with a minimal API,
230// satisfying the requirements of a bitset while consuming no storage.
231template <>
232class BitSet<0> {
233 public:
234 using value_type = uint8_t;
235
236 constexpr BitSet() = default;
237
238 constexpr BitSet(const BitSet&) = default;
239 constexpr BitSet& operator=(const BitSet&) = default;
240
241 static constexpr BitSet LittleEndian() { return BitSet(); }
242
243 [[nodiscard]] constexpr bool operator==(const BitSet&) const { return true; }
244 [[nodiscard]] constexpr bool operator!=(const BitSet&) const { return false; }
245
246 template <size_t kBit>
247 [[nodiscard]] constexpr bool test() const {
248 static_assert(kBit < 0, "test() is not supported for zero-bit BitSets");
249 return false;
250 }
251
252 [[nodiscard]] constexpr bool all() const { return true; }
253 [[nodiscard]] constexpr bool any() const { return false; }
254 [[nodiscard]] constexpr bool none() const { return true; }
255
256 constexpr size_t count() const { return 0; }
257 constexpr size_t size() const { return 0; }
258
259 // Indiviadual bit variants of set, reset, and flip are not supported.
260 constexpr BitSet& set() { return *this; }
261 constexpr BitSet& reset() { return *this; }
262 constexpr BitSet& flip() { return *this; }
263
264 constexpr BitSet& operator&=(const BitSet&) { return *this; }
265 constexpr BitSet& operator|=(const BitSet&) { return *this; }
266 constexpr BitSet& operator^=(const BitSet&) { return *this; }
267
268 constexpr BitSet& operator<<=(size_t) { return *this; }
269 constexpr BitSet& operator>>=(size_t) { return *this; }
270
271 constexpr BitSet operator~() const { return *this; }
272
273 friend constexpr BitSet operator&(const BitSet&, const BitSet&) {
274 return BitSet();
275 }
276 friend constexpr BitSet operator|(const BitSet&, const BitSet&) {
277 return BitSet();
278 }
279 friend constexpr BitSet operator^(const BitSet&, const BitSet&) {
280 return BitSet();
281 }
282
283 friend constexpr BitSet operator<<(const BitSet&, size_t) { return BitSet(); }
284 friend constexpr BitSet operator>>(const BitSet&, size_t) { return BitSet(); }
285
286 constexpr value_type to_integer() const { return 0; }
287};
288
289} // namespace pw
Definition: bitset.h:34
constexpr value_type to_integer() const
Returns the bit set as an integer.
Definition: bitset.h:193
static constexpr BitSet LittleEndian(Args... bits_least_to_most_significant)
Definition: bitset.h:58
std::conditional_t< kBits<=8, uint8_t, std::conditional_t< kBits<=16, uint16_t, std::conditional_t< kBits<=32, uint32_t, uint64_t > > > value_type
Definition: bitset.h:43
static constexpr BitSet Of()
Definition: bitset.h:48
The Pigweed namespace.
Definition: alignment.h:27