Files
test/source/blender/blenlib/BLI_array_utils.hh
Brecht Van Lommel 39107b3133 Revert changes from main commits that were merged into blender-v4.0-release
The last good commit was 8474716abb.

After this commits from main were pushed to blender-v4.0-release. These are
being reverted.

Commits a4880576dc from to b26f176d1a that happend afterwards were meant for
4.0, and their contents is preserved.
2023-10-30 21:40:35 +01:00

233 lines
7.2 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include <numeric>
#include "BLI_generic_span.hh"
#include "BLI_generic_virtual_array.hh"
#include "BLI_index_mask.hh"
#include "BLI_offset_indices.hh"
#include "BLI_task.hh"
#include "BLI_virtual_array.hh"
namespace blender::array_utils {
/**
* Fill the destination span by copying all values from the `src` array. Threaded based on
* grain-size.
*/
void copy(const GVArray &src, GMutableSpan dst, int64_t grain_size = 4096);
template<typename T>
inline void copy(const VArray<T> &src, MutableSpan<T> dst, const int64_t grain_size = 4096)
{
BLI_assert(src.size() == dst.size());
threading::parallel_for(src.index_range(), grain_size, [&](const IndexRange range) {
src.materialize_to_uninitialized(range, dst);
});
}
/**
* Fill the destination span by copying all values from the `src` array. Threaded based on
* grain-size.
*/
template<typename T>
inline void copy(const Span<T> src, MutableSpan<T> dst, const int64_t grain_size = 4096)
{
BLI_assert(src.size() == dst.size());
threading::parallel_for(src.index_range(), grain_size, [&](const IndexRange range) {
dst.slice(range).copy_from(src.slice(range));
});
}
/**
* Fill the destination span by copying masked values from the `src` array. Threaded based on
* grain-size.
*/
void copy(const GVArray &src,
const IndexMask &selection,
GMutableSpan dst,
int64_t grain_size = 4096);
/**
* Fill the destination span by copying values from the `src` array. Threaded based on
* grain-size.
*/
template<typename T>
inline void copy(const Span<T> src,
const IndexMask &selection,
MutableSpan<T> dst,
const int64_t grain_size = 4096)
{
BLI_assert(src.size() == dst.size());
selection.foreach_index_optimized<int64_t>(GrainSize(grain_size),
[&](const int64_t i) { dst[i] = src[i]; });
}
/**
* Fill the destination span by gathering indexed values from the `src` array.
*/
void gather(const GVArray &src,
const IndexMask &indices,
GMutableSpan dst,
int64_t grain_size = 4096);
/**
* Fill the destination span by gathering indexed values from the `src` array.
*/
void gather(GSpan src, const IndexMask &indices, GMutableSpan dst, int64_t grain_size = 4096);
/**
* Fill the destination span by gathering indexed values from the `src` array.
*/
template<typename T>
inline void gather(const VArray<T> &src,
const IndexMask &indices,
MutableSpan<T> dst,
const int64_t grain_size = 4096)
{
BLI_assert(indices.size() == dst.size());
threading::parallel_for(indices.index_range(), grain_size, [&](const IndexRange range) {
src.materialize_compressed_to_uninitialized(indices.slice(range), dst.slice(range));
});
}
/**
* Fill the destination span by gathering indexed values from the `src` array.
*/
template<typename T, typename IndexT>
inline void gather(const Span<T> src,
const IndexMask &indices,
MutableSpan<T> dst,
const int64_t grain_size = 4096)
{
BLI_assert(indices.size() == dst.size());
indices.foreach_segment(GrainSize(grain_size),
[&](const IndexMaskSegment segment, const int64_t segment_pos) {
for (const int64_t i : segment.index_range()) {
dst[segment_pos + i] = src[segment[i]];
}
});
}
/**
* Fill the destination span by gathering indexed values from the `src` array.
*/
template<typename T, typename IndexT>
inline void gather(const Span<T> src,
const Span<IndexT> indices,
MutableSpan<T> dst,
const int64_t grain_size = 4096)
{
BLI_assert(indices.size() == dst.size());
threading::parallel_for(indices.index_range(), grain_size, [&](const IndexRange range) {
for (const int64_t i : range) {
dst[i] = src[indices[i]];
}
});
}
/**
* Fill the destination span by gathering indexed values from the `src` array.
*/
template<typename T, typename IndexT>
inline void gather(const VArray<T> &src,
const Span<IndexT> indices,
MutableSpan<T> dst,
const int64_t grain_size = 4096)
{
BLI_assert(indices.size() == dst.size());
devirtualize_varray(src, [&](const auto &src) {
threading::parallel_for(indices.index_range(), grain_size, [&](const IndexRange range) {
for (const int64_t i : range) {
dst[i] = src[indices[i]];
}
});
});
}
/**
* Copy the \a src data from the groups defined by \a src_offsets to the groups in \a dst defined
* by \a dst_offsets. Groups to use are masked by \a selection, and it is assumed that the
* corresponding groups have the same size.
*/
void copy_group_to_group(OffsetIndices<int> src_offsets,
OffsetIndices<int> dst_offsets,
const IndexMask &selection,
GSpan src,
GMutableSpan dst);
template<typename T>
void copy_group_to_group(OffsetIndices<int> src_offsets,
OffsetIndices<int> dst_offsets,
const IndexMask &selection,
Span<T> src,
MutableSpan<T> dst)
{
copy_group_to_group(src_offsets, dst_offsets, selection, GSpan(src), GMutableSpan(dst));
}
/**
* Count the number of occurrences of each index.
* \param indices: The indices to count.
* \param counts: The number of occurrences of each index. Typically initialized to zero.
* Must be large enough to contain the maximum index.
*
* \note The memory referenced by the two spans must not overlap.
*/
void count_indices(Span<int> indices, MutableSpan<int> counts);
void invert_booleans(MutableSpan<bool> span);
void invert_booleans(MutableSpan<bool> span, const IndexMask &mask);
int64_t count_booleans(const VArray<bool> &varray);
enum class BooleanMix {
None,
AllFalse,
AllTrue,
Mixed,
};
BooleanMix booleans_mix_calc(const VArray<bool> &varray, IndexRange range_to_check);
inline BooleanMix booleans_mix_calc(const VArray<bool> &varray)
{
return booleans_mix_calc(varray, varray.index_range());
}
/**
* Finds all the index ranges for which consecutive values in \a span equal \a value.
*/
template<typename T> inline Vector<IndexRange> find_all_ranges(const Span<T> span, const T &value)
{
if (span.is_empty()) {
return Vector<IndexRange>();
}
Vector<IndexRange> ranges;
int64_t length = (span.first() == value) ? 1 : 0;
for (const int64_t i : span.index_range().drop_front(1)) {
if (span[i - 1] == value && span[i] != value) {
ranges.append(IndexRange(i - length, length));
length = 0;
}
else if (span[i] == value) {
length++;
}
}
if (length > 0) {
ranges.append(IndexRange(span.size() - length, length));
}
return ranges;
}
/**
* Fill the span with increasing indices: 0, 1, 2, ...
* Optionally, the start value can be provided.
*/
template<typename T> inline void fill_index_range(MutableSpan<T> span, const T start = 0)
{
std::iota(span.begin(), span.end(), start);
}
} // namespace blender::array_utils