/* * Created by Brett on 26/12/22. * Licensed under GNU General Public License V3.0 * See LICENSE file for license detail */ #ifndef BLT_QUEUE_H #define BLT_QUEUE_H /** * Do no use any queue in this file. They are slower than std::queue. */ namespace blt { template struct node { T t; node* next; node(const T& t, node* next) { this->t = t; this->next = next; } }; /** * Standard array backed first in first out queue * @tparam T type stored in the queue */ template class flat_stack { private: int m_size = 16; int m_insertIndex = 0; T* m_data = new T[m_size]; /** * Expands the internal array to the new size, copying over the data and shifting its minimal position to index 0 * and deletes the old array from memory. * @param newSize new size of the internal array */ void expand(int newSize) { auto tempData = new T[newSize]; for (int i = 0; i < m_insertIndex; i++) tempData[i] = m_data[i]; delete[] m_data; m_data = tempData; m_size = newSize; } public: void push(const T& t) { if (m_insertIndex >= m_size) { expand(m_size * 2); } m_data[m_insertIndex++] = t; } /** * Warning does not contain runtime error checking! * @return the element at the "front" of the queue. */ [[nodiscard]] const T& top() const { return m_data[m_insertIndex - 1]; } void pop() { // TODO: throw exception when popping would result in a overflow? // I didn't make it an exception here due to not wanting to import the class. if (isEmpty()) return; m_insertIndex--; } bool isEmpty() { return m_insertIndex <= 0; } int size() { return m_insertIndex; } ~flat_stack() { delete[](m_data); } }; /** * Standard array backed first in last out queue (stack) * @tparam T type stored in the queue */ template class flat_queue { private: int m_size = 16; int m_headIndex = 0; int m_insertIndex = 0; T* m_data = new T[m_size]; /** * Expands the internal array to the new size, copying over the data and shifting its minimal position to index 0 * and deletes the old array from memory. * @param newSize new size of the internal array */ void expand(int newSize) { auto tempData = new T[newSize]; for (int i = 0; i < m_size - m_headIndex; i++) tempData[i] = m_data[i + m_headIndex]; delete[] m_data; m_insertIndex = m_size - m_headIndex; m_headIndex = 0; m_data = tempData; m_size = newSize; } public: void push(const T& t) { if (m_insertIndex >= m_size) { expand(m_size * 2); } m_data[m_insertIndex++] = t; } /** * Warning does not contain runtime error checking! * @return the element at the "front" of the queue. */ [[nodiscard]] const T& front() const { return m_data[m_headIndex]; } void pop() { // TODO: throw exception when popping would result in a overflow? // I didn't make it an exception here due to not wanting to import the class. if (isEmpty()) return; m_headIndex++; } bool isEmpty() { return m_headIndex >= m_size; } int size() { return m_insertIndex - m_headIndex; } ~flat_queue() { delete[](m_data); } }; // avoid this. it is very slow. template class node_queue { private: node* m_head; public: void push(const T& t) { if (m_head == nullptr) m_head = new node(t, nullptr); else m_head = new node(t, m_head); } [[nodiscard]] const T& front() const { return m_head->t; } void pop() { auto nextNode = m_head->next; delete (m_head); m_head = nextNode; } ~node_queue() { auto next = m_head; while (next != nullptr) { auto nextNode = next->next; delete (next); next = nextNode; } } }; } #endif //BLT_QUEUE_H