|
|
- #pragma once
-
- #include <gp/buffer.hpp>
- #include <gp/allocator/allocator.hpp>
-
- #include <initializer_list>
-
- namespace gp{
- template<typename T>
- class vector final {
- T* ary = nullptr;
- size_t sz = 0;
- size_t cap = 0;
- 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)
- {
- 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<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};
- }
- };
- }
|