Skip to content

Commit

Permalink
Clarified some double-to-string conversion documentation, and made it…
Browse files Browse the repository at this point in the history
… avoid adding unnecessary trailing zeros (which were bloating XML and other dumps generated by things like ValueTree)
  • Loading branch information
julianstorer committed Jun 18, 2018
1 parent e242706 commit cba0803
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 27 deletions.
75 changes: 56 additions & 19 deletions modules/juce_core/text/juce_String.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -351,19 +351,19 @@ String::String (const CharPointer_UTF16 t) : text (StringHolder::createFromCha
String::String (const CharPointer_UTF32 t) : text (StringHolder::createFromCharPointer (t)) {}
String::String (const CharPointer_ASCII t) : text (StringHolder::createFromCharPointer (t)) {}

String::String (const CharPointer_UTF8 t, const size_t maxChars) : text (StringHolder::createFromCharPointer (t, maxChars)) {}
String::String (const CharPointer_UTF16 t, const size_t maxChars) : text (StringHolder::createFromCharPointer (t, maxChars)) {}
String::String (const CharPointer_UTF32 t, const size_t maxChars) : text (StringHolder::createFromCharPointer (t, maxChars)) {}
String::String (const wchar_t* const t, size_t maxChars) : text (StringHolder::createFromCharPointer (castToCharPointer_wchar_t (t), maxChars)) {}
String::String (CharPointer_UTF8 t, size_t maxChars) : text (StringHolder::createFromCharPointer (t, maxChars)) {}
String::String (CharPointer_UTF16 t, size_t maxChars) : text (StringHolder::createFromCharPointer (t, maxChars)) {}
String::String (CharPointer_UTF32 t, size_t maxChars) : text (StringHolder::createFromCharPointer (t, maxChars)) {}
String::String (const wchar_t* t, size_t maxChars) : text (StringHolder::createFromCharPointer (castToCharPointer_wchar_t (t), maxChars)) {}

String::String (const CharPointer_UTF8 start, const CharPointer_UTF8 end) : text (StringHolder::createFromCharPointer (start, end)) {}
String::String (const CharPointer_UTF16 start, const CharPointer_UTF16 end) : text (StringHolder::createFromCharPointer (start, end)) {}
String::String (const CharPointer_UTF32 start, const CharPointer_UTF32 end) : text (StringHolder::createFromCharPointer (start, end)) {}
String::String (CharPointer_UTF8 start, CharPointer_UTF8 end) : text (StringHolder::createFromCharPointer (start, end)) {}
String::String (CharPointer_UTF16 start, CharPointer_UTF16 end) : text (StringHolder::createFromCharPointer (start, end)) {}
String::String (CharPointer_UTF32 start, CharPointer_UTF32 end) : text (StringHolder::createFromCharPointer (start, end)) {}

String::String (const std::string& s) : text (StringHolder::createFromFixedLength (s.data(), s.size())) {}
String::String (StringRef s) : text (StringHolder::createFromCharPointer (s.text)) {}

String String::charToString (const juce_wchar character)
String String::charToString (juce_wchar character)
{
String result (PreallocationBytes (CharPointerType::getBytesRequiredFor (character)));
CharPointerType t (result.text);
Expand Down Expand Up @@ -397,7 +397,7 @@ namespace NumberToStringConverters
}

// pass in a pointer to the END of a buffer..
static char* numberToString (char* t, const int64 n) noexcept
static char* numberToString (char* t, int64 n) noexcept
{
if (n >= 0)
return printDigits (t, static_cast<uint64> (n));
Expand All @@ -414,7 +414,7 @@ namespace NumberToStringConverters
return printDigits (t, v);
}

static char* numberToString (char* t, const int n) noexcept
static char* numberToString (char* t, int n) noexcept
{
if (n >= 0)
return printDigits (t, static_cast<unsigned int> (n));
Expand All @@ -426,12 +426,12 @@ namespace NumberToStringConverters
return t;
}

static char* numberToString (char* t, const unsigned int v) noexcept
static char* numberToString (char* t, unsigned int v) noexcept
{
return printDigits (t, v);
}

static char* numberToString (char* t, const long n) noexcept
static char* numberToString (char* t, long n) noexcept
{
if (n >= 0)
return printDigits (t, static_cast<unsigned long> (n));
Expand All @@ -441,7 +441,7 @@ namespace NumberToStringConverters
return t;
}

static char* numberToString (char* t, const unsigned long v) noexcept
static char* numberToString (char* t, unsigned long v) noexcept
{
return printDigits (t, v);
}
Expand Down Expand Up @@ -469,11 +469,34 @@ namespace NumberToStringConverters
o << n;
}

return (size_t) (pptr() - pbase());
return findLengthWithoutTrailingZeros (pbase(), pptr());
}

