#ifndef BITS_HPP_ #define BITS_HPP_ #include "util.hpp" #include template requires std::unsigned_integral // ReSharper disable once CppRedundantInlineSpecifier INLINE inline auto create_mask(const u8 first, const u8 last) -> T { // If the mask width is equal the type width return all 1s instead of shifting // as shifting by type-width is undefined behavior. if (static_cast(last - first + 1) >= sizeof(T) * 8) { return ~T{0}; } // Example: first=4, last=7, 7-4+1=4 // 1 << 4 = 0b00010000 // 32 - 1 = 0b00001111 // 31 << 4 = 0b11110000 // Subtracting 1 generates a consecutive mask. return ((T{1} << (last - first + 1)) - 1) << first; } template requires std::unsigned_integral // ReSharper disable once CppRedundantInlineSpecifier INLINE inline auto clear_bits(T& bits, const u8 first, const u8 last) -> void { const T mask = create_mask(first, last); bits = bits & ~mask; } template requires std::unsigned_integral && std::unsigned_integral // ReSharper disable once CppRedundantInlineSpecifier INLINE inline auto set_bits(T& bits, const u8 first, const u8 last, const U value) -> void { const T mask = create_mask(first, last); // Example: first=4, last=6, value=0b1110, bits = 0b 01111110 // mask = 0b 01110000 // bits & ~mask = 0b 00001110 // value << 4 = 0b 11100000 // (value << 4) & mask = 0b 01100000 // (bits & ~mask) | (value << 4) & mask = 0b 01101110 // Insert position: ^^^ // First clear the bits, then | with the value positioned at the insertion point. // The value may be larger than [first, last], extra bits are ignored. bits = (bits & ~mask) | ((static_cast(value) << first) & mask); } template requires std::unsigned_integral // ReSharper disable once CppRedundantInlineSpecifier INLINE inline auto get_bits(const T bits, const u8 first, const u8 last) -> T { const T mask = create_mask(first, last); // We can >> without sign extension because T is unsigned_integral return (bits & mask) >> first; } auto print_bitmap(u64 bitmap, u8 w, u8 h, const std::string& title) -> void; #endif