squall/storm/list/TSList.hpp

216 lines
4.8 KiB
C++
Raw Normal View History

2020-09-16 01:28:32 -05:00
#ifndef STORM_LIST_TS_LIST_HPP
#define STORM_LIST_TS_LIST_HPP
2020-11-01 17:45:45 -06:00
#include "storm/Memory.hpp"
#include "storm/list/TSGetLink.hpp"
#include "storm/list/TSLink.hpp"
2020-09-16 01:28:32 -05:00
#include <cstddef>
#include <cstdint>
#define STORM_LIST(T) TSList<T, TSGetLink<T>>
template <class T, class TGetLink>
class TSList {
public:
// Member variables
ptrdiff_t m_linkoffset = 0;
TSLink<T> m_terminator;
// Member functions
TSList();
~TSList();
void ChangeLinkOffset(ptrdiff_t linkoffset);
void DeleteAll(void);
T* DeleteNode(T* ptr);
T* Head(void);
void InitializeTerminator(void);
bool IsLinked(T* ptr);
TSLink<T>* Link(const T* ptr);
void LinkNode(T* ptr, uint32_t linktype, T* existingptr);
void LinkToHead(T* ptr);
void LinkToTail(T* ptr);
T* NewNode(uint32_t location, size_t extrabytes, uint32_t flags);
T* Next(const T* ptr);
T* RawNext(const T* ptr);
void SetLinkOffset(ptrdiff_t linkoffset);
T* Tail(void);
void UnlinkAll(void);
void UnlinkNode(T* node);
};
template <class T, class TGetLink>
TSList<T, TGetLink>::TSList() {
this->InitializeTerminator();
}
template <class T, class TGetLink>
TSList<T, TGetLink>::~TSList() {
this->UnlinkAll();
}
template <class T, class TGetLink>
void TSList<T, TGetLink>::ChangeLinkOffset(ptrdiff_t linkoffset) {
if (linkoffset != this->m_linkoffset) {
this->UnlinkAll();
this->SetLinkOffset(linkoffset);
}
}
template <class T, class TGetLink>
void TSList<T, TGetLink>::DeleteAll() {
T* node;
while ((node = this->Head())) {
this->DeleteNode(node);
}
}
template <class T, class TGetLink>
T* TSList<T, TGetLink>::DeleteNode(T* ptr) {
T* next = this->Next(ptr);
ptr->~T();
SMemFree(ptr, __FILE__, __LINE__, 0);
return next;
}
template <class T, class TGetLink>
T* TSList<T, TGetLink>::Head() {
return this->m_terminator.Next();
}
template <class T, class TGetLink>
void TSList<T, TGetLink>::InitializeTerminator() {
this->m_terminator.m_prevlink = &this->m_terminator;
// Set sentinel node (indicates list end)
this->m_terminator.m_next = reinterpret_cast<T*>(~reinterpret_cast<uintptr_t>(&this->m_terminator));
}
template <class T, class TGetLink>
bool TSList<T, TGetLink>::IsLinked(T* ptr) {
return TGetLink::Link(ptr, this->m_linkoffset)->IsLinked();
}
template <class T, class TGetLink>
TSLink<T>* TSList<T, TGetLink>::Link(const T* ptr) {
if (ptr) {
return TGetLink::Link(ptr, this->m_linkoffset);
} else {
return &this->m_terminator;
}
}
template <class T, class TGetLink>
void TSList<T, TGetLink>::LinkNode(T* ptr, uint32_t linktype, T* existingptr) {
TSLink<T>* v5 = this->Link(ptr);
if (v5->m_prevlink) {
v5->Unlink();
}
TSLink<T>* v7;
if (existingptr) {
v7 = this->Link(existingptr);
} else {
v7 = &this->m_terminator;
}
TSLink<T>* v8;
switch (linktype) {
case 1:
// After existingptr
v5->m_prevlink = v7;
v5->m_next = v7->m_next;
v7->NextLink(this->m_linkoffset)->m_prevlink = v5;
v7->m_next = ptr;
break;
case 2:
// Before existingptr
v8 = v7->m_prevlink;
v5->m_prevlink = v7->m_prevlink;
v5->m_next = v8->m_next;
v8->m_next = ptr;
v7->m_prevlink = v5;
break;
default:
// TODO error
break;
}
}
template <class T, class TGetLink>
void TSList<T, TGetLink>::LinkToHead(T* ptr) {
this->LinkNode(ptr, 1, nullptr);
}
template <class T, class TGetLink>
void TSList<T, TGetLink>::LinkToTail(T* ptr) {
this->LinkNode(ptr, 2, nullptr);
}
template <class T, class TGetLink>
T* TSList<T, TGetLink>::NewNode(uint32_t location, size_t extrabytes, uint32_t flags) {
void* m = SMemAlloc(sizeof(T) + extrabytes, __FILE__, __LINE__, flags);
T* node;
if (m) {
node = new (m) T();
} else {
node = nullptr;
}
if (location) {
this->LinkNode(node, location, nullptr);
}
return node;
}
template <class T, class TGetLink>
T* TSList<T, TGetLink>::Next(const T* ptr) {
return this->Link(ptr)->Next();
}
template <class T, class TGetLink>
T* TSList<T, TGetLink>::RawNext(const T* ptr) {
TSLink<T>* link = this->Link(ptr);
return link->RawNext();
}
template <class T, class TGetLink>
void TSList<T, TGetLink>::SetLinkOffset(ptrdiff_t linkoffset) {
this->m_linkoffset = linkoffset;
this->InitializeTerminator();
}
template <class T, class TGetLink>
T* TSList<T, TGetLink>::Tail() {
return this->m_terminator.Prev();
}
template <class T, class TGetLink>
void TSList<T, TGetLink>::UnlinkAll() {
T* node;
while ((node = this->Head())) {
this->UnlinkNode(node);
}
}
template <class T, class TGetLink>
void TSList<T, TGetLink>::UnlinkNode(T* node) {
TSLink<T>* link = this->Link(node);
link->Unlink();
}
#endif