| @ -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}; | |||||
| } | |||||
| }; | |||||
| } | |||||