Curves: add OffsetIndices abstraction
This changes how we access the points that correspond to each curve in a `CurvesGeometry`. Previously, `CurvesGeometry::points_for_curve(int curve_index) -> IndexRange` was called for every curve in many loops. Now one has to call `CurvesGeometry::points_by_curve() -> OffsetIndices` before the loop and use the returned value inside the loop. While this is a little bit more verbose in general, it has some benefits: * Better standardization of how "offset indices" are used. The new data structure can be used independent of curves. * Allows for better data oriented design. Generally, we want to retrieve all the arrays we need for a loop first and then do the processing. Accessing the old `CurvesGeometry::points_for_curve(...)` did not follow that design because it hid the underlying offset array. * Makes it easier to pass the offsets to a function without having to pass the entire `CurvesGeometry`. * Can improve performance in theory due to one less memory access because `this` does not have to be dereferenced every time. This likely doesn't have a noticable impact in practice. Differential Revision: https://developer.blender.org/D17025
This commit is contained in:
70
source/blender/blenlib/BLI_offset_indices.hh
Normal file
70
source/blender/blenlib/BLI_offset_indices.hh
Normal file
@@ -0,0 +1,70 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_index_range.hh"
|
||||
#include "BLI_span.hh"
|
||||
|
||||
namespace blender::offset_indices {
|
||||
|
||||
/**
|
||||
* References an array of ascending indices. A pair of consecutive indices encode an index range.
|
||||
* Another common way to store the same kind of data is to store the start and size of every range
|
||||
* separately. Using offsets instead halves the memory consumption. The downside is that the
|
||||
* array has to be one element longer than the total number of ranges. The extra element is
|
||||
* necessary to be able to get the last index range without requiring an extra branch for the case.
|
||||
*
|
||||
* This class is a thin wrapper around such an array that makes it easy to retrieve the index range
|
||||
* at a specific index.
|
||||
*/
|
||||
template<typename T> class OffsetIndices {
|
||||
private:
|
||||
static_assert(std::is_integral_v<T>);
|
||||
|
||||
Span<T> offsets_;
|
||||
|
||||
public:
|
||||
OffsetIndices(const Span<T> offsets) : offsets_(offsets)
|
||||
{
|
||||
BLI_assert(std::is_sorted(offsets_.begin(), offsets_.end()));
|
||||
}
|
||||
|
||||
T size(const int64_t index) const
|
||||
{
|
||||
BLI_assert(index >= 0);
|
||||
BLI_assert(index < offsets_.size() - 1);
|
||||
const int64_t begin = offsets_[index];
|
||||
const int64_t end = offsets_[index + 1];
|
||||
const int64_t size = end - begin;
|
||||
return size;
|
||||
}
|
||||
|
||||
IndexRange operator[](const int64_t index) const
|
||||
{
|
||||
BLI_assert(index >= 0);
|
||||
BLI_assert(index < offsets_.size() - 1);
|
||||
const int64_t begin = offsets_[index];
|
||||
const int64_t end = offsets_[index + 1];
|
||||
const int64_t size = end - begin;
|
||||
return IndexRange(begin, size);
|
||||
}
|
||||
|
||||
IndexRange operator[](const IndexRange indices) const
|
||||
{
|
||||
const int64_t begin = offsets_[indices.start()];
|
||||
const int64_t end = offsets_[indices.one_after_last()];
|
||||
const int64_t size = end - begin;
|
||||
return IndexRange(begin, size);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Turn an array of sizes into the offset at each index including all previous sizes.
|
||||
*/
|
||||
void accumulate_counts_to_offsets(MutableSpan<int> counts_to_offsets, int start_offset = 0);
|
||||
|
||||
} // namespace blender::offset_indices
|
||||
|
||||
namespace blender {
|
||||
using offset_indices::OffsetIndices;
|
||||
}
|
Reference in New Issue
Block a user