Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add String::concat and string.extend functions to core for efficient String concatenation. #99929

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion core/math/aabb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -445,5 +445,8 @@ Variant AABB::intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) c
}

AABB::operator String() const {
return "[P: " + position.operator String() + ", S: " + size + "]";
return String::concat(
"[P: ", position.operator String(),
", S: ", size,
"]");
}
8 changes: 5 additions & 3 deletions core/math/basis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -715,9 +715,11 @@ bool Basis::operator!=(const Basis &p_matrix) const {
}

Basis::operator String() const {
return "[X: " + get_column(0).operator String() +
", Y: " + get_column(1).operator String() +
", Z: " + get_column(2).operator String() + "]";
return String::concat(
"[X: ", get_column(0).operator String(),
", Y: ", get_column(1).operator String(),
", Z: ", get_column(2).operator String(),
"]");
}

Quaternion Basis::get_quaternion() const {
Expand Down
8 changes: 7 additions & 1 deletion core/math/color.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,13 @@ Color Color::from_rgba8(int64_t p_r8, int64_t p_g8, int64_t p_b8, int64_t p_a8)
}

Color::operator String() const {
return "(" + String::num(r, 4) + ", " + String::num(g, 4) + ", " + String::num(b, 4) + ", " + String::num(a, 4) + ")";
return String::concat(
"(",
String::num(r, 4), ", ",
String::num(g, 4), ", ",
String::num(b, 4), ", ",
String::num(a, 4),
")");
}

