mirror of
https://github.com/thunderbrewhq/squall.git
synced 2025-12-12 02:22:30 +00:00
feat(list): add list templates
This commit is contained in:
parent
7713223e60
commit
ced42bbfed
8 changed files with 434 additions and 0 deletions
9
storm/List.hpp
Normal file
9
storm/List.hpp
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
#ifndef STORM_LIST_HPP
|
||||||
|
#define STORM_LIST_HPP
|
||||||
|
|
||||||
|
#include "list/TSExplicitList.hpp"
|
||||||
|
#include "list/TSLink.hpp"
|
||||||
|
#include "list/TSLinkedNode.hpp"
|
||||||
|
#include "list/TSList.hpp"
|
||||||
|
|
||||||
|
#endif
|
||||||
23
storm/list/TSExplicitList.hpp
Normal file
23
storm/list/TSExplicitList.hpp
Normal 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
|
||||||
20
storm/list/TSGetExplicitLink.hpp
Normal file
20
storm/list/TSGetExplicitLink.hpp
Normal 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
21
storm/list/TSGetLink.hpp
Normal 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
81
storm/list/TSLink.hpp
Normal 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
|
||||||
39
storm/list/TSLinkedNode.hpp
Normal file
39
storm/list/TSLinkedNode.hpp
Normal 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
215
storm/list/TSList.hpp
Normal 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
|
||||||
26
test/List.cpp
Normal file
26
test/List.cpp
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
#include "Test.hpp"
|
||||||
|
#include "List.hpp"
|
||||||
|
|
||||||
|
struct TestListNode : TSLinkedNode<TestListNode> {
|
||||||
|
uint32_t index = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_CASE("TSList", "[list]") {
|
||||||
|
SECTION("constructs correctly") {
|
||||||
|
STORM_LIST(TestListNode) list;
|
||||||
|
REQUIRE(list.Head() == nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("TSList::LinkToHead", "[list]") {
|
||||||
|
SECTION("links node to head correctly") {
|
||||||
|
STORM_LIST(TestListNode) list;
|
||||||
|
|
||||||
|
auto node = new TestListNode();
|
||||||
|
list.LinkToHead(node);
|
||||||
|
|
||||||
|
REQUIRE(list.Head() == node);
|
||||||
|
|
||||||
|
delete(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue