libostd/octa/vector.h

349 lines
11 KiB
C
Raw Normal View History

2015-04-06 01:05:21 +02:00
/* Self-expanding dynamic array implementation for OctaSTD.
*
2015-04-12 22:41:02 +02:00
* This file is part of OctaSTD. See COPYING.md for futher information.
2015-04-06 01:05:21 +02:00
*/
2015-04-11 22:00:10 +02:00
#ifndef OCTA_VECTOR_H
#define OCTA_VECTOR_H
2015-04-06 01:05:21 +02:00
2015-04-14 23:16:06 +02:00
#include <string.h>
#include <stddef.h>
2015-04-14 23:16:06 +02:00
2015-04-13 23:25:31 +02:00
#include "octa/new.h"
2015-04-25 17:13:21 +02:00
#include "octa/type_traits.h"
#include "octa/utility.h"
#include "octa/range.h"
#include "octa/algorithm.h"
#include "octa/initializer_list.h"
2015-04-06 01:05:21 +02:00
2015-04-11 22:00:10 +02:00
namespace octa {
2015-04-06 01:05:21 +02:00
template<typename T>
2015-04-12 22:41:02 +02:00
class Vector {
2015-04-14 23:16:06 +02:00
T *p_buf;
size_t p_len, p_cap;
2015-04-06 01:05:21 +02:00
2015-04-29 02:38:16 +02:00
void insert_base(size_t idx, size_t n) noexcept(
IsNothrowDestructible<T>::value
&& IsNothrowMoveConstructible<T>::value
&& IsNothrowMoveAssignable<T>::value
) {
2015-04-16 23:44:25 +02:00
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) {
2015-04-18 21:20:40 +02:00
p_buf[i] = move(p_buf[i - n]);
2015-04-16 23:44:25 +02:00
}
}
2015-04-06 01:05:21 +02:00
public:
2015-04-14 23:16:06 +02:00
enum { MIN_SIZE = 8 };
2015-05-04 00:44:48 +02:00
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;
2015-04-15 23:09:20 +02:00
2015-04-28 19:48:58 +02:00
Vector() noexcept: p_buf(nullptr), p_len(0), p_cap(0) {}
2015-04-06 01:05:21 +02:00
2015-04-29 02:38:16 +02:00
explicit Vector(size_t n, const T &val = T()) noexcept(
IsNothrowCopyConstructible<T>::value
): Vector() {
2015-04-14 23:16:06 +02:00
p_buf = 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);
}
2015-04-29 02:38:16 +02:00
Vector(const Vector &v) noexcept(
IsNothrowDestructible<T>::value
&& IsNothrowCopyConstructible<T>::value
): Vector() {
2015-04-14 23:21:17 +02:00
*this = v;
}
2015-04-28 19:48:58 +02:00
Vector(Vector &&v) noexcept: p_buf(v.p_buf), p_len(v.p_len),
p_cap(v.p_cap) {
2015-04-15 23:41:32 +02:00
v.p_buf = nullptr;
2015-04-15 00:04:51 +02:00
v.p_len = v.p_cap = 0;
}
2015-04-29 02:38:16 +02:00
Vector(InitializerList<T> v) noexcept(
IsNothrowCopyConstructible<T>::value
): Vector() {
2015-04-16 23:33:31 +02:00
size_t len = v.length();
const T *ptr = v.get();
reserve(len);
for (size_t i = 0; i < len; ++i)
new (&p_buf[i]) T(ptr[i]);
p_len = len;
}
2015-04-28 19:48:58 +02:00
~Vector() noexcept(IsNothrowDestructible<T>::value) {
2015-04-14 23:16:06 +02:00
clear();
delete[] (uchar *)p_buf;
p_buf = nullptr;
p_cap = 0;
2015-04-06 01:05:21 +02:00
}
2015-04-28 19:48:58 +02:00
void clear() noexcept(IsNothrowDestructible<T>::value) {
if (p_len > 0 && !octa::IsPod<T>()) {
T *cur = p_buf, *last = p_buf + p_len;
while (cur != last) (*cur++).~T();
2015-04-14 23:16:06 +02:00
}
p_len = 0;
2015-04-14 23:16:06 +02:00
}
2015-04-29 02:38:16 +02:00
Vector<T> &operator=(const Vector<T> &v) noexcept(
IsNothrowDestructible<T>::value
&& IsNothrowCopyConstructible<T>::value
) {
2015-04-14 23:16:06 +02:00
if (this == &v) return *this;
clear();
reserve(v.p_cap);
p_len = v.p_len;
2015-04-27 21:23:38 +02:00
if (octa::IsPod<T>()) {
2015-04-14 23:16:06 +02:00
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++);
}
}
2015-04-06 01:05:21 +02:00
return *this;
}
2015-04-12 22:41:02 +02:00
2015-04-29 02:38:16 +02:00
Vector<T> &operator=(Vector<T> &&v) noexcept(
IsNothrowDestructible<T>::value
) {
2015-04-18 21:20:40 +02:00
clear();
delete[] (uchar *)p_buf;
2015-04-18 21:20:40 +02:00
p_len = v.p_len;
p_cap = v.p_cap;
p_buf = v.disown();
return *this;
}
Vector<T> &operator=(InitializerList<T> il) noexcept(
IsNothrowDestructible<T>::value &&
IsNothrowCopyConstructible<T>::value
) {
clear();
size_t ilen = il.length();
reserve(ilen);
if (octa::IsPod<T>()) {
memcpy(p_buf, il.get(), ilen);
} else {
T *buf = p_buf, *ibuf = il.get(), *last = il.get() + ilen;
while (ibuf != last) {
new (buf++) T(*ibuf++);
}
}
p_len = ilen;
return *this;
}
2015-04-29 02:38:16 +02:00
void resize(size_t n, const T &v = T()) noexcept(
IsNothrowDestructible<T>::value
2015-04-28 19:48:58 +02:00
&& IsNothrowMoveConstructible<T>::value
2015-04-29 02:38:16 +02:00
&& IsNothrowCopyConstructible<T>::value
) {
2015-04-14 23:16:06 +02:00
size_t len = p_len;
reserve(n);
p_len = n;
2015-04-27 21:23:38 +02:00
if (octa::IsPod<T>()) {
2015-04-14 23:16:06 +02:00
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);
}
}
2015-04-29 02:38:16 +02:00
void reserve(size_t n) noexcept(
IsNothrowDestructible<T>::value
&& IsNothrowMoveConstructible<T>::value
) {
2015-04-14 23:16:06 +02:00
if (n <= p_len) {
if (n == p_len) return;
while (p_len > n) pop();
return;
}
size_t oc = p_cap;
if (!oc) {
p_cap = max(n, size_t(MIN_SIZE));
2015-04-14 23:16:06 +02:00
} else {
while (p_cap < n) p_cap *= 2;
}
T *tmp = (T *)new uchar[p_cap * sizeof(T)];
if (oc > 0) {
2015-04-27 21:23:38 +02:00
if (octa::IsPod<T>()) {
2015-04-14 23:16:06 +02:00
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));
2015-04-14 23:16:06 +02:00
(*cur).~T();
++cur;
}
}
delete[] (uchar *)p_buf;
}
p_buf = tmp;
}
2015-04-28 19:48:58 +02:00
T &operator[](size_t i) noexcept { return p_buf[i]; }
const T &operator[](size_t i) const noexcept { return p_buf[i]; }
2015-04-14 23:16:06 +02:00
2015-04-28 19:48:58 +02:00
T &at(size_t i) noexcept { return p_buf[i]; }
const T &at(size_t i) const noexcept { return p_buf[i]; }
2015-04-14 23:16:06 +02:00
2015-04-29 02:38:16 +02:00
T &push(const T &v) noexcept(
noexcept(reserve(p_len + 1))
&& IsNothrowCopyConstructible<T>::value
) {
2015-04-14 23:16:06 +02:00
if (p_len == p_cap) reserve(p_len + 1);
new (&p_buf[p_len]) T(v);
return p_buf[p_len++];
2015-04-12 22:41:02 +02:00
}
2015-04-29 02:38:16 +02:00
T &push() noexcept(
noexcept(reserve(p_len + 1))
&& IsNothrowDefaultConstructible<T>::value
) {
2015-04-14 23:16:06 +02:00
if (p_len == p_cap) reserve(p_len + 1);
new (&p_buf[p_len]) T;
return p_buf[p_len++];
2015-04-12 22:41:02 +02:00
}
2015-04-15 00:04:51 +02:00
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)...);
2015-04-15 00:04:51 +02:00
return p_buf[p_len++];
}
2015-04-28 19:48:58 +02:00
void pop() noexcept(IsNothrowDestructible<T>::value) {
2015-04-27 21:23:38 +02:00
if (!octa::IsPod<T>()) {
2015-04-14 23:16:06 +02:00
p_buf[--p_len].~T();
} else {
--p_len;
2015-04-12 22:41:02 +02:00
}
}
2015-04-14 23:16:06 +02:00
2015-04-28 19:48:58 +02:00
T &pop_ret() noexcept {
2015-04-15 23:09:20 +02:00
return p_buf[--p_len];
}
2015-04-28 19:48:58 +02:00
T &first() noexcept { return p_buf[0]; }
const T &first() const noexcept { return p_buf[0]; };
2015-04-15 23:09:20 +02:00
2015-04-28 19:48:58 +02:00
T &last() noexcept { return p_buf[p_len - 1]; }
const T &last() const noexcept { return p_buf[p_len - 1]; }
2015-04-15 23:09:20 +02:00
2015-04-28 19:48:58 +02:00
T *get() noexcept { return p_buf; }
const T *get() const noexcept { return p_buf; }
2015-04-14 23:16:06 +02:00
2015-04-28 19:48:58 +02:00
size_t length() const noexcept { return p_len; }
size_t capacity() const noexcept { return p_cap; }
2015-04-14 23:16:06 +02:00
2015-04-28 19:48:58 +02:00
bool empty() const noexcept { return (p_len == 0); }
2015-04-15 23:09:20 +02:00
2015-04-28 19:48:58 +02:00
bool in_range(size_t idx) noexcept { return idx < p_len; }
bool in_range(int idx) noexcept { return idx >= 0 && idx < p_len; }
bool in_range(const T *ptr) noexcept {
2015-04-15 23:09:20 +02:00
return ptr >= p_buf && ptr < &p_buf[p_len];
}
2015-04-28 19:48:58 +02:00
T *disown() noexcept {
2015-04-15 23:09:20 +02:00
T *r = p_buf;
2015-04-15 23:41:32 +02:00
p_buf = nullptr;
2015-04-15 23:09:20 +02:00
p_len = p_cap = 0;
return r;
}
2015-05-01 21:21:47 +02:00
T *insert(size_t idx, T &&v) noexcept(
IsNothrowDestructible<T>::value
&& IsNothrowMoveConstructible<T>::value
&& IsNothrowMoveAssignable<T>::value
) {
2015-04-16 23:44:25 +02:00
insert_base(idx, 1);
2015-04-28 19:48:58 +02:00
p_buf[idx] = move(v);
2015-04-16 23:44:25 +02:00
return &p_buf[idx];
}
2015-04-29 02:38:16 +02:00
T *insert(size_t idx, const T &v) noexcept(
2015-05-01 21:21:47 +02:00
IsNothrowDestructible<T>::value
&& IsNothrowMoveConstructible<T>::value
&& IsNothrowMoveAssignable<T>::value
&& IsNothrowCopyAssignable<T>::value
2015-04-29 02:38:16 +02:00
) {
2015-04-16 23:44:25 +02:00
insert_base(idx, 1);
2015-04-18 21:20:40 +02:00
p_buf[idx] = v;
2015-04-16 23:33:31 +02:00
return &p_buf[idx];
}
2015-04-29 02:38:16 +02:00
T *insert(size_t idx, size_t n, const T &v) noexcept(
2015-05-01 21:21:47 +02:00
IsNothrowDestructible<T>::value
&& IsNothrowMoveConstructible<T>::value
&& IsNothrowMoveAssignable<T>::value
&& IsNothrowCopyAssignable<T>::value
2015-04-29 02:38:16 +02:00
) {
2015-04-16 23:44:25 +02:00
insert_base(idx, n);
2015-04-16 23:33:31 +02:00
for (size_t i = 0; i < n; ++i) {
2015-04-18 21:20:40 +02:00
p_buf[idx + i] = v;
2015-04-16 23:33:31 +02:00
}
return &p_buf[idx];
}
template<typename U>
2015-04-29 02:38:16 +02:00
T *insert_range(size_t idx, U range) noexcept(
IsNothrowDestructible<T>::value
&& IsNothrowMoveConstructible<T>::value
&& IsNothrowMoveAssignable<T>::value
&& noexcept(range.first())
&& noexcept(range.pop_first())
&& noexcept((*p_buf = range.first()))
) {
size_t len = range.length();
insert_base(idx, len);
for (size_t i = 0; i < len; ++i) {
2015-04-18 21:20:40 +02:00
p_buf[idx + i] = range.first();
range.pop_first();
}
return &p_buf[idx];
}
2015-04-29 02:38:16 +02:00
T *insert(size_t idx, InitializerList<T> il) noexcept(
2015-05-01 21:21:47 +02:00
noexcept(declval<Vector<T>>().insert_range(idx, il.range()))
2015-04-29 02:38:16 +02:00
) {
return insert_range(idx, il.range());
2015-04-17 00:11:56 +02:00
}
2015-05-04 00:44:48 +02:00
RangeType each() noexcept {
return PointerRange<T>(p_buf, p_buf + p_len);
}
2015-05-04 00:44:48 +02:00
ConstRangeType each() const noexcept {
return PointerRange<const T>(p_buf, p_buf + p_len);
2015-04-16 21:35:10 +02:00
}
2015-04-28 19:48:58 +02:00
void swap(Vector &v) noexcept {
swap(p_len, v.p_len);
swap(p_cap, v.p_cap);
swap(p_buf, v.p_buf);
}
2015-04-06 01:05:21 +02:00
};
template<typename T>
2015-04-28 19:48:58 +02:00
void swap(Vector<T> &a, Vector<T> &b) noexcept {
a.swap(b);
}
2015-04-06 01:05:21 +02:00
}
#endif