ReXGlue SDK
Loading...
Searching...
No Matches
bit.h
Go to the documentation of this file.
1
13
14#pragma once
15
16#include <algorithm>
17#include <bit>
18#include <climits>
19#include <cstddef>
20#include <cstdint>
21#include <cstring>
22#include <span>
23#include <type_traits>
24#include <utility>
25#include <vector>
26
27#include <rex/platform.h>
28#include <rex/types.h>
29
30namespace rex {
31
33template <typename T>
34constexpr bool is_pow2(T value) {
35 return (value & (value - 1)) == 0;
36}
37
43template <typename T>
44T next_pow2(T value) {
45 value--;
46 value |= value >> 1;
47 value |= value >> 2;
48 value |= value >> 4;
49 value |= value >> 8;
50 value |= value >> 16;
51 value++;
52 return value;
53}
54
61constexpr u32 MakeBitmask(u32 a, u32 b) {
62 return (static_cast<u32>(-1) >> (31 - b)) & ~((1u << a) - 1);
63}
64
71constexpr u32 select_bits(u32 value, u32 a, u32 b) {
72 return (value & MakeBitmask(a, b)) >> a;
73}
74
80template <class T>
81constexpr u32 BitCount(T v) {
82 return static_cast<u32>(std::popcount(v));
83}
84
86inline u8 lzcnt(u8 v) {
87 return static_cast<u8>(std::countl_zero(v));
88}
89
91inline u8 lzcnt(u16 v) {
92 return static_cast<u8>(std::countl_zero(v));
93}
94
96inline u8 lzcnt(u32 v) {
97 return static_cast<u8>(std::countl_zero(v));
98}
99
101inline u8 lzcnt(u64 v) {
102 return static_cast<u8>(std::countl_zero(v));
103}
104
106inline u8 tzcnt(u8 v) {
107 return static_cast<u8>(std::countr_zero(v));
108}
109
111inline u8 tzcnt(u16 v) {
112 return static_cast<u8>(std::countr_zero(v));
113}
114
116inline u8 tzcnt(u32 v) {
117 return static_cast<u8>(std::countr_zero(v));
118}
119
121inline u8 tzcnt(u64 v) {
122 return static_cast<u8>(std::countr_zero(v));
123}
124
130inline u8 lzcnt(i8 v) {
131 return lzcnt(static_cast<u8>(v));
132}
133
139inline u8 lzcnt(i16 v) {
140 return lzcnt(static_cast<u16>(v));
141}
142
148inline u8 lzcnt(i32 v) {
149 return lzcnt(static_cast<u32>(v));
150}
151
157inline u8 lzcnt(i64 v) {
158 return lzcnt(static_cast<u64>(v));
159}
160
166inline u8 tzcnt(i8 v) {
167 return tzcnt(static_cast<u8>(v));
168}
169
175inline u8 tzcnt(i16 v) {
176 return tzcnt(static_cast<u16>(v));
177}
178
184inline u8 tzcnt(i32 v) {
185 return tzcnt(static_cast<u32>(v));
186}
187
193inline u8 tzcnt(i64 v) {
194 return tzcnt(static_cast<u64>(v));
195}
196
203inline bool bit_scan_forward(u32 v, u32* out_first_set_index) {
204 if (v == 0) {
205 return false;
206 }
207 *out_first_set_index = static_cast<u32>(std::countr_zero(v));
208 return true;
209}
210
217inline bool bit_scan_forward(u64 v, u32* out_first_set_index) {
218 if (v == 0) {
219 return false;
220 }
221 *out_first_set_index = static_cast<u32>(std::countr_zero(v));
222 return true;
223}
224
232inline bool bit_scan_forward(i32 v, u32* out_first_set_index) {
233 return bit_scan_forward(static_cast<u32>(v), out_first_set_index);
234}
235
243inline bool bit_scan_forward(i64 v, u32* out_first_set_index) {
244 return bit_scan_forward(static_cast<u64>(v), out_first_set_index);
245}
246
252template <typename T>
253inline T log2_floor(T v) {
254 return sizeof(T) * 8 - 1 - lzcnt(v);
255}
256
262template <typename T>
263inline T log2_ceil(T v) {
264 return sizeof(T) * 8 - lzcnt(v - 1);
265}
266
273template <typename T>
274inline T RotateLeft(T v, u8 sh) {
275 return (v << sh) | (v >> ((sizeof(T) * 8) - sh));
276}
277
279class REX_API BitMap {
280 public:
281 BitMap();
282
288 BitMap(size_t size_bits);
289
296 BitMap(u64* data, size_t size_bits);
297
303 size_t AcquireEntry();
304
306 void ReleaseEntry(size_t index);
307
313 void Resize(size_t new_size_bits);
314
315 void Reset();
316
318 const std::vector<u64> GetWords() const { return data_; }
319
320 std::vector<u64>& GetWords() { return data_; }
321
322 private:
323 const static size_t kDataSize = 8;
324 const static size_t kDataSizeBits = kDataSize * 8;
325 std::vector<u64> data_;
326};
327
337template <typename Block>
338std::pair<size_t, size_t> GetNextRangeUnset(const Block* bits, size_t first, size_t length) {
339 if (!length) {
340 return std::make_pair(first, static_cast<size_t>(0));
341 }
342 size_t last = first + length - 1;
343 const size_t block_bits = sizeof(Block) * CHAR_BIT;
344 size_t block_first = first / block_bits;
345 size_t block_last = last / block_bits;
346 size_t range_start = SIZE_MAX;
347 for (size_t i = block_first; i <= block_last; ++i) {
348 Block block = bits[i];
349 if (i == block_first) {
350 block |= (Block(1) << (first & (block_bits - 1))) - 1;
351 }
352 if (i == block_last && (last & (block_bits - 1)) != block_bits - 1) {
353 block |= ~((Block(1) << ((last & (block_bits - 1)) + 1)) - 1);
354 }
355 while (true) {
356 u32 block_bit;
357 if (range_start == SIZE_MAX) {
358 if (!rex::bit_scan_forward(~block, &block_bit)) {
359 break;
360 }
361 range_start = i * block_bits + block_bit;
362 } else {
363 Block block_bits_set_from_start = block;
364 if (i == range_start / block_bits) {
365 block_bits_set_from_start &= ~((Block(1) << (range_start & (block_bits - 1))) - 1);
366 }
367 if (!rex::bit_scan_forward(block_bits_set_from_start, &block_bit)) {
368 break;
369 }
370 return std::make_pair(range_start, (i * block_bits) + block_bit - range_start);
371 }
372 }
373 }
374 if (range_start != SIZE_MAX) {
375 return std::make_pair(range_start, last + static_cast<size_t>(1) - range_start);
376 }
377 return std::make_pair(first + length, static_cast<size_t>(0));
378}
379
388template <typename Block>
389void SetRange(Block* bits, size_t first, size_t length) {
390 if (!length) {
391 return;
392 }
393 size_t last = first + length - 1;
394 const size_t block_bits = sizeof(Block) * CHAR_BIT;
395 size_t block_first = first / block_bits;
396 size_t block_last = last / block_bits;
397 Block set_first = ~((Block(1) << (first & (block_bits - 1))) - 1);
398 Block set_last = ~Block(0);
399 if ((last & (block_bits - 1)) != (block_bits - 1)) {
400 set_last &= (Block(1) << ((last & (block_bits - 1)) + 1)) - 1;
401 }
402 if (block_first == block_last) {
403 bits[block_first] |= set_first & set_last;
404 return;
405 }
406 bits[block_first] |= set_first;
407 if (block_first + 1 < block_last) {
408 std::fill_n(bits + block_first + 1, block_last - (block_first + 1), ~Block(0));
409 }
410 bits[block_last] |= set_last;
411}
412
421template <typename E>
422inline constexpr bool is_flags_enum = false;
423
425template <typename E>
426concept FlagsEnum = std::is_enum_v<E> && is_flags_enum<E>;
427
428template <FlagsEnum E>
429[[nodiscard]] constexpr E operator|(E lhs, E rhs) {
430 return static_cast<E>(std::to_underlying(lhs) | std::to_underlying(rhs));
431}
432
433template <FlagsEnum E>
434[[nodiscard]] constexpr E operator&(E lhs, E rhs) {
435 return static_cast<E>(std::to_underlying(lhs) & std::to_underlying(rhs));
436}
437
438template <FlagsEnum E>
439[[nodiscard]] constexpr E operator^(E lhs, E rhs) {
440 return static_cast<E>(std::to_underlying(lhs) ^ std::to_underlying(rhs));
441}
442
443template <FlagsEnum E>
444[[nodiscard]] constexpr E operator~(E value) {
445 return static_cast<E>(~std::to_underlying(value));
446}
447
453template <FlagsEnum E>
454constexpr E& operator|=(E& lhs, E rhs) {
455 lhs = lhs | rhs;
456 return lhs;
457}
458
464template <FlagsEnum E>
465constexpr E& operator&=(E& lhs, E rhs) {
466 lhs = lhs & rhs;
467 return lhs;
468}
469
475template <FlagsEnum E>
476constexpr E& operator^=(E& lhs, E rhs) {
477 lhs = lhs ^ rhs;
478 return lhs;
479}
480
482template <FlagsEnum E>
483[[nodiscard]] constexpr bool HasFlags(E value, E flags) {
484 return (value & flags) == flags;
485}
486
494#define REX_RESTRICT_VAR __restrict
495
497template <typename Dst, typename Src>
498void Reinterpret(Dst& REX_RESTRICT_VAR dst, const Src& REX_RESTRICT_VAR src) {
499 static_assert(sizeof(Dst) == sizeof(Src));
500 static_assert(std::is_trivially_copyable_v<Dst>);
501 static_assert(std::is_trivially_copyable_v<Src>);
502 dst = std::bit_cast<Dst>(src);
503}
504
506template <typename Dst, typename Src>
507Dst Reinterpret(const Src& REX_RESTRICT_VAR src) {
508 Dst dst;
509 Reinterpret(dst, src);
510 return dst;
511}
512
518inline bool AreBitsEqual(std::span<const f32> a, std::span<const f32> b) {
519 return std::ranges::equal(
520 a, b, [](f32 x, f32 y) { return std::bit_cast<u32>(x) == std::bit_cast<u32>(y); });
521}
522
523} // namespace rex
#define REX_RESTRICT_VAR
Definition bit.h:494
BitMap(u64 *data, size_t size_bits)
size_t AcquireEntry()
const std::vector< u64 > GetWords() const
Definition bit.h:318
BitMap(size_t size_bits)
void ReleaseEntry(size_t index)
void Resize(size_t new_size_bits)
Definition bit.h:426
Definition app.h:36
constexpr bool is_flags_enum
Definition bit.h:422
constexpr E & operator&=(E &lhs, E rhs)
Definition bit.h:465
void Reinterpret(Dst &REX_RESTRICT_VAR dst, const Src &REX_RESTRICT_VAR src)
Definition bit.h:498
constexpr u32 select_bits(u32 value, u32 a, u32 b)
Definition bit.h:71
T log2_floor(T v)
Definition bit.h:253
u8 tzcnt(u8 v)
Definition bit.h:106
constexpr bool is_pow2(T value)
Definition bit.h:34
constexpr bool HasFlags(E value, E flags)
Definition bit.h:483
bool AreBitsEqual(std::span< const f32 > a, std::span< const f32 > b)
Definition bit.h:518
constexpr u32 BitCount(T v)
Definition bit.h:81
T RotateLeft(T v, u8 sh)
Definition bit.h:274
T log2_ceil(T v)
Definition bit.h:263
void SetRange(Block *bits, size_t first, size_t length)
Definition bit.h:389
bool bit_scan_forward(u32 v, u32 *out_first_set_index)
Definition bit.h:203
constexpr u32 MakeBitmask(u32 a, u32 b)
Definition bit.h:61
u8 lzcnt(u8 v)
Definition bit.h:86
constexpr E & operator|=(E &lhs, E rhs)
Definition bit.h:454
T next_pow2(T value)
Definition bit.h:44
std::pair< size_t, size_t > GetNextRangeUnset(const Block *bits, size_t first, size_t length)
Definition bit.h:338
constexpr E & operator^=(E &lhs, E rhs)
Definition bit.h:476
Platform flags, packing macros and export markers.
#define REX_API
Definition platform.h:177
Integer types, byte order wrappers and size literals.