// SPDX-License-Identifier: MIT #pragma once #include #include #include #include #include #include #include namespace FEXCore { template struct BitSet final { using ElementType = T; constexpr static size_t MinimumSize = sizeof(ElementType); constexpr static size_t MinimumSizeBits = sizeof(ElementType) * 8; ElementType* Memory {}; void Allocate(size_t Elements) { size_t AllocateSize = ToBytes(Elements); LOGMAN_THROW_A_FMT((AllocateSize * MinimumSize) >= Elements, "Fail"); Memory = static_cast(FEXCore::Allocator::malloc(AllocateSize)); } void Realloc(size_t Elements) { size_t AllocateSize = ToBytes(Elements); LOGMAN_THROW_A_FMT((AllocateSize * MinimumSize) >= Elements, "Fail"); Memory = static_cast(FEXCore::Allocator::realloc(Memory, AllocateSize)); } void Free() { FEXCore::Allocator::free(Memory); Memory = nullptr; } [[nodiscard]] bool Get(T Element) const { return (Memory[Element / MinimumSizeBits] & (1ULL << (Element % MinimumSizeBits))) != 0; } void Set(T Element) { Memory[Element / MinimumSizeBits] |= (1ULL << (Element % MinimumSizeBits)); } void Clear(T Element) { Memory[Element / MinimumSizeBits] &= ~(1ULL << (Element % MinimumSizeBits)); } void MemClear(size_t Elements) { memset(Memory, 0, ToBytes(Elements)); } void MemSet(size_t Elements) { memset(Memory, 0xFF, ToBytes(Elements)); } [[nodiscard]] static size_t ToBytes(size_t Elements) { return AlignUp(Elements, MinimumSizeBits) / 8; } // This very explicitly doesn't let you take an address // Is only a getter [[nodiscard]] bool operator[](T Element) const { return Get(Element); } }; template struct BitSetView final { using ElementType = T; constexpr static size_t MinimumSize = BitSet::MinimumSize; constexpr static size_t MinimumSizeBits = BitSet::MinimumSizeBits; ElementType* Memory {}; void GetView(BitSet& Set, uint64_t ElementOffset) { LOGMAN_THROW_A_FMT((ElementOffset % MinimumSize) == 0, "Bitset view offset needs to be aligned to size of backing element"); Memory = &Set.Memory[ElementOffset / MinimumSizeBits]; } [[nodiscard]] bool Get(T Element) const { return (Memory[Element / MinimumSizeBits] & (1ULL << (Element % MinimumSizeBits))) != 0; } void Set(T Element) { Memory[Element / MinimumSizeBits] |= (1ULL << (Element % MinimumSizeBits)); } void Clear(T Element) { Memory[Element / MinimumSizeBits] &= ~(1ULL << (Element % MinimumSizeBits)); } void MemClear(size_t Elements) { memset(Memory, 0, BitSet::ToBytes(Elements)); } void MemSet(size_t Elements) { memset(Memory, 0xFF, BitSet::ToBytes(Elements)); } // This very explicitly doesn't let you take an address // Is only a getter [[nodiscard]] bool operator[](T Element) const { return Get(Element); } }; static_assert(sizeof(BitSet) == sizeof(uintptr_t), "Needs to just be a pointer"); static_assert(std::is_trivially_copyable_v>, "Needs to trivially copyable"); static_assert(sizeof(BitSetView) == sizeof(uintptr_t), "Needs to just be a pointer"); static_assert(std::is_trivially_copyable_v>, "Needs to trivially copyable"); } // namespace FEXCore