General Purpose library for Freestanding C++ and POSIX systems
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

261 lines
4.9 KiB

#pragma once
#include <gp/buffer.hpp>
#include <gp/allocator/allocator.hpp>
#include <initializer_list>
namespace gp{
template<typename T>
class vector final {
T* ary;
size_t sz;
size_t cap;
gp::reference_wrapper<allocator> alloc;
public:
using associated_iterator = pointer_iterator<T, 1>;
using associated_const_iterator = const_pointer_iterator<T, 1>;
using associated_riterator = pointer_iterator<T, -1>;
using associated_const_riterator = const_pointer_iterator<T, -1>;
vector(allocator& v)
: ary()
, alloc(v)
{}
vector(const vector& oth)
{
sz = 0;
cap = 0;
ary = nullptr;
alloc = oth.alloc;
gp_config::assertion(reserve(oth.size()), "could not reserve space on building");
sz = oth.size();
cap = oth.size();
auto it_l = begin();
auto it_o = oth.cbegin();
for(size_t i = 0; i < sz; ++i)
{
new(&*(it_l++)) T(*(it_o++));
}
}
vector(vector&& oth)
: ary(oth.ary)
, sz(oth.sz)
, cap(oth.cap)
, alloc(oth.alloc)
{
oth.ary = nullptr;
}
/* TODO: Build the templated equivalents
array(T (& oth)[sz]) {
gp::move_uninitialized<T>(
gp::nameless_range<int*>(oth, oth+sz),
gp::nameless_range<associated_iterator>(begin(), end())
);
}
array(T (&& oth)[sz]) {
gp::move_uninitialized(
gp::nameless_range<int*>((T*)oth, (T*)oth+sz),
gp::nameless_range<associated_iterator>(begin(), end())
);
}*/
vector& operator=(vector& oth)
{
gp_config::assertion(reserve(oth.size()), "could not reserve space on assign");
for(size_t i = 0; i < gp::min(sz, oth.sz); ++i)
{
ary[i]=oth[i];
}
if(sz < oth.sz) {
for(size_t i = sz; i < oth.sz; ++i) {
new(ary+i) T(oth[i]);
}
} else if(sz > oth.sz) {
for(size_t i = oth.sz; i < sz; ++i) {
ary[i]->~T();
}
}
sz = oth.sz;
return *this;
}
vector& operator=(vector&& oth)
{
gp::swap(ary, oth.ary);
gp::swap(alloc, oth.alloc);
gp::swap(sz, oth.sz);
gp::swap(cap, oth.cap);
return *this;
}
constexpr T& operator[] (size_t off)
{
if constexpr (gp_config::has_buffer_bounds)
{
gp_config::assertion(
off < sz,
"Array bounds infringed"
);
}
return ary[off];
}
~vector()
{
if(ary)
{
for(auto& elem : *this) {
elem.~T();
}
gp_config::assertion(alloc.get().deallocate(ary), "could not deallocate");
}
}
bool grow() {
if(sz == cap) return reserve(1 + sz + (sz >> 1));
return true;
}
bool reserve(size_t new_cap) {
if(new_cap <= cap) return true;
size_t new_data_size = new_cap*sizeof(T);
if(alloc.get().try_reallocate(ary, new_data_size)) return true;
if(T* new_ary = (T*)alloc.get().allocate(new_data_size); new_ary) {
auto new_it = new_ary;
for(auto& elem : *this) {
*(++new_it) = gp::move(elem);
}
gp_config::assertion(alloc.get().deallocate(ary), "failed to deallocate old range");
ary = new_ary;
cap = new_cap;
return true;
}
return false;
}
constexpr const T& operator[] (size_t off) const
{
return ary[off];
}
constexpr size_t size() const
{
return sz;
}
constexpr size_t capacity() const
{
return cap;
}
constexpr bool push_back(T& value) {
if(grow()) {
new(ary+sz) T(value);
sz++;
return true;
}
return false;
}
constexpr bool push_back(T&& value) {
if(grow()) {
new(ary+sz) T(gp::move(value));
sz++;
return true;
}
return false;
}
template<typename ...U>
constexpr bool emplace_back(U&&... value) {
if(grow()) {
new(ary+sz) T(gp::forward<U>(value)...);
sz++;
return true;
}
return false;
}
constexpr gp::optional<T> pop_back() {
if(sz == 0) return gp::nullopt;
sz--;
gp::optional<T> ret_val = gp::move(ary[sz]);
ary[sz]->~T();
return gp::move(ret_val);
}
constexpr pointer_iterator<T, 1> begin()
{
return associated_iterator(&ary[0]);
}
constexpr pointer_iterator<T, 1> end()
{
return associated_iterator(&ary[sz]);
}
constexpr const_pointer_iterator<T, 1> cbegin() const
{
return associated_const_iterator(&ary[0]);
}
constexpr const_pointer_iterator<T, 1> cend() const
{
return associated_const_iterator(&ary[sz]);
}
constexpr pointer_iterator<T, -1> rbegin()
{
return associated_riterator(&ary[sz-1]);
}
constexpr pointer_iterator<T, -1> rend()
{
return associated_riterator(ary-1);
}
constexpr const_pointer_iterator<T, -1> crbegin() const
{
return associated_const_riterator(&ary[sz-1]);
}
constexpr const_pointer_iterator<T, -1> crend() const
{
return associated_const_riterator(ary-1);
}
constexpr bool operator==(const vector& oth) const
{
for(size_t idx = 0; idx<sz; idx++)
{
if(ary[idx] != oth.ary[idx])
{
return false;
}
}
return true;
}
constexpr bool operator!=(const vector& oth) const
{
return !(*this == oth);
}
gp::buffer<T> as_buffer()
{
return gp::buffer<T>{(T*)ary, (T*)ary+sz};
}
};
}