upgrade to JUCE 5.4.3. Remove (probably) unused JUCE modules. Remove VST2 target (it's been end-of-life'd by Steinberg and by JUCE)

This commit is contained in:
Alex Birch
2019-06-22 20:41:38 +01:00
parent d22c2cd4fa
commit 9ee566b251
1140 changed files with 67534 additions and 105952 deletions

View File

@ -44,10 +44,7 @@ public:
{
}
inline CharPointer_ASCII (const CharPointer_ASCII& other) noexcept
: data (other.data)
{
}
inline CharPointer_ASCII (const CharPointer_ASCII& other) = default;
inline CharPointer_ASCII operator= (const CharPointer_ASCII other) noexcept
{

View File

@ -45,10 +45,7 @@ public:
{
}
inline CharPointer_UTF16 (const CharPointer_UTF16& other) noexcept
: data (other.data)
{
}
inline CharPointer_UTF16 (const CharPointer_UTF16& other) = default;
inline CharPointer_UTF16 operator= (CharPointer_UTF16 other) noexcept
{

View File

@ -41,10 +41,7 @@ public:
{
}
inline CharPointer_UTF32 (const CharPointer_UTF32& other) noexcept
: data (other.data)
{
}
inline CharPointer_UTF32 (const CharPointer_UTF32& other) = default;
inline CharPointer_UTF32 operator= (CharPointer_UTF32 other) noexcept
{

View File

@ -41,10 +41,7 @@ public:
{
}
inline CharPointer_UTF8 (const CharPointer_UTF8& other) noexcept
: data (other.data)
{
}
inline CharPointer_UTF8 (const CharPointer_UTF8& other) = default;
inline CharPointer_UTF8 operator= (CharPointer_UTF8 other) noexcept
{

View File

@ -236,13 +236,23 @@ public:
STRING_DOUBLE_PAIR_COMBOS (10e10),
STRING_DOUBLE_PAIR_COMBOS (1.4962e+2),
STRING_DOUBLE_PAIR_COMBOS (3198693.0973e4),
STRING_DOUBLE_PAIR_COMBOS (10973097.2087e-4),
STRING_DOUBLE_PAIR_COMBOS (10973097.2087E-4),
STRING_DOUBLE_PAIR_COMBOS (1.3986e00006),
STRING_DOUBLE_PAIR_COMBOS (2087.3087e+00006),
STRING_DOUBLE_PAIR_COMBOS (6.0872e-00006),
// Too many sig figs. The parsing routine on MinGW gets the last
// significant figure wrong.
STRING_DOUBLE_PAIR_COMBOS (17654321098765432.9),
STRING_DOUBLE_PAIR_COMBOS (183456789012345678.9),
STRING_DOUBLE_PAIR_COMBOS (1934567890123456789.9),
STRING_DOUBLE_PAIR_COMBOS (20345678901234567891.9),
STRING_DOUBLE_PAIR_COMBOS (10000000000000000303786028427003666890752.000000),
STRING_DOUBLE_PAIR_COMBOS (10000000000000000303786028427003666890752e3),
STRING_DOUBLE_PAIR_COMBOS (10000000000000000303786028427003666890752e100),
STRING_DOUBLE_PAIR_COMBOS (10000000000000000303786028427003666890752.000000e-5),
STRING_DOUBLE_PAIR_COMBOS (10000000000000000303786028427003666890752.000000e-40),
STRING_DOUBLE_PAIR_COMBOS (1.23456789012345678901234567890),
STRING_DOUBLE_PAIR_COMBOS (1.23456789012345678901234567890e-111)
@ -262,6 +272,7 @@ public:
{
String nans[] = { "NaN", "-nan", "+NAN", "1.0E1024", "-1.0E-999", "1.23456789012345678901234567890e123456789"};
for (auto nan : nans)
{
auto charPtr = nan.getCharPointer();
@ -271,6 +282,7 @@ public:
{
String infs[] = { "Inf", "-inf", "INF"};
for (auto inf : infs)
{
auto charPtr = inf.getCharPointer();

View File

@ -295,6 +295,7 @@ public:
int numSigFigs = 0;
bool decimalPointFound = false;
int extraExponent = 0;
for (;;)
{
@ -302,9 +303,22 @@ public:
{
auto digit = (int) text.getAndAdvance() - '0';
if (numSigFigs >= maxSignificantDigits
|| ((numSigFigs == 0 && (! decimalPointFound)) && digit == 0))
continue;
if (decimalPointFound)
{
if (numSigFigs >= maxSignificantDigits)
continue;
}
else
{
if (numSigFigs >= maxSignificantDigits)
{
++extraExponent;
continue;
}
if (numSigFigs == 0 && digit == 0)
continue;
}
*currentCharacter++ = (char) ('0' + (char) digit);
numSigFigs++;
@ -323,37 +337,58 @@ public:
c = *text;
auto writeExponentDigits = [](int exponent, char* destination)
{
auto exponentDivisor = 100;
while (exponentDivisor > 1)
{
auto digit = exponent / exponentDivisor;
*destination++ = (char) ('0' + (char) digit);
exponent -= digit * exponentDivisor;
exponentDivisor /= 10;
}
*destination++ = (char) ('0' + (char) exponent);
};
if ((c == 'e' || c == 'E') && numSigFigs > 0)
{
*currentCharacter++ = 'e';
bool parsedExponentIsPositive = true;
switch (*++text)
{
case '-': *currentCharacter++ = '-'; // Fall-through..
case '-': parsedExponentIsPositive = false; // Fall-through..
case '+': ++text;
}
int exponentMagnitude = 0;
int exponent = 0;
while (text.isDigit())
{
if (currentCharacter == &buffer[bufferSize - 1])
return std::numeric_limits<double>::quiet_NaN();
auto digit = (int) text.getAndAdvance() - '0';
if (digit != 0 || exponentMagnitude != 0)
{
*currentCharacter++ = (char) ('0' + (char) digit);
exponentMagnitude = (exponentMagnitude * 10) + digit;
}
if (digit != 0 || exponent != 0)
exponent = (exponent * 10) + digit;
}
if (exponentMagnitude > std::numeric_limits<double>::max_exponent10)
exponent = extraExponent + (parsedExponentIsPositive ? exponent : -exponent);
if (exponent < 0)
*currentCharacter++ = '-';
exponent = std::abs (exponent);
if (exponent > std::numeric_limits<double>::max_exponent10)
return std::numeric_limits<double>::quiet_NaN();
if (exponentMagnitude == 0)
*currentCharacter++ = '0';
writeExponentDigits (exponent, currentCharacter);
}
else if (extraExponent > 0)
{
*currentCharacter++ = 'e';
writeExponentDigits (extraExponent, currentCharacter);
}
#if JUCE_WINDOWS

View File

@ -28,11 +28,11 @@ Identifier::~Identifier() noexcept {}
Identifier::Identifier (const Identifier& other) noexcept : name (other.name) {}
Identifier::Identifier (Identifier&& other) noexcept : name (static_cast<String&&> (other.name)) {}
Identifier::Identifier (Identifier&& other) noexcept : name (std::move (other.name)) {}
Identifier& Identifier::operator= (Identifier&& other) noexcept
{
name = static_cast<String&&> (other.name);
name = std::move (other.name);
return *this;
}

View File

@ -191,7 +191,6 @@ private:
StringArray countryCodes;
StringPairArray translations;
std::unique_ptr<LocalisedStrings> fallback;
friend struct ContainerDeletePolicy<LocalisedStrings>;
void loadFromText (const String&, bool ignoreCase);

View File

@ -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);
@ -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));
@ -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));
@ -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));
@ -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);
}
@ -455,14 +455,14 @@ namespace NumberToStringConverters
setp (d, d + charsNeededForDouble);
}
size_t writeDouble (double n, int numDecPlaces)
size_t writeDouble (double n, int numDecPlaces, bool useScientificNotation)
{
{
std::ostream o (this);
if (numDecPlaces > 0)
{
o.setf (std::ios_base::fixed);
o.setf (useScientificNotation ? std::ios_base::scientific : std::ios_base::fixed);
o.precision ((std::streamsize) numDecPlaces);
}
@ -473,41 +473,16 @@ namespace NumberToStringConverters
}
};
static char* doubleToString (char* buffer, const int numChars, double n, int numDecPlaces, size_t& len) noexcept
static char* doubleToString (char* buffer, double n, int numDecPlaces, bool useScientificNotation, size_t& len) noexcept
{
if (numDecPlaces > 0 && numDecPlaces < 7 && n > -1.0e20 && n < 1.0e20)
{
auto* end = buffer + numChars;
auto* t = end;
auto v = (int64) (std::pow (10.0, numDecPlaces) * std::abs (n) + 0.5);
*--t = (char) 0;
while (numDecPlaces >= 0 || v > 0)
{
if (numDecPlaces == 0)
*--t = '.';
*--t = (char) ('0' + (v % 10));
v /= 10;
--numDecPlaces;
}
if (n < 0)
*--t = '-';
len = (size_t) (end - t - 1);
return t;
}
StackArrayStream strm (buffer);
len = strm.writeDouble (n, numDecPlaces);
len = strm.writeDouble (n, numDecPlaces, useScientificNotation);
jassert (len <= charsNeededForDouble);
return buffer;
}
template <typename IntegerType>
static String::CharPointerType createFromInteger (const IntegerType number)
static String::CharPointerType createFromInteger (IntegerType number)
{
char buffer [charsNeededForInt];
auto* end = buffer + numElementsInArray (buffer);
@ -515,11 +490,11 @@ namespace NumberToStringConverters
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, bool useScientificNotation)
{
char buffer [charsNeededForDouble];
size_t len;
auto start = doubleToString (buffer, numElementsInArray (buffer), (double) number, numberOfDecimalPlaces, len);
auto start = doubleToString (buffer, number, numberOfDecimalPlaces, useScientificNotation, len);
return StringHolder::createFromFixedLength (start, len);
}
}
@ -534,10 +509,10 @@ String::String (uint64 number) : text (NumberToStringConverters::createF
String::String (long number) : text (NumberToStringConverters::createFromInteger (number)) {}
String::String (unsigned long number) : text (NumberToStringConverters::createFromInteger (number)) {}
String::String (float number) : text (NumberToStringConverters::createFromDouble ((double) number, 0)) {}
String::String (double number) : text (NumberToStringConverters::createFromDouble (number, 0)) {}
String::String (float number, int numberOfDecimalPlaces) : text (NumberToStringConverters::createFromDouble ((double) number, numberOfDecimalPlaces)) {}
String::String (double number, int numberOfDecimalPlaces) : text (NumberToStringConverters::createFromDouble (number, numberOfDecimalPlaces)) {}
String::String (float number) : text (NumberToStringConverters::createFromDouble ((double) number, 0, false)) {}
String::String (double number) : text (NumberToStringConverters::createFromDouble ( number, 0, false)) {}
String::String (float number, int numberOfDecimalPlaces, bool useScientificNotation) : text (NumberToStringConverters::createFromDouble ((double) number, numberOfDecimalPlaces, useScientificNotation)) {}
String::String (double number, int numberOfDecimalPlaces, bool useScientificNotation) : text (NumberToStringConverters::createFromDouble ( number, numberOfDecimalPlaces, useScientificNotation)) {}
//==============================================================================
int String::length() const noexcept
@ -1392,7 +1367,7 @@ String String::replaceCharacter (const juce_wchar charToReplace, const juce_wcha
break;
}
return static_cast<String&&> (builder.result);
return std::move (builder.result);
}
String String::replaceCharacters (StringRef charactersToReplace, StringRef charactersToInsertInstead) const
@ -1417,7 +1392,7 @@ String String::replaceCharacters (StringRef charactersToReplace, StringRef chara
break;
}
return static_cast<String&&> (builder.result);
return std::move (builder.result);
}
//==============================================================================
@ -1499,7 +1474,7 @@ String String::toUpperCase() const
++(builder.source);
}
return static_cast<String&&> (builder.result);
return std::move (builder.result);
}
String String::toLowerCase() const
@ -1517,7 +1492,7 @@ String String::toLowerCase() const
++(builder.source);
}
return static_cast<String&&> (builder.result);
return std::move (builder.result);
}
//==============================================================================
@ -1782,7 +1757,7 @@ String String::retainCharacters (StringRef charactersToRetain) const
}
builder.write (0);
return static_cast<String&&> (builder.result);
return std::move (builder.result);
}
String String::removeCharacters (StringRef charactersToRemove) const
@ -1803,7 +1778,7 @@ String String::removeCharacters (StringRef charactersToRemove) const
break;
}
return static_cast<String&&> (builder.result);
return std::move (builder.result);
}
String String::initialSectionContainingOnly (StringRef permittedCharacters) const
@ -2005,7 +1980,7 @@ String String::createStringFromData (const void* const unknownData, int size)
StringCreationHelper builder ((size_t) numChars);
auto src = (const uint16*) (data + 2);
auto src = reinterpret_cast<const uint16*> (data + 2);
if (CharPointer_UTF16::isByteOrderMarkBigEndian (data))
{
@ -2019,7 +1994,7 @@ String String::createStringFromData (const void* const unknownData, int size)
}
builder.write (0);
return static_cast<String&&> (builder.result);
return std::move (builder.result);
}
auto* start = (const char*) data;
@ -2047,7 +2022,7 @@ struct StringEncodingConverter
{
auto& source = const_cast<String&> (s);
typedef typename CharPointerType_Dest::CharType DestChar;
using DestChar = typename CharPointerType_Dest::CharType;
if (source.isEmpty())
return CharPointerType_Dest (reinterpret_cast<const DestChar*> (&emptyChar));
@ -2075,19 +2050,19 @@ struct StringEncodingConverter
template <>
struct StringEncodingConverter<CharPointer_UTF8, CharPointer_UTF8>
{
static CharPointer_UTF8 convert (const String& source) noexcept { return CharPointer_UTF8 ((CharPointer_UTF8::CharType*) source.getCharPointer().getAddress()); }
static CharPointer_UTF8 convert (const String& source) noexcept { return CharPointer_UTF8 (reinterpret_cast<CharPointer_UTF8::CharType*> (source.getCharPointer().getAddress())); }
};
template <>
struct StringEncodingConverter<CharPointer_UTF16, CharPointer_UTF16>
{
static CharPointer_UTF16 convert (const String& source) noexcept { return CharPointer_UTF16 ((CharPointer_UTF16::CharType*) source.getCharPointer().getAddress()); }
static CharPointer_UTF16 convert (const String& source) noexcept { return CharPointer_UTF16 (reinterpret_cast<CharPointer_UTF16::CharType*> (source.getCharPointer().getAddress())); }
};
template <>
struct StringEncodingConverter<CharPointer_UTF32, CharPointer_UTF32>
{
static CharPointer_UTF32 convert (const String& source) noexcept { return CharPointer_UTF32 ((CharPointer_UTF32::CharType*) source.getCharPointer().getAddress()); }
static CharPointer_UTF32 convert (const String& source) noexcept { return CharPointer_UTF32 (reinterpret_cast<CharPointer_UTF32::CharType*> (source.getCharPointer().getAddress())); }
};
CharPointer_UTF8 String::toUTF8() const { return StringEncodingConverter<CharPointerType, CharPointer_UTF8 >::convert (*this); }
@ -2210,12 +2185,128 @@ StringRef::StringRef (String::CharPointerType stringLiteral) noexcept : text (s
StringRef::StringRef (const String& string) noexcept : text (string.getCharPointer()) {}
StringRef::StringRef (const std::string& string) : StringRef (string.c_str()) {}
//==============================================================================
static String reduceLengthOfFloatString (const String& input)
{
const auto start = input.getCharPointer();
const auto end = start + (int) input.length();
auto trimStart = end;
auto trimEnd = trimStart;
auto exponentTrimStart = end;
auto exponentTrimEnd = exponentTrimStart;
decltype (*start) currentChar = '\0';
for (auto c = end - 1; c > start; --c)
{
currentChar = *c;
if (currentChar == '0' && c + 1 == trimStart)
{
--trimStart;
}
else if (currentChar == '.')
{
if (trimStart == c + 1 && trimStart != end && *trimStart == '0')
++trimStart;
break;
}
else if (currentChar == 'e' || currentChar == 'E')
{
auto cNext = c + 1;
if (cNext != end)
{
if (*cNext == '-')
++cNext;
exponentTrimStart = cNext;
if (cNext != end && *cNext == '+')
++cNext;
exponentTrimEnd = cNext;
}
while (cNext != end && *cNext++ == '0')
exponentTrimEnd = cNext;
if (exponentTrimEnd == end)
exponentTrimStart = c;
trimStart = c;
trimEnd = trimStart;
}
}
if ((trimStart != trimEnd && currentChar == '.') || exponentTrimStart != exponentTrimEnd)
{
if (trimStart == trimEnd)
return String (start, exponentTrimStart) + String (exponentTrimEnd, end);
if (exponentTrimStart == exponentTrimEnd)
return String (start, trimStart) + String (trimEnd, end);
if (trimEnd == exponentTrimStart)
return String (start, trimStart) + String (exponentTrimEnd, end);
return String (start, trimStart) + String (trimEnd, exponentTrimStart) + String (exponentTrimEnd, end);
}
return input;
}
static String serialiseDouble (double input)
{
auto absInput = std::abs (input);
if (absInput >= 1.0e6 || absInput <= 1.0e-5)
return reduceLengthOfFloatString ({ input, 15, true });
int intInput = (int) input;
if ((double) intInput == input)
return { 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 reduceLengthOfFloatString (String (input, numberOfDecimalPlaces));
}
//==============================================================================
//==============================================================================
#if JUCE_UNIT_TESTS
#define STRINGIFY2(X) #X
#define STRINGIFY(X) STRINGIFY2(X)
#define STRINGIFY2(X) #X
#define STRINGIFY(X) STRINGIFY2(X)
class StringTests : public UnitTest
{
public:
@ -2491,7 +2582,21 @@ public:
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 (12345.67, 4), String ("12345.6700"));
expectEquals (String (12345.67, 6), String ("12345.670000"));
expectEquals (String (2589410.5894, 7), String ("2589410.5894000"));
expectEquals (String (12345.67, 8), String ("12345.67000000"));
expectEquals (String (1e19, 4), String ("10000000000000000000.0000"));
expectEquals (String (1e-34, 36), String ("0.000000000000000000000000000000000100"));
expectEquals (String (1.39, 1), String ("1.4"));
expectEquals (String (12345.67, 4, true), String ("1.2346e+04"));
expectEquals (String (12345.67, 6, true), String ("1.234567e+04"));
expectEquals (String (2589410.5894, 7, true), String ("2.5894106e+06"));
expectEquals (String (12345.67, 8, true), String ("1.23456700e+04"));
expectEquals (String (1e19, 4, true), String ("1.0000e+19"));
expectEquals (String (1e-34, 5, true), String ("1.00000e-34"));
expectEquals (String (1.39, 1, true), String ("1.4e+00"));
beginTest ("Subsections");
String s3;
@ -2681,6 +2786,147 @@ public:
expect (! v2.equals (v4));
expect (! v4.equals (v2));
}
{
beginTest ("Significant figures");
// Integers
expectEquals (String::toDecimalStringWithSignificantFigures (13, 1), String ("10"));
expectEquals (String::toDecimalStringWithSignificantFigures (13, 2), String ("13"));
expectEquals (String::toDecimalStringWithSignificantFigures (13, 3), String ("13.0"));
expectEquals (String::toDecimalStringWithSignificantFigures (13, 4), String ("13.00"));
expectEquals (String::toDecimalStringWithSignificantFigures (19368, 1), String ("20000"));
expectEquals (String::toDecimalStringWithSignificantFigures (19348, 3), String ("19300"));
expectEquals (String::toDecimalStringWithSignificantFigures (-5, 1), String ("-5"));
expectEquals (String::toDecimalStringWithSignificantFigures (-5, 3), String ("-5.00"));
// Zero
expectEquals (String::toDecimalStringWithSignificantFigures (0, 1), String ("0"));
expectEquals (String::toDecimalStringWithSignificantFigures (0, 2), String ("0.0"));
expectEquals (String::toDecimalStringWithSignificantFigures (0, 3), String ("0.00"));
// Floating point
expectEquals (String::toDecimalStringWithSignificantFigures (19.0, 1), String ("20"));
expectEquals (String::toDecimalStringWithSignificantFigures (19.0, 2), String ("19"));
expectEquals (String::toDecimalStringWithSignificantFigures (19.0, 3), String ("19.0"));
expectEquals (String::toDecimalStringWithSignificantFigures (19.0, 4), String ("19.00"));
expectEquals (String::toDecimalStringWithSignificantFigures (-5.45, 1), String ("-5"));
expectEquals (String::toDecimalStringWithSignificantFigures (-5.45, 3), String ("-5.45"));
expectEquals (String::toDecimalStringWithSignificantFigures (12345.6789, 9), String ("12345.6789"));
expectEquals (String::toDecimalStringWithSignificantFigures (12345.6789, 8), String ("12345.679"));
expectEquals (String::toDecimalStringWithSignificantFigures (12345.6789, 5), String ("12346"));
expectEquals (String::toDecimalStringWithSignificantFigures (0.00028647, 6), String ("0.000286470"));
expectEquals (String::toDecimalStringWithSignificantFigures (0.0028647, 6), String ("0.00286470"));
expectEquals (String::toDecimalStringWithSignificantFigures (2.8647, 6), String ("2.86470"));
expectEquals (String::toDecimalStringWithSignificantFigures (-0.0000000000019, 1), String ("-0.000000000002"));
}
{
beginTest ("Float trimming");
{
StringPairArray tests;
tests.set ("1", "1");
tests.set ("1.0", "1.0");
tests.set ("-1", "-1");
tests.set ("-100", "-100");
tests.set ("110", "110");
tests.set ("9090", "9090");
tests.set ("1000.0", "1000.0");
tests.set ("1.0", "1.0");
tests.set ("-1.00", "-1.0");
tests.set ("1.20", "1.2");
tests.set ("1.300", "1.3");
tests.set ("1.301", "1.301");
tests.set ("1e", "1");
tests.set ("-1e+", "-1");
tests.set ("1e-", "1");
tests.set ("1e0", "1");
tests.set ("1e+0", "1");
tests.set ("1e-0", "1");
tests.set ("1e000", "1");
tests.set ("1e+000", "1");
tests.set ("-1e-000", "-1");
tests.set ("1e100", "1e100");
tests.set ("100e100", "100e100");
tests.set ("100.0e0100", "100.0e100");
tests.set ("-1e1", "-1e1");
tests.set ("1e10", "1e10");
tests.set ("-1e+10", "-1e10");
tests.set ("1e-10", "1e-10");
tests.set ("1e0010", "1e10");
tests.set ("1e-0010", "1e-10");
tests.set ("1e-1", "1e-1");
tests.set ("-1.0e1", "-1.0e1");
tests.set ("1.0e-1", "1.0e-1");
tests.set ("1.00e-1", "1.0e-1");
tests.set ("1.001e1", "1.001e1");
tests.set ("1.010e+1", "1.01e1");
tests.set ("-1.1000e1", "-1.1e1");
for (auto& input : tests.getAllKeys())
expectEquals (reduceLengthOfFloatString (input), tests[input]);
}
{
std::map<double, String> tests;
tests[1] = "1.0";
tests[1.1] = "1.1";
tests[1.01] = "1.01";
tests[0.76378] = "7.6378e-1";
tests[-10] = "-1.0e1";
tests[10.01] = "1.001e1";
tests[10691.01] = "1.069101e4";
tests[0.0123] = "1.23e-2";
tests[-3.7e-27] = "-3.7e-27";
tests[1e+40] = "1.0e40";
for (auto& test : tests)
expectEquals (reduceLengthOfFloatString (String (test.first, 15, true)), test.second);
}
}
{
beginTest ("Serialisation");
std::map <double, String> tests;
tests[364] = "364.0";
tests[1e7] = "1.0e7";
tests[12345678901] = "1.2345678901e10";
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);
}
}
}
};

