Files

185 lines
5.5 KiB
C++

#pragma once
#include <algorithm>
#include <cstdint>
#include <new>
#include <utility>
// Reconstructed from the common layout shared by all 2,438 recovered PDB
// instantiations and the template bodies in the Hex-Rays list.h dump.
template<typename type, int memoryTag = 5>
class idList {
public:
type* list;
int num;
int size;
std::int16_t granularity;
std::uint8_t memTag;
std::uint8_t listStatic;
explicit idList(const int initialGranularity = 16)
: list(nullptr), num(0), size(0),
granularity(static_cast<std::int16_t>(initialGranularity)),
memTag(static_cast<std::uint8_t>(memoryTag)), listStatic(0) {}
idList(const idList& other) : idList(other.granularity) { *this = other; }
~idList() {
if (listStatic == 0) delete[] list;
}
idList& operator=(const idList& other) {
if (this != &other && SetNum(other.num)) {
for (int index = 0; index < num; ++index) list[index] = other.list[index];
}
return *this;
}
int Num() const { return num; }
int NumAllocated() const { return size; }
int MemoryUsed() const { return size * static_cast<int>(sizeof(type)); }
bool IsEmpty() const { return num == 0; }
type* Ptr() { return list; }
const type* Ptr() const { return list; }
type& operator[](const int index) { return list[index]; }
const type& operator[](const int index) const { return list[index]; }
void SetGranularity(const int newGranularity) {
granularity = static_cast<std::int16_t>(newGranularity > 0 ? newGranularity : 16);
}
bool Resize(const int newSize) {
if (newSize < 0 || (listStatic != 0 && newSize > size)) return false;
if (newSize == size) return true;
type* replacement = new (std::nothrow) type[newSize];
if (replacement == nullptr && newSize != 0) return false;
const int copyCount = (std::min)(num, newSize);
for (int index = 0; index < copyCount; ++index)
replacement[index] = std::move(list[index]);
if (listStatic == 0) delete[] list;
list = replacement;
size = newSize;
num = copyCount;
listStatic = 0;
return true;
}
bool PreAllocate(const int requestedSize) {
if (requestedSize <= size) return true;
return Resize(RoundedCapacity(requestedSize));
}
bool SetNum(const int newNum) {
if (newNum < 0) return false;
if (newNum > size && !PreAllocate(newNum)) return false;
num = newNum;
return true;
}
type* Alloc() {
if (!SetNum(num + 1)) return nullptr;
return &list[num - 1];
}
int Append(const type& object) {
if (!SetNum(num + 1)) return -1;
list[num - 1] = object;
return num - 1;
}
int Append(type&& object) {
if (!SetNum(num + 1)) return -1;
list[num - 1] = std::move(object);
return num - 1;
}
int AddUnique(const type& object) {
const int found = FindIndex(object);
return found >= 0 ? found : Append(object);
}
int Insert(const type& object, int index = 0) {
if (index < 0) index = 0;
if (index > num) index = num;
if (!SetNum(num + 1)) return -1;
for (int move = num - 1; move > index; --move)
list[move] = std::move(list[move - 1]);
list[index] = object;
return index;
}
int FindIndex(const type& object) const {
for (int index = 0; index < num; ++index)
if (list[index] == object) return index;
return -1;
}
type* Find(const type& object) {
const int index = FindIndex(object);
return index >= 0 ? &list[index] : nullptr;
}
const type* Find(const type& object) const {
const int index = FindIndex(object);
return index >= 0 ? &list[index] : nullptr;
}
bool RemoveIndex(const int index) {
if (index < 0 || index >= num) return false;
for (int move = index; move + 1 < num; ++move)
list[move] = std::move(list[move + 1]);
--num;
return true;
}
bool RemoveIndexFast(const int index) {
if (index < 0 || index >= num) return false;
if (index != num - 1) list[index] = std::move(list[num - 1]);
--num;
return true;
}
bool Remove(const type& object) { return RemoveIndex(FindIndex(object)); }
void Clear() { num = 0; }
void ClearFree() {
num = 0;
if (listStatic == 0) {
delete[] list;
list = nullptr;
size = 0;
}
}
void Swap(idList& other) {
using std::swap;
swap(list, other.list); swap(num, other.num); swap(size, other.size);
swap(granularity, other.granularity); swap(memTag, other.memTag);
swap(listStatic, other.listStatic);
}
protected:
void SetStaticBuffer(type* buffer, const int capacity) {
if (listStatic == 0) delete[] list;
list = buffer;
num = 0;
size = capacity;
// Recovered idStaticList constructors consistently materialize a
// granularity of one for their embedded fixed-capacity storage.
granularity = 1;
listStatic = 1;
}
private:
int RoundedCapacity(const int requestedSize) const {
const int step = granularity > 0 ? granularity : 16;
return ((requestedSize + step - 1) / step) * step;
}
};
#if defined(_WIN32) && !defined(_WIN64)
static_assert(sizeof(idList<int, 5>) == 16, "Recovered idList ABI changed");
#endif