Skip to content

Instantly share code, notes, and snippets.

@DragonOsman
Last active November 29, 2017 13:11
Show Gist options
  • Save DragonOsman/a9b2fef7f8afd634bb584bac1678aecb to your computer and use it in GitHub Desktop.
Save DragonOsman/a9b2fef7f8afd634bb584bac1678aecb to your computer and use it in GitHub Desktop.
#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();
}
#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