diff options
Diffstat (limited to 'source/blender/blenlib/BLI_span.hh')
-rw-r--r-- | source/blender/blenlib/BLI_span.hh | 230 |
1 files changed, 123 insertions, 107 deletions
diff --git a/source/blender/blenlib/BLI_span.hh b/source/blender/blenlib/BLI_span.hh index ce4e90d5e16..81b86f647f6 100644 --- a/source/blender/blenlib/BLI_span.hh +++ b/source/blender/blenlib/BLI_span.hh @@ -87,8 +87,8 @@ namespace blender { */ template<typename T> class Span { private: - const T *m_start = nullptr; - uint m_size = 0; + const T *data_ = nullptr; + int64_t size_ = 0; public: /** @@ -96,8 +96,15 @@ template<typename T> class Span { */ Span() = default; - Span(const T *start, uint size) : m_start(start), m_size(size) + 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_((const T *)start), size_(size) + { + BLI_assert(size >= 0); } /** @@ -111,11 +118,11 @@ template<typename T> class Span { * Span<int> span = {1, 2, 3, 4}; * call_function_with_array(span); */ - Span(const std::initializer_list<T> &list) : Span(list.begin(), (uint)list.size()) + Span(const std::initializer_list<T> &list) : Span(list.begin(), (int64_t)list.size()) { } - Span(const std::vector<T> &vector) : Span(vector.data(), (uint)vector.size()) + Span(const std::vector<T> &vector) : Span(vector.data(), (int64_t)vector.size()) { } @@ -128,9 +135,8 @@ template<typename T> class Span { * Span<T *> -> Span<const T *> * Span<Derived *> -> Span<Base *> */ - template<typename U, - typename std::enable_if<std::is_convertible<U *, T>::value>::type * = 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) : data_((T *)array.data()), size_(array.size()) { } @@ -138,10 +144,12 @@ 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(uint start, uint size) const + Span slice(int64_t start, int64_t size) const { + BLI_assert(start >= 0); + BLI_assert(size >= 0); BLI_assert(start + size <= this->size() || size == 0); - return Span(m_start + start, size); + return Span(data_ + start, size); } Span slice(IndexRange range) const @@ -153,8 +161,9 @@ 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(uint n) const + Span drop_front(int64_t n) const { + BLI_assert(n >= 0); BLI_assert(n <= this->size()); return this->slice(n, this->size() - n); } @@ -163,8 +172,9 @@ 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(uint n) const + Span drop_back(int64_t n) const { + BLI_assert(n >= 0); BLI_assert(n <= this->size()); return this->slice(0, this->size() - n); } @@ -173,8 +183,9 @@ 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(uint n) const + Span take_front(int64_t n) const { + BLI_assert(n >= 0); BLI_assert(n <= this->size()); return this->slice(0, n); } @@ -183,8 +194,9 @@ 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(uint n) const + Span take_back(int64_t n) const { + BLI_assert(n >= 0); BLI_assert(n <= this->size()); return this->slice(this->size() - n, n); } @@ -195,35 +207,36 @@ template<typename T> class Span { */ const T *data() const { - return m_start; + return data_; } const T *begin() const { - return m_start; + return data_; } const T *end() const { - return m_start + m_size; + return data_ + size_; } /** * Access an element in the array. This invokes undefined behavior when the index is out of * bounds. */ - const T &operator[](uint index) const + const T &operator[](int64_t index) const { - BLI_assert(index < m_size); - return m_start[index]; + BLI_assert(index >= 0); + BLI_assert(index < size_); + return data_[index]; } /** * Returns the number of elements in the referenced array. */ - uint size() const + int64_t size() const { - return m_size; + return size_; } /** @@ -231,15 +244,15 @@ template<typename T> class Span { */ bool is_empty() const { - return m_size == 0; + return size_ == 0; } /** * Returns the number of bytes referenced by this Span. */ - uint size_in_bytes() const + int64_t size_in_bytes() const { - return sizeof(T) * m_size; + return sizeof(T) * size_; } /** @@ -269,9 +282,9 @@ template<typename T> class Span { * Does a linear search to count how often the value is in the array. * Returns the number of occurrences. */ - uint count(const T &value) const + int64_t count(const T &value) const { - uint counter = 0; + int64_t counter = 0; for (const T &element : *this) { if (element == value) { counter++; @@ -286,8 +299,8 @@ template<typename T> class Span { */ const T &first() const { - BLI_assert(m_size > 0); - return m_start[0]; + BLI_assert(size_ > 0); + return data_[0]; } /** @@ -296,18 +309,18 @@ template<typename T> class Span { */ const T &last() const { - BLI_assert(m_size > 0); - return m_start[m_size - 1]; + BLI_assert(size_ > 0); + return data_[size_ - 1]; } /** * Returns the element at the given index. If the index is out of range, return the fallback * value. */ - T get(uint index, const T &fallback) const + T get(int64_t index, const T &fallback) const { - if (index < m_size) { - return m_start[index]; + if (index < size_ && index >= 0) { + return data_[index]; } return fallback; } @@ -320,12 +333,12 @@ template<typename T> class Span { { /* The size should really be smaller than that. If it is not, the calling code should be * changed. */ - BLI_assert(m_size < 1000); + BLI_assert(size_ < 1000); - for (uint i = 0; i < m_size; i++) { - const T &value = m_start[i]; - for (uint j = i + 1; j < m_size; j++) { - if (value == m_start[j]) { + for (int64_t i = 0; i < size_; i++) { + const T &value = data_[i]; + for (int64_t j = i + 1; j < size_; j++) { + if (value == data_[j]) { return true; } } @@ -342,10 +355,10 @@ template<typename T> class Span { { /* The size should really be smaller than that. If it is not, the calling code should be * changed. */ - BLI_assert(m_size < 1000); + BLI_assert(size_ < 1000); - for (uint i = 0; i < m_size; i++) { - const T &value = m_start[i]; + for (int64_t i = 0; i < size_; i++) { + const T &value = data_[i]; if (other.contains(value)) { return true; } @@ -357,20 +370,20 @@ 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. */ - uint first_index(const T &search_value) const + int64_t first_index(const T &search_value) const { - int index = this->first_index_try(search_value); + const int64_t index = this->first_index_try(search_value); BLI_assert(index >= 0); - return (uint)index; + return (int64_t)index; } /** * Returns the index of the first occurrence of the given value or -1 if it does not exist. */ - int first_index_try(const T &search_value) const + int64_t first_index_try(const T &search_value) const { - for (uint i = 0; i < m_size; i++) { - if (m_start[i] == search_value) { + for (int64_t i = 0; i < size_; i++) { + if (data_[i] == search_value) { return i; } } @@ -383,7 +396,7 @@ template<typename T> class Span { */ IndexRange index_range() const { - return IndexRange(m_size); + return IndexRange(size_); } /** @@ -391,9 +404,9 @@ template<typename T> class Span { */ template<typename NewT> Span<NewT> cast() const { - BLI_assert((m_size * sizeof(T)) % sizeof(NewT) == 0); - uint new_size = m_size * sizeof(T) / sizeof(NewT); - return Span<NewT>(reinterpret_cast<const NewT *>(m_start), new_size); + BLI_assert((size_ * sizeof(T)) % sizeof(NewT) == 0); + int64_t new_size = size_ * sizeof(T) / sizeof(NewT); + return Span<NewT>(reinterpret_cast<const NewT *>(data_), new_size); } /** @@ -402,7 +415,7 @@ template<typename T> class Span { */ template<typename PrintLineF> void print_as_lines(std::string name, PrintLineF print_line) const { - std::cout << "Span: " << name << " \tSize:" << m_size << '\n'; + std::cout << "Span: " << name << " \tSize:" << size_ << '\n'; for (const T &value : *this) { std::cout << " "; print_line(value); @@ -426,28 +439,13 @@ template<typename T> class Span { */ template<typename T> class MutableSpan { private: - T *m_start; - uint m_size; + T *data_; + int64_t size_; public: MutableSpan() = default; - MutableSpan(T *start, uint size) : m_start(start), m_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. - * - * Do: - * call_function_with_array({1, 2, 3, 4}); - * - * Don't: - * MutableSpan<int> span = {1, 2, 3, 4}; - * call_function_with_array(span); - */ - MutableSpan(std::initializer_list<T> &list) : MutableSpan(list.begin(), list.size()) + MutableSpan(T *start, const int64_t size) : data_(start), size_(size) { } @@ -461,15 +459,15 @@ template<typename T> class MutableSpan { operator Span<T>() const { - return Span<T>(m_start, m_size); + return Span<T>(data_, size_); } /** * Returns the number of elements in the array. */ - uint size() const + int64_t size() const { - return m_size; + return size_; } /** @@ -477,18 +475,18 @@ template<typename T> class MutableSpan { */ void fill(const T &value) { - initialized_fill_n(m_start, m_size, value); + initialized_fill_n(data_, size_, value); } /** * 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<uint> indices, const T &value) + void fill_indices(Span<int64_t> indices, const T &value) { - for (uint i : indices) { - BLI_assert(i < m_size); - m_start[i] = value; + for (int64_t i : indices) { + BLI_assert(i < size_); + data_[i] = value; } } @@ -498,40 +496,40 @@ template<typename T> class MutableSpan { */ T *data() const { - return m_start; + return data_; } T *begin() const { - return m_start; + return data_; } T *end() const { - return m_start + m_size; + return data_ + size_; } - T &operator[](uint index) const + T &operator[](const int64_t index) const { BLI_assert(index < this->size()); - return m_start[index]; + return data_[index]; } /** * Returns a contiguous part of the array. This invokes undefined behavior when the slice would * go out of bounds. */ - MutableSpan slice(uint start, uint length) const + MutableSpan slice(const int64_t start, const int64_t length) const { BLI_assert(start + length <= this->size()); - return MutableSpan(m_start + start, length); + return MutableSpan(data_ + start, length); } /** * Returns a new MutableSpan with n elements removed from the beginning. This invokes * undefined behavior when the array is too small. */ - MutableSpan drop_front(uint n) const + MutableSpan drop_front(const int64_t n) const { BLI_assert(n <= this->size()); return this->slice(n, this->size() - n); @@ -541,7 +539,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(uint n) const + MutableSpan drop_back(const int64_t n) const { BLI_assert(n <= this->size()); return this->slice(0, this->size() - n); @@ -551,7 +549,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(uint n) const + MutableSpan take_front(const int64_t n) const { BLI_assert(n <= this->size()); return this->slice(0, n); @@ -561,7 +559,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(uint n) const + MutableSpan take_back(const int64_t n) const { BLI_assert(n <= this->size()); return this->slice(this->size() - n, n); @@ -573,7 +571,7 @@ template<typename T> class MutableSpan { */ Span<T> as_span() const { - return Span<T>(m_start, m_size); + return Span<T>(data_, size_); } /** @@ -582,7 +580,7 @@ template<typename T> class MutableSpan { */ IndexRange index_range() const { - return IndexRange(m_size); + return IndexRange(size_); } /** @@ -591,8 +589,34 @@ template<typename T> class MutableSpan { */ T &last() const { - BLI_assert(m_size > 0); - return m_start[m_size - 1]; + BLI_assert(size_ > 0); + return data_[size_ - 1]; + } + + /** + * 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 + { + int64_t counter = 0; + for (const T &element : *this) { + if (element == value) { + counter++; + } + } + return counter; + } + + /** + * Copy all values from another span into this span. This invokes undefined behavior when the + * 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) + { + BLI_assert(size_ == values.size()); + initialized_copy_n(values.data(), size_, data_); } /** @@ -600,28 +624,20 @@ template<typename T> class MutableSpan { */ template<typename NewT> MutableSpan<NewT> cast() const { - BLI_assert((m_size * sizeof(T)) % sizeof(NewT) == 0); - uint new_size = m_size * sizeof(T) / sizeof(NewT); - return MutableSpan<NewT>(reinterpret_cast<NewT *>(m_start), new_size); + BLI_assert((size_ * sizeof(T)) % sizeof(NewT) == 0); + int64_t new_size = size_ * sizeof(T) / sizeof(NewT); + return MutableSpan<NewT>(reinterpret_cast<NewT *>(data_), new_size); } }; /** - * Shorthand to make use of automatic template parameter deduction. - */ -template<typename T> Span<T> ref_c_array(const T *array, uint size) -{ - return Span<T>(array, size); -} - -/** * 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) { UNUSED_VARS_NDEBUG(v1, v2); #ifdef DEBUG - uint size = v1.size(); + int64_t size = v1.size(); BLI_assert(size == v1.size()); BLI_assert(size == v2.size()); #endif @@ -632,7 +648,7 @@ void assert_same_size(const T1 &v1, const T2 &v2, const T3 &v3) { UNUSED_VARS_NDEBUG(v1, v2, v3); #ifdef DEBUG - uint size = v1.size(); + int64_t size = v1.size(); BLI_assert(size == v1.size()); BLI_assert(size == v2.size()); BLI_assert(size == v3.size()); |