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 digits argument to String::num_scientific and fix serializing #96676

Closed
Closed
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
7 changes: 4 additions & 3 deletions core/doc_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,13 @@
#include "doc_data.h"

String DocData::get_default_value_string(const Variant &p_value) {
const int digits = 6; // Reduced precision is better for documentation, avoids unnecessary decimals.
if (p_value.get_type() == Variant::ARRAY) {
return Variant(Array(p_value, 0, StringName(), Variant())).get_construct_string().replace("\n", " ");
return Variant(Array(p_value, 0, StringName(), Variant())).get_construct_string(digits).replace("\n", " ");
} else if (p_value.get_type() == Variant::DICTIONARY) {
return Variant(Dictionary(p_value, 0, StringName(), Variant(), 0, StringName(), Variant())).get_construct_string().replace("\n", " ");
return Variant(Dictionary(p_value, 0, StringName(), Variant(), 0, StringName(), Variant())).get_construct_string(digits).replace("\n", " ");
} else {
return p_value.get_construct_string().replace("\n", " ");
return p_value.get_construct_string(digits).replace("\n", " ");
}
}

Expand Down
13 changes: 10 additions & 3 deletions core/string/ustring.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1938,7 +1938,7 @@ String String::num_real(double p_num, bool p_trailing) {
return num(p_num, decimals);
}

