| @ -0,0 +1,251 @@ | |||
| #pragma once | |||
| #include <gp/buffer.hpp> | |||
| #include <gp/allocator/allocator.hpp> | |||
| #include <initializer_list> | |||
| namespace gp{ | |||
| template<typename T> | |||
| class vector{ | |||
| public: | |||
| T* ary; | |||
| size_t sz; | |||
| size_t cap; | |||
| gp::reference_wrapper<allocator> alloc; | |||
| 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(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 = 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; | |||
| } | |||
| 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}; | |||
| } | |||
| }; | |||
| } | |||