From d778a3190a085b70aa36c5f8cc9d99ea8423ade3 Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Wed, 21 Dec 2022 21:53:18 +0100 Subject: [PATCH] Finish vector --- src/driver/vector.hpp | 329 +++++++++++++++++++++++------------------- 1 file changed, 181 insertions(+), 148 deletions(-) diff --git a/src/driver/vector.hpp b/src/driver/vector.hpp index 69c716a..68563c5 100644 --- a/src/driver/vector.hpp +++ b/src/driver/vector.hpp @@ -2,194 +2,227 @@ #include "type_traits.hpp" #include "memory.hpp" #include "exception.hpp" +#include "finally.hpp" -template -class vector +namespace utils { -public: - using type = T; - - vector() = default; - - ~vector() + template + class vector { - this->clear(); - } + public: + using type = T; - vector(const vector& obj) - : vector() - { - this->operator=(obj); - } + vector() = default; - vector(vector&& obj) noexcept - : vector() - { - this->operator=(std::move(obj)); - } - - vector& operator=(const vector& obj) - { - if (this != &obj) + ~vector() { 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; - } - - vector& operator=(vector&& obj) noexcept - { - if (this != &obj) + T& push_back(T obj) { - this->clear(); + if (this->size_ + 1 > this->capacity_) + { + this->reserve(max(this->capacity_, 5) * 2); + } - this->storage_ = obj.storage_; - this->capacity_ = obj.capacity_; - this->size_ = obj.size_; + auto* data = this->data() + this->size_++; + new(data) T(std::move(obj)); - obj.storage_ = nullptr; - obj.capacity_ = 0; - obj.size_ = 0; + return *data; } - return *this; - } - - void reserve(size_t capacity) - { - if (this->capacity_ >= capacity) + T& operator[](const size_t index) { - return; + return this->at(index); } - auto* old_mem = this->storage_; - auto* old_data = this->data(); - - this->storage_ = allocate_memory_for_capacity(capacity); - this->capacity_ = capacity; - - auto _ = finally([&old_mem] + const T& operator[](const size_t index) const { - 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(); - } - } - - T& push_back(T obj) - { - if (this->size_ + 1 > this->capacity_) - { - this->reserve(max(this->capacity_, 5) * 2); + return this->at(index); } - auto* data = this->data() + this->size_++; - new(data) T(std::move(obj)); - - return *data; - } - - - T& at(size_t index) - { - if (index >= this->size_) + T& at(const size_t index) { - 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(size_t index) const - { - if (index >= this->size_) + const T& at(const size_t index) const { - 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() - { - auto* data = this->data(); - for (size_t i = 0; i < this->size_; ++i) + void clear() { - 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_); - 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_) + [[nodiscard]] size_t capacity() const { - return nullptr; + return this->capacity_; } - return static_cast(align_pointer(this->storage_)); - } - - const T* data() const - { - if (!this->storage_) + [[nodiscard]] size_t size() const { - return nullptr; + return this->size_; } - return static_cast(align_pointer(this->storage_)); - } + T* data() + { + if (!this->storage_) + { + return nullptr; + } -private: - void* storage_{nullptr}; - size_t capacity_{0}; - size_t size_{0}; + return static_cast(align_pointer(this->storage_)); + } - 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; - } + const T* data() const + { + if (!this->storage_) + { + return nullptr; + } - static void free_memory(void* memory) - { - memory::free_non_paged_memory(memory); - } + return static_cast(align_pointer(this->storage_)); + } - template - static U* align_pointer(U* pointer) - { - const auto align_bits = alignof(T) - 1; - auto ptr = static_cast(pointer); - ptr = (ptr + align_bits) & (~align_bits); + T* begin() + { + return this->data(); + } - return static_cast(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 + static U* align_pointer(U* pointer) + { + const auto align_bits = alignof(T) - 1; + auto ptr = reinterpret_cast(pointer); + ptr = (ptr + align_bits) & (~align_bits); + + return reinterpret_cast(ptr); + } + }; +}