// SPDX-License-Identifier: MIT #pragma once #include #include #include namespace FEXCore { // BucketList is an optimized container, it includes an inline array of Size // and can overflow to a linked list of further buckets // // To optimize for best performance, Size should be big enough to allocate one or two // buckets for the typical case // Picking a Size so sizeof(Bucket<...>) is a power of two is also a small win template struct BucketList { static constexpr size_t Size = _Size; T Items[Size]; fextl::unique_ptr> Next; void Clear() { Items[0] = T {}; #if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED for (size_t i = 1; i < Size; i++) { Items[i] = T {0xDEADBEEF}; } #endif Next.reset(); } BucketList() { Clear(); } template void Iterate(EnumeratorFn Enumerator) const { size_t i = 0; auto Bucket = this; while (true) { auto Item = Bucket->Items[i]; if (Item == T {}) { break; } Enumerator(Item); if (++i == Size) { LOGMAN_THROW_A_FMT(Bucket->Next != nullptr, "Interference bug"); Bucket = Bucket->Next.get(); i = 0; } } } template bool Find(EnumeratorFn Enumerator) const { size_t i = 0; auto Bucket = this; while (true) { auto Item = Bucket->Items[i]; if (Item == T {}) { break; } if (Enumerator(Item)) { return true; } if (++i == Size) { LOGMAN_THROW_A_FMT(Bucket->Next != nullptr, "Bucket in bad state"); Bucket = Bucket->Next.get(); i = 0; } } return false; } void Append(T Val) { auto that = this; while (that->Next) { that = that->Next.get(); } size_t i; for (i = 0; i < Size; i++) { if (that->Items[i] == T {}) { that->Items[i] = Val; break; } } if (i < (Size - 1)) { that->Items[i + 1] = T {}; } else { that->Next = fextl::make_unique>(); } } void Erase(T Val) { size_t i = 0; auto that = this; auto foundThat = this; size_t foundI = 0; while (true) { if (that->Items[i] == Val) { foundThat = that; foundI = i; break; } else if (++i == Size) { i = 0; LOGMAN_THROW_A_FMT(that->Next != nullptr, "Bucket::Erase but element not contained"); that = that->Next.get(); } } while (true) { if (that->Items[i] == T {}) { foundThat->Items[foundI] = that->Items[i - 1]; that->Items[i - 1] = T {}; break; } else if (++i == Size) { if (that->Next->Items[0] == T {}) { that->Next.reset(); foundThat->Items[foundI] = that->Items[Size - 1]; that->Items[Size - 1] = T {}; break; } i = 0; that = that->Next.get(); } } } }; } // namespace FEXCore