214 lines
5.6 KiB
C++
214 lines
5.6 KiB
C++
#pragma once
|
|
|
|
#include <cstring>
|
|
#include <cstddef>
|
|
#include <memory>
|
|
#include <type_traits>
|
|
#include <limits>
|
|
|
|
namespace tf {
|
|
|
|
// Class: PassiveVector
|
|
// A vector storing only passive data structure (PDS) or POD data type.
|
|
template <typename T, size_t S = 4, typename A = std::allocator<T>>
|
|
class PassiveVector {
|
|
|
|
static_assert(
|
|
std::is_trivial<T>::value && std::is_standard_layout<T>::value,
|
|
"must be a plain old data type"
|
|
);
|
|
|
|
public:
|
|
|
|
typedef T value_type;
|
|
typedef T & reference;
|
|
typedef const T & const_reference;
|
|
typedef T * pointer;
|
|
typedef const T * const_pointer;
|
|
typedef T * iterator;
|
|
typedef const T * const_iterator;
|
|
typedef std::reverse_iterator<iterator> reverse_iterator;
|
|
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
|
typedef ptrdiff_t difference_type;
|
|
typedef size_t size_type;
|
|
|
|
PassiveVector() noexcept :
|
|
_data {reinterpret_cast<pointer>(_stack)},
|
|
_num {0},
|
|
_cap {S} {
|
|
}
|
|
|
|
explicit PassiveVector(size_type n) : _num {n} {
|
|
|
|
// need to place on heap
|
|
if(n > S) {
|
|
_cap = n << 2;
|
|
_data = _allocator.allocate(_cap);
|
|
}
|
|
// stack
|
|
else {
|
|
_cap = S;
|
|
_data = reinterpret_cast<pointer>(_stack);
|
|
}
|
|
|
|
}
|
|
|
|
PassiveVector(const PassiveVector& rhs) : _num {rhs._num} {
|
|
|
|
// heap
|
|
if(rhs._num > S) {
|
|
_cap = rhs._cap;
|
|
_data = _allocator.allocate(rhs._cap);
|
|
}
|
|
else {
|
|
_cap = S;
|
|
_data = reinterpret_cast<pointer>(_stack);
|
|
}
|
|
|
|
std::memcpy(_data, rhs._data, _num * sizeof(T));
|
|
}
|
|
|
|
PassiveVector(PassiveVector&& rhs) : _num {rhs._num} {
|
|
|
|
// rhs is in the stack
|
|
if(rhs.in_stack()) {
|
|
_cap = S;
|
|
_data = reinterpret_cast<pointer>(_stack);
|
|
std::memcpy(_stack, rhs._stack, rhs._num*sizeof(T));
|
|
}
|
|
// rhs is in the heap
|
|
else {
|
|
_cap = rhs._cap;
|
|
_data = rhs._data;
|
|
rhs._data = reinterpret_cast<pointer>(rhs._stack);
|
|
rhs._cap = S;
|
|
}
|
|
|
|
rhs._num = 0;
|
|
}
|
|
|
|
~PassiveVector() {
|
|
if(!in_stack()) {
|
|
_allocator.deallocate(_data, _cap);
|
|
}
|
|
}
|
|
|
|
iterator begin() noexcept { return _data; }
|
|
const_iterator begin() const noexcept { return _data; }
|
|
const_iterator cbegin() const noexcept { return _data; }
|
|
iterator end() noexcept { return _data + _num; }
|
|
const_iterator end() const noexcept { return _data + _num; }
|
|
const_iterator cend() const noexcept { return _data + _num; }
|
|
|
|
reverse_iterator rbegin() noexcept { return _data + _num; }
|
|
const_reverse_iterator crbegin() const noexcept { return _data + _num; }
|
|
reverse_iterator rend() noexcept { return _data; }
|
|
const_reverse_iterator crend() const noexcept { return _data; }
|
|
|
|
reference operator [] (size_type idx) { return _data[idx]; }
|
|
const_reference operator [] (size_type idx) const { return _data[idx]; }
|
|
|
|
reference at(size_type pos) {
|
|
if(pos >= _num) {
|
|
throw std::out_of_range("accessed position is out of range");
|
|
}
|
|
return this->operator[](pos);
|
|
}
|
|
|
|
const_reference at(size_type pos) const {
|
|
if(pos >= _num) {
|
|
throw std::out_of_range("accessed position is out of range");
|
|
}
|
|
return this->operator[](pos);
|
|
}
|
|
|
|
|
|
reference front() { return _data[0]; }
|
|
const_reference front() const { return _data[0]; }
|
|
reference back() { return _data[_num-1]; }
|
|
const_reference back() const { return _data[_num-1]; }
|
|
|
|
pointer data() noexcept { return _data; }
|
|
const_pointer data() const noexcept { return _data; }
|
|
|
|
void push_back(const T& item) {
|
|
if(_num == _cap) {
|
|
_enlarge(_cap << 1);
|
|
}
|
|
_data[_num++] = item;
|
|
}
|
|
|
|
void push_back(T&& item) {
|
|
if(_num == _cap) {
|
|
_enlarge(_cap << 1);
|
|
}
|
|
_data[_num++] = item;
|
|
}
|
|
|
|
void pop_back() {
|
|
if(_num > 0) {
|
|
--_num;
|
|
}
|
|
}
|
|
|
|
void clear() {
|
|
_num = 0;
|
|
}
|
|
|
|
void resize(size_type N) {
|
|
if(N > _cap) {
|
|
_enlarge(N<<1);
|
|
}
|
|
_num = N;
|
|
}
|
|
|
|
void reserve(size_type C) {
|
|
if(C > _cap) {
|
|
_enlarge(C);
|
|
}
|
|
}
|
|
|
|
bool empty() const { return _num == 0; }
|
|
bool in_stack() const { return _data == reinterpret_cast<const_pointer>(_stack); }
|
|
|
|
size_type size() const { return _num; }
|
|
size_type capacity() const { return _cap; }
|
|
size_type max_size() const { return (std::numeric_limits<size_type>::max)(); }
|
|
|
|
bool operator == (const PassiveVector& rhs) const {
|
|
if(_num != rhs._num) {
|
|
return false;
|
|
}
|
|
return std::memcmp(_data, rhs._data, _num * sizeof(T)) == 0;
|
|
}
|
|
|
|
private:
|
|
|
|
char _stack[S*sizeof(T)];
|
|
|
|
T* _data;
|
|
|
|
size_type _num;
|
|
size_type _cap;
|
|
|
|
A _allocator;
|
|
|
|
void _enlarge(size_type new_cap) {
|
|
|
|
auto new_data = _allocator.allocate(new_cap);
|
|
|
|
std::memcpy(new_data, _data, sizeof(T) * _num);
|
|
|
|
if(!in_stack()) {
|
|
_allocator.deallocate(_data, _cap);
|
|
}
|
|
|
|
_cap = new_cap;
|
|
_data = new_data;
|
|
}
|
|
};
|
|
|
|
|
|
} // end of namespace tf. ----------------------------------------------------
|
|
|