BLI: Follow up and fix recent span slicing change

a5e7657cee didn't account for slices of zero sizes, and the asserts
were slightly incorrect otherwise. Also, the change didn't apply to
`Span`, only `MutableSpan`, which was a mistake. This also adds "safe"
methods to `IndexMask`, and switches function calls where necessary.
This commit is contained in:
Hans Goudey 2022-11-23 11:35:59 -06:00
parent 38cf48f62b
commit 584089879c
7 changed files with 41 additions and 10 deletions

View File

@ -654,7 +654,7 @@ Span<float3> CurvesGeometry::evaluated_positions() const
case CURVE_TYPE_NURBS: {
curves::nurbs::interpolate_to_evaluated(this->runtime->nurbs_basis_cache[curve_index],
nurbs_orders[curve_index],
nurbs_weights.slice(points),
nurbs_weights.slice_safe(points),
positions.slice(points),
evaluated_positions.slice(evaluated_points));
break;
@ -812,7 +812,7 @@ void CurvesGeometry::interpolate_to_evaluated(const int curve_index,
case CURVE_TYPE_NURBS:
curves::nurbs::interpolate_to_evaluated(this->runtime->nurbs_basis_cache[curve_index],
this->nurbs_orders()[curve_index],
this->nurbs_weights().slice(points),
this->nurbs_weights().slice_safe(points),
src,
dst);
return;
@ -853,7 +853,7 @@ void CurvesGeometry::interpolate_to_evaluated(const GSpan src, GMutableSpan dst)
case CURVE_TYPE_NURBS:
curves::nurbs::interpolate_to_evaluated(this->runtime->nurbs_basis_cache[curve_index],
nurbs_orders[curve_index],
nurbs_weights.slice(points),
nurbs_weights.slice_safe(points),
src.slice(points),
dst.slice(evaluated_points));
continue;

View File

@ -236,6 +236,9 @@ class IndexMask {
IndexMask slice(int64_t start, int64_t size) const;
IndexMask slice(IndexRange slice) const;
IndexMask slice_safe(int64_t start, int64_t size) const;
IndexMask slice_safe(IndexRange slice) const;
/**
* Create a sub-mask that is also shifted to the beginning.
* The shifting to the beginning allows code to work with smaller indices,

View File

@ -141,8 +141,8 @@ template<typename T> class Span {
{
BLI_assert(start >= 0);
BLI_assert(size >= 0);
const int64_t new_size = std::max<int64_t>(0, std::min(size, size_ - start));
return Span(data_ + start, new_size);
BLI_assert(start + size <= size_ || size == 0);
return Span(data_ + start, size);
}
constexpr Span slice(IndexRange range) const
@ -150,6 +150,23 @@ template<typename T> class Span {
return this->slice(range.start(), range.size());
}
/**
* Returns a contiguous part of the array. This invokes undefined behavior when the start or size
* is negative. Clamps the size of the new new span so it fits in the current one.
*/
constexpr Span slice_safe(const int64_t start, const int64_t size) const
{
BLI_assert(start >= 0);
BLI_assert(size >= 0);
const int64_t new_size = std::max<int64_t>(0, std::min(size, size_ - start));
return Span(data_ + start, new_size);
}
constexpr Span slice_safe(IndexRange range) const
{
return this->slice_safe(range.start(), range.size());
}
/**
* Returns a new Span with n elements removed from the beginning. This invokes undefined
* behavior when n is negative.
@ -578,8 +595,9 @@ template<typename T> class MutableSpan {
*/
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
{
BLI_assert(this->index_range().contains(start));
BLI_assert(this->index_range().contains(IndexRange(start, size).last()));
BLI_assert(start >= 0);
BLI_assert(size >= 0);
BLI_assert(start + size <= size_ || size == 0);
return MutableSpan(data_ + start, size);
}

View File

@ -15,6 +15,16 @@ IndexMask IndexMask::slice(IndexRange slice) const
return IndexMask(indices_.slice(slice));
}
IndexMask IndexMask::slice_safe(int64_t start, int64_t size) const
{
return this->slice_safe(IndexRange(start, size));
}
IndexMask IndexMask::slice_safe(IndexRange slice) const
{
return IndexMask(indices_.slice_safe(slice));
}
IndexMask IndexMask::slice_and_offset(const IndexRange slice, Vector<int64_t> &r_new_indices) const
{
const int slice_size = slice.size();

View File

@ -142,7 +142,7 @@ TEST(span, SliceRange)
TEST(span, SliceLargeN)
{
Vector<int> a = {1, 2, 3, 4, 5};
Span<int> slice1 = Span<int>(a).slice(3, 100);
Span<int> slice1 = Span<int>(a).slice_safe(3, 100);
MutableSpan<int> slice2 = MutableSpan<int>(a).slice_safe(3, 100);
EXPECT_EQ(slice1.size(), 2);
EXPECT_EQ(slice2.size(), 2);

View File

@ -232,7 +232,7 @@ void execute_materialized(TypeSequence<ParamTags...> /* param_tags */,
/* Outer loop over all chunks. */
for (int64_t chunk_start = 0; chunk_start < mask_size; chunk_start += MaxChunkSize) {
const IndexMask sliced_mask = mask.slice(chunk_start, MaxChunkSize);
const IndexMask sliced_mask = mask.slice_safe(chunk_start, MaxChunkSize);
const int64_t chunk_size = sliced_mask.size();
const bool sliced_mask_is_range = sliced_mask.is_range();

View File

@ -254,7 +254,7 @@ static CurvesGeometry resample_to_uniform(const CurvesGeometry &src_curves,
bke::CurvesFieldContext field_context{src_curves, ATTR_DOMAIN_CURVE};
fn::FieldEvaluator evaluator{field_context, src_curves.curves_num()};
evaluator.set_selection(selection_field);
evaluator.add_with_destination(count_field, dst_offsets);
evaluator.add_with_destination(count_field, dst_offsets.drop_back(1));
evaluator.evaluate();
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert(