#include #include #include #include #include #include #include namespace phundrak { using size_type = std::size_t; template > class vector { private: void double_capacity() { if (data_) { T *olddata = data_; capacity_ <<= 1; data_ = new T[capacity_]; for (size_t i = 0; i < size_; ++i) data_[i] = olddata[i]; delete[] olddata; } else { data_ = new T[1]; capacity_ = 1; } } T *data_ = nullptr; size_t size_ = 0; size_t capacity_ = 0; Allocator alloc_ = Allocator{}; public: /////////////////////////////////////////////////////////////////////////// // Member functions // /////////////////////////////////////////////////////////////////////////// // constructor //////////////////////////////////////////////////////////// vector() noexcept(noexcept(Allocator())) {} explicit vector(const Allocator &alloc) noexcept : alloc_{alloc} {} vector(size_type count, const T &value, const Allocator &alloc = Allocator()) : vector{alloc} { for (size_t i = 0; i < count; ++i) push_back(value); } explicit vector(size_type count, const Allocator &alloc = Allocator()) : alloc_{alloc} { for (size_type i = 0; i < count; ++i) push_back(T{}); } template vector(InputIt first, InputIt last, const Allocator &alloc = Allocator()) : alloc_{alloc} { for (; first != last; ++first) push_back(*first); } // Copy constructor /////////////////////////////////////////////////////// vector(const vector &other) : data_{new T[other.size_]}, size_{other.size_}, capacity_{other.capacity_}, alloc_{other.alloc_} { if (!alloc_) { alloc_ = std::allocator_traits:: select_on_container_copy_construction(other.get_allocator()); } for (size_type i = 0; i < size_; ++i) data_[i] = other.data_[i]; } vector(const vector &other, const Allocator &alloc) : data_{new T[other.size_]}, size_{other.size}, capacity_{other.capacity_}, alloc_{alloc} { try { if (alloc_ != other.alloc_) throw 20; } catch (int error) { std::cout << "Error in phundrak::vector(const vector &other, const " "Allocator &alloc) :\nThe allocator " << alloc << " passed as argument is different from other’s allocator " << other.alloc_ << "\nAborting...\n"; std::terminate(); } for (size_type i = 0; i < size_; ++i) data_[i] = other.data_[i]; } // Move constructor /////////////////////////////////////////////////////// vector(vector &&other) noexcept { std::swap(data_, other.data_); std::swap(size_, other.size_); std::swap(capacity_, other.capacity_); std::swap(alloc_, other.alloc_); } vector(vector &&other, const Allocator &alloc) { if (alloc != other.alloc_) { std::swap(capacity_, other.capacity_); std::swap(size_, other.size_); data_ = new T[capacity_]; alloc_ = alloc; for (size_type i = 0; i < size_; ++i) data_[i] = std::move(other.data_[i]); } else { std::swap(capacity_, other.capacity); std::swap(size_, other.size); std::swap(data_, other.data_); std::swap(alloc_, other.alloc_); } } // Constructor by initializer list ////////////////////////////////////////// vector(std::initializer_list init, const Allocator &alloc = Allocator()) : vector{alloc} { for (auto &elem : init) push_back(std::move(elem)); } // Destructor /////////////////////////////////////////////////////////////// virtual ~vector() noexcept { delete[] data_; } // Copy assignment operator ///////////////////////////////////////////////// vector &operator=(const vector &other) { delete[] data_; size_ = other.size_; capacity_ = other.capacity_; data_ = new T[capacity_]; for (size_type i = 0; i < size_; ++i) data_[i] = other.data_[i]; return *this; } vector &operator=(vector &&other) noexcept { std::swap(alloc_, other.alloc_); std::swap(size_, other.size_); std::swap(capacity_, other.capacity_); std::swap(data_, other.data_); return *this; } vector &operator=(std::initializer_list ilist) { delete[] data_; size_ = ilist.size(); capacity_ = size_; data_ = new T[capacity_]; size_type i = 0; std::for_each(std::begin(ilist), std::end(ilist), [&i, this](T &elem) { data_[i] = std::move(elem); ++i; }); return *this; } // assign /////////////////////////////////////////////////////////////////// void assign(size_t count, const T &value) { clear(); reserve(count); for (size_t i = 0; i < count; ++i) push_back(value); } template ::value, InputIt> * = nullptr> void assign(InputIt first, InputIt last) { clear(); capacity_ = std::distance(first, last); size_ = capacity_; data_ = new T[capacity_]; for (int i = 0; first != last, i < size_; ++first, ++i) data_[i] = *first; } void assign(std::initializer_list ilist) { delete[] data_; size_ = ilist.size(); capacity_ = ilist.size(); data_ = new T[size_]; size_type i = 0; for (auto pos = ilist.begin(); pos != ilist.end(); ++pos, ++i) data_[i] = std::move(*pos); } // get_allocator //////////////////////////////////////////////////////////// Allocator get_allocator() const { return alloc_; } ///////////////////////////////////////////////////////////////////////////// // Element access // ///////////////////////////////////////////////////////////////////////////// // at /////////////////////////////////////////////////////////////////////// T &at(size_t pos) { try { if (pos >= size_) throw std::out_of_range("Out of range"); } catch (const std::out_of_range &e) { std::cout << e.what() << " in phundrak::vector " << this << '\n'; std::terminate(); } return data_[pos]; } const T &at(size_t pos) const { try { if (pos >= size_ || pos < 0) throw std::out_of_range("Out of range"); } catch (const std::out_of_range &e) { std::cout << e.what() << " in phundrak::vector " << this << '\n'; std::terminate(); } return data_[pos]; } // operator[] /////////////////////////////////////////////////////////////// T &operator[](size_type pos) { return data_[pos]; } const T &operator[](size_type pos) const { return data_[pos]; } // front //////////////////////////////////////////////////////////////////// T &front() { return data_[0]; } const T &front() const { return data_[0]; } // back ///////////////////////////////////////////////////////////////////// T &back() { return data_[size_ - 1]; } const T &back() const { return data_[size_ - 1]; } // data ///////////////////////////////////////////////////////////////////// T *data() noexcept { return data_; } const T *data() const noexcept { return data_; } ///////////////////////////////////////////////////////////////////////////// // Iterators // ///////////////////////////////////////////////////////////////////////////// // TODO: iterator functions // Capacity /////////////////////////////////////////////////////////////// bool empty() const noexcept { return (data_ == nullptr) ? true : false; } size_t size() const noexcept { return size_; } void reserve(size_t new_cap) { while (capacity_ < new_cap) double_capacity(); } size_t capacity() const noexcept { return capacity_; } void shrink_to_fit() { T *olddata = data_; capacity_ = size_; data_ = new T[capacity_]; for (size_t i = 0; i < size_; ++i) data_[i] = olddata[i]; delete[] olddata; } // Modifiers ////////////////////////////////////////////////////////////// void clear() noexcept { delete[] data_; data_ = new T[capacity_]; size_ = 0; } // insert: can't do iterators :( // emplace: can't do iterators :( // erase: can't do iterators :( void push_back(const T &value) { ++size_; reserve(size_); data_[size_ - 1] = value; } void push_back(T &&value) { ++size_; reserve(size_); data_[size_ - 1] = std::move(value); } // emplace_back: don't know how to use std::allocator_traits void pop_back() { if (size_ > 0) --size_; } void resize(size_t count, T value = T()) { if (count < size_) size_ = count; else if (count > size_) reserve(count); while (size_ < count) push_back(value); } void swap(vector &other) { std::swap(capacity_, other.capacity_); std::swap(size_, other.size_); std::swap(data_, other.data_); } ///////////////////////////////////////////////////////////////////////////// // // // // // ITERATOR CLASS // // // // // ///////////////////////////////////////////////////////////////////////////// class iterator { protected: T *it; public: iterator() : it{nullptr} {} explicit iterator(T *point) : it{point} {} iterator(const iterator &other) : it{other.it} {} iterator(iterator &&other) { std::swap(it, other.it); } iterator &operator=(T *point) { it = point; return *this; } iterator &operator=(const iterator &other) { it = other.it; return *this; } iterator &operator=(iterator &&other) { std::swap(it, other.it); return *this; } ~iterator() { // delete it; } iterator &operator++() { // ++i ++it; return *this; } iterator operator++(int) { // i++ // iterator t; // t.it = it; iterator t{*this}; ++it; return t; } iterator &operator--() { // --i --it; return *this; } iterator operator--(int) { // i-- // iterator t; // t.it = it; iterator t{it}; --it; return t; } bool operator==(T *point) { return point == it; } bool operator==(const iterator &other) { return other.it == it; } bool operator==(iterator &&other) { return other.it == it; } bool operator!=(T *point) { return point != it; } bool operator!=(const iterator &other) { return other.it != it; } bool operator!=(iterator &&other) { return other.it != it; } T &operator*() { return *it; } friend class vector; }; class const_iterator : public iterator { public: const_iterator() : iterator() {} explicit const_iterator(T *point) : iterator{point} {} explicit const_iterator(const iterator &other) : iterator{other} {} const_iterator(const const_iterator &other) : iterator{other} {} explicit const_iterator(iterator &&other) : iterator{std::move(other)} {} const_iterator(const_iterator &&other) : iterator{std::move(other)} {} const T &operator*() { return this->it; } }; class reverse_iterator : public iterator { public: reverse_iterator() : iterator() {} explicit reverse_iterator(T *point) : iterator(point) {} reverse_iterator(const reverse_iterator &other) : iterator(other) {} reverse_iterator(reverse_iterator &&other) : iterator(std::move(other)) {} reverse_iterator &operator++() { ++this->it; return *this; } reverse_iterator operator++(int) { reverse_iterator t{*this}; ++this->it; ; return t; } reverse_iterator &operator--() { --this->it; return *this; } reverse_iterator operator--(int) { reverse_iterator t{*this}; --this->it; return t; } ~reverse_iterator() {} }; class const_reverse_iterator : public reverse_iterator { public: const_reverse_iterator() : reverse_iterator() {} explicit const_reverse_iterator(T *point) : reverse_iterator{point} {} explicit const_reverse_iterator(const reverse_iterator &other) : reverse_iterator{other} {} const_reverse_iterator(const const_reverse_iterator &other) : reverse_iterator{other} {} explicit const_reverse_iterator(reverse_iterator &&other) : reverse_iterator{other} {} virtual ~const_reverse_iterator() { ~reverse_iterator(); } }; protected: }; } // namespace phundrak