diff --git a/source/tinystl/container/vector.h b/source/tinystl/container/vector.h new file mode 100644 index 0000000..fdad7be --- /dev/null +++ b/source/tinystl/container/vector.h @@ -0,0 +1,328 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace tinystl { + +template > +class vector { + using alloc_traits = std::allocator_traits; + +public: + using value_type = T; + using allocator_type = Alloc; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using reference = T &; + using const_reference = const T &; + using pointer = T *; + using const_pointer = const T *; + using iterator = T *; + using const_iterator = const T *; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + // construct/copy/destroy + vector() noexcept(noexcept(Alloc())); + explicit vector(const Alloc &alloc) noexcept; + explicit vector(std::size_t n, const Alloc &alloc = Alloc()); + vector(std::size_t n, const T &val, const Alloc &alloc = Alloc()); + template + requires std::constructible_from> + vector(ForwardIter first, ForwardIter last, const Alloc &alloc = Alloc()); + template + requires std::constructible_from> && + (!std::forward_iterator) && + (std::movable || std::copyable) + vector(InputIter first, InputIter last, const Alloc &alloc = Alloc()); + vector(std::initializer_list init, const Alloc &alloc = Alloc()); + vector(const vector &other); + vector(const vector &other, const Alloc &alloc); + vector(vector &&other) noexcept; + vector(vector &&other, const Alloc &alloc); + + ~vector(); + + vector &operator=(const vector &other); + vector &operator=(vector &&other); + vector &operator=(std::initializer_list init); + + void assign(std::size_t n, const T &val); + template + void assign(InputIt first, InputIt last); + void assign(std::initializer_list ilist); + + allocator_type get_allocator() const; + + // element access + reference at(std::size_t pos); + const T &at(std::size_t pos) const; + reference operator[](std::size_t pos); + const T &operator[](std::size_t pos) const; + reference front(); + const T &front() const; + reference back(); + const T &back() const; + T *data() noexcept; + const T *data() const noexcept; + + // iterators + T *begin() noexcept; + T *begin() const noexcept; + T *cbegin() const noexcept; + T *end() noexcept; + T *end() const noexcept; + T *cend() const noexcept; + reverse_iterator rbegin() noexcept; + const_reverse_iterator rbegin() const noexcept; + const_reverse_iterator crbegin() const noexcept; + reverse_iterator rend() noexcept; + const_reverse_iterator rend() const noexcept; + const_reverse_iterator crend() const noexcept; + + // capacity + bool empty() const noexcept; + std::size_t size() const noexcept; + std::size_t max_size() const noexcept; + void reserve(std::size_t new_cap); + std::size_t capacity() const noexcept; + void shrink_to_fit(); + + // modifiers + void clear() noexcept; + T *insert(T *pos, const T &val); + T *insert(T *pos, T &&val); + T *insert(T *pos, std::size_t n, const T &val); + template + T *insert(T *position, InputIter first, InputIter last); + template + T *emplace(T *pos, Args &&...args); + T *erase(T *pos); + T *erase(T *first, T *last); + void push_back(const T &val); + void push_back(T &&val); + template + reference emplace_back(Args &&...args); + void pop_back(); + void resize(std::size_t sz); + void resize(std::size_t sz, const value_type &val); + void swap(vector &other) noexcept( + alloc_traits::propagate_on_container_swap::val || + alloc_traits::is_always_equal::val + ); + +private: + void throw_length_error(); + + void allocate(std::size_t n); + + void construct(std::size_t n); + void construct(std::size_t n, const T& val); + template + void construct(InputIterator first, Sential last, std::size_t n); + +private: + Alloc m_alloc; + T *m_begin; + T *m_end; + T *m_cap; +}; + +template +bool operator==(const vector &lhs, const vector &rhs); + +template +auto operator<=>(const vector &lhs, const vector &rhs); + +template +void swap(vector &lhs, vector &rhs) noexcept; + +template +typename vector::size_type erase(vector &c, const U &val); + +template +typename vector::size_type erase_if(vector &c, Pred pred); + +/* -------------------------------------------------------------------------- */ +/* public member functions */ +/* -------------------------------------------------------------------------- */ + +/* -------------------------------- construct ------------------------------- */ +template +vector::vector() noexcept(noexcept(Alloc())) + : m_begin(nullptr), m_end(nullptr), m_cap(nullptr) {} + +template +vector::vector(const Alloc &alloc) noexcept : m_alloc(alloc) {} + +template +vector::vector(std::size_t n, const Alloc &alloc) : m_alloc(alloc) { + if (n > 0) { + this->allocate(n); + this->construct(n); + } else { + m_begin = m_end = m_cap = nullptr; + } +} + +template +vector::vector(std::size_t n, const T &val, const Alloc &alloc) + : m_alloc(alloc) { + if (n > 0) { + this->allocate(n); + this->construct(n, val); + } else { + m_begin = m_end = m_cap = nullptr; + } +} + +template +template + requires std::constructible_from> +vector::vector( + ForwardIter first, ForwardIter last, const Alloc &alloc +) + : m_alloc(alloc) { + std::size_t n = std::distance(first, last); + if (n > 0) { + this->allocate(n); + this->construct(first, last, n); + } else { + m_begin = m_end = m_cap = nullptr; + } +} + +template +template + requires std::constructible_from> && + (!std::forward_iterator) && + (std::movable || std::copyable) +vector::vector( + InputIterator first, InputIterator last, const Alloc &alloc +) { + static_assert( + true, "tinystl::vector does not support construction from input iterators." + ); +} + +template +vector::vector(std::initializer_list init, const Alloc &alloc) + : m_alloc(alloc) { + std::size_t n = init.size(); + if (n > 0) { + this->allocate(n); + this->construct(init.begin(), init.end(), n); + } else { + m_begin = m_end = m_cap = nullptr; + } +} + +/* ----------------------------- copy construct ----------------------------- */ +template +vector::vector(const vector &other) + : m_alloc( + alloc_traits::select_on_container_copy_construction(other.m_alloc) + ) { + std::size_t n = other.size(); + if (n > 0) { + this->allocate(n); + this->construct(other.begin(), other.end(), n); + } else { + m_end = m_cap = m_begin = nullptr; + } +} + +template +vector::vector(const vector &other, const Alloc &alloc) + : m_alloc(alloc) { + std::size_t n = other.size(); + if (n > 0) { + this->allocate(n); + this->construct(other.begin(), other.end(), n); + } else { + m_begin = m_end = m_cap = nullptr; + } +} + +/* ----------------------------- move construct ----------------------------- */ +template +vector::vector(vector &&other) noexcept + : m_alloc(std::move(other.m_alloc)) { + m_begin = other.m_begin; + m_end = other.m_end; + m_cap = other.m_cap; + other.m_begin = other.m_end = other.m_cap = nullptr; +} + +template +vector::vector(vector &&other, const Alloc &alloc) : m_alloc(alloc) { + if (m_alloc == other.m_alloc) { + m_begin = other.m_begin; + m_end = other.m_end; + m_cap = other.m_cap; + other.m_begin = other.m_end = other.m_cap = nullptr; + } else { + std::size_t n = other.size(); + if (n > 0) { + this->allocate(n); + this->construct(std::make_move_iterator(other.begin()), + std::make_move_iterator(other.end()), n); + } else { + m_begin = m_end = m_cap = nullptr; + } + } +} + +/* -------------------------------------------------------------------------- */ +/* private member functions */ +/* -------------------------------------------------------------------------- */ +template +void vector::throw_length_error() { + throw std::length_error("vector"); +} + +template +void vector::allocate(std::size_t n) { + if (n > this->max_size()) { + this->throw_length_error(); + } else { + m_begin = alloc_traits::allocate(m_alloc, n); + m_cap = m_begin + n; + } +} + +template +void vector::construct(std::size_t n) { + m_end = m_begin; + for (std::size_t i = 0; i < n; ++i) { + alloc_traits::construct(m_alloc, m_end); + ++m_end; + } +} + +template +void vector::construct(std::size_t n, const T& val) { + m_end = m_begin; + for (std::size_t i = 0; i < n; ++i) { + alloc_traits::construct(m_alloc, m_end, val); + ++m_end; + } +} + +template +template +void vector::construct( + InputIterator first, Sential last, std::size_t n +) { + m_end = m_begin; + for (std::size_t i = 0; i < n; ++i) { + alloc_traits::construct(m_alloc, m_end, *first); + ++m_end; + ++first; + } +} +} // namespace tinystl