#ifndef STACK_H #define STACK_H #include #include #include #include #include /// @brief Default initial size for the stack #define DEFAULT_STACK_SIZE 4 /** * @brief Error codes for stack operations */ enum class StackErr { ok, ///< Operation successful bad_alloc, ///< Memory allocation failed empty, ///< Stack is empty }; /** * @brief Generic stack implementation * * @tparam T Type of elements stored in the stack * @note T must be formattable with std::format */ template requires std::formattable class Stack { private: uint64_t len; ///< Current number of elements uint64_t cap; ///< Current capacity T *data; ///< Pointer to data array public: /** * @brief Construct a new Stack object */ Stack(); /** * @brief Destroy the Stack object */ ~Stack(); /** * @brief Remove and return the top element * * @return std::expected Top element or error */ std::expected pop(); /** * @brief Get the top element without removing it * * @return std::expected Top element or error */ std::expected peek(); /** * @brief Push a new element onto the stack * * @param val Value to push * @return StackErr Result of the operation */ StackErr push(T val); /** * @brief Get current size of the stack * * @return uint64_t Number of elements */ uint64_t size(); /** * @brief Print stack contents to console */ void print(); }; template requires std::formattable uint64_t Stack::size() { return this->len; } template requires std::formattable Stack::Stack() { this->data = new T[DEFAULT_STACK_SIZE]; this->cap = DEFAULT_STACK_SIZE; this->len = 0; } template requires std::formattable Stack::~Stack() { delete[] this->data; } template requires std::formattable StackErr Stack::push(T value) { /// Resize if needed if (this->len >= this->cap) { uint64_t new_capacity = this->cap * 2; T *tmp; try { tmp = new T[new_capacity]; } catch (const std::bad_alloc& e) { return StackErr::bad_alloc; } for (int i = 0; i < this->len; i++) { tmp[i] = this->data[i]; } delete[] this->data; this->data = tmp; this->cap = new_capacity; } this->data[this->len] = value; this->len++; return StackErr::ok; } template requires std::formattable std::expected Stack::pop() { /// Check empty stack if (this->len == 0) { return std::unexpected(StackErr::empty); } T return_val = this->data[this->len - 1]; this->len--; /// Shrink if too much unused space if (this->cap / 4 > this->len) { uint64_t new_capacity = this->cap / 2; T *tmp; try { tmp = new T[new_capacity]; } catch (const std::bad_alloc& e) { return std::unexpected(StackErr::bad_alloc); } for (int i = 0; i < this->len; i++) { tmp[i] = this->data[i]; } delete[] this->data; this->data = tmp; this->cap = new_capacity; } return return_val; } template requires std::formattable std::expected Stack::peek() { /// Check empty stack if (this->len == 0) { return std::unexpected(StackErr::empty); } return this->data[this->len - 1]; } template requires std::formattable void Stack::print() { std::println("Stack:"); std::println("Length: {}.", this->len); std::println("Capacity: {}.", this->cap); std::println("{:^22}", "Datos"); std::println("{:^22}", "|"); std::println("{:^22}", "v"); for (uint64_t i = 0; i < this->cap; i++) { if (i < this->len) { std::println("[{:^20}]", this->data[i]); } else { std::println("[{:^20}]", "EMPTY"); } } } #endif // STACK_H