181 lines
3.8 KiB
C++
181 lines
3.8 KiB
C++
#ifndef QUEUE_H
|
|
#define QUEUE_H
|
|
|
|
#include <cstdint>
|
|
#include <new>
|
|
#include <print>
|
|
#include <format>
|
|
#include <expected>
|
|
|
|
#define DEFAULT_QUEUE_SIZE 4
|
|
|
|
enum class QueueErr {
|
|
ok,
|
|
bad_alloc,
|
|
empty,
|
|
};
|
|
|
|
template <typename T>
|
|
requires std::formattable<T, char>
|
|
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<T, QueueErr> peek();
|
|
|
|
std::expected<T, QueueErr> dequeue();
|
|
|
|
void print();
|
|
};
|
|
|
|
template <typename T>
|
|
requires std::formattable<T, char>
|
|
Queue<T>::Queue() {
|
|
this->cap = 0;
|
|
this->len = 0;
|
|
this->head = 0;
|
|
this->tail = 0;
|
|
this->data = new T[DEFAULT_QUEUE_SIZE];
|
|
}
|
|
|
|
template <typename T>
|
|
requires std::formattable<T, char>
|
|
Queue<T>::Queue(uint64_t size) {
|
|
this->cap = 0;
|
|
this->len = 0;
|
|
this->head = 0;
|
|
this->tail = 0;
|
|
this->data = new T[size];
|
|
|
|
}
|
|
|
|
|
|
template <typename T>
|
|
requires std::formattable<T, char>
|
|
QueueErr Queue<T>::enqueue(T value) {
|
|
if (this->len >= this->cap) {
|
|
uint64_t new_cap = this->cap * 2;
|
|
T *tmp;
|
|
|
|
try {
|
|
T *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) % 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 <typename T>
|
|
requires std::formattable<T, char>
|
|
std::expected<T, QueueErr> Queue<T>::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) % 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 <typename T>
|
|
requires std::formattable<T, char>
|
|
std::expected<T, QueueErr> Queue<T>::peek() {
|
|
if (this->len == 0) {
|
|
return std::unexpected(QueueErr::empty);
|
|
}
|
|
|
|
T out;
|
|
out = this->data[this->tail];
|
|
this->len--;
|
|
this->tail = (this->tail + 1) % this->cap;
|
|
|
|
return out;
|
|
}
|
|
|
|
template <typename T>
|
|
requires std::formattable<T, char>
|
|
void Queue<T>::print() {
|
|
if (this->len == 0) {
|
|
std::println("Queue is empty.");
|
|
return;
|
|
}
|
|
|
|
std::println("Lenght: {}", this->len);
|
|
std::println("Capacity: {}", this->cap);
|
|
for (uint64_t i = 0; i < this->cap; i++) {
|
|
if (this->tail == this->head) {
|
|
std::println("H/T --->");
|
|
} else if (this->tail == i) {
|
|
std::println("Tail--->");
|
|
} else if (this->head == i) {
|
|
std::println("Head--->");
|
|
} else {
|
|
std::println("|{:^20}|", "");
|
|
}
|
|
|
|
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
|