Last active
March 16, 2023 13:50
-
-
Save bkrmendy/d7d5b0416b997b562f1c3c2275b5a4ec to your computer and use it in GitHub Desktop.
vector
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdexcept> | |
#include <iostream> | |
#include <initializer_list> | |
template <typename T> | |
class Vector | |
{ | |
static constexpr std::size_t min_capacity = 8; | |
public: | |
class Iterator; | |
class ConstIterator; | |
using value_type = T; | |
using size_type = std::size_t; | |
using difference_type = std::ptrdiff_t; | |
using reference = value_type &; | |
using const_reference = const value_type &; | |
using pointer = value_type *; | |
using const_pointer = const value_type *; | |
using iterator = Vector::Iterator; | |
using const_iterator = Vector::ConstIterator; | |
private: | |
size_type size_ = 0; | |
size_type max_size_ = 0; | |
value_type *values_ = nullptr; | |
void realloc(size_type next_size) | |
{ | |
size_type new_size = std::max(this->size_, next_size); | |
value_type *new_values = new value_type[new_size]; | |
for (size_type idx = 0; idx < this->size_; idx++) | |
{ | |
new_values[idx] = this->values_[idx]; | |
} | |
if (this->values_ != nullptr) | |
{ | |
delete[] this->values_; | |
} | |
this->max_size_ = new_size; | |
this->values_ = new_values; | |
} | |
public: | |
Vector() : size_{0} | |
{ | |
this->realloc(min_capacity); | |
} | |
Vector(std::size_t desired_size) : size_{0} | |
{ | |
this->realloc(std::max(desired_size, min_capacity)); | |
} | |
Vector(const Vector &other) | |
{ | |
this->realloc(other.size()); | |
this->clear(); | |
for (auto value : other) | |
{ | |
this->push_back(value); | |
} | |
} | |
Vector(std::initializer_list<Vector::value_type> initial) | |
{ | |
this->realloc(std::max(initial.size(), min_capacity)); | |
for (auto value : initial) | |
{ | |
this->push_back(value); | |
} | |
} | |
Vector &operator=(const Vector &other) | |
{ | |
if (this == &other) | |
{ | |
return *this; | |
} | |
this->realloc(other.size()); | |
this->clear(); | |
for (auto value : other) | |
{ | |
this->push_back(value); | |
} | |
return *this; | |
} | |
~Vector() | |
{ | |
delete[] values_; | |
} | |
size_type size() const | |
{ | |
return this->size_; | |
} | |
size_type capacity() const | |
{ | |
return this->max_size_; | |
} | |
bool empty() const | |
{ | |
return this->size_ == 0; | |
} | |
void clear() | |
{ | |
this->size_ = 0; | |
} | |
void reserve(size_type desired_size) | |
{ | |
this->realloc(desired_size); | |
} | |
void shrink_to_fit() | |
{ | |
this->realloc(this->size_); | |
} | |
void push_back(value_type value) | |
{ | |
if (this->size_ >= this->max_size_) | |
{ | |
this->realloc(this->max_size_ * 2); | |
} | |
this->values_[this->size_] = value; | |
this->size_ += 1; | |
} | |
void pop_back() | |
{ | |
if (this->empty()) | |
{ | |
throw std::runtime_error("Popping empty Vector"); | |
} | |
this->size_ -= 1; | |
} | |
value_type &operator[](size_type index) | |
{ | |
if (index < this->size_) | |
{ | |
return this->values_[index]; | |
} | |
throw std::runtime_error("Index out of range"); | |
} | |
const value_type &operator[](size_type index) const | |
{ | |
if (index < this->size_) | |
{ | |
return this->values_[index]; | |
} | |
throw std::runtime_error("Index out of range"); | |
} | |
iterator begin() | |
{ | |
return Iterator{this->values_}; | |
} | |
iterator end() | |
{ | |
return Iterator{this->values_ + this->size_}; | |
} | |
const_iterator begin() const | |
{ | |
return ConstIterator{this->values_}; | |
} | |
const_iterator end() const | |
{ | |
return ConstIterator{this->values_ + this->size_}; | |
} | |
iterator insert(const_iterator pos, const_reference val) | |
{ | |
auto diff = pos - (const_iterator)begin(); | |
if (diff < 0 || static_cast<size_type>(diff) > this->size_) | |
{ | |
throw std::runtime_error("insert: Iterator out of bounds"); | |
} | |
size_type current{static_cast<size_type>(diff)}; | |
if (this->size_ >= this->max_size_) | |
{ | |
reserve(this->max_size_ * 2 + 1); | |
} | |
for (auto i{this->size_}; i-- > current;) | |
{ | |
this->values_[i + 1] = this->values_[i]; | |
} | |
this->values_[current] = val; | |
++this->size_; | |
return iterator{this->values_ + current}; | |
} | |
iterator erase(const_iterator pos) | |
{ | |
auto diff = pos - begin(); | |
if (diff < 0 || static_cast<size_type>(diff) > this->size_) | |
{ | |
throw std::runtime_error("erase: Iterator out of bounds"); | |
} | |
size_type current{static_cast<size_type>(diff)}; | |
for (auto i{current}; i < this->size_ - 1; ++i) | |
{ | |
this->values_[i] = this->values_[i + 1]; | |
} | |
--this->size_; | |
return iterator{this->values_ + current}; | |
} | |
class Iterator | |
{ | |
using value_type = Vector::value_type; | |
using reference = Vector::reference; | |
using pointer = Vector::pointer; | |
using difference_type = Vector::difference_type; | |
using iterator_category = std::forward_iterator_tag; | |
private: | |
Vector::pointer elem_; | |
public: | |
Iterator() : elem_{nullptr} {} | |
Iterator(Vector::pointer elem) : elem_{elem} {} | |
Iterator &operator=(const Iterator &other) | |
{ | |
this->elem_ = other.elem_; | |
return *this; | |
} | |
reference operator*() | |
{ | |
if (this->elem_ == nullptr) | |
{ | |
throw std::runtime_error(""); | |
} | |
return *(this->elem_); | |
} | |
pointer operator->() | |
{ | |
if (this->elem_ == nullptr) | |
{ | |
throw std::runtime_error(""); | |
} | |
return this->elem_; | |
} | |
iterator &operator++() | |
{ | |
this->elem_++; | |
return *this; | |
} | |
iterator operator++(int) | |
{ | |
Iterator temp = *this; | |
this->elem_++; | |
return temp; | |
} | |
friend bool operator==(const Iterator &lhs, const Iterator &rhs) | |
{ | |
return lhs.elem_ == rhs.elem_; | |
} | |
friend bool operator!=(const Iterator &lhs, const Iterator &rhs) | |
{ | |
return !(lhs == rhs); | |
} | |
operator const_iterator() const | |
{ | |
return ConstIterator{this->elem_}; | |
} | |
}; | |
class ConstIterator | |
{ | |
using value_type = Vector::value_type; | |
using reference = Vector::reference; | |
using pointer = Vector::pointer; | |
using difference_type = Vector::difference_type; | |
using iterator_category = std::forward_iterator_tag; | |
private: | |
Vector::pointer elem_; | |
public: | |
ConstIterator() : elem_{nullptr} {} | |
ConstIterator(Vector::pointer elem) : elem_{elem} {} | |
ConstIterator &operator=(const ConstIterator &other) | |
{ | |
this->elem_ = other.elem_; | |
return *this; | |
} | |
const_reference operator*() const | |
{ | |
if (this->elem_ == nullptr) | |
{ | |
throw std::runtime_error(""); | |
} | |
return *(this->elem_); | |
} | |
const_pointer operator->() const | |
{ | |
if (this->elem_ == nullptr) | |
{ | |
throw std::runtime_error(""); | |
} | |
return this->elem_; | |
} | |
const_iterator &operator++() | |
{ | |
this->elem_++; | |
return *this; | |
} | |
const_iterator operator++(int) | |
{ | |
ConstIterator temp = *this; | |
++(*this); | |
return temp; | |
} | |
friend bool operator==(const ConstIterator &lhs, const ConstIterator &rhs) | |
{ | |
return lhs.elem_ == rhs.elem_; | |
} | |
friend bool operator!=(const ConstIterator &lhs, const ConstIterator &rhs) | |
{ | |
return !(lhs == rhs); | |
} | |
friend Vector::difference_type operator-(const Vector::ConstIterator &lop, const Vector::ConstIterator &rop) | |
{ | |
return (*lop) - (*rop); | |
} | |
}; | |
}; | |
template <typename T> | |
std::ostream &operator<<(std::ostream &os, const Vector<T> &vector) | |
{ | |
os << '['; | |
for (const auto value : vector) | |
{ | |
os << value; | |
os << ' '; | |
} | |
os << ']'; | |
return os; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment