fix util::stack_vector

This commit is contained in:
MihailRis 2025-10-16 18:17:30 +03:00
parent ec94abccbc
commit fa6950ca87
2 changed files with 56 additions and 18 deletions

View File

@ -5,20 +5,30 @@
namespace util { namespace util {
template<typename T, int capacity> template<typename T, int capacity>
class stack_vector { class stack_vector {
struct buffer {
alignas(alignof(T)) char* data[sizeof(T) * capacity];
T* ptr() {
return reinterpret_cast<T*>(data);
}
const T* ptr() const {
return reinterpret_cast<const T*>(data);
}
};
public: public:
stack_vector() : size_(0) {} stack_vector() : size_(0) {}
stack_vector(const stack_vector<T, capacity>& other) stack_vector(const stack_vector<T, capacity>& other)
: size_(other.size_) { : size_(other.size_) {
for (int i = 0; i < size_; ++i) { for (int i = 0; i < size_; ++i) {
new (&data_[i]) T(other.data_[i]); new (&data_.ptr()[i]) T(other.data_.ptr()[i]);
} }
} }
stack_vector(stack_vector<T, capacity>&& other) noexcept stack_vector(stack_vector<T, capacity>&& other) noexcept
: size_(other.size_) { : size_(other.size_) {
for (int i = 0; i < size_; ++i) { for (int i = 0; i < size_; ++i) {
new (&data_[i]) T(std::move(other.data_[i])); new (&data_.ptr()[i]) T(std::move(other.data_.ptr()[i]));
} }
other.size_ = 0; other.size_ = 0;
} }
@ -29,17 +39,25 @@ namespace util {
"initializer list exceeds stack vector capacity" "initializer list exceeds stack vector capacity"
); );
for (const auto& value : init) { for (const auto& value : init) {
new (&data_[size_++]) T(value); new (&data_.ptr()[size_++]) T(value);
} }
} }
~stack_vector() { ~stack_vector() = default;
clear();
}
void push_back(const T& value) { void push_back(const T& value) {
if (size_ < capacity) { if (size_ < capacity) {
data_[size_++] = value; auto data = reinterpret_cast<char*>(data_.ptr() + (size_++));
new (data) T(value);
} else {
throw std::overflow_error("stack vector capacity exceeded");
}
}
void push_back(T&& value) {
if (size_ < capacity) {
auto data = reinterpret_cast<char*>(data_.ptr() + (size_++));
new (data) T(std::move(value));
} else { } else {
throw std::overflow_error("stack vector capacity exceeded"); throw std::overflow_error("stack vector capacity exceeded");
} }
@ -47,7 +65,7 @@ namespace util {
void pop_back() { void pop_back() {
if (size_ > 0) { if (size_ > 0) {
data_[size_ - 1].~T(); data_.ptr()[size_ - 1].~T();
--size_; --size_;
} else { } else {
throw std::underflow_error("stack vector is empty"); throw std::underflow_error("stack vector is empty");
@ -56,31 +74,31 @@ namespace util {
void clear() { void clear() {
for (int i = 0; i < size_; ++i) { for (int i = 0; i < size_; ++i) {
data_[i].~T(); data_.ptr()[i].~T();
} }
size_ = 0; size_ = 0;
} }
T& operator[](int index) { T& operator[](int index) {
return data_[index]; return data_.ptr()[index];
} }
const T& operator[](int index) const { const T& operator[](int index) const {
return data_[index]; return data_.ptr()[index];
} }
T& at(int index) { T& at(int index) {
if (index < 0 || index >= size_) { if (index < 0 || index >= size_) {
throw std::out_of_range("index out of range"); throw std::out_of_range("index out of range");
} }
return data_[index]; return data_.ptr()[index];
} }
const T& at(int index) const { const T& at(int index) const {
if (index < 0 || index >= size_) { if (index < 0 || index >= size_) {
throw std::out_of_range("index out of range"); throw std::out_of_range("index out of range");
} }
return data_[index]; return data_.ptr()[index];
} }
int size() const { int size() const {
@ -96,22 +114,22 @@ namespace util {
} }
auto begin() { auto begin() {
return data_; return data_.ptr();
} }
auto end() { auto end() {
return data_ + size_; return data_.ptr() + size_;
} }
auto begin() const { auto begin() const {
return data_; return data_.ptr();
} }
auto end() const { auto end() const {
return data_ + size_; return data_.ptr() + size_;
} }
private: private:
T data_[capacity]; buffer data_;
int size_; int size_;
}; };
} }

View File

@ -0,0 +1,20 @@
#include <gtest/gtest.h>
#include <string>
#include "util/stack_vector.hpp"
using namespace util;
TEST(util, stack_vector) {
stack_vector<std::string, 4> vec;
vec.push_back("hello");
vec.push_back("world");
vec.push_back("?");
ASSERT_EQ(3, vec.size());
vec.pop_back();
ASSERT_EQ(2, vec.size());
vec.clear();
ASSERT_EQ(0, vec.size());
ASSERT_TRUE(vec.empty());
vec.push_back("test");
}