Files
FEX-Emu--FEX/FEXCore/Source/Utils/BucketList.h
T
Paulo Matos 2b4ec88dae Whole-tree reformat
This follows discussions from #3413.
Followup commits add clang-format file, script and blame ignore lists.
2024-04-12 16:26:02 +02:00

142 lines
3.0 KiB
C++

// SPDX-License-Identifier: MIT
#pragma once
#include <cstddef>
#include <FEXCore/Utils/LogManager.h>
#include <FEXCore/fextl/memory.h>
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<size_t _Size, typename T = uint32_t>
struct BucketList {
static constexpr size_t Size = _Size;
T Items[Size];
fextl::unique_ptr<BucketList<Size, T>> 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<typename EnumeratorFn>
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<typename EnumeratorFn>
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<BucketList<Size, T>>();
}
}
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