mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Serialise doubles into more human friendly XML and JSON
This commit is contained in:
parent
77db5fde66
commit
bbe49f6b36
6 changed files with 124 additions and 17 deletions
|
|
@ -4,6 +4,30 @@ JUCE breaking changes
|
||||||
Develop
|
Develop
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
Change
|
||||||
|
------
|
||||||
|
The formatting of floating point numbers written to XML and JSON files has
|
||||||
|
changed.
|
||||||
|
|
||||||
|
Note that there is no change in precision - the XML and JSON files containing
|
||||||
|
the new format numbers will parse in exactly the same way, it is only the
|
||||||
|
string representation that has changed.
|
||||||
|
|
||||||
|
Possible Issues
|
||||||
|
---------------
|
||||||
|
If you rely upon exactly reproducing XML or JSON files then the new files may
|
||||||
|
be different.
|
||||||
|
|
||||||
|
Workaround
|
||||||
|
----------
|
||||||
|
Update any reference XML or JSON files to use the new format.
|
||||||
|
|
||||||
|
Rationale
|
||||||
|
---------
|
||||||
|
The new format retains full precision, provides a human friendly representation
|
||||||
|
of values near 1, and uses scientific notation for small and large numbers.
|
||||||
|
This prevents needless file size bloat from numbers like 0.00000000000000001.
|
||||||
|
|
||||||
|
|
||||||
Version 5.4.3
|
Version 5.4.3
|
||||||
=============
|
=============
|
||||||
|
|
|
||||||
|
|
@ -175,7 +175,7 @@ public:
|
||||||
int toInt (const ValueUnion& data) const noexcept override { return (int) data.doubleValue; }
|
int toInt (const ValueUnion& data) const noexcept override { return (int) data.doubleValue; }
|
||||||
int64 toInt64 (const ValueUnion& data) const noexcept override { return (int64) data.doubleValue; }
|
int64 toInt64 (const ValueUnion& data) const noexcept override { return (int64) data.doubleValue; }
|
||||||
double toDouble (const ValueUnion& data) const noexcept override { return data.doubleValue; }
|
double toDouble (const ValueUnion& data) const noexcept override { return data.doubleValue; }
|
||||||
String toString (const ValueUnion& data) const override { return minimiseLengthOfFloatString (String (data.doubleValue, 15, true)); }
|
String toString (const ValueUnion& data) const override { return serialiseDouble (data.doubleValue); }
|
||||||
bool toBool (const ValueUnion& data) const noexcept override { return data.doubleValue != 0.0; }
|
bool toBool (const ValueUnion& data) const noexcept override { return data.doubleValue != 0.0; }
|
||||||
bool isDouble() const noexcept override { return true; }
|
bool isDouble() const noexcept override { return true; }
|
||||||
bool isComparable() const noexcept override { return true; }
|
bool isComparable() const noexcept override { return true; }
|
||||||
|
|
|
||||||
|
|
@ -352,8 +352,7 @@ struct JSONFormatter
|
||||||
|
|
||||||
if (juce_isfinite (d))
|
if (juce_isfinite (d))
|
||||||
{
|
{
|
||||||
String doubleString (d, maximumDecimalPlaces, true);
|
out << serialiseDouble (d);
|
||||||
out << minimiseLengthOfFloatString (doubleString);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -664,12 +663,17 @@ public:
|
||||||
tests[1] = "1";
|
tests[1] = "1";
|
||||||
tests[1.1] = "1.1";
|
tests[1.1] = "1.1";
|
||||||
tests[1.01] = "1.01";
|
tests[1.01] = "1.01";
|
||||||
tests[0.76378] = "7.6378e-1";
|
tests[0.76378] = "0.76378";
|
||||||
tests[-10] = "-1e1";
|
tests[-10] = "-10";
|
||||||
tests[10.01] = "1.001e1";
|
tests[10.01] = "10.01";
|
||||||
tests[0.0123] = "1.23e-2";
|
tests[0.0123] = "0.0123";
|
||||||
tests[-3.7e-27] = "-3.7e-27";
|
tests[-3.7e-27] = "-3.7e-27";
|
||||||
tests[1e+40] = "1e40";
|
tests[1e+40] = "1e40";
|
||||||
|
tests[-12345678901234567.0] = "-1.234567890123457e16";
|
||||||
|
tests[192000] = "192000";
|
||||||
|
tests[1234567] = "1.234567e6";
|
||||||
|
tests[0.00006] = "0.00006";
|
||||||
|
tests[0.000006] = "6e-6";
|
||||||
|
|
||||||
for (auto& test : tests)
|
for (auto& test : tests)
|
||||||
expectEquals (JSON::toString (test.first), test.second);
|
expectEquals (JSON::toString (test.first), test.second);
|
||||||
|
|
|
||||||
|
|
@ -2258,6 +2258,48 @@ static String minimiseLengthOfFloatString (const String& input)
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static String serialiseDouble (double input)
|
||||||
|
{
|
||||||
|
auto absInput = std::abs (input);
|
||||||
|
|
||||||
|
if (absInput >= 1.0e6 || absInput <= 1.0e-5)
|
||||||
|
return minimiseLengthOfFloatString ({ input, 15, true });
|
||||||
|
|
||||||
|
int intInput = (int) input;
|
||||||
|
|
||||||
|
if ((double) intInput == input)
|
||||||
|
return minimiseLengthOfFloatString ({ input, 1 });
|
||||||
|
|
||||||
|
auto numberOfDecimalPlaces = [absInput]
|
||||||
|
{
|
||||||
|
if (absInput < 1.0)
|
||||||
|
{
|
||||||
|
if (absInput >= 1.0e-3)
|
||||||
|
{
|
||||||
|
if (absInput >= 1.0e-1) return 16;
|
||||||
|
if (absInput >= 1.0e-2) return 17;
|
||||||
|
return 18;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (absInput >= 1.0e-4) return 19;
|
||||||
|
return 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (absInput < 1.0e3)
|
||||||
|
{
|
||||||
|
if (absInput < 1.0e1) return 15;
|
||||||
|
if (absInput < 1.0e2) return 14;
|
||||||
|
return 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (absInput < 1.0e4) return 12;
|
||||||
|
if (absInput < 1.0e5) return 11;
|
||||||
|
return 10;
|
||||||
|
}();
|
||||||
|
|
||||||
|
return minimiseLengthOfFloatString (String (input, numberOfDecimalPlaces));
|
||||||
|
}
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
#if JUCE_UNIT_TESTS
|
#if JUCE_UNIT_TESTS
|
||||||
|
|
@ -2851,6 +2893,34 @@ public:
|
||||||
expectEquals (minimiseLengthOfFloatString (String (test.first, 15, true)), test.second);
|
expectEquals (minimiseLengthOfFloatString (String (test.first, 15, true)), test.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
beginTest ("Serialisation");
|
||||||
|
|
||||||
|
std::map <double, String> tests;
|
||||||
|
tests[1234567890123456.7] = "1.234567890123457e15";
|
||||||
|
tests[12345678.901234567] = "1.234567890123457e7";
|
||||||
|
tests[1234567.8901234567] = "1.234567890123457e6";
|
||||||
|
tests[123456.78901234567] = "123456.7890123457";
|
||||||
|
tests[12345.678901234567] = "12345.67890123457";
|
||||||
|
tests[1234.5678901234567] = "1234.567890123457";
|
||||||
|
tests[123.45678901234567] = "123.4567890123457";
|
||||||
|
tests[12.345678901234567] = "12.34567890123457";
|
||||||
|
tests[1.2345678901234567] = "1.234567890123457";
|
||||||
|
tests[0.12345678901234567] = "0.1234567890123457";
|
||||||
|
tests[0.012345678901234567] = "0.01234567890123457";
|
||||||
|
tests[0.0012345678901234567] = "0.001234567890123457";
|
||||||
|
tests[0.00012345678901234567] = "0.0001234567890123457";
|
||||||
|
tests[0.000012345678901234567] = "0.00001234567890123457";
|
||||||
|
tests[0.0000012345678901234567] = "1.234567890123457e-6";
|
||||||
|
tests[0.00000012345678901234567] = "1.234567890123457e-7";
|
||||||
|
|
||||||
|
for (auto& test : tests)
|
||||||
|
{
|
||||||
|
expectEquals (serialiseDouble (test.first), test.second);
|
||||||
|
expectEquals (serialiseDouble (-test.first), "-" + test.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -580,8 +580,7 @@ void XmlElement::setAttribute (const Identifier& attributeName, const int number
|
||||||
|
|
||||||
void XmlElement::setAttribute (const Identifier& attributeName, const double number)
|
void XmlElement::setAttribute (const Identifier& attributeName, const double number)
|
||||||
{
|
{
|
||||||
String doubleString (number, 15, true);
|
setAttribute (attributeName, serialiseDouble (number));
|
||||||
setAttribute (attributeName, minimiseLengthOfFloatString (doubleString));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void XmlElement::removeAttribute (const Identifier& attributeName) noexcept
|
void XmlElement::removeAttribute (const Identifier& attributeName) noexcept
|
||||||
|
|
@ -946,12 +945,17 @@ public:
|
||||||
tests[1] = "1";
|
tests[1] = "1";
|
||||||
tests[1.1] = "1.1";
|
tests[1.1] = "1.1";
|
||||||
tests[1.01] = "1.01";
|
tests[1.01] = "1.01";
|
||||||
tests[0.76378] = "7.6378e-1";
|
tests[0.76378] = "0.76378";
|
||||||
tests[-10] = "-1e1";
|
tests[-10] = "-10";
|
||||||
tests[10.01] = "1.001e1";
|
tests[10.01] = "10.01";
|
||||||
tests[0.0123] = "1.23e-2";
|
tests[0.0123] = "0.0123";
|
||||||
tests[-3.7e-27] = "-3.7e-27";
|
tests[-3.7e-27] = "-3.7e-27";
|
||||||
tests[1e+40] = "1e40";
|
tests[1e+40] = "1e40";
|
||||||
|
tests[-12345678901234567.0] = "-1.234567890123457e16";
|
||||||
|
tests[192000] = "192000";
|
||||||
|
tests[1234567] = "1.234567e6";
|
||||||
|
tests[0.00006] = "0.00006";
|
||||||
|
tests[0.000006] = "6e-6";
|
||||||
|
|
||||||
for (auto& test : tests)
|
for (auto& test : tests)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1198,12 +1198,17 @@ public:
|
||||||
tests[1] = "1";
|
tests[1] = "1";
|
||||||
tests[1.1] = "1.1";
|
tests[1.1] = "1.1";
|
||||||
tests[1.01] = "1.01";
|
tests[1.01] = "1.01";
|
||||||
tests[0.76378] = "7.6378e-1";
|
tests[0.76378] = "0.76378";
|
||||||
tests[-10] = "-1e1";
|
tests[-10] = "-10";
|
||||||
tests[10.01] = "1.001e1";
|
tests[10.01] = "10.01";
|
||||||
tests[0.0123] = "1.23e-2";
|
tests[0.0123] = "0.0123";
|
||||||
tests[-3.7e-27] = "-3.7e-27";
|
tests[-3.7e-27] = "-3.7e-27";
|
||||||
tests[1e+40] = "1e40";
|
tests[1e+40] = "1e40";
|
||||||
|
tests[-12345678901234567.0] = "-1.234567890123457e16";
|
||||||
|
tests[192000] = "192000";
|
||||||
|
tests[1234567] = "1.234567e6";
|
||||||
|
tests[0.00006] = "0.00006";
|
||||||
|
tests[0.000006] = "6e-6";
|
||||||
|
|
||||||
for (auto& test : tests)
|
for (auto& test : tests)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue