libostd/octa/vector.h

316 lines
9.0 KiB
C++

/* Self-expanding dynamic array implementation for OctaSTD.
*
* This file is part of OctaSTD. See COPYING.md for futher information.
*/
#ifndef OCTA_VECTOR_H
#define OCTA_VECTOR_H
#include <string.h>
#include <stddef.h>
#include "octa/new.h"
#include "octa/type_traits.h"
#include "octa/utility.h"
#include "octa/range.h"
#include "octa/algorithm.h"
#include "octa/initializer_list.h"
namespace octa {
template<typename T>
class Vector {
T *p_buf;
size_t p_len, p_cap;
void insert_base(size_t idx, size_t n) {
if (p_len + n > p_cap) reserve(p_len + n);
p_len += n;
for (size_t i = p_len - 1; i > idx + n - 1; --i) {
p_buf[i] = move(p_buf[i - n]);
}
}
template<typename R>
void ctor_from_range(R &range, EnableIf<IsFiniteRandomAccessRange<R>
::value, bool
> = true) {
RangeSize<R> len = range.size();
reserve(len);
p_len = len;
for (size_t i = 0; !range.empty(); range.pop_front()) {
new (&p_buf[i]) T(range.front());
++i;
}
}
template<typename R>
void ctor_from_range(R &range, EnableIf<!IsFiniteRandomAccessRange<R>
::value, bool
> = true) {
size_t i = 0;
for (; !range.empty(); range.pop_front()) {
reserve(i + 1);
new (&p_buf[i]) T(range.front());
++i;
p_len = i;
}
}
public:
enum { MIN_SIZE = 8 };
typedef size_t SizeType;
typedef ptrdiff_t DiffType;
typedef T ValType;
typedef T &RefType;
typedef const T &ConstRefType;
typedef T *PtrType;
typedef const T *ConstPtrType;
typedef PointerRange< T> RangeType;
typedef PointerRange<const T> ConstRangeType;
Vector(): p_buf(nullptr), p_len(0), p_cap(0) {}
explicit Vector(size_t n, const T &val = T()): Vector() {
p_buf = (T *)new uchar[n * sizeof(T)];
p_len = p_cap = n;
T *cur = p_buf, *last = p_buf + n;
while (cur != last) new (cur++) T(val);
}
Vector(const Vector &v): Vector() {
*this = v;
}
Vector(Vector &&v): p_buf(v.p_buf), p_len(v.p_len), p_cap(v.p_cap) {
v.p_buf = nullptr;
v.p_len = v.p_cap = 0;
}
Vector(InitializerList<T> v): Vector() {
size_t len = v.end() - v.begin();
const T *ptr = v.begin();
reserve(len);
for (size_t i = 0; i < len; ++i)
new (&p_buf[i]) T(ptr[i]);
p_len = len;
}
template<typename R> Vector(R range): Vector() {
ctor_from_range(range);
}
~Vector() {
clear();
delete[] (uchar *)p_buf;
p_buf = nullptr;
p_cap = 0;
}
void clear() {
if (p_len > 0 && !octa::IsPod<T>()) {
T *cur = p_buf, *last = p_buf + p_len;
while (cur != last) (*cur++).~T();
}
p_len = 0;
}
Vector<T> &operator=(const Vector<T> &v) {
if (this == &v) return *this;
clear();
reserve(v.p_cap);
p_len = v.p_len;
if (octa::IsPod<T>()) {
memcpy(p_buf, v.p_buf, p_len * sizeof(T));
} else {
T *cur = p_buf, *last = p_buf + p_len;
T *vbuf = v.p_buf;
while (cur != last) {
new (cur++) T(*vbuf++);
}
}
return *this;
}
Vector<T> &operator=(Vector<T> &&v) {
clear();
delete[] (uchar *)p_buf;
p_len = v.p_len;
p_cap = v.p_cap;
p_buf = v.disown();
return *this;
}
Vector<T> &operator=(InitializerList<T> il) {
clear();
size_t ilen = il.end() - il.begin();
reserve(ilen);
if (octa::IsPod<T>()) {
memcpy(p_buf, il.begin(), ilen);
} else {
T *buf = p_buf, *ibuf = il.begin(), *last = il.end();
while (ibuf != last) {
new (buf++) T(*ibuf++);
}
}
p_len = ilen;
return *this;
}
template<typename R>
Vector<T> &operator=(R range) {
clear();
ctor_from_range(range);
}
void resize(size_t n, const T &v = T()) {
size_t len = p_len;
reserve(n);
p_len = n;
if (octa::IsPod<T>()) {
for (size_t i = len; i < p_len; ++i) {
p_buf[i] = T(v);
}
} else {
T *first = p_buf + len;
T *last = p_buf + p_len;
while (first != last) new (first++) T(v);
}
}
void reserve(size_t n) {
if (n <= p_cap) return;
size_t oc = p_cap;
if (!oc) {
p_cap = max(n, size_t(MIN_SIZE));
} else {
while (p_cap < n) p_cap *= 2;
}
T *tmp = (T *)new uchar[p_cap * sizeof(T)];
if (oc > 0) {
if (octa::IsPod<T>()) {
memcpy(tmp, p_buf, p_len * sizeof(T));
} else {
T *cur = p_buf, *tcur = tmp, *last = tmp + p_len;
while (tcur != last) {
new (tcur++) T(move(*cur));
(*cur).~T();
++cur;
}
}
delete[] (uchar *)p_buf;
}
p_buf = tmp;
}
T &operator[](size_t i) { return p_buf[i]; }
const T &operator[](size_t i) const { return p_buf[i]; }
T &at(size_t i) { return p_buf[i]; }
const T &at(size_t i) const { return p_buf[i]; }
T &push(const T &v) {
if (p_len == p_cap) reserve(p_len + 1);
new (&p_buf[p_len]) T(v);
return p_buf[p_len++];
}
T &push() {
if (p_len == p_cap) reserve(p_len + 1);
new (&p_buf[p_len]) T;
return p_buf[p_len++];
}
template<typename ...U>
T &emplace_back(U &&...args) {
if (p_len == p_cap) reserve(p_len + 1);
new (&p_buf[p_len]) T(forward<U>(args)...);
return p_buf[p_len++];
}
void pop() {
if (!octa::IsPod<T>()) {
p_buf[--p_len].~T();
} else {
--p_len;
}
}
T &front() { return p_buf[0]; }
const T &front() const { return p_buf[0]; };
T &back() { return p_buf[p_len - 1]; }
const T &back() const { return p_buf[p_len - 1]; }
T *data() { return p_buf; }
const T *data() const { return p_buf; }
size_t size() const { return p_len; }
size_t capacity() const { return p_cap; }
bool empty() const { return (p_len == 0); }
bool in_range(size_t idx) { return idx < p_len; }
bool in_range(int idx) { return idx >= 0 && size_t(idx) < p_len; }
bool in_range(const T *ptr) {
return ptr >= p_buf && ptr < &p_buf[p_len];
}
T *disown() {
T *r = p_buf;
p_buf = nullptr;
p_len = p_cap = 0;
return r;
}
T *insert(size_t idx, T &&v) {
insert_base(idx, 1);
p_buf[idx] = move(v);
return &p_buf[idx];
}
T *insert(size_t idx, const T &v) {
insert_base(idx, 1);
p_buf[idx] = v;
return &p_buf[idx];
}
T *insert(size_t idx, size_t n, const T &v) {
insert_base(idx, n);
for (size_t i = 0; i < n; ++i) {
p_buf[idx + i] = v;
}
return &p_buf[idx];
}
template<typename U>
T *insert_range(size_t idx, U range) {
size_t len = range.size();
insert_base(idx, len);
for (size_t i = 0; i < len; ++i) {
p_buf[idx + i] = range.front();
range.pop_front();
}
return &p_buf[idx];
}
T *insert(size_t idx, InitializerList<T> il) {
return insert_range(idx, octa::each(il));
}
RangeType each() {
return PointerRange<T>(p_buf, p_buf + p_len);
}
ConstRangeType each() const {
return PointerRange<const T>(p_buf, p_buf + p_len);
}
void swap(Vector &v) {
octa::swap(p_len, v.p_len);
octa::swap(p_cap, v.p_cap);
octa::swap(p_buf, v.p_buf);
}
};
}
#endif