Finish vector

This commit is contained in:
Maurice Heumann 2022-12-21 21:53:18 +01:00
parent 4cd7e711f7
commit d778a3190a

View File

@ -2,194 +2,227 @@
#include "type_traits.hpp" #include "type_traits.hpp"
#include "memory.hpp" #include "memory.hpp"
#include "exception.hpp" #include "exception.hpp"
#include "finally.hpp"
template <typename T> namespace utils
class vector
{ {
public: template <typename T>
using type = T; class vector
vector() = default;
~vector()
{ {
this->clear(); public:
} using type = T;
vector(const vector& obj) vector() = default;
: vector()
{
this->operator=(obj);
}
vector(vector&& obj) noexcept ~vector()
: vector()
{
this->operator=(std::move(obj));
}
vector& operator=(const vector& obj)
{
if (this != &obj)
{ {
this->clear(); this->clear();
this->reserve(obj.size_); }
for (size_t i = 0; i < obj.size_; ++i) vector(const vector& obj)
: vector()
{
this->operator=(obj);
}
vector(vector&& obj) noexcept
: vector()
{
this->operator=(std::move(obj));
}
vector& operator=(const vector& obj)
{
if (this != &obj)
{ {
this->push_back(obj.at(i)); this->clear();
this->reserve(obj.size_);
for (size_t i = 0; i < obj.size_; ++i)
{
this->push_back(obj.at(i));
}
}
return *this;
}
vector& operator=(vector&& obj) noexcept
{
if (this != &obj)
{
this->clear();
this->storage_ = obj.storage_;
this->capacity_ = obj.capacity_;
this->size_ = obj.size_;
obj.storage_ = nullptr;
obj.capacity_ = 0;
obj.size_ = 0;
}
return *this;
}
void reserve(size_t capacity)
{
if (this->capacity_ >= capacity)
{
return;
}
auto* old_mem = this->storage_;
auto* old_data = this->data();
this->storage_ = allocate_memory_for_capacity(capacity);
this->capacity_ = capacity;
auto _ = utils::finally([&old_mem]
{
free_memory(old_mem);
});
auto* data = this->data();
for (size_t i = 0; i < this->size_; ++i)
{
new(data + i) T(std::move(old_data[i]));
old_data[i].~T();
} }
} }
return *this; T& push_back(T obj)
}
vector& operator=(vector&& obj) noexcept
{
if (this != &obj)
{ {
this->clear(); if (this->size_ + 1 > this->capacity_)
{
this->reserve(max(this->capacity_, 5) * 2);
}
this->storage_ = obj.storage_; auto* data = this->data() + this->size_++;
this->capacity_ = obj.capacity_; new(data) T(std::move(obj));
this->size_ = obj.size_;
obj.storage_ = nullptr; return *data;
obj.capacity_ = 0;
obj.size_ = 0;
} }
return *this; T& operator[](const size_t index)
}
void reserve(size_t capacity)
{
if (this->capacity_ >= capacity)
{ {
return; return this->at(index);
} }
auto* old_mem = this->storage_; const T& operator[](const size_t index) const
auto* old_data = this->data();
this->storage_ = allocate_memory_for_capacity(capacity);
this->capacity_ = capacity;
auto _ = finally([&old_mem]
{ {
free_memory(old_mem); return this->at(index);
});
auto* data = this->data();
for (size_t i = 0; i < this->size_; ++i)
{
new(data + i) T(std::move(old_data[i]));
old_data[i]->~T();
}
}
T& push_back(T obj)
{
if (this->size_ + 1 > this->capacity_)
{
this->reserve(max(this->capacity_, 5) * 2);
} }
auto* data = this->data() + this->size_++; T& at(const size_t index)
new(data) T(std::move(obj));
return *data;
}
T& at(size_t index)
{
if (index >= this->size_)
{ {
throw std::runtime_error("Out of bounds access"); if (index >= this->size_)
{
throw std::runtime_error("Out of bounds access");
}
return this->data()[index];
} }
return this->data()[index]; const T& at(const size_t index) const
}
const T& at(size_t index) const
{
if (index >= this->size_)
{ {
throw std::runtime_error("Out of bounds access"); if (index >= this->size_)
{
throw std::runtime_error("Out of bounds access");
}
return this->data()[index];
} }
return this->data()[index]; void clear()
}
void clear()
{
auto* data = this->data();
for (size_t i = 0; i < this->size_; ++i)
{ {
data[i]->~T(); auto* data = this->data();
for (size_t i = 0; i < this->size_; ++i)
{
data[i].~T();
}
free_memory(this->storage_);
this->storage_ = nullptr;
this->capacity_ = 0;
this->size_ = 0;
} }
free_memory(this->storage_); [[nodiscard]] size_t capacity() const
this->storage_ = nullptr;
this->capacity_ = nullptr;
this->size_ = nullptr;
}
size_t capacity() const
{
return this->capacity_;
}
size_t size() const
{
return this->size_;
}
T* data()
{
if (!this->storage_)
{ {
return nullptr; return this->capacity_;
} }
return static_cast<T*>(align_pointer(this->storage_)); [[nodiscard]] size_t size() const
}
const T* data() const
{
if (!this->storage_)
{ {
return nullptr; return this->size_;
} }
return static_cast<const T*>(align_pointer(this->storage_)); T* data()
} {
if (!this->storage_)
{
return nullptr;
}
private: return static_cast<T*>(align_pointer(this->storage_));
void* storage_{nullptr}; }
size_t capacity_{0};
size_t size_{0};
static void* allocate_memory_for_capacity(const size_t capacity) const T* data() const
{ {
constexpr auto alignment = alignof(T); if (!this->storage_)
auto* memory = memory::allocate_non_paged_memory(capacity * sizeof(T) + alignment); {
return memory; return nullptr;
} }
static void free_memory(void* memory) return static_cast<const T*>(align_pointer(this->storage_));
{ }
memory::free_non_paged_memory(memory);
}
template <typename U> T* begin()
static U* align_pointer(U* pointer) {
{ return this->data();
const auto align_bits = alignof(T) - 1; }
auto ptr = static_cast<intptr_t>(pointer);
ptr = (ptr + align_bits) & (~align_bits);
return static_cast<U*>(ptr); const T* begin() const
} {
}; return this->data();
}
T* end()
{
return this->data() + this->size_;
}
const T* end() const
{
return this->data() + this->size_;
}
private:
void* storage_{nullptr};
size_t capacity_{0};
size_t size_{0};
static void* allocate_memory_for_capacity(const size_t capacity)
{
constexpr auto alignment = alignof(T);
auto* memory = memory::allocate_non_paged_memory(capacity * sizeof(T) + alignment);
return memory;
}
static void free_memory(void* memory)
{
memory::free_non_paged_memory(memory);
}
template <typename U>
static U* align_pointer(U* pointer)
{
const auto align_bits = alignof(T) - 1;
auto ptr = reinterpret_cast<intptr_t>(pointer);
ptr = (ptr + align_bits) & (~align_bits);
return reinterpret_cast<U*>(ptr);
}
};
}