diff --git a/include/xo/arena/DArenaVector.hpp b/include/xo/arena/DArenaVector.hpp index ea1557f..a5834ea 100644 --- a/include/xo/arena/DArenaVector.hpp +++ b/include/xo/arena/DArenaVector.hpp @@ -53,18 +53,23 @@ namespace xo { /** create empty vector using @p cfg to configure backing store **/ static DArenaVector map(const ArenaConfig & cfg); + /** true iff vector is emtpy **/ bool empty() const { return size_ == 0; } size_type size() const { return size_; } size_type max_size() const { return capacity(); } size_type capacity() const { return store_.reserved() / sizeof(T); } - T & operator[](size_t i) { return *(this->_address_of(i)); } - const T & operator[](size_t i) const { return *(this->_address_of(i)); } + /** get reference to element at zero-based index @p i. Do not check bounds **/ + T & operator[](size_t i) noexcept { return *(this->_address_of(i)); } + const T & operator[](size_t i) const noexcept { return *(this->_address_of(i)); } + /** get reference to element at zero-based index @p i. Do check bounds **/ T & at(size_type i) { _check_valid_index(i); return *(this->_address_of(i)); } const T & at(size_type i) const { _check_valid_index(i); return *(this->_address_of(i)); } + /** get to at first element of vector. Same as @p end if vector is empty **/ iterator begin() noexcept { return this->_address_of(0); } + /** get iterator to end of vector - "one past the last element" **/ iterator end() noexcept { return this->_address_of(size_); } const_iterator cbegin() const noexcept { return this->_address_of(0); } const_iterator begin() const noexcept { return this->cbegin(); } @@ -74,11 +79,20 @@ namespace xo { constexpr T * data() { return reinterpret_cast(store_.lo_); } constexpr const T * data() const { return reinterpret_cast(store_.lo_); } + /** reserve space, if possible, for at least @p z elements. + * Always limited by ArenaConfig.size_ + **/ void reserve(size_type z); void resize(size_type z); void shrink_to_fit(); + /** reset vector to empty state **/ void clear(); + T & insert(size_type pos, T && x); + T & insert(size_type pos, const T & x); + + void erase(size_type pos); + void push_back(T && x); void push_back(const T & x); @@ -211,19 +225,84 @@ namespace xo { throw std::out_of_range("DArenaVector index out of bounds"); } + template + T & + DArenaVector::insert(size_type pos, T && x) { + { + size_type new_z = size_ + 1; + size_type req_z = new_z * sizeof(T); + + store_.expand(req_z); + } + + // move elements [i .. z-1] right by one position. + // must proceed in reverse order! + for (size_type ip1 = size_; ip1 > pos; --ip1) { + (*this)[ip1] = std::move((*this)[ip1-1]); + } + + T * addr = this->_address_of(pos); + + new (addr) T{std::move(x)}; + + this->size_ = size_ + 1; + + return *addr; + } + + template + T & + DArenaVector::insert(size_type pos, const T & x) { + { + size_type new_z = size_ + 1; + size_type req_z = new_z * sizeof(T); + + store_.expand(req_z); + } + + // move elements [i .. z-1] right by one position. + // must proceed in reverse order! + for (size_type ip1 = size_; ip1 > pos; --ip1) { + (*this)[ip1] = std::move((*this)[ip1-1]); + } + + T * addr = this->_address_of(pos); + + new (addr) T{x}; + + this->size_ = size_ + 1; + + return *addr; + } + + template + void + DArenaVector::erase(size_type pos) { + // move elements [pos+1 .. z-1] left by one position. + + if (pos >= size_) [[unlikely]] + return; + + for (size_type i = pos; i+1 < size_; ++i) { + (*this)[i] = std::move((*this)[i+1]); + } + + --(this->size_); + } + template void DArenaVector::push_back(T && x) { size_type z = size_ + 1; size_type req_z = z * sizeof(T); - store_.expand(req_z); + this->store_.expand(req_z); T * addr = this->_address_of(size_); new (addr) T{std::move(x)}; - size_ = z; + this->size_ = z; } template