diff --git a/loader/include/Geode/c++stl/gnustl.hpp b/loader/include/Geode/c++stl/gnustl.hpp index 37a2a291..19d4b50a 100644 --- a/loader/include/Geode/c++stl/gnustl.hpp +++ b/loader/include/Geode/c++stl/gnustl.hpp @@ -280,11 +280,22 @@ namespace gd { m_reserveEnd = nullptr; } + size_t nextCapacity(size_t x) { + // minimum 16, powers of 2, don't use builtins + if (x < 16) return 16; + size_t out = 16; + while (out < x) { + out *= 2; + } + return out; + } + vector(std::vector<T> const& input) : vector() { if (input.size()) { - m_start = this->allocator().allocate(input.size()); + auto capacity = nextCapacity(input.size()); + m_start = this->allocator().allocate(capacity); m_finish = m_start + input.size(); - m_reserveEnd = m_start + input.size(); + m_reserveEnd = m_start + capacity; std::uninitialized_default_construct(m_start, m_finish); std::copy(input.begin(), input.end(), m_start); @@ -293,9 +304,10 @@ namespace gd { vector(gd::vector<T> const& input) : vector() { if (input.size()) { - m_start = this->allocator().allocate(input.size()); + auto capacity = nextCapacity(input.size()); + m_start = this->allocator().allocate(capacity); m_finish = m_start + input.size(); - m_reserveEnd = m_start + input.size(); + m_reserveEnd = m_start + capacity; std::uninitialized_default_construct(m_start, m_finish); std::copy(input.begin(), input.end(), m_start); @@ -316,10 +328,12 @@ namespace gd { this->clear(); if (input.size()) { - m_start = this->allocator().allocate(input.size()); + auto capacity = nextCapacity(input.size()); + m_start = this->allocator().allocate(capacity); m_finish = m_start + input.size(); - m_reserveEnd = m_start + input.size(); + m_reserveEnd = m_start + capacity; + std::uninitialized_default_construct(m_start, m_finish); std::copy(input.begin(), input.end(), m_start); } @@ -338,11 +352,71 @@ namespace gd { return *this; } + void grow() { + if (m_finish == m_reserveEnd) { + auto newSize = this->capacity() * 2; + auto newStart = this->allocator().allocate(newSize); + auto newFinish = newStart + this->size(); + + std::uninitialized_default_construct(newStart, newFinish); + std::copy(m_start, m_finish, newStart); + + std::destroy(m_start, m_finish); + this->allocator().deallocate(m_start, this->capacity()); + + m_start = newStart; + m_finish = newFinish; + m_reserveEnd = newStart + newSize; + } + } + + void shrink() { + if (m_finish < m_reserveEnd / 2 && this->capacity() > 16) { + auto newSize = this->capacity() / 2; + auto newStart = this->allocator().allocate(newSize); + auto newFinish = newStart + this->size(); + + std::uninitialized_default_construct(newStart, newFinish); + std::copy(m_start, m_finish, newStart); + + std::destroy(m_start, m_finish); + this->allocator().deallocate(m_start, this->capacity()); + + m_start = newStart; + m_finish = newFinish; + m_reserveEnd = newStart + newSize; + } + } + + void push_back(T const& input) { + this->grow(); + + new (m_finish) T(input); + ++m_finish; + } + + void push_back(T&& input) { + this->grow(); + + new (m_finish) T(std::move(input)); + ++m_finish; + } + + void pop_back() { + if (m_finish != m_start) { + --m_finish; + m_finish->~T(); + } + + this->shrink(); + } + vector(std::initializer_list<T> const& input) : vector() { if (input.size()) { - m_start = this->allocator().allocate(input.size()); + auto capacity = nextCapacity(input.size()); + m_start = this->allocator().allocate(capacity); m_finish = m_start + input.size(); - m_reserveEnd = m_start + input.size(); + m_reserveEnd = m_start + capacity; std::uninitialized_default_construct(m_start, m_finish); std::copy(input.begin(), input.end(), m_start); @@ -353,7 +427,7 @@ namespace gd { if (m_start) { std::destroy(m_start, m_finish); - this->allocator().deallocate(m_start, this->size()); + this->allocator().deallocate(m_start, this->capacity()); } m_start = nullptr;