LibWeb: Avoid Vector allocation in parse_coordinate{_pair_}_sequence

Previously we would often return a `Vector` just for the caller to
iterate over it a single time and disregard it. We instead now skip the
`Vector` allocation and second iteration by executing a callback as we
parse each value in the sequence.
This commit is contained in:
Callum Law 2026-06-08 17:09:50 +12:00 committed by Tim Ledbetter
parent 5fbb8d82e7
commit 3c4076597e
2 changed files with 27 additions and 17 deletions

View file

@ -123,7 +123,16 @@ Vector<Gfx::FloatPoint> AttributeParser::parse_points(StringView input)
parser.parse_whitespace();
return parser.parse_coordinate_pair_sequence().value_or(Vector<Gfx::FloatPoint> {});
Vector<Gfx::FloatPoint> points;
auto result = parser.parse_coordinate_pair_sequence([&](Gfx::FloatPoint point) {
points.append(point);
});
if (result.is_error())
return {};
return points;
}
ErrorOr<void> AttributeParser::parse_drawto()
@ -162,14 +171,14 @@ ErrorOr<void> AttributeParser::parse_moveto()
parse_whitespace();
bool is_first = true;
for (auto& pair : TRY(parse_coordinate_pair_sequence())) {
TRY(parse_coordinate_pair_sequence([&](Gfx::FloatPoint pair) {
// NOTE: "M 1 2 3 4" is equivalent to "M 1 2 L 3 4".
if (is_first)
m_instructions.append(MoveToInstruction { absolute, pair });
else
m_instructions.append(LineToInstruction { absolute, pair });
is_first = false;
}
}));
return {};
}
@ -186,8 +195,9 @@ ErrorOr<void> AttributeParser::parse_lineto()
{
bool absolute = consume() == 'L';
parse_whitespace();
for (auto& pair : TRY(parse_coordinate_pair_sequence()))
m_instructions.append(LineToInstruction { absolute, pair });
TRY(parse_coordinate_pair_sequence([&](Gfx::FloatPoint point) {
m_instructions.append(LineToInstruction { absolute, point });
}));
return {};
}
@ -196,8 +206,9 @@ ErrorOr<void> AttributeParser::parse_horizontal_lineto()
{
bool absolute = consume() == 'H';
parse_whitespace();
for (auto coordinate : TRY(parse_coordinate_sequence()))
TRY(parse_coordinate_sequence([&](float coordinate) {
m_instructions.append(HorizontalLineToInstruction { absolute, coordinate });
}));
return {};
}
@ -206,8 +217,9 @@ ErrorOr<void> AttributeParser::parse_vertical_lineto()
{
bool absolute = consume() == 'V';
parse_whitespace();
for (auto coordinate : TRY(parse_coordinate_sequence()))
TRY(parse_coordinate_sequence([&](float coordinate) {
m_instructions.append(VerticalLineToInstruction { absolute, coordinate });
}));
return {};
}
@ -348,9 +360,8 @@ ErrorOr<Gfx::FloatPoint> AttributeParser::parse_coordinate_pair()
return Gfx::FloatPoint { x, y };
}
ErrorOr<Vector<float>> AttributeParser::parse_coordinate_sequence()
ErrorOr<void> AttributeParser::parse_coordinate_sequence(Function<void(float)> const& callback)
{
Vector<float> sequence;
bool is_first = true;
while (true) {
auto coordinate_or_error = parse_coordinate();
@ -360,18 +371,17 @@ ErrorOr<Vector<float>> AttributeParser::parse_coordinate_sequence()
break;
}
is_first = false;
sequence.append(coordinate_or_error.release_value());
callback(coordinate_or_error.release_value());
if (match_comma_whitespace())
parse_comma_whitespace();
if (!match_comma_whitespace() && !match_coordinate())
break;
}
return sequence;
return {};
}
ErrorOr<Vector<Gfx::FloatPoint>> AttributeParser::parse_coordinate_pair_sequence()
ErrorOr<void> AttributeParser::parse_coordinate_pair_sequence(Function<void(Gfx::FloatPoint)> const& callback)
{
Vector<Gfx::FloatPoint> sequence;
bool is_first = true;
while (true) {
auto coordinate_pair_or_error = parse_coordinate_pair();
@ -381,13 +391,13 @@ ErrorOr<Vector<Gfx::FloatPoint>> AttributeParser::parse_coordinate_pair_sequence
break;
}
is_first = false;
sequence.append(coordinate_pair_or_error.release_value());
callback(coordinate_pair_or_error.release_value());
if (match_comma_whitespace())
parse_comma_whitespace();
if (!match_comma_whitespace() && !match_coordinate())
break;
}
return sequence;
return {};
}
ErrorOr<Vector<Gfx::FloatPoint, 2>> AttributeParser::parse_coordinate_pair_double()

View file

@ -174,8 +174,8 @@ private:
ErrorOr<float> parse_coordinate();
ErrorOr<i32> parse_integer();
ErrorOr<Gfx::FloatPoint> parse_coordinate_pair();
ErrorOr<Vector<float>> parse_coordinate_sequence();
ErrorOr<Vector<Gfx::FloatPoint>> parse_coordinate_pair_sequence();
ErrorOr<void> parse_coordinate_sequence(Function<void(float)> const& callback);
ErrorOr<void> parse_coordinate_pair_sequence(Function<void(Gfx::FloatPoint)> const& callback);
ErrorOr<Vector<Gfx::FloatPoint, 2>> parse_coordinate_pair_double();
ErrorOr<Vector<Gfx::FloatPoint, 3>> parse_coordinate_pair_triplet();
void parse_whitespace(bool must_match_once = false);