static size_t findLengthWithoutTrailingZeros (const char* const start,
const char* const end)
{
for (auto e = end; e > start + 1; --e)
{
auto lastChar = *(e - 1);

if (lastChar != '0')
{
if (lastChar == '.')
return (size_t) (e + 1 - start);

for (auto s = start; s < e; ++s)
if (*s == '.')
return (size_t) (e - start);

break;
}
}

return (size_t) (end - start);
}
};

static char* doubleToString (char* buffer, const int numChars, double n, int numDecPlaces, size_t& len) noexcept
static char* doubleToString (char* buffer, int numChars, double n, int numDecPlaces, size_t& len) noexcept
{
if (numDecPlaces > 0 && numDecPlaces < 7 && n > -1.0e20 && n < 1.0e20)
{
Expand All @@ -482,7 +505,14 @@ namespace NumberToStringConverters
auto v = (int64) (std::pow (10.0, numDecPlaces) * std::abs (n) + 0.5);
*--t = (char) 0;

while (numDecPlaces >= 0 || v > 0)
// skip trailing zeros
while (numDecPlaces > 1 && (v % 10) == 0)
{
v /= 10;
--numDecPlaces;
}

while (v > 0 || numDecPlaces >= 0)
{
if (numDecPlaces == 0)
*--t = '.';
Expand All @@ -507,15 +537,15 @@ namespace NumberToStringConverters
}

template <typename IntegerType>
static String::CharPointerType createFromInteger (const IntegerType number)
static String::CharPointerType createFromInteger (IntegerType number)
{
char buffer [charsNeededForInt];
auto* end = buffer + numElementsInArray (buffer);
auto* start = numberToString (end, number);
return StringHolder::createFromFixedLength (start, (size_t) (end - start - 1));
}

static String::CharPointerType createFromDouble (const double number, const int numberOfDecimalPlaces)
static String::CharPointerType createFromDouble (double number, int numberOfDecimalPlaces)
{
char buffer [charsNeededForDouble];
size_t len;
Expand Down Expand Up @@ -2491,7 +2521,14 @@ class StringTests : public UnitTest
expect (String::toHexString (data, 8, 1).equalsIgnoreCase ("01 02 03 04 0a 0b 0c 0d"));
expect (String::toHexString (data, 8, 2).equalsIgnoreCase ("0102 0304 0a0b 0c0d"));

expectEquals (String (2589410.5894, 7), String ("2589410.5894000"));
expectEquals (String (2589410.5894, 7), String ("2589410.5894"));
expectEquals (String (2589410.5894, 4), String ("2589410.5894"));
expectEquals (String (100000.0, 1), String ("100000.0"));
expectEquals (String (100000.0, 10), String ("100000.0"));
expectEquals (String (100000.001, 8), String ("100000.001"));
expectEquals (String (100000.001, 4), String ("100000.001"));
expectEquals (String (100000.001, 3), String ("100000.001"));
expectEquals (String (100000.001, 2), String ("100000.0"));

beginTest ("Subsections");
String s3;
Expand Down
18 changes: 10 additions & 8 deletions modules/juce_core/text/juce_String.h
Original file line number Diff line number Diff line change
Expand Up @@ -962,21 +962,23 @@ class JUCE_API String final

/** Creates a string representing this floating-point number.
@param floatValue the value to convert to a string
@param numberOfDecimalPlaces if this is > 0, it will format the number using that many
decimal places, and will not use exponent notation. If 0 or
less, it will use exponent notation if necessary.
@param maxNumberOfDecimalPlaces if this is > 0, it will format the number using no more
decimal places than this amount, and will not use exponent
notation. If 0 or less, it will use a default format, and
exponent notation if necessary.
@see getDoubleValue, getIntValue
*/
String (float floatValue, int numberOfDecimalPlaces);
String (float floatValue, int maxNumberOfDecimalPlaces);

/** Creates a string representing this floating-point number.
@param doubleValue the value to convert to a string
@param numberOfDecimalPlaces if this is > 0, it will format the number using that many
decimal places, and will not use exponent notation. If 0 or
less, it will use exponent notation if necessary.
@param maxNumberOfDecimalPlaces if this is > 0, it will format the number using no more
decimal places than this amount, and will not use exponent
notation. If 0 or less, it will use a default format, and
exponent notation if necessary.
@see getFloatValue, getIntValue
*/
String (double doubleValue, int numberOfDecimalPlaces);
String (double doubleValue, int maxNumberOfDecimalPlaces);

// Automatically creating a String from a bool opens up lots of nasty type conversion edge cases.
// If you want a String representation of a bool you can cast the bool to an int first.
Expand Down

0 comments on commit cba0803

Please sign in to comment.