diff options
author | Jacques Lucke <jacques@blender.org> | 2020-08-24 18:24:13 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2020-08-24 18:24:13 +0300 |
commit | 8e18a9984505514a229d66b38fff31d930367968 (patch) | |
tree | 97bb3e6f766e997df712bf081e05e027648e2c28 /source/blender/blenlib/BLI_array.hh | |
parent | 530350935472970dccc211b0e728e2db4fd1d8ef (diff) |
BLI: improve exception safety of Set and Map
For more information see rB2aff45146f1464ba8899368ad004522cb6a1a98c.
Diffstat (limited to 'source/blender/blenlib/BLI_array.hh')
-rw-r--r-- | source/blender/blenlib/BLI_array.hh | 43 |
1 files changed, 37 insertions, 6 deletions
diff --git a/source/blender/blenlib/BLI_array.hh b/source/blender/blenlib/BLI_array.hh index d6b7ab03203..dddf4f64ff5 100644 --- a/source/blender/blenlib/BLI_array.hh +++ b/source/blender/blenlib/BLI_array.hh @@ -168,7 +168,7 @@ class Array { Array(Array &&other) noexcept(std::is_nothrow_move_constructible_v<T>) : Array(NoExceptConstructor(), other.allocator_) { - if (other.uses_inline_buffer()) { + if (other.data_ == other.inline_buffer_) { uninitialized_relocate_n(other.data_, other.size_, data_); } else { @@ -183,9 +183,7 @@ class Array { ~Array() { destruct_n(data_, size_); - if (!this->uses_inline_buffer()) { - allocator_.deallocate(static_cast<void *>(data_)); - } + this->deallocate_if_not_inline(data_); } Array &operator=(const Array &other) @@ -365,6 +363,37 @@ class Array { return InlineBufferCapacity; } + /** + * Destruct values and create a new array of the given size. The values in the new array are + * default constructed. + */ + void reinitialize(const int64_t new_size) + { + BLI_assert(new_size >= 0); + int64_t old_size = size_; + + destruct_n(data_, size_); + size_ = 0; + + if (new_size <= old_size) { + default_construct_n(data_, new_size); + } + else { + T *new_data = this->get_buffer_for_size(new_size); + try { + default_construct_n(new_data, new_size); + } + catch (...) { + this->deallocate_if_not_inline(new_data); + throw; + } + this->deallocate_if_not_inline(data_); + data_ = new_data; + } + + size_ = new_size; + } + private: T *get_buffer_for_size(int64_t size) { @@ -382,9 +411,11 @@ class Array { allocator_.allocate(static_cast<size_t>(size) * sizeof(T), alignof(T), AT)); } - bool uses_inline_buffer() const + void deallocate_if_not_inline(T *ptr) { - return data_ == inline_buffer_; + if (ptr != inline_buffer_) { + allocator_.deallocate(ptr); + } } }; |