#pragma once #include "../jabyengine_defines.hpp" #include "types.hpp" namespace JabyEngine { namespace bit { template static constexpr T set(T raw_value, size_t bit); namespace value { template static constexpr T set_normalized(T raw_value, T value, size_t start_bit, size_t length); } } struct ClearBit { uint16_t pos; constexpr ClearBit(uint16_t bit_pos) : pos(bit_pos) { } }; struct Bit { uint16_t pos; constexpr Bit(uint16_t bit_pos) : pos(bit_pos) { } constexpr ClearBit operator!() const { return ClearBit(this->pos); } template constexpr explicit operator T() const { return bit::set(0, this->pos); } }; struct BitRange { template using RangeValuePair = pair; uint16_t pos; uint16_t length; constexpr BitRange(uint16_t pos, uint16_t length) : pos(pos), length(length) { } static constexpr BitRange from_to(uint16_t first_bit, uint16_t last_bit) { return BitRange(first_bit, (last_bit - first_bit) + 1); } template constexpr RangeValuePair with(T value) const { return {*this, value}; } template constexpr T as_value(T value) const { return bit::value::set_normalized(static_cast(0), value, this->pos, this->length); } template constexpr RangeValuePair range_max() const { return BitRange::with((1 << this->length) - 1); } }; namespace bit { template static constexpr T clear(T raw_value, size_t bit) { return (raw_value & ~(1 << bit)); } template static constexpr T clear(T raw_value, Bit bit) { return clear(raw_value, bit.pos); } template static constexpr T set(T raw_value, size_t bit) { return (raw_value | (1 << bit)); } template static constexpr T set(T raw_value, Bit bit) { return set(raw_value, bit.pos); } template static constexpr T set(T raw_value, ClearBit bit) { return clear(raw_value, bit.pos); } template static constexpr bool is_set(T raw_value, size_t bit) { return static_cast(raw_value & (1 << bit)); } template static constexpr bool is_set(T raw_value, Bit bit) { return is_set(raw_value, bit.pos); } namespace value { namespace helper { template static constexpr T crop_value(T raw_value, size_t length) { return (raw_value & ((1 << length) - 1)); } template static constexpr T range_mask(size_t start_bit, size_t length) { return (((1 << length) - 1) << start_bit); } } template static constexpr T clear_normalized(T raw_value, size_t start_bit, size_t length) { return (raw_value & ~helper::range_mask(start_bit, length)); } template static constexpr T set_normalized(T raw_value, T value, size_t start_bit, size_t length) { return (clear_normalized(raw_value, start_bit, length) | (helper::crop_value(value, length) << start_bit)); } template static constexpr T set_normalized(T raw_value, BitRange bits, T value) { return set_normalized(raw_value, value, bits.pos, bits.length); } template static constexpr T set_normalized(T raw_value, const BitRange::RangeValuePair &value_pair) { return set_normalized(raw_value, value_pair.first, static_cast(value_pair.second)); } template static constexpr T get_normalized(T raw_value, size_t start_bit, size_t length) { return helper::crop_value((raw_value & helper::range_mask(start_bit, length)) >> start_bit, length); } template static constexpr T get_normalized(T raw_value, BitRange range) { return get_normalized(raw_value, range.pos, range.length); } } template static constexpr S cast(T value) { return *reinterpret_cast(&value); } } static constexpr uint32_t operator<<(uint32_t value, const Bit& bit) { return value << bit.pos; } } #define __start_end_bit2_start_length(start_bit, end_bit) start_bit, (end_bit - start_bit + 1)