mirror of
https://github.com/zeldaret/ss
synced 2026-05-23 15:01:38 -04:00
193 lines
5.2 KiB
C++
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
|