#pragma once #include #include #include namespace gp{ template class vector final { T* ary = nullptr; size_t sz = 0; size_t cap = 0; gp::reference_wrapper alloc; public: using associated_iterator = pointer_iterator; using associated_const_iterator = const_pointer_iterator; using associated_riterator = pointer_iterator; using associated_const_riterator = const_pointer_iterator; vector(allocator& v) : ary() , alloc(v) {} vector(vector& oth) : alloc(oth.alloc) { sz = 0; cap = 0; ary = nullptr; 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( gp::nameless_range(oth, oth+sz), gp::nameless_range(begin(), end()) ); } array(T (&& oth)[sz]) { gp::move_uninitialized( gp::nameless_range((T*)oth, (T*)oth+sz), gp::nameless_range(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) { new(ary+i) T(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(++new_it) T(gp::move(elem)); } if(ary != nullptr) 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 constexpr bool emplace_back(U&&... value) { if(grow()) { new(ary+sz) T(gp::forward(value)...); sz++; return true; } return false; } constexpr gp::optional pop_back() { if(sz == 0) return gp::nullopt; sz--; gp::optional ret_val = gp::move(ary[sz]); ary[sz]->~T(); return gp::move(ret_val); } constexpr pointer_iterator begin() { return associated_iterator(&ary[0]); } constexpr pointer_iterator end() { return associated_iterator(&ary[sz]); } constexpr const_pointer_iterator cbegin() const { return associated_const_iterator(&ary[0]); } constexpr const_pointer_iterator cend() const { return associated_const_iterator(&ary[sz]); } constexpr pointer_iterator rbegin() { return associated_riterator(&ary[sz-1]); } constexpr pointer_iterator rend() { return associated_riterator(ary-1); } constexpr const_pointer_iterator crbegin() const { return associated_const_riterator(&ary[sz-1]); } constexpr const_pointer_iterator crend() const { return associated_const_riterator(ary-1); } constexpr bool operator==(const vector& oth) const { for(size_t idx = 0; idx as_buffer() { return gp::buffer{(T*)ary, (T*)ary+sz}; } }; }