From 850a539c903605586d0f32bd14fc3dcf63d5a89e Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 7 May 2020 14:21:26 +0200 Subject: BLI: improve linear allocator documentation --- source/blender/blenlib/BLI_array_ref.hh | 10 ++ source/blender/blenlib/BLI_linear_allocator.hh | 125 +++++++++++++++++-------- 2 files changed, 96 insertions(+), 39 deletions(-) (limited to 'source/blender/blenlib') diff --git a/source/blender/blenlib/BLI_array_ref.hh b/source/blender/blenlib/BLI_array_ref.hh index dd9421d289c..c0484493bda 100644 --- a/source/blender/blenlib/BLI_array_ref.hh +++ b/source/blender/blenlib/BLI_array_ref.hh @@ -508,6 +508,16 @@ template class MutableArrayRef { BLI_assert(m_size > 0); return m_start[m_size - 1]; } + + /** + * Get a new array ref to the same underlying memory buffer. No conversions are done. + */ + template MutableArrayRef cast() const + { + BLI_assert((m_size * sizeof(T)) % sizeof(NewT) == 0); + uint new_size = m_size * sizeof(T) / sizeof(NewT); + return MutableArrayRef(reinterpret_cast(m_start), new_size); + } }; /** diff --git a/source/blender/blenlib/BLI_linear_allocator.hh b/source/blender/blenlib/BLI_linear_allocator.hh index cebf878580c..ffa81b3ac6b 100644 --- a/source/blender/blenlib/BLI_linear_allocator.hh +++ b/source/blender/blenlib/BLI_linear_allocator.hh @@ -60,28 +60,13 @@ template class LinearAllocator : NonCopya } } - void provide_buffer(void *buffer, uint size) - { - m_unused_borrowed_buffers.append(ArrayRef((char *)buffer, size)); - } - - template - void provide_buffer(AlignedBuffer &aligned_buffer) - { - this->provide_buffer(aligned_buffer.ptr(), Size); - } - - template T *allocate() - { - return (T *)this->allocate(sizeof(T), alignof(T)); - } - - template MutableArrayRef allocate_array(uint length) - { - return MutableArrayRef((T *)this->allocate(sizeof(T) * length), length); - } - - void *allocate(uint size, uint alignment = 4) + /** + * Get a pointer to a memory buffer with the given size an alignment. The memory buffer will be + * freed when this LinearAllocator is destructed. + * + * The alignment has to be a power of 2. + */ + void *allocate(uint size, uint alignment) { BLI_assert(alignment >= 1); BLI_assert(is_power_of_2_i(alignment)); @@ -104,6 +89,55 @@ template class LinearAllocator : NonCopya } }; + /** + * Allocate a memory buffer that can hold an instance of T. + * + * This method only allocates memory and does not construct the instance. + */ + template T *allocate() + { + return (T *)this->allocate(sizeof(T), alignof(T)); + } + + /** + * Allocate a memory buffer that can hold T array with the given size. + * + * This method only allocates memory and does not construct the instance. + */ + template MutableArrayRef allocate_array(uint size) + { + return MutableArrayRef((T *)this->allocate(sizeof(T) * size, alignof(T)), size); + } + + /** + * Construct an instance of T in memory provided by this allocator. + * + * Arguments passed to this method will be forwarded to the constructor of T. + * + * You must not call `delete` on the returned pointer. Instead, the destructor has to be called + * explicitely. + */ + template T *construct(Args &&... args) + { + void *buffer = this->allocate(sizeof(T), alignof(T)); + T *value = new (buffer) T(std::forward(args)...); + return value; + } + + /** + * Copy the given array into a memory buffer provided by this allocator. + */ + template MutableArrayRef construct_array_copy(ArrayRef src) + { + MutableArrayRef dst = this->allocate_array(src.size()); + uninitialized_copy_n(src.begin(), src.size(), dst.begin()); + return dst; + } + + /** + * Copy the given string into a memory buffer provided by this allocator. The returned string is + * always null terminated. + */ StringRefNull copy_string(StringRef str) { uint alloc_size = str.size() + 1; @@ -112,37 +146,50 @@ template class LinearAllocator : NonCopya return StringRefNull((const char *)buffer); } - template T *construct(Args &&... args) + MutableArrayRef allocate_elements_and_pointer_array(uint element_amount, + uint element_size, + uint element_alignment) { - void *buffer = this->allocate(sizeof(T), alignof(T)); - T *value = new (buffer) T(std::forward(args)...); - return value; + void *pointer_buffer = this->allocate(element_amount * sizeof(void *), alignof(void *)); + void *elements_buffer = this->allocate(element_amount * element_size, element_alignment); + + MutableArrayRef pointers((void **)pointer_buffer, element_amount); + void *next_element_buffer = elements_buffer; + for (uint i : IndexRange(element_amount)) { + pointers[i] = next_element_buffer; + next_element_buffer = POINTER_OFFSET(next_element_buffer, element_size); + } + + return pointers; } template ArrayRef construct_elements_and_pointer_array(uint n, Args &&... args) { - void *pointer_buffer = this->allocate(n * sizeof(T *), alignof(T *)); - void *element_buffer = this->allocate(n * sizeof(T), alignof(T)); - - MutableArrayRef pointers((T **)pointer_buffer, n); - T *elements = (T *)element_buffer; + MutableArrayRef void_pointers = this->allocate_elements_and_pointer_array( + n, sizeof(T), alignof(T)); + MutableArrayRef pointers = void_pointers.cast(); for (uint i : IndexRange(n)) { - pointers[i] = elements + i; - } - for (uint i : IndexRange(n)) { - new (elements + i) T(std::forward(args)...); + new (pointers[i]) T(std::forward(args)...); } return pointers; } - template MutableArrayRef construct_array_copy(ArrayRef source) + /** + * Tell the allocator to use up the given memory buffer, before allocating new memory from the + * system. + */ + void provide_buffer(void *buffer, uint size) { - T *buffer = (T *)this->allocate(source.byte_size(), alignof(T)); - uninitialized_copy_n(source.begin(), source.size(), buffer); - return MutableArrayRef(buffer, source.size()); + m_unused_borrowed_buffers.append(ArrayRef((char *)buffer, size)); + } + + template + void provide_buffer(AlignedBuffer &aligned_buffer) + { + this->provide_buffer(aligned_buffer.ptr(), Size); } private: -- cgit v1.2.3