Files
robojumper a8023aa4fa checkpoint
2025-05-10 22:23:47 +02:00

193 lines
5.2 KiB
C++

#ifndef T_LIST_H
#define T_LIST_H
#include "common.h"
// A templated list, similar to nw4r::ut::LinkList.
// Notable differences are:
// * No dtor
// * Entirely in headers
// * Swapped node and count members
// Used in DowsingTarget, maybe also in dAcBase_c.soundStuff
//
// The current implementation has various unexplained behaviors
// * Constructor doesn't match if offset != 0 https://decomp.me/scratch/YqOCh
// * Many loops based on these iterators don't match in general, but probably not worth
// messing with until the ctor is fixed
// * -ipa file optimizes things that shouldn't be optimized https://decomp.me/scratch/lqM6i
template <typename T>
class TListNode {
public:
TListNode() : mpPrev(nullptr), mpNext(nullptr) {}
T *GetNext() const {
return mpNext;
}
T *GetPrev() const {
return mpPrev;
}
T *mpPrev;
T *mpNext;
};
template <typename T, int offset>
class TList {
public:
typedef TListNode<T> TNode;
class Iterator {
public:
Iterator() : pVal(NULL) {}
Iterator(T *p_val) : pVal(p_val) {}
Iterator &operator++() {
pVal = GetNodeFromPtr(pVal)->GetNext();
return *this;
}
Iterator &operator--() {
pVal = GetNodeFromPtr(pVal)->GetPrev();
return *this;
}
T *operator->() const {
return pVal;
}
T &operator*() {
return *this->operator->();
}
friend bool operator==(const Iterator &lhs, const Iterator &rhs) {
return lhs.pVal == rhs.pVal;
}
friend bool operator!=(const Iterator &lhs, const Iterator &rhs) {
return !(lhs.pVal == rhs.pVal);
}
private:
T *pVal; // at 0x0
};
TList() {
mStartEnd.mpNext = GetPtrFromNode(&mStartEnd);
mStartEnd.mpPrev = GetPtrFromNode(&mStartEnd);
mCount = 0;
}
Iterator GetBeginIter() {
if (GetEndIter() != Iterator(mStartEnd.GetNext())) {
return Iterator(mStartEnd.GetNext());
} else {
return GetEndIter();
}
}
/**
* Returns an iterator representing the position of pT in this
* list. If pT is not in the list, the result is the end iterator.
*
* This is typically used to check if an object is contained in a
* list of this type.
*/
Iterator GetPosition(T *pT) {
if (GetNodeFromPtr(pT)->mpNext == nullptr || GetNodeFromPtr(pT)->mpPrev == nullptr) {
return GetEndIter();
} else {
return Iterator(pT);
}
}
Iterator GetEndIter() {
return Iterator(GetPtrFromNode(&mStartEnd));
}
static TNode *GetNodeFromPtr(T *pT) {
return (TNode *)((u8 *)pT + offset);
}
static T *GetPtrFromNode(TNode *pN) {
return (T *)((u8 *)pN - offset);
}
void append(T *value) {
TNode *node = GetNodeFromPtr(value);
if (GetPtrFromNode(&mStartEnd) == mStartEnd.mpNext) {
node->mpNext = GetPtrFromNode(&mStartEnd);
node->mpPrev = GetPtrFromNode(&mStartEnd);
mStartEnd.mpNext = value;
mStartEnd.mpPrev = value;
mCount++;
} else {
node->mpPrev = mStartEnd.mpPrev;
node->mpNext = GetPtrFromNode(&mStartEnd);
GetNodeFromPtr(mStartEnd.mpPrev)->mpNext = value;
mStartEnd.mpPrev = value;
mCount++;
}
}
void prepend(T *value) {
TNode *node = GetNodeFromPtr(value);
if (GetPtrFromNode(&mStartEnd) == mStartEnd.mpNext) {
node->mpNext = GetPtrFromNode(&mStartEnd);
node->mpPrev = GetPtrFromNode(&mStartEnd);
mStartEnd.mpNext = value;
mStartEnd.mpPrev = value;
mCount++;
} else {
node->mpPrev = GetPtrFromNode(&mStartEnd);
node->mpNext = mStartEnd.mpNext;
GetNodeFromPtr(mStartEnd.mpNext)->mpPrev = value;
mStartEnd.mpNext = value;
mCount++;
}
}
void insertBefore(T* existing, T *value) {
TNode *node = GetNodeFromPtr(value);
TNode *existingNode = GetNodeFromPtr(existing);
T* itPrev = existingNode->mpPrev;
node->mpPrev = itPrev;
node->mpNext = existing;
GetNodeFromPtr(itPrev)->mpNext = value;
existingNode->mpPrev = value;
mCount++;
}
void remove(T *value) {
TNode *node = GetNodeFromPtr(value);
T *next = reinterpret_cast<T *>(node->mpNext);
if (GetPtrFromNode(&mStartEnd) == node->mpPrev) {
this->mStartEnd.mpNext = next;
} else {
GetNodeFromPtr(node->mpPrev)->mpNext = next;
}
if (GetPtrFromNode(&mStartEnd) == node->mpNext) {
this->mStartEnd.mpPrev = node->mpPrev;
} else {
GetNodeFromPtr(node->mpNext)->mpPrev = node->mpPrev;
}
node->mpPrev = nullptr;
node->mpNext = nullptr;
mCount--;
}
T *GetFirst() {
return GetPtrFromNode(&mStartEnd);
}
void RemoveFirst() {
if (mCount != 0) {
remove(GetFirst());
}
}
TNode mStartEnd;
s32 mCount;
};
#endif