27#if JUCE_WINDOWS && ! defined (DOXYGEN)
28 #define JUCE_NATIVE_WCHAR_IS_UTF8 0
29 #define JUCE_NATIVE_WCHAR_IS_UTF16 1
30 #define JUCE_NATIVE_WCHAR_IS_UTF32 0
33 #define JUCE_NATIVE_WCHAR_IS_UTF8 0
35 #define JUCE_NATIVE_WCHAR_IS_UTF16 0
37 #define JUCE_NATIVE_WCHAR_IS_UTF32 1
40#if JUCE_NATIVE_WCHAR_IS_UTF32 || DOXYGEN
42 using juce_wchar = wchar_t;
44 using juce_wchar = uint32;
49 #define JUCE_T(stringLiteral) (L##stringLiteral)
52#if JUCE_DEFINE_T_MACRO
60 #define T(stringLiteral) JUCE_T(stringLiteral)
69 template <
typename Type>
struct make_unsigned {
using type = Type; };
70 template <>
struct make_unsigned<signed char> {
using type =
unsigned char; };
71 template <>
struct make_unsigned<char> {
using type =
unsigned char; };
72 template <>
struct make_unsigned<short> {
using type =
unsigned short; };
73 template <>
struct make_unsigned<int> {
using type =
unsigned int; };
74 template <>
struct make_unsigned<long> {
using type =
unsigned long; };
75 template <>
struct make_unsigned<long long> {
using type =
unsigned long long; };
96 static juce_wchar toUpperCase (juce_wchar character)
noexcept;
98 static juce_wchar toLowerCase (juce_wchar character)
noexcept;
101 static bool isUpperCase (juce_wchar character)
noexcept;
103 static bool isLowerCase (juce_wchar character)
noexcept;
106 static bool isWhitespace (
char character)
noexcept;
108 static bool isWhitespace (juce_wchar character)
noexcept;
111 static bool isDigit (
char character)
noexcept;
113 static bool isDigit (juce_wchar character)
noexcept;
116 static bool isLetter (
char character)
noexcept;
118 static bool isLetter (juce_wchar character)
noexcept;
121 static bool isLetterOrDigit (
char character)
noexcept;
123 static bool isLetterOrDigit (juce_wchar character)
noexcept;
128 static bool isPrintable (
char character)
noexcept;
133 static bool isPrintable (juce_wchar character)
noexcept;
136 static int getHexDigitValue (juce_wchar digit)
noexcept;
139 static juce_wchar getUnicodeCharFromWindows1252Codepage (uint8 windows1252Char)
noexcept;
146 template <
typename CharPo
interType>
149 constexpr auto inf = std::numeric_limits<double>::infinity();
151 bool isNegative =
false;
153 constexpr const int maxSignificantDigits = 17 + 1;
154 constexpr const int bufferSize = maxSignificantDigits + 7 + 1;
155 char buffer[(size_t) bufferSize] = {};
156 char* writePtr = &(buffer[0]);
159 const auto endOfWhitspace = text.findEndOfWhitespace();
160 text = endOfWhitspace;
184 if ((text[1] ==
'a' || text[1] ==
'A') && (text[2] ==
'n' || text[2] ==
'N'))
187 return std::numeric_limits<double>::quiet_NaN();
190 text = endOfWhitspace;
197 if ((text[1] ==
'n' || text[1] ==
'N') && (text[2] ==
'f' || text[2] ==
'F'))
200 return isNegative ? -inf : inf;
203 text = endOfWhitspace;
214 double result[3] = { 0 }, accumulator[2] = { 0 };
215 int exponentAdjustment[2] = { 0 }, exponentAccumulator[2] = { -1, -1 };
216 int exponent = 0, decPointIndex = 0, digit = 0;
217 int lastDigit = 0, numSignificantDigits = 0;
218 bool digitsFound =
false;
219 constexpr const int maxSignificantDigits = 17 + 1;
226 digit = (int) text.getAndAdvance() -
'0';
229 if (decPointIndex != 0)
230 exponentAdjustment[1]++;
232 if (numSignificantDigits == 0 && digit == 0)
235 if (++numSignificantDigits > maxSignificantDigits)
238 ++accumulator [decPointIndex];
239 else if (digit == 5 && (lastDigit & 1) != 0)
240 ++accumulator [decPointIndex];
242 if (decPointIndex > 0)
243 exponentAdjustment[1]--;
245 exponentAdjustment[0]++;
247 while (text.isDigit())
250 if (decPointIndex == 0)
251 exponentAdjustment[0]++;
256 const auto maxAccumulatorValue = (double) ((std::numeric_limits<unsigned int>::max() - 9) / 10);
257 if (accumulator [decPointIndex] > maxAccumulatorValue)
259 result [decPointIndex] = mulexp10 (result [decPointIndex], exponentAccumulator [decPointIndex])
260 + accumulator [decPointIndex];
261 accumulator [decPointIndex] = 0;
262 exponentAccumulator [decPointIndex] = 0;
265 accumulator [decPointIndex] = accumulator[decPointIndex] * 10 + digit;
266 exponentAccumulator [decPointIndex]++;
269 else if (decPointIndex == 0 && *text ==
'.')
274 if (numSignificantDigits > maxSignificantDigits)
276 while (text.isDigit())
287 result[0] = mulexp10 (result[0], exponentAccumulator[0]) + accumulator[0];
289 if (decPointIndex != 0)
290 result[1] = mulexp10 (result[1], exponentAccumulator[1]) + accumulator[1];
293 if ((c ==
'e' || c ==
'E') && digitsFound)
295 auto negativeExponent =
false;
299 case '-': negativeExponent =
true; JUCE_FALLTHROUGH
303 while (text.isDigit())
304 exponent = (exponent * 10) + ((
int) text.getAndAdvance() -
'0');
306 if (negativeExponent)
307 exponent = -exponent;
310 auto r = mulexp10 (result[0], exponent + exponentAdjustment[0]);
311 if (decPointIndex != 0)
312 r += mulexp10 (result[1], exponent - exponentAdjustment[1]);
314 return isNegative ? -r : r;
318 int numSigFigs = 0, extraExponent = 0;
319 bool decimalPointFound =
false, leadingZeros =
false;
325 auto digit = (int) text.getAndAdvance() -
'0';
327 if (decimalPointFound)
329 if (numSigFigs >= maxSignificantDigits)
334 if (numSigFigs >= maxSignificantDigits)
340 if (numSigFigs == 0 && digit == 0)
347 *writePtr++ = (char) (
'0' + (
char) digit);
350 else if ((! decimalPointFound) && *text ==
'.')
354 decimalPointFound =
true;
362 if ((! leadingZeros) && (numSigFigs == 0))
364 text = endOfWhitspace;
368 auto writeExponentDigits = [] (
int exponent,
char* destination)
370 auto exponentDivisor = 100;
372 while (exponentDivisor > 1)
374 auto digit = exponent / exponentDivisor;
375 *destination++ = (char) (
'0' + (
char) digit);
376 exponent -= digit * exponentDivisor;
377 exponentDivisor /= 10;
380 *destination++ = (char) (
'0' + (
char) exponent);
385 if (c ==
'e' || c ==
'E')
387 const auto startOfExponent = text;
389 bool parsedExponentIsPositive =
true;
394 parsedExponentIsPositive =
false;
404 const auto startOfExponentDigits = text;
406 while (text.isDigit())
408 auto digit = (int) text.getAndAdvance() -
'0';
410 if (digit != 0 || exponent != 0)
411 exponent = (exponent * 10) + digit;
414 if (text == startOfExponentDigits)
415 text = startOfExponent;
417 exponent = extraExponent + (parsedExponentIsPositive ? exponent : -exponent);
421 if (exponent < std::numeric_limits<double>::min_exponent10 - 1)
422 return isNegative ? -0.0 : 0.0;
425 exponent = -exponent;
427 else if (exponent > std::numeric_limits<double>::max_exponent10 + 1)
429 return isNegative ? -inf : inf;
432 writeExponentDigits (exponent, writePtr);
434 else if (extraExponent > 0)
437 writeExponentDigits (extraExponent, writePtr);
441 static _locale_t locale = _create_locale (LC_ALL,
"C");
442 return _strtod_l (&buffer[0],
nullptr, locale);
444 static locale_t locale = newlocale (LC_ALL_MASK,
"C",
nullptr);
446 return (
double) strtold_l (&buffer[0],
nullptr, locale);
448 return strtod_l (&buffer[0],
nullptr, locale);
456 template <
typename CharPo
interType>
459 return readDoubleValue (text);
464 template <
typename IntType,
typename CharPo
interType>
467 using UIntType =
typename internal::make_unsigned<IntType>::type;
470 auto s = text.findEndOfWhitespace();
471 const bool isNeg = *s ==
'-';
478 auto c = s.getAndAdvance();
480 if (c >=
'0' && c <=
'9')
481 v = v * 10 + (UIntType) (c -
'0');
486 return isNeg ? - (IntType) v : (IntType) v;
490 template <
typename ResultType>
493 static_assert (std::is_unsigned_v<ResultType>,
"ResultType must be unsigned because "
494 "left-shifting a negative value is UB");
496 template <
typename CharPo
interType>
497 static ResultType parse (CharPointerType t)
noexcept
499 ResultType result = 0;
501 while (! t.isEmpty())
506 result =
static_cast<ResultType
> (result << 4) | static_cast<ResultType> (hexValue);
516 template <
typename CharPo
interType>
517 static size_t lengthUpTo (CharPointerType text,
const size_t maxCharsToCount)
noexcept
521 while (len < maxCharsToCount && text.getAndAdvance() != 0)
529 template <
typename CharPo
interType>
530 static size_t lengthUpTo (CharPointerType start,
const CharPointerType end)
noexcept
534 while (start < end && start.getAndAdvance() != 0)
541 template <
typename DestCharPo
interType,
typename SrcCharPo
interType>
542 static void copyAll (DestCharPointerType& dest, SrcCharPointerType src)
noexcept
544 while (
auto c = src.getAndAdvance())
552 template <
typename DestCharPo
interType,
typename SrcCharPo
interType>
553 static size_t copyWithDestByteLimit (DestCharPointerType& dest, SrcCharPointerType src,
size_t maxBytesToWrite)
noexcept
555 auto startAddress = dest.getAddress();
556 auto maxBytes = (ssize_t) maxBytesToWrite;
557 maxBytes -= (ssize_t)
sizeof (
typename DestCharPointerType::CharType);
561 auto c = src.getAndAdvance();
562 auto bytesNeeded = (ssize_t) DestCharPointerType::getBytesRequiredFor (c);
563 maxBytes -= bytesNeeded;
565 if (c == 0 || maxBytes < 0)
573 return (
size_t) getAddressDifference (dest.getAddress(), startAddress)
574 +
sizeof (
typename DestCharPointerType::CharType);
579 template <
typename DestCharPo
interType,
typename SrcCharPo
interType>
580 static void copyWithCharLimit (DestCharPointerType& dest, SrcCharPointerType src,
int maxChars)
noexcept
582 while (--maxChars > 0)
584 auto c = src.getAndAdvance();
596 static int compare (juce_wchar char1, juce_wchar char2)
noexcept
598 if (
auto diff =
static_cast<int> (char1) -
static_cast<int> (char2))
599 return diff < 0 ? -1 : 1;
605 template <
typename CharPo
interType1,
typename CharPo
interType2>
606 static int compare (CharPointerType1 s1, CharPointerType2 s2)
noexcept
610 auto c1 = s1.getAndAdvance();
612 if (
auto diff = compare (c1, s2.getAndAdvance()))
623 template <
typename CharPo
interType1,
typename CharPo
interType2>
624 static int compareUpTo (CharPointerType1 s1, CharPointerType2 s2,
int maxChars)
noexcept
626 while (--maxChars >= 0)
628 auto c1 = s1.getAndAdvance();
630 if (
auto diff = compare (c1, s2.getAndAdvance()))
643 return char1 != char2 ? compare (toUpperCase (char1), toUpperCase (char2)) : 0;
647 template <
typename CharPo
interType1,
typename CharPo
interType2>
652 auto c1 = s1.getAndAdvance();
654 if (
auto diff = compareIgnoreCase (c1, s2.getAndAdvance()))
665 template <
typename CharPo
interType1,
typename CharPo
interType2>
668 while (--maxChars >= 0)
670 auto c1 = s1.getAndAdvance();
672 if (
auto diff = compareIgnoreCase (c1, s2.getAndAdvance()))
685 template <
typename CharPo
interType1,
typename CharPo
interType2>
686 static int indexOf (CharPointerType1 textToSearch,
const CharPointerType2 substringToLookFor)
noexcept
689 auto substringLength = (int) substringToLookFor.length();
693 if (textToSearch.compareUpTo (substringToLookFor, substringLength) == 0)
696 if (textToSearch.getAndAdvance() == 0)
707 template <
typename CharPo
interType1,
typename CharPo
interType2>
708 static CharPointerType1
find (CharPointerType1 textToSearch,
const CharPointerType2 substringToLookFor)
noexcept
710 auto substringLength = (int) substringToLookFor.length();
712 while (textToSearch.compareUpTo (substringToLookFor, substringLength) != 0
713 && ! textToSearch.isEmpty())
723 template <
typename CharPo
interType>
724 static CharPointerType
find (CharPointerType textToSearch,
const juce_wchar charToLookFor)
noexcept
726 for (;; ++textToSearch)
728 auto c = *textToSearch;
730 if (c == charToLookFor || c == 0)
741 template <
typename CharPo
interType1,
typename CharPo
interType2>
742 static int indexOfIgnoreCase (CharPointerType1 haystack,
const CharPointerType2 needle)
noexcept
745 auto needleLength = (int) needle.length();
749 if (haystack.compareIgnoreCaseUpTo (needle, needleLength) == 0)
752 if (haystack.getAndAdvance() == 0)
762 template <
typename Type>
763 static int indexOfChar (Type text,
const juce_wchar charToFind)
noexcept
767 while (! text.isEmpty())
769 if (text.getAndAdvance() == charToFind)
782 template <
typename Type>
788 while (! text.isEmpty())
790 if (text.toLowerCase() == charToFind)
806 template <
typename Type>
809 while (text.isWhitespace())
817 template <
typename Type>
820 incrementToEndOfWhitespace (text);
827 template <
typename Type,
typename BreakType>
828 static Type
findEndOfToken (Type text, BreakType breakCharacters, Type quoteCharacters)
830 juce_wchar currentQuoteChar = 0;
832 while (! text.isEmpty())
834 auto c = text.getAndAdvance();
836 if (currentQuoteChar == 0 && breakCharacters.indexOf (c) >= 0)
842 if (quoteCharacters.indexOf (c) >= 0)
844 if (currentQuoteChar == 0)
845 currentQuoteChar = c;
846 else if (currentQuoteChar == c)
847 currentQuoteChar = 0;
855 static double mulexp10 (
double value,
int exponent)
noexcept;
static int indexOfIgnoreCase(CharPointerType1 haystack, const CharPointerType2 needle) noexcept
static void incrementToEndOfWhitespace(Type &text) noexcept
static int compare(juce_wchar char1, juce_wchar char2) noexcept
static juce_wchar toLowerCase(juce_wchar character) noexcept
static size_t copyWithDestByteLimit(DestCharPointerType &dest, SrcCharPointerType src, size_t maxBytesToWrite) noexcept
static int indexOfCharIgnoreCase(Type text, juce_wchar charToFind) noexcept
static IntType getIntValue(const CharPointerType text) noexcept
static int compareIgnoreCaseUpTo(CharPointerType1 s1, CharPointerType2 s2, int maxChars) noexcept
static int indexOfChar(Type text, const juce_wchar charToFind) noexcept
static int compare(CharPointerType1 s1, CharPointerType2 s2) noexcept
static int compareIgnoreCase(juce_wchar char1, juce_wchar char2) noexcept
static size_t lengthUpTo(CharPointerType start, const CharPointerType end) noexcept
static int indexOf(CharPointerType1 textToSearch, const CharPointerType2 substringToLookFor) noexcept
static size_t lengthUpTo(CharPointerType text, const size_t maxCharsToCount) noexcept
static double readDoubleValue(CharPointerType &text) noexcept
static CharPointerType find(CharPointerType textToSearch, const juce_wchar charToLookFor) noexcept
static Type findEndOfWhitespace(Type text) noexcept
static void copyWithCharLimit(DestCharPointerType &dest, SrcCharPointerType src, int maxChars) noexcept
static int getHexDigitValue(juce_wchar digit) noexcept
static Type findEndOfToken(Type text, BreakType breakCharacters, Type quoteCharacters)
static CharPointerType1 find(CharPointerType1 textToSearch, const CharPointerType2 substringToLookFor) noexcept
static int compareIgnoreCase(CharPointerType1 s1, CharPointerType2 s2) noexcept
static double getDoubleValue(CharPointerType text) noexcept
static void copyAll(DestCharPointerType &dest, SrcCharPointerType src) noexcept
static int compareUpTo(CharPointerType1 s1, CharPointerType2 s2, int maxChars) noexcept