#ifndef QUEUE_H #define QUEUE_H #include #include #include #include #include #define DEFAULT_QUEUE_SIZE 4 enum class QueueErr { ok, bad_alloc, empty, }; template requires std::formattable class Queue { private: uint64_t len; uint64_t cap; uint64_t head; uint64_t tail; T *data; public: Queue(); Queue(uint64_t size); ~Queue(); QueueErr enqueue(T value); std::expected peek(); std::expected dequeue(); void print(); }; template requires std::formattable Queue::Queue() { this->cap = DEFAULT_QUEUE_SIZE; this->len = 0; this->head = 0; this->tail = 0; this->data = new T[DEFAULT_QUEUE_SIZE]; } template requires std::formattable Queue::Queue(uint64_t size) { this->cap = DEFAULT_QUEUE_SIZE; this->len = 0; this->head = 0; this->tail = 0; this->data = new T[size]; } template requires std::formattable Queue::~Queue() { delete[] this->data; this->cap = 0; this->len = 0; this->head = 0; this->tail = 0; } template requires std::formattable QueueErr Queue::enqueue(T value) { if (this->len >= this->cap) { uint64_t new_cap = this->cap * 2; T *tmp; try { tmp = new T[new_cap]; } catch(const std::bad_alloc& e) { return QueueErr::bad_alloc; } for (uint64_t i = 0; i < this->len; i++) { uint64_t index = (this->tail + i) % this->cap; tmp[i] = this->data[index]; } delete[] this->data; this->data = tmp; this->cap = new_cap; this->tail = 0; this->head = this->len; } this->data[this->head] = value; this->len++; this->head = (this->head + 1) % this->cap; return QueueErr::ok; } template requires std::formattable std::expected Queue::dequeue() { if (this->len == 0) { return std::unexpected(QueueErr::empty); } if (this->cap > DEFAULT_QUEUE_SIZE && this->cap / 4 > this->len) { uint64_t new_cap = this->cap / 2; if (new_cap < DEFAULT_QUEUE_SIZE) { new_cap = DEFAULT_QUEUE_SIZE; } T *tmp; try { tmp = new T[new_cap]; } catch(const std::bad_alloc& e) { return std::unexpected(QueueErr::bad_alloc); } for (uint64_t i = 0; i < this->len; i++) { uint64_t index = (this->tail + i) % this->cap; tmp[i] = this->data[index]; } delete[] this->data; this->data = tmp; this->cap = new_cap; this->tail = 0; this->head = this->len; } T out; out = this->data[this->tail]; this->len--; this->tail = (this->tail + 1) % this->cap; return out; } template requires std::formattable std::expected Queue::peek() { if (this->len == 0) { return std::unexpected(QueueErr::empty); } T out; out = this->data[this->tail]; return out; } template requires std::formattable void Queue::print() { if (this->len == 0) { std::println("Queue is empty."); return; } std::println("Length: {}", this->len); std::println("Capacity: {}", this->cap); for (uint64_t i = 0; i < this->cap; i++) { if (i == this->tail && i == this->head) { std::print("H/T --->"); } else if (i == this->tail) { std::print("Tail--->"); } else if (i == this->head) { std::print("Head--->"); } else { std::print(" "); } uint64_t dist = (i + this->cap - this->tail) % this->cap; if (dist < this->len) { std::println("|{:^20}|", this->data[i]); } else { std::println("|{:^20}|", ""); } } } #endif // !QUEUE_H