Last active
November 29, 2017 13:11
-
-
Save DragonOsman/a9b2fef7f8afd634bb584bac1678aecb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <vld.h> | |
#include "../../cust_std_lib_facilities.h" | |
int main() | |
{ | |
vector<int> v1; | |
try | |
{ | |
for (int num; std::cin >> num;) | |
{ | |
v1.push_back(num); | |
} | |
} | |
catch (const std::invalid_argument &e) | |
{ | |
std::cerr << "Exception caught: " << e.what() << '\n'; | |
} | |
for (const int &x : v1) | |
{ | |
std::cout << x << '\n'; | |
} | |
std::cin.ignore(32767, '\n'); | |
std::cin.clear(); | |
keep_window_open(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef VECTOR_H | |
#define VECTOR_H | |
#include <stdexcept> | |
#include <algorithm> | |
#include <iterator> | |
#include <memory> | |
template<typename T, typename A> | |
struct vector_base | |
{ | |
A alloc; // allocator | |
T *elem; // start of allocation | |
int sz; // number of elements | |
int space; // amount of allocated space | |
using size_type = unsigned long; | |
using difference_type = T*; | |
vector_base(const A &a, int n) | |
: alloc{ a }, elem{ alloc.allocate(n) }, sz{ n }, space{ n } {} | |
vector_base() | |
: alloc{}, elem{}, sz{}, space{} {} | |
~vector_base() { alloc.deallocate(elem, space); } | |
}; | |
// an almost real vector of Ts | |
template<typename T, typename A = std::allocator<T>> | |
class vector : private vector_base<T, A> // read "for all types T" (just like in math) | |
{ | |
/* | |
invariant: | |
if 0<=n<sz, elem[n] is element n | |
sz<=space; | |
if sz<space there is space for (space-sz) doubles after elem[sz-1] | |
*/ | |
A alloc; // use allocate to handle memory for elements | |
unsigned long sz; // the size | |
T *elem; // pointer to the elements (or 0) | |
unsigned long space; // number of elements plus number of free slots | |
public: | |
explicit vector(int s) | |
: sz{ s }, | |
elem{ new T[s] }, | |
space{ s } | |
{ | |
for (std::size_t i = 0; i < sz; ++i) | |
{ | |
elem[i] = 0; | |
} | |
} | |
vector(std::initializer_list<T> lst) | |
: sz{ lst.size() }, | |
elem{ new T[sz] } | |
{ | |
std::copy(lst.begin(), lst.end(), elem); | |
} | |
vector(const vector<T> &arg) | |
: sz{ arg.size() }, | |
elem{ new T[arg.sz] } | |
{ | |
std::copy(arg.elem, arg.elem + arg.sz, elem); | |
} | |
vector &operator=(const vector &a); // copy assignment | |
using size_type = unsigned long; | |
using value_type = T; | |
using iterator = T*; | |
using const_iterator = const T*; | |
using difference_type = T*; | |
using pointer_type = T*; | |
using reference_type = T&; | |
using iterator_category = std::random_access_iterator_tag; | |
vector(vector &&a) // move constructor: define move | |
: sz{ a.sz }, elem{ a.elem }, space{ 0 } | |
{ | |
a.sz = 0; | |
a.elem = nullptr; | |
} | |
vector &operator=(vector<T> &&a); | |
vector() : sz{ 0 }, elem{ nullptr }, space{ 0 } {} // default constructor | |
~vector(); // destructor | |
iterator begin() { return elem; } | |
const_iterator begin() const { return elem; } | |
iterator end() { return (elem + sz); } | |
const_iterator end() const { return (elem + sz); } | |
iterator insert(iterator p, const T &val); | |
iterator erase(iterator p); | |
size_type size() const { return sz; } // return current size | |
size_type capacity() const { return space; } | |
T &at(size_type n); | |
const T &at(size_type n) const; | |
T &operator[](size_type n); // access: return reference | |
const T operator[](size_type n) const { return elem[n]; } | |
T *back() { return elem[sz - 1]; } | |
T *front() { return elem[0]; } | |
const T *back() const { return elem[sz - 1]; } | |
const T *front() const { return elem[0]; } | |
void reserve(const int newalloc); //growth | |
void resize(int newsize, T val); | |
void push_back(const T &val); | |
void push_front(const T &val) { insert(0, val); } | |
template <typename T, typename A> | |
friend std::ostream &operator<<(std::ostream &os, const vector &v); | |
template <typename T, typename A> | |
friend std::istream &operator>>(std::istream &is, vector &v); | |
}; | |
#endif | |
template<typename T, typename A> | |
vector<T, A>::~vector() | |
{ | |
delete[] elem; | |
} | |
template<typename T, typename A> | |
typename vector<T, A>::iterator vector<T, A>::insert(typename vector<T, A>::iterator p, const T &val) | |
{ | |
int index = p - begin(); | |
if (size() == capacity()) | |
{ | |
reserve(size() == 0 ? 8 : 2 * size()); // make sure we have space | |
} | |
// first copy last element into uninitialized space | |
alloc.construct(elem + sz, *back()); | |
++sz; | |
iterator pp = begin() + index; // the place to put val | |
for (auto pos = end() - 1; pos != pp; --pos) | |
{ | |
*pos = *(pos - 1); // copy elements one position to the right | |
} | |
*(begin() + index) = val; // "insert" val | |
return pp; | |
} | |
template<typename T, typename A> | |
typename vector<T, A>::iterator vector<T, A>::erase(typename vector<T, A>::iterator p) | |
{ | |
if (p == end()) | |
{ | |
return p; | |
} | |
for (auto pos = p + 1; pos != end(); ++pos) | |
{ | |
*(pos - 1) = *pos; // copyy element "one position to the left" | |
} | |
alloc.destroy(&*(end() - 1)); // destroy surplus copy of last element | |
--sz; | |
return p; | |
} | |
template<typename T, typename A> | |
T &vector<T, A>::operator[](size_type n) | |
{ | |
if (n < 0 || n >= sz) | |
{ | |
throw std::out_of_range{ "vector index out of range" }; | |
} | |
return elem[n]; | |
} | |
template<typename T, typename A> | |
vector<T, A> &vector<T, A>::operator=(const vector<T, A> &a) | |
{ | |
if (this == &a) | |
{ | |
return *this; // self-assignment; no work needed | |
} | |
if (a.sz <= space) // enough space, no need for new allocation | |
{ | |
for (size_type i = 0; i < a.sz; ++i) | |
{ | |
elem[i] = a.elem[i]; // copy elements | |
} | |
sz = a.sz; | |
return *this; | |
} | |
T *p = new T[a.sz]; // allocate new space | |
for (size_type i = 0; i < a.sz; ++i) | |
{ | |
p[i] = a.elem[i]; // copy elements | |
} | |
delete[] elem; // deallocate old space | |
space = sz = a.sz; // set new size | |
elem = p; // set new elements | |
return *this; // return a self-reference | |
} | |
template<typename T, typename A> | |
void vector<T, A>::resize(int newsize, T val) | |
// make the vector have newsize elements | |
// initialize each new element with the default value 0.0 | |
{ | |
if (elem) | |
{ | |
reserve(newsize); | |
for (size_type i = sz; i < newsize; ++i) | |
{ | |
alloc.construct(&elem[i], val); | |
} | |
for (size_type i = newsize; i < sz; ++i) | |
{ | |
alloc.destroy(&elem[sz]); | |
} | |
sz = newsize; | |
} | |
else | |
{ | |
throw std::invalid_argument{ "elem is null (line 242, vector.h)" }; | |
} | |
} | |
template<typename T, typename A> | |
void vector<T, A>::push_back(const T &val) | |
{ | |
if (elem) | |
{ | |
if (space == 0) | |
{ | |
reserve(8); | |
} | |
else if (sz == space) | |
{ | |
reserve(2 * space); // get more space | |
} | |
alloc.construct(&elem[sz], val); // add val at end | |
++sz; // increase the size | |
} | |
else | |
{ | |
throw std::invalid_argument{ "elem is null (line 242, vector.h)" }; | |
} | |
} | |
template<typename T, typename A> | |
void vector<T, A>::reserve(const int newalloc) | |
{ | |
if (elem) | |
{ | |
if (newalloc <= this->space) | |
{ | |
return; // never decrease allocation | |
} | |
vector_base<T, A> b{ this->alloc, newalloc }; // allocate new space | |
std::uninitialized_copy(b.elem, (&b.elem[this->sz]), this->elem); // copy | |
for (size_type i = 0; i < this->sz; ++i) | |
{ | |
this->alloc.destroy(&this->elem[i]); // destroy old | |
} | |
std::swap<vector_base<T, A>>(*this, b); // swap representations | |
} | |
else | |
{ | |
throw std::invalid_argument{ "elem is null (line 242, vector.h)" }; | |
} | |
} | |
template<typename T, typename A> | |
vector<T, A> &vector<T, A>::operator=(vector<T> &&a) | |
{ | |
delete[] elem; // deallocate old space | |
elem = a.elem; // copy a's elem and sz | |
sz = a.sz; | |
a.elem = nullptr; // make a the empty vector | |
a.sz = 0; | |
return *this; | |
} | |
template<typename T, typename A> | |
T &vector<T, A>::at(size_type n) | |
{ | |
if (n < 0 || sz <= n) | |
{ | |
throw std::out_of_range{ "vector element out of range" }; | |
} | |
return elem[n]; | |
} | |
template<typename T, typename A> | |
const T &vector<T, A>::at(size_type n) const | |
{ | |
if (n < 0 || sz <= n) | |
{ | |
throw std::out_of_range{ "vector element out of range" }; | |
} | |
return elem[n]; | |
} | |
template<typename T, typename A = std::allocator<T>> | |
std::ostream &operator<<(std::ostream &os, const vector<T, A> &v) | |
{ | |
for (auto i = v.begin(); i != v.end(); ++i) | |
{ | |
os << *i; | |
} | |
return os; | |
} | |
template<typename T, typename A = std::allocator<T>> | |
std::istream &operator>>(std::istream &is, vector<T, A> &v) | |
{ | |
if (is) | |
{ | |
auto it = std::istream_iterator<T>(is); | |
auto end = std::istream_iterator<T>(); | |
std::copy(it, end, std::back_inserter(v)); | |
} | |
return is; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment