Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Lucke <jacques@blender.org>2020-07-08 23:27:25 +0300
committerJacques Lucke <jacques@blender.org>2020-07-08 23:27:25 +0300
commit403384998a6bb5f428e15ced5503206b45032b25 (patch)
tree23e09b183faa196603aafb1572ed0f13b3964333 /source/blender/blenlib
parent4b85ed819dc0746f6fc46eab1019aab4c4fcf9c9 (diff)
BLI: improve constructors and conversions to span
This allows us to avoid many calls to `as_span()` methods. I will remove those in the next commit. Furthermore, constructors of Vector and Array can convert from one type to another now. I tested these changes on Linux with gcc and on Windows.
Diffstat (limited to 'source/blender/blenlib')
-rw-r--r--source/blender/blenlib/BLI_array.hh20
-rw-r--r--source/blender/blenlib/BLI_memory_utils.hh36
-rw-r--r--source/blender/blenlib/BLI_span.hh9
-rw-r--r--source/blender/blenlib/BLI_vector.hh43
4 files changed, 91 insertions, 17 deletions
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<T> values, Allocator allocator = {}) : allocator_(allocator)
+ template<typename U, typename std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr>
+ Array(Span<U> 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<U, T>(values.data(), size_, data_);
}
/**
* Create a new array that contains copies of all values.
*/
- Array(const std::initializer_list<T> &values) : Array(Span<T>(values))
+ template<typename U, typename std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr>
+ Array(const std::initializer_list<U> &values) : Array(Span<U>(values))
{
}
@@ -219,6 +221,18 @@ class Array {
return MutableSpan<T>(data_, size_);
}
+ template<typename U, typename std::enable_if_t<is_convertible_pointer_v<T, U>> * = nullptr>
+ operator Span<U>() const
+ {
+ return Span<U>(data_, size_);
+ }
+
+ template<typename U, typename std::enable_if_t<is_convertible_pointer_v<T, U>> * = nullptr>
+ operator MutableSpan<U>()
+ {
+ return MutableSpan<U>(data_, size_);
+ }
+
Span<T> 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 <memory>
#include <new>
+#include <type_traits>
#include "BLI_utildefines.h"
@@ -135,6 +136,32 @@ template<typename T> 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<typename From, typename To> 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.
*
* Exception Safety: Basic.
@@ -364,6 +391,15 @@ template<typename T, size_t Size = 1> 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<typename From, typename To>
+inline constexpr bool is_convertible_pointer_v =
+ std::is_convertible_v<From, To> &&std::is_pointer_v<From> &&std::is_pointer_v<To>;
+
} // 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<typename T> class Span {
{
}
+ template<typename U, typename std::enable_if_t<is_convertible_pointer_v<U, T>> * = 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<typename T> class Span {
* Span<T *> -> Span<const T *>
* Span<Derived *> -> Span<Base *>
*/
- template<typename U, typename std::enable_if_t<std::is_convertible_v<U *, T>> * = nullptr>
- Span(Span<U *> array) : Span((T *)array.data(), array.size())
+ template<typename U, typename std::enable_if_t<is_convertible_pointer_v<U, T>> * = nullptr>
+ Span(Span<U> 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<typename U, typename std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr>
+ Vector(Span<U> 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<U, T>(values.data(), size, begin_);
}
/**
@@ -152,24 +162,21 @@ class Vector {
* This allows you to write code like:
* Vector<int> vec = {3, 4, 5};
*/
- Vector(const std::initializer_list<T> &values) : Vector(Span<T>(values))
+ template<typename U, typename std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr>
+ Vector(const std::initializer_list<U> &values) : Vector(Span<U>(values))
{
}
- /**
- * Create a vector from an array ref. The values in the vector are copy constructed.
- */
- Vector(Span<T> values, Allocator allocator = {}) : Vector(allocator)
+ template<typename U,
+ size_t N,
+ typename std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr>
+ Vector(const std::array<U, N> &values) : Vector(Span(values))
{
- 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<typename ContainerT> static Vector FromContainer(const ContainerT &container)
{
@@ -313,6 +320,18 @@ class Vector {
return MutableSpan<T>(begin_, this->size());
}
+ template<typename U, typename std::enable_if_t<is_convertible_pointer_v<T, U>> * = nullptr>
+ operator Span<U>() const
+ {
+ return Span<U>(begin_, this->size());
+ }
+
+ template<typename U, typename std::enable_if_t<is_convertible_pointer_v<T, U>> * = nullptr>
+ operator MutableSpan<U>()
+ {
+ return MutableSpan<U>(begin_, this->size());
+ }
+
Span<T> as_span() const
{
return *this;