feat(list): add list templates

This commit is contained in:
fallenoak 2020-09-16 01:28:32 -05:00
parent 7713223e60
commit ced42bbfed
No known key found for this signature in database
GPG key ID: 7628F8E61AEA070D
8 changed files with 434 additions and 0 deletions

View file

@ -0,0 +1,23 @@
#ifndef STORM_LIST_TS_EXPLICIT_LIST_HPP
#define STORM_LIST_TS_EXPLICIT_LIST_HPP
#include "list/TSGetExplicitLink.hpp"
#include "list/TSList.hpp"
#include <cstdlib>
#define STORM_EXPLICIT_LIST(T, link) TSExplicitList<T, offsetof(T, link)>
template <class T, size_t offset>
class TSExplicitList : public TSList<T, TSGetExplicitLink<T>> {
public:
// Member functions
TSExplicitList();
};
template <class T, size_t offset>
TSExplicitList<T, offset>::TSExplicitList()
: TSList<T, TSGetExplicitLink<T>>() {
this->SetLinkOffset(offset);
}
#endif

View file

@ -0,0 +1,20 @@
#ifndef STORM_LIST_TS_GET_EXPLICIT_LINK_HPP
#define STORM_LIST_TS_GET_EXPLICIT_LINK_HPP
#include "list/TSLink.hpp"
#include <cstddef>
#include <cstdint>
template <class T>
class TSGetExplicitLink {
public:
// Static functions
static TSLink<T>* Link(const void* nodeptr, ptrdiff_t linkoffset);
};
template <class T>
TSLink<T>* TSGetExplicitLink<T>::Link(const void* nodeptr, ptrdiff_t linkoffset) {
return reinterpret_cast<TSLink<T>*>((reinterpret_cast<uintptr_t>(nodeptr) + linkoffset));
}
#endif

21
storm/list/TSGetLink.hpp Normal file
View file

@ -0,0 +1,21 @@
#ifndef STORM_LIST_TS_GET_LINK_HPP
#define STORM_LIST_TS_GET_LINK_HPP
#include "list/TSLink.hpp"
#include "list/TSLinkedNode.hpp"
#include <cstddef>
#include <cstdint>
template <class T>
class TSGetLink {
public:
// Static functions
static TSLink<T>* Link(const TSLinkedNode<T>* nodeptr, ptrdiff_t linkoffset);
};
template <class T>
TSLink<T>* TSGetLink<T>::Link(const TSLinkedNode<T>* nodeptr, ptrdiff_t linkoffset) {
return reinterpret_cast<TSLink<T>*>(reinterpret_cast<uintptr_t>(nodeptr));
}
#endif

81
storm/list/TSLink.hpp Normal file
View file

@ -0,0 +1,81 @@
#ifndef STORM_LIST_TS_LINK_HPP
#define STORM_LIST_TS_LINK_HPP
#include <cstddef>
#include <cstdint>
template <class T>
class TSLink {
public:
// Member variables
TSLink<T>* m_prevlink = nullptr;
T* m_next = nullptr;
// Member functions
~TSLink();
bool IsLinked(void);
T* Next(void);
TSLink<T>* NextLink(ptrdiff_t linkoffset);
T* Prev(void);
T* RawNext(void);
void Unlink(void);
};
template <class T>
TSLink<T>::~TSLink() {
this->Unlink();
}
template <class T>
bool TSLink<T>::IsLinked() {
return this->m_next != nullptr;
}
template <class T>
T* TSLink<T>::Next() {
// Check for sentinel node (indicates list end)
return reinterpret_cast<intptr_t>(this->m_next) <= 0 ? nullptr : this->m_next;
}
template <class T>
TSLink<T>* TSLink<T>::NextLink(ptrdiff_t linkoffset) {
T* next = this->m_next;
if (reinterpret_cast<intptr_t>(next) <= 0) {
// End of list
return reinterpret_cast<TSLink<T>*>(~reinterpret_cast<uintptr_t>(next));
} else {
ptrdiff_t offset;
if (linkoffset < 0) {
offset = reinterpret_cast<uintptr_t>(this) - reinterpret_cast<uintptr_t>(this->m_prevlink->m_next);
} else {
offset = linkoffset;
}
return reinterpret_cast<TSLink<T>*>(reinterpret_cast<uintptr_t>(this->m_next) + offset);
}
}
template <class T>
T* TSLink<T>::Prev() {
return this->m_prevlink->m_prevlink->Next();
}
template <class T>
T* TSLink<T>::RawNext() {
return this->m_next;
}
template <class T>
void TSLink<T>::Unlink() {
if (this->m_prevlink) {
this->NextLink(-1)->m_prevlink = this->m_prevlink;
this->m_prevlink->m_next = this->m_next;
this->m_prevlink = nullptr;
this->m_next = nullptr;
}
}
#endif

View file

@ -0,0 +1,39 @@
#ifndef STORM_LIST_TS_LINKED_NODE_HPP
#define STORM_LIST_TS_LINKED_NODE_HPP
#include "list/TSLink.hpp"
template <class T>
class TSLinkedNode {
public:
// Member variables
TSLink<T> m_link;
// Member functions
~TSLinkedNode();
T* Next(void);
T* Prev(void);
void Unlink(void);
};
template <class T>
TSLinkedNode<T>::~TSLinkedNode() {
this->Unlink();
}
template <class T>
T* TSLinkedNode<T>::Next() {
return this->m_link.Next();
}
template <class T>
T* TSLinkedNode<T>::Prev() {
return this->m_link.Prev();
}
template <class T>
void TSLinkedNode<T>::Unlink() {
this->m_link.Unlink();
}
#endif

215
storm/list/TSList.hpp Normal file
View file

@ -0,0 +1,215 @@
#ifndef STORM_LIST_TS_LIST_HPP
#define STORM_LIST_TS_LIST_HPP
#include "Memory.hpp"
#include "list/TSGetLink.hpp"
#include "list/TSLink.hpp"
#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