Untitled
unknown
plain_text
2 years ago
7.2 kB
1
Indexable
Never
#pragma once #include <cassert> #include <cstdlib> #include <new> #include <utility> #include <memory> #include <type_traits> template <typename T> class RawMemory { public: RawMemory() = default; RawMemory(const RawMemory&) = delete; RawMemory& operator=(const RawMemory& rhs) = delete; RawMemory(RawMemory&& other) noexcept : buffer_(other.buffer_) , capacity_(other.capacity_) { other.buffer_ = nullptr; other.capacity_ = 0; } RawMemory& operator=(RawMemory&& rhs) noexcept { if (this != &rhs) { Deallocate(buffer_); buffer_ = rhs.buffer_; capacity_ = rhs.capacity_; rhs.buffer_ = nullptr; rhs.capacity_ = 0; } return *this; } explicit RawMemory(size_t capacity) : buffer_(Allocate(capacity)) , capacity_(capacity) { } ~RawMemory() { Deallocate(buffer_); } T* operator+(size_t offset) noexcept { // Разрешается получать адрес ячейки памяти, следующей за последним элементом массива assert(offset <= capacity_); return buffer_ + offset; } const T* operator+(size_t offset) const noexcept { return const_cast<RawMemory&>(*this) + offset; } const T& operator[](size_t index) const noexcept { return const_cast<RawMemory&>(*this)[index]; } T& operator[](size_t index) noexcept { assert(index < capacity_); return buffer_[index]; } void Swap(RawMemory& other) noexcept { std::swap(buffer_, other.buffer_); std::swap(capacity_, other.capacity_); } const T* GetAddress() const noexcept { return buffer_; } T* GetAddress() noexcept { return buffer_; } size_t Capacity() const { return capacity_; } private: // Выделяет сырую память под n элементов и возвращает указатель на неё static T* Allocate(size_t n) { return n != 0 ? static_cast<T*>(operator new(n * sizeof(T))) : nullptr; } // Освобождает сырую память, выделенную ранее по адресу buf при помощи Allocate static void Deallocate(T* buf) noexcept { operator delete(buf); } T* buffer_ = nullptr; size_t capacity_ = 0; }; template <typename T> class Vector { public: Vector() = default; Vector(const Vector& other) : data_(other.size_) , size_(other.size_) { std::uninitialized_copy_n(other.data_.GetAddress(), other.size_, data_.GetAddress()); } Vector& operator=(const Vector& rhs) { if (this != &rhs) { if (rhs.size_ > data_.Capacity()) { Vector rhs_copy(rhs); Swap(rhs_copy); } else { if (rhs.size_ < size_) { for (size_t i = 0; i != rhs.size_; ++i) { data_[i] = rhs.data_[i]; } std::destroy_n(data_.GetAddress(), size_ - rhs.size_); } else { for (size_t i = 0; i != size_; ++i) { data_[i] = rhs.data_[i]; } std::uninitialized_copy_n(rhs.data_.GetAddress(), rhs.size_ - size_, data_.GetAddress()); } size_ = rhs.size_; } } return *this; } Vector(Vector&& other) noexcept { Swap(other); other.size_ = 0; } Vector& operator=(Vector&& rhs) noexcept { if (this != &rhs) { Swap(rhs); rhs.size_ = 0; } return *this; } void Swap(Vector& other) noexcept { data_.Swap(other.data_); std::swap(size_, other.size_); } explicit Vector(size_t size) : data_(size) , size_(size) // { std::uninitialized_value_construct_n(data_.GetAddress(), size); } ~Vector() { std::destroy_n(data_.GetAddress(), size_); } size_t Size() const noexcept { return size_; } size_t Capacity() const noexcept { return data_.Capacity(); } const T& operator[](size_t index) const noexcept { return const_cast<Vector&>(*this)[index]; } T& operator[](size_t index) noexcept { assert(index < size_); return data_[index]; } void Reserve(size_t new_capacity) { if (new_capacity <= data_.Capacity()) { return; } RawMemory<T> new_data(new_capacity); // constexpr оператор if будет вычислен во время компиляции if constexpr (std::is_nothrow_move_constructible_v<T> or not std::is_copy_constructible_v<T>) { std::uninitialized_move_n(data_.GetAddress(), size_, new_data.GetAddress()); } else { std::uninitialized_copy_n(data_.GetAddress(), size_, new_data.GetAddress()); } std::destroy_n(data_.GetAddress(), size_); data_.Swap(new_data); } void Resize(size_t new_size) { if (size_ < new_size) { if (Capacity() < new_size) { Reserve(new_size); } std::uninitialized_value_construct_n(data_.GetAddress(), new_size - size_); } else if (size_ > new_size) { std::destroy_n(data_.GetAddress(), size_ - new_size); } else return; size_ = new_size; } void PushBack(const T& value) { if (size_ == Capacity()) { size_t size_new = 0; if (size_ == 0) { size_new = 1; } else { size_new = size_ * 2; } RawMemory<T> new_data(size_new); new (new_data + size_) T(value); std::uninitialized_move_n(data_.GetAddress(), size_, new_data.GetAddress()); std::destroy_n(data_.GetAddress(), size_); data_.Swap(new_data); } else { new (data_ + size_) T(value); } ++size_; } void PushBack(T&& value) { if (size_ == Capacity()) { size_t size_new = 0; if (size_ == 0) { size_new = 1; } else { size_new = size_ * 2; } RawMemory<T> new_data(size_new), t(1); t[0] = value; new (new_data + size_) T(std::move(t[0])); std::uninitialized_move_n(data_.GetAddress(), size_, new_data.GetAddress()); std::destroy_n(data_.GetAddress(), size_); data_.Swap(new_data); } else { new (data_ + size_) T(std::move(value)); } ++size_; } void PopBack() { if (size_) { std::destroy_n(data_.GetAddress(), 1); --size_; } else return; } private: RawMemory<T> data_; size_t size_ = 0; };