BLI: support transferring ownership of buffers between linear allocators

This can be useful when e.g. each thread has its own `LinearAllocator`,
but in the end they are combined into one.
This commit is contained in:
Jacques Lucke
2023-05-22 09:25:09 +02:00
parent 92512f224d
commit 2b49d4eeea
2 changed files with 38 additions and 0 deletions

View File

@@ -211,6 +211,25 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
this->provide_buffer(aligned_buffer.ptr(), Size);
}
/**
* This allocator takes ownership of the buffers owned by `other`. Therefor, when `other` is
* destructed, memory allocated using it is not freed.
*
* Note that the caller is responsible for making sure that buffers passed into #provide_buffer
* of `other` live at least as long as this allocator.
*/
void transfer_ownership_from(LinearAllocator<> &other)
{
owned_buffers_.extend(other.owned_buffers_);
#ifdef BLI_DEBUG_LINEAR_ALLOCATOR_SIZE
user_requested_size_ += other.user_requested_size_;
owned_allocation_size_ += other.owned_allocation_size_;
#endif
other.owned_buffers_.clear();
std::destroy_at(&other);
new (&other) LinearAllocator<>();
}
private:
void allocate_new_buffer(int64_t min_allocation_size, int64_t min_alignment)
{

View File

@@ -149,4 +149,23 @@ TEST(linear_allocator, ConstructArray)
}
}
TEST(linear_allocator, TransferOwnership)
{
LinearAllocator<> main_allocator;
MutableSpan<int> values;
/* Allocate a large buffer that is likely to be given back to the system when freed. This test
* essentially only fails by crashing with a segfault. */
const int size = 1'000'000;
const int value = 42;
const int index = 500'000;
{
LinearAllocator<> nested_allocator;
values = nested_allocator.allocate_array<int>(size);
values[index] = value;
main_allocator.transfer_ownership_from(nested_allocator);
}
EXPECT_EQ(values[index], value);
}
} // namespace blender::tests