1
1

BLI: Add a reverse method to MutableSpan

Add a method that allows a MutableSpan to reverse itself. This reverses
the data in the original span object. This is a first step in extracting
some functionality from nodes and making it more general.

Differential Revision: https://developer.blender.org/D12485
This commit is contained in:
Johnny Matthews
2021-09-15 11:13:10 -05:00
committed by Hans Goudey
parent 09f14b38f2
commit a6adb7ecae
3 changed files with 46 additions and 33 deletions

View File

@@ -643,6 +643,16 @@ template<typename T> class MutableSpan {
return MutableSpan(data_ + size_ - new_size, new_size);
}
/**
* Reverse the data in the MutableSpan.
*/
constexpr void reverse()
{
for (const int i : IndexRange(size_ / 2)) {
std::swap(data_[size_ - 1 - i], data_[i]);
}
}
/**
* 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.

View File

@@ -362,6 +362,29 @@ TEST(span, ReverseIterator)
EXPECT_EQ_ARRAY(reversed_vec.data(), Span({7, 6, 5, 4}).data(), 4);
}
TEST(span, ReverseMutableSpan)
{
std::array<int, 0> src0 = {};
MutableSpan<int> span0 = src0;
span0.reverse();
EXPECT_EQ_ARRAY(span0.data(), Span<int>({}).data(), 0);
std::array<int, 1> src1 = {4};
MutableSpan<int> span1 = src1;
span1.reverse();
EXPECT_EQ_ARRAY(span1.data(), Span<int>({4}).data(), 1);
std::array<int, 2> src2 = {4, 5};
MutableSpan<int> span2 = src2;
span2.reverse();
EXPECT_EQ_ARRAY(span2.data(), Span<int>({5, 4}).data(), 2);
std::array<int, 5> src5 = {4, 5, 6, 7, 8};
MutableSpan<int> span5 = src5;
span5.reverse();
EXPECT_EQ_ARRAY(span5.data(), Span<int>({8, 7, 6, 5, 4}).data(), 5);
}
TEST(span, MutableReverseIterator)
{
std::array<int, 4> src = {4, 5, 6, 7};

View File

@@ -29,31 +29,6 @@ static void geo_node_curve_reverse_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>("Curve");
}
/**
* Reverse the data in a MutableSpan object.
*/
template<typename T> static void reverse_data(MutableSpan<T> r_data)
{
const int size = r_data.size();
for (const int i : IndexRange(size / 2)) {
std::swap(r_data[size - 1 - i], r_data[i]);
}
}
/**
* Reverse and Swap the data between 2 MutableSpans.
*/
template<typename T> static void reverse_data(MutableSpan<T> left, MutableSpan<T> right)
{
BLI_assert(left.size() == right.size());
const int size = left.size();
for (const int i : IndexRange(size / 2 + size % 2)) {
std::swap(left[i], right[size - 1 - i]);
std::swap(right[i], left[size - 1 - i]);
}
}
static void geo_node_curve_reverse_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
@@ -78,9 +53,9 @@ static void geo_node_curve_reverse_exec(GeoNodeExecParams params)
continue;
}
reverse_data<float3>(splines[i]->positions());
reverse_data<float>(splines[i]->radii());
reverse_data<float>(splines[i]->tilts());
splines[i]->positions().reverse();
splines[i]->radii().reverse();
splines[i]->tilts().reverse();
splines[i]->attributes.foreach_attribute(
[&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
@@ -92,7 +67,7 @@ static void geo_node_curve_reverse_exec(GeoNodeExecParams params)
}
attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
using T = decltype(dummy);
reverse_data(output_attribute->typed<T>());
output_attribute->typed<T>().reverse();
});
return true;
},
@@ -100,12 +75,17 @@ static void geo_node_curve_reverse_exec(GeoNodeExecParams params)
/* Deal with extra info on derived types. */
if (BezierSpline *spline = dynamic_cast<BezierSpline *>(splines[i].get())) {
reverse_data<BezierSpline::HandleType>(spline->handle_types_left());
reverse_data<BezierSpline::HandleType>(spline->handle_types_right());
reverse_data<float3>(spline->handle_positions_left(), spline->handle_positions_right());
spline->handle_types_left().reverse();
spline->handle_types_right().reverse();
spline->handle_positions_left().reverse();
spline->handle_positions_right().reverse();
for (int i : spline->handle_positions_left().index_range()) {
std::swap(spline->handle_positions_left()[i], spline->handle_positions_right()[i]);
}
}
else if (NURBSpline *spline = dynamic_cast<NURBSpline *>(splines[i].get())) {
reverse_data<float>(spline->weights());
spline->weights().reverse();
}
/* Nothing to do for poly splines. */