#pragma once #include #include #include #include // 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 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(initialGranularity)), memTag(static_cast(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(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(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) == 16, "Recovered idList ABI changed"); #endif