BizHawk/waterbox/ares64/ares/nall/primitives/bit-range.hpp

262 lines
7.0 KiB
C++

#pragma once
namespace nall {
/* static BitRange */
template<s32 Precision, s32 Lo, s32 Hi> struct BitRange {
static_assert(Precision >= 1 && Precision <= 64);
static_assert(Lo < Precision && Hi < Precision);
static_assert(Lo <= Hi);
using type =
conditional_t<Precision <= 8, u8,
conditional_t<Precision <= 16, u16,
conditional_t<Precision <= 32, u32,
conditional_t<Precision <= 64, u64,
void>>>>;
enum : u32 { lo = Lo < 0 ? Precision + Lo : Lo };
enum : u32 { hi = Hi < 0 ? Precision + Hi : Hi };
enum : type { mask = ~0ull >> 64 - (hi - lo + 1) << lo };
enum : u32 { shift = lo };
BitRange(const BitRange& source) = delete;
BitRange(BitRange&& source) = default;
auto& operator=(const BitRange& source) {
target = target & ~mask | ((source.target & source.mask) >> source.shift) << shift & mask;
return *this;
}
template<typename T> BitRange(T* source) : target((type&)*source) {
static_assert(sizeof(T) == sizeof(type));
}
operator type() const {
return (target & mask) >> shift;
}
auto operator++(s32) {
auto value = (target & mask) >> shift;
target = target & ~mask | target + (1 << shift) & mask;
return value;
}
auto operator--(s32) {
auto value = (target & mask) >> shift;
target = target & ~mask | target - (1 << shift) & mask;
return value;
}
auto& operator++() {
target = target & ~mask | target + (1 << shift) & mask;
return *this;
}
auto& operator--() {
target = target & ~mask | target - (1 << shift) & mask;
return *this;
}
template<typename T> auto& operator=(const T& source) {
type value = source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> auto& operator*=(const T& source) {
auto value = ((target & mask) >> shift) * source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> auto& operator/=(const T& source) {
auto value = ((target & mask) >> shift) / source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> auto& operator%=(const T& source) {
auto value = ((target & mask) >> shift) % source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> auto& operator+=(const T& source) {
auto value = ((target & mask) >> shift) + source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> auto& operator-=(const T& source) {
auto value = ((target & mask) >> shift) - source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> auto& operator<<=(const T& source) {
auto value = ((target & mask) >> shift) << source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> auto& operator>>=(const T& source) {
auto value = ((target & mask) >> shift) >> source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> auto& operator&=(const T& source) {
type value = source;
target = target & (~mask | value << shift & mask);
return *this;
}
template<typename T> auto& operator^=(const T& source) {
type value = source;
target = target ^ value << shift & mask;
return *this;
}
template<typename T> auto& operator|=(const T& source) {
type value = source;
target = target | value << shift & mask;
return *this;
}
private:
type& target;
};
/* dynamic BitRange */
template<typename Type, s32 Precision = Type::bits()> struct DynamicBitRange {
static_assert(Precision >= 1 && Precision <= 64);
using type =
conditional_t<Precision <= 8, u8,
conditional_t<Precision <= 16, u16,
conditional_t<Precision <= 32, u32,
conditional_t<Precision <= 64, u64,
void>>>>;
DynamicBitRange(const DynamicBitRange& source) = delete;
DynamicBitRange(DynamicBitRange&& source) = default;
auto& operator=(const DynamicBitRange& source) {
target = target & ~mask | ((source.target & source.mask) >> source.shift) << shift & mask;
return *this;
}
DynamicBitRange(Type& source, s32 index) : target(source) {
if(index < 0) index = Precision + index;
mask = 1ull << index;
shift = index;
}
DynamicBitRange(Type& source, s32 lo, s32 hi) : target(source) {
if(lo < 0) lo = Precision + lo;
if(hi < 0) hi = Precision + hi;
if(lo > hi) swap(lo, hi);
mask = ~0ull >> 64 - (hi - lo + 1) << lo;
shift = lo;
}
operator type() const {
return (target & mask) >> shift;
}
auto operator++(s32) {
auto value = (target & mask) >> shift;
target = target & ~mask | target + (1 << shift) & mask;
return value;
}
auto operator--(s32) {
auto value = (target & mask) >> shift;
target = target & ~mask | target - (1 << shift) & mask;
return value;
}
auto& operator++() {
target = target & ~mask | target + (1 << shift) & mask;
return *this;
}
auto& operator--() {
target = target & ~mask | target - (1 << shift) & mask;
return *this;
}
template<typename T> auto& operator=(const T& source) {
type value = source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> auto& operator*=(const T& source) {
auto value = ((target & mask) >> shift) * source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> auto& operator/=(const T& source) {
auto value = ((target & mask) >> shift) / source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> auto& operator%=(const T& source) {
auto value = ((target & mask) >> shift) % source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> auto& operator+=(const T& source) {
auto value = ((target & mask) >> shift) + source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> auto& operator-=(const T& source) {
auto value = ((target & mask) >> shift) - source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> auto& operator<<=(const T& source) {
auto value = ((target & mask) >> shift) << source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> auto& operator>>=(const T& source) {
auto value = ((target & mask) >> shift) >> source;
target = target & ~mask | value << shift & mask;
return *this;
}
template<typename T> auto& operator&=(const T& source) {
type value = source;
target = target & (~mask | value << shift & mask);
return *this;
}
template<typename T> auto& operator^=(const T& source) {
type value = source;
target = target ^ value << shift & mask;
return *this;
}
template<typename T> auto& operator|=(const T& source) {
type value = source;
target = target | value << shift & mask;
return *this;
}
private:
Type& target;
type mask;
u32 shift;
};
}