Color Color::operator+(const Color &p_color) const {
Expand Down
5 changes: 4 additions & 1 deletion core/math/face3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,10 @@ bool Face3::intersects_aabb(const AABB &p_aabb) const {
}

Face3::operator String() const {
return String() + vertex[0] + ", " + vertex[1] + ", " + vertex[2];
return String::concat(
vertex[0], ", ",
vertex[1], ", ",
vertex[2]);
}

void Face3::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const {
Expand Down
5 changes: 4 additions & 1 deletion core/math/plane.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,5 +177,8 @@ bool Plane::is_finite() const {
}

Plane::operator String() const {
return "[N: " + normal.operator String() + ", D: " + String::num_real(d, false) + "]";
return String::concat(
"[N: ", normal.operator String(),
", D: ", String::num_real(d, false),
"]");
}
10 changes: 6 additions & 4 deletions core/math/projection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -912,10 +912,12 @@ void Projection::set_light_atlas_rect(const Rect2 &p_rect) {
}

Projection::operator String() const {
return "[X: " + columns[0].operator String() +
", Y: " + columns[1].operator String() +
", Z: " + columns[2].operator String() +
", W: " + columns[3].operator String() + "]";
return String::concat(
"[X: ", columns[0].operator String(),
", Y: ", columns[1].operator String(),
", Z: ", columns[2].operator String(),
", W: ", columns[3].operator String(),
"]");
}

real_t Projection::get_aspect() const {
Expand Down
10 changes: 8 additions & 2 deletions core/math/quaternion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,13 @@ Quaternion Quaternion::spherical_cubic_interpolate_in_time(const Quaternion &p_b
}

Quaternion::operator String() const {
return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ", " + String::num_real(w, false) + ")";
return String::concat(
"(",
String::num_real(x, false), ", ",
String::num_real(y, false), ", ",
String::num_real(z, false), ", ",
String::num_real(w, false),
")");
}

Vector3 Quaternion::get_axis() const {
Expand All @@ -294,7 +300,7 @@ real_t Quaternion::get_angle() const {

Quaternion::Quaternion(const Vector3 &p_axis, real_t p_angle) {
#ifdef MATH_CHECKS
ERR_FAIL_COND_MSG(!p_axis.is_normalized(), "The axis Vector3 " + p_axis.operator String() + " must be normalized.");
ERR_FAIL_COND_MSG(!p_axis.is_normalized(), String::concat("The axis Vector3 ", p_axis.operator String(), " must be normalized."));
#endif
real_t d = p_axis.length();
if (d == 0) {
Expand Down
5 changes: 4 additions & 1 deletion core/math/rect2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,10 @@ bool Rect2::intersects_transformed(const Transform2D &p_xform, const Rect2 &p_re
}

Rect2::operator String() const {
return "[P: " + position.operator String() + ", S: " + size.operator String() + "]";
return String::concat(
"[P: ", position.operator String(),
", S: ", size.operator String(),
"]");
}

Rect2::operator Rect2i() const {
Expand Down
5 changes: 4 additions & 1 deletion core/math/rect2i.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@
#include "core/string/ustring.h"

Rect2i::operator String() const {
return "[P: " + position.operator String() + ", S: " + size + "]";
return String::concat(
"[P: ", position.operator String(),
", S: ", size,
"]");
}

Rect2i::operator Rect2() const {
Expand Down
8 changes: 5 additions & 3 deletions core/math/transform_2d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,9 @@ Transform2D Transform2D::operator/(real_t p_val) const {
}

Transform2D::operator String() const {
return "[X: " + columns[0].operator String() +
", Y: " + columns[1].operator String() +
", O: " + columns[2].operator String() + "]";
return String::concat(
"[X: ", columns[0].operator String(),
", Y: ", columns[1].operator String(),
", O: ", columns[2].operator String(),
"]");
}
10 changes: 6 additions & 4 deletions core/math/transform_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,10 +219,12 @@ Transform3D Transform3D::operator/(real_t p_val) const {
}

Transform3D::operator String() const {
return "[X: " + basis.get_column(0).operator String() +
", Y: " + basis.get_column(1).operator String() +
", Z: " + basis.get_column(2).operator String() +
", O: " + origin.operator String() + "]";
return String::concat(
"[X: ", basis.get_column(0).operator String(),
", Y: ", basis.get_column(1).operator String(),
", Z: ", basis.get_column(2).operator String(),
", O: ", origin.operator String(),
"]");
}

Transform3D::Transform3D(const Basis &p_basis, const Vector3 &p_origin) :
Expand Down
6 changes: 5 additions & 1 deletion core/math/vector2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,11 @@ bool Vector2::is_finite() const {
}

Vector2::operator String() const {
return "(" + String::num_real(x, true) + ", " + String::num_real(y, true) + ")";
return String::concat(
"(",
String::num_real(x, true), ", ",
String::num_real(y, true),
")");
}

Vector2::operator Vector2i() const {
Expand Down
6 changes: 5 additions & 1 deletion core/math/vector2i.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,11 @@ bool Vector2i::operator!=(const Vector2i &p_vec2) const {
}

Vector2i::operator String() const {
return "(" + itos(x) + ", " + itos(y) + ")";
return String::concat(
"(",
itos(x), ", ",
itos(y),
")");
}

Vector2i::operator Vector2() const {
Expand Down
7 changes: 6 additions & 1 deletion core/math/vector3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,12 @@ bool Vector3::is_finite() const {
}

Vector3::operator String() const {
return "(" + String::num_real(x, true) + ", " + String::num_real(y, true) + ", " + String::num_real(z, true) + ")";
return String::concat(
"(",
String::num_real(x, true), ", ",
String::num_real(y, true), ", ",
String::num_real(z, true),
")");
}

Vector3::operator Vector3i() const {
Expand Down
7 changes: 6 additions & 1 deletion core/math/vector3i.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,12 @@ Vector3i Vector3i::snappedi(int32_t p_step) const {
}

Vector3i::operator String() const {
return "(" + itos(x) + ", " + itos(y) + ", " + itos(z) + ")";
return String::concat(
"(",
itos(x), ", ",
itos(y), ", ",
itos(z),
")");
}

Vector3i::operator Vector3() const {
Expand Down
8 changes: 7 additions & 1 deletion core/math/vector4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,13 @@ Vector4 Vector4::clampf(real_t p_min, real_t p_max) const {
}

Vector4::operator String() const {
return "(" + String::num_real(x, true) + ", " + String::num_real(y, true) + ", " + String::num_real(z, true) + ", " + String::num_real(w, true) + ")";
return String::concat(
"(",
String::num_real(x, true), ", ",
String::num_real(y, true), ", ",
String::num_real(z, true), ", ",
String::num_real(w, true),
")");
}

static_assert(sizeof(Vector4) == 4 * sizeof(real_t));
Expand Down
8 changes: 7 additions & 1 deletion core/math/vector4i.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,13 @@ Vector4i Vector4i::snappedi(int32_t p_step) const {
}

Vector4i::operator String() const {
return "(" + itos(x) + ", " + itos(y) + ", " + itos(z) + ", " + itos(w) + ")";
return String::concat(
"(",
itos(x), ", ",
itos(y), ", ",
itos(z), ", ",
itos(w),
")");
}

Vector4i::operator Vector4() const {
Expand Down
61 changes: 61 additions & 0 deletions core/string/ustring.h
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,23 @@ class String {
// Use `is_valid_ascii_identifier()` instead. Kept for compatibility.
bool is_valid_identifier() const { return is_valid_ascii_identifier(); }

template <typename... Args>
void extend(Args... args);

template <typename... Args>
static String concat(Args... args) {
String string;
string.extend(args...);
return string;
}

template <typename... Args>
static String concat(String &&string, Args... args) {
// Optimized case of the concat call, where we can consume the first argument to avoid re-allocation.
string.extend(args...);
return std::move(string);
}

/**
* The constructors must not depend on other overloads
*/
Expand Down Expand Up @@ -654,6 +671,50 @@ String operator+(const char *p_chr, const String &p_str);
String operator+(const wchar_t *p_chr, const String &p_str);
String operator+(char32_t p_chr, const String &p_str);

_FORCE_INLINE_ char32_t *_insert_string(const StrRange<char> &string, char32_t *dst) {
const char32_t *src = dst;
for (const char32_t *end = dst + string.len; src < end; ++src, ++dst) {
*dst = *src;
}
return dst;
}

_FORCE_INLINE_ char32_t *_insert_string(const StrRange<char32_t> &string, char32_t *dst) {
memcpy(dst, string.c_str, string.len * sizeof(char32_t));
dst += string.len;
return dst;
}

inline StrRange<char32_t> _to_str_range(const String &string) {
return StrRange<char32_t>(string);
}
template <typename Char, typename = std::enable_if_t<std::is_fundamental_v<Char>>>
StrRange<Char> _to_str_range(const StrRange<Char> &string) {
return string;
}
template <typename Char, size_t len, typename = std::enable_if_t<std::is_fundamental_v<Char>>>
StrRange<Char> _to_str_range(const Char (&string)[len]) {
return StrRange<Char>::from_c_str(string);
}
template <typename Char, typename = std::enable_if_t<std::is_fundamental_v<Char>>>
StrRange<Char> _to_str_range(const Char &chr) {
return StrRange<Char>(&chr, 1);
}

template <typename... Args>
void _extend_string_ranges(String &string, Args... args) {
const int length_before = string.length();
string.resize(length_before + (args.len + ...) + 1);
char32_t *dst = string.ptrw() + length_before;
((dst = _insert_string(args, dst)), ...);
*dst = 0;
}

template <typename... Args>
void String::extend(Args... args) {
_extend_string_ranges(*this, _to_str_range(args)...);
}

String itos(int64_t p_val);
String uitos(uint64_t p_val);
String rtos(double p_val);
Expand Down
4 changes: 2 additions & 2 deletions core/variant/variant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1875,10 +1875,10 @@ String Variant::stringify(int recursion_count) const {
}
case RID: {
const ::RID &s = *reinterpret_cast<const ::RID *>(_data._mem);
return "RID(" + itos(s.get_id()) + ")";
return String::concat("RID(", itos(s.get_id()), ")");
}
default: {
return "<" + get_type_name(type) + ">";
return String::concat("<", get_type_name(type), ">");
}
}
}
Expand Down