diff --git a/source/blender/blenlib/BLI_array.hh b/source/blender/blenlib/BLI_array.hh index 18f9aad1000..c7a9c49c972 100644 --- a/source/blender/blenlib/BLI_array.hh +++ b/source/blender/blenlib/BLI_array.hh @@ -89,17 +89,19 @@ class Array { /** * Create a new array that contains copies of all values. */ - Array(Span values, Allocator allocator = {}) : allocator_(allocator) + template> * = nullptr> + Array(Span values, Allocator allocator = {}) : allocator_(allocator) { size_ = values.size(); data_ = this->get_buffer_for_size(values.size()); - uninitialized_copy_n(values.data(), size_, data_); + uninitialized_convert_n(values.data(), size_, data_); } /** * Create a new array that contains copies of all values. */ - Array(const std::initializer_list &values) : Array(Span(values)) + template> * = nullptr> + Array(const std::initializer_list &values) : Array(Span(values)) { } @@ -219,6 +221,18 @@ class Array { return MutableSpan(data_, size_); } + template> * = nullptr> + operator Span() const + { + return Span(data_, size_); + } + + template> * = nullptr> + operator MutableSpan() + { + return MutableSpan(data_, size_); + } + Span as_span() const { return *this; diff --git a/source/blender/blenlib/BLI_memory_utils.hh b/source/blender/blenlib/BLI_memory_utils.hh index 16d6227a551..133615f0f31 100644 --- a/source/blender/blenlib/BLI_memory_utils.hh +++ b/source/blender/blenlib/BLI_memory_utils.hh @@ -26,6 +26,7 @@ #include #include +#include #include "BLI_utildefines.h" @@ -134,6 +135,32 @@ template void uninitialized_copy_n(const T *src, uint n, T *dst) } } +/** + * Convert n values from type `From` to type `To`. + * + * Exception Safety: Strong. + * + * Before: + * src: initialized + * dst: uninitialized + * After: + * src: initialized + * dst: initialized + */ +template void uninitialized_convert_n(const From *src, uint n, To *dst) +{ + uint current = 0; + try { + for (; current < n; current++) { + new ((void *)(dst + current)) To((To)src[current]); + } + } + catch (...) { + destruct_n(dst, current); + throw; + } +} + /** * Move n values from src to dst. * @@ -364,6 +391,15 @@ template class TypedBuffer { class NoInitialization { }; +/** + * Helper variable that checks if a pointer type can be converted into another pointer type without + * issues. Possible issues are casting away const and casting a pointer to a child class. + * Adding const or casting to a parent class is fine. + */ +template +inline constexpr bool is_convertible_pointer_v = + std::is_convertible_v &&std::is_pointer_v &&std::is_pointer_v; + } // namespace blender #endif /* __BLI_MEMORY_UTILS_HH__ */ diff --git a/source/blender/blenlib/BLI_span.hh b/source/blender/blenlib/BLI_span.hh index 9688c93ec14..5c841787520 100644 --- a/source/blender/blenlib/BLI_span.hh +++ b/source/blender/blenlib/BLI_span.hh @@ -100,6 +100,11 @@ template class Span { { } + template> * = nullptr> + Span(const U *start, uint size) : start_((const T *)start), size_(size) + { + } + /** * Reference an initializer_list. Note that the data in the initializer_list is only valid until * the expression containing it is fully computed. @@ -128,8 +133,8 @@ template class Span { * Span -> Span * Span -> Span */ - template> * = nullptr> - Span(Span array) : Span((T *)array.data(), array.size()) + template> * = nullptr> + Span(Span array) : start_((T *)array.data()), size_(array.size()) { } diff --git a/source/blender/blenlib/BLI_vector.hh b/source/blender/blenlib/BLI_vector.hh index f608290f5df..df885588d9b 100644 --- a/source/blender/blenlib/BLI_vector.hh +++ b/source/blender/blenlib/BLI_vector.hh @@ -141,9 +141,19 @@ class Vector { */ Vector(uint size, const T &value) : Vector() { + this->resize(size, value); + } + + /** + * Create a vector from an array ref. The values in the vector are copy constructed. + */ + template> * = nullptr> + Vector(Span values, Allocator allocator = {}) : Vector(allocator) + { + const uint size = values.size(); this->reserve(size); this->increase_size_by_unchecked(size); - blender::uninitialized_fill_n(begin_, size, value); + uninitialized_convert_n(values.data(), size, begin_); } /** @@ -152,24 +162,21 @@ class Vector { * This allows you to write code like: * Vector vec = {3, 4, 5}; */ - Vector(const std::initializer_list &values) : Vector(Span(values)) + template> * = nullptr> + Vector(const std::initializer_list &values) : Vector(Span(values)) + { + } + + template> * = nullptr> + Vector(const std::array &values) : Vector(Span(values)) { } /** - * Create a vector from an array ref. The values in the vector are copy constructed. - */ - Vector(Span values, Allocator allocator = {}) : Vector(allocator) - { - const uint size = values.size(); - this->reserve(size); - this->increase_size_by_unchecked(size); - blender::uninitialized_copy_n(values.data(), size, begin_); - } - - /** - * Create a vector from any container. It must be possible to use the container in a range-for - * loop. + * Create a vector from any container. It must be possible to use the container in a + * range-for loop. */ template static Vector FromContainer(const ContainerT &container) { @@ -313,6 +320,18 @@ class Vector { return MutableSpan(begin_, this->size()); } + template> * = nullptr> + operator Span() const + { + return Span(begin_, this->size()); + } + + template> * = nullptr> + operator MutableSpan() + { + return MutableSpan(begin_, this->size()); + } + Span as_span() const { return *this; diff --git a/tests/gtests/blenlib/BLI_memory_utils_test.cc b/tests/gtests/blenlib/BLI_memory_utils_test.cc index eb896c0cca6..b99db5c5eca 100644 --- a/tests/gtests/blenlib/BLI_memory_utils_test.cc +++ b/tests/gtests/blenlib/BLI_memory_utils_test.cc @@ -1,5 +1,6 @@ /* Apache License, Version 2.0 */ +#include "BLI_float3.hh" #include "BLI_memory_utils.hh" #include "BLI_strict_flags.h" #include "testing/testing.h" @@ -119,4 +120,40 @@ TEST(memory_utils, UninitializedFillN_StrongExceptionSafety) EXPECT_EQ(MyValue::alive, 0); } +class TestBaseClass { + virtual void mymethod(){}; +}; + +class TestChildClass : public TestBaseClass { + void mymethod() override + { + } +}; + +static_assert(is_convertible_pointer_v); +static_assert(is_convertible_pointer_v); +static_assert(is_convertible_pointer_v); +static_assert(is_convertible_pointer_v); +static_assert(!is_convertible_pointer_v); +static_assert(!is_convertible_pointer_v); +static_assert(!is_convertible_pointer_v); +static_assert(is_convertible_pointer_v); +static_assert(!is_convertible_pointer_v); +static_assert(is_convertible_pointer_v); +static_assert(!is_convertible_pointer_v); +static_assert(is_convertible_pointer_v); +static_assert(!is_convertible_pointer_v); +static_assert(!is_convertible_pointer_v); +static_assert(!is_convertible_pointer_v); +static_assert(!is_convertible_pointer_v); +static_assert(!is_convertible_pointer_v); +static_assert(is_convertible_pointer_v); +static_assert(is_convertible_pointer_v); +static_assert(!is_convertible_pointer_v); +static_assert(!is_convertible_pointer_v); +static_assert(!is_convertible_pointer_v); +static_assert(is_convertible_pointer_v); +static_assert(is_convertible_pointer_v); +static_assert(is_convertible_pointer_v); + } // namespace blender diff --git a/tests/gtests/blenlib/BLI_vector_test.cc b/tests/gtests/blenlib/BLI_vector_test.cc index 1f6bd1ded5b..92fb12fb4e5 100644 --- a/tests/gtests/blenlib/BLI_vector_test.cc +++ b/tests/gtests/blenlib/BLI_vector_test.cc @@ -59,6 +59,18 @@ TEST(vector, InitializerListConstructor) EXPECT_EQ(vec[3], 6); } +TEST(vector, ConvertingConstructor) +{ + std::array values = {5.4f, 7.3f, -8.1f, 5.0f, 0.0f}; + Vector vec = values; + EXPECT_EQ(vec.size(), 5u); + EXPECT_EQ(vec[0], 5); + EXPECT_EQ(vec[1], 7); + EXPECT_EQ(vec[2], -8); + EXPECT_EQ(vec[3], 5); + EXPECT_EQ(vec[4], 0); +} + struct TestListValue { TestListValue *next, *prev; int value; diff --git a/tests/gtests/functions/FN_attributes_ref_test.cc b/tests/gtests/functions/FN_attributes_ref_test.cc index 1c05bb930db..fee8c5dc058 100644 --- a/tests/gtests/functions/FN_attributes_ref_test.cc +++ b/tests/gtests/functions/FN_attributes_ref_test.cc @@ -65,7 +65,8 @@ TEST(mutable_attributes_ref, ComplexTest) Array sizes(amount); Array names(amount); - Array buffers = {positions.data(), ids.data(), sizes.data(), names.data()}; + Array buffers = { + (void *)positions.data(), (void *)ids.data(), (void *)sizes.data(), (void *)names.data()}; MutableAttributesRef attributes{info, buffers, IndexRange(1, 3)}; EXPECT_EQ(attributes.size(), 3); EXPECT_EQ(attributes.info().size(), 4);