| /* | |
| * 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 |