View File

@ -153,11 +153,11 @@ public:
toUTF32() methods let you access the string's content in any of the other formats.
*/
#if (JUCE_STRING_UTF_TYPE == 32)
typedef CharPointer_UTF32 CharPointerType;
using CharPointerType = CharPointer_UTF32;
#elif (JUCE_STRING_UTF_TYPE == 16)
typedef CharPointer_UTF16 CharPointerType;
using CharPointerType = CharPointer_UTF16;
#elif (DOXYGEN || JUCE_STRING_UTF_TYPE == 8)
typedef CharPointer_UTF8 CharPointerType;
using CharPointerType = CharPointer_UTF8;
#else
#error "You must set the value of JUCE_STRING_UTF_TYPE to be either 8, 16, or 32!"
#endif
@ -962,21 +962,26 @@ public:
/** 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 numberOfDecimalPlaces if this is > 0 the number will be formatted using that many
decimal places, adding trailing zeros as required. If 0 or
less the number will be formatted using the C++ standard
library default format, which uses scientific notation for
large and small numbers.
@param useScientificNotation if the number should be formatted using scientific notation
@see getDoubleValue, getIntValue
*/
String (float floatValue, int numberOfDecimalPlaces);
String (float floatValue, int numberOfDecimalPlaces, bool useScientificNotation = false);
/** 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.
decimal places, adding trailing zeros as required, and
will not use exponent notation. If 0 or less, it will use
exponent notation if necessary.
@param useScientificNotation if the number should be formatted using scientific notation
@see getFloatValue, getIntValue
*/
String (double doubleValue, int numberOfDecimalPlaces);
String (double doubleValue, int numberOfDecimalPlaces, bool useScientificNotation = false);
// 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.
@ -1056,6 +1061,131 @@ public:
*/
static String toHexString (const void* data, int size, int groupSize = 1);
/** Returns a string containing a decimal with a set number of significant figures.
@param number the intput number
@param numberOfSignificantFigures the number of significant figures to use
*/
template <typename DecimalType>
static String toDecimalStringWithSignificantFigures (DecimalType number, int numberOfSignificantFigures)
{
jassert (numberOfSignificantFigures > 0);
if (number == 0)
{
if (numberOfSignificantFigures > 1)
{
String result ("0.0");
for (int i = 2; i < numberOfSignificantFigures; ++i)
result += "0";
return result;
}
return "0";
}
auto numDigitsBeforePoint = (int) std::ceil (std::log10 (number < 0 ? -number : number));
#if JUCE_PROJUCER_LIVE_BUILD
auto doubleNumber = (double) number;
constexpr int bufferSize = 311;
char buffer[bufferSize];
auto* ptr = &(buffer[0]);
auto* const safeEnd = ptr + (bufferSize - 1);
auto numSigFigsParsed = 0;
auto writeToBuffer = [safeEnd] (char* destination, char data)
{
*destination++ = data;
if (destination == safeEnd)
{
*destination = '\0';
return true;
}
return false;
};
auto truncateOrRound = [numberOfSignificantFigures] (double fractional, int sigFigsParsed)
{
return (sigFigsParsed == numberOfSignificantFigures - 1) ? (int) std::round (fractional)
: (int) fractional;
};
if (doubleNumber < 0)
{
doubleNumber *= -1;
*ptr++ = '-';
}
if (numDigitsBeforePoint > 0)
{
doubleNumber /= std::pow (10.0, numDigitsBeforePoint);
while (numDigitsBeforePoint-- > 0)
{
if (numSigFigsParsed == numberOfSignificantFigures)
{
if (writeToBuffer (ptr++, '0'))
return buffer;
continue;
}
doubleNumber *= 10;
auto digit = truncateOrRound (doubleNumber, numSigFigsParsed);
if (writeToBuffer (ptr++, (char) ('0' + digit)))
return buffer;
++numSigFigsParsed;
doubleNumber -= digit;
}
if (numSigFigsParsed == numberOfSignificantFigures)
{
*ptr++ = '\0';
return buffer;
}
}
else
{
*ptr++ = '0';
}
if (writeToBuffer (ptr++, '.'))
return buffer;
while (numSigFigsParsed < numberOfSignificantFigures)
{
doubleNumber *= 10;
auto digit = truncateOrRound (doubleNumber, numSigFigsParsed);
if (writeToBuffer (ptr++, (char) ('0' + digit)))
return buffer;
if (numSigFigsParsed != 0 || digit != 0)
++numSigFigsParsed;
doubleNumber -= digit;
}
*ptr++ = '\0';
return buffer;
#else
auto shift = numberOfSignificantFigures - numDigitsBeforePoint;
auto factor = std::pow (10.0, shift);
auto rounded = std::round (number * factor) / factor;
std::stringstream ss;
ss << std::fixed << std::setprecision (std::max (shift, 0)) << rounded;
return ss.str();
#endif
}
//==============================================================================
/** Returns the character pointer currently being used to store this string.
@ -1278,7 +1408,7 @@ private:
static String createHex (uint64);
template <typename Type>
static String createHex (Type n) { return createHex (static_cast<typename TypeHelpers::UnsignedTypeWithSize<sizeof (n)>::type> (n)); }
static String createHex (Type n) { return createHex (static_cast<typename TypeHelpers::UnsignedTypeWithSize<(int) sizeof (n)>::type> (n)); }
};
//==============================================================================

View File

@ -33,7 +33,12 @@ StringArray::StringArray (const StringArray& other)
}
StringArray::StringArray (StringArray&& other) noexcept
: strings (static_cast<Array<String>&&> (other.strings))
: strings (std::move (other.strings))
{
}
StringArray::StringArray (Array<String>&& other) noexcept
: strings (std::move (other))
{
}
@ -80,7 +85,7 @@ StringArray& StringArray::operator= (const StringArray& other)
StringArray& StringArray::operator= (StringArray&& other) noexcept
{
strings = static_cast<Array<String>&&> (other.strings);
strings = std::move (other.strings);
return *this;
}
@ -127,19 +132,18 @@ String& StringArray::getReference (int index) noexcept
return strings.getReference (index);
}
void StringArray::add (const String& newString)
void StringArray::add (String newString)
{
strings.add (newString);
// NB: the local temp copy is to avoid a dangling pointer if the
// argument being passed-in is a reference into this array.
strings.add (std::move (newString));
}
void StringArray::add (String&& stringToAdd)
void StringArray::insert (int index, String newString)
{
strings.add (static_cast<String&&> (stringToAdd));
}
void StringArray::insert (int index, const String& newString)
{
strings.insert (index, newString);
// NB: the local temp copy is to avoid a dangling pointer if the
// argument being passed-in is a reference into this array.
strings.insert (index, std::move (newString));
}
bool StringArray::addIfNotAlreadyThere (const String& newString, bool ignoreCase)
@ -153,6 +157,8 @@ bool StringArray::addIfNotAlreadyThere (const String& newString, bool ignoreCase
void StringArray::addArray (const StringArray& otherArray, int startIndex, int numElementsToAdd)
{
jassert (this != &otherArray); // can't add from our own elements!
if (startIndex < 0)
{
jassertfalse;
@ -168,13 +174,15 @@ void StringArray::addArray (const StringArray& otherArray, int startIndex, int n
void StringArray::mergeArray (const StringArray& otherArray, bool ignoreCase)
{
jassert (this != &otherArray); // can't add from our own elements!
for (auto& s : otherArray)
addIfNotAlreadyThere (s, ignoreCase);
}
void StringArray::set (int index, const String& newString)
void StringArray::set (int index, String newString)
{
strings.set (index, newString);
strings.set (index, std::move (newString));
}
bool StringArray::contains (StringRef stringToLookFor, bool ignoreCase) const

View File

@ -54,6 +54,16 @@ public:
/** Creates an array containing a list of strings. */
StringArray (const std::initializer_list<const char*>& strings);
/** Creates a StringArray by moving from an Array<String> */
StringArray (Array<String>&&) noexcept;
/** Creates a StringArray from an array of objects which can be implicitly converted to Strings. */
template <typename Type>
StringArray (const Array<Type>& stringArray)
{
addArray (stringArray.begin(), stringArray.end());
}
/** Creates an array from a raw array of strings.
@param strings an array of strings to add
@param numberOfStrings how many items there are in the array
@ -96,6 +106,14 @@ public:
/** Move assignment operator */
StringArray& operator= (StringArray&&) noexcept;
/** Copies a StringArray from an array of objects which can be implicitly converted to Strings. */
template <typename Type>
StringArray& operator= (const Array<Type>& stringArray)
{
addArray (stringArray.begin(), stringArray.end());
return *this;
}
/** Swaps the contents of this and another StringArray. */
void swapWith (StringArray&) noexcept;
@ -169,10 +187,7 @@ public:
//==============================================================================
/** Appends a string at the end of the array. */
void add (const String& stringToAdd);
/** Appends a string at the end of the array. */
void add (String&& stringToAdd);
void add (String stringToAdd);
/** Inserts a string into the array.
@ -181,7 +196,7 @@ public:
If the index is less than zero or greater than the size of the array,
the new string will be added to the end of the array.
*/
void insert (int index, const String& stringToAdd);
void insert (int index, String stringToAdd);
/** Adds a string to the array as long as it's not already in there.
The search can optionally be case-insensitive.
@ -195,7 +210,7 @@ public:
If the index is higher than the array's size, the new string will be
added to the end of the array; if it's less than zero nothing happens.
*/
void set (int index, const String& newString);
void set (int index, String newString);
/** Appends some strings from another array to the end of this one.
@ -208,6 +223,18 @@ public:
int startIndex = 0,
int numElementsToAdd = -1);
/** Adds items from a range of start/end iterators of some kind of objects which
can be implicitly converted to Strings.
*/
template <typename Iterator>
void addArray (Iterator&& start, Iterator&& end)
{
ensureStorageAllocated (size() + (int) static_cast<size_t> (end - start));
while (start != end)
strings.add (*start++);
}
/** Merges the strings from another array into this one.
This will not add a string that already exists.
@ -393,7 +420,7 @@ public:
//==============================================================================
/** Sorts the array into alphabetical order.
@param ignoreCase if true, the comparisons used will be case-sensitive.
@param ignoreCase if true, the comparisons used will not be case-sensitive.
*/
void sort (bool ignoreCase);