BLI: rename ArrayRef to Span

This also renames `MutableArrayRef` to `MutableSpan`.
The name "Span" works better, because `std::span` will provide
similar functionality in C++20. Furthermore, a shorter, more
concise name for a common data structure is nice.
This commit is contained in:
Jacques Lucke 2020-06-09 11:58:47 +02:00
parent 7d2b4ae9c6
commit f7c0f1b8b8
28 changed files with 511 additions and 501 deletions

View File

@ -27,11 +27,11 @@
#include "DNA_scene_types.h"
#include "DNA_simulation_types.h"
#include "BLI_array_ref.hh"
#include "BLI_compiler_compat.h"
#include "BLI_float3.hh"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_span.hh"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@ -54,9 +54,9 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
using blender::ArrayRef;
using blender::float3;
using blender::MutableArrayRef;
using blender::MutableSpan;
using blender::Span;
static void simulation_init_data(ID *id)
{
@ -168,9 +168,9 @@ void *BKE_simulation_add(Main *bmain, const char *name)
return simulation;
}
static MutableArrayRef<float3> get_particle_positions(ParticleSimulationState *state)
static MutableSpan<float3> get_particle_positions(ParticleSimulationState *state)
{
return MutableArrayRef<float3>(
return MutableSpan<float3>(
(float3 *)CustomData_get_layer_named(&state->attributes, CD_LOCATION, "Position"),
state->tot_particles);
}
@ -239,7 +239,7 @@ void BKE_simulation_data_update(Depsgraph *depsgraph, Scene *scene, Simulation *
CustomData_realloc(&state_orig->attributes, state_orig->tot_particles);
ensure_attributes_exist(state_orig);
MutableArrayRef<float3> positions = get_particle_positions(state_orig);
MutableSpan<float3> positions = get_particle_positions(state_orig);
for (uint i : positions.index_range()) {
positions[i] = {i / 10.0f, 0, 0};
}
@ -250,7 +250,7 @@ void BKE_simulation_data_update(Depsgraph *depsgraph, Scene *scene, Simulation *
else if (current_frame == state_orig->current_frame + 1) {
state_orig->current_frame = current_frame;
ensure_attributes_exist(state_orig);
MutableArrayRef<float3> positions = get_particle_positions(state_orig);
MutableSpan<float3> positions = get_particle_positions(state_orig);
for (float3 &position : positions) {
position.z += 0.1f;
}

View File

@ -39,9 +39,9 @@
*/
#include "BLI_allocator.hh"
#include "BLI_array_ref.hh"
#include "BLI_index_range.hh"
#include "BLI_memory_utils.hh"
#include "BLI_span.hh"
#include "BLI_utildefines.h"
namespace blender {
@ -90,7 +90,7 @@ class Array {
/**
* Create a new array that contains copies of all values.
*/
Array(ArrayRef<T> values)
Array(Span<T> values)
{
m_size = values.size();
m_data = this->get_buffer_for_size(values.size());
@ -100,7 +100,7 @@ class Array {
/**
* Create a new array that contains copies of all values.
*/
Array(const std::initializer_list<T> &values) : Array(ArrayRef<T>(values))
Array(const std::initializer_list<T> &values) : Array(Span<T>(values))
{
}
@ -184,22 +184,22 @@ class Array {
return *this;
}
operator ArrayRef<T>() const
operator Span<T>() const
{
return ArrayRef<T>(m_data, m_size);
return Span<T>(m_data, m_size);
}
operator MutableArrayRef<T>()
operator MutableSpan<T>()
{
return MutableArrayRef<T>(m_data, m_size);
return MutableSpan<T>(m_data, m_size);
}
ArrayRef<T> as_ref() const
Span<T> as_span() const
{
return *this;
}
MutableArrayRef<T> as_mutable_ref()
MutableSpan<T> as_mutable_span()
{
return *this;
}
@ -243,9 +243,9 @@ class Array {
/**
* Copies the value to the given indices in the array.
*/
void fill_indices(ArrayRef<uint> indices, const T &value)
void fill_indices(Span<uint> indices, const T &value)
{
MutableArrayRef<T>(*this).fill_indices(indices, value);
MutableSpan<T>(*this).fill_indices(indices, value);
}
/**

View File

@ -267,8 +267,8 @@ class NodeWithSocketsRef {
public:
NodeWithSocketsRef(Node &node,
StringRef name,
ArrayRef<std::string> input_names,
ArrayRef<std::string> output_names);
Span<std::string> input_names,
Span<std::string> output_names);
NodePort input(uint index) const
{

View File

@ -38,15 +38,15 @@
* same time.
*/
#include "BLI_array_ref.hh"
#include "BLI_index_range.hh"
#include "BLI_span.hh"
namespace blender {
class IndexMask {
private:
/* The underlying reference to sorted integers. */
ArrayRef<uint> m_indices;
Span<uint> m_indices;
public:
/* Creates an IndexMask that contains no indices. */
@ -57,7 +57,7 @@ class IndexMask {
* This constructor asserts that the given integers are in ascending order and that there are no
* duplicates.
*/
IndexMask(ArrayRef<uint> indices) : m_indices(indices)
IndexMask(Span<uint> indices) : m_indices(indices)
{
#ifdef DEBUG
for (uint i = 1; i < indices.size(); i++) {
@ -70,7 +70,7 @@ class IndexMask {
* Use this method when you know that no indices are skipped. It is more efficient than preparing
* an integer array all the time.
*/
IndexMask(IndexRange range) : m_indices(range.as_array_ref())
IndexMask(IndexRange range) : m_indices(range.as_span())
{
}
@ -84,7 +84,7 @@ class IndexMask {
* Do this:
* do_something_with_an_index_mask({3, 4, 5});
*/
IndexMask(const std::initializer_list<uint> &indices) : IndexMask(ArrayRef<uint>(indices))
IndexMask(const std::initializer_list<uint> &indices) : IndexMask(Span<uint>(indices))
{
}
@ -95,7 +95,7 @@ class IndexMask {
{
}
operator ArrayRef<uint>() const
operator Span<uint>() const
{
return m_indices;
}
@ -133,7 +133,7 @@ class IndexMask {
}
}
ArrayRef<uint> indices() const
Span<uint> indices() const
{
return m_indices;
}

View File

@ -49,7 +49,7 @@
* Ideally this could be could be even closer to Python's enumerate(). We might get that in the
* future with newer C++ versions.
*
* One other important feature is the as_array_ref method. This method returns an ArrayRef<uint>
* One other important feature is the as_span method. This method returns an Span<uint>
* that contains the interval as individual numbers.
*/
@ -66,7 +66,7 @@ template<typename Value> class blocked_range;
namespace blender {
template<typename T> class ArrayRef;
template<typename T> class Span;
class IndexRange {
private:
@ -227,7 +227,7 @@ class IndexRange {
/**
* Get read-only access to a memory buffer that contains the range as actual numbers.
*/
ArrayRef<uint> as_array_ref() const;
Span<uint> as_span() const;
friend std::ostream &operator<<(std::ostream &stream, IndexRange range)
{

View File

@ -35,7 +35,7 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
private:
Allocator m_allocator;
Vector<void *> m_owned_buffers;
Vector<ArrayRef<char>> m_unused_borrowed_buffers;
Vector<Span<char>> m_unused_borrowed_buffers;
uintptr_t m_current_begin;
uintptr_t m_current_end;
@ -104,9 +104,9 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
*
* This method only allocates memory and does not construct the instance.
*/
template<typename T> MutableArrayRef<T> allocate_array(uint size)
template<typename T> MutableSpan<T> allocate_array(uint size)
{
return MutableArrayRef<T>((T *)this->allocate(sizeof(T) * size, alignof(T)), size);
return MutableSpan<T>((T *)this->allocate(sizeof(T) * size, alignof(T)), size);
}
/**
@ -127,9 +127,9 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
/**
* Copy the given array into a memory buffer provided by this allocator.
*/
template<typename T> MutableArrayRef<T> construct_array_copy(ArrayRef<T> src)
template<typename T> MutableSpan<T> construct_array_copy(Span<T> src)
{
MutableArrayRef<T> dst = this->allocate_array<T>(src.size());
MutableSpan<T> dst = this->allocate_array<T>(src.size());
uninitialized_copy_n(src.data(), src.size(), dst.data());
return dst;
}
@ -146,14 +146,14 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
return StringRefNull((const char *)buffer);
}
MutableArrayRef<void *> allocate_elements_and_pointer_array(uint element_amount,
uint element_size,
uint element_alignment)
MutableSpan<void *> allocate_elements_and_pointer_array(uint element_amount,
uint element_size,
uint element_alignment)
{
void *pointer_buffer = this->allocate(element_amount * sizeof(void *), alignof(void *));
void *elements_buffer = this->allocate(element_amount * element_size, element_alignment);
MutableArrayRef<void *> pointers((void **)pointer_buffer, element_amount);
MutableSpan<void *> pointers((void **)pointer_buffer, element_amount);
void *next_element_buffer = elements_buffer;
for (uint i : IndexRange(element_amount)) {
pointers[i] = next_element_buffer;
@ -164,11 +164,11 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
}
template<typename T, typename... Args>
ArrayRef<T *> construct_elements_and_pointer_array(uint n, Args &&... args)
Span<T *> construct_elements_and_pointer_array(uint n, Args &&... args)
{
MutableArrayRef<void *> void_pointers = this->allocate_elements_and_pointer_array(
MutableSpan<void *> void_pointers = this->allocate_elements_and_pointer_array(
n, sizeof(T), alignof(T));
MutableArrayRef<T *> pointers = void_pointers.cast<T *>();
MutableSpan<T *> pointers = void_pointers.cast<T *>();
for (uint i : IndexRange(n)) {
new (pointers[i]) T(std::forward<Args>(args)...);
@ -183,7 +183,7 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
*/
void provide_buffer(void *buffer, uint size)
{
m_unused_borrowed_buffers.append(ArrayRef<char>((char *)buffer, size));
m_unused_borrowed_buffers.append(Span<char>((char *)buffer, size));
}
template<size_t Size, size_t Alignment>
@ -196,7 +196,7 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
void allocate_new_buffer(uint min_allocation_size)
{
for (uint i : m_unused_borrowed_buffers.index_range()) {
ArrayRef<char> buffer = m_unused_borrowed_buffers[i];
Span<char> buffer = m_unused_borrowed_buffers[i];
if (buffer.size() >= min_allocation_size) {
m_unused_borrowed_buffers.remove_and_reorder(i);
m_current_begin = (uintptr_t)buffer.begin();

View File

@ -276,7 +276,7 @@ class Set {
* We might be able to make this faster than sequentially adding all keys, but that is not
* implemented yet.
*/
void add_multiple(ArrayRef<Key> keys)
void add_multiple(Span<Key> keys)
{
for (const Key &key : keys) {
this->add(key);
@ -287,7 +287,7 @@ class Set {
* Convenience function to add many new keys to the set at once. The keys must not exist in the
* set before and there must not be duplicates in the array.
*/
void add_multiple_new(ArrayRef<Key> keys)
void add_multiple_new(Span<Key> keys)
{
for (const Key &key : keys) {
this->add_new(key);
@ -726,7 +726,7 @@ template<typename Key> class StdUnorderedSetWrapper {
return m_set.insert(std::move(key)).second;
}
void add_multiple(ArrayRef<Key> keys)
void add_multiple(Span<Key> keys)
{
for (const Key &key : keys) {
m_set.insert(key);

View File

@ -14,44 +14,59 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __BLI_ARRAY_REF_HH__
#define __BLI_ARRAY_REF_HH__
#ifndef __BLI_SPAN_HH__
#define __BLI_SPAN_HH__
/** \file
* \ingroup bli
*
* An `blender::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
* An `blender::Span<T>` references an array that is owned by someone else. It is just a
* pointer and a size. Since the memory is not owned, Span should not be used to transfer
* ownership. The array cannot be modified through the Span. However, if T is a non-const
* pointer, the pointed-to elements can be modified.
*
* There is also `blender::MutableArrayRef<T>`. It is mostly the same as ArrayRef, but allows the
* There is also `blender::MutableSpan<T>`. It is mostly the same as Span, but allows the
* array to be modified.
*
* An (Mutable)ArrayRef can refer to data owned by many different data structures including
* A (Mutable)Span can refer to data owned by many different data structures including
* blender::Vector, blender::Array, blender::VectorSet, std::vector, std::array, std::string,
* std::initializer_list and c-style array.
*
* `blender::ArrayRef<T>` should be your default choice when you have to pass a read-only array
* `blender::Span` is very similar to `std::span` (C++20). However, there are a few differences:
* - `blender::Span` is const by default. This is to avoid making things mutable when they don't
* have to be. To get a non-const span, you need to use `blender::MutableSpan`. Below is a list
* of const-behavior-equivalent pairs of data structures:
* - std::span<int> <==> blender::MutableSpan<int>
* - std::span<const int> <==> blender::Span<int>
* - std::span<int *> <==> blender::MutableSpan<int *>
* - std::span<const int *> <==> blender::MutableSpan<const int *>
* - std::span<int * const> <==> blender::Span<int *>
* - std::span<const int * const> <==> blender::Span<const int *>
* - `blender::Span` always has a dynamic extent, while `std::span` can have a size that is
* determined at compile time. I did not have a use case for that yet. If we need it, we can
* decide to add this functionality to `blender::Span` or introduce a new type like
* `blender::FixedSpan<T, N>`.
*
* `blender::Span<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
* works for vectors and not for e.g. arrays. Using Span 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.
*
* `blender::MutableArrayRef<T>` can be used when a function is supposed to return an array, the
* `blender::MutableSpan<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,
* Note: When a function has a MutableSpan<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
* Since the arrays are only referenced, it is generally unsafe to store an Span. When you
* store one, you should know who owns the memory.
*
* Instances of ArrayRef and MutableArrayRef are small and should be passed by value.
* Instances of Span and MutableSpan are small and should be passed by value.
*/
#include <algorithm>
@ -70,7 +85,7 @@ namespace blender {
* References an array of type T that is owned by someone else. The data in the array cannot be
* modified.
*/
template<typename T> class ArrayRef {
template<typename T> class Span {
private:
const T *m_start = nullptr;
uint m_size = 0;
@ -79,9 +94,9 @@ template<typename T> class ArrayRef {
/**
* Create a reference to an empty array.
*/
ArrayRef() = default;
Span() = default;
ArrayRef(const T *start, uint size) : m_start(start), m_size(size)
Span(const T *start, uint size) : m_start(start), m_size(size)
{
}
@ -93,29 +108,29 @@ template<typename T> class ArrayRef {
* call_function_with_array({1, 2, 3, 4});
*
* Don't:
* ArrayRef<int> ref = {1, 2, 3, 4};
* call_function_with_array(ref);
* Span<int> span = {1, 2, 3, 4};
* call_function_with_array(span);
*/
ArrayRef(const std::initializer_list<T> &list) : ArrayRef(list.begin(), (uint)list.size())
Span(const std::initializer_list<T> &list) : Span(list.begin(), (uint)list.size())
{
}
ArrayRef(const std::vector<T> &vector) : ArrayRef(vector.data(), (uint)vector.size())
Span(const std::vector<T> &vector) : Span(vector.data(), (uint)vector.size())
{
}
template<std::size_t N> ArrayRef(const std::array<T, N> &array) : ArrayRef(array.data(), N)
template<std::size_t N> Span(const std::array<T, N> &array) : Span(array.data(), N)
{
}
/**
* Support implicit conversions like the ones below:
* ArrayRef<T *> -> ArrayRef<const T *>
* ArrayRef<Derived *> -> ArrayRef<Base *>
* Span<T *> -> Span<const T *>
* Span<Derived *> -> Span<Base *>
*/
template<typename U,
typename std::enable_if<std::is_convertible<U *, T>::value>::type * = nullptr>
ArrayRef(ArrayRef<U *> array) : ArrayRef((T *)array.data(), array.size())
Span(Span<U *> array) : Span((T *)array.data(), array.size())
{
}
@ -123,52 +138,52 @@ template<typename T> class ArrayRef {
* Returns a contiguous part of the array. This invokes undefined behavior when the slice does
* not stay within the bounds of the array.
*/
ArrayRef slice(uint start, uint size) const
Span slice(uint start, uint size) const
{
BLI_assert(start + size <= this->size() || size == 0);
return ArrayRef(m_start + start, size);
return Span(m_start + start, size);
}
ArrayRef slice(IndexRange range) const
Span slice(IndexRange range) const
{
return this->slice(range.start(), range.size());
}
/**
* Returns a new ArrayRef with n elements removed from the beginning. This invokes undefined
* Returns a new Span with n elements removed from the beginning. This invokes undefined
* behavior when the array is too small.
*/
ArrayRef drop_front(uint n) const
Span drop_front(uint n) const
{
BLI_assert(n <= this->size());
return this->slice(n, this->size() - n);
}
/**
* Returns a new ArrayRef with n elements removed from the beginning. This invokes undefined
* Returns a new Span with n elements removed from the beginning. This invokes undefined
* behavior when the array is too small.
*/
ArrayRef drop_back(uint n) const
Span drop_back(uint n) const
{
BLI_assert(n <= this->size());
return this->slice(0, this->size() - n);
}
/**
* Returns a new ArrayRef that only contains the first n elements. This invokes undefined
* Returns a new Span that only contains the first n elements. This invokes undefined
* behavior when the array is too small.
*/
ArrayRef take_front(uint n) const
Span take_front(uint n) const
{
BLI_assert(n <= this->size());
return this->slice(0, n);
}
/**
* Returns a new ArrayRef that only contains the last n elements. This invokes undefined
* Returns a new Span that only contains the last n elements. This invokes undefined
* behavior when the array is too small.
*/
ArrayRef take_back(uint n) const
Span take_back(uint n) const
{
BLI_assert(n <= this->size());
return this->slice(this->size() - n, n);
@ -220,7 +235,7 @@ template<typename T> class ArrayRef {
}
/**
* Returns the number of bytes referenced by this ArrayRef.
* Returns the number of bytes referenced by this Span.
*/
uint size_in_bytes() const
{
@ -323,7 +338,7 @@ template<typename T> class ArrayRef {
* 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(ArrayRef other) const
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. */
@ -372,22 +387,22 @@ template<typename T> class ArrayRef {
}
/**
* Returns a new ArrayRef to the same underlying memory buffer. No conversions are done.
* Returns a new Span to the same underlying memory buffer. No conversions are done.
*/
template<typename NewT> ArrayRef<NewT> cast() const
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 ArrayRef<NewT>(reinterpret_cast<const NewT *>(m_start), new_size);
return Span<NewT>(reinterpret_cast<const NewT *>(m_start), new_size);
}
/**
* A debug utility to print the content of the ArrayRef. Every element will be printed on a
* A debug utility to print the content of the Span. Every element will be printed on a
* 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';
std::cout << "Span: " << name << " \tSize:" << m_size << '\n';
for (const T &value : *this) {
std::cout << " ";
print_line(value);
@ -396,7 +411,7 @@ template<typename T> class ArrayRef {
}
/**
* A debug utility to print the content of the array ref. Every element be printed on a separate
* A debug utility to print the content of the span. Every element be printed on a separate
* line.
*/
void print_as_lines(std::string name) const
@ -406,18 +421,18 @@ template<typename T> class ArrayRef {
};
/**
* Mostly the same as ArrayRef, except that one can change the array elements through a
* MutableArrayRef.
* Mostly the same as Span, except that one can change the array elements through a
* MutableSpan.
*/
template<typename T> class MutableArrayRef {
template<typename T> class MutableSpan {
private:
T *m_start;
uint m_size;
public:
MutableArrayRef() = default;
MutableSpan() = default;
MutableArrayRef(T *start, uint size) : m_start(start), m_size(size)
MutableSpan(T *start, uint size) : m_start(start), m_size(size)
{
}
@ -429,25 +444,24 @@ template<typename T> class MutableArrayRef {
* call_function_with_array({1, 2, 3, 4});
*
* Don't:
* MutableArrayRef<int> ref = {1, 2, 3, 4};
* call_function_with_array(ref);
* MutableSpan<int> span = {1, 2, 3, 4};
* call_function_with_array(span);
*/
MutableArrayRef(std::initializer_list<T> &list) : MutableArrayRef(list.begin(), list.size())
MutableSpan(std::initializer_list<T> &list) : MutableSpan(list.begin(), list.size())
{
}
MutableArrayRef(std::vector<T> &vector) : MutableArrayRef(vector.data(), vector.size())
MutableSpan(std::vector<T> &vector) : MutableSpan(vector.data(), vector.size())
{
}
template<std::size_t N>
MutableArrayRef(std::array<T, N> &array) : MutableArrayRef(array.data(), N)
template<std::size_t N> MutableSpan(std::array<T, N> &array) : MutableSpan(array.data(), N)
{
}
operator ArrayRef<T>() const
operator Span<T>() const
{
return ArrayRef<T>(m_start, m_size);
return Span<T>(m_start, m_size);
}
/**
@ -470,7 +484,7 @@ template<typename T> class MutableArrayRef {
* 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(ArrayRef<uint> indices, const T &value)
void fill_indices(Span<uint> indices, const T &value)
{
for (uint i : indices) {
BLI_assert(i < m_size);
@ -507,59 +521,59 @@ template<typename T> class MutableArrayRef {
* Returns a contiguous part of the array. This invokes undefined behavior when the slice would
* go out of bounds.
*/
MutableArrayRef slice(uint start, uint length) const
MutableSpan slice(uint start, uint length) const
{
BLI_assert(start + length <= this->size());
return MutableArrayRef(m_start + start, length);
return MutableSpan(m_start + start, length);
}
/**
* Returns a new MutableArrayRef with n elements removed from the beginning. This invokes
* Returns a new MutableSpan with n elements removed from the beginning. This invokes
* undefined behavior when the array is too small.
*/
MutableArrayRef drop_front(uint n) const
MutableSpan drop_front(uint n) const
{
BLI_assert(n <= this->size());
return this->slice(n, this->size() - n);
}
/**
* Returns a new MutableArrayRef with n elements removed from the end. This invokes undefined
* Returns a new MutableSpan with n elements removed from the end. This invokes undefined
* behavior when the array is too small.
*/
MutableArrayRef drop_back(uint n) const
MutableSpan drop_back(uint n) const
{
BLI_assert(n <= this->size());
return this->slice(0, this->size() - n);
}
/**
* Returns a new MutableArrayRef that only contains the first n elements. This invokes undefined
* Returns a new MutableSpan that only contains the first n elements. This invokes undefined
* behavior when the array is too small.
*/
MutableArrayRef take_front(uint n) const
MutableSpan take_front(uint n) const
{
BLI_assert(n <= this->size());
return this->slice(0, n);
}
/**
* Return a new MutableArrayRef that only contains the last n elements. This invokes undefined
* Return a new MutableSpan that only contains the last n elements. This invokes undefined
* behavior when the array is too small.
*/
MutableArrayRef take_back(uint n) const
MutableSpan take_back(uint n) const
{
BLI_assert(n <= this->size());
return this->slice(this->size() - n, n);
}
/**
* Returns an (immutable) ArrayRef that references the same array. This is usually not needed,
* 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.
*/
ArrayRef<T> as_ref() const
Span<T> as_span() const
{
return ArrayRef<T>(m_start, m_size);
return Span<T>(m_start, m_size);
}
/**
@ -582,22 +596,22 @@ template<typename T> class MutableArrayRef {
}
/**
* Returns a new array ref to the same underlying memory buffer. No conversions are done.
* Returns a new span to the same underlying memory buffer. No conversions are done.
*/
template<typename NewT> MutableArrayRef<NewT> cast() const
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 MutableArrayRef<NewT>(reinterpret_cast<NewT *>(m_start), new_size);
return MutableSpan<NewT>(reinterpret_cast<NewT *>(m_start), new_size);
}
};
/**
* Shorthand to make use of automatic template parameter deduction.
*/
template<typename T> ArrayRef<T> ref_c_array(const T *array, uint size)
template<typename T> Span<T> ref_c_array(const T *array, uint size)
{
return ArrayRef<T>(array, size);
return Span<T>(array, size);
}
/**
@ -627,4 +641,4 @@ void assert_same_size(const T1 &v1, const T2 &v2, const T3 &v3)
} /* namespace blender */
#endif /* __BLI_ARRAY_REF_HH__ */
#endif /* __BLI_SPAN_HH__ */

View File

@ -41,8 +41,8 @@
*/
#include "BLI_allocator.hh"
#include "BLI_array_ref.hh"
#include "BLI_memory_utils.hh"
#include "BLI_span.hh"
namespace blender {
@ -139,7 +139,7 @@ class Stack {
* Create a new stack that contains the given elements. The values are pushed to the stack in
* the order they are in the array.
*/
Stack(ArrayRef<T> values) : Stack()
Stack(Span<T> values) : Stack()
{
this->push_multiple(values);
}
@ -153,7 +153,7 @@ class Stack {
* assert(stack.pop() == 6);
* assert(stack.pop() == 5);
*/
Stack(const std::initializer_list<T> &values) : Stack(ArrayRef<T>(values))
Stack(const std::initializer_list<T> &values) : Stack(Span<T>(values))
{
}
@ -162,7 +162,7 @@ class Stack {
for (const Chunk *chunk = &other.m_inline_chunk; chunk; chunk = chunk->above) {
const T *begin = chunk->begin;
const T *end = (chunk == other.m_top_chunk) ? other.m_top : chunk->capacity_end;
this->push_multiple(ArrayRef<T>(begin, end - begin));
this->push_multiple(Span<T>(begin, end - begin));
}
}
@ -289,9 +289,9 @@ class Stack {
* This method is more efficient than pushing multiple elements individually and might cause less
* heap allocations.
*/
void push_multiple(ArrayRef<T> values)
void push_multiple(Span<T> values)
{
ArrayRef<T> remaining_values = values;
Span<T> remaining_values = values;
while (!remaining_values.is_empty()) {
if (m_top == m_top_chunk->capacity_end) {
this->activate_next_chunk(remaining_values.size());

View File

@ -46,7 +46,7 @@
#include <sstream>
#include <string>
#include "BLI_array_ref.hh"
#include "BLI_span.hh"
#include "BLI_utildefines.h"
namespace blender {
@ -83,9 +83,9 @@ class StringRefBase {
return m_data;
}
operator ArrayRef<char>() const
operator Span<char>() const
{
return ArrayRef<char>(m_data, m_size);
return Span<char>(m_data, m_size);
}
/**

View File

@ -44,11 +44,11 @@
#include <memory>
#include "BLI_allocator.hh"
#include "BLI_array_ref.hh"
#include "BLI_index_range.hh"
#include "BLI_listbase_wrapper.hh"
#include "BLI_math_base.h"
#include "BLI_memory_utils.hh"
#include "BLI_span.hh"
#include "BLI_string.h"
#include "BLI_string_ref.hh"
#include "BLI_utildefines.h"
@ -152,14 +152,14 @@ class Vector {
* This allows you to write code like:
* Vector<int> vec = {3, 4, 5};
*/
Vector(const std::initializer_list<T> &values) : Vector(ArrayRef<T>(values))
Vector(const std::initializer_list<T> &values) : Vector(Span<T>(values))
{
}
/**
* Create a vector from an array ref. The values in the vector are copy constructed.
*/
Vector(ArrayRef<T> values) : Vector()
Vector(Span<T> values) : Vector()
{
uint size = values.size();
this->reserve(size);
@ -263,22 +263,22 @@ class Vector {
}
}
operator ArrayRef<T>() const
operator Span<T>() const
{
return ArrayRef<T>(m_begin, this->size());
return Span<T>(m_begin, this->size());
}
operator MutableArrayRef<T>()
operator MutableSpan<T>()
{
return MutableArrayRef<T>(m_begin, this->size());
return MutableSpan<T>(m_begin, this->size());
}
ArrayRef<T> as_ref() const
Span<T> as_span() const
{
return *this;
}
MutableArrayRef<T> as_mutable_ref()
MutableSpan<T> as_mutable_span()
{
return *this;
}
@ -478,7 +478,7 @@ class Vector {
*
* This can be used to emulate parts of std::vector::insert.
*/
void extend(ArrayRef<T> array)
void extend(Span<T> array)
{
this->extend(array.data(), array.size());
}
@ -493,7 +493,7 @@ class Vector {
* operation when the vector is large, but can be very cheap when it is known that the vector is
* small.
*/
void extend_non_duplicates(ArrayRef<T> array)
void extend_non_duplicates(Span<T> array)
{
for (const T &value : array) {
this->append_non_duplicates(value);
@ -504,7 +504,7 @@ class Vector {
* Extend the vector without bounds checking. It is assumed that enough memory has been reserved
* beforehand. Only use this in performance critical code.
*/
void extend_unchecked(ArrayRef<T> array)
void extend_unchecked(Span<T> array)
{
this->extend_unchecked(array.data(), array.size());
}
@ -542,9 +542,9 @@ class Vector {
/**
* Copy the value to all positions specified by the indices array.
*/
void fill_indices(ArrayRef<uint> indices, const T &value)
void fill_indices(Span<uint> indices, const T &value)
{
MutableArrayRef<T>(*this).fill_indices(indices, value);
MutableSpan<T>(*this).fill_indices(indices, value);
}
/**

View File

@ -32,7 +32,7 @@
* - The insertion order is important.
* - Iteration over all keys has to be fast.
* - The keys in the set are supposed to be passed to a function that does not have to know that
* the keys are stored in a set. With a VectorSet, one can get an ArrayRef containing all keys
* the keys are stored in a set. With a VectorSet, one can get a Span containing all keys
* without additional copies.
*
* blender::VectorSet is implemented using open addressing in a slot array with a power-of-two
@ -279,7 +279,7 @@ class VectorSet {
* We might be able to make this faster than sequentially adding all keys, but that is not
* implemented yet.
*/
void add_multiple(ArrayRef<Key> keys)
void add_multiple(Span<Key> keys)
{
for (const Key &key : keys) {
this->add(key);
@ -411,18 +411,18 @@ class VectorSet {
return m_keys[index];
}
operator ArrayRef<Key>() const
operator Span<Key>() const
{
return ArrayRef<Key>(m_keys, this->size());
return Span<Key>(m_keys, this->size());
}
/**
* Get an ArrayRef referencing the keys vector. The referenced memory buffer is only valid as
* Get an Span referencing the keys vector. The referenced memory buffer is only valid as
* long as the vector set is not changed.
*
* The keys must not be changed, because this would change their hash value.
*/
ArrayRef<Key> as_ref() const
Span<Key> as_span() const
{
return *this;
}
@ -432,7 +432,7 @@ class VectorSet {
*/
void print_stats(StringRef name = "") const
{
HashTableStats stats(*this, this->as_ref());
HashTableStats stats(*this, this->as_span());
stats.print();
}

View File

@ -144,7 +144,6 @@ set(SRC
BLI_args.h
BLI_array.h
BLI_array.hh
BLI_array_ref.hh
BLI_array_store.h
BLI_array_store_utils.h
BLI_array_utils.h
@ -240,6 +239,7 @@ set(SRC
BLI_smallhash.h
BLI_sort.h
BLI_sort_utils.h
BLI_span.hh
BLI_stack.h
BLI_stack.hh
BLI_strict_flags.h

View File

@ -18,8 +18,8 @@
#include <mutex>
#include "BLI_array.hh"
#include "BLI_array_ref.hh"
#include "BLI_index_range.hh"
#include "BLI_span.hh"
#include "BLI_vector.hh"
namespace blender {
@ -29,18 +29,18 @@ static uint current_array_size = 0;
static uint *current_array = nullptr;
static std::mutex current_array_mutex;
ArrayRef<uint> IndexRange::as_array_ref() const
Span<uint> IndexRange::as_span() const
{
uint min_required_size = m_start + m_size;
if (min_required_size <= current_array_size) {
return ArrayRef<uint>(current_array + m_start, m_size);
return Span<uint>(current_array + m_start, m_size);
}
std::lock_guard<std::mutex> lock(current_array_mutex);
if (min_required_size <= current_array_size) {
return ArrayRef<uint>(current_array + m_start, m_size);
return Span<uint>(current_array + m_start, m_size);
}
uint new_size = std::max<uint>(1000, power_of_2_max_u(min_required_size));
@ -54,7 +54,7 @@ ArrayRef<uint> IndexRange::as_array_ref() const
std::atomic_thread_fence(std::memory_order_seq_cst);
current_array_size = new_size;
return ArrayRef<uint>(current_array + m_start, m_size);
return Span<uint>(current_array + m_start, m_size);
}
} // namespace blender

View File

@ -250,8 +250,8 @@ std::string color_attr_from_hsv(float h, float s, float v)
NodeWithSocketsRef::NodeWithSocketsRef(Node &node,
StringRef name,
ArrayRef<std::string> input_names,
ArrayRef<std::string> output_names)
Span<std::string> input_names,
Span<std::string> output_names)
: m_node(&node)
{
std::stringstream ss;

View File

@ -49,7 +49,7 @@ void unregister_graph(Depsgraph *depsgraph)
}
}
ArrayRef<Depsgraph *> get_all_registered_graphs(Main *bmain)
Span<Depsgraph *> get_all_registered_graphs(Main *bmain)
{
VectorSet<Depsgraph *> *graphs = g_graph_registry.lookup_ptr(bmain);
if (graphs != nullptr) {

View File

@ -33,6 +33,6 @@ struct Depsgraph;
void register_graph(Depsgraph *depsgraph);
void unregister_graph(Depsgraph *depsgraph);
ArrayRef<Depsgraph *> get_all_registered_graphs(Main *bmain);
Span<Depsgraph *> get_all_registered_graphs(Main *bmain);
} // namespace DEG

View File

@ -53,9 +53,9 @@ struct CustomData_MeshMasks;
namespace DEG {
/* Commonly used types. */
using blender::ArrayRef;
using blender::Map;
using blender::Set;
using blender::Span;
using blender::StringRef;
using blender::StringRefNull;
using blender::Vector;

View File

@ -67,10 +67,10 @@
#include "BLI_vector.hh"
using blender::Array;
using blender::ArrayRef;
using blender::IndexRange;
using blender::ListBaseWrapper;
using blender::MutableArrayRef;
using blender::MutableSpan;
using blender::Span;
using blender::Vector;
static void requiredDataMask(Object *UNUSED(ob),
@ -104,7 +104,7 @@ static void compute_vertex_mask__armature_mode(MDeformVert *dvert,
Object *ob,
Object *armature_ob,
float threshold,
MutableArrayRef<bool> r_vertex_mask)
MutableSpan<bool> r_vertex_mask)
{
/* Element i is true if there is a selected bone that uses vertex group i. */
Vector<bool> selected_bone_uses_group;
@ -115,10 +115,10 @@ static void compute_vertex_mask__armature_mode(MDeformVert *dvert,
selected_bone_uses_group.append(bone_for_group_exists);
}
ArrayRef<bool> use_vertex_group = selected_bone_uses_group;
Span<bool> use_vertex_group = selected_bone_uses_group;
for (int i : r_vertex_mask.index_range()) {
ArrayRef<MDeformWeight> weights(dvert[i].dw, dvert[i].totweight);
Span<MDeformWeight> weights(dvert[i].dw, dvert[i].totweight);
r_vertex_mask[i] = false;
/* check the groups that vertex is assigned to, and see if it was any use */
@ -137,7 +137,7 @@ static void compute_vertex_mask__armature_mode(MDeformVert *dvert,
static void compute_vertex_mask__vertex_group_mode(MDeformVert *dvert,
int defgrp_index,
float threshold,
MutableArrayRef<bool> r_vertex_mask)
MutableSpan<bool> r_vertex_mask)
{
for (int i : r_vertex_mask.index_range()) {
const bool found = BKE_defvert_find_weight(&dvert[i], defgrp_index) > threshold;
@ -145,15 +145,15 @@ static void compute_vertex_mask__vertex_group_mode(MDeformVert *dvert,
}
}
static void invert_boolean_array(MutableArrayRef<bool> array)
static void invert_boolean_array(MutableSpan<bool> array)
{
for (bool &value : array) {
value = !value;
}
}
static void compute_masked_vertices(ArrayRef<bool> vertex_mask,
MutableArrayRef<int> r_vertex_map,
static void compute_masked_vertices(Span<bool> vertex_mask,
MutableSpan<int> r_vertex_map,
uint *r_num_masked_vertices)
{
BLI_assert(vertex_mask.size() == r_vertex_map.size());
@ -173,8 +173,8 @@ static void compute_masked_vertices(ArrayRef<bool> vertex_mask,
}
static void computed_masked_edges(const Mesh *mesh,
ArrayRef<bool> vertex_mask,
MutableArrayRef<int> r_edge_map,
Span<bool> vertex_mask,
MutableSpan<int> r_edge_map,
uint *r_num_masked_edges)
{
BLI_assert(mesh->totedge == r_edge_map.size());
@ -197,7 +197,7 @@ static void computed_masked_edges(const Mesh *mesh,
}
static void computed_masked_polygons(const Mesh *mesh,
ArrayRef<bool> vertex_mask,
Span<bool> vertex_mask,
Vector<int> &r_masked_poly_indices,
Vector<int> &r_loop_starts,
uint *r_num_masked_polys,
@ -213,7 +213,7 @@ static void computed_masked_polygons(const Mesh *mesh,
const MPoly &poly_src = mesh->mpoly[i];
bool all_verts_in_mask = true;
ArrayRef<MLoop> loops_src(&mesh->mloop[poly_src.loopstart], poly_src.totloop);
Span<MLoop> loops_src(&mesh->mloop[poly_src.loopstart], poly_src.totloop);
for (const MLoop &loop : loops_src) {
if (!vertex_mask[loop.v]) {
all_verts_in_mask = false;
@ -234,7 +234,7 @@ static void computed_masked_polygons(const Mesh *mesh,
static void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh,
Mesh &dst_mesh,
ArrayRef<int> vertex_map)
Span<int> vertex_map)
{
BLI_assert(src_mesh.totvert == vertex_map.size());
for (const int i_src : vertex_map.index_range()) {
@ -253,8 +253,8 @@ static void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh,
static void copy_masked_edges_to_new_mesh(const Mesh &src_mesh,
Mesh &dst_mesh,
ArrayRef<int> vertex_map,
ArrayRef<int> edge_map)
Span<int> vertex_map,
Span<int> edge_map)
{
BLI_assert(src_mesh.totvert == vertex_map.size());
BLI_assert(src_mesh.totedge == edge_map.size());
@ -276,10 +276,10 @@ static void copy_masked_edges_to_new_mesh(const Mesh &src_mesh,
static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
Mesh &dst_mesh,
ArrayRef<int> vertex_map,
ArrayRef<int> edge_map,
ArrayRef<int> masked_poly_indices,
ArrayRef<int> new_loop_starts)
Span<int> vertex_map,
Span<int> edge_map,
Span<int> masked_poly_indices,
Span<int> new_loop_starts)
{
for (const int i_dst : masked_poly_indices.index_range()) {
const int i_src = masked_poly_indices[i_dst];

View File

@ -1,288 +0,0 @@
#include "BLI_array_ref.hh"
#include "BLI_strict_flags.h"
#include "BLI_vector.hh"
#include "testing/testing.h"
using namespace blender;
using IntVector = blender::Vector<int>;
using IntArrayRef = blender::ArrayRef<int>;
using MutableIntArrayRef = blender::MutableArrayRef<int>;
TEST(array_ref, FromSmallVector)
{
IntVector a = {1, 2, 3};
IntArrayRef a_ref = a;
EXPECT_EQ(a_ref.size(), 3);
EXPECT_EQ(a_ref[0], 1);
EXPECT_EQ(a_ref[1], 2);
EXPECT_EQ(a_ref[2], 3);
}
TEST(array_ref, AddConstToPointer)
{
int a = 0;
std::vector<int *> vec = {&a};
ArrayRef<int *> ref = vec;
ArrayRef<const int *> const_ref = ref;
EXPECT_EQ(const_ref.size(), 1);
}
TEST(array_ref, IsReferencing)
{
int array[] = {3, 5, 8};
MutableIntArrayRef ref(array, ARRAY_SIZE(array));
EXPECT_EQ(ref.size(), 3);
EXPECT_EQ(ref[1], 5);
array[1] = 10;
EXPECT_EQ(ref[1], 10);
}
TEST(array_ref, DropBack)
{
IntVector a = {4, 5, 6, 7};
auto slice = IntArrayRef(a).drop_back(2);
EXPECT_EQ(slice.size(), 2);
EXPECT_EQ(slice[0], 4);
EXPECT_EQ(slice[1], 5);
}
TEST(array_ref, DropBackAll)
{
IntVector a = {4, 5, 6, 7};
auto slice = IntArrayRef(a).drop_back(a.size());
EXPECT_EQ(slice.size(), 0);
}
TEST(array_ref, DropFront)
{
IntVector a = {4, 5, 6, 7};
auto slice = IntArrayRef(a).drop_front(1);
EXPECT_EQ(slice.size(), 3);
EXPECT_EQ(slice[0], 5);
EXPECT_EQ(slice[1], 6);
EXPECT_EQ(slice[2], 7);
}
TEST(array_ref, DropFrontAll)
{
IntVector a = {4, 5, 6, 7};
auto slice = IntArrayRef(a).drop_front(a.size());
EXPECT_EQ(slice.size(), 0);
}
TEST(array_ref, TakeFront)
{
IntVector a = {4, 5, 6, 7};
auto slice = IntArrayRef(a).take_front(2);
EXPECT_EQ(slice.size(), 2);
EXPECT_EQ(slice[0], 4);
EXPECT_EQ(slice[1], 5);
}
TEST(array_ref, TakeBack)
{
IntVector a = {5, 6, 7, 8};
auto slice = IntArrayRef(a).take_back(2);
EXPECT_EQ(slice.size(), 2);
EXPECT_EQ(slice[0], 7);
EXPECT_EQ(slice[1], 8);
}
TEST(array_ref, Slice)
{
IntVector a = {4, 5, 6, 7};
auto slice = IntArrayRef(a).slice(1, 2);
EXPECT_EQ(slice.size(), 2);
EXPECT_EQ(slice[0], 5);
EXPECT_EQ(slice[1], 6);
}
TEST(array_ref, SliceEmpty)
{
IntVector a = {4, 5, 6, 7};
auto slice = IntArrayRef(a).slice(2, 0);
EXPECT_EQ(slice.size(), 0);
}
TEST(array_ref, SliceRange)
{
IntVector a = {1, 2, 3, 4, 5};
auto slice = IntArrayRef(a).slice(IndexRange(2, 2));
EXPECT_EQ(slice.size(), 2);
EXPECT_EQ(slice[0], 3);
EXPECT_EQ(slice[1], 4);
}
TEST(array_ref, Contains)
{
IntVector a = {4, 5, 6, 7};
IntArrayRef a_ref = a;
EXPECT_TRUE(a_ref.contains(4));
EXPECT_TRUE(a_ref.contains(5));
EXPECT_TRUE(a_ref.contains(6));
EXPECT_TRUE(a_ref.contains(7));
EXPECT_FALSE(a_ref.contains(3));
EXPECT_FALSE(a_ref.contains(8));
}
TEST(array_ref, Count)
{
IntVector a = {2, 3, 4, 3, 3, 2, 2, 2, 2};
IntArrayRef a_ref = a;
EXPECT_EQ(a_ref.count(1), 0);
EXPECT_EQ(a_ref.count(2), 5);
EXPECT_EQ(a_ref.count(3), 3);
EXPECT_EQ(a_ref.count(4), 1);
EXPECT_EQ(a_ref.count(5), 0);
}
static void test_ref_from_initializer_list(IntArrayRef ref)
{
EXPECT_EQ(ref.size(), 4);
EXPECT_EQ(ref[0], 3);
EXPECT_EQ(ref[1], 6);
EXPECT_EQ(ref[2], 8);
EXPECT_EQ(ref[3], 9);
}
TEST(array_ref, FromInitializerList)
{
test_ref_from_initializer_list({3, 6, 8, 9});
}
TEST(array_ref, FromVector)
{
std::vector<int> a = {1, 2, 3, 4};
IntArrayRef a_ref(a);
EXPECT_EQ(a_ref.size(), 4);
EXPECT_EQ(a_ref[0], 1);
EXPECT_EQ(a_ref[1], 2);
EXPECT_EQ(a_ref[2], 3);
EXPECT_EQ(a_ref[3], 4);
}
TEST(array_ref, FromArray)
{
std::array<int, 2> a = {5, 6};
IntArrayRef a_ref(a);
EXPECT_EQ(a_ref.size(), 2);
EXPECT_EQ(a_ref[0], 5);
EXPECT_EQ(a_ref[1], 6);
}
TEST(array_ref, Fill)
{
std::array<int, 5> a = {4, 5, 6, 7, 8};
MutableIntArrayRef a_ref(a);
a_ref.fill(1);
EXPECT_EQ(a[0], 1);
EXPECT_EQ(a[1], 1);
EXPECT_EQ(a[2], 1);
EXPECT_EQ(a[3], 1);
EXPECT_EQ(a[4], 1);
}
TEST(array_ref, FillIndices)
{
std::array<int, 5> a = {0, 0, 0, 0, 0};
MutableIntArrayRef a_ref(a);
a_ref.fill_indices({0, 2, 3}, 1);
EXPECT_EQ(a[0], 1);
EXPECT_EQ(a[1], 0);
EXPECT_EQ(a[2], 1);
EXPECT_EQ(a[3], 1);
EXPECT_EQ(a[4], 0);
}
TEST(array_ref, SizeInBytes)
{
std::array<int, 10> a;
IntArrayRef a_ref(a);
EXPECT_EQ(a_ref.size_in_bytes(), sizeof(a));
EXPECT_EQ(a_ref.size_in_bytes(), 40);
}
TEST(array_ref, FirstLast)
{
std::array<int, 4> a = {6, 7, 8, 9};
IntArrayRef a_ref(a);
EXPECT_EQ(a_ref.first(), 6);
EXPECT_EQ(a_ref.last(), 9);
}
TEST(array_ref, FirstLast_OneElement)
{
int a = 3;
IntArrayRef a_ref(&a, 1);
EXPECT_EQ(a_ref.first(), 3);
EXPECT_EQ(a_ref.last(), 3);
}
TEST(array_ref, Get)
{
std::array<int, 3> a = {5, 6, 7};
IntArrayRef a_ref(a);
EXPECT_EQ(a_ref.get(0, 42), 5);
EXPECT_EQ(a_ref.get(1, 42), 6);
EXPECT_EQ(a_ref.get(2, 42), 7);
EXPECT_EQ(a_ref.get(3, 42), 42);
EXPECT_EQ(a_ref.get(4, 42), 42);
}
TEST(array_ref, ContainsPtr)
{
std::array<int, 3> a = {5, 6, 7};
int other = 10;
IntArrayRef a_ref(a);
EXPECT_TRUE(a_ref.contains_ptr(&a[0] + 0));
EXPECT_TRUE(a_ref.contains_ptr(&a[0] + 1));
EXPECT_TRUE(a_ref.contains_ptr(&a[0] + 2));
EXPECT_FALSE(a_ref.contains_ptr(&a[0] + 3));
EXPECT_FALSE(a_ref.contains_ptr(&a[0] - 1));
EXPECT_FALSE(a_ref.contains_ptr(&other));
}
TEST(array_ref, FirstIndex)
{
std::array<int, 5> a = {4, 5, 4, 2, 5};
IntArrayRef a_ref(a);
EXPECT_EQ(a_ref.first_index(4), 0);
EXPECT_EQ(a_ref.first_index(5), 1);
EXPECT_EQ(a_ref.first_index(2), 3);
}
TEST(array_ref, CastSameSize)
{
int value = 0;
std::array<int *, 4> a = {&value, nullptr, nullptr, nullptr};
ArrayRef<int *> a_ref = a;
ArrayRef<float *> new_a_ref = a_ref.cast<float *>();
EXPECT_EQ(a_ref.size(), 4);
EXPECT_EQ(new_a_ref.size(), 4);
EXPECT_EQ(a_ref[0], &value);
EXPECT_EQ(new_a_ref[0], (float *)&value);
}
TEST(array_ref, CastSmallerSize)
{
std::array<uint32_t, 4> a = {3, 4, 5, 6};
ArrayRef<uint32_t> a_ref = a;
ArrayRef<uint16_t> new_a_ref = a_ref.cast<uint16_t>();
EXPECT_EQ(a_ref.size(), 4);
EXPECT_EQ(new_a_ref.size(), 8);
}
TEST(array_ref, CastLargerSize)
{
std::array<uint16_t, 4> a = {4, 5, 6, 7};
ArrayRef<uint16_t> a_ref = a;
ArrayRef<uint32_t> new_a_ref = a_ref.cast<uint32_t>();
EXPECT_EQ(a_ref.size(), 4);
EXPECT_EQ(new_a_ref.size(), 2);
}

View File

@ -39,11 +39,11 @@ TEST(array, InitializerListConstructor)
EXPECT_EQ(array[3], 7);
}
TEST(array, ArrayRefConstructor)
TEST(array, SpanConstructor)
{
int stackarray[4] = {6, 7, 8, 9};
ArrayRef<int> array_ref(stackarray, ARRAY_SIZE(stackarray));
Array<int> array(array_ref);
Span<int> span(stackarray, ARRAY_SIZE(stackarray));
Array<int> array(span);
EXPECT_EQ(array.size(), 4);
EXPECT_EQ(array[0], 6);
EXPECT_EQ(array[1], 7);

View File

@ -32,7 +32,7 @@ TEST(index_mask, RangeConstructor)
EXPECT_TRUE(mask.is_range());
EXPECT_EQ(mask.as_range().first(), 3);
EXPECT_EQ(mask.as_range().last(), 7);
ArrayRef<uint> indices = mask.indices();
Span<uint> indices = mask.indices();
EXPECT_EQ(indices[0], 3);
EXPECT_EQ(indices[1], 4);
EXPECT_EQ(indices[2], 5);

View File

@ -127,13 +127,13 @@ TEST(index_range, SliceRange)
EXPECT_EQ(slice.last(), 12);
}
TEST(index_range, AsArrayRef)
TEST(index_range, AsSpan)
{
IndexRange range = IndexRange(4, 6);
ArrayRef<uint> ref = range.as_array_ref();
EXPECT_EQ(ref.size(), 6);
EXPECT_EQ(ref[0], 4);
EXPECT_EQ(ref[1], 5);
EXPECT_EQ(ref[2], 6);
EXPECT_EQ(ref[3], 7);
Span<uint> span = range.as_span();
EXPECT_EQ(span.size(), 6);
EXPECT_EQ(span[0], 4);
EXPECT_EQ(span[1], 5);
EXPECT_EQ(span[2], 6);
EXPECT_EQ(span[3], 7);
}

View File

@ -67,8 +67,8 @@ TEST(linear_allocator, AllocateArray)
{
LinearAllocator<> allocator;
MutableArrayRef<int> array = allocator.allocate_array<int>(5);
EXPECT_EQ(array.size(), 5);
MutableSpan<int> span = allocator.allocate_array<int>(5);
EXPECT_EQ(span.size(), 5);
}
TEST(linear_allocator, Construct)
@ -87,7 +87,7 @@ TEST(linear_allocator, ConstructElementsAndPointerArray)
LinearAllocator<> allocator;
std::array<int, 7> values = {1, 2, 3, 4, 5, 6, 7};
ArrayRef<Vector<int> *> vectors = allocator.construct_elements_and_pointer_array<Vector<int>>(
Span<Vector<int> *> vectors = allocator.construct_elements_and_pointer_array<Vector<int>>(
5, values);
EXPECT_EQ(vectors.size(), 5);
@ -104,11 +104,11 @@ TEST(linear_allocator, ConstructArrayCopy)
LinearAllocator<> allocator;
Vector<int> values = {1, 2, 3};
MutableArrayRef<int> array1 = allocator.construct_array_copy(values.as_ref());
MutableArrayRef<int> array2 = allocator.construct_array_copy(values.as_ref());
EXPECT_NE(array1.data(), array2.data());
EXPECT_EQ(array1.size(), 3);
EXPECT_EQ(array2.size(), 3);
EXPECT_EQ(array1[1], 2);
EXPECT_EQ(array2[2], 3);
MutableSpan<int> span1 = allocator.construct_array_copy(values.as_span());
MutableSpan<int> span2 = allocator.construct_array_copy(values.as_span());
EXPECT_NE(span1.data(), span2.data());
EXPECT_EQ(span1.size(), 3);
EXPECT_EQ(span2.size(), 3);
EXPECT_EQ(span1[1], 2);
EXPECT_EQ(span2[2], 3);
}

View File

@ -0,0 +1,284 @@
#include "BLI_span.hh"
#include "BLI_strict_flags.h"
#include "BLI_vector.hh"
#include "testing/testing.h"
using namespace blender;
TEST(array_ref, FromSmallVector)
{
Vector<int> a = {1, 2, 3};
Span<int> a_span = a;
EXPECT_EQ(a_span.size(), 3);
EXPECT_EQ(a_span[0], 1);
EXPECT_EQ(a_span[1], 2);
EXPECT_EQ(a_span[2], 3);
}
TEST(array_ref, AddConstToPointer)
{
int a = 0;
std::vector<int *> vec = {&a};
Span<int *> span = vec;
Span<const int *> const_span = span;
EXPECT_EQ(const_span.size(), 1);
}
TEST(array_ref, IsReferencing)
{
int array[] = {3, 5, 8};
MutableSpan<int> span(array, ARRAY_SIZE(array));
EXPECT_EQ(span.size(), 3);
EXPECT_EQ(span[1], 5);
array[1] = 10;
EXPECT_EQ(span[1], 10);
}
TEST(array_ref, DropBack)
{
Vector<int> a = {4, 5, 6, 7};
auto slice = Span<int>(a).drop_back(2);
EXPECT_EQ(slice.size(), 2);
EXPECT_EQ(slice[0], 4);
EXPECT_EQ(slice[1], 5);
}
TEST(array_ref, DropBackAll)
{
Vector<int> a = {4, 5, 6, 7};
auto slice = Span<int>(a).drop_back(a.size());
EXPECT_EQ(slice.size(), 0);
}
TEST(array_ref, DropFront)
{
Vector<int> a = {4, 5, 6, 7};
auto slice = Span<int>(a).drop_front(1);
EXPECT_EQ(slice.size(), 3);
EXPECT_EQ(slice[0], 5);
EXPECT_EQ(slice[1], 6);
EXPECT_EQ(slice[2], 7);
}
TEST(array_ref, DropFrontAll)
{
Vector<int> a = {4, 5, 6, 7};
auto slice = Span<int>(a).drop_front(a.size());
EXPECT_EQ(slice.size(), 0);
}
TEST(array_ref, TakeFront)
{
Vector<int> a = {4, 5, 6, 7};
auto slice = Span<int>(a).take_front(2);
EXPECT_EQ(slice.size(), 2);
EXPECT_EQ(slice[0], 4);
EXPECT_EQ(slice[1], 5);
}
TEST(array_ref, TakeBack)
{
Vector<int> a = {5, 6, 7, 8};
auto slice = Span<int>(a).take_back(2);
EXPECT_EQ(slice.size(), 2);
EXPECT_EQ(slice[0], 7);
EXPECT_EQ(slice[1], 8);
}
TEST(array_ref, Slice)
{
Vector<int> a = {4, 5, 6, 7};
auto slice = Span<int>(a).slice(1, 2);
EXPECT_EQ(slice.size(), 2);
EXPECT_EQ(slice[0], 5);
EXPECT_EQ(slice[1], 6);
}
TEST(array_ref, SliceEmpty)
{
Vector<int> a = {4, 5, 6, 7};
auto slice = Span<int>(a).slice(2, 0);
EXPECT_EQ(slice.size(), 0);
}
TEST(array_ref, SliceRange)
{
Vector<int> a = {1, 2, 3, 4, 5};
auto slice = Span<int>(a).slice(IndexRange(2, 2));
EXPECT_EQ(slice.size(), 2);
EXPECT_EQ(slice[0], 3);
EXPECT_EQ(slice[1], 4);
}
TEST(array_ref, Contains)
{
Vector<int> a = {4, 5, 6, 7};
Span<int> a_span = a;
EXPECT_TRUE(a_span.contains(4));
EXPECT_TRUE(a_span.contains(5));
EXPECT_TRUE(a_span.contains(6));
EXPECT_TRUE(a_span.contains(7));
EXPECT_FALSE(a_span.contains(3));
EXPECT_FALSE(a_span.contains(8));
}
TEST(array_ref, Count)
{
Vector<int> a = {2, 3, 4, 3, 3, 2, 2, 2, 2};
Span<int> a_span = a;
EXPECT_EQ(a_span.count(1), 0);
EXPECT_EQ(a_span.count(2), 5);
EXPECT_EQ(a_span.count(3), 3);
EXPECT_EQ(a_span.count(4), 1);
EXPECT_EQ(a_span.count(5), 0);
}
static void test_ref_from_initializer_list(Span<int> span)
{
EXPECT_EQ(span.size(), 4);
EXPECT_EQ(span[0], 3);
EXPECT_EQ(span[1], 6);
EXPECT_EQ(span[2], 8);
EXPECT_EQ(span[3], 9);
}
TEST(array_ref, FromInitializerList)
{
test_ref_from_initializer_list({3, 6, 8, 9});
}
TEST(array_ref, FromVector)
{
std::vector<int> a = {1, 2, 3, 4};
Span<int> a_span(a);
EXPECT_EQ(a_span.size(), 4);
EXPECT_EQ(a_span[0], 1);
EXPECT_EQ(a_span[1], 2);
EXPECT_EQ(a_span[2], 3);
EXPECT_EQ(a_span[3], 4);
}
TEST(array_ref, FromArray)
{
std::array<int, 2> a = {5, 6};
Span<int> a_span(a);
EXPECT_EQ(a_span.size(), 2);
EXPECT_EQ(a_span[0], 5);
EXPECT_EQ(a_span[1], 6);
}
TEST(array_ref, Fill)
{
std::array<int, 5> a = {4, 5, 6, 7, 8};
MutableSpan<int> a_span(a);
a_span.fill(1);
EXPECT_EQ(a[0], 1);
EXPECT_EQ(a[1], 1);
EXPECT_EQ(a[2], 1);
EXPECT_EQ(a[3], 1);
EXPECT_EQ(a[4], 1);
}
TEST(array_ref, FillIndices)
{
std::array<int, 5> a = {0, 0, 0, 0, 0};
MutableSpan<int> a_span(a);
a_span.fill_indices({0, 2, 3}, 1);
EXPECT_EQ(a[0], 1);
EXPECT_EQ(a[1], 0);
EXPECT_EQ(a[2], 1);
EXPECT_EQ(a[3], 1);
EXPECT_EQ(a[4], 0);
}
TEST(array_ref, SizeInBytes)
{
std::array<int, 10> a;
Span<int> a_span(a);
EXPECT_EQ(a_span.size_in_bytes(), sizeof(a));
EXPECT_EQ(a_span.size_in_bytes(), 40);
}
TEST(array_ref, FirstLast)
{
std::array<int, 4> a = {6, 7, 8, 9};
Span<int> a_span(a);
EXPECT_EQ(a_span.first(), 6);
EXPECT_EQ(a_span.last(), 9);
}
TEST(array_ref, FirstLast_OneElement)
{
int a = 3;
Span<int> a_span(&a, 1);
EXPECT_EQ(a_span.first(), 3);
EXPECT_EQ(a_span.last(), 3);
}
TEST(array_ref, Get)
{
std::array<int, 3> a = {5, 6, 7};
Span<int> a_span(a);
EXPECT_EQ(a_span.get(0, 42), 5);
EXPECT_EQ(a_span.get(1, 42), 6);
EXPECT_EQ(a_span.get(2, 42), 7);
EXPECT_EQ(a_span.get(3, 42), 42);
EXPECT_EQ(a_span.get(4, 42), 42);
}
TEST(array_ref, ContainsPtr)
{
std::array<int, 3> a = {5, 6, 7};
int other = 10;
Span<int> a_span(a);
EXPECT_TRUE(a_span.contains_ptr(&a[0] + 0));
EXPECT_TRUE(a_span.contains_ptr(&a[0] + 1));
EXPECT_TRUE(a_span.contains_ptr(&a[0] + 2));
EXPECT_FALSE(a_span.contains_ptr(&a[0] + 3));
EXPECT_FALSE(a_span.contains_ptr(&a[0] - 1));
EXPECT_FALSE(a_span.contains_ptr(&other));
}
TEST(array_ref, FirstIndex)
{
std::array<int, 5> a = {4, 5, 4, 2, 5};
Span<int> a_span(a);
EXPECT_EQ(a_span.first_index(4), 0);
EXPECT_EQ(a_span.first_index(5), 1);
EXPECT_EQ(a_span.first_index(2), 3);
}
TEST(array_ref, CastSameSize)
{
int value = 0;
std::array<int *, 4> a = {&value, nullptr, nullptr, nullptr};
Span<int *> a_span = a;
Span<float *> new_a_span = a_span.cast<float *>();
EXPECT_EQ(a_span.size(), 4);
EXPECT_EQ(new_a_span.size(), 4);
EXPECT_EQ(a_span[0], &value);
EXPECT_EQ(new_a_span[0], (float *)&value);
}
TEST(array_ref, CastSmallerSize)
{
std::array<uint32_t, 4> a = {3, 4, 5, 6};
Span<uint32_t> a_span = a;
Span<uint16_t> new_a_span = a_span.cast<uint16_t>();
EXPECT_EQ(a_span.size(), 4);
EXPECT_EQ(new_a_span.size(), 8);
}
TEST(array_ref, CastLargerSize)
{
std::array<uint16_t, 4> a = {4, 5, 6, 7};
Span<uint16_t> a_span = a;
Span<uint32_t> new_a_span = a_span.cast<uint32_t>();
EXPECT_EQ(a_span.size(), 4);
EXPECT_EQ(new_a_span.size(), 2);
}

View File

@ -12,7 +12,7 @@ TEST(stack, DefaultConstructor)
EXPECT_TRUE(stack.is_empty());
}
TEST(stack, ArrayRefConstructor)
TEST(stack, SpanConstructor)
{
std::array<int, 3> array = {4, 7, 2};
Stack<int> stack(array);

View File

@ -408,17 +408,17 @@ TEST(vector, Remove)
{
Vector<int> vec = {1, 2, 3, 4, 5, 6};
vec.remove(3);
EXPECT_TRUE(std::equal(vec.begin(), vec.end(), ArrayRef<int>({1, 2, 3, 5, 6}).begin()));
EXPECT_TRUE(std::equal(vec.begin(), vec.end(), Span<int>({1, 2, 3, 5, 6}).begin()));
vec.remove(0);
EXPECT_TRUE(std::equal(vec.begin(), vec.end(), ArrayRef<int>({2, 3, 5, 6}).begin()));
EXPECT_TRUE(std::equal(vec.begin(), vec.end(), Span<int>({2, 3, 5, 6}).begin()));
vec.remove(3);
EXPECT_TRUE(std::equal(vec.begin(), vec.end(), ArrayRef<int>({2, 3, 5}).begin()));
EXPECT_TRUE(std::equal(vec.begin(), vec.end(), Span<int>({2, 3, 5}).begin()));
vec.remove(1);
EXPECT_TRUE(std::equal(vec.begin(), vec.end(), ArrayRef<int>({2, 5}).begin()));
EXPECT_TRUE(std::equal(vec.begin(), vec.end(), Span<int>({2, 5}).begin()));
vec.remove(1);
EXPECT_TRUE(std::equal(vec.begin(), vec.end(), ArrayRef<int>({2}).begin()));
EXPECT_TRUE(std::equal(vec.begin(), vec.end(), Span<int>({2}).begin()));
vec.remove(0);
EXPECT_TRUE(std::equal(vec.begin(), vec.end(), ArrayRef<int>({}).begin()));
EXPECT_TRUE(std::equal(vec.begin(), vec.end(), Span<int>({}).begin()));
}
TEST(vector, ExtendSmallVector)

View File

@ -40,7 +40,6 @@ else()
endif()
BLENDER_TEST(BLI_array "bf_blenlib")
BLENDER_TEST(BLI_array_ref "bf_blenlib")
BLENDER_TEST(BLI_array_store "bf_blenlib")
BLENDER_TEST(BLI_array_utils "bf_blenlib")
BLENDER_TEST(BLI_delaunay_2d "bf_blenlib")
@ -67,6 +66,7 @@ BLENDER_TEST(BLI_optional "bf_blenlib")
BLENDER_TEST(BLI_path_util "${BLI_path_util_extra_libs}")
BLENDER_TEST(BLI_polyfill_2d "bf_blenlib")
BLENDER_TEST(BLI_set "bf_blenlib")
BLENDER_TEST(BLI_span "bf_blenlib")
BLENDER_TEST(BLI_stack "bf_blenlib")
BLENDER_TEST(BLI_stack_cxx "bf_blenlib")
BLENDER_TEST(BLI_string "bf_blenlib")