Array Utils: Add find_all_ranges function

This functions returns a vector of all the index ranges for which the
span contains consecutive values that equal to the value given.

Pull Request: https://projects.blender.org/blender/blender/pulls/110265
This commit is contained in:
Falk David
2023-07-19 16:37:50 +02:00
committed by Falk David
parent 93855a5efd
commit 46d60aacd8
2 changed files with 75 additions and 0 deletions

View File

@@ -169,4 +169,29 @@ 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;
}
} // namespace blender::array_utils

View File

@@ -5,6 +5,7 @@
#include "testing/testing.h"
#include "BLI_array_utils.h"
#include "BLI_array_utils.hh"
#include "BLI_utildefines.h"
#include "BLI_utildefines_stack.h"
@@ -241,3 +242,52 @@ TEST(array_utils, DeduplicateOrdered3)
}
#undef DEDUPLICATE_ORDERED_TEST
static void find_all_ranges_test(const blender::Span<bool> data,
const blender::Span<blender::IndexRange> data_cmp)
{
using namespace blender;
Vector<IndexRange> ranges = array_utils::find_all_ranges(data, true);
EXPECT_EQ(ranges.size(), data_cmp.size());
EXPECT_EQ_ARRAY(data_cmp.data(), ranges.as_span().data(), data_cmp.size());
}
TEST(array_utils, FindAllRanges1)
{
using namespace blender;
const std::array data = {false};
Vector<IndexRange> ranges = array_utils::find_all_ranges(Span(data.data(), data.size()), true);
EXPECT_EQ(ranges.size(), 0);
}
TEST(array_utils, FindAllRanges2)
{
using namespace blender;
const std::array data = {true, true, true};
const std::array data_cmp = {IndexRange(0, 3)};
find_all_ranges_test(data, data_cmp);
}
TEST(array_utils, FindAllRanges3)
{
using namespace blender;
const std::array data = {true, false};
const std::array data_cmp = {IndexRange(0, 1)};
find_all_ranges_test(data, data_cmp);
}
TEST(array_utils, FindAllRanges4)
{
using namespace blender;
const std::array data = {false, true};
const std::array data_cmp = {IndexRange(1, 1)};
find_all_ranges_test(data, data_cmp);
}
TEST(array_utils, FindAllRanges5)
{
using namespace blender;
const std::array data = {true, false, false, true, true, false, true};
const std::array data_cmp = {IndexRange(0, 1), IndexRange(3, 2), IndexRange(6, 1)};
find_all_ranges_test(data, data_cmp);
}