From 2e82693829c233f5eb8807b9bf3526fb2e220789 Mon Sep 17 00:00:00 2001 From: fallenoak Date: Sun, 6 Dec 2020 23:28:15 -0600 Subject: [PATCH] feat(queue): add TSPriorityQueue and TSTimerPriority --- storm/CMakeLists.txt | 1 + storm/Queue.hpp | 7 +++ storm/queue/CSBasePriority.cpp | 92 +++++++++++++++++++++++++++++ storm/queue/CSBasePriority.hpp | 20 +++++++ storm/queue/CSBasePriorityQueue.cpp | 63 ++++++++++++++++++++ storm/queue/CSBasePriorityQueue.hpp | 23 ++++++++ storm/queue/TSPriorityQueue.hpp | 26 ++++++++ storm/queue/TSTimerPriority.hpp | 16 +++++ test/Queue.cpp | 16 +++++ 9 files changed, 264 insertions(+) create mode 100644 storm/Queue.hpp create mode 100644 storm/queue/CSBasePriority.cpp create mode 100644 storm/queue/CSBasePriority.hpp create mode 100644 storm/queue/CSBasePriorityQueue.cpp create mode 100644 storm/queue/CSBasePriorityQueue.hpp create mode 100644 storm/queue/TSPriorityQueue.hpp create mode 100644 storm/queue/TSTimerPriority.hpp create mode 100644 test/Queue.cpp diff --git a/storm/CMakeLists.txt b/storm/CMakeLists.txt index 36fbf04..e02197a 100644 --- a/storm/CMakeLists.txt +++ b/storm/CMakeLists.txt @@ -4,6 +4,7 @@ check_cxx_compiler_flag(-Wno-invalid-offsetof HAS_NO_INVALID_OFFSETOF) file(GLOB STORM_SOURCES "*.cpp" "hash/*.cpp" + "queue/*.cpp" "string/*.cpp" "thread/*.cpp" ) diff --git a/storm/Queue.hpp b/storm/Queue.hpp new file mode 100644 index 0000000..0ffe0e9 --- /dev/null +++ b/storm/Queue.hpp @@ -0,0 +1,7 @@ +#ifndef STORM_QUEUE_HPP +#define STORM_QUEUE_HPP + +#include "storm/queue/TSPriorityQueue.hpp" +#include "storm/queue/TSTimerPriority.hpp" + +#endif diff --git a/storm/queue/CSBasePriority.cpp b/storm/queue/CSBasePriority.cpp new file mode 100644 index 0000000..30e5f4d --- /dev/null +++ b/storm/queue/CSBasePriority.cpp @@ -0,0 +1,92 @@ +#include "storm/queue/CSBasePriority.hpp" +#include "storm/queue/CSBasePriorityQueue.hpp" + +void CSBasePriority::Relink() { + CSBasePriorityQueue* queue = this->m_queue; + + if (!queue) { + return; + } + + void* ptr = queue->operator[](this->m_index); + + this->Unlink(); + + int32_t v18 = queue->Count(); + queue->SetCount(v18 + 1); + + while (v18) { + auto v19 = reinterpret_cast( + reinterpret_cast(ptr) + queue->m_linkOffset); + + CSBasePriority* v20 = queue->Link((v18 - 1) >> 1); + + if (v20->Compare(v19)) { + break; + } + + queue->operator[](v18) = queue->operator[]((v18 - 1) >> 1); + queue->SetLink(v18); + + v18 = (v18 - 1) >> 1; + } + + queue->operator[](v18) = ptr; + queue->SetLink(v18); +} + +void CSBasePriority::Unlink() { + CSBasePriorityQueue* queue = this->m_queue; + + if (!queue) { + return; + } + + int32_t index = this->m_index; + + CSBasePriority* link = this->m_queue->Link(this->m_index); + link->m_queue = 0; + link->m_index = 0; + + void* top = queue->Top(); + + int32_t v8 = queue->Count(); + int32_t v9 = queue->Count() - 1; + + queue->SetCount(v9); + + if (index == v9) { + return; + } + + int32_t hBound = v9 - 1; + int32_t lBound = (v9 - 2) >> 1; + + if (index < hBound && index <= lBound >> 1) { + while (true) { + int32_t v11 = 2 * index + 1; + + if (v11 < hBound) { + if (queue->Link(2 * index + 2)->Compare(queue->Link(v11))) { + v11 = 2 * index + 2; + } + } + + if (reinterpret_cast(reinterpret_cast(top) + queue->m_linkOffset)->Compare(queue->Link(v11))) { + break; + } + + queue->operator[](index) = queue->operator[](v11); + queue->SetLink(index); + + index = v11; + + if (v11 > lBound) { + break; + } + } + } + + queue->operator[](index) = top; + queue->SetLink(index); +} diff --git a/storm/queue/CSBasePriority.hpp b/storm/queue/CSBasePriority.hpp new file mode 100644 index 0000000..2c53ad1 --- /dev/null +++ b/storm/queue/CSBasePriority.hpp @@ -0,0 +1,20 @@ +#ifndef STORM_QUEUE_CS_BASE_PRIORITY_HPP +#define STORM_QUEUE_CS_BASE_PRIORITY_HPP + +#include + +class CSBasePriorityQueue; + +class CSBasePriority { + public: + // Member variables + CSBasePriorityQueue* m_queue; + uint32_t m_index; + + // Member functions + virtual bool Compare(CSBasePriority* a) = 0; + void Unlink(); + void Relink(); +}; + +#endif diff --git a/storm/queue/CSBasePriorityQueue.cpp b/storm/queue/CSBasePriorityQueue.cpp new file mode 100644 index 0000000..36376fc --- /dev/null +++ b/storm/queue/CSBasePriorityQueue.cpp @@ -0,0 +1,63 @@ +#include "storm/queue/CSBasePriorityQueue.hpp" +#include "storm/queue/CSBasePriority.hpp" + +void* CSBasePriorityQueue::Dequeue() { + if (this->Count()) { + void* bottom = this->operator[](0); + this->Remove(0); + return bottom; + } else { + return nullptr; + } +} + +void CSBasePriorityQueue::Enqueue(void* val) { + int32_t v3 = this->Count(); + this->SetCount(v3 + 1); + + while (true) { + int32_t v4 = (v3 - 1) >> 1; + + if (!v3) { + break; + } + + if (this->Link(v4)->Compare(reinterpret_cast(reinterpret_cast(val) + this->m_linkOffset))) { + break; + } + + this->operator[](v3) = this->operator[](v4); + this->SetLink(v3); + + v3 = (v3 - 1) >> 1; + } + + this->operator[](v3) = val; + this->SetLink(v3); +} + +CSBasePriority* CSBasePriorityQueue::Link(uint32_t index) const { + return reinterpret_cast( + reinterpret_cast(this->m_data[index]) + this->m_linkOffset); +} + +void CSBasePriorityQueue::SetLink(uint32_t index) { + CSBasePriority* link = this->Link(index); + + link->m_index = index; + link->m_queue = this; +} + +void* CSBasePriorityQueue::Top() { + int32_t count = this->Count(); + + if (count) { + return this->m_data[count - 1]; + } else { + return nullptr; + } +} + +void CSBasePriorityQueue::Remove(uint32_t index) { + this->Link(index)->Unlink(); +} diff --git a/storm/queue/CSBasePriorityQueue.hpp b/storm/queue/CSBasePriorityQueue.hpp new file mode 100644 index 0000000..58df369 --- /dev/null +++ b/storm/queue/CSBasePriorityQueue.hpp @@ -0,0 +1,23 @@ +#ifndef STORM_QUEUE_CS_BASE_PRIORITY_QUEUE_HPP +#define STORM_QUEUE_CS_BASE_PRIORITY_QUEUE_HPP + +#include "storm/Array.hpp" +#include + +class CSBasePriority; + +class CSBasePriorityQueue : public TSGrowableArray { + public: + // Member variables + uint32_t m_linkOffset; + + // Member functions + void* Dequeue(); + void Enqueue(void* val); + CSBasePriority* Link(uint32_t index) const; + void Remove(uint32_t index); + void SetLink(uint32_t index); + void* Top(); +}; + +#endif diff --git a/storm/queue/TSPriorityQueue.hpp b/storm/queue/TSPriorityQueue.hpp new file mode 100644 index 0000000..011787d --- /dev/null +++ b/storm/queue/TSPriorityQueue.hpp @@ -0,0 +1,26 @@ +#ifndef STORM_QUEUE_TS_PRIORITY_QUEUE_HPP +#define STORM_QUEUE_TS_PRIORITY_QUEUE_HPP + +#include "storm/queue/CSBasePriorityQueue.hpp" +#include + +template +class TSPriorityQueue : public CSBasePriorityQueue { + public: + // Member functions + TSPriorityQueue(uint32_t linkOffset); + T* Dequeue(); +}; + +template +TSPriorityQueue::TSPriorityQueue(uint32_t linkOffset) + : CSBasePriorityQueue() { + this->m_linkOffset = linkOffset; +} + +template +T* TSPriorityQueue::Dequeue() { + return static_cast(CSBasePriorityQueue::Dequeue()); +} + +#endif diff --git a/storm/queue/TSTimerPriority.hpp b/storm/queue/TSTimerPriority.hpp new file mode 100644 index 0000000..17e0979 --- /dev/null +++ b/storm/queue/TSTimerPriority.hpp @@ -0,0 +1,16 @@ +#include "storm/queue/CSBasePriority.hpp" + +template +class TSTimerPriority : public CSBasePriority { + public: + // Member variables + T m_val; + + // Member functions + virtual bool Compare(CSBasePriority* a); +}; + +template +bool TSTimerPriority::Compare(CSBasePriority* a) { + return this->m_val - static_cast*>(a)->m_val <= 0; +} diff --git a/test/Queue.cpp b/test/Queue.cpp new file mode 100644 index 0000000..01582e7 --- /dev/null +++ b/test/Queue.cpp @@ -0,0 +1,16 @@ +#include "storm/Queue.hpp" +#include "test/Test.hpp" + +struct TestPriority : TSTimerPriority { +}; + +struct TestElement { + TestPriority m_priority; +}; + +TEST_CASE("TSPriorityQueue", "[queue]") { + SECTION("constructs correctly") { + auto queue = TSPriorityQueue(offsetof(TestElement, m_priority)); + REQUIRE(queue.Dequeue() == nullptr); + } +}