From 2edac15430ad93e052c32c063d0db255aad6c707 Mon Sep 17 00:00:00 2001 From: Phuntsok Drak-pa Date: Sun, 22 Oct 2017 01:17:55 +0200 Subject: [PATCH] Re-did the constructors for the vector class --- README.org | 12 +- src/list.hh | 8 +- src/test.cc | 37 ++++- src/vector.hh | 446 ++++++++++++++++++++++++++++---------------------- 4 files changed, 293 insertions(+), 210 deletions(-) diff --git a/README.org b/README.org index 2e67192..9615ec8 100644 --- a/README.org +++ b/README.org @@ -2,15 +2,17 @@ * P’undrak’s STL -This is my very own partial, sketchy, weird and ineffective STL implementation, mainly focused around the containers of the actual Standard Template Library. You have absolutely no other reason to look at this source code than being a student like myself seeking for hints on how to do things. Spoiler: what you will see here is probably not the right way to do it, but hey, it works! +This is my very own partial, sketchy, weird and ineffective STL implementation, mainly focused on the containers of the actual Standard Template Library. You have absolutely no other reason to look at this source code than being a student like myself seeking for hints on how to do things. Spoiler: what you will see here is probably not the right way to do it, but hey, it works!... sometimes. I also try to stay as close as possible to the C++17 standard. I might not always follow it though. -Developped under Spacemacs, compiled with Clang++, debugged with GDB and DDD, and drinking milk. Yeah, I don’t like coffee. Milk though... +Developped under Spacemacs, compiled with Clang++, debugged with GDB, drinking milk. Yeah, I don’t like coffee. Milk though... + +Also, don’t pay any attention to [[https://github.com/Phundrak/PhundrakSTL/blob/master/src/test.cc][src/test.cc]], it is just me testing my STL and fooling around with it. * Installation -Haha, good joke. +Haha, good joke! -Seriously, if you want to use it, just download the header files, place them in your include directory in your project, and add them with ~#include "vector.hh"~ or something like that. But honestly, use it only for testing purposes, not for actual work. That would be a terrible idea. +Seriously, if you want to use it, just download the header files, place them in your include directory in your project, and add them with ~#include "vector.hh"~ or something like that. But honestly, use it only for testing purposes, or looking at how I did things, but not for actual work. That would be a terrible idea. * Licence @@ -19,3 +21,5 @@ See the LICENCE.md file, basically you are free to do whatever you want with my * Bugs Yep, there are bugs. I may or may not fix them, it’s up to me. + +Also, Github doesn’t seem to fully recognize org-mode’s syntax. Well... diff --git a/src/list.hh b/src/list.hh index e8e68c4..ada40b3 100644 --- a/src/list.hh +++ b/src/list.hh @@ -68,21 +68,21 @@ namespace phundrak { } list(size_type count, const T &value, const Allocator &alloc = Allocator()) - : list(alloc), alloc_{alloc} { + : list{alloc} { while (size() < count) push_back(value); } explicit list(size_type count, const Allocator &alloc = Allocator()) - : list(alloc), alloc_{alloc} { + : list{alloc} { while (size() < count) push_back(T()); } template list(InputIt first, InputIt last, const Allocator &alloc = Allocator()) - : list(alloc) { - while (first != last) + : list{alloc} { + for (;first != last; ++first) push_back(*first); } diff --git a/src/test.cc b/src/test.cc index e45db9f..6408c60 100644 --- a/src/test.cc +++ b/src/test.cc @@ -2,27 +2,48 @@ #include "vector.hh" #include -using namespace phundrak; +using phundrak::list; +using phundrak::vector; using std::cout; int main(void) { - list test {'C', 'a', 'r', 't', 'i', 'e', 'r'}; + cout << "\n\nTest vecteur\n"; - for(auto c : test) + vector testvec; + testvec.push_back('C'); + testvec.push_back('a'); + testvec.push_back('r'); + testvec.push_back('t'); + testvec.push_back('i'); + testvec.push_back('e'); + testvec.push_back('r'); + + for(size_t i = 0; i < testvec.size(); ++i) { + cout << testvec[i] << " "; + } + cout << std::endl; + + + cout << "\n\nTest list\n"; + + list test{'C', 'a', 'r', 't', 'i', 'e', 'r'}; + + for (auto c : test) cout << c << " "; cout << "\n"; - list test_unique {1,1,1,1,1,2,2,2,3,3,3,4,4,1,1,5,1,2,1,1,3,3,3}; + list test_unique{1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, + 4, 1, 1, 5, 1, 2, 1, 1, 3, 3, 3}; printf("Elements before unique():\n"); - for(const auto& elem : test_unique) - cout << elem << " "; + for (const auto &elem : test_unique) + cout << elem << " "; cout << "\n"; test_unique.unique(); - for(const auto& elem : test_unique) - cout << elem << " "; + for (const auto &elem : test_unique) + cout << elem << " "; cout << "\n"; return 0; diff --git a/src/vector.hh b/src/vector.hh index 166f9c3..61fee66 100644 --- a/src/vector.hh +++ b/src/vector.hh @@ -1,219 +1,277 @@ #include -#include -#include -#include #include +#include +#include +#include #include namespace phundrak { +using size_type = size_t; - template - class vector { - public: +template > class vector { - // Member functions /////////////////////////////////////////////////////// - - //! Default constructor - vector() : data_{nullptr}, size_{0}, capacity_{0} {} - - //! Copy constructor - vector(const vector &other) - : data_{new T[other.size_]}, size_{other.size_}, - capacity_{other.capacity_} { - for (size_t 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_); - } - - //! Destructor - virtual ~vector() noexcept { - delete[] data_; - } - - //! Copy assignment operator - vector& operator=(const vector &other) { - vector w{other}; - std::swap(data_, w.data_); - std::swap(size_, w.size_); - std::swap(capacity_, w.capacity_); - return *this; - } - - //! Move assignment operator - vector &operator=(vector &&other) noexcept { - std::swap(data_, other.data_); - std::swap(size_, other.size_); - std::swap(capacity_, other.capacity_); - return *this; - } - - T &operator=(size_t pos) { return data_[pos]; } - const T &operator=(size_t pos) const { return data_[pos]; } - - 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> - - - // template void assign(InputIt first, InputIt last) { - // clear(); - // capacity_ = std::distance(first, last); - // size_ = std::distance(first, last); - // data_ = new T[size_]; - // for (int i = 0; first != last; ++first, ++i) - // data_[i] = *first; - // } - - // Element access ///////////////////////////////////////////////////////// - - 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 (std::out_of_range e) { - std::cout << e.what() << " in phundrak::vector " << this << '\n'; - std::terminate(); - } - - return data_[pos]; - } - - T &operator[](size_t pos) { return data_[pos]; } - const T &operator[](size_t pos) const { return data_[pos]; } - - T &front() { return data_[0]; } - const T &front() const { return data_[0]; } - - T &back() { return data_[size_ - 1]; } - const T &back() const { return data_[size_ - 1]; } - - T *data() noexcept { return data_; } - const T *data() const noexcept { return data_; } - - // Iterators ////////////////////////////////////////////////////////////// - - // I don't know how to create custom iterators :( - - // 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() { +private: + void double_capacity() { + if (data_) { T *olddata = data_; - capacity_ = size_; + 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_; + size_t size_; + size_t capacity_; + Allocator alloc_; + +public: + /////////////////////////////////////////////////////////////////////////// + // Member functions // + /////////////////////////////////////////////////////////////////////////// + + // constructor //////////////////////////////////////////////////////////// + + vector() noexcept(noexcept(Allocator())) + : vector{Allocator()} {} + + explicit vector(const Allocator &alloc) noexcept + : data_{nullptr}, size_{0}, capacity_{0}, alloc_{alloc} {} + + vector(size_type count, const T &value, const Allocator &alloc = Allocator()) + : vector{alloc}, data_{nullptr}, size_{0}, capacity_{0} { + for (size_t i = 0; i < count; ++i) + push_back(value); + } + + explicit vector(size_type count, const Allocator &alloc = Allocator()) + : data_{nullptr}, size_{0}, capacity_{0}, alloc_{alloc} { + for (size_type i = 0; i < count; ++i) + push_back(T{}); + } + + template + vector(InputIt first, InputIt last, const Allocator &alloc = Allocator()) + : data_{nullptr}, size_{0}, capacity_{0}, 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(); } - // Modifiers ////////////////////////////////////////////////////////////// + for (size_type i = 0; i < size_; ++i) + data_[i] = other.data_[i]; + } - void clear() noexcept { - delete[] data_; + // 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_) { + capacity_ = other.capacity_; + size_ = other.size_; 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_); - } - - protected: - - - 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; + 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_); + } + } + + //! Destructor + virtual ~vector() noexcept { delete[] data_; } + + //! Copy assignment operator + vector &operator=(const vector &other) { + vector w{other}; + std::swap(data_, w.data_); + std::swap(size_, w.size_); + std::swap(capacity_, w.capacity_); + return *this; + } + + //! Move assignment operator + vector &operator=(vector &&other) noexcept { + std::swap(data_, other.data_); + std::swap(size_, other.size_); + std::swap(capacity_, other.capacity_); + return *this; + } + + T &operator=(size_t pos) { return data_[pos]; } + const T &operator=(size_t pos) const { return data_[pos]; } + + 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; + } + + // Element access ///////////////////////////////////////////////////////// + + 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]; + } + T &operator[](size_t pos) { return data_[pos]; } + const T &operator[](size_t pos) const { return data_[pos]; } - T * data_; - size_t size_; - size_t capacity_; + T &front() { return data_[0]; } + const T &front() const { return data_[0]; } - }; + T &back() { return data_[size_ - 1]; } + const T &back() const { return data_[size_ - 1]; } + T *data() noexcept { return data_; } + const T *data() const noexcept { return data_; } + // Iterators ////////////////////////////////////////////////////////////// -} // phundrak namespace + // I don't know how to create custom iterators :( + + // 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_); + } + +protected: +}; + +} // namespace phundrak