diff --git a/octa/vector.h b/octa/vector.h index 9188e79..b47bdf5 100644 --- a/octa/vector.h +++ b/octa/vector.h @@ -6,66 +6,153 @@ #ifndef OCTA_VECTOR_H #define OCTA_VECTOR_H +#include + #include "octa/new.h" #include "octa/traits.h" namespace octa { template class Vector { - T *buf; - size_t length, capacity; + T *p_buf; + size_t p_len, p_cap; public: - explicit vector(): buf(NULL), length(0), capacity(0) {} + enum { MIN_SIZE = 8 }; - vector(const vector &v): buf(NULL), length(0), capacity(0) { + explicit Vector(): p_buf(NULL), p_len(0), p_cap(0) {} + + Vector(const Vector &v): p_buf(NULL), p_len(0), p_cap(0) { *this = v; } - ~vector() { - resize(0); - if (buf) delete[] (unsigned char *)buf; + Vector(size_t n, const T &val = T()): Vector() { + 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); } - vector &operator=(const vector &v) { - resize(0); - if (v.length() > capacity) resize(v.length()); - for (size_t i = 0; i < v.length(); ++i) push(v[i]); + ~Vector() { + clear(); + } + + void clear() { + if (p_cap > 0) { + if (octa::IsClass::value) { + T *cur = p_buf, *last = p_buf + p_len; + } + delete[] (uchar *)p_buf; + p_buf = NULL; + p_len = p_cap = 0; + } + } + + Vector &operator=(const Vector &v) { + if (this == &v) return *this; + + if (p_cap >= v.p_cap) { + if (octa::IsClass::value) { + T *cur = p_buf, *last = p_buf + p_len; + while (cur != last) (*cur++).~T(); + } + p_len = v.p_len; + } else { + clear(); + p_len = v.p_len; + p_cap = v.p_cap; + p_buf = (T *)new uchar[p_cap * sizeof(T)]; + } + + if (!octa::IsClass::value) { + 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; } + void resize(size_t n, const T &v = T()) { + size_t len = p_len; + reserve(n); + p_len = n; + if (!octa::IsClass::value) { + 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_len) { + if (n == p_len) return; + while (p_len > n) pop(); + return; + } + size_t oc = p_cap; + if (!oc) { + p_cap = (n > MIN_SIZE) ? n : MIN_SIZE; + } else { + while (p_cap < n) p_cap *= 2; + } + T *tmp = (T *)new uchar[p_cap * sizeof(T)]; + if (oc > 0) { + if (!octa::IsClass::value) { + 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(*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 (length == capacity) resize(length + 1); - new (&buf[length]) T(v); - return buf[length++]; + if (p_len == p_cap) reserve(p_len + 1); + new (&p_buf[p_len]) T(v); + return p_buf[p_len++]; } T &push() { - if (length == capacity) resize(length + 1); - new (&buf[length]) T; - return buf[length++]; + if (p_len == p_cap) reserve(p_len + 1); + new (&p_buf[p_len]) T; + return p_buf[p_len++]; } - void resize(size_t n) { - if (n <= length) { - if (n == length) return; - while (length > n) pop(); - return; + void pop() { + if (octa::IsClass::value) { + p_buf[--p_len].~T(); + } else { + --p_len; } - int old = capacity; - if (!old) - capacity = max(n, 8); - else - while (capacity < n) capacity += (capacity / 2); - if (capacity <= old) - return; - unsigned char *nbuf = new unsigned char[capacity * sizeof(T)]; - if (old > 0) { - if (length > 0) memcpy(nbuf, (void *)buf, length * sizeof(T)); - delete[] (unsigned char *)buf; - } - buf = (T *)buf; } + + T *get() { return p_buf; } + + size_t length() const { return p_len; } + size_t capacity() const { return p_cap; } + + bool empty() const { return (p_len == 0); } }; }