Repository: google/filament
File: filament/src/details/BufferAllocator.cpp (C++)

Code before:
constexpr static bool isPowerOfTwo(uint32_t n) {
    return (n > 0) && ((n & (n - 1)) == 0);
}
#endif

} // anonymous namespace

BufferAllocator::BufferAllocator(allocation_size_t totalSize, allocation_size_t slotSize)
    : mTotalSize(totalSize),
      mSlotSize(slotSize) {
    assert_invariant(mSlotSize > 0);
    assert_invariant(isPowerOfTwo(mSlotSize));

    reset(mTotalSize);
}

void BufferAllocator::reset(allocation_size_t newTotalSize) {
    assert_invariant(newTotalSize % mSlotSize == 0);

    mTotalSize = newTotalSize;
    mFreeList.clear();

    // Resize mNodes to the number of slots
    size_t slotCount = mTotalSize / mSlotSize;
    mNodes.clear();
    mNodes.reserve(slotCount);
    mNodes.resize(slotCount);

    // Initialize the single free block covering the entire buffer
    InternalSlotNode* node = &mNodes[0];
    node->slot.offset = 0;
    node->slot.slotSize = mTotalSize;
    node->slot.isAllocated = false;
    node->slot.gpuUseCount = 0;
    node->freeListIterator = mFreeList.emplace(mTotalSize, node);

    // Set the tail tag
    mNodes[slotCount - 1] = *node;
}

std::pair<BufferAllocator::AllocationId, BufferAllocator::allocation_size_t>
    BufferAllocator::allocate(allocation_size_t size) noexcept {
    if (size == 0) {
        return { UNALLOCATED, 0 };
    }

    const allocation_size_t alignedSize = alignUp(size);
    auto bestFitIter = mFreeList.lower_bound(alignedSize);

    if (bestFitIter == mFreeList.end()) {
        return { REALLOCATION_REQUIRED, 0 };

Review comment (refactor):
nit: You could remove this `reserve` call as `resize` will handle it internally.

Code after:
constexpr static bool isPowerOfTwo(uint32_t n) {
    return (n > 0) && ((n & (n - 1)) == 0);
}
#endif

} // anonymous namespace

BufferAllocator::BufferAllocator(allocation_size_t totalSize, allocation_size_t slotSize)
    : mTotalSize(totalSize),
      mSlotSize(slotSize) {
    assert_invariant(mSlotSize > 0);
    assert_invariant(isPowerOfTwo(mSlotSize));

    reset(mTotalSize);
}

void BufferAllocator::reset(allocation_size_t newTotalSize) {
    assert_invariant(newTotalSize % mSlotSize == 0);

    mTotalSize = newTotalSize;
    mFreeList.clear();

    // Resize mNodes to the number of slots
    const size_t slotCount = mTotalSize / mSlotSize;
    mNodes.clear();
    mNodes.reserve(slotCount);
    mNodes.resize(slotCount);

    // Initialize the single free block covering the entire buffer
    InternalSlotNode* node = &mNodes[0];
    node->slot.offset = 0;
    node->slot.slotSize = mTotalSize;
    node->slot.isAllocated = false;
    node->slot.gpuUseCount = 0;
    node->freeListIterator = mFreeList.emplace(mTotalSize, node);

    // Set the tail tag
    mNodes[slotCount - 1] = *node;
}

std::pair<BufferAllocator::AllocationId, BufferAllocator::allocation_size_t>
    BufferAllocator::allocate(allocation_size_t size) noexcept {
    if (size == 0) {
        return { UNALLOCATED, 0 };
    }

    const allocation_size_t alignedSize = alignUp(size);
    auto bestFitIter = mFreeList.lower_bound(alignedSize);

    if (bestFitIter == mFreeList.end()) {
        return { REALLOCATION_REQUIRED, 0 };