#ifndef LITB_VECTOR_H
#define LITB_VECTOR_H
namespace litb {
template<typename T>
T min(const T& a, const T& b) {
return a < b ? a : b;
}
template<typename T>
T max(const T& a, const T& b) {
return a > b ? a : b;
}
}
#include <new>
#include <type_traits>
namespace litb {
// The functionality of Vector that does not depend on the "SmallSize"
// template parameter.
template<typename T>
class VectorBase {
public:
typedef T *iterator;
typedef const T *const_iterator;
typedef T value_type;
public:
VectorBase(T *data, T *endData)
:_data(data), _endData(data), _endReserve(endData)
{ }
~VectorBase() {
clear();
if(usesHeap()) {
operator delete(_data);
}
}
public:
iterator begin() { return _data; }
iterator end() { return _endData; }
const_iterator begin() const { return _data; }
const_iterator end() const { return _endData; }
public:
// appends a new item to the back of the vector
void append(const T& t) {
insert(end(), t);
}
void prepend(const T& t) {
insert(begin(), t);
}
// inserts a new item before the given iterator, and return
// an iterator to the new item
iterator insert(iterator it, const T& t) {
it = grow(it, 1);
new ((void*)it) T(t);
_endData++;
return it;
}
// assigns the given range to this vector
template<typename Iterator>
void assign(Iterator b, Iterator e) {
clear();
insert(end(), b, e);
}
// inserts the range [b, e) before iterator position "it", and return
// a pointer to the first item inserted
template<typename Iterator>
iterator insert(iterator it, Iterator b, Iterator e) {
it = grow(it, e - b);
for(; b != e; b++, it++) {
new ((void*)it) T(*b);
_endData++;
}
return it;
}
// makes the vector have size() 0, without changing the capacity
void clear() {
for(; _endData != _data; _endData--) {
_endData[-1].~T();
}
_endData = _data;
}
// erases the portion [b, e) of the vector, without changing the capacity
void erase(iterator b, iterator e) {
if(b == e) {
clear();
return;
}
for(; e != _endData; e++, b++) {
*b = *e;
}
T *dptr = _endData;
for(T *edptr = dptr - (e - b); dptr != edptr; dptr--)
dptr->~T();
_endData = dptr;
}
// returns the actual size of the vector
int size() const { return _endData - _data; }
// returns the reserved capacity of the vector that it can insert without
// reallocating
int capacity() const { return _endReserve - _data; }
// returns true if we use the heap memory currently.
bool usesHeap() const {
return (const void*)_data != (this + 1);
}
// reserves space for at least "space" items
void reserve(int space) {
if(space <= capacity())
return;
grow(end(), space - capacity());
}
private:
// copying this class would slice away the builtin array - so we forbid that
VectorBase(const VectorBase &other);
private:
// reserves space for "elements" items before iterator "it".
// returns an iterator pointing at the first free slot.
iterator grow(iterator it, int elements) {
if(elements == 0)
return it;
int index = it - begin();
if((_endReserve - _endData) < elements) {
// reallocate, leaving "elements" free slots at "index"
int newCapacity = max(capacity() * 2, capacity() + elements);
T *data1 = (T*)operator new(sizeof(T) * newCapacity);
T *endData1 = data1;
T *endReserve1 = data1 + newCapacity;
for(T *data = _data; data != _endData; data++, endData1++) {
if(data - _data == index) {
endData1 += elements;
}
new ((void*)endData1) T(*data);
}
for(; _endData != _data; _endData--)
_endData[-1].~T();
if(usesHeap()) {
operator delete(_data);
}
_data = data1;
_endData= endData1;
_endReserve = endReserve1;
} else if(it != end()) {
T *endData1 = _endData, *endDataNew1 = _endData + elements;
int newlyAllocated = min(elements, end() - it);
for(; newlyAllocated > 0; newlyAllocated--, endDataNew1--, endData1--) {
new ((void*)&endDataNew1[-1]) T(endData1[-1]);
}
for(; endData1 != it; endData1--, endDataNew1--) {
endDataNew1[-1] = endData1[-1];
}
// the hole should contain unconstructed items that the caller can placement-new into
int dtorsInHole = min(elements, (end() - it));
for(iterator itHole = it; dtorsInHole > 0; dtorsInHole--, itHole++)
itHole->~T();
}
return begin() + index;
}
private:
T *_data;
T *_endData;
T *_endReserve;
};
// A vector that allocates "SmallSize" elements in its own memory and
// only if more elements are needed, reverts to heap memory.
template<typename T, int SmallSize>
class Vector : public VectorBase<T> {
union {
typename std::aligned_storage<sizeof(T), alignof(T)>::type
_aligner;
unsigned char _buffer[sizeof(T) * SmallSize];
};
public:
Vector():VectorBase<T>((T*)_buffer, (T*)_buffer + SmallSize) {}
Vector(const Vector& other):Vector() {
this->insert(this->end(), other.begin(), other.end());
}
template<int SmallSize1>
Vector(const Vector<T, SmallSize1>& other):Vector() {
this->insert(this->end(), other.begin(), other.end());
}
};
}
#endif
#include <iostream>
struct A {
A(int x):x(x) {
std::cout << "A(" << x << ")" << std::endl;
}
~A() {
std::cout << "~A(" << x << ")" << std::endl;
}
A(A const& other):x(other.x) {
std::cout << "A(A const&)(" << other.x << ")" << std::endl;
}
int x;
};
int main() {
litb::Vector<A, 5> v;
v.append(A(1));
v.append(A(2));
v.append(A(3));
v.append(A(4));
v.append(A(5));
v.append(A(6));
std::cout << "\n";
for(const A& a : v)
std::cout << "> " << a.x << std::endl;
litb::Vector<A, 6> v1(v);
std::cout << "\n";
for(const A& a : v1)
std::cout << "> " << a.x << std::endl;
}