diff options
Diffstat (limited to 'source/blender/blenlib/BLI_memory_utils.hh')
-rw-r--r-- | source/blender/blenlib/BLI_memory_utils.hh | 189 |
1 files changed, 160 insertions, 29 deletions
diff --git a/source/blender/blenlib/BLI_memory_utils.hh b/source/blender/blenlib/BLI_memory_utils.hh index d9acf08a43f..2f7b27240f3 100644 --- a/source/blender/blenlib/BLI_memory_utils.hh +++ b/source/blender/blenlib/BLI_memory_utils.hh @@ -21,71 +21,191 @@ * \ingroup bli */ -#include <algorithm> #include <memory> #include "BLI_utildefines.h" namespace BLI { -using std::copy; -using std::copy_n; -using std::uninitialized_copy; -using std::uninitialized_copy_n; -using std::uninitialized_fill; -using std::uninitialized_fill_n; +/** + * Call the default constructor on n consecutive elements. For trivially constructible types, this + * does nothing. + * + * Before: + * ptr: uninitialized + * After: + * ptr: initialized + */ +template<typename T> void default_construct_n(T *ptr, uint n) +{ + /* This is not strictly necessary, because the loop below will be optimized away anyway. It is + * nice to make behavior this explicitely, though. */ + if (std::is_trivially_constructible<T>::value) { + return; + } -template<typename T> void construct_default(T *ptr) + for (uint i = 0; i < n; i++) { + new (ptr + i) T; + } +} + +/** + * Call the destructor on n consecutive values. For trivially destructible types, this does + * nothing. + * + * Before: + * ptr: initialized + * After: + * ptr: uninitialized + */ +template<typename T> void destruct_n(T *ptr, uint n) { - new (ptr) T(); + /* This is not strictly necessary, because the loop below will be optimized away anyway. It is + * nice to make behavior this explicitely, though. */ + if (std::is_trivially_destructible<T>::value) { + return; + } + + for (uint i = 0; i < n; i++) { + ptr[i].~T(); + } } -template<typename T> void destruct(T *ptr) +/** + * Copy n values from src to dst. + * + * Before: + * src: initialized + * dst: initialized + * After: + * src: initialized + * dst: initialized + */ +template<typename T> void initialized_copy_n(const T *src, uint n, T *dst) { - ptr->~T(); + for (uint i = 0; i < n; i++) { + dst[i] = src[i]; + } } -template<typename T> void destruct_n(T *ptr, uint n) +/** + * Copy n values from src to dst. + * + * Before: + * src: initialized + * dst: uninitialized + * After: + * src: initialized + * dst: initialized + */ +template<typename T> void uninitialized_copy_n(const T *src, uint n, T *dst) { for (uint i = 0; i < n; i++) { - ptr[i].~T(); + new (dst + i) T(src[i]); } } -template<typename T> void uninitialized_move_n(T *src, uint n, T *dst) +/** + * Move n values from src to dst. + * + * Before: + * src: initialized + * dst: initialized + * After: + * src: initialized, moved-from + * dst: initialized + */ +template<typename T> void initialized_move_n(T *src, uint n, T *dst) { - std::uninitialized_copy_n(std::make_move_iterator(src), n, dst); + for (uint i = 0; i < n; i++) { + dst[i] = std::move(src[i]); + } } -template<typename T> void move_n(T *src, uint n, T *dst) +/** + * Move n values from src to dst. + * + * Before: + * src: initialized + * dst: uninitialized + * After: + * src: initialized, moved-from + * dst: initialized + */ +template<typename T> void uninitialized_move_n(T *src, uint n, T *dst) { - std::copy_n(std::make_move_iterator(src), n, dst); + for (uint i = 0; i < n; i++) { + new (dst + i) T(std::move(src[i])); + } } -template<typename T> void uninitialized_relocate(T *src, T *dst) +/** + * Relocate n values from src to dst. Relocation is a move followed by destruction of the src + * value. + * + * Before: + * src: initialized + * dst: initialized + * After: + * src: uninitialized + * dst: initialized + */ +template<typename T> void initialized_relocate_n(T *src, uint n, T *dst) { - new (dst) T(std::move(*src)); - destruct(src); + initialized_move_n(src, n, dst); + destruct_n(src, n); } +/** + * Relocate n values from src to dst. Relocation is a move followed by destruction of the src + * value. + * + * Before: + * src: initialized + * dst: uinitialized + * After: + * src: uninitialized + * dst: initialized + */ template<typename T> void uninitialized_relocate_n(T *src, uint n, T *dst) { uninitialized_move_n(src, n, dst); destruct_n(src, n); } -template<typename T> void relocate(T *src, T *dst) +/** + * Copy the value to n consecutive elements. + * + * Before: + * dst: initialized + * After: + * dst: initialized + */ +template<typename T> void initialized_fill_n(T *dst, uint n, const T &value) { - *dst = std::move(*src); - destruct(src); + for (uint i = 0; i < n; i++) { + dst[i] = value; + } } -template<typename T> void relocate_n(T *src, uint n, T *dst) +/** + * Copy the value to n consecutive elements. + * + * Before: + * dst: uninitialized + * After: + * dst: initialized + */ +template<typename T> void uninitialized_fill_n(T *dst, uint n, const T &value) { - move_n(src, n, dst); - destruct_n(src, n); + for (uint i = 0; i < n; i++) { + new (dst + i) T(value); + } } +/** + * The same as std::unique_ptr. This can be removed when we start using C++14. + */ template<typename T, typename... Args> std::unique_ptr<T> make_unique(Args &&... args) { return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); @@ -98,13 +218,24 @@ template<typename T> struct DestructValueAtAddress { } }; +/** + * A destruct_ptr is like unique_ptr, but it will only call the destructor and will not free the + * memory. This is useful when using custom allocators. + */ template<typename T> using destruct_ptr = std::unique_ptr<T, DestructValueAtAddress<T>>; -template<uint Size, uint Alignment> class alignas(Alignment) AlignedBuffer { +/** + * An `AlignedBuffer` is simply a byte array with the given size and alignment. The buffer will + * not be initialized by the default constructor. + * + * This can be used to reserve memory for C++ objects whose lifetime is different from the + * lifetime of the object they are embedded in. It's used by containers with small buffer + * optimization and hash table implementations. + */ +template<size_t Size, size_t Alignment> class alignas(Alignment) AlignedBuffer { private: /* Don't create an empty array. This causes problems with some compilers. */ - static constexpr uint ActualSize = (Size > 0) ? Size : 1; - char m_buffer[ActualSize]; + char m_buffer[(Size > 0) ? Size : 1]; public: void *ptr() |