blob: 471650219c0f5f3a5f70a816c6a4d50069aeef26 [file] [log] [blame]
/*
* Copyright 2023 Rive
*/
#pragma once
#include <cassert>
#include <memory>
#include <vector>
namespace rive
{
// Fast block allocator for trivially-destructible types.
class TrivialBlockAllocator
{
public:
TrivialBlockAllocator(size_t initialBlockSize) : m_initialBlockSize(initialBlockSize)
{
m_blocks.push_back(std::unique_ptr<char[]>(new char[m_initialBlockSize]));
reset();
}
void reset()
{
m_fibMinus2 = 0;
m_fibMinus1 = 1;
m_blocks.resize(1);
m_currentBlockSize = m_initialBlockSize;
m_currentBlockUsage = 0;
}
void* alloc(size_t allocSize)
{
// Align all allocations on 8-byte boundaries.
allocSize = (allocSize + 7) & ~size_t(7);
// Ensure there is room for this allocation in our newest block, pushing a new one if
// needed.
if (m_currentBlockUsage + allocSize > m_currentBlockSize)
{
// Grow with a fibonacci function.
size_t fib = m_fibMinus2 + m_fibMinus1;
m_fibMinus2 = m_fibMinus1;
m_fibMinus1 = fib;
size_t blockSize = std::max(fib * m_initialBlockSize, allocSize);
m_blocks.push_back(std::unique_ptr<char[]>(new char[blockSize]));
m_currentBlockSize = blockSize;
m_currentBlockUsage = 0;
}
char* ret = &m_blocks.back()[m_currentBlockUsage];
m_currentBlockUsage += allocSize;
// Since we round up all allocation sizes, allocations should be 8-byte aligned.
assert((reinterpret_cast<uintptr_t>(ret) & 7) == 0);
assert(ret + allocSize <= m_blocks.back().get() + m_currentBlockSize);
return ret;
}
template <typename T, typename... Args> T* make(Args&&... args)
{
// We don't call destructors on objects that get allocated here. We just free the blocks
// at the end. So objects must be trivially destructible.
static_assert(std::is_trivially_destructible<T>::value);
return new (alloc(sizeof(T))) T(std::forward<Args>(args)...);
}
private:
const size_t m_initialBlockSize;
// Grow block sizes using a fibonacci function.
size_t m_fibMinus2;
size_t m_fibMinus1;
std::vector<std::unique_ptr<char[]>> m_blocks;
size_t m_currentBlockSize;
size_t m_currentBlockUsage;
};
} // namespace rive