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:
Diffstat (limited to 'source/blender/blenlib')
-rw-r--r--source/blender/blenlib/BLI_array.hh4
-rw-r--r--source/blender/blenlib/BLI_hash.h58
-rw-r--r--source/blender/blenlib/BLI_index_range.hh45
-rw-r--r--source/blender/blenlib/BLI_inplace_priority_queue.hh304
-rw-r--r--source/blender/blenlib/BLI_kdopbvh.h1
-rw-r--r--source/blender/blenlib/BLI_memory_utils.hh19
-rw-r--r--source/blender/blenlib/BLI_span.hh129
-rw-r--r--source/blender/blenlib/BLI_string_ref.hh126
-rw-r--r--source/blender/blenlib/BLI_threads.h1
-rw-r--r--source/blender/blenlib/BLI_vector.hh4
-rw-r--r--source/blender/blenlib/CMakeLists.txt2
-rw-r--r--source/blender/blenlib/intern/BLI_kdopbvh.c19
-rw-r--r--source/blender/blenlib/intern/math_rotation.c17
-rw-r--r--source/blender/blenlib/intern/mesh_boolean.cc7
-rw-r--r--source/blender/blenlib/intern/path_util.c99
-rw-r--r--source/blender/blenlib/tests/BLI_index_range_test.cc7
-rw-r--r--source/blender/blenlib/tests/BLI_inplace_priority_queue_test.cc113
-rw-r--r--source/blender/blenlib/tests/BLI_math_rotation_test.cc21
-rw-r--r--source/blender/blenlib/tests/BLI_memory_utils_test.cc11
-rw-r--r--source/blender/blenlib/tests/BLI_span_test.cc15
-rw-r--r--source/blender/blenlib/tests/BLI_string_ref_test.cc8
21 files changed, 792 insertions, 218 deletions
diff --git a/source/blender/blenlib/BLI_array.hh b/source/blender/blenlib/BLI_array.hh
index 8a7dcb7ffaa..284d62fb876 100644
--- a/source/blender/blenlib/BLI_array.hh
+++ b/source/blender/blenlib/BLI_array.hh
@@ -220,13 +220,13 @@ class Array {
return MutableSpan<T>(data_, size_);
}
- template<typename U, typename std::enable_if_t<is_convertible_pointer_v<T, U>> * = nullptr>
+ template<typename U, typename std::enable_if_t<is_span_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>
+ template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<T, U>> * = nullptr>
operator MutableSpan<U>()
{
return MutableSpan<U>(data_, size_);
diff --git a/source/blender/blenlib/BLI_hash.h b/source/blender/blenlib/BLI_hash.h
index c2be416ef5f..d687e805323 100644
--- a/source/blender/blenlib/BLI_hash.h
+++ b/source/blender/blenlib/BLI_hash.h
@@ -26,35 +26,59 @@
extern "C" {
#endif
-BLI_INLINE unsigned int BLI_hash_int_2d(unsigned int kx, unsigned int ky)
-{
+/**
+ * Jenkins Lookup3 Hash Functions.
+ * Source: http://burtleburtle.net/bob/c/lookup3.c
+ */
+
#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
+#define final(a, b, c) \
+ { \
+ c ^= b; \
+ c -= rot(b, 14); \
+ a ^= c; \
+ a -= rot(c, 11); \
+ b ^= a; \
+ b -= rot(a, 25); \
+ c ^= b; \
+ c -= rot(b, 16); \
+ a ^= c; \
+ a -= rot(c, 4); \
+ b ^= a; \
+ b -= rot(a, 14); \
+ c ^= b; \
+ c -= rot(b, 24); \
+ } \
+ ((void)0)
+
+BLI_INLINE unsigned int BLI_hash_int_3d(unsigned int kx, unsigned int ky, unsigned int kz)
+{
+ unsigned int a, b, c;
+ a = b = c = 0xdeadbeef + (3 << 2) + 13;
+
+ c += kz;
+ b += ky;
+ a += kx;
+ final(a, b, c);
+
+ return c;
+}
+BLI_INLINE unsigned int BLI_hash_int_2d(unsigned int kx, unsigned int ky)
+{
unsigned int a, b, c;
a = b = c = 0xdeadbeef + (2 << 2) + 13;
a += kx;
b += ky;
- c ^= b;
- c -= rot(b, 14);
- a ^= c;
- a -= rot(c, 11);
- b ^= a;
- b -= rot(a, 25);
- c ^= b;
- c -= rot(b, 16);
- a ^= c;
- a -= rot(c, 4);
- b ^= a;
- b -= rot(a, 14);
- c ^= b;
- c -= rot(b, 24);
+ final(a, b, c);
return c;
+}
+#undef final
#undef rot
-}
BLI_INLINE unsigned int BLI_hash_string(const char *str)
{
diff --git a/source/blender/blenlib/BLI_index_range.hh b/source/blender/blenlib/BLI_index_range.hh
index 2b060c986cd..4121542c887 100644
--- a/source/blender/blenlib/BLI_index_range.hh
+++ b/source/blender/blenlib/BLI_index_range.hh
@@ -73,21 +73,22 @@ class IndexRange {
int64_t size_ = 0;
public:
- IndexRange() = default;
+ constexpr IndexRange() = default;
- explicit IndexRange(int64_t size) : start_(0), size_(size)
+ constexpr explicit IndexRange(int64_t size) : start_(0), size_(size)
{
BLI_assert(size >= 0);
}
- IndexRange(int64_t start, int64_t size) : start_(start), size_(size)
+ constexpr IndexRange(int64_t start, int64_t size) : start_(start), size_(size)
{
BLI_assert(start >= 0);
BLI_assert(size >= 0);
}
template<typename T>
- IndexRange(const tbb::blocked_range<T> &range) : start_(range.begin()), size_(range.size())
+ constexpr IndexRange(const tbb::blocked_range<T> &range)
+ : start_(range.begin()), size_(range.size())
{
}
@@ -96,33 +97,33 @@ class IndexRange {
int64_t current_;
public:
- Iterator(int64_t current) : current_(current)
+ constexpr Iterator(int64_t current) : current_(current)
{
}
- Iterator &operator++()
+ constexpr Iterator &operator++()
{
current_++;
return *this;
}
- bool operator!=(const Iterator &iterator) const
+ constexpr bool operator!=(const Iterator &iterator) const
{
return current_ != iterator.current_;
}
- int64_t operator*() const
+ constexpr int64_t operator*() const
{
return current_;
}
};
- Iterator begin() const
+ constexpr Iterator begin() const
{
return Iterator(start_);
}
- Iterator end() const
+ constexpr Iterator end() const
{
return Iterator(start_ + size_);
}
@@ -130,7 +131,7 @@ class IndexRange {
/**
* Access an element in the range.
*/
- int64_t operator[](int64_t index) const
+ constexpr int64_t operator[](int64_t index) const
{
BLI_assert(index >= 0);
BLI_assert(index < this->size());
@@ -140,7 +141,7 @@ class IndexRange {
/**
* Two ranges compare equal when they contain the same numbers.
*/
- friend bool operator==(IndexRange a, IndexRange b)
+ constexpr friend bool operator==(IndexRange a, IndexRange b)
{
return (a.size_ == b.size_) && (a.start_ == b.start_ || a.size_ == 0);
}
@@ -148,7 +149,7 @@ class IndexRange {
/**
* Get the amount of numbers in the range.
*/
- int64_t size() const
+ constexpr int64_t size() const
{
return size_;
}
@@ -156,7 +157,7 @@ class IndexRange {
/**
* Create a new range starting at the end of the current one.
*/
- IndexRange after(int64_t n) const
+ constexpr IndexRange after(int64_t n) const
{
BLI_assert(n >= 0);
return IndexRange(start_ + size_, n);
@@ -165,7 +166,7 @@ class IndexRange {
/**
* Create a new range that ends at the start of the current one.
*/
- IndexRange before(int64_t n) const
+ constexpr IndexRange before(int64_t n) const
{
BLI_assert(n >= 0);
return IndexRange(start_ - n, n);
@@ -175,7 +176,7 @@ class IndexRange {
* Get the first element in the range.
* Asserts when the range is empty.
*/
- int64_t first() const
+ constexpr int64_t first() const
{
BLI_assert(this->size() > 0);
return start_;
@@ -185,7 +186,7 @@ class IndexRange {
* Get the last element in the range.
* Asserts when the range is empty.
*/
- int64_t last() const
+ constexpr int64_t last() const
{
BLI_assert(this->size() > 0);
return start_ + size_ - 1;
@@ -194,7 +195,7 @@ class IndexRange {
/**
* Get the element one after the end. The returned value is undefined when the range is empty.
*/
- int64_t one_after_last() const
+ constexpr int64_t one_after_last() const
{
return start_ + size_;
}
@@ -202,7 +203,7 @@ class IndexRange {
/**
* Get the first element in the range. The returned value is undefined when the range is empty.
*/
- int64_t start() const
+ constexpr int64_t start() const
{
return start_;
}
@@ -210,7 +211,7 @@ class IndexRange {
/**
* Returns true when the range contains a certain number, otherwise false.
*/
- bool contains(int64_t value) const
+ constexpr bool contains(int64_t value) const
{
return value >= start_ && value < start_ + size_;
}
@@ -218,7 +219,7 @@ class IndexRange {
/**
* Returns a new range, that contains a sub-interval of the current one.
*/
- IndexRange slice(int64_t start, int64_t size) const
+ constexpr IndexRange slice(int64_t start, int64_t size) const
{
BLI_assert(start >= 0);
BLI_assert(size >= 0);
@@ -226,7 +227,7 @@ class IndexRange {
BLI_assert(new_start + size <= start_ + size_ || size == 0);
return IndexRange(new_start, size);
}
- IndexRange slice(IndexRange range) const
+ constexpr IndexRange slice(IndexRange range) const
{
return this->slice(range.start(), range.size());
}
diff --git a/source/blender/blenlib/BLI_inplace_priority_queue.hh b/source/blender/blenlib/BLI_inplace_priority_queue.hh
new file mode 100644
index 00000000000..e76cb8504a3
--- /dev/null
+++ b/source/blender/blenlib/BLI_inplace_priority_queue.hh
@@ -0,0 +1,304 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#include "BLI_array.hh"
+#include "BLI_dot_export.hh"
+
+namespace blender {
+
+/**
+ * An InplacePriorityQueue adds priority queue functionality to an existing array. The underlying
+ * array is not changed. Instead, the priority queue maintains indices into the original array.
+ *
+ * The priority queue provides efficient access to the element in order of their priorities.
+ *
+ * When a priority changes, the priority queue has to be informed using one of the following
+ * methods: #priority_decreased, #priority_increased or #priority_changed.
+ */
+template<
+ /* Type of the elements in the underlying array. */
+ typename T,
+ /* Binary function that takes two `const T &` inputs and returns true, when the first input has
+ greater priority than the second. */
+ typename FirstHasHigherPriority = std::greater<T>>
+class InplacePriorityQueue {
+ private:
+ /* Underlying array the priority queue is built upon. This is a span instead of a mutable span,
+ * because this data structure never changes the values itself. */
+ Span<T> data_;
+ /* Maps indices from the heap (binary tree in array format) to indices of the underlying/original
+ * array. */
+ Array<int64_t> heap_to_orig_;
+ /* This is the inversion of the above mapping. */
+ Array<int64_t> orig_to_heap_;
+ /* Number of elements that are currently in the priority queue. */
+ int64_t heap_size_ = 0;
+ /* Function that can be changed to customize how the priority of two elements is compared. */
+ FirstHasHigherPriority first_has_higher_priority_fn_;
+
+ public:
+ /**
+ * Construct the priority queue on top of the data in the given span.
+ */
+ InplacePriorityQueue(Span<T> data)
+ : data_(data), heap_to_orig_(data_.size()), orig_to_heap_(data_.size())
+ {
+ for (const int64_t i : IndexRange(data_.size())) {
+ heap_to_orig_[i] = i;
+ orig_to_heap_[i] = i;
+ }
+
+ this->rebuild();
+ }
+
+ /**
+ * Rebuilds the priority queue from the array that has been passed to the constructor.
+ */
+ void rebuild()
+ {
+ const int final_heap_size = data_.size();
+ if (final_heap_size > 1) {
+ for (int64_t i = this->get_parent(final_heap_size - 1); i >= 0; i--) {
+ this->heapify(i, final_heap_size);
+ }
+ }
+ heap_size_ = final_heap_size;
+ }
+
+ /**
+ * Returns the number of elements in the priority queue.
+ * This is less or equal than the size of the underlying array.
+ */
+ int64_t size() const
+ {
+ return heap_size_;
+ }
+
+ /**
+ * Returns true, when the priority queue contains no elements. If this returns true, #peek and
+ * #pop must not be used.
+ */
+ bool is_empty() const
+ {
+ return heap_size_ == 0;
+ }
+
+ /**
+ * Get the element with the highest priority in the priority queue.
+ * The returned reference is const, because the priority queue has read-only access to the
+ * underlying data. If you need a mutable reference, use #peek_index instead.
+ */
+ const T &peek() const
+ {
+ return data_[this->peek_index()];
+ }
+
+ /**
+ * Get the element with the highest priority in the priority queue and remove it.
+ * The returned reference is const, because the priority queue has read-only access to the
+ * underlying data. If you need a mutable reference, use #pop_index instead.
+ */
+ const T &pop()
+ {
+ return data_[this->pop_index()];
+ }
+
+ /**
+ * Get the index of the element with the highest priority in the priority queue.
+ */
+ int64_t peek_index() const
+ {
+ BLI_assert(!this->is_empty());
+ return heap_to_orig_[0];
+ }
+
+ /**
+ * Get the index of the element with the highest priority in the priority queue and remove it.
+ */
+ int64_t pop_index()
+ {
+ BLI_assert(!this->is_empty());
+ const int64_t top_index_orig = heap_to_orig_[0];
+ heap_size_--;
+ if (heap_size_ > 1) {
+ this->swap_indices(0, heap_size_);
+ this->heapify(0, heap_size_);
+ }
+ return top_index_orig;
+ }
+
+ /**
+ * Inform the priority queue that the priority of the element at the given index has been
+ * decreased.
+ */
+ void priority_decreased(const int64_t index)
+ {
+ const int64_t heap_index = orig_to_heap_[index];
+ if (heap_index >= heap_size_) {
+ /* This element is not in the queue currently. */
+ return;
+ }
+ this->heapify(heap_index, heap_size_);
+ }
+
+ /**
+ * Inform the priority queue that the priority of the element at the given index has been
+ * increased.
+ */
+ void priority_increased(const int64_t index)
+ {
+ int64_t current = orig_to_heap_[index];
+ if (current >= heap_size_) {
+ /* This element is not in the queue currently. */
+ return;
+ }
+ while (true) {
+ if (current == 0) {
+ break;
+ }
+ const int64_t parent = this->get_parent(current);
+ if (this->first_has_higher_priority(parent, current)) {
+ break;
+ }
+ this->swap_indices(current, parent);
+ current = parent;
+ }
+ }
+
+ /**
+ * Inform the priority queue that the priority of the element at the given index has been
+ * changed.
+ */
+ void priority_changed(const int64_t index)
+ {
+ this->priority_increased(index);
+ this->priority_decreased(index);
+ }
+
+ /**
+ * Returns the indices of all elements that are in the priority queue.
+ * There are no guarantees about the order of indices.
+ */
+ Span<int64_t> active_indices() const
+ {
+ return heap_to_orig_.as_span().take_front(heap_size_);
+ }
+
+ /**
+ * Returns the indices of all elements that are not in the priority queue.
+ * The indices are in reverse order of their removal from the queue.
+ * I.e. the index that has been removed last, comes first.
+ */
+ Span<int64_t> inactive_indices() const
+ {
+ return heap_to_orig_.as_span().drop_front(heap_size_);
+ }
+
+ /**
+ * Returns the concatenation of the active and inactive indices.
+ */
+ Span<int64_t> all_indices() const
+ {
+ return heap_to_orig_;
+ }
+
+ /**
+ * Return the heap used by the priority queue as dot graph string.
+ * This exists for debugging purposes.
+ */
+ std::string to_dot() const
+ {
+ return this->partial_to_dot(heap_size_);
+ }
+
+ private:
+ bool first_has_higher_priority(const int64_t a, const int64_t b)
+ {
+ const T &value_a = data_[heap_to_orig_[a]];
+ const T &value_b = data_[heap_to_orig_[b]];
+ return first_has_higher_priority_fn_(value_a, value_b);
+ }
+
+ void swap_indices(const int64_t a, const int64_t b)
+ {
+ std::swap(heap_to_orig_[a], heap_to_orig_[b]);
+ orig_to_heap_[heap_to_orig_[a]] = a;
+ orig_to_heap_[heap_to_orig_[b]] = b;
+ }
+
+ void heapify(const int64_t parent, const int64_t heap_size)
+ {
+ int64_t max_index = parent;
+ const int left = this->get_left(parent);
+ const int right = this->get_right(parent);
+ if (left < heap_size && this->first_has_higher_priority(left, max_index)) {
+ max_index = left;
+ }
+ if (right < heap_size && this->first_has_higher_priority(right, max_index)) {
+ max_index = right;
+ }
+ if (max_index != parent) {
+ this->swap_indices(parent, max_index);
+ this->heapify(max_index, heap_size);
+ }
+ if (left < heap_size) {
+ BLI_assert(!this->first_has_higher_priority(left, parent));
+ }
+ if (right < heap_size) {
+ BLI_assert(!this->first_has_higher_priority(right, parent));
+ }
+ }
+
+ int64_t get_parent(const int64_t child) const
+ {
+ BLI_assert(child > 0);
+ return (child - 1) / 2;
+ }
+
+ int64_t get_left(const int64_t parent) const
+ {
+ return parent * 2 + 1;
+ }
+
+ int64_t get_right(const int64_t parent) const
+ {
+ return parent * 2 + 2;
+ }
+
+ std::string partial_to_dot(const int size) const
+ {
+ dot::DirectedGraph digraph;
+ Array<dot::Node *> dot_nodes(size);
+ for (const int i : IndexRange(size)) {
+ std::stringstream ss;
+ ss << data_[heap_to_orig_[i]];
+ const std::string name = ss.str();
+ dot::Node &node = digraph.new_node(name);
+ node.set_shape(dot::Attr_shape::Rectangle);
+ node.attributes.set("ordering", "out");
+ dot_nodes[i] = &node;
+ if (i > 0) {
+ const int64_t parent = this->get_parent(i);
+ digraph.new_edge(*dot_nodes[parent], node);
+ }
+ }
+ return digraph.to_dot_string();
+ }
+};
+
+} // namespace blender
diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h
index c34b71a60f9..5e0ea4f2a99 100644
--- a/source/blender/blenlib/BLI_kdopbvh.h
+++ b/source/blender/blenlib/BLI_kdopbvh.h
@@ -178,6 +178,7 @@ int *BLI_bvhtree_intersect_plane(BVHTree *tree, float plane[4], uint *r_intersec
int BLI_bvhtree_get_len(const BVHTree *tree);
int BLI_bvhtree_get_tree_type(const BVHTree *tree);
float BLI_bvhtree_get_epsilon(const BVHTree *tree);
+void BLI_bvhtree_get_bounding_box(BVHTree *tree, float r_bb_min[3], float r_bb_max[3]);
/* find nearest node to the given coordinates
* (if nearest is given it will only search nodes where
diff --git a/source/blender/blenlib/BLI_memory_utils.hh b/source/blender/blenlib/BLI_memory_utils.hh
index 49076bb1aae..b3b6855089e 100644
--- a/source/blender/blenlib/BLI_memory_utils.hh
+++ b/source/blender/blenlib/BLI_memory_utils.hh
@@ -428,6 +428,25 @@ inline constexpr bool is_convertible_pointer_v =
std::is_convertible_v<From, To> &&std::is_pointer_v<From> &&std::is_pointer_v<To>;
/**
+ * Helper variable that checks if a Span<From> can be converted to Span<To> safely, whereby From
+ * and To are pointers. Adding const and casting to a void pointer is allowed.
+ * Casting up and down a class hierarchy generally is not allowed, because this might change the
+ * pointer under some circumstances.
+ */
+template<typename From, typename To>
+inline constexpr bool is_span_convertible_pointer_v =
+ /* Make sure we are working with pointers. */
+ std::is_pointer_v<From> &&std::is_pointer_v<To> &&
+ (/* No casting is necessary when both types are the same. */
+ std::is_same_v<From, To> ||
+ /* Allow adding const to the underlying type. */
+ std::is_same_v<const std::remove_pointer_t<From>, std::remove_pointer_t<To>> ||
+ /* Allow casting non-const pointers to void pointers. */
+ (!std::is_const_v<std::remove_pointer_t<From>> && std::is_same_v<To, void *>) ||
+ /* Allow casting any pointer to const void pointers. */
+ std::is_same_v<To, const void *>);
+
+/**
* Inline buffers for small-object-optimization should be disable by default. Otherwise we might
* get large unexpected allocations on the stack.
*/
diff --git a/source/blender/blenlib/BLI_span.hh b/source/blender/blenlib/BLI_span.hh
index 5b4d2769f57..8011b2f9abc 100644
--- a/source/blender/blenlib/BLI_span.hh
+++ b/source/blender/blenlib/BLI_span.hh
@@ -93,15 +93,15 @@ template<typename T> class Span {
/**
* Create a reference to an empty array.
*/
- Span() = default;
+ constexpr Span() = default;
- Span(const T *start, int64_t size) : data_(start), size_(size)
+ constexpr Span(const T *start, int64_t size) : data_(start), size_(size)
{
BLI_assert(size >= 0);
}
- template<typename U, typename std::enable_if_t<is_convertible_pointer_v<U, T>> * = nullptr>
- Span(const U *start, int64_t size) : data_(static_cast<const T *>(start)), size_(size)
+ template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<U, T>> * = nullptr>
+ constexpr Span(const U *start, int64_t size) : data_(static_cast<const T *>(start)), size_(size)
{
BLI_assert(size >= 0);
}
@@ -117,16 +117,17 @@ template<typename T> class Span {
* Span<int> span = {1, 2, 3, 4};
* call_function_with_array(span);
*/
- Span(const std::initializer_list<T> &list)
+ constexpr Span(const std::initializer_list<T> &list)
: Span(list.begin(), static_cast<int64_t>(list.size()))
{
}
- Span(const std::vector<T> &vector) : Span(vector.data(), static_cast<int64_t>(vector.size()))
+ constexpr Span(const std::vector<T> &vector)
+ : Span(vector.data(), static_cast<int64_t>(vector.size()))
{
}
- template<std::size_t N> Span(const std::array<T, N> &array) : Span(array.data(), N)
+ template<std::size_t N> constexpr Span(const std::array<T, N> &array) : Span(array.data(), N)
{
}
@@ -134,8 +135,9 @@ template<typename T> class Span {
* Support implicit conversions like the ones below:
* Span<T *> -> Span<const T *>
*/
- template<typename U, typename std::enable_if_t<is_convertible_pointer_v<U, T>> * = nullptr>
- Span(Span<U> array) : data_(static_cast<const T *>(array.data())), size_(array.size())
+
+ template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<U, T>> * = nullptr>
+ constexpr Span(Span<U> array) : data_(static_cast<const T *>(array.data())), size_(array.size())
{
}
@@ -143,7 +145,7 @@ template<typename T> class Span {
* Returns a contiguous part of the array. This invokes undefined behavior when the slice does
* not stay within the bounds of the array.
*/
- Span slice(int64_t start, int64_t size) const
+ constexpr Span slice(int64_t start, int64_t size) const
{
BLI_assert(start >= 0);
BLI_assert(size >= 0);
@@ -151,7 +153,7 @@ template<typename T> class Span {
return Span(data_ + start, size);
}
- Span slice(IndexRange range) const
+ constexpr Span slice(IndexRange range) const
{
return this->slice(range.start(), range.size());
}
@@ -160,7 +162,7 @@ template<typename T> class Span {
* Returns a new Span with n elements removed from the beginning. This invokes undefined
* behavior when the array is too small.
*/
- Span drop_front(int64_t n) const
+ constexpr Span drop_front(int64_t n) const
{
BLI_assert(n >= 0);
BLI_assert(n <= this->size());
@@ -171,7 +173,7 @@ template<typename T> class Span {
* Returns a new Span with n elements removed from the beginning. This invokes undefined
* behavior when the array is too small.
*/
- Span drop_back(int64_t n) const
+ constexpr Span drop_back(int64_t n) const
{
BLI_assert(n >= 0);
BLI_assert(n <= this->size());
@@ -182,7 +184,7 @@ template<typename T> class Span {
* Returns a new Span that only contains the first n elements. This invokes undefined
* behavior when the array is too small.
*/
- Span take_front(int64_t n) const
+ constexpr Span take_front(int64_t n) const
{
BLI_assert(n >= 0);
BLI_assert(n <= this->size());
@@ -193,7 +195,7 @@ template<typename T> class Span {
* Returns a new Span that only contains the last n elements. This invokes undefined
* behavior when the array is too small.
*/
- Span take_back(int64_t n) const
+ constexpr Span take_back(int64_t n) const
{
BLI_assert(n >= 0);
BLI_assert(n <= this->size());
@@ -204,25 +206,25 @@ template<typename T> class Span {
* Returns the pointer to the beginning of the referenced array. This may be nullptr when the
* size is zero.
*/
- const T *data() const
+ constexpr const T *data() const
{
return data_;
}
- const T *begin() const
+ constexpr const T *begin() const
{
return data_;
}
- const T *end() const
+ constexpr const T *end() const
{
return data_ + size_;
}
- std::reverse_iterator<const T *> rbegin() const
+ constexpr std::reverse_iterator<const T *> rbegin() const
{
return std::reverse_iterator<const T *>(this->end());
}
- std::reverse_iterator<const T *> rend() const
+ constexpr std::reverse_iterator<const T *> rend() const
{
return std::reverse_iterator<const T *>(this->begin());
}
@@ -231,7 +233,7 @@ template<typename T> class Span {
* Access an element in the array. This invokes undefined behavior when the index is out of
* bounds.
*/
- const T &operator[](int64_t index) const
+ constexpr const T &operator[](int64_t index) const
{
BLI_assert(index >= 0);
BLI_assert(index < size_);
@@ -241,7 +243,7 @@ template<typename T> class Span {
/**
* Returns the number of elements in the referenced array.
*/
- int64_t size() const
+ constexpr int64_t size() const
{
return size_;
}
@@ -249,7 +251,7 @@ template<typename T> class Span {
/**
* Returns true if the size is zero.
*/
- bool is_empty() const
+ constexpr bool is_empty() const
{
return size_ == 0;
}
@@ -257,7 +259,7 @@ template<typename T> class Span {
/**
* Returns the number of bytes referenced by this Span.
*/
- int64_t size_in_bytes() const
+ constexpr int64_t size_in_bytes() const
{
return sizeof(T) * size_;
}
@@ -266,7 +268,7 @@ template<typename T> class Span {
* Does a linear search to see of the value is in the array.
* Returns true if it is, otherwise false.
*/
- bool contains(const T &value) const
+ constexpr bool contains(const T &value) const
{
for (const T &element : *this) {
if (element == value) {
@@ -280,7 +282,7 @@ template<typename T> class Span {
* Does a constant time check to see if the pointer points to a value in the referenced array.
* Return true if it is, otherwise false.
*/
- bool contains_ptr(const T *ptr) const
+ constexpr bool contains_ptr(const T *ptr) const
{
return (this->begin() <= ptr) && (ptr < this->end());
}
@@ -289,7 +291,7 @@ template<typename T> class Span {
* Does a linear search to count how often the value is in the array.
* Returns the number of occurrences.
*/
- int64_t count(const T &value) const
+ constexpr int64_t count(const T &value) const
{
int64_t counter = 0;
for (const T &element : *this) {
@@ -304,7 +306,7 @@ template<typename T> class Span {
* Return a reference to the first element in the array. This invokes undefined behavior when the
* array is empty.
*/
- const T &first() const
+ constexpr const T &first() const
{
BLI_assert(size_ > 0);
return data_[0];
@@ -314,7 +316,7 @@ template<typename T> class Span {
* Returns a reference to the last element in the array. This invokes undefined behavior when the
* array is empty.
*/
- const T &last() const
+ constexpr const T &last() const
{
BLI_assert(size_ > 0);
return data_[size_ - 1];
@@ -324,7 +326,7 @@ template<typename T> class Span {
* Returns the element at the given index. If the index is out of range, return the fallback
* value.
*/
- T get(int64_t index, const T &fallback) const
+ constexpr T get(int64_t index, const T &fallback) const
{
if (index < size_ && index >= 0) {
return data_[index];
@@ -336,7 +338,7 @@ template<typename T> class Span {
* Check if the array contains duplicates. Does a linear search for every element. So the total
* running time is O(n^2). Only use this for small arrays.
*/
- bool has_duplicates__linear_search() const
+ constexpr bool has_duplicates__linear_search() const
{
/* The size should really be smaller than that. If it is not, the calling code should be
* changed. */
@@ -358,7 +360,7 @@ template<typename T> class Span {
* called on small arrays, because it has a running time of O(n*m) where n and m are the sizes of
* the arrays.
*/
- bool intersects__linear_search(Span other) const
+ constexpr bool intersects__linear_search(Span other) const
{
/* The size should really be smaller than that. If it is not, the calling code should be
* changed. */
@@ -377,7 +379,7 @@ template<typename T> class Span {
* Returns the index of the first occurrence of the given value. This invokes undefined behavior
* when the value is not in the array.
*/
- int64_t first_index(const T &search_value) const
+ constexpr int64_t first_index(const T &search_value) const
{
const int64_t index = this->first_index_try(search_value);
BLI_assert(index >= 0);
@@ -387,7 +389,7 @@ template<typename T> class Span {
/**
* Returns the index of the first occurrence of the given value or -1 if it does not exist.
*/
- int64_t first_index_try(const T &search_value) const
+ constexpr int64_t first_index_try(const T &search_value) const
{
for (int64_t i = 0; i < size_; i++) {
if (data_[i] == search_value) {
@@ -401,7 +403,7 @@ template<typename T> class Span {
* Utility to make it more convenient to iterate over all indices that can be used with this
* array.
*/
- IndexRange index_range() const
+ constexpr IndexRange index_range() const
{
return IndexRange(size_);
}
@@ -409,7 +411,7 @@ template<typename T> class Span {
/**
* Returns a new Span to the same underlying memory buffer. No conversions are done.
*/
- template<typename NewT> Span<NewT> cast() const
+ template<typename NewT> Span<NewT> constexpr cast() const
{
BLI_assert((size_ * sizeof(T)) % sizeof(NewT) == 0);
int64_t new_size = size_ * sizeof(T) / sizeof(NewT);
@@ -450,21 +452,22 @@ template<typename T> class MutableSpan {
int64_t size_;
public:
- MutableSpan() = default;
+ constexpr MutableSpan() = default;
- MutableSpan(T *start, const int64_t size) : data_(start), size_(size)
+ constexpr MutableSpan(T *start, const int64_t size) : data_(start), size_(size)
{
}
- MutableSpan(std::vector<T> &vector) : MutableSpan(vector.data(), vector.size())
+ constexpr MutableSpan(std::vector<T> &vector) : MutableSpan(vector.data(), vector.size())
{
}
- template<std::size_t N> MutableSpan(std::array<T, N> &array) : MutableSpan(array.data(), N)
+ template<std::size_t N>
+ constexpr MutableSpan(std::array<T, N> &array) : MutableSpan(array.data(), N)
{
}
- operator Span<T>() const
+ constexpr operator Span<T>() const
{
return Span<T>(data_, size_);
}
@@ -472,7 +475,7 @@ template<typename T> class MutableSpan {
/**
* Returns the number of elements in the array.
*/
- int64_t size() const
+ constexpr int64_t size() const
{
return size_;
}
@@ -480,7 +483,7 @@ template<typename T> class MutableSpan {
/**
* Replace all elements in the referenced array with the given value.
*/
- void fill(const T &value)
+ constexpr void fill(const T &value)
{
initialized_fill_n(data_, size_, value);
}
@@ -489,7 +492,7 @@ template<typename T> class MutableSpan {
* Replace a subset of all elements with the given value. This invokes undefined behavior when
* one of the indices is out of bounds.
*/
- void fill_indices(Span<int64_t> indices, const T &value)
+ constexpr void fill_indices(Span<int64_t> indices, const T &value)
{
for (int64_t i : indices) {
BLI_assert(i < size_);
@@ -501,30 +504,30 @@ template<typename T> class MutableSpan {
* Returns a pointer to the beginning of the referenced array. This may be nullptr, when the size
* is zero.
*/
- T *data() const
+ constexpr T *data() const
{
return data_;
}
- T *begin() const
+ constexpr T *begin() const
{
return data_;
}
- T *end() const
+ constexpr T *end() const
{
return data_ + size_;
}
- std::reverse_iterator<T *> rbegin() const
+ constexpr std::reverse_iterator<T *> rbegin() const
{
return std::reverse_iterator<T *>(this->end());
}
- std::reverse_iterator<T *> rend() const
+ constexpr std::reverse_iterator<T *> rend() const
{
return std::reverse_iterator<T *>(this->begin());
}
- T &operator[](const int64_t index) const
+ constexpr T &operator[](const int64_t index) const
{
BLI_assert(index < this->size());
return data_[index];
@@ -534,7 +537,7 @@ template<typename T> class MutableSpan {
* Returns a contiguous part of the array. This invokes undefined behavior when the slice would
* go out of bounds.
*/
- MutableSpan slice(const int64_t start, const int64_t length) const
+ constexpr MutableSpan slice(const int64_t start, const int64_t length) const
{
BLI_assert(start + length <= this->size());
return MutableSpan(data_ + start, length);
@@ -544,7 +547,7 @@ template<typename T> class MutableSpan {
* Returns a new MutableSpan with n elements removed from the beginning. This invokes
* undefined behavior when the array is too small.
*/
- MutableSpan drop_front(const int64_t n) const
+ constexpr MutableSpan drop_front(const int64_t n) const
{
BLI_assert(n <= this->size());
return this->slice(n, this->size() - n);
@@ -554,7 +557,7 @@ template<typename T> class MutableSpan {
* Returns a new MutableSpan with n elements removed from the end. This invokes undefined
* behavior when the array is too small.
*/
- MutableSpan drop_back(const int64_t n) const
+ constexpr MutableSpan drop_back(const int64_t n) const
{
BLI_assert(n <= this->size());
return this->slice(0, this->size() - n);
@@ -564,7 +567,7 @@ template<typename T> class MutableSpan {
* Returns a new MutableSpan that only contains the first n elements. This invokes undefined
* behavior when the array is too small.
*/
- MutableSpan take_front(const int64_t n) const
+ constexpr MutableSpan take_front(const int64_t n) const
{
BLI_assert(n <= this->size());
return this->slice(0, n);
@@ -574,7 +577,7 @@ template<typename T> class MutableSpan {
* Return a new MutableSpan that only contains the last n elements. This invokes undefined
* behavior when the array is too small.
*/
- MutableSpan take_back(const int64_t n) const
+ constexpr MutableSpan take_back(const int64_t n) const
{
BLI_assert(n <= this->size());
return this->slice(this->size() - n, n);
@@ -584,7 +587,7 @@ template<typename T> class MutableSpan {
* Returns an (immutable) Span that references the same array. This is usually not needed,
* due to implicit conversions. However, sometimes automatic type deduction needs some help.
*/
- Span<T> as_span() const
+ constexpr Span<T> as_span() const
{
return Span<T>(data_, size_);
}
@@ -593,7 +596,7 @@ template<typename T> class MutableSpan {
* Utility to make it more convenient to iterate over all indices that can be used with this
* array.
*/
- IndexRange index_range() const
+ constexpr IndexRange index_range() const
{
return IndexRange(size_);
}
@@ -602,7 +605,7 @@ template<typename T> class MutableSpan {
* Returns a reference to the last element. This invokes undefined behavior when the array is
* empty.
*/
- T &last() const
+ constexpr T &last() const
{
BLI_assert(size_ > 0);
return data_[size_ - 1];
@@ -612,7 +615,7 @@ template<typename T> class MutableSpan {
* Does a linear search to count how often the value is in the array.
* Returns the number of occurrences.
*/
- int64_t count(const T &value) const
+ constexpr int64_t count(const T &value) const
{
int64_t counter = 0;
for (const T &element : *this) {
@@ -628,7 +631,7 @@ template<typename T> class MutableSpan {
* destination contains uninitialized data and T is not trivially copy constructible.
* The size of both spans is expected to be the same.
*/
- void copy_from(Span<T> values)
+ constexpr void copy_from(Span<T> values)
{
BLI_assert(size_ == values.size());
initialized_copy_n(values.data(), size_, data_);
@@ -637,7 +640,7 @@ template<typename T> class MutableSpan {
/**
* Returns a new span to the same underlying memory buffer. No conversions are done.
*/
- template<typename NewT> MutableSpan<NewT> cast() const
+ template<typename NewT> constexpr MutableSpan<NewT> cast() const
{
BLI_assert((size_ * sizeof(T)) % sizeof(NewT) == 0);
int64_t new_size = size_ * sizeof(T) / sizeof(NewT);
@@ -648,7 +651,7 @@ template<typename T> class MutableSpan {
/**
* Utilities to check that arrays have the same size in debug builds.
*/
-template<typename T1, typename T2> void assert_same_size(const T1 &v1, const T2 &v2)
+template<typename T1, typename T2> constexpr void assert_same_size(const T1 &v1, const T2 &v2)
{
UNUSED_VARS_NDEBUG(v1, v2);
#ifdef DEBUG
@@ -659,7 +662,7 @@ template<typename T1, typename T2> void assert_same_size(const T1 &v1, const T2
}
template<typename T1, typename T2, typename T3>
-void assert_same_size(const T1 &v1, const T2 &v2, const T3 &v3)
+constexpr void assert_same_size(const T1 &v1, const T2 &v2, const T3 &v3)
{
UNUSED_VARS_NDEBUG(v1, v2, v3);
#ifdef DEBUG
diff --git a/source/blender/blenlib/BLI_string_ref.hh b/source/blender/blenlib/BLI_string_ref.hh
index 8597e54d03b..a2562c6100a 100644
--- a/source/blender/blenlib/BLI_string_ref.hh
+++ b/source/blender/blenlib/BLI_string_ref.hh
@@ -64,7 +64,7 @@ class StringRefBase {
const char *data_;
int64_t size_;
- StringRefBase(const char *data, const int64_t size) : data_(data), size_(size)
+ constexpr StringRefBase(const char *data, const int64_t size) : data_(data), size_(size)
{
}
@@ -75,12 +75,12 @@ class StringRefBase {
/**
* Return the (byte-)length of the referenced string, without any null-terminator.
*/
- int64_t size() const
+ constexpr int64_t size() const
{
return size_;
}
- bool is_empty() const
+ constexpr bool is_empty() const
{
return size_ == 0;
}
@@ -88,12 +88,12 @@ class StringRefBase {
/**
* Return a pointer to the start of the string.
*/
- const char *data() const
+ constexpr const char *data() const
{
return data_;
}
- operator Span<char>() const
+ constexpr operator Span<char>() const
{
return Span<char>(data_, size_);
}
@@ -107,22 +107,22 @@ class StringRefBase {
return std::string(data_, static_cast<size_t>(size_));
}
- operator std::string_view() const
+ constexpr operator std::string_view() const
{
return std::string_view(data_, static_cast<size_t>(size_));
}
- const char *begin() const
+ constexpr const char *begin() const
{
return data_;
}
- const char *end() const
+ constexpr const char *end() const
{
return data_ + size_;
}
- IndexRange index_range() const
+ constexpr IndexRange index_range() const
{
return IndexRange(size_);
}
@@ -165,19 +165,19 @@ class StringRefBase {
/**
* Returns true when the string begins with the given prefix. Otherwise false.
*/
- bool startswith(StringRef prefix) const;
+ constexpr bool startswith(StringRef prefix) const;
/**
* Returns true when the string ends with the given suffix. Otherwise false.
*/
- bool endswith(StringRef suffix) const;
+ constexpr bool endswith(StringRef suffix) const;
- StringRef substr(int64_t start, const int64_t size) const;
+ constexpr StringRef substr(int64_t start, const int64_t size) const;
/**
* Get the first char in the string. This invokes undefined behavior when the string is empty.
*/
- const char &front() const
+ constexpr const char &front() const
{
BLI_assert(size_ >= 1);
return data_[0];
@@ -186,7 +186,7 @@ class StringRefBase {
/**
* Get the last char in the string. This invokes undefined behavior when the string is empty.
*/
- const char &back() const
+ constexpr const char &back() const
{
BLI_assert(size_ >= 1);
return data_[size_ - 1];
@@ -196,18 +196,18 @@ class StringRefBase {
* The behavior of those functions matches the standard library implementation of
* std::string_view.
*/
- int64_t find(char c, int64_t pos = 0) const;
- int64_t find(StringRef str, int64_t pos = 0) const;
- int64_t rfind(char c, int64_t pos = INT64_MAX) const;
- int64_t rfind(StringRef str, int64_t pos = INT64_MAX) const;
- int64_t find_first_of(StringRef chars, int64_t pos = 0) const;
- int64_t find_first_of(char c, int64_t pos = 0) const;
- int64_t find_last_of(StringRef chars, int64_t pos = INT64_MAX) const;
- int64_t find_last_of(char c, int64_t pos = INT64_MAX) const;
- int64_t find_first_not_of(StringRef chars, int64_t pos = 0) const;
- int64_t find_first_not_of(char c, int64_t pos = 0) const;
- int64_t find_last_not_of(StringRef chars, int64_t pos = INT64_MAX) const;
- int64_t find_last_not_of(char c, int64_t pos = INT64_MAX) const;
+ constexpr int64_t find(char c, int64_t pos = 0) const;
+ constexpr int64_t find(StringRef str, int64_t pos = 0) const;
+ constexpr int64_t rfind(char c, int64_t pos = INT64_MAX) const;
+ constexpr int64_t rfind(StringRef str, int64_t pos = INT64_MAX) const;
+ constexpr int64_t find_first_of(StringRef chars, int64_t pos = 0) const;
+ constexpr int64_t find_first_of(char c, int64_t pos = 0) const;
+ constexpr int64_t find_last_of(StringRef chars, int64_t pos = INT64_MAX) const;
+ constexpr int64_t find_last_of(char c, int64_t pos = INT64_MAX) const;
+ constexpr int64_t find_first_not_of(StringRef chars, int64_t pos = 0) const;
+ constexpr int64_t find_first_not_of(char c, int64_t pos = 0) const;
+ constexpr int64_t find_last_not_of(StringRef chars, int64_t pos = INT64_MAX) const;
+ constexpr int64_t find_last_not_of(char c, int64_t pos = INT64_MAX) const;
};
/**
@@ -216,7 +216,7 @@ class StringRefBase {
class StringRefNull : public StringRefBase {
public:
- StringRefNull() : StringRefBase("", 0)
+ constexpr StringRefNull() : StringRefBase("", 0)
{
}
@@ -226,7 +226,7 @@ class StringRefNull : public StringRefBase {
*/
StringRefNull(const char *str) : StringRefBase(str, static_cast<int64_t>(strlen(str)))
{
- BLI_assert(str != NULL);
+ BLI_assert(str != nullptr);
BLI_assert(data_[size_] == '\0');
}
@@ -234,7 +234,7 @@ class StringRefNull : public StringRefBase {
* Construct a StringRefNull from a null terminated c-string. This invokes undefined behavior
* when the given size is not the correct size of the string.
*/
- StringRefNull(const char *str, const int64_t size) : StringRefBase(str, size)
+ constexpr StringRefNull(const char *str, const int64_t size) : StringRefBase(str, size)
{
BLI_assert(static_cast<int64_t>(strlen(str)) == size);
}
@@ -250,7 +250,7 @@ class StringRefNull : public StringRefBase {
/**
* Get the char at the given index.
*/
- char operator[](const int64_t index) const
+ constexpr char operator[](const int64_t index) const
{
BLI_assert(index >= 0);
/* Use '<=' instead of just '<', so that the null character can be accessed as well. */
@@ -263,7 +263,7 @@ class StringRefNull : public StringRefBase {
*
* This is like ->data(), but can only be called on a StringRefNull.
*/
- const char *c_str() const
+ constexpr const char *c_str() const
{
return data_;
}
@@ -274,25 +274,26 @@ class StringRefNull : public StringRefBase {
*/
class StringRef : public StringRefBase {
public:
- StringRef() : StringRefBase(nullptr, 0)
+ constexpr StringRef() : StringRefBase(nullptr, 0)
{
}
/**
* StringRefNull can be converted into StringRef, but not the other way around.
*/
- StringRef(StringRefNull other) : StringRefBase(other.data(), other.size())
+ constexpr StringRef(StringRefNull other) : StringRefBase(other.data(), other.size())
{
}
/**
* Create a StringRef from a null-terminated c-string.
*/
- StringRef(const char *str) : StringRefBase(str, str ? static_cast<int64_t>(strlen(str)) : 0)
+ constexpr StringRef(const char *str)
+ : StringRefBase(str, str ? static_cast<int64_t>(std::char_traits<char>::length(str)) : 0)
{
}
- StringRef(const char *str, const int64_t length) : StringRefBase(str, length)
+ constexpr StringRef(const char *str, const int64_t length) : StringRefBase(str, length)
{
}
@@ -300,7 +301,7 @@ class StringRef : public StringRefBase {
* Create a StringRef from a start and end pointer. This invokes undefined behavior when the
* second point points to a smaller address than the first one.
*/
- StringRef(const char *begin, const char *one_after_end)
+ constexpr StringRef(const char *begin, const char *one_after_end)
: StringRefBase(begin, static_cast<int64_t>(one_after_end - begin))
{
BLI_assert(begin <= one_after_end);
@@ -314,7 +315,8 @@ class StringRef : public StringRefBase {
{
}
- StringRef(std::string_view view) : StringRefBase(view.data(), static_cast<int64_t>(view.size()))
+ constexpr StringRef(std::string_view view)
+ : StringRefBase(view.data(), static_cast<int64_t>(view.size()))
{
}
@@ -323,7 +325,7 @@ class StringRef : public StringRefBase {
*
* This is similar to std::string_view::remove_prefix.
*/
- StringRef drop_prefix(const int64_t n) const
+ constexpr StringRef drop_prefix(const int64_t n) const
{
BLI_assert(n >= 0);
BLI_assert(n <= size_);
@@ -334,7 +336,7 @@ class StringRef : public StringRefBase {
* Return a new StringRef with the given prefix being skipped. This invokes undefined behavior if
* the string does not begin with the given prefix.
*/
- StringRef drop_prefix(StringRef prefix) const
+ constexpr StringRef drop_prefix(StringRef prefix) const
{
BLI_assert(this->startswith(prefix));
return this->drop_prefix(prefix.size());
@@ -345,7 +347,7 @@ class StringRef : public StringRefBase {
*
* This is similar to std::string_view::remove_suffix.
*/
- StringRef drop_suffix(const int64_t n) const
+ constexpr StringRef drop_suffix(const int64_t n) const
{
BLI_assert(n >= 0);
BLI_assert(n <= size_);
@@ -355,7 +357,7 @@ class StringRef : public StringRefBase {
/**
* Get the char at the given index.
*/
- char operator[](int64_t index) const
+ constexpr char operator[](int64_t index) const
{
BLI_assert(index >= 0);
BLI_assert(index < size_);
@@ -391,7 +393,7 @@ inline std::string operator+(StringRef a, StringRef b)
* not a problem when std::string_view is only used at api boundaries. To compare a StringRef and a
* std::string_view, one should convert the std::string_view to StringRef (which is very cheap).
* Ideally, we only use StringRef in our code to avoid this problem altogether. */
-inline bool operator==(StringRef a, StringRef b)
+constexpr inline bool operator==(StringRef a, StringRef b)
{
if (a.size() != b.size()) {
return false;
@@ -399,27 +401,27 @@ inline bool operator==(StringRef a, StringRef b)
return STREQLEN(a.data(), b.data(), (size_t)a.size());
}
-inline bool operator!=(StringRef a, StringRef b)
+constexpr inline bool operator!=(StringRef a, StringRef b)
{
return !(a == b);
}
-inline bool operator<(StringRef a, StringRef b)
+constexpr inline bool operator<(StringRef a, StringRef b)
{
return std::string_view(a) < std::string_view(b);
}
-inline bool operator>(StringRef a, StringRef b)
+constexpr inline bool operator>(StringRef a, StringRef b)
{
return std::string_view(a) > std::string_view(b);
}
-inline bool operator<=(StringRef a, StringRef b)
+constexpr inline bool operator<=(StringRef a, StringRef b)
{
return std::string_view(a) <= std::string_view(b);
}
-inline bool operator>=(StringRef a, StringRef b)
+constexpr inline bool operator>=(StringRef a, StringRef b)
{
return std::string_view(a) >= std::string_view(b);
}
@@ -427,7 +429,7 @@ inline bool operator>=(StringRef a, StringRef b)
/**
* Return true when the string starts with the given prefix.
*/
-inline bool StringRefBase::startswith(StringRef prefix) const
+constexpr inline bool StringRefBase::startswith(StringRef prefix) const
{
if (size_ < prefix.size_) {
return false;
@@ -443,7 +445,7 @@ inline bool StringRefBase::startswith(StringRef prefix) const
/**
* Return true when the string ends with the given suffix.
*/
-inline bool StringRefBase::endswith(StringRef suffix) const
+constexpr inline bool StringRefBase::endswith(StringRef suffix) const
{
if (size_ < suffix.size_) {
return false;
@@ -460,8 +462,8 @@ inline bool StringRefBase::endswith(StringRef suffix) const
/**
* Return a new #StringRef containing only a sub-string of the original string.
*/
-inline StringRef StringRefBase::substr(const int64_t start,
- const int64_t max_size = INT64_MAX) const
+constexpr inline StringRef StringRefBase::substr(const int64_t start,
+ const int64_t max_size = INT64_MAX) const
{
BLI_assert(max_size >= 0);
BLI_assert(start >= 0);
@@ -469,7 +471,7 @@ inline StringRef StringRefBase::substr(const int64_t start,
return StringRef(data_ + start, substr_size);
}
-inline int64_t index_or_npos_to_int64(size_t index)
+constexpr inline int64_t index_or_npos_to_int64(size_t index)
{
/* The compiler will probably optimize this check away. */
if (index == std::string_view::npos) {
@@ -478,62 +480,62 @@ inline int64_t index_or_npos_to_int64(size_t index)
return static_cast<int64_t>(index);
}
-inline int64_t StringRefBase::find(char c, int64_t pos) const
+constexpr inline int64_t StringRefBase::find(char c, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(std::string_view(*this).find(c, static_cast<size_t>(pos)));
}
-inline int64_t StringRefBase::find(StringRef str, int64_t pos) const
+constexpr inline int64_t StringRefBase::find(StringRef str, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(std::string_view(*this).find(str, static_cast<size_t>(pos)));
}
-inline int64_t StringRefBase::find_first_of(StringRef chars, int64_t pos) const
+constexpr inline int64_t StringRefBase::find_first_of(StringRef chars, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(
std::string_view(*this).find_first_of(chars, static_cast<size_t>(pos)));
}
-inline int64_t StringRefBase::find_first_of(char c, int64_t pos) const
+constexpr inline int64_t StringRefBase::find_first_of(char c, int64_t pos) const
{
return this->find_first_of(StringRef(&c, 1), pos);
}
-inline int64_t StringRefBase::find_last_of(StringRef chars, int64_t pos) const
+constexpr inline int64_t StringRefBase::find_last_of(StringRef chars, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(
std::string_view(*this).find_last_of(chars, static_cast<size_t>(pos)));
}
-inline int64_t StringRefBase::find_last_of(char c, int64_t pos) const
+constexpr inline int64_t StringRefBase::find_last_of(char c, int64_t pos) const
{
return this->find_last_of(StringRef(&c, 1), pos);
}
-inline int64_t StringRefBase::find_first_not_of(StringRef chars, int64_t pos) const
+constexpr inline int64_t StringRefBase::find_first_not_of(StringRef chars, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(
std::string_view(*this).find_first_not_of(chars, static_cast<size_t>(pos)));
}
-inline int64_t StringRefBase::find_first_not_of(char c, int64_t pos) const
+constexpr inline int64_t StringRefBase::find_first_not_of(char c, int64_t pos) const
{
return this->find_first_not_of(StringRef(&c, 1), pos);
}
-inline int64_t StringRefBase::find_last_not_of(StringRef chars, int64_t pos) const
+constexpr inline int64_t StringRefBase::find_last_not_of(StringRef chars, int64_t pos) const
{
BLI_assert(pos >= 0);
return index_or_npos_to_int64(
std::string_view(*this).find_last_not_of(chars, static_cast<size_t>(pos)));
}
-inline int64_t StringRefBase::find_last_not_of(char c, int64_t pos) const
+constexpr inline int64_t StringRefBase::find_last_not_of(char c, int64_t pos) const
{
return this->find_last_not_of(StringRef(&c, 1), pos);
}
diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h
index d19b5393aa7..eefde1afefb 100644
--- a/source/blender/blenlib/BLI_threads.h
+++ b/source/blender/blenlib/BLI_threads.h
@@ -35,7 +35,6 @@ extern "C" {
#define BLENDER_MAX_THREADS 1024
struct ListBase;
-struct TaskScheduler;
/* Threading API */
diff --git a/source/blender/blenlib/BLI_vector.hh b/source/blender/blenlib/BLI_vector.hh
index 053dcb6faea..fe6d54ae9e5 100644
--- a/source/blender/blenlib/BLI_vector.hh
+++ b/source/blender/blenlib/BLI_vector.hh
@@ -315,13 +315,13 @@ class Vector {
return MutableSpan<T>(begin_, this->size());
}
- template<typename U, typename std::enable_if_t<is_convertible_pointer_v<T, U>> * = nullptr>
+ template<typename U, typename std::enable_if_t<is_span_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>
+ template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<T, U>> * = nullptr>
operator MutableSpan<U>()
{
return MutableSpan<U>(begin_, this->size());
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 46a3ad87dfe..aa4c4efe7d4 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -203,6 +203,7 @@ set(SRC
BLI_heap_simple.h
BLI_index_mask.hh
BLI_index_range.hh
+ BLI_inplace_priority_queue.hh
BLI_iterator.h
BLI_jitter_2d.h
BLI_kdopbvh.h
@@ -390,6 +391,7 @@ if(WITH_GTESTS)
tests/BLI_heap_test.cc
tests/BLI_index_mask_test.cc
tests/BLI_index_range_test.cc
+ tests/BLI_inplace_priority_queue_test.cc
tests/BLI_kdopbvh_test.cc
tests/BLI_linear_allocator_test.cc
tests/BLI_linklist_lockfree_test.cc
diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c
index f126c5a977b..0f90ad3a490 100644
--- a/source/blender/blenlib/intern/BLI_kdopbvh.c
+++ b/source/blender/blenlib/intern/BLI_kdopbvh.c
@@ -1076,6 +1076,25 @@ float BLI_bvhtree_get_epsilon(const BVHTree *tree)
return tree->epsilon;
}
+/**
+ * This function returns the bounding box of the BVH tree.
+ */
+void BLI_bvhtree_get_bounding_box(BVHTree *tree, float r_bb_min[3], float r_bb_max[3])
+{
+ BVHNode *root = tree->nodes[tree->totleaf];
+ if (root != NULL) {
+ const float bb_min[3] = {root->bv[0], root->bv[2], root->bv[4]};
+ const float bb_max[3] = {root->bv[1], root->bv[3], root->bv[5]};
+ copy_v3_v3(r_bb_min, bb_min);
+ copy_v3_v3(r_bb_max, bb_max);
+ }
+ else {
+ BLI_assert(false);
+ zero_v3(r_bb_min);
+ zero_v3(r_bb_max);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c
index a0ee16bee76..19828e69638 100644
--- a/source/blender/blenlib/intern/math_rotation.c
+++ b/source/blender/blenlib/intern/math_rotation.c
@@ -372,6 +372,11 @@ void mat3_normalized_to_quat(float q[4], const float mat[3][3])
q[1] = (mat[2][0] + mat[0][2]) * s;
q[2] = (mat[2][1] + mat[1][2]) * s;
}
+
+ /* Make sure w is nonnegative for a canonical result. */
+ if (q[0] < 0) {
+ negate_v4(q);
+ }
}
normalize_qt(q);
@@ -556,10 +561,20 @@ void rotation_between_quats_to_quat(float q[4], const float q1[4], const float q
* \param r_twist: if not NULL, receives the twist quaternion.
* \returns twist angle.
*/
-float quat_split_swing_and_twist(const float q[4], int axis, float r_swing[4], float r_twist[4])
+float quat_split_swing_and_twist(const float q_in[4], int axis, float r_swing[4], float r_twist[4])
{
BLI_assert(axis >= 0 && axis <= 2);
+ /* The calculation requires a canonical quaternion. */
+ float q[4];
+
+ if (q_in[0] < 0) {
+ negate_v4_v4(q, q_in);
+ }
+ else {
+ copy_v4_v4(q, q_in);
+ }
+
/* Half-twist angle can be computed directly. */
float t = atan2f(q[axis + 1], q[0]);
diff --git a/source/blender/blenlib/intern/mesh_boolean.cc b/source/blender/blenlib/intern/mesh_boolean.cc
index 2db939cd628..88d90a7816f 100644
--- a/source/blender/blenlib/intern/mesh_boolean.cc
+++ b/source/blender/blenlib/intern/mesh_boolean.cc
@@ -401,11 +401,6 @@ class Cell {
void add_patch(int p)
{
- patches_.add_new(p);
- }
-
- void add_patch_non_duplicates(int p)
- {
patches_.add(p);
}
@@ -693,7 +688,7 @@ static void merge_cells(int merge_to, int merge_from, CellsInfo &cinfo, PatchesI
merge_to_cell = cinfo.cell(final_merge_to);
}
for (int cell_p : merge_from_cell.patches()) {
- merge_to_cell.add_patch_non_duplicates(cell_p);
+ merge_to_cell.add_patch(cell_p);
Patch &patch = pinfo.patch(cell_p);
if (patch.cell_above == merge_from) {
patch.cell_above = merge_to;
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index 74bbe59bc04..5636ffafb6a 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -32,6 +32,7 @@
#include "BLI_fnmatch.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utf8.h"
#include "BLI_utildefines.h"
#ifdef WIN32
@@ -287,7 +288,7 @@ void BLI_path_normalize_dir(const char *relabase, char *dir)
* (good practice anyway).
* REMOVED based on popular demand (see T45900).
* Percent '%' char is a bit same case - not recommended to use it,
- * but supported by all decent FS/OS around.
+ * but supported by all decent file-systems/operating-systems around.
*
* \note On Windows, it also ensures there is no '.' (dot char) at the end of the file,
* this can lead to issues.
@@ -512,8 +513,8 @@ void BLI_path_normalize_unc_16(wchar_t *path_16)
#endif
/**
- * Replaces *file with a relative version (prefixed by "//") such that BLI_path_abs, given
- * the same *relfile, will convert it back to its original value.
+ * Replaces `file` with a relative version (prefixed by "//") such that #BLI_path_abs, given
+ * the same `relfile`, will convert it back to its original value.
*/
void BLI_path_rel(char *file, const char *relfile)
{
@@ -663,7 +664,7 @@ void BLI_path_rel(char *file, const char *relfile)
* \param maxlen: Maximum length of string
* \param suffix: String to append to the original string
* \param sep: Optional separator character
- * \return true if succeeded
+ * \return true if succeeded
*/
bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char *sep)
{
@@ -702,7 +703,7 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char
/**
* Replaces path with the path of its parent directory, returning true if
- * it was able to find a parent directory within the pathname.
+ * it was able to find a parent directory within the path.
*/
bool BLI_path_parent_dir(char *path)
{
@@ -721,7 +722,7 @@ bool BLI_path_parent_dir(char *path)
}
/**
- * Strips off nonexistent (or non-accessible) subdirectories from the end of *dir,
+ * Strips off nonexistent (or non-accessible) sub-directories from the end of `dir`,
* leaving the path of the lowest-level directory that does exist and we can read.
*/
bool BLI_path_parent_dir_until_exists(char *dir)
@@ -736,9 +737,9 @@ bool BLI_path_parent_dir_until_exists(char *dir)
}
/**
- * Looks for a sequence of "#" characters in the last slash-separated component of *path,
+ * Looks for a sequence of "#" characters in the last slash-separated component of `path`,
* returning the indexes of the first and one past the last character in the sequence in
- * *char_start and *char_end respectively. Returns true if such a sequence was found.
+ * `char_start` and `char_end` respectively. Returns true if such a sequence was found.
*/
static bool stringframe_chars(const char *path, int *char_start, int *char_end)
{
@@ -773,7 +774,7 @@ static bool stringframe_chars(const char *path, int *char_start, int *char_end)
}
/**
- * Ensure *path contains at least one "#" character in its last slash-separated
+ * Ensure `path` contains at least one "#" character in its last slash-separated
* component, appending one digits long if not.
*/
static void ensure_digits(char *path, int digits)
@@ -795,7 +796,7 @@ static void ensure_digits(char *path, int digits)
}
/**
- * Replaces "#" character sequence in last slash-separated component of *path
+ * Replaces "#" character sequence in last slash-separated component of `path`
* with frame as decimal integer, with leading zeroes as necessary, to make digits digits.
*/
bool BLI_path_frame(char *path, int frame, int digits)
@@ -817,7 +818,7 @@ bool BLI_path_frame(char *path, int frame, int digits)
}
/**
- * Replaces "#" character sequence in last slash-separated component of *path
+ * Replaces "#" character sequence in last slash-separated component of `path`
* with sta and end as decimal integers, with leading zeroes as necessary, to make digits
* digits each, with a hyphen in-between.
*/
@@ -962,7 +963,7 @@ bool BLI_path_frame_check_chars(const char *path)
/**
* Creates a display string from path to be used menus and the user interface.
- * Like bpy.path.display_name().
+ * Like `bpy.path.display_name()`.
*/
void BLI_path_to_display_name(char *display_name, int maxlen, const char *name)
{
@@ -1003,7 +1004,7 @@ void BLI_path_to_display_name(char *display_name, int maxlen, const char *name)
}
/**
- * If path begins with "//", strips that and replaces it with basepath directory.
+ * If path begins with "//", strips that and replaces it with `basepath` directory.
*
* \note Also converts drive-letter prefix to something more sensible
* if this is a non-drive-letter-based system.
@@ -1161,7 +1162,7 @@ bool BLI_path_abs_from_cwd(char *path, const size_t maxlen)
#ifdef _WIN32
/**
* Tries appending each of the semicolon-separated extensions in the PATHEXT
- * environment variable (Windows-only) onto *name in turn until such a file is found.
+ * environment variable (Windows-only) onto `name` in turn until such a file is found.
* Returns success/failure.
*/
bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen)
@@ -1268,7 +1269,7 @@ bool BLI_path_program_search(char *fullname, const size_t maxlen, const char *na
/**
* Sets the specified environment variable to the specified value,
- * and clears it if val == NULL.
+ * and clears it if `val == NULL`.
*/
void BLI_setenv(const char *env, const char *val)
{
@@ -1304,30 +1305,44 @@ void BLI_setenv_if_new(const char *env, const char *val)
/**
* Get an env var, result has to be used immediately.
*
- * On windows getenv gets its variables from a static copy of the environment variables taken at
+ * On windows #getenv gets its variables from a static copy of the environment variables taken at
* process start-up, causing it to not pick up on environment variables created during runtime.
* This function uses an alternative method to get environment variables that does pick up on
- * runtime environment variables.
+ * runtime environment variables. The result will be UTF-8 encoded.
*/
const char *BLI_getenv(const char *env)
{
#ifdef _MSC_VER
- static char buffer[32767]; /* 32767 is the total size of the environment block on windows*/
- if (GetEnvironmentVariableA(env, buffer, sizeof(buffer))) {
- return buffer;
- }
- else {
- return NULL;
+ const char *result = NULL;
+ /* 32767 is the maximum size of the environment variable on windows,
+ * reserve one more character for the zero terminator. */
+ static wchar_t buffer[32768];
+ wchar_t *env_16 = alloc_utf16_from_8(env, 0);
+ if (env_16) {
+ if (GetEnvironmentVariableW(env_16, buffer, ARRAY_SIZE(buffer))) {
+ char *res_utf8 = alloc_utf_8_from_16(buffer, 0);
+ /* Make sure the result is valid, and will fit into our temporary storage buffer. */
+ if (res_utf8) {
+ if (strlen(res_utf8) + 1 < sizeof(buffer)) {
+ /* We are re-using the utf16 buffer here, since allocating a second static buffer to
+ * contain the UTF-8 version to return would be wasteful. */
+ memcpy(buffer, res_utf8, strlen(res_utf8) + 1);
+ result = (const char *)buffer;
+ }
+ free(res_utf8);
+ }
+ }
}
+ return result;
#else
return getenv(env);
#endif
}
/**
- * Ensures that the parent directory of *name exists.
+ * Ensures that the parent directory of `name` exists.
*
- * \return true on success (i.e. given path now exists on FS), false otherwise.
+ * \return true on success (i.e. given path now exists on file-system), false otherwise.
*/
bool BLI_make_existing_file(const char *name)
{
@@ -1339,13 +1354,13 @@ bool BLI_make_existing_file(const char *name)
}
/**
- * Returns in *string the concatenation of *dir and *file (also with *relabase on the
- * front if specified and *dir begins with "//"). Normalizes all occurrences of path
- * separators, including ensuring there is exactly one between the copies of *dir and *file,
- * and between the copies of *relabase and *dir.
+ * Returns in `string` the concatenation of `dir` and `file` (also with `relabase` on the
+ * front if specified and `dir` begins with "//"). Normalizes all occurrences of path
+ * separators, including ensuring there is exactly one between the copies of `dir` and `file`,
+ * and between the copies of `relabase` and `dir`.
*
- * \param relabase: Optional prefix to substitute for "//" on front of *dir
- * \param string: Area to return result
+ * \param relabase: Optional prefix to substitute for "//" on front of `dir`.
+ * \param string: Area to return result.
*/
void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file)
{
@@ -1485,9 +1500,8 @@ bool BLI_path_extension_check_array(const char *str, const char **ext_array)
}
/**
- * Semicolon separated wildcards, eg:
- * '*.zip;*.py;*.exe'
- * does str match any of the semicolon-separated glob patterns in fnmatch.
+ * Semicolon separated wildcards, eg: `*.zip;*.py;*.exe`
+ * does str match any of the semicolon-separated glob patterns in #fnmatch.
*/
bool BLI_path_extension_check_glob(const char *str, const char *ext_fnmatch)
{
@@ -1516,10 +1530,11 @@ bool BLI_path_extension_check_glob(const char *str, const char *ext_fnmatch)
}
/**
- * Does basic validation of the given glob string, to prevent common issues from string truncation.
+ * Does basic validation of the given glob string, to prevent common issues from string
+ * truncation.
*
* For now, only forbids last group to be a wildcard-only one, if there are more than one group
- * (i.e. things like "*.txt;*.cpp;*" are changed to "*.txt;*.cpp;")
+ * (i.e. things like `*.txt;*.cpp;*` are changed to `*.txt;*.cpp;`)
*
* \returns true if it had to modify given \a ext_fnmatch pattern.
*/
@@ -1629,7 +1644,7 @@ bool BLI_path_filename_ensure(char *filepath, size_t maxlen, const char *filenam
}
/**
- * Converts `/foo/bar.txt` to "/foo/" and `bar.txt`
+ * Converts `/foo/bar.txt` to `/foo/` and `bar.txt`
*
* - Wont change \a string.
* - Wont create any directories.
@@ -1662,7 +1677,7 @@ void BLI_split_dirfile(
}
/**
- * Copies the parent directory part of string into *dir, max length dirlen.
+ * Copies the parent directory part of string into `dir`, max length `dirlen`.
*/
void BLI_split_dir_part(const char *string, char *dir, const size_t dirlen)
{
@@ -1670,7 +1685,7 @@ void BLI_split_dir_part(const char *string, char *dir, const size_t dirlen)
}
/**
- * Copies the leaf filename part of string into *file, max length filelen.
+ * Copies the leaf filename part of string into `file`, max length `filelen`.
*/
void BLI_split_file_part(const char *string, char *file, const size_t filelen)
{
@@ -1717,7 +1732,7 @@ void BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__re
/**
* Simple appending of filename to dir, does not check for valid path!
- * Puts result into *dst, which may be same area as *dir.
+ * Puts result into `dst`, which may be same area as `dir`.
*/
void BLI_join_dirfile(char *__restrict dst,
const size_t maxlen,
@@ -1761,7 +1776,7 @@ void BLI_join_dirfile(char *__restrict dst,
* Join multiple strings into a path, ensuring only a single path separator between each,
* and trailing slash is kept.
*
- * \note If you want a trailing slash, add ``SEP_STR`` as the last path argument,
+ * \note If you want a trailing slash, add `SEP_STR` as the last path argument,
* duplicate slashes will be cleaned up.
*/
size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *path, ...)
@@ -1845,7 +1860,7 @@ size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *pat
}
/**
- * like pythons os.path.basename()
+ * like Python's `os.path.basename()`
*
* \return The pointer into \a path string immediately after last slash,
* or start of \a path if none found.
diff --git a/source/blender/blenlib/tests/BLI_index_range_test.cc b/source/blender/blenlib/tests/BLI_index_range_test.cc
index d472ded0f18..ddaa067f50e 100644
--- a/source/blender/blenlib/tests/BLI_index_range_test.cc
+++ b/source/blender/blenlib/tests/BLI_index_range_test.cc
@@ -140,4 +140,11 @@ TEST(index_range, AsSpan)
EXPECT_EQ(span[3], 7);
}
+TEST(index_range, constexpr_)
+{
+ constexpr IndexRange range = IndexRange(1, 1);
+ std::array<int, range[0]> compiles = {1};
+ BLI_STATIC_ASSERT(range.size() == 1, "");
+ EXPECT_EQ(compiles[0], 1);
+}
} // namespace blender::tests
diff --git a/source/blender/blenlib/tests/BLI_inplace_priority_queue_test.cc b/source/blender/blenlib/tests/BLI_inplace_priority_queue_test.cc
new file mode 100644
index 00000000000..3adf12f36a7
--- /dev/null
+++ b/source/blender/blenlib/tests/BLI_inplace_priority_queue_test.cc
@@ -0,0 +1,113 @@
+/* Apache License, Version 2.0 */
+
+#include "testing/testing.h"
+
+#include "BLI_inplace_priority_queue.hh"
+#include "BLI_rand.hh"
+
+namespace blender::tests {
+
+TEST(inplace_priority_queue, BuildSmall)
+{
+ Array<int> values = {1, 5, 2, 8, 5, 6, 5, 4, 3, 6, 7, 3};
+ InplacePriorityQueue<int> priority_queue{values};
+
+ EXPECT_EQ(priority_queue.peek(), 8);
+ EXPECT_EQ(priority_queue.pop(), 8);
+ EXPECT_EQ(priority_queue.peek(), 7);
+ EXPECT_EQ(priority_queue.pop(), 7);
+ EXPECT_EQ(priority_queue.pop(), 6);
+ EXPECT_EQ(priority_queue.pop(), 6);
+ EXPECT_EQ(priority_queue.pop(), 5);
+}
+
+TEST(inplace_priority_queue, DecreasePriority)
+{
+ Array<int> values = {5, 2, 7, 4};
+ InplacePriorityQueue<int> priority_queue(values);
+
+ EXPECT_EQ(priority_queue.peek(), 7);
+ values[2] = 0;
+ EXPECT_EQ(priority_queue.peek(), 0);
+ priority_queue.priority_decreased(2);
+ EXPECT_EQ(priority_queue.peek(), 5);
+}
+
+TEST(inplace_priority_queue, IncreasePriority)
+{
+ Array<int> values = {5, 2, 7, 4};
+ InplacePriorityQueue<int> priority_queue(values);
+
+ EXPECT_EQ(priority_queue.peek(), 7);
+ values[1] = 10;
+ EXPECT_EQ(priority_queue.peek(), 7);
+ priority_queue.priority_increased(1);
+ EXPECT_EQ(priority_queue.peek(), 10);
+}
+
+TEST(inplace_priority_queue, PopAll)
+{
+ RandomNumberGenerator rng;
+ Vector<int> values;
+ const int amount = 1000;
+ for (int i = 0; i < amount; i++) {
+ values.append(rng.get_int32() % amount);
+ }
+
+ InplacePriorityQueue<int> priority_queue(values);
+
+ int last_value = amount;
+ while (!priority_queue.is_empty()) {
+ const int value = priority_queue.pop();
+ EXPECT_LE(value, last_value);
+ last_value = value;
+ }
+}
+
+TEST(inplace_priority_queue, ManyPriorityChanges)
+{
+ RandomNumberGenerator rng;
+ Vector<int> values;
+ const int amount = 1000;
+ for (int i = 0; i < amount; i++) {
+ values.append(rng.get_int32() % amount);
+ }
+
+ InplacePriorityQueue<int> priority_queue(values);
+
+ for (int i = 0; i < amount; i++) {
+ const int index = rng.get_int32() % amount;
+ const int new_priority = rng.get_int32() % amount;
+ values[index] = new_priority;
+ priority_queue.priority_changed(index);
+ }
+
+ int last_value = amount;
+ while (!priority_queue.is_empty()) {
+ const int value = priority_queue.pop();
+ EXPECT_LE(value, last_value);
+ last_value = value;
+ }
+}
+
+TEST(inplace_priority_queue, IndicesAccess)
+{
+ Array<int> values = {4, 6, 2, 4, 8, 1, 10, 2, 5};
+ InplacePriorityQueue<int> priority_queue(values);
+
+ EXPECT_EQ(priority_queue.active_indices().size(), 9);
+ EXPECT_EQ(priority_queue.inactive_indices().size(), 0);
+ EXPECT_EQ(priority_queue.all_indices().size(), 9);
+ EXPECT_EQ(priority_queue.pop(), 10);
+ EXPECT_EQ(priority_queue.active_indices().size(), 8);
+ EXPECT_EQ(priority_queue.inactive_indices().size(), 1);
+ EXPECT_EQ(values[priority_queue.inactive_indices()[0]], 10);
+ EXPECT_EQ(priority_queue.all_indices().size(), 9);
+ EXPECT_EQ(priority_queue.pop(), 8);
+ EXPECT_EQ(priority_queue.inactive_indices().size(), 2);
+ EXPECT_EQ(values[priority_queue.inactive_indices()[0]], 8);
+ EXPECT_EQ(values[priority_queue.inactive_indices()[1]], 10);
+ EXPECT_EQ(priority_queue.all_indices().size(), 9);
+}
+
+} // namespace blender::tests
diff --git a/source/blender/blenlib/tests/BLI_math_rotation_test.cc b/source/blender/blenlib/tests/BLI_math_rotation_test.cc
index 02257ba83dd..5a179bff3d6 100644
--- a/source/blender/blenlib/tests/BLI_math_rotation_test.cc
+++ b/source/blender/blenlib/tests/BLI_math_rotation_test.cc
@@ -2,6 +2,7 @@
#include "testing/testing.h"
+#include "BLI_math_base.h"
#include "BLI_math_rotation.h"
#include <cmath>
@@ -71,6 +72,12 @@ TEST(math_rotation, quat_to_mat_to_quat_bad_T83196)
test_quat_to_mat_to_quat(0.0149f, 0.9996f, -0.0212f, -0.0107f);
}
+TEST(math_rotation, quat_to_mat_to_quat_bad_negative)
+{
+ /* This shouldn't produce a negative q[0]. */
+ test_quat_to_mat_to_quat(0.5f - 1e-6f, 0, -sqrtf(3) / 2 - 1e-6f, 0);
+}
+
TEST(math_rotation, quat_to_mat_to_quat_near_1000)
{
test_quat_to_mat_to_quat(0.9999f, 0.01f, -0.001f, -0.01f);
@@ -126,3 +133,17 @@ TEST(math_rotation, quat_to_mat_to_quat_near_0001)
test_quat_to_mat_to_quat(0.25f, -0.025f, -0.25f, 0.97f);
test_quat_to_mat_to_quat(0.30f, -0.030f, -0.30f, 0.95f);
}
+
+TEST(math_rotation, quat_split_swing_and_twist_negative)
+{
+ const float input[4] = {-0.5f, 0, sqrtf(3) / 2, 0};
+ const float expected_swing[4] = {1.0f, 0, 0, 0};
+ const float expected_twist[4] = {0.5f, 0, -sqrtf(3) / 2, 0};
+ float swing[4], twist[4];
+
+ float twist_angle = quat_split_swing_and_twist(input, 1, swing, twist);
+
+ EXPECT_NEAR(twist_angle, -M_PI * 2 / 3, FLT_EPSILON);
+ EXPECT_V4_NEAR(swing, expected_swing, FLT_EPSILON);
+ EXPECT_V4_NEAR(twist, expected_twist, FLT_EPSILON);
+}
diff --git a/source/blender/blenlib/tests/BLI_memory_utils_test.cc b/source/blender/blenlib/tests/BLI_memory_utils_test.cc
index fcef2f8688a..23415e69b04 100644
--- a/source/blender/blenlib/tests/BLI_memory_utils_test.cc
+++ b/source/blender/blenlib/tests/BLI_memory_utils_test.cc
@@ -158,4 +158,15 @@ static_assert(is_convertible_pointer_v<int **, int **const>);
static_assert(is_convertible_pointer_v<int **, int *const *>);
static_assert(is_convertible_pointer_v<int **, int const *const *>);
+static_assert(is_span_convertible_pointer_v<int *, int *>);
+static_assert(is_span_convertible_pointer_v<int *, const int *>);
+static_assert(!is_span_convertible_pointer_v<const int *, int *>);
+static_assert(is_span_convertible_pointer_v<const int *, const int *>);
+static_assert(is_span_convertible_pointer_v<const int *, const void *>);
+static_assert(!is_span_convertible_pointer_v<const int *, void *>);
+static_assert(is_span_convertible_pointer_v<int *, void *>);
+static_assert(is_span_convertible_pointer_v<int *, const void *>);
+static_assert(!is_span_convertible_pointer_v<TestBaseClass *, TestChildClass *>);
+static_assert(!is_span_convertible_pointer_v<TestChildClass *, TestBaseClass *>);
+
} // namespace blender::tests
diff --git a/source/blender/blenlib/tests/BLI_span_test.cc b/source/blender/blenlib/tests/BLI_span_test.cc
index 9a8d9df7873..d1c9f312b97 100644
--- a/source/blender/blenlib/tests/BLI_span_test.cc
+++ b/source/blender/blenlib/tests/BLI_span_test.cc
@@ -337,4 +337,19 @@ TEST(span, MutableReverseIterator)
EXPECT_EQ_ARRAY(src.data(), Span({14, 15, 16, 17}).data(), 4);
}
+TEST(span, constexpr_)
+{
+ static constexpr std::array<int, 3> src = {3, 2, 1};
+ constexpr Span<int> span(src);
+ BLI_STATIC_ASSERT(span[2] == 1, "");
+ BLI_STATIC_ASSERT(span.size() == 3, "");
+ BLI_STATIC_ASSERT(span.slice(1, 2).size() == 2, "");
+ BLI_STATIC_ASSERT(span.has_duplicates__linear_search() == false, "");
+
+ std::integral_constant<bool, span.first_index(1) == 2> ic;
+ BLI_STATIC_ASSERT(ic.value, "");
+
+ EXPECT_EQ(span.slice(1, 2).size(), 2);
+}
+
} // namespace blender::tests
diff --git a/source/blender/blenlib/tests/BLI_string_ref_test.cc b/source/blender/blenlib/tests/BLI_string_ref_test.cc
index 2d488feff71..401a7bc1118 100644
--- a/source/blender/blenlib/tests/BLI_string_ref_test.cc
+++ b/source/blender/blenlib/tests/BLI_string_ref_test.cc
@@ -298,4 +298,12 @@ TEST(string_ref, ToStringView)
EXPECT_EQ(view, "hello");
}
+TEST(string_ref, constexpr_)
+{
+ constexpr StringRef sref("World");
+ BLI_STATIC_ASSERT(sref[2] == 'r', "");
+ BLI_STATIC_ASSERT(sref.size() == 5, "");
+ std::array<int, static_cast<std::size_t>(sref.find_first_of('o'))> compiles = {1};
+ EXPECT_EQ(compiles[0], 1);
+}
} // namespace blender::tests