diff --git a/include/region.h b/include/region.h index a75d06e..0943fa3 100644 --- a/include/region.h +++ b/include/region.h @@ -49,6 +49,10 @@ public: size_t getMaxSize() const; std::byte* getAddress() const; + // Helper functions for allocators + bool maybeGrow(size_t minSize); + void maybeShrink(size_t targetSize); + private: std::byte* m_data; size_t m_committedSize; diff --git a/src/arena.cpp b/src/arena.cpp index 005911c..6d9996d 100644 --- a/src/arena.cpp +++ b/src/arena.cpp @@ -77,16 +77,8 @@ size_t Arena::getMaxSize() const std::byte* Arena::alloc(size_t size) { size_t neededSize = m_usedSize + size; - if (neededSize > m_region.getSize()) - { - // Increase the size exponentially when we run out - size_t newSize = std::bit_ceil(neededSize) << 1; - if (newSize < m_minSize) { - newSize = m_minSize; - } - if (!m_region.resize(newSize)) { - return nullptr; - } + if (!m_region.maybeGrow(std::max(neededSize, m_minSize))) { + return nullptr; } std::byte* ret = m_region.getAddress() + m_usedSize; @@ -128,13 +120,7 @@ void Arena::reset() m_watermark[kWatermarkLen - 1] = m_usedSize; size_t targetSize = std::bit_ceil(highWatermark) << 1; - if (targetSize < m_minSize) { - targetSize = m_minSize; - } - size_t thresholdSize = targetSize << 1; // The threshold for shrinking is greater than the target to implement hysteresis - if (m_region.getSize() > thresholdSize) { - m_region.resize(targetSize); - } + m_region.maybeShrink(std::max(m_minSize, targetSize)); m_usedSize = 0; } diff --git a/src/region.cpp b/src/region.cpp index 8e7f9dc..6d55ab3 100644 --- a/src/region.cpp +++ b/src/region.cpp @@ -154,4 +154,32 @@ std::byte* Region::getAddress() const return m_data; } -}; +bool Region::maybeGrow(size_t minSize) +{ + if (minSize < m_committedSize) { + // Already big enough + return true; + } + + if (minSize > m_maxSize) { + // We can't grow this big + return false; + } + + // We need to grow. + // Increase the size exponentially, capped to m_maxSize + size_t newSize = std::bit_ceil(minSize) << 1; + newSize = std::min(m_maxSize, newSize); + + return resize(newSize); +} + +void Region::maybeShrink(size_t targetSize) +{ + size_t thresholdSize = targetSize << 1; // The threshold for shrinking is greater than the target to implement hysteresis + if (getSize() > thresholdSize) { + resize(targetSize); + } +} + +} // namespace mimir