First pass idLib conversion from hex rays4.

This commit is contained in:
Justin Marshall
2026-08-08 13:54:26 -07:00
parent 3d01d735ce
commit 09a4cb91c3
120 changed files with 17718 additions and 0 deletions
+84
View File
@@ -0,0 +1,84 @@
#pragma once
#include <cstdint>
#include <cstdlib>
template<typename type>
class idAutoPtr {
public:
explicit idAutoPtr(type* pointer = nullptr)
: Pointee(pointer) {
}
~idAutoPtr() {
delete Pointee;
}
idAutoPtr(idAutoPtr&& other) noexcept
: Pointee(other.Release()) {
}
idAutoPtr& operator=(idAutoPtr&& other) noexcept {
if (this != &other) {
Reset(other.Release());
}
return *this;
}
idAutoPtr(const idAutoPtr&) = delete;
idAutoPtr& operator=(const idAutoPtr&) = delete;
type* Get() const { return Pointee; }
type* operator->() const { return Pointee; }
type& operator*() const { return *Pointee; }
explicit operator bool() const { return Pointee != nullptr; }
type* Release() {
type* const result = Pointee;
Pointee = nullptr;
return result;
}
void Reset(type* pointer = nullptr) {
if (Pointee != pointer) {
delete Pointee;
Pointee = pointer;
}
}
private:
type* Pointee;
};
template<typename type>
class idAutoPtr_Array {
public:
explicit idAutoPtr_Array(type* pointer = nullptr)
: Pointee(pointer) {
}
virtual ~idAutoPtr_Array() {
std::free(Pointee);
}
idAutoPtr_Array(const idAutoPtr_Array&) = delete;
idAutoPtr_Array& operator=(const idAutoPtr_Array&) = delete;
type* Get() const { return Pointee; }
type& operator[](const int index) const { return Pointee[index]; }
type* Release() {
type* const result = Pointee;
Pointee = nullptr;
return result;
}
private:
type* Pointee;
};
#if INTPTR_MAX == INT32_MAX
static_assert(sizeof(idAutoPtr<int>) == 4, "Recovered idAutoPtr ABI changed");
static_assert(sizeof(idAutoPtr_Array<int>) == 8,
"Recovered idAutoPtr_Array ABI changed");
#endif
@@ -0,0 +1,5 @@
#include "binaryheap.h"
// The recovered BinaryHeap.cpp contains only the testBinaryHeap console
// command. The reusable implementation was inline in BinaryHeap.h; its PC
// regression coverage lives in source/tests/idlib_containers_test.cpp.
+188
View File
@@ -0,0 +1,188 @@
#pragma once
#include <algorithm>
#include <cstdint>
#include <cstdlib>
#include <cstring>
template<typename nodeType, typename priorityType, priorityType LOWEST_VALUE>
class idBinaryHeap {
public:
struct idHeapNode {
nodeType node;
priorityType priority;
};
explicit idBinaryHeap(const int initialSize_ = 16)
: nodes(nullptr), curSize(0), initialSize(std::max(1, initialSize_)),
numNodes(0), ordered(true), externalBuffer(false) {
Allocate(initialSize);
}
idBinaryHeap(idHeapNode* const buffer, const int bufferSize)
: nodes(buffer), curSize(std::max(0, bufferSize - 1)),
initialSize(std::max(0, bufferSize - 1)), numNodes(0),
ordered(true), externalBuffer(true) {
if (nodes != nullptr && bufferSize > 0) {
nodes[0].priority = LOWEST_VALUE;
}
}
~idBinaryHeap() {
if (!externalBuffer) {
std::free(nodes);
}
}
idBinaryHeap(const idBinaryHeap&) = delete;
idBinaryHeap& operator=(const idBinaryHeap&) = delete;
bool Insert(const nodeType& node, const priorityType& priority) {
if (!ordered) {
return InsertUnsorted(node, priority);
}
if (!EnsureCapacity()) {
return false;
}
int hole = ++numNodes;
while (hole > 1 && priority < nodes[hole / 2].priority) {
nodes[hole] = nodes[hole / 2];
hole /= 2;
}
nodes[hole].node = node;
nodes[hole].priority = priority;
return true;
}
bool InsertUnsorted(const nodeType& node, const priorityType& priority) {
if (!EnsureCapacity()) {
return false;
}
++numNodes;
nodes[numNodes].node = node;
nodes[numNodes].priority = priority;
if (numNodes > 1 && priority < nodes[numNodes / 2].priority) {
ordered = false;
}
return true;
}
nodeType GetMin() {
SortHeap();
return numNodes == 0 ? nodeType() : nodes[1].node;
}
priorityType GetMinPriority() {
SortHeap();
return numNodes == 0 ? LOWEST_VALUE : nodes[1].priority;
}
nodeType RemoveMin() {
SortHeap();
if (numNodes == 0) {
return nodeType();
}
const nodeType result = nodes[1].node;
nodes[1] = nodes[numNodes--];
if (numNodes > 0) {
PercolateDown(1);
}
return result;
}
void SortHeap() {
if (ordered || numNodes < 2) {
ordered = true;
return;
}
for (int index = numNodes / 2; index > 0; --index) {
PercolateDown(index);
}
ordered = true;
}
void MakeEmpty() {
if (!externalBuffer && curSize != initialSize) {
std::free(nodes);
nodes = nullptr;
curSize = 0;
Allocate(initialSize);
}
numNodes = 0;
ordered = true;
if (nodes != nullptr) {
nodes[0].priority = LOWEST_VALUE;
}
}
int Num() const { return numNodes; }
bool IsEmpty() const { return numNodes == 0; }
private:
idHeapNode* nodes;
int curSize;
int initialSize;
int numNodes;
bool ordered;
bool externalBuffer;
bool Allocate(const int size) {
idHeapNode* const storage = static_cast<idHeapNode*>(
std::malloc(sizeof(idHeapNode) * static_cast<std::size_t>(size + 1))
);
if (storage == nullptr) {
return false;
}
nodes = storage;
curSize = size;
nodes[0].priority = LOWEST_VALUE;
return true;
}
bool Resize(const int newSize) {
if (externalBuffer || newSize <= curSize) {
return false;
}
idHeapNode* const replacement = static_cast<idHeapNode*>(
std::malloc(sizeof(idHeapNode) * static_cast<std::size_t>(newSize + 1))
);
if (replacement == nullptr) {
return false;
}
std::memcpy(replacement, nodes,
sizeof(idHeapNode) * static_cast<std::size_t>(numNodes + 1));
std::free(nodes);
nodes = replacement;
curSize = newSize;
return true;
}
bool EnsureCapacity() {
if (numNodes < curSize) {
return true;
}
return Resize(std::max(1, curSize * 2));
}
void PercolateDown(int hole) {
const idHeapNode value = nodes[hole];
while (hole * 2 <= numNodes) {
int child = hole * 2;
if (child != numNodes
&& nodes[child + 1].priority < nodes[child].priority) {
++child;
}
if (!(nodes[child].priority < value.priority)) {
break;
}
nodes[hole] = nodes[child];
hole = child;
}
nodes[hole] = value;
}
};
#if INTPTR_MAX == INT32_MAX
static_assert(sizeof(idBinaryHeap<int, int, (-2147483647 - 1)>) == 20,
"Recovered idBinaryHeap ABI changed");
#endif
+102
View File
@@ -0,0 +1,102 @@
#pragma once
#include <cstdint>
#include <cstdlib>
#include <cstring>
// Recovered from shared/idlib/containers/BitArray.h. The field order is
// intentionally kept identical to the 32-bit tungsten type.
class idBitArray {
public:
explicit idBitArray(const std::int16_t tag = 0)
: buffer(nullptr), bits(0), memTag(tag), ownsBuffer(false) {
}
idBitArray(unsigned char* storage, const unsigned int numBits,
const std::int16_t tag = 0)
: buffer(storage), bits(numBits), memTag(tag), ownsBuffer(false) {
Clear();
}
~idBitArray() {
Free();
}
idBitArray(const idBitArray&) = delete;
idBitArray& operator=(const idBitArray&) = delete;
bool Alloc(const unsigned int numBits) {
Free();
bits = numBits;
ownsBuffer = true;
const std::size_t bytes = ByteCount();
if (bytes == 0) {
return true;
}
buffer = static_cast<unsigned char*>(std::calloc(bytes, 1));
if (buffer == nullptr) {
bits = 0;
ownsBuffer = false;
return false;
}
return true;
}
void Clear() {
if (buffer != nullptr) {
std::memset(buffer, 0, ByteCount());
}
}
void Set(const unsigned int bitNum) {
if (bitNum < bits && buffer != nullptr) {
buffer[bitNum >> 3] |= static_cast<unsigned char>(1u << (bitNum & 7));
}
}
void Clear(const unsigned int bitNum) {
if (bitNum < bits && buffer != nullptr) {
buffer[bitNum >> 3] &= static_cast<unsigned char>(~(1u << (bitNum & 7)));
}
}
void Set(const unsigned int bitNum, const bool value) {
if (value) {
Set(bitNum);
} else {
Clear(bitNum);
}
}
bool Get(const unsigned int bitNum) const {
return bitNum < bits && buffer != nullptr
&& (buffer[bitNum >> 3] & (1u << (bitNum & 7))) != 0;
}
unsigned int Num() const {
return bits;
}
private:
unsigned char* buffer;
unsigned int bits;
std::int16_t memTag;
bool ownsBuffer;
std::size_t ByteCount() const {
return static_cast<std::size_t>((bits + 7u) >> 3);
}
void Free() {
if (buffer != nullptr && ownsBuffer) {
std::free(buffer);
}
buffer = nullptr;
bits = 0;
ownsBuffer = false;
}
};
#if INTPTR_MAX == INT32_MAX
static_assert(sizeof(idBitArray) == 12, "Recovered idBitArray ABI changed");
#endif
+3
View File
@@ -0,0 +1,3 @@
// Tungsten's containers/BTree.cpp contains only the testBinaryTree console
// command. The reusable idBTree implementation is header-only and is supplied
// by the compiled Doom 3 BFG idlib/containers/BTree.h baseline.
+4
View File
@@ -0,0 +1,4 @@
// Tungsten's containers/List.cpp contains diagnostic console commands for the
// header-only idList and idArray implementations. The PC runtime templates are
// supplied by the compiled Doom 3 BFG idlib/containers/List.h baseline; the
// recovery suite exercises container behavior without registering engine CVars.
@@ -0,0 +1,85 @@
#pragma once
#include <algorithm>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <new>
template<class T>
class idRecoveredList {
public:
explicit idRecoveredList(const int initialGranularity = 16)
: list(nullptr), num(0), size(0),
granularity(static_cast<std::int16_t>(initialGranularity)),
memTag(0), listStatic(0) {
}
~idRecoveredList() {
Clear(true);
}
idRecoveredList(const idRecoveredList&) = delete;
idRecoveredList& operator=(const idRecoveredList&) = delete;
bool Reserve(const int capacity) {
if (capacity <= size) return true;
const int step = granularity > 0 ? granularity : 16;
const int newSize = ((capacity + step - 1) / step) * step;
T* const replacement = static_cast<T*>(
std::malloc(sizeof(T) * static_cast<std::size_t>(newSize)));
if (replacement == nullptr) return false;
if (list != nullptr && num > 0) {
std::memcpy(replacement, list,
sizeof(T) * static_cast<std::size_t>(num));
}
std::free(list);
list = replacement;
size = newSize;
return true;
}
T* Alloc() {
if (!Reserve(num + 1)) return nullptr;
T* const result = list + num++;
std::memset(result, 0, sizeof(T));
return result;
}
bool Append(const T& value) {
T* const destination = Alloc();
if (destination == nullptr) return false;
*destination = value;
return true;
}
void Clear(const bool freeMemory = false) {
num = 0;
if (freeMemory) {
std::free(list);
list = nullptr;
size = 0;
}
}
int Num() const { return num; }
int Capacity() const { return size; }
T* Ptr() { return list; }
const T* Ptr() const { return list; }
T& operator[](const int index) { return list[index]; }
const T& operator[](const int index) const { return list[index]; }
private:
T* list;
int num;
int size;
std::int16_t granularity;
std::uint8_t memTag;
std::uint8_t listStatic;
};
#if INTPTR_MAX == INT32_MAX
static_assert(sizeof(idRecoveredList<int>) == 16,
"Recovered list ABI changed");
#endif
+99
View File
@@ -0,0 +1,99 @@
#pragma once
template<typename type>
class idSearch {
public:
virtual ~idSearch() = default;
virtual int Search(const type* base, unsigned int num,
const type& value) const = 0;
virtual int Search_FirstGreater(const type* base, int num,
const type& value) const = 0;
virtual int Search_FirstGreaterEqual(const type* base, int num,
const type& value) const = 0;
virtual int Search_LastLess(const type* base, int num,
const type& value) const = 0;
virtual int Search_LastLessEqual(const type* base, int num,
const type& value) const = 0;
};
template<typename type, typename derived>
class idSearch_Binary : public idSearch<type> {
public:
int Search(const type* base, const unsigned int num,
const type& value) const override {
if (base == nullptr || num == 0) {
return -1;
}
const int index = Search_LastLessEqual(base, static_cast<int>(num), value);
return Compare(base[index], value) == 0 ? index : -1;
}
int Search_FirstGreater(const type* base, const int num,
const type& value) const override {
int first = 0;
int count = num < 0 ? 0 : num;
while (count > 0) {
const int step = count / 2;
const int middle = first + step;
if (Compare(base[middle], value) <= 0) {
first = middle + 1;
count -= step + 1;
} else {
count = step;
}
}
return first;
}
int Search_FirstGreaterEqual(const type* base, const int num,
const type& value) const override {
int first = 0;
int count = num < 0 ? 0 : num;
while (count > 0) {
const int step = count / 2;
const int middle = first + step;
if (Compare(base[middle], value) < 0) {
first = middle + 1;
count -= step + 1;
} else {
count = step;
}
}
return first;
}
int Search_LastLess(const type* base, const int num,
const type& value) const override {
const int result = Search_FirstGreaterEqual(base, num, value) - 1;
return result < 0 ? 0 : result;
}
int Search_LastLessEqual(const type* base, const int num,
const type& value) const override {
const int result = Search_FirstGreater(base, num, value) - 1;
return result < 0 ? 0 : result;
}
private:
int Compare(const type& left, const type& right) const {
return static_cast<const derived*>(this)->Compare(left, right);
}
};
template<typename type>
class idSearch_BinaryDefault
: public idSearch_Binary<type, idSearch_BinaryDefault<type>> {
public:
int Compare(const type& left, const type& right) const {
if (left < right) {
return -1;
}
if (right < left) {
return 1;
}
return 0;
}
};
template<typename type>
using idSearch_DefaultCompare = idSearch_BinaryDefault<type>;