String String::num_scientific(double p_num) {
String String::num_scientific(double p_num, int p_digits) {
if (Math::is_nan(p_num)) {
return "nan";
}
Expand All @@ -1951,6 +1951,9 @@ String String::num_scientific(double p_num) {
}
}

if (p_digits > MAX_DECIMALS) {
p_digits = MAX_DECIMALS;
}
char buf[256];

#if defined(__GNUC__) || defined(_MSC_VER)
Expand All @@ -1959,21 +1962,25 @@ String String::num_scientific(double p_num) {
// MinGW requires _set_output_format() to conform to C99 output for printf
unsigned int old_exponent_format = _set_output_format(_TWO_DIGIT_EXPONENT);
#endif
snprintf(buf, 256, "%lg", p_num);
snprintf(buf, 256, "%.*g", p_digits, p_num);

#if defined(__MINGW32__) && defined(_TWO_DIGIT_EXPONENT) && !defined(_UCRT)
_set_output_format(old_exponent_format);
#endif

#else
sprintf(buf, "%.16lg", p_num);
sprintf(buf, "%.*g", p_digits, p_num);
#endif

buf[255] = 0;

return buf;
}

String String::num_scientific_compat_bind(double p_num) {
return num_scientific(p_num);
}

String String::md5(const uint8_t *p_md5) {
return String::hex_encode_buffer(p_md5, 16);
}
Expand Down
3 changes: 2 additions & 1 deletion core/string/ustring.h
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,8 @@ class String {
String quote(const String &quotechar = "\"") const;
String unquote() const;
static String num(double p_num, int p_decimals = -1);
static String num_scientific(double p_num);
static String num_scientific(double p_num, int p_digits = 6);
static String num_scientific_compat_bind(double p_num); // Delete in Godot 5.0
static String num_real(double p_num, bool p_trailing = true);
static String num_int64(int64_t p_num, int base = 10, bool capitalize_hex = false);
static String num_uint64(uint64_t p_num, int base = 10, bool capitalize_hex = false);
Expand Down
4 changes: 2 additions & 2 deletions core/variant/variant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3619,9 +3619,9 @@ void Variant::construct_from_string(const String &p_string, Variant &r_value, Ob
r_value = Variant();
}

String Variant::get_construct_string() const {
String Variant::get_construct_string(int p_max_digits) const {
String vars;
VariantWriter::write_to_string(*this, vars);
VariantWriter::write_to_string(*this, vars, nullptr, nullptr, true, p_max_digits);

return vars;
}
Expand Down
2 changes: 1 addition & 1 deletion core/variant/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ class Variant {
typedef String (*ObjectDeConstruct)(const Variant &p_object, void *ud);
typedef void (*ObjectConstruct)(const String &p_text, void *ud, Variant &r_value);

String get_construct_string() const;
String get_construct_string(int p_max_digits = 17) const;
static void construct_from_string(const String &p_string, Variant &r_value, ObjectConstruct p_obj_construct = nullptr, void *p_construct_ud = nullptr);

void operator=(const Variant &p_variant); // only this is enough for all the other types
Expand Down
12 changes: 11 additions & 1 deletion core/variant/variant_call.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1591,6 +1591,16 @@ int Variant::get_enum_value(Variant::Type p_type, const StringName &p_enum_name,
register_builtin_method<Method_##m_type##_##m_method>(sarray(), m_default_args);
#endif

#ifdef DEBUG_METHODS_ENABLED
#define bind_static_method_with_name(m_type, m_exposed_name, m_method, m_arg_names, m_default_args) \
STATIC_METHOD_CLASS(m_type, m_exposed_name, m_type::m_method); \
register_builtin_method<Method_##m_type##_##m_exposed_name>(m_arg_names, m_default_args);
#else
#define bind_static_method_with_name(m_type, m_exposed_name, m_method, m_arg_names, m_default_args) \
STATIC_METHOD_CLASS(m_type, m_exposed_name, m_type ::m_method); \
register_builtin_method<Method_##m_type##_##m_exposed_name>(sarray(), m_default_args);
#endif

#ifdef DEBUG_METHODS_ENABLED
#define bind_methodv(m_type, m_name, m_method, m_arg_names, m_default_args) \
METHOD_CLASS(m_type, m_name, m_method); \
Expand Down Expand Up @@ -1769,7 +1779,7 @@ static void _register_variant_builtin_methods_string() {
bind_string_method(hex_decode, sarray(), varray());
bind_string_method(to_wchar_buffer, sarray(), varray());

bind_static_method(String, num_scientific, sarray("number"), varray());
bind_static_method_with_name(String, num_scientific, num_scientific_compat_bind, sarray("number"), varray());
bind_static_method(String, num, sarray("number", "decimals"), varray(-1));
bind_static_method(String, num_int64, sarray("number", "base", "capitalize_hex"), varray(10, false));
bind_static_method(String, num_uint64, sarray("number", "base", "capitalize_hex"), varray(10, false));
Expand Down
74 changes: 48 additions & 26 deletions core/variant/variant_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1931,9 +1931,11 @@ Error VariantParser::parse(Stream *p_stream, Variant &r_ret, String &r_err_str,
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////

static String rtos_fix(double p_value) {
// These two functions serialize floats or doubles in a way that ensures they
// can be read back in the same way (except collapsing -0 to 0, and NaN values).
static String serialize_real(float p_value, int p_max_digits = 9) {
if (p_value == 0.0) {
return "0"; //avoid negative zero (-0) being written, which may annoy git, svn, etc. for changes when they don't exist.
return "0"; // Avoid negative zero (-0) being written, which may annoy git, svn, etc. for changes when they don't exist.
} else if (isnan(p_value)) {
return "nan";
} else if (isinf(p_value)) {
Expand All @@ -1943,11 +1945,31 @@ static String rtos_fix(double p_value) {
return "inf_neg";
}
} else {
return rtoss(p_value);
int digits = p_max_digits > 9 ? 9 : p_max_digits;
return String::num_scientific(p_value, digits);
}
}

Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int p_recursion_count, bool p_compat) {
static String serialize_real(double p_value, int p_max_digits = 17) {
if (p_value == 0.0) {
return "0"; // Avoid negative zero (-0) being written, which may annoy git, svn, etc. for changes when they don't exist.
} else if (isnan(p_value)) {
return "nan";
} else if (isinf(p_value)) {
if (p_value > 0) {
return "inf";
} else {
return "inf_neg";
}
} else {
int digits = p_max_digits > 17 ? 17 : p_max_digits;
return String::num_scientific(p_value, digits);
}
}

#define SERIALIZE_REAL(m_num) serialize_real(m_num, p_max_digits)

Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int p_recursion_count, bool p_compat, int p_max_digits) {
switch (p_variant.get_type()) {
case Variant::NIL: {
p_store_string_func(p_store_string_ud, "null");
Expand All @@ -1959,7 +1981,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
p_store_string_func(p_store_string_ud, itos(p_variant.operator int64_t()));
} break;
case Variant::FLOAT: {
String s = rtos_fix(p_variant.operator double());
String s = SERIALIZE_REAL(p_variant.operator double());
if (s != "inf" && s != "inf_neg" && s != "nan") {
if (!s.contains(".") && !s.contains("e")) {
s += ".0";
Expand All @@ -1976,47 +1998,47 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
// Math types.
case Variant::VECTOR2: {
Vector2 v = p_variant;
p_store_string_func(p_store_string_ud, "Vector2(" + rtos_fix(v.x) + ", " + rtos_fix(v.y) + ")");
p_store_string_func(p_store_string_ud, "Vector2(" + SERIALIZE_REAL(v.x) + ", " + SERIALIZE_REAL(v.y) + ")");
} break;
case Variant::VECTOR2I: {
Vector2i v = p_variant;
p_store_string_func(p_store_string_ud, "Vector2i(" + itos(v.x) + ", " + itos(v.y) + ")");
} break;
case Variant::RECT2: {
Rect2 aabb = p_variant;
p_store_string_func(p_store_string_ud, "Rect2(" + rtos_fix(aabb.position.x) + ", " + rtos_fix(aabb.position.y) + ", " + rtos_fix(aabb.size.x) + ", " + rtos_fix(aabb.size.y) + ")");
p_store_string_func(p_store_string_ud, "Rect2(" + SERIALIZE_REAL(aabb.position.x) + ", " + SERIALIZE_REAL(aabb.position.y) + ", " + SERIALIZE_REAL(aabb.size.x) + ", " + SERIALIZE_REAL(aabb.size.y) + ")");
} break;
case Variant::RECT2I: {
Rect2i aabb = p_variant;
p_store_string_func(p_store_string_ud, "Rect2i(" + itos(aabb.position.x) + ", " + itos(aabb.position.y) + ", " + itos(aabb.size.x) + ", " + itos(aabb.size.y) + ")");
} break;
case Variant::VECTOR3: {
Vector3 v = p_variant;
p_store_string_func(p_store_string_ud, "Vector3(" + rtos_fix(v.x) + ", " + rtos_fix(v.y) + ", " + rtos_fix(v.z) + ")");
p_store_string_func(p_store_string_ud, "Vector3(" + SERIALIZE_REAL(v.x) + ", " + SERIALIZE_REAL(v.y) + ", " + SERIALIZE_REAL(v.z) + ")");
} break;
case Variant::VECTOR3I: {
Vector3i v = p_variant;
p_store_string_func(p_store_string_ud, "Vector3i(" + itos(v.x) + ", " + itos(v.y) + ", " + itos(v.z) + ")");
} break;
case Variant::VECTOR4: {
Vector4 v = p_variant;
p_store_string_func(p_store_string_ud, "Vector4(" + rtos_fix(v.x) + ", " + rtos_fix(v.y) + ", " + rtos_fix(v.z) + ", " + rtos_fix(v.w) + ")");
p_store_string_func(p_store_string_ud, "Vector4(" + SERIALIZE_REAL(v.x) + ", " + SERIALIZE_REAL(v.y) + ", " + SERIALIZE_REAL(v.z) + ", " + SERIALIZE_REAL(v.w) + ")");
} break;
case Variant::VECTOR4I: {
Vector4i v = p_variant;
p_store_string_func(p_store_string_ud, "Vector4i(" + itos(v.x) + ", " + itos(v.y) + ", " + itos(v.z) + ", " + itos(v.w) + ")");
} break;
case Variant::PLANE: {
Plane p = p_variant;
p_store_string_func(p_store_string_ud, "Plane(" + rtos_fix(p.normal.x) + ", " + rtos_fix(p.normal.y) + ", " + rtos_fix(p.normal.z) + ", " + rtos_fix(p.d) + ")");
p_store_string_func(p_store_string_ud, "Plane(" + SERIALIZE_REAL(p.normal.x) + ", " + SERIALIZE_REAL(p.normal.y) + ", " + SERIALIZE_REAL(p.normal.z) + ", " + SERIALIZE_REAL(p.d) + ")");
} break;
case Variant::AABB: {
AABB aabb = p_variant;
p_store_string_func(p_store_string_ud, "AABB(" + rtos_fix(aabb.position.x) + ", " + rtos_fix(aabb.position.y) + ", " + rtos_fix(aabb.position.z) + ", " + rtos_fix(aabb.size.x) + ", " + rtos_fix(aabb.size.y) + ", " + rtos_fix(aabb.size.z) + ")");
p_store_string_func(p_store_string_ud, "AABB(" + SERIALIZE_REAL(aabb.position.x) + ", " + SERIALIZE_REAL(aabb.position.y) + ", " + SERIALIZE_REAL(aabb.position.z) + ", " + SERIALIZE_REAL(aabb.size.x) + ", " + SERIALIZE_REAL(aabb.size.y) + ", " + SERIALIZE_REAL(aabb.size.z) + ")");
} break;
case Variant::QUATERNION: {
Quaternion quaternion = p_variant;
p_store_string_func(p_store_string_ud, "Quaternion(" + rtos_fix(quaternion.x) + ", " + rtos_fix(quaternion.y) + ", " + rtos_fix(quaternion.z) + ", " + rtos_fix(quaternion.w) + ")");
p_store_string_func(p_store_string_ud, "Quaternion(" + SERIALIZE_REAL(quaternion.x) + ", " + SERIALIZE_REAL(quaternion.y) + ", " + SERIALIZE_REAL(quaternion.z) + ", " + SERIALIZE_REAL(quaternion.w) + ")");
} break;
case Variant::TRANSFORM2D: {
String s = "Transform2D(";
Expand All @@ -2026,7 +2048,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
if (i != 0 || j != 0) {
s += ", ";
}
s += rtos_fix(m3.columns[i][j]);
s += SERIALIZE_REAL(m3.columns[i][j]);
}
}

Expand All @@ -2040,7 +2062,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
if (i != 0 || j != 0) {
s += ", ";
}
s += rtos_fix(m3.rows[i][j]);
s += SERIALIZE_REAL(m3.rows[i][j]);
}
}

Expand All @@ -2055,11 +2077,11 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
if (i != 0 || j != 0) {
s += ", ";
}
s += rtos_fix(m3.rows[i][j]);
s += SERIALIZE_REAL(m3.rows[i][j]);
}
}

s = s + ", " + rtos_fix(t.origin.x) + ", " + rtos_fix(t.origin.y) + ", " + rtos_fix(t.origin.z);
s = s + ", " + SERIALIZE_REAL(t.origin.x) + ", " + SERIALIZE_REAL(t.origin.y) + ", " + SERIALIZE_REAL(t.origin.z);

p_store_string_func(p_store_string_ud, s + ")");
} break;
Expand All @@ -2071,7 +2093,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
if (i != 0 || j != 0) {
s += ", ";
}
s += rtos_fix(t.columns[i][j]);
s += SERIALIZE_REAL(t.columns[i][j]);
}
}

Expand All @@ -2081,7 +2103,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
// Misc types.
case Variant::COLOR: {
Color c = p_variant;
p_store_string_func(p_store_string_ud, "Color(" + rtos_fix(c.r) + ", " + rtos_fix(c.g) + ", " + rtos_fix(c.b) + ", " + rtos_fix(c.a) + ")");
p_store_string_func(p_store_string_ud, "Color(" + SERIALIZE_REAL(c.r) + ", " + SERIALIZE_REAL(c.g) + ", " + SERIALIZE_REAL(c.b) + ", " + SERIALIZE_REAL(c.a) + ")");
} break;
case Variant::STRING_NAME: {
String str = p_variant;
Expand Down Expand Up @@ -2396,7 +2418,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
if (i > 0) {
p_store_string_func(p_store_string_ud, ", ");
}
p_store_string_func(p_store_string_ud, rtos_fix(ptr[i]));
p_store_string_func(p_store_string_ud, SERIALIZE_REAL(ptr[i]));
}

p_store_string_func(p_store_string_ud, ")");
Expand All @@ -2411,7 +2433,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
if (i > 0) {
p_store_string_func(p_store_string_ud, ", ");
}
p_store_string_func(p_store_string_ud, rtos_fix(ptr[i]));
p_store_string_func(p_store_string_ud, SERIALIZE_REAL(ptr[i]));
}

p_store_string_func(p_store_string_ud, ")");
Expand Down Expand Up @@ -2441,7 +2463,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
if (i > 0) {
p_store_string_func(p_store_string_ud, ", ");
}
p_store_string_func(p_store_string_ud, rtos_fix(ptr[i].x) + ", " + rtos_fix(ptr[i].y));
p_store_string_func(p_store_string_ud, SERIALIZE_REAL(ptr[i].x) + ", " + SERIALIZE_REAL(ptr[i].y));
}

p_store_string_func(p_store_string_ud, ")");
Expand All @@ -2456,7 +2478,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
if (i > 0) {
p_store_string_func(p_store_string_ud, ", ");
}
p_store_string_func(p_store_string_ud, rtos_fix(ptr[i].x) + ", " + rtos_fix(ptr[i].y) + ", " + rtos_fix(ptr[i].z));
p_store_string_func(p_store_string_ud, SERIALIZE_REAL(ptr[i].x) + ", " + SERIALIZE_REAL(ptr[i].y) + ", " + SERIALIZE_REAL(ptr[i].z));
}

p_store_string_func(p_store_string_ud, ")");
Expand All @@ -2471,7 +2493,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
if (i > 0) {
p_store_string_func(p_store_string_ud, ", ");
}
p_store_string_func(p_store_string_ud, rtos_fix(ptr[i].r) + ", " + rtos_fix(ptr[i].g) + ", " + rtos_fix(ptr[i].b) + ", " + rtos_fix(ptr[i].a));
p_store_string_func(p_store_string_ud, SERIALIZE_REAL(ptr[i].r) + ", " + SERIALIZE_REAL(ptr[i].g) + ", " + SERIALIZE_REAL(ptr[i].b) + ", " + SERIALIZE_REAL(ptr[i].a));
}

