Skip to content

Commit

Permalink
Add digits argument to String::num_scientific and fix serializing
Browse files Browse the repository at this point in the history
  • Loading branch information
aaronfranke committed Oct 5, 2024
1 parent db66bd3 commit 61f94d0
Show file tree
Hide file tree
Showing 13 changed files with 287 additions and 45 deletions.
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

0 comments on commit 61f94d0

Please sign in to comment.