Re-did the constructors for the vector class
This commit is contained in:
parent
f8efc21ff6
commit
2edac15430
12
README.org
12
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...
|
||||
|
@ -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 <class InputIt>
|
||||
list(InputIt first, InputIt last, const Allocator &alloc = Allocator())
|
||||
: list(alloc) {
|
||||
while (first != last)
|
||||
: list{alloc} {
|
||||
for (;first != last; ++first)
|
||||
push_back(*first);
|
||||
}
|
||||
|
||||
|
37
src/test.cc
37
src/test.cc
@ -2,27 +2,48 @@
|
||||
#include "vector.hh"
|
||||
#include <iostream>
|
||||
|
||||
using namespace phundrak;
|
||||
using phundrak::list;
|
||||
using phundrak::vector;
|
||||
using std::cout;
|
||||
|
||||
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 << "\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");
|
||||
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;
|
||||
|
446
src/vector.hh
446
src/vector.hh
@ -1,219 +1,277 @@
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <iterator>
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
|
||||
namespace phundrak {
|
||||
using size_type = size_t;
|
||||
|
||||
template<class T>
|
||||
class vector {
|
||||
public:
|
||||
template <class T, class Allocator = std::allocator<T>> class vector {
|
||||
|
||||
// Member functions ///////////////////////////////////////////////////////
|
||||
|
||||
//! Default constructor
|
||||
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() {
|
||||
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 <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 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<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_];
|
||||
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:
|
||||
|
||||
|
||||
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<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_;
|
||||
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<T> &other) {
|
||||
std::swap(capacity_, other.capacity_);
|
||||
std::swap(size_, other.size_);
|
||||
std::swap(data_, other.data_);
|
||||
}
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
} // namespace phundrak
|
||||
|
Loading…
Reference in New Issue
Block a user