OpenTTD Source 20250312-master-gcdcc6b491d
bitmath_func.hpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
10#ifndef BITMATH_FUNC_HPP
11#define BITMATH_FUNC_HPP
12
31template <typename T>
32debug_inline constexpr static uint GB(const T x, const uint8_t s, const uint8_t n)
33{
34 return (x >> s) & (((T)1U << n) - 1);
35}
36
57template <typename T, typename U>
58constexpr T SB(T &x, const uint8_t s, const uint8_t n, const U d)
59{
60 x &= (T)(~((((T)1U << n) - 1) << s));
61 x |= (T)(d << s);
62 return x;
63}
64
82template <typename T, typename U>
83constexpr T AB(T &x, const uint8_t s, const uint8_t n, const U i)
84{
85 const T mask = ((((T)1U << n) - 1) << s);
86 x = (T)((x & ~mask) | ((x + (i << s)) & mask));
87 return x;
88}
89
102template <typename T>
103debug_inline constexpr bool HasBit(const T x, const uint8_t y)
104{
105 return (x & ((T)1U << y)) != 0;
106}
107
120template <typename T>
121constexpr T SetBit(T &x, const uint8_t y)
122{
123 return x = (T)(x | ((T)1U << y));
124}
125
138template <typename T>
139constexpr T ClrBit(T &x, const uint8_t y)
140{
141 return x = (T)(x & ~((T)1U << y));
142}
143
154#define CLRBITS(x, y) ((x) &= ~(y))
155
168template <typename T>
169constexpr T ToggleBit(T &x, const uint8_t y)
170{
171 return x = (T)(x ^ ((T)1U << y));
172}
173
187template <typename T>
188constexpr T AssignBit(T &x, const uint8_t y, bool value)
189{
190 return SB<T>(x, y, 1, value ? 1 : 0);
191}
192
200template <typename T>
201constexpr uint8_t FindFirstBit(T x)
202{
203 if (x == 0) return 0;
204
205 if constexpr (std::is_enum_v<T>) {
206 return std::countr_zero<std::underlying_type_t<T>>(x);
207 } else {
208 return std::countr_zero(x);
209 }
210}
211
219template <typename T>
220constexpr uint8_t FindLastBit(T x)
221{
222 if (x == 0) return 0;
223
224 return std::numeric_limits<T>::digits - std::countl_zero(x) - 1;
225}
226
237template <typename T>
238constexpr T KillFirstBit(T value)
239{
240 return value &= (T)(value - 1);
241}
242
249template <typename T>
250constexpr uint CountBits(T value)
251{
252 if constexpr (std::is_enum_v<T>) {
253 return std::popcount<std::underlying_type_t<T>>(value);
254 } else {
255 return std::popcount(value);
256 }
257}
258
265template <typename T>
266constexpr bool HasExactlyOneBit(T value)
267{
268 return value != 0 && (value & (value - 1)) == 0;
269}
270
277template <typename T>
278constexpr bool HasAtMostOneBit(T value)
279{
280 return (value & (value - 1)) == 0;
281}
282
288template <typename Tbitpos = uint, typename Tbitset = uint>
290 struct Iterator {
291 typedef Tbitpos value_type;
292 typedef value_type *pointer;
293 typedef value_type &reference;
294 typedef size_t difference_type;
295 typedef std::forward_iterator_tag iterator_category;
296
297 explicit Iterator(Tbitset bitset) : bitset(bitset), bitpos(static_cast<Tbitpos>(0))
298 {
299 this->Validate();
300 }
301
302 bool operator==(const Iterator &other) const
303 {
304 return this->bitset == other.bitset;
305 }
306 Tbitpos operator*() const { return this->bitpos; }
307 Iterator & operator++() { this->Next(); this->Validate(); return *this; }
308
309 private:
310 Tbitset bitset;
311 Tbitpos bitpos;
312 void Validate()
313 {
314 if (this->bitset != 0) {
315 typename std::make_unsigned<Tbitset>::type unsigned_value = this->bitset;
316 this->bitpos = static_cast<Tbitpos>(FindFirstBit(unsigned_value));
317 }
318 }
319 void Next()
320 {
321 this->bitset = KillFirstBit(this->bitset);
322 }
323 };
324
325 SetBitIterator(Tbitset bitset) : bitset(bitset) {}
326 Iterator begin() { return Iterator(this->bitset); }
327 Iterator end() { return Iterator(static_cast<Tbitset>(0)); }
328 bool empty() { return this->begin() == this->end(); }
329
330private:
331 Tbitset bitset;
332};
333
334namespace std {
341 template <typename T>
342 [[nodiscard]] constexpr enable_if_t<is_integral_v<T>, T> byteswap(T x) noexcept
343 {
344 if constexpr (sizeof(T) == 1) return x;
345 if constexpr (sizeof(T) == 2) return (x >> 8) | (x << 8);
346 if constexpr (sizeof(T) == 4) return ((x >> 24) & 0xFF) | ((x >> 8) & 0xFF00) | ((x << 8) & 0xFF0000) | ((x << 24) & 0xFF000000);
347 }
348}
349
350#endif /* BITMATH_FUNC_HPP */
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr bool HasExactlyOneBit(T value)
Test whether value has exactly 1 bit set.
constexpr T AssignBit(T &x, const uint8_t y, bool value)
Assigns a bit in a variable.
constexpr T SB(T &x, const uint8_t s, const uint8_t n, const U d)
Set n bits in x starting at bit s to d.
constexpr uint8_t FindLastBit(T x)
Search the last set bit in a value.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
constexpr uint8_t FindFirstBit(T x)
Search the first set bit in a value.
constexpr uint CountBits(T value)
Counts the number of set bits in a variable.
constexpr bool HasAtMostOneBit(T value)
Test whether value has at most 1 bit set.
constexpr T AB(T &x, const uint8_t s, const uint8_t n, const U i)
Add i to n bits of x starting at bit s.
constexpr enable_if_t< is_integral_v< T >, T > byteswap(T x) noexcept
Custom implementation of std::byteswap; remove once we build with C++23.
debug_inline static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
constexpr T ToggleBit(T &x, const uint8_t y)
Toggles a bit in a variable.
constexpr T KillFirstBit(T value)
Clear the first bit in an integer.
constexpr T ClrBit(T &x, const uint8_t y)
Clears a bit in a variable.
Iterable ensemble of each set bit in a value.