Re-did the constructors for the vector class

This commit is contained in:
Phuntsok Drak-pa 2017-10-22 01:17:55 +02:00
parent f8efc21ff6
commit 2edac15430
4 changed files with 293 additions and 210 deletions

View File

@ -2,15 +2,17 @@
* Pundraks STL * Pundraks 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 dont like coffee. Milk though... Developped under Spacemacs, compiled with Clang++, debugged with GDB, drinking milk. Yeah, I dont like coffee. Milk though...
Also, dont 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 * 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 * Licence
@ -19,3 +21,5 @@ See the LICENCE.md file, basically you are free to do whatever you want with my
* Bugs * Bugs
Yep, there are bugs. I may or may not fix them, its up to me. Yep, there are bugs. I may or may not fix them, its up to me.
Also, Github doesnt seem to fully recognize org-modes syntax. Well...

View File

@ -68,21 +68,21 @@ namespace phundrak {
} }
list(size_type count, const T &value, const Allocator &alloc = Allocator()) list(size_type count, const T &value, const Allocator &alloc = Allocator())
: list(alloc), alloc_{alloc} { : list{alloc} {
while (size() < count) while (size() < count)
push_back(value); push_back(value);
} }
explicit list(size_type count, const Allocator &alloc = Allocator()) explicit list(size_type count, const Allocator &alloc = Allocator())
: list(alloc), alloc_{alloc} { : list{alloc} {
while (size() < count) while (size() < count)
push_back(T()); push_back(T());
} }
template <class InputIt> template <class InputIt>
list(InputIt first, InputIt last, const Allocator &alloc = Allocator()) list(InputIt first, InputIt last, const Allocator &alloc = Allocator())
: list(alloc) { : list{alloc} {
while (first != last) for (;first != last; ++first)
push_back(*first); push_back(*first);
} }

View File

@ -2,27 +2,48 @@
#include "vector.hh" #include "vector.hh"
#include <iostream> #include <iostream>
using namespace phundrak; using phundrak::list;
using phundrak::vector;
using std::cout; using std::cout;
int main(void) { int main(void) {
list<char> test {'C', 'a', 'r', 't', 'i', 'e', 'r'}; cout << "\n\nTest vecteur\n";
for(auto c : test) vector<char> 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<char> test{'C', 'a', 'r', 't', 'i', 'e', 'r'};
for (auto c : test)
cout << c << " "; cout << c << " ";
cout << "\n"; cout << "\n";
list<int> 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<int> 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"); printf("Elements before unique():\n");
for(const auto& elem : test_unique) for (const auto &elem : test_unique)
cout << elem << " "; cout << elem << " ";
cout << "\n"; cout << "\n";
test_unique.unique(); test_unique.unique();
for(const auto& elem : test_unique) for (const auto &elem : test_unique)
cout << elem << " "; cout << elem << " ";
cout << "\n"; cout << "\n";
return 0; return 0;

View File

@ -1,219 +1,277 @@
#include <cstdio> #include <cstdio>
#include <memory>
#include <iterator>
#include <stdexcept>
#include <iostream> #include <iostream>
#include <iterator>
#include <memory>
#include <stdexcept>
#include <type_traits> #include <type_traits>
namespace phundrak { namespace phundrak {
using size_type = size_t;
template<class T> template <class T, class Allocator = std::allocator<T>> class vector {
class vector {
public:
// Member functions /////////////////////////////////////////////////////// private:
void double_capacity() {
//! Default constructor if (data_) {
vector() : data_{nullptr}, size_{0}, capacity_{0} {}
//! Copy constructor
vector(const vector<T> &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<T> &&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<T> &other) {
vector<T> 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<typename InputIt,
typename std::enable_if_t<!std::is_integral<InputIt>::value, InputIt>* = nullptr>
// template <class InputIt> 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() {
T *olddata = data_; T *olddata = data_;
capacity_ = size_; capacity_ <<= 1;
data_ = new T[capacity_]; data_ = new T[capacity_];
for (size_t i = 0; i < size_; ++i) for (size_t i = 0; i < size_; ++i)
data_[i] = olddata[i]; data_[i] = olddata[i];
delete[] olddata; 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 <class InputIt>
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<T> &other)
: data_{new T[other.size_]}, size_{other.size_},
capacity_{other.capacity_}, alloc_{other.alloc_} {
if (!alloc_) {
alloc_ = std::allocator_traits<Allocator>::
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 others allocator "
<< other.alloc_ << "\nAborting...\n";
std::terminate();
} }
// Modifiers ////////////////////////////////////////////////////////////// for (size_type i = 0; i < size_; ++i)
data_[i] = other.data_[i];
}
void clear() noexcept { // Move constructor ///////////////////////////////////////////////////////
delete[] data_;
vector(vector<T> &&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_]; data_ = new T[capacity_];
size_ = 0; alloc_ = alloc;
} for (size_type i = 0; i < size_; ++i) {
data_[i] = std::move(other.data_[i]);
// 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<T>& 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;
} }
} 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<T> &other) {
vector<T> 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 <typename InputIt,
typename std::enable_if_t<!std::is_integral<InputIt>::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_; T &front() { return data_[0]; }
size_t size_; const T &front() const { return data_[0]; }
size_t capacity_;
}; 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<T> &other) {
std::swap(capacity_, other.capacity_);
std::swap(size_, other.size_);
std::swap(data_, other.data_);
}
protected:
};
} // namespace phundrak