mirror of
https://github.com/RPCSX/rpcsx.git
synced 2025-12-06 07:12:14 +01:00
fix blockpool & dmem implementation modernize blockpool & dmem io devices use budgets per allocation add serialization support for MemoryTableWithPayload and AddressRange utils add format support for EnumBitSet util implemented trace formatter per syscall increased allowed reference count for Ref
349 lines
9.9 KiB
C++
349 lines
9.9 KiB
C++
#pragma once
|
|
|
|
/*
|
|
This header implements EnumBitSet<> class for scoped enum types (enum class).
|
|
To enable EnumBitSet<>, enum scope must contain `bitset_last` entry.
|
|
|
|
enum class flagzz : u32
|
|
{
|
|
flag1, // Bit indices start from zero
|
|
flag2,
|
|
|
|
bitset_last = flag2
|
|
};
|
|
|
|
This also enables helper operators for this enum type.
|
|
|
|
Examples:
|
|
`flagzz::flag1 | flagzz::flag2` - bitset union
|
|
`flagzz::flag1 & ~flagzz::flag2` - bitset difference
|
|
Intersection (&) and symmetric difference (^) is also available.
|
|
*/
|
|
|
|
#include "format-base.hpp"
|
|
#include "rx/refl.hpp"
|
|
#include <type_traits>
|
|
|
|
namespace rx {
|
|
template <typename T>
|
|
concept BitSetEnum = std::is_enum_v<T> && requires { T::bitset_last; };
|
|
|
|
template <BitSetEnum T> class EnumBitSet;
|
|
|
|
namespace detail {
|
|
template <BitSetEnum T> class InvertedEnumBitSet final {
|
|
using underlying_type = std::underlying_type_t<T>;
|
|
underlying_type m_data;
|
|
constexpr InvertedEnumBitSet(underlying_type data) : m_data(data) {}
|
|
friend EnumBitSet<T>;
|
|
};
|
|
} // namespace detail
|
|
|
|
// Bitset type for enum class with available bits [0, fieldCount)
|
|
template <BitSetEnum T> class EnumBitSet final {
|
|
public:
|
|
// Underlying type
|
|
using underlying_type = std::underlying_type_t<T>;
|
|
|
|
private:
|
|
// Underlying value
|
|
underlying_type m_data;
|
|
|
|
// Value constructor
|
|
constexpr explicit EnumBitSet(int, underlying_type data) noexcept
|
|
: m_data(data) {}
|
|
|
|
public:
|
|
static constexpr std::size_t bitmax = sizeof(T) * 8;
|
|
static constexpr std::size_t bitsize =
|
|
static_cast<underlying_type>(T::bitset_last) + 1;
|
|
|
|
static_assert(std::is_enum_v<T>,
|
|
"BitSet<> error: invalid type (must be enum)");
|
|
static_assert(bitsize <= bitmax,
|
|
"BitSet<> error: failed to determine enum field count");
|
|
static_assert(bitsize != bitmax || std::is_unsigned_v<underlying_type>,
|
|
"BitSet<> error: invalid field count (sign bit)");
|
|
|
|
// Helper function
|
|
static constexpr underlying_type shift(T value) {
|
|
return static_cast<underlying_type>(1)
|
|
<< static_cast<underlying_type>(value);
|
|
}
|
|
|
|
constexpr EnumBitSet() = default;
|
|
|
|
// Construct from a single bit
|
|
constexpr EnumBitSet(T bit) noexcept : m_data(shift(bit)) {}
|
|
|
|
[[nodiscard]] constexpr underlying_type toUnderlying() const {
|
|
return m_data;
|
|
}
|
|
|
|
[[nodiscard]] static constexpr EnumBitSet
|
|
fromUnderlying(underlying_type raw) {
|
|
return EnumBitSet(0, raw);
|
|
}
|
|
|
|
// Test for empty bitset
|
|
constexpr explicit operator bool() const noexcept { return m_data != 0; }
|
|
|
|
// Extract underlying data
|
|
constexpr explicit operator underlying_type() const noexcept {
|
|
return m_data;
|
|
}
|
|
|
|
constexpr detail::InvertedEnumBitSet<T> operator~() const {
|
|
return static_cast<underlying_type>(~m_data);
|
|
}
|
|
|
|
[[deprecated("Use operator|=")]] constexpr EnumBitSet &
|
|
operator+=(EnumBitSet rhs) {
|
|
m_data |= static_cast<underlying_type>(rhs);
|
|
return *this;
|
|
}
|
|
|
|
constexpr EnumBitSet &operator|=(EnumBitSet rhs) {
|
|
m_data |= static_cast<underlying_type>(rhs);
|
|
return *this;
|
|
}
|
|
|
|
constexpr EnumBitSet &operator-=(EnumBitSet rhs) {
|
|
m_data &= ~static_cast<underlying_type>(rhs);
|
|
return *this;
|
|
}
|
|
|
|
constexpr EnumBitSet without(EnumBitSet rhs) const {
|
|
EnumBitSet result = *this;
|
|
result.m_data &= ~static_cast<underlying_type>(rhs);
|
|
return result;
|
|
}
|
|
|
|
constexpr EnumBitSet with(EnumBitSet rhs) const {
|
|
EnumBitSet result = *this;
|
|
result.m_data |= static_cast<underlying_type>(rhs);
|
|
return result;
|
|
}
|
|
|
|
constexpr EnumBitSet &operator&=(EnumBitSet rhs) {
|
|
m_data &= static_cast<underlying_type>(rhs);
|
|
return *this;
|
|
}
|
|
|
|
constexpr EnumBitSet &operator&=(detail::InvertedEnumBitSet<T> rhs) {
|
|
m_data &= rhs.m_data;
|
|
return *this;
|
|
}
|
|
|
|
constexpr EnumBitSet &operator^=(EnumBitSet rhs) {
|
|
m_data ^= static_cast<underlying_type>(rhs);
|
|
return *this;
|
|
}
|
|
|
|
[[deprecated("Use operator|")]] friend constexpr EnumBitSet
|
|
operator+(EnumBitSet lhs, EnumBitSet rhs) {
|
|
return EnumBitSet(0, lhs.m_data | rhs.m_data);
|
|
}
|
|
|
|
friend constexpr EnumBitSet operator-(EnumBitSet lhs, EnumBitSet rhs) {
|
|
return EnumBitSet(0, lhs.m_data & ~rhs.m_data);
|
|
}
|
|
|
|
friend constexpr EnumBitSet operator|(EnumBitSet lhs, EnumBitSet rhs) {
|
|
return EnumBitSet(0, lhs.m_data | rhs.m_data);
|
|
}
|
|
|
|
friend constexpr EnumBitSet operator&(EnumBitSet lhs, EnumBitSet rhs) {
|
|
return EnumBitSet(0, lhs.m_data & rhs.m_data);
|
|
}
|
|
|
|
friend constexpr EnumBitSet operator&(EnumBitSet lhs,
|
|
detail::InvertedEnumBitSet<T> rhs) {
|
|
return EnumBitSet(0, lhs.m_data & rhs.m_data);
|
|
}
|
|
|
|
friend constexpr EnumBitSet operator^(EnumBitSet lhs, EnumBitSet rhs) {
|
|
return EnumBitSet(0, lhs.m_data ^ rhs.m_data);
|
|
}
|
|
|
|
constexpr bool operator==(EnumBitSet rhs) const noexcept {
|
|
return m_data == rhs.m_data;
|
|
}
|
|
|
|
constexpr bool test_and_set(T bit) {
|
|
bool r = (m_data & shift(bit)) != 0;
|
|
m_data |= shift(bit);
|
|
return r;
|
|
}
|
|
|
|
constexpr bool test_and_reset(T bit) {
|
|
bool r = (m_data & shift(bit)) != 0;
|
|
m_data &= ~shift(bit);
|
|
return r;
|
|
}
|
|
|
|
constexpr bool test_and_complement(T bit) {
|
|
bool r = (m_data & shift(bit)) != 0;
|
|
m_data ^= shift(bit);
|
|
return r;
|
|
}
|
|
|
|
constexpr bool any_of(EnumBitSet arg) const {
|
|
return (m_data & arg.m_data) != 0;
|
|
}
|
|
|
|
constexpr bool all_of(EnumBitSet arg) const {
|
|
return (m_data & arg.m_data) == arg.m_data;
|
|
}
|
|
|
|
constexpr bool none_of(EnumBitSet arg) const {
|
|
return (m_data & arg.m_data) == 0;
|
|
}
|
|
|
|
constexpr underlying_type &raw() { return m_data; }
|
|
|
|
constexpr auto operator<=>(const EnumBitSet &) const = default;
|
|
};
|
|
|
|
template <BitSetEnum T> constexpr EnumBitSet<T> toBitSet(T bit) {
|
|
return EnumBitSet<T>(bit);
|
|
}
|
|
|
|
namespace bitset {
|
|
// Unary '+' operator: promote plain enum value to bitset value
|
|
template <BitSetEnum T>
|
|
[[deprecated("Use toBitSet(bit)")]] constexpr EnumBitSet<T> operator+(T bit) {
|
|
return EnumBitSet<T>(bit);
|
|
}
|
|
template <BitSetEnum T>
|
|
constexpr detail::InvertedEnumBitSet<T> operator~(T bit) {
|
|
return ~toBitSet(bit);
|
|
}
|
|
// Binary '+' operator: bitset union
|
|
template <BitSetEnum T, typename U>
|
|
requires(std::is_constructible_v<EnumBitSet<T>, U>)
|
|
[[deprecated("Use operator|")]] constexpr EnumBitSet<T>
|
|
operator+(T lhs, const U &rhs) {
|
|
return EnumBitSet<T>(lhs) | EnumBitSet<T>(rhs);
|
|
}
|
|
|
|
// Binary '+' operator: bitset union
|
|
template <typename U, BitSetEnum T>
|
|
requires(std::is_constructible_v<EnumBitSet<T>, U> && !std::is_enum_v<U>)
|
|
[[deprecated("Use operator|")]] constexpr EnumBitSet<T> operator+(const U &lhs,
|
|
T rhs) {
|
|
return EnumBitSet<T>(lhs) | EnumBitSet<T>(rhs);
|
|
}
|
|
|
|
// Binary '|' operator: bitset union
|
|
template <BitSetEnum T, typename U>
|
|
requires(std::is_constructible_v<EnumBitSet<T>, U>)
|
|
constexpr EnumBitSet<T> operator|(T lhs, const U &rhs) {
|
|
return EnumBitSet<T>(lhs) | EnumBitSet<T>(rhs);
|
|
}
|
|
|
|
// Binary '|' operator: bitset union
|
|
template <typename U, BitSetEnum T>
|
|
requires(std::is_constructible_v<EnumBitSet<T>, U> && !std::is_enum_v<U>)
|
|
constexpr EnumBitSet<T> operator|(const U &lhs, T rhs) {
|
|
return EnumBitSet<T>(lhs) | EnumBitSet<T>(rhs);
|
|
}
|
|
|
|
// Binary '-' operator: bitset difference
|
|
template <BitSetEnum T, typename U>
|
|
requires(std::is_constructible_v<EnumBitSet<T>, U>)
|
|
constexpr EnumBitSet<T> operator-(T lhs, const U &rhs) {
|
|
return EnumBitSet<T>(lhs) - EnumBitSet<T>(rhs);
|
|
}
|
|
|
|
// Binary '-' operator: bitset difference
|
|
template <typename U, BitSetEnum T>
|
|
requires(std::is_constructible_v<EnumBitSet<T>, U> && !std::is_enum_v<U>)
|
|
constexpr EnumBitSet<T> operator-(const U &lhs, T rhs) {
|
|
return EnumBitSet<T>(lhs) - EnumBitSet<T>(rhs);
|
|
}
|
|
|
|
// Binary '&' operator: bitset intersection
|
|
template <BitSetEnum T, typename U>
|
|
requires(std::is_constructible_v<EnumBitSet<T>, U>)
|
|
constexpr EnumBitSet<T> operator&(T lhs, const U &rhs) {
|
|
return EnumBitSet<T>(lhs) & EnumBitSet<T>(rhs);
|
|
}
|
|
|
|
// Binary '&' operator: bitset intersection
|
|
template <typename U, BitSetEnum T>
|
|
requires(std::is_constructible_v<EnumBitSet<T>, U> && !std::is_enum_v<U>)
|
|
constexpr EnumBitSet<T> operator&(const U &lhs, T rhs) {
|
|
return EnumBitSet<T>(lhs) & EnumBitSet<T>(rhs);
|
|
}
|
|
|
|
// Binary '&' operator: bitset intersection
|
|
template <BitSetEnum T, typename U>
|
|
constexpr EnumBitSet<T> operator&(T lhs, detail::InvertedEnumBitSet<T> rhs) {
|
|
return EnumBitSet<T>(lhs) & rhs;
|
|
}
|
|
|
|
// Binary '^' operator: bitset symmetric difference
|
|
template <BitSetEnum T, typename U>
|
|
requires(std::is_constructible_v<EnumBitSet<T>, U>)
|
|
constexpr EnumBitSet<T> operator^(T lhs, const U &rhs) {
|
|
return EnumBitSet<T>(lhs) ^ EnumBitSet<T>(rhs);
|
|
}
|
|
|
|
// Binary '^' operator: bitset symmetric difference
|
|
template <typename U, BitSetEnum T>
|
|
requires(std::is_constructible_v<EnumBitSet<T>, U> && !std::is_enum_v<U>)
|
|
constexpr EnumBitSet<T> operator^(const U &lhs, T rhs) {
|
|
return EnumBitSet<T>(lhs) ^ EnumBitSet<T>(rhs);
|
|
}
|
|
} // namespace bitset
|
|
} // namespace rx
|
|
|
|
template <typename T>
|
|
requires requires(rx::format_parse_context &ctx) {
|
|
rx::formatter<T>().parse(ctx);
|
|
}
|
|
struct rx::formatter<rx::EnumBitSet<T>> {
|
|
constexpr rx::format_parse_context::iterator
|
|
parse(rx::format_parse_context &ctx) {
|
|
return ctx.begin();
|
|
}
|
|
|
|
rx::format_context::iterator format(rx::EnumBitSet<T> bitSet,
|
|
rx::format_context &ctx) const {
|
|
auto raw = bitSet.toUnderlying();
|
|
if (raw != 0) {
|
|
bool first = true;
|
|
for (std::size_t i = 0; i <= static_cast<std::size_t>(T::bitset_last);
|
|
++i) {
|
|
auto mask = 1ull << i;
|
|
if (!(raw & mask)) {
|
|
continue;
|
|
}
|
|
|
|
if (first) {
|
|
first = false;
|
|
} else {
|
|
rx::format_to(ctx.out(), " | ");
|
|
}
|
|
|
|
rx::format_to(ctx.out(), "{}", T(i));
|
|
raw &= ~mask;
|
|
}
|
|
|
|
if (raw) {
|
|
if (!first) {
|
|
rx::format_to(ctx.out(), " | ");
|
|
}
|
|
|
|
rx::format_to(ctx.out(), "{:#x}", raw);
|
|
}
|
|
} else {
|
|
rx::format_to(ctx.out(), "{}::None", rx::getNameOf<T>());
|
|
}
|
|
return ctx.out();
|
|
}
|
|
};
|
|
|
|
using namespace rx::bitset;
|