2019-09-12 14:23:21 +02:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2020-04-21 17:31:56 +02:00
|
|
|
#ifndef __BLI_ARRAY_REF_HH__
|
|
|
|
#define __BLI_ARRAY_REF_HH__
|
2019-09-13 21:12:26 +10:00
|
|
|
|
2019-09-12 14:23:21 +02:00
|
|
|
/** \file
|
|
|
|
* \ingroup bli
|
|
|
|
*
|
2020-06-09 10:10:56 +02:00
|
|
|
* A `BLI::ArrayRef<T>` references an array that is owned by someone else. It is just a pointer and
|
|
|
|
* a size. Since the memory is not owned, ArrayRef should not be used to transfer ownership. The
|
|
|
|
* array cannot be modified through the ArrayRef. However, if T is a non-const pointer, the
|
|
|
|
* pointed-to elements can be modified.
|
2019-09-12 14:23:21 +02:00
|
|
|
*
|
2020-06-09 10:10:56 +02:00
|
|
|
* There is also `BLI::MutableArrayRef<T>`. It is mostly the same as ArrayRef, but allows the array
|
|
|
|
* to be modified.
|
2019-09-12 14:23:21 +02:00
|
|
|
*
|
2020-06-09 10:10:56 +02:00
|
|
|
* An (Mutable)ArrayRef can refer to data owned by many different data structures including
|
|
|
|
* BLI::Vector, BLI::Array, BLI::VectorSet, std::vector, std::array, std::string,
|
|
|
|
* std::initializer_list and c-style array.
|
|
|
|
*
|
|
|
|
* `BLI::ArrayRef<T>` should be your default choice when you have to pass a read-only array into a
|
|
|
|
* function. It is better than passing a `const Vector &`, because then the function only works for
|
|
|
|
* vectors and not for e.g. arrays. Using ArrayRef as function parameter makes it usable in more
|
|
|
|
* contexts, better expresses the intent and does not sacrifice performance. It is also better than
|
|
|
|
* passing a raw pointer and size separately, because it is more convenient and safe.
|
|
|
|
*
|
|
|
|
* `BLI::MutableArrayRef<T>` can be used when a function is supposed to return an array, the size
|
|
|
|
* of which is known before the function is called. One advantage of this approach is that the
|
|
|
|
* caller is responsible for allocation and deallocation. Furthermore, the function can focus on
|
|
|
|
* its task, without having to worry about memory allocation. Alternatively, a function could
|
|
|
|
* return an Array or Vector.
|
|
|
|
*
|
|
|
|
* Note: When a function has a MutableArrayRef<T> output parameter and T is not a trivial type,
|
|
|
|
* then the function has to specify whether the referenced array is expected to be initialized or
|
|
|
|
* not.
|
|
|
|
*
|
|
|
|
* Since the arrays are only referenced, it is generally unsafe to store an ArrayRef. When you
|
|
|
|
* store one, you should know who owns the memory.
|
|
|
|
*
|
|
|
|
* Instances of ArrayRef and MutableArrayRef are small and should be passed by value.
|
2019-09-12 14:23:21 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <algorithm>
|
2020-03-19 09:33:03 +01:00
|
|
|
#include <array>
|
2019-09-12 14:23:21 +02:00
|
|
|
#include <iostream>
|
|
|
|
#include <string>
|
2020-03-19 09:33:03 +01:00
|
|
|
#include <vector>
|
2019-09-12 14:23:21 +02:00
|
|
|
|
2020-04-21 17:31:56 +02:00
|
|
|
#include "BLI_index_range.hh"
|
|
|
|
#include "BLI_memory_utils.hh"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BLI_utildefines.h"
|
2019-09-12 14:23:21 +02:00
|
|
|
|
|
|
|
namespace BLI {
|
|
|
|
|
|
|
|
/**
|
2020-06-09 10:10:56 +02:00
|
|
|
* References an array of type T that is owned by someone else. The data in the array cannot be
|
|
|
|
* modified.
|
2019-09-12 14:23:21 +02:00
|
|
|
*/
|
|
|
|
template<typename T> class ArrayRef {
|
|
|
|
private:
|
|
|
|
const T *m_start = nullptr;
|
|
|
|
uint m_size = 0;
|
|
|
|
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Create a reference to an empty array.
|
|
|
|
*/
|
|
|
|
ArrayRef() = default;
|
|
|
|
|
|
|
|
ArrayRef(const T *start, uint size) : m_start(start), m_size(size)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-06-09 10:10:56 +02:00
|
|
|
/**
|
|
|
|
* 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:
|
|
|
|
* ArrayRef<int> ref = {1, 2, 3, 4};
|
|
|
|
* call_function_with_array(ref);
|
|
|
|
*/
|
|
|
|
ArrayRef(const std::initializer_list<T> &list) : ArrayRef(list.begin(), (uint)list.size())
|
2019-09-12 14:23:21 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-06-09 10:10:56 +02:00
|
|
|
ArrayRef(const std::vector<T> &vector) : ArrayRef(vector.data(), (uint)vector.size())
|
2019-09-12 14:23:21 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
template<std::size_t N> ArrayRef(const std::array<T, N> &array) : ArrayRef(array.data(), N)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-02-10 13:54:57 +01:00
|
|
|
/**
|
2020-06-09 10:10:56 +02:00
|
|
|
* Support implicit conversions like the ones below:
|
|
|
|
* ArrayRef<T *> -> ArrayRef<const T *>
|
|
|
|
* ArrayRef<Derived *> -> ArrayRef<Base *>
|
2020-02-10 13:54:57 +01:00
|
|
|
*/
|
|
|
|
template<typename U,
|
|
|
|
typename std::enable_if<std::is_convertible<U *, T>::value>::type * = nullptr>
|
2020-06-09 10:10:56 +02:00
|
|
|
ArrayRef(ArrayRef<U *> array) : ArrayRef((T *)array.data(), array.size())
|
2020-02-10 13:54:57 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-09-12 14:23:21 +02:00
|
|
|
/**
|
2020-06-09 10:10:56 +02:00
|
|
|
* Returns a contiguous part of the array. This invokes undefined behavior when the slice does
|
|
|
|
* not stay within the bounds of the array.
|
2019-09-12 14:23:21 +02:00
|
|
|
*/
|
|
|
|
ArrayRef slice(uint start, uint size) const
|
|
|
|
{
|
|
|
|
BLI_assert(start + size <= this->size() || size == 0);
|
|
|
|
return ArrayRef(m_start + start, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
ArrayRef slice(IndexRange range) const
|
|
|
|
{
|
|
|
|
return this->slice(range.start(), range.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-09 10:10:56 +02:00
|
|
|
* Returns a new ArrayRef with n elements removed from the beginning. This invokes undefined
|
|
|
|
* behavior when the array is too small.
|
2019-09-12 14:23:21 +02:00
|
|
|
*/
|
2020-06-09 10:10:56 +02:00
|
|
|
ArrayRef drop_front(uint n) const
|
2019-09-12 14:23:21 +02:00
|
|
|
{
|
|
|
|
BLI_assert(n <= this->size());
|
|
|
|
return this->slice(n, this->size() - n);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-09 10:10:56 +02:00
|
|
|
* Returns a new ArrayRef with n elements removed from the beginning. This invokes undefined
|
|
|
|
* behavior when the array is too small.
|
2019-09-12 14:23:21 +02:00
|
|
|
*/
|
2020-06-09 10:10:56 +02:00
|
|
|
ArrayRef drop_back(uint n) const
|
2019-09-12 14:23:21 +02:00
|
|
|
{
|
|
|
|
BLI_assert(n <= this->size());
|
|
|
|
return this->slice(0, this->size() - n);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-09 10:10:56 +02:00
|
|
|
* Returns a new ArrayRef that only contains the first n elements. This invokes undefined
|
|
|
|
* behavior when the array is too small.
|
2019-09-12 14:23:21 +02:00
|
|
|
*/
|
|
|
|
ArrayRef take_front(uint n) const
|
|
|
|
{
|
|
|
|
BLI_assert(n <= this->size());
|
|
|
|
return this->slice(0, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-09 10:10:56 +02:00
|
|
|
* Returns a new ArrayRef that only contains the last n elements. This invokes undefined
|
|
|
|
* behavior when the array is too small.
|
2019-09-12 14:23:21 +02:00
|
|
|
*/
|
|
|
|
ArrayRef take_back(uint n) const
|
|
|
|
{
|
|
|
|
BLI_assert(n <= this->size());
|
|
|
|
return this->slice(this->size() - n, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-09 10:10:56 +02:00
|
|
|
* Returns the pointer to the beginning of the referenced array. This may be nullptr when the
|
|
|
|
* size is zero.
|
2019-09-12 14:23:21 +02:00
|
|
|
*/
|
2020-06-09 10:10:56 +02:00
|
|
|
const T *data() const
|
2019-09-12 14:23:21 +02:00
|
|
|
{
|
2020-06-09 10:10:56 +02:00
|
|
|
return m_start;
|
2019-09-12 14:23:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const T *begin() const
|
|
|
|
{
|
|
|
|
return m_start;
|
|
|
|
}
|
|
|
|
|
|
|
|
const T *end() const
|
|
|
|
{
|
|
|
|
return m_start + m_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-09 10:10:56 +02:00
|
|
|
* Access an element in the array. This invokes undefined behavior when the index is out of
|
|
|
|
* bounds.
|
2019-09-12 14:23:21 +02:00
|
|
|
*/
|
|
|
|
const T &operator[](uint index) const
|
|
|
|
{
|
|
|
|
BLI_assert(index < m_size);
|
|
|
|
return m_start[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-09 10:10:56 +02:00
|
|
|
* Returns the number of elements in the referenced array.
|
2019-09-12 14:23:21 +02:00
|
|
|
*/
|
|
|
|
uint size() const
|
|
|
|
{
|
|
|
|
return m_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-09 10:10:56 +02:00
|
|
|
* Returns true if the size is zero.
|
2019-09-12 14:23:21 +02:00
|
|
|
*/
|
2020-06-09 10:10:56 +02:00
|
|
|
bool is_empty() const
|
|
|
|
{
|
|
|
|
return m_size == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the number of bytes referenced by this ArrayRef.
|
|
|
|
*/
|
|
|
|
uint size_in_bytes() const
|
2019-09-12 14:23:21 +02:00
|
|
|
{
|
|
|
|
return sizeof(T) * m_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Does a linear search to see of the value is in the array.
|
2020-06-09 10:10:56 +02:00
|
|
|
* Returns true if it is, otherwise false.
|
2019-09-12 14:23:21 +02:00
|
|
|
*/
|
|
|
|
bool contains(const T &value) const
|
|
|
|
{
|
|
|
|
for (const T &element : *this) {
|
|
|
|
if (element == value) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-09 10:10:56 +02:00
|
|
|
* Does a constant time check to see if the pointer points to a value in the referenced array.
|
2019-09-12 14:23:21 +02:00
|
|
|
* Return true if it is, otherwise false.
|
|
|
|
*/
|
|
|
|
bool contains_ptr(const T *ptr) const
|
|
|
|
{
|
|
|
|
return (this->begin() <= ptr) && (ptr < this->end());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Does a linear search to count how often the value is in the array.
|
2019-09-19 13:18:52 +10:00
|
|
|
* Returns the number of occurrences.
|
2019-09-12 14:23:21 +02:00
|
|
|
*/
|
|
|
|
uint count(const T &value) const
|
|
|
|
{
|
|
|
|
uint counter = 0;
|
|
|
|
for (const T &element : *this) {
|
|
|
|
if (element == value) {
|
|
|
|
counter++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return counter;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-09 10:10:56 +02:00
|
|
|
* Return a reference to the first element in the array. This invokes undefined behavior when the
|
|
|
|
* array is empty.
|
2019-09-12 14:23:21 +02:00
|
|
|
*/
|
|
|
|
const T &first() const
|
|
|
|
{
|
|
|
|
BLI_assert(m_size > 0);
|
|
|
|
return m_start[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-09 10:10:56 +02:00
|
|
|
* Returns a reference to the last element in the array. This invokes undefined behavior when the
|
|
|
|
* array is empty.
|
2019-09-12 14:23:21 +02:00
|
|
|
*/
|
|
|
|
const T &last() const
|
|
|
|
{
|
|
|
|
BLI_assert(m_size > 0);
|
|
|
|
return m_start[m_size - 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-09 10:10:56 +02:00
|
|
|
* Returns the element at the given index. If the index is out of range, return the fallback
|
|
|
|
* value.
|
2019-09-12 14:23:21 +02:00
|
|
|
*/
|
|
|
|
T get(uint index, const T &fallback) const
|
|
|
|
{
|
|
|
|
if (index < m_size) {
|
|
|
|
return m_start[index];
|
|
|
|
}
|
|
|
|
return fallback;
|
|
|
|
}
|
|
|
|
|
2020-02-10 13:54:57 +01:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
{
|
|
|
|
/* The size should really be smaller than that. If it is not, the calling code should be
|
|
|
|
* changed. */
|
|
|
|
BLI_assert(m_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]) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-06-09 10:10:56 +02:00
|
|
|
/**
|
|
|
|
* Returns true when this and the other array have an element in common. This should only be
|
|
|
|
* called on small arrays, because it has a running time of O(n*m) where n and m are the sizes of
|
|
|
|
* the arrays.
|
|
|
|
*/
|
2020-02-10 13:54:57 +01:00
|
|
|
bool intersects__linear_search(ArrayRef other) const
|
|
|
|
{
|
|
|
|
/* The size should really be smaller than that. If it is not, the calling code should be
|
|
|
|
* changed. */
|
|
|
|
BLI_assert(m_size < 1000);
|
|
|
|
|
|
|
|
for (uint i = 0; i < m_size; i++) {
|
|
|
|
const T &value = m_start[i];
|
|
|
|
if (other.contains(value)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-06-09 10:10:56 +02:00
|
|
|
/**
|
|
|
|
* Returns the index of the first occurrence of the given value. This invokes undefined behavior
|
|
|
|
* when the value is not in the array.
|
|
|
|
*/
|
2020-02-10 13:54:57 +01:00
|
|
|
uint first_index(const T &search_value) const
|
|
|
|
{
|
|
|
|
int index = this->first_index_try(search_value);
|
|
|
|
BLI_assert(index >= 0);
|
|
|
|
return (uint)index;
|
|
|
|
}
|
|
|
|
|
2020-06-09 10:10:56 +02:00
|
|
|
/**
|
|
|
|
* Returns the index of the first occurrence of the given value or -1 if it does not exist.
|
|
|
|
*/
|
2020-02-10 13:54:57 +01:00
|
|
|
int first_index_try(const T &search_value) const
|
|
|
|
{
|
|
|
|
for (uint i = 0; i < m_size; i++) {
|
|
|
|
if (m_start[i] == search_value) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Utility to make it more convenient to iterate over all indices that can be used with this
|
|
|
|
* array.
|
|
|
|
*/
|
2020-02-07 17:23:25 +01:00
|
|
|
IndexRange index_range() const
|
|
|
|
{
|
|
|
|
return IndexRange(m_size);
|
|
|
|
}
|
|
|
|
|
2019-09-12 14:23:21 +02:00
|
|
|
/**
|
2020-06-09 10:10:56 +02:00
|
|
|
* Returns a new ArrayRef to the same underlying memory buffer. No conversions are done.
|
2019-09-12 14:23:21 +02:00
|
|
|
*/
|
|
|
|
template<typename NewT> ArrayRef<NewT> cast() const
|
|
|
|
{
|
2020-02-10 13:54:57 +01:00
|
|
|
BLI_assert((m_size * sizeof(T)) % sizeof(NewT) == 0);
|
|
|
|
uint new_size = m_size * sizeof(T) / sizeof(NewT);
|
|
|
|
return ArrayRef<NewT>(reinterpret_cast<const NewT *>(m_start), new_size);
|
2019-09-12 14:23:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-09 10:10:56 +02:00
|
|
|
* A debug utility to print the content of the ArrayRef. Every element will be printed on a
|
2019-09-12 14:23:21 +02:00
|
|
|
* separate line using the given callback.
|
|
|
|
*/
|
|
|
|
template<typename PrintLineF> void print_as_lines(std::string name, PrintLineF print_line) const
|
|
|
|
{
|
|
|
|
std::cout << "ArrayRef: " << name << " \tSize:" << m_size << '\n';
|
|
|
|
for (const T &value : *this) {
|
|
|
|
std::cout << " ";
|
|
|
|
print_line(value);
|
|
|
|
std::cout << '\n';
|
|
|
|
}
|
|
|
|
}
|
2020-02-10 13:54:57 +01:00
|
|
|
|
2020-06-09 10:10:56 +02:00
|
|
|
/**
|
|
|
|
* A debug utility to print the content of the array ref. Every element be printed on a separate
|
|
|
|
* line.
|
|
|
|
*/
|
2020-02-10 13:54:57 +01:00
|
|
|
void print_as_lines(std::string name) const
|
|
|
|
{
|
|
|
|
this->print_as_lines(name, [](const T &value) { std::cout << value; });
|
|
|
|
}
|
2019-09-12 14:23:21 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2020-06-09 10:10:56 +02:00
|
|
|
* Mostly the same as ArrayRef, except that one can change the array elements through a
|
|
|
|
* MutableArrayRef.
|
2019-09-12 14:23:21 +02:00
|
|
|
*/
|
|
|
|
template<typename T> class MutableArrayRef {
|
|
|
|
private:
|
|
|
|
T *m_start;
|
|
|
|
uint m_size;
|
|
|
|
|
|
|
|
public:
|
|
|
|
MutableArrayRef() = default;
|
|
|
|
|
|
|
|
MutableArrayRef(T *start, uint size) : m_start(start), m_size(size)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-06-09 10:10:56 +02:00
|
|
|
/**
|
|
|
|
* 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:
|
|
|
|
* MutableArrayRef<int> ref = {1, 2, 3, 4};
|
|
|
|
* call_function_with_array(ref);
|
|
|
|
*/
|
2019-09-12 14:23:21 +02:00
|
|
|
MutableArrayRef(std::initializer_list<T> &list) : MutableArrayRef(list.begin(), list.size())
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
MutableArrayRef(std::vector<T> &vector) : MutableArrayRef(vector.data(), vector.size())
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
template<std::size_t N>
|
|
|
|
MutableArrayRef(std::array<T, N> &array) : MutableArrayRef(array.data(), N)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-02-10 13:54:57 +01:00
|
|
|
operator ArrayRef<T>() const
|
2019-09-12 14:23:21 +02:00
|
|
|
{
|
|
|
|
return ArrayRef<T>(m_start, m_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-09 10:10:56 +02:00
|
|
|
* Returns the number of elements in the array.
|
2019-09-12 14:23:21 +02:00
|
|
|
*/
|
|
|
|
uint size() const
|
|
|
|
{
|
|
|
|
return m_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Replace all elements in the referenced array with the given value.
|
|
|
|
*/
|
2020-06-09 10:10:56 +02:00
|
|
|
void fill(const T &value)
|
2019-09-12 14:23:21 +02:00
|
|
|
{
|
2020-06-09 10:10:56 +02:00
|
|
|
initialized_fill_n(m_start, m_size, value);
|
2019-09-12 14:23:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-09 10:10:56 +02:00
|
|
|
* Replace a subset of all elements with the given value. This invokes undefined behavior when
|
|
|
|
* one of the indices is out of bounds.
|
2019-09-12 14:23:21 +02:00
|
|
|
*/
|
2020-06-09 10:10:56 +02:00
|
|
|
void fill_indices(ArrayRef<uint> indices, const T &value)
|
2019-09-12 14:23:21 +02:00
|
|
|
{
|
|
|
|
for (uint i : indices) {
|
2020-06-09 10:10:56 +02:00
|
|
|
BLI_assert(i < m_size);
|
|
|
|
m_start[i] = value;
|
2019-09-12 14:23:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-09 10:10:56 +02:00
|
|
|
* Returns a pointer to the beginning of the referenced array. This may be nullptr, when the size
|
|
|
|
* is zero.
|
2019-09-12 14:23:21 +02:00
|
|
|
*/
|
2020-06-09 10:10:56 +02:00
|
|
|
T *data() const
|
2019-09-12 14:23:21 +02:00
|
|
|
{
|
2020-06-09 10:10:56 +02:00
|
|
|
return m_start;
|
2019-09-12 14:23:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
T *begin() const
|
|
|
|
{
|
|
|
|
return m_start;
|
|
|
|
}
|
|
|
|
|
|
|
|
T *end() const
|
|
|
|
{
|
|
|
|
return m_start + m_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
T &operator[](uint index) const
|
|
|
|
{
|
|
|
|
BLI_assert(index < this->size());
|
|
|
|
return m_start[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-09 10:10:56 +02:00
|
|
|
* Returns a contiguous part of the array. This invokes undefined behavior when the slice would
|
|
|
|
* go out of bounds.
|
2019-09-12 14:23:21 +02:00
|
|
|
*/
|
|
|
|
MutableArrayRef slice(uint start, uint length) const
|
|
|
|
{
|
|
|
|
BLI_assert(start + length <= this->size());
|
|
|
|
return MutableArrayRef(m_start + start, length);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-09 10:10:56 +02:00
|
|
|
* Returns a new MutableArrayRef with n elements removed from the beginning. This invokes
|
|
|
|
* undefined behavior when the array is too small.
|
2019-09-12 14:23:21 +02:00
|
|
|
*/
|
2020-06-09 10:10:56 +02:00
|
|
|
MutableArrayRef drop_front(uint n) const
|
2019-09-12 14:23:21 +02:00
|
|
|
{
|
|
|
|
BLI_assert(n <= this->size());
|
|
|
|
return this->slice(n, this->size() - n);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-09 10:10:56 +02:00
|
|
|
* Returns a new MutableArrayRef with n elements removed from the end. This invokes undefined
|
|
|
|
* behavior when the array is too small.
|
2019-09-12 14:23:21 +02:00
|
|
|
*/
|
2020-06-09 10:10:56 +02:00
|
|
|
MutableArrayRef drop_back(uint n) const
|
2019-09-12 14:23:21 +02:00
|
|
|
{
|
|
|
|
BLI_assert(n <= this->size());
|
|
|
|
return this->slice(0, this->size() - n);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-09 10:10:56 +02:00
|
|
|
* Returns a new MutableArrayRef that only contains the first n elements. This invokes undefined
|
|
|
|
* behavior when the array is too small.
|
2019-09-12 14:23:21 +02:00
|
|
|
*/
|
|
|
|
MutableArrayRef take_front(uint n) const
|
|
|
|
{
|
|
|
|
BLI_assert(n <= this->size());
|
|
|
|
return this->slice(0, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-09 10:10:56 +02:00
|
|
|
* Return a new MutableArrayRef that only contains the last n elements. This invokes undefined
|
|
|
|
* behavior when the array is too small.
|
2019-09-12 14:23:21 +02:00
|
|
|
*/
|
|
|
|
MutableArrayRef take_back(uint n) const
|
|
|
|
{
|
|
|
|
BLI_assert(n <= this->size());
|
|
|
|
return this->slice(this->size() - n, n);
|
|
|
|
}
|
|
|
|
|
2020-06-09 10:10:56 +02:00
|
|
|
/**
|
|
|
|
* Returns an (immutable) ArrayRef that references the same array. This is usually not needed,
|
|
|
|
* due to implicit conversions. However, sometimes automatic type deduction needs some help.
|
|
|
|
*/
|
2019-09-12 14:23:21 +02:00
|
|
|
ArrayRef<T> as_ref() const
|
|
|
|
{
|
|
|
|
return ArrayRef<T>(m_start, m_size);
|
|
|
|
}
|
2020-02-07 17:23:25 +01:00
|
|
|
|
2020-06-09 10:10:56 +02:00
|
|
|
/**
|
|
|
|
* Utility to make it more convenient to iterate over all indices that can be used with this
|
|
|
|
* array.
|
|
|
|
*/
|
2020-02-07 17:23:25 +01:00
|
|
|
IndexRange index_range() const
|
|
|
|
{
|
|
|
|
return IndexRange(m_size);
|
|
|
|
}
|
2020-02-10 13:54:57 +01:00
|
|
|
|
2020-06-09 10:10:56 +02:00
|
|
|
/**
|
|
|
|
* Returns a reference to the last element. This invokes undefined behavior when the array is
|
|
|
|
* empty.
|
|
|
|
*/
|
2020-02-10 13:54:57 +01:00
|
|
|
const T &last() const
|
|
|
|
{
|
|
|
|
BLI_assert(m_size > 0);
|
|
|
|
return m_start[m_size - 1];
|
|
|
|
}
|
2020-05-07 14:21:26 +02:00
|
|
|
|
|
|
|
/**
|
2020-06-09 10:10:56 +02:00
|
|
|
* Returns a new array ref to the same underlying memory buffer. No conversions are done.
|
2020-05-07 14:21:26 +02:00
|
|
|
*/
|
|
|
|
template<typename NewT> MutableArrayRef<NewT> cast() const
|
|
|
|
{
|
|
|
|
BLI_assert((m_size * sizeof(T)) % sizeof(NewT) == 0);
|
|
|
|
uint new_size = m_size * sizeof(T) / sizeof(NewT);
|
|
|
|
return MutableArrayRef<NewT>(reinterpret_cast<NewT *>(m_start), new_size);
|
|
|
|
}
|
2019-09-12 14:23:21 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Shorthand to make use of automatic template parameter deduction.
|
|
|
|
*/
|
|
|
|
template<typename T> ArrayRef<T> ref_c_array(const T *array, uint size)
|
|
|
|
{
|
|
|
|
return ArrayRef<T>(array, size);
|
|
|
|
}
|
|
|
|
|
2020-06-09 10:10:56 +02:00
|
|
|
/**
|
|
|
|
* Utilities to check that arrays have the same size in debug builds.
|
|
|
|
*/
|
2020-02-10 13:54:57 +01:00
|
|
|
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();
|
|
|
|
BLI_assert(size == v1.size());
|
|
|
|
BLI_assert(size == v2.size());
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T1, typename T2, typename T3>
|
|
|
|
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();
|
|
|
|
BLI_assert(size == v1.size());
|
|
|
|
BLI_assert(size == v2.size());
|
|
|
|
BLI_assert(size == v3.size());
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-09-12 14:23:21 +02:00
|
|
|
} /* namespace BLI */
|
2019-09-13 21:12:26 +10:00
|
|
|
|
2020-04-21 17:31:56 +02:00
|
|
|
#endif /* __BLI_ARRAY_REF_HH__ */
|