p_store_string_func(p_store_string_ud, ")");
Expand All @@ -2486,7 +2508,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
if (i > 0) {
p_store_string_func(p_store_string_ud, ", ");
}
p_store_string_func(p_store_string_ud, rtos_fix(ptr[i].x) + ", " + rtos_fix(ptr[i].y) + ", " + rtos_fix(ptr[i].z) + ", " + rtos_fix(ptr[i].w));
p_store_string_func(p_store_string_ud, SERIALIZE_REAL(ptr[i].x) + ", " + SERIALIZE_REAL(ptr[i].y) + ", " + SERIALIZE_REAL(ptr[i].z) + ", " + SERIALIZE_REAL(ptr[i].w));
}

p_store_string_func(p_store_string_ud, ")");
Expand All @@ -2507,8 +2529,8 @@ static Error _write_to_str(void *ud, const String &p_string) {
return OK;
}

Error VariantWriter::write_to_string(const Variant &p_variant, String &r_string, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, bool p_compat) {
Error VariantWriter::write_to_string(const Variant &p_variant, String &r_string, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, bool p_compat, int p_max_digits) {
r_string = String();

return write(p_variant, _write_to_str, &r_string, p_encode_res_func, p_encode_res_ud, 0, p_compat);
return write(p_variant, _write_to_str, &r_string, p_encode_res_func, p_encode_res_ud, 0, p_compat, p_max_digits);
}
4 changes: 2 additions & 2 deletions core/variant/variant_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,8 @@ class VariantWriter {
typedef Error (*StoreStringFunc)(void *ud, const String &p_string);
typedef String (*EncodeResourceFunc)(void *ud, const Ref<Resource> &p_resource);

static Error write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int p_recursion_count = 0, bool p_compat = true);
static Error write_to_string(const Variant &p_variant, String &r_string, EncodeResourceFunc p_encode_res_func = nullptr, void *p_encode_res_ud = nullptr, bool p_compat = true);
static Error write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int p_recursion_count = 0, bool p_compat = true, int p_max_digits = 17);
static Error write_to_string(const Variant &p_variant, String &r_string, EncodeResourceFunc p_encode_res_func = nullptr, void *p_encode_res_ud = nullptr, bool p_compat = true, int p_max_digits = 17);
};

#endif // VARIANT_PARSER_H
3 changes: 2 additions & 1 deletion editor/doc_tools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -915,7 +915,8 @@ void DocTools::generate(BitField<GenerateFlags> p_flags) {
DocData::ConstantDoc constant;
constant.name = E;
Variant value = Variant::get_constant_value(Variant::Type(i), E);
constant.value = value.get_type() == Variant::INT ? itos(value) : value.get_construct_string().replace("\n", " ");
const int digits = 6; // Reduced precision is better for documentation, avoids unnecessary decimals.
constant.value = value.get_type() == Variant::INT ? itos(value) : value.get_construct_string(digits).replace("\n", " ");
constant.is_value_valid = true;
c.constants.push_back(constant);
}
Expand Down
Loading
Loading