2 ==============================================================================
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
7 JUCE is an open source library subject to commercial or open-source
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
20 ==============================================================================
26 JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4514 4996)
30 #if defined (JUCE_STRINGS_ARE_UNICODE) && ! JUCE_STRINGS_ARE_UNICODE
31 #error "JUCE_STRINGS_ARE_UNICODE is deprecated! All strings are now unicode by default."
34 #if JUCE_NATIVE_WCHAR_IS_UTF8
35 using CharPointer_wchar_t
= CharPointer_UTF8
;
36 #elif JUCE_NATIVE_WCHAR_IS_UTF16
37 using CharPointer_wchar_t
= CharPointer_UTF16
;
39 using CharPointer_wchar_t
= CharPointer_UTF32
;
42 static CharPointer_wchar_t
castToCharPointer_wchar_t (const void* t
) noexcept
44 return CharPointer_wchar_t (static_cast<const CharPointer_wchar_t::CharType
*> (t
));
47 //==============================================================================
50 using CharPointerType
= String::CharPointerType
;
51 using CharType
= String::CharPointerType::CharType
;
53 std::atomic
<int> refCount
{ 0 };
54 size_t allocatedNumBytes
= sizeof (CharType
);
55 CharType text
[1] { 0 };
58 constexpr StringHolder emptyString
;
60 //==============================================================================
61 class StringHolderUtils
64 using CharPointerType
= StringHolder::CharPointerType
;
65 using CharType
= StringHolder::CharType
;
67 static CharPointerType
createUninitialisedBytes (size_t numBytes
)
69 numBytes
= (numBytes
+ 3) & ~(size_t) 3;
70 auto* bytes
= new char [sizeof (StringHolder
) - sizeof (CharType
) + numBytes
];
71 auto s
= unalignedPointerCast
<StringHolder
*> (bytes
);
73 s
->allocatedNumBytes
= numBytes
;
74 return CharPointerType (unalignedPointerCast
<CharType
*> (bytes
+ offsetof (StringHolder
, text
)));
77 template <class CharPointer
>
78 static CharPointerType
createFromCharPointer (const CharPointer text
)
80 if (text
.getAddress() == nullptr || text
.isEmpty())
81 return CharPointerType (emptyString
.text
);
83 auto bytesNeeded
= sizeof (CharType
) + CharPointerType::getBytesRequiredFor (text
);
84 auto dest
= createUninitialisedBytes (bytesNeeded
);
85 CharPointerType (dest
).writeAll (text
);
89 template <class CharPointer
>
90 static CharPointerType
createFromCharPointer (const CharPointer text
, size_t maxChars
)
92 if (text
.getAddress() == nullptr || text
.isEmpty() || maxChars
== 0)
93 return CharPointerType (emptyString
.text
);
97 size_t bytesNeeded
= sizeof (CharType
);
99 while (numChars
< maxChars
&& ! end
.isEmpty())
101 bytesNeeded
+= CharPointerType::getBytesRequiredFor (end
.getAndAdvance());
105 auto dest
= createUninitialisedBytes (bytesNeeded
);
106 CharPointerType (dest
).writeWithCharLimit (text
, (int) numChars
+ 1);
110 template <class CharPointer
>
111 static CharPointerType
createFromCharPointer (const CharPointer start
, const CharPointer end
)
113 if (start
.getAddress() == nullptr || start
.isEmpty())
114 return CharPointerType (emptyString
.text
);
118 auto bytesNeeded
= sizeof (CharType
);
120 while (e
< end
&& ! e
.isEmpty())
122 bytesNeeded
+= CharPointerType::getBytesRequiredFor (e
.getAndAdvance());
126 auto dest
= createUninitialisedBytes (bytesNeeded
);
127 CharPointerType (dest
).writeWithCharLimit (start
, numChars
+ 1);
131 static CharPointerType
createFromCharPointer (const CharPointerType start
, const CharPointerType end
)
133 if (start
.getAddress() == nullptr || start
.isEmpty())
134 return CharPointerType (emptyString
.text
);
136 auto numBytes
= (size_t) (reinterpret_cast<const char*> (end
.getAddress())
137 - reinterpret_cast<const char*> (start
.getAddress()));
138 auto dest
= createUninitialisedBytes (numBytes
+ sizeof (CharType
));
139 memcpy (dest
.getAddress(), start
, numBytes
);
140 dest
.getAddress()[numBytes
/ sizeof (CharType
)] = 0;
144 static CharPointerType
createFromFixedLength (const char* const src
, const size_t numChars
)
146 auto dest
= createUninitialisedBytes (numChars
* sizeof (CharType
) + sizeof (CharType
));
147 CharPointerType (dest
).writeWithCharLimit (CharPointer_UTF8 (src
), (int) (numChars
+ 1));
151 //==============================================================================
152 static void retain (const CharPointerType text
) noexcept
154 auto* b
= bufferFromText (text
);
156 if (! isEmptyString (b
))
160 static void release (StringHolder
* const b
) noexcept
162 if (! isEmptyString (b
))
163 if (--(b
->refCount
) == -1)
164 delete[] reinterpret_cast<char*> (b
);
167 static void release (const CharPointerType text
) noexcept
169 release (bufferFromText (text
));
172 static int getReferenceCount (const CharPointerType text
) noexcept
174 return bufferFromText (text
)->refCount
+ 1;
177 //==============================================================================
178 static CharPointerType
makeUniqueWithByteSize (const CharPointerType text
, size_t numBytes
)
180 auto* b
= bufferFromText (text
);
182 if (isEmptyString (b
))
184 auto newText
= createUninitialisedBytes (numBytes
);
189 if (b
->allocatedNumBytes
>= numBytes
&& b
->refCount
<= 0)
192 auto newText
= createUninitialisedBytes (jmax (b
->allocatedNumBytes
, numBytes
));
193 memcpy (newText
.getAddress(), text
.getAddress(), b
->allocatedNumBytes
);
199 static size_t getAllocatedNumBytes (const CharPointerType text
) noexcept
201 return bufferFromText (text
)->allocatedNumBytes
;
205 StringHolderUtils() = delete;
206 ~StringHolderUtils() = delete;
208 static StringHolder
* bufferFromText (const CharPointerType charPtr
) noexcept
210 return unalignedPointerCast
<StringHolder
*> (unalignedPointerCast
<char*> (charPtr
.getAddress()) - offsetof (StringHolder
, text
));
213 static bool isEmptyString (StringHolder
* other
)
215 return other
== &emptyString
;
218 void compileTimeChecks()
220 // Let me know if any of these assertions fail on your system!
221 #if JUCE_NATIVE_WCHAR_IS_UTF8
222 static_assert (sizeof (wchar_t) == 1, "JUCE_NATIVE_WCHAR_IS_* macro has incorrect value");
223 #elif JUCE_NATIVE_WCHAR_IS_UTF16
224 static_assert (sizeof (wchar_t) == 2, "JUCE_NATIVE_WCHAR_IS_* macro has incorrect value");
225 #elif JUCE_NATIVE_WCHAR_IS_UTF32
226 static_assert (sizeof (wchar_t) == 4, "JUCE_NATIVE_WCHAR_IS_* macro has incorrect value");
228 #error "native wchar_t size is unknown"
233 //==============================================================================
234 String::String() noexcept
: text (emptyString
.text
)
238 String::~String() noexcept
240 StringHolderUtils::release (text
);
243 String::String (const String
& other
) noexcept
: text (other
.text
)
245 StringHolderUtils::retain (text
);
248 void String::swapWith (String
& other
) noexcept
250 std::swap (text
, other
.text
);
253 void String::clear() noexcept
255 StringHolderUtils::release (text
);
256 text
= emptyString
.text
;
259 String
& String::operator= (const String
& other
) noexcept
261 StringHolderUtils::retain (other
.text
);
262 StringHolderUtils::release (text
.atomicSwap (other
.text
));
266 String::String (String
&& other
) noexcept
: text (other
.text
)
268 other
.text
= emptyString
.text
;
271 String
& String::operator= (String
&& other
) noexcept
273 std::swap (text
, other
.text
);
277 inline String::PreallocationBytes::PreallocationBytes (const size_t num
) noexcept
: numBytes (num
) {}
279 String::String (const PreallocationBytes
& preallocationSize
)
280 : text (StringHolderUtils::createUninitialisedBytes (preallocationSize
.numBytes
+ sizeof (CharPointerType::CharType
)))
284 void String::preallocateBytes (const size_t numBytesNeeded
)
286 text
= StringHolderUtils::makeUniqueWithByteSize (text
, numBytesNeeded
+ sizeof (CharPointerType::CharType
));
289 int String::getReferenceCount() const noexcept
291 return StringHolderUtils::getReferenceCount (text
);
294 //==============================================================================
295 String::String (const char* const t
)
296 : text (StringHolderUtils::createFromCharPointer (CharPointer_ASCII (t
)))
298 /* If you get an assertion here, then you're trying to create a string from 8-bit data
299 that contains values greater than 127. These can NOT be correctly converted to unicode
300 because there's no way for the String class to know what encoding was used to
301 create them. The source data could be UTF-8, ASCII or one of many local code-pages.
303 To get around this problem, you must be more explicit when you pass an ambiguous 8-bit
304 string to the String class - so for example if your source data is actually UTF-8,
305 you'd call String (CharPointer_UTF8 ("my utf8 string..")), and it would be able to
306 correctly convert the multi-byte characters to unicode. It's *highly* recommended that
307 you use UTF-8 with escape characters in your source code to represent extended characters,
308 because there's no other way to represent these strings in a way that isn't dependent on
309 the compiler, source code editor and platform.
311 Note that the Projucer has a handy string literal generator utility that will convert
312 any unicode string to a valid C++ string literal, creating ascii escape sequences that will
313 work in any compiler.
315 jassert (t
== nullptr || CharPointer_ASCII::isValidString (t
, std::numeric_limits
<int>::max()));
318 String::String (const char* const t
, const size_t maxChars
)
319 : text (StringHolderUtils::createFromCharPointer (CharPointer_ASCII (t
), maxChars
))
321 /* If you get an assertion here, then you're trying to create a string from 8-bit data
322 that contains values greater than 127. These can NOT be correctly converted to unicode
323 because there's no way for the String class to know what encoding was used to
324 create them. The source data could be UTF-8, ASCII or one of many local code-pages.
326 To get around this problem, you must be more explicit when you pass an ambiguous 8-bit
327 string to the String class - so for example if your source data is actually UTF-8,
328 you'd call String (CharPointer_UTF8 ("my utf8 string..")), and it would be able to
329 correctly convert the multi-byte characters to unicode. It's *highly* recommended that
330 you use UTF-8 with escape characters in your source code to represent extended characters,
331 because there's no other way to represent these strings in a way that isn't dependent on
332 the compiler, source code editor and platform.
334 Note that the Projucer has a handy string literal generator utility that will convert
335 any unicode string to a valid C++ string literal, creating ascii escape sequences that will
336 work in any compiler.
338 jassert (t
== nullptr || CharPointer_ASCII::isValidString (t
, (int) maxChars
));
341 String::String (const wchar_t* const t
) : text (StringHolderUtils::createFromCharPointer (castToCharPointer_wchar_t (t
))) {}
342 String::String (const CharPointer_UTF8 t
) : text (StringHolderUtils::createFromCharPointer (t
)) {}
343 String::String (const CharPointer_UTF16 t
) : text (StringHolderUtils::createFromCharPointer (t
)) {}
344 String::String (const CharPointer_UTF32 t
) : text (StringHolderUtils::createFromCharPointer (t
)) {}
345 String::String (const CharPointer_ASCII t
) : text (StringHolderUtils::createFromCharPointer (t
)) {}
347 String::String (CharPointer_UTF8 t
, size_t maxChars
) : text (StringHolderUtils::createFromCharPointer (t
, maxChars
)) {}
348 String::String (CharPointer_UTF16 t
, size_t maxChars
) : text (StringHolderUtils::createFromCharPointer (t
, maxChars
)) {}
349 String::String (CharPointer_UTF32 t
, size_t maxChars
) : text (StringHolderUtils::createFromCharPointer (t
, maxChars
)) {}
350 String::String (const wchar_t* t
, size_t maxChars
) : text (StringHolderUtils::createFromCharPointer (castToCharPointer_wchar_t (t
), maxChars
)) {}
352 String::String (CharPointer_UTF8 start
, CharPointer_UTF8 end
) : text (StringHolderUtils::createFromCharPointer (start
, end
)) {}
353 String::String (CharPointer_UTF16 start
, CharPointer_UTF16 end
) : text (StringHolderUtils::createFromCharPointer (start
, end
)) {}
354 String::String (CharPointer_UTF32 start
, CharPointer_UTF32 end
) : text (StringHolderUtils::createFromCharPointer (start
, end
)) {}
356 String::String (const std::string
& s
) : text (StringHolderUtils::createFromFixedLength (s
.data(), s
.size())) {}
357 String::String (StringRef s
) : text (StringHolderUtils::createFromCharPointer (s
.text
)) {}
359 String
String::charToString (juce_wchar character
)
361 String
result (PreallocationBytes (CharPointerType::getBytesRequiredFor (character
)));
362 CharPointerType
t (result
.text
);
368 //==============================================================================
369 namespace NumberToStringConverters
373 charsNeededForInt
= 32,
374 charsNeededForDouble
= 48
377 template <typename Type
>
378 static char* printDigits (char* t
, Type v
) noexcept
384 *--t
= static_cast<char> ('0' + (char) (v
% 10));
392 // pass in a pointer to the END of a buffer..
393 static char* numberToString (char* t
, int64 n
) noexcept
396 return printDigits (t
, static_cast<uint64
> (n
));
398 // NB: this needs to be careful not to call -std::numeric_limits<int64>::min(),
399 // which has undefined behaviour
400 t
= printDigits (t
, static_cast<uint64
> (-(n
+ 1)) + 1);
405 static char* numberToString (char* t
, uint64 v
) noexcept
407 return printDigits (t
, v
);
410 static char* numberToString (char* t
, int n
) noexcept
413 return printDigits (t
, static_cast<unsigned int> (n
));
415 // NB: this needs to be careful not to call -std::numeric_limits<int>::min(),
416 // which has undefined behaviour
417 t
= printDigits (t
, static_cast<unsigned int> (-(n
+ 1)) + 1);
422 static char* numberToString (char* t
, unsigned int v
) noexcept
424 return printDigits (t
, v
);
427 static char* numberToString (char* t
, long n
) noexcept
430 return printDigits (t
, static_cast<unsigned long> (n
));
432 t
= printDigits (t
, static_cast<unsigned long> (-(n
+ 1)) + 1);
437 static char* numberToString (char* t
, unsigned long v
) noexcept
439 return printDigits (t
, v
);
442 struct StackArrayStream
: public std::basic_streambuf
<char, std::char_traits
<char>>
444 explicit StackArrayStream (char* d
)
446 static const std::locale
classicLocale (std::locale::classic());
447 imbue (classicLocale
);
448 setp (d
, d
+ charsNeededForDouble
);
451 size_t writeDouble (double n
, int numDecPlaces
, bool useScientificNotation
)
454 std::ostream
o (this);
456 if (numDecPlaces
> 0)
458 o
.setf (useScientificNotation
? std::ios_base::scientific
: std::ios_base::fixed
);
459 o
.precision ((std::streamsize
) numDecPlaces
);
465 return (size_t) (pptr() - pbase());
469 static char* doubleToString (char* buffer
, double n
, int numDecPlaces
, bool useScientificNotation
, size_t& len
) noexcept
471 StackArrayStream
strm (buffer
);
472 len
= strm
.writeDouble (n
, numDecPlaces
, useScientificNotation
);
473 jassert (len
<= charsNeededForDouble
);
477 template <typename IntegerType
>
478 static String::CharPointerType
createFromInteger (IntegerType number
)
480 char buffer
[charsNeededForInt
];
481 auto* end
= buffer
+ numElementsInArray (buffer
);
482 auto* start
= numberToString (end
, number
);
483 return StringHolderUtils::createFromFixedLength (start
, (size_t) (end
- start
- 1));
486 static String::CharPointerType
createFromDouble (double number
, int numberOfDecimalPlaces
, bool useScientificNotation
)
488 char buffer
[charsNeededForDouble
];
490 auto start
= doubleToString (buffer
, number
, numberOfDecimalPlaces
, useScientificNotation
, len
);
491 return StringHolderUtils::createFromFixedLength (start
, len
);
495 //==============================================================================
496 String::String (int number
) : text (NumberToStringConverters::createFromInteger (number
)) {}
497 String::String (unsigned int number
) : text (NumberToStringConverters::createFromInteger (number
)) {}
498 String::String (short number
) : text (NumberToStringConverters::createFromInteger ((int) number
)) {}
499 String::String (unsigned short number
) : text (NumberToStringConverters::createFromInteger ((unsigned int) number
)) {}
500 String::String (int64 number
) : text (NumberToStringConverters::createFromInteger (number
)) {}
501 String::String (uint64 number
) : text (NumberToStringConverters::createFromInteger (number
)) {}
502 String::String (long number
) : text (NumberToStringConverters::createFromInteger (number
)) {}
503 String::String (unsigned long number
) : text (NumberToStringConverters::createFromInteger (number
)) {}
505 String::String (float number
) : text (NumberToStringConverters::createFromDouble ((double) number
, 0, false)) {}
506 String::String (double number
) : text (NumberToStringConverters::createFromDouble ( number
, 0, false)) {}
507 String::String (float number
, int numberOfDecimalPlaces
, bool useScientificNotation
) : text (NumberToStringConverters::createFromDouble ((double) number
, numberOfDecimalPlaces
, useScientificNotation
)) {}
508 String::String (double number
, int numberOfDecimalPlaces
, bool useScientificNotation
) : text (NumberToStringConverters::createFromDouble ( number
, numberOfDecimalPlaces
, useScientificNotation
)) {}
510 //==============================================================================
511 int String::length() const noexcept
513 return (int) text
.length();
516 static size_t findByteOffsetOfEnd (String::CharPointerType text
) noexcept
518 return (size_t) (((char*) text
.findTerminatingNull().getAddress()) - (char*) text
.getAddress());
521 size_t String::getByteOffsetOfEnd() const noexcept
523 return findByteOffsetOfEnd (text
);
526 juce_wchar
String::operator[] (int index
) const noexcept
528 jassert (index
== 0 || (index
> 0 && index
<= (int) text
.lengthUpTo ((size_t) index
+ 1)));
532 template <typename Type
>
535 template <typename CharPointer
>
536 static Type
calculate (CharPointer t
) noexcept
540 while (! t
.isEmpty())
541 result
= ((Type
) multiplier
) * result
+ (Type
) t
.getAndAdvance();
546 enum { multiplier
= sizeof (Type
) > 4 ? 101 : 31 };
549 int String::hashCode() const noexcept
{ return (int) HashGenerator
<uint32
> ::calculate (text
); }
550 int64
String::hashCode64() const noexcept
{ return (int64
) HashGenerator
<uint64
> ::calculate (text
); }
551 size_t String::hash() const noexcept
{ return HashGenerator
<size_t> ::calculate (text
); }
553 //==============================================================================
554 JUCE_API
bool JUCE_CALLTYPE
operator== (const String
& s1
, const String
& s2
) noexcept
{ return s1
.compare (s2
) == 0; }
555 JUCE_API
bool JUCE_CALLTYPE
operator!= (const String
& s1
, const String
& s2
) noexcept
{ return s1
.compare (s2
) != 0; }
556 JUCE_API
bool JUCE_CALLTYPE
operator== (const String
& s1
, const char* s2
) noexcept
{ return s1
.compare (s2
) == 0; }
557 JUCE_API
bool JUCE_CALLTYPE
operator!= (const String
& s1
, const char* s2
) noexcept
{ return s1
.compare (s2
) != 0; }
558 JUCE_API
bool JUCE_CALLTYPE
operator== (const String
& s1
, const wchar_t* s2
) noexcept
{ return s1
.compare (s2
) == 0; }
559 JUCE_API
bool JUCE_CALLTYPE
operator!= (const String
& s1
, const wchar_t* s2
) noexcept
{ return s1
.compare (s2
) != 0; }
560 JUCE_API
bool JUCE_CALLTYPE
operator== (const String
& s1
, StringRef s2
) noexcept
{ return s1
.getCharPointer().compare (s2
.text
) == 0; }
561 JUCE_API
bool JUCE_CALLTYPE
operator!= (const String
& s1
, StringRef s2
) noexcept
{ return s1
.getCharPointer().compare (s2
.text
) != 0; }
562 JUCE_API
bool JUCE_CALLTYPE
operator< (const String
& s1
, StringRef s2
) noexcept
{ return s1
.getCharPointer().compare (s2
.text
) < 0; }
563 JUCE_API
bool JUCE_CALLTYPE
operator<= (const String
& s1
, StringRef s2
) noexcept
{ return s1
.getCharPointer().compare (s2
.text
) <= 0; }
564 JUCE_API
bool JUCE_CALLTYPE
operator> (const String
& s1
, StringRef s2
) noexcept
{ return s1
.getCharPointer().compare (s2
.text
) > 0; }
565 JUCE_API
bool JUCE_CALLTYPE
operator>= (const String
& s1
, StringRef s2
) noexcept
{ return s1
.getCharPointer().compare (s2
.text
) >= 0; }
566 JUCE_API
bool JUCE_CALLTYPE
operator== (const String
& s1
, const CharPointer_UTF8 s2
) noexcept
{ return s1
.getCharPointer().compare (s2
) == 0; }
567 JUCE_API
bool JUCE_CALLTYPE
operator!= (const String
& s1
, const CharPointer_UTF8 s2
) noexcept
{ return s1
.getCharPointer().compare (s2
) != 0; }
568 JUCE_API
bool JUCE_CALLTYPE
operator== (const String
& s1
, const CharPointer_UTF16 s2
) noexcept
{ return s1
.getCharPointer().compare (s2
) == 0; }
569 JUCE_API
bool JUCE_CALLTYPE
operator!= (const String
& s1
, const CharPointer_UTF16 s2
) noexcept
{ return s1
.getCharPointer().compare (s2
) != 0; }
570 JUCE_API
bool JUCE_CALLTYPE
operator== (const String
& s1
, const CharPointer_UTF32 s2
) noexcept
{ return s1
.getCharPointer().compare (s2
) == 0; }
571 JUCE_API
bool JUCE_CALLTYPE
operator!= (const String
& s1
, const CharPointer_UTF32 s2
) noexcept
{ return s1
.getCharPointer().compare (s2
) != 0; }
573 bool String::equalsIgnoreCase (const wchar_t* const t
) const noexcept
575 return t
!= nullptr ? text
.compareIgnoreCase (castToCharPointer_wchar_t (t
)) == 0
579 bool String::equalsIgnoreCase (const char* const t
) const noexcept
581 return t
!= nullptr ? text
.compareIgnoreCase (CharPointer_UTF8 (t
)) == 0
585 bool String::equalsIgnoreCase (StringRef t
) const noexcept
587 return text
.compareIgnoreCase (t
.text
) == 0;
590 bool String::equalsIgnoreCase (const String
& other
) const noexcept
592 return text
== other
.text
593 || text
.compareIgnoreCase (other
.text
) == 0;
596 int String::compare (const String
& other
) const noexcept
{ return (text
== other
.text
) ? 0 : text
.compare (other
.text
); }
597 int String::compare (const char* const other
) const noexcept
{ return text
.compare (CharPointer_UTF8 (other
)); }
598 int String::compare (const wchar_t* const other
) const noexcept
{ return text
.compare (castToCharPointer_wchar_t (other
)); }
599 int String::compareIgnoreCase (const String
& other
) const noexcept
{ return (text
== other
.text
) ? 0 : text
.compareIgnoreCase (other
.text
); }
601 static int stringCompareRight (String::CharPointerType s1
, String::CharPointerType s2
) noexcept
605 auto c1
= s1
.getAndAdvance();
606 bool isDigit1
= CharacterFunctions::isDigit (c1
);
608 auto c2
= s2
.getAndAdvance();
609 bool isDigit2
= CharacterFunctions::isDigit (c2
);
611 if (! (isDigit1
|| isDigit2
)) return bias
;
612 if (! isDigit1
) return -1;
613 if (! isDigit2
) return 1;
615 if (c1
!= c2
&& bias
== 0)
616 bias
= c1
< c2
? -1 : 1;
618 jassert (c1
!= 0 && c2
!= 0);
622 static int stringCompareLeft (String::CharPointerType s1
, String::CharPointerType s2
) noexcept
626 auto c1
= s1
.getAndAdvance();
627 bool isDigit1
= CharacterFunctions::isDigit (c1
);
629 auto c2
= s2
.getAndAdvance();
630 bool isDigit2
= CharacterFunctions::isDigit (c2
);
632 if (! (isDigit1
|| isDigit2
)) return 0;
633 if (! isDigit1
) return -1;
634 if (! isDigit2
) return 1;
635 if (c1
< c2
) return -1;
636 if (c1
> c2
) return 1;
640 static int naturalStringCompare (String::CharPointerType s1
, String::CharPointerType s2
, bool isCaseSensitive
) noexcept
642 bool firstLoop
= true;
646 const bool hasSpace1
= s1
.isWhitespace();
647 const bool hasSpace2
= s2
.isWhitespace();
649 if ((! firstLoop
) && (hasSpace1
^ hasSpace2
))
651 if (s1
.isEmpty()) return -1;
652 if (s2
.isEmpty()) return 1;
654 return hasSpace2
? 1 : -1;
659 if (hasSpace1
) s1
= s1
.findEndOfWhitespace();
660 if (hasSpace2
) s2
= s2
.findEndOfWhitespace();
662 if (s1
.isDigit() && s2
.isDigit())
664 auto result
= (*s1
== '0' || *s2
== '0') ? stringCompareLeft (s1
, s2
)
665 : stringCompareRight (s1
, s2
);
671 auto c1
= s1
.getAndAdvance();
672 auto c2
= s2
.getAndAdvance();
674 if (c1
!= c2
&& ! isCaseSensitive
)
676 c1
= CharacterFunctions::toUpperCase (c1
);
677 c2
= CharacterFunctions::toUpperCase (c2
);
687 const bool isAlphaNum1
= CharacterFunctions::isLetterOrDigit (c1
);
688 const bool isAlphaNum2
= CharacterFunctions::isLetterOrDigit (c2
);
690 if (isAlphaNum2
&& ! isAlphaNum1
) return -1;
691 if (isAlphaNum1
&& ! isAlphaNum2
) return 1;
693 return c1
< c2
? -1 : 1;
696 jassert (c1
!= 0 && c2
!= 0);
700 int String::compareNatural (StringRef other
, bool isCaseSensitive
) const noexcept
702 return naturalStringCompare (getCharPointer(), other
.text
, isCaseSensitive
);
705 //==============================================================================
706 void String::append (const String
& textToAppend
, size_t maxCharsToTake
)
708 appendCharPointer (this == &textToAppend
? String (textToAppend
).text
709 : textToAppend
.text
, maxCharsToTake
);
712 void String::appendCharPointer (const CharPointerType textToAppend
)
714 appendCharPointer (textToAppend
, textToAppend
.findTerminatingNull());
717 void String::appendCharPointer (const CharPointerType startOfTextToAppend
,
718 const CharPointerType endOfTextToAppend
)
720 jassert (startOfTextToAppend
.getAddress() != nullptr && endOfTextToAppend
.getAddress() != nullptr);
722 auto extraBytesNeeded
= getAddressDifference (endOfTextToAppend
.getAddress(),
723 startOfTextToAppend
.getAddress());
724 jassert (extraBytesNeeded
>= 0);
726 if (extraBytesNeeded
> 0)
728 auto byteOffsetOfNull
= getByteOffsetOfEnd();
729 preallocateBytes ((size_t) extraBytesNeeded
+ byteOffsetOfNull
);
731 auto* newStringStart
= addBytesToPointer (text
.getAddress(), (int) byteOffsetOfNull
);
732 memcpy (newStringStart
, startOfTextToAppend
.getAddress(), (size_t) extraBytesNeeded
);
733 CharPointerType (addBytesToPointer (newStringStart
, extraBytesNeeded
)).writeNull();
737 String
& String::operator+= (const wchar_t* t
)
739 appendCharPointer (castToCharPointer_wchar_t (t
));
743 String
& String::operator+= (const char* t
)
745 appendCharPointer (CharPointer_UTF8 (t
)); // (using UTF8 here triggers a faster code-path than ascii)
749 String
& String::operator+= (const String
& other
)
752 return operator= (other
);
755 return operator+= (String (*this));
757 appendCharPointer (other
.text
);
761 String
& String::operator+= (StringRef other
)
763 return operator+= (String (other
));
766 String
& String::operator+= (char ch
)
768 const char asString
[] = { ch
, 0 };
769 return operator+= (asString
);
772 String
& String::operator+= (wchar_t ch
)
774 const wchar_t asString
[] = { ch
, 0 };
775 return operator+= (asString
);
778 #if ! JUCE_NATIVE_WCHAR_IS_UTF32
779 String
& String::operator+= (juce_wchar ch
)
781 const juce_wchar asString
[] = { ch
, 0 };
782 appendCharPointer (CharPointer_UTF32 (asString
));
787 namespace StringHelpers
789 template <typename T
>
790 inline String
& operationAddAssign (String
& str
, const T number
)
792 char buffer
[(sizeof(T
) * 8) / 2];
793 auto* end
= buffer
+ numElementsInArray (buffer
);
794 auto* start
= NumberToStringConverters::numberToString (end
, number
);
796 #if JUCE_STRING_UTF_TYPE == 8
797 str
.appendCharPointer (String::CharPointerType (start
), String::CharPointerType (end
));
799 str
.appendCharPointer (CharPointer_ASCII (start
), CharPointer_ASCII (end
));
806 String
& String::operator+= (const int number
) { return StringHelpers::operationAddAssign
<int> (*this, number
); }
807 String
& String::operator+= (const long number
) { return StringHelpers::operationAddAssign
<long> (*this, number
); }
808 String
& String::operator+= (const int64 number
) { return StringHelpers::operationAddAssign
<int64
> (*this, number
); }
809 String
& String::operator+= (const uint64 number
) { return StringHelpers::operationAddAssign
<uint64
> (*this, number
); }
811 //==============================================================================
812 JUCE_API String JUCE_CALLTYPE
operator+ (const char* s1
, const String
& s2
) { String
s (s1
); return s
+= s2
; }
813 JUCE_API String JUCE_CALLTYPE
operator+ (const wchar_t* s1
, const String
& s2
) { String
s (s1
); return s
+= s2
; }
815 JUCE_API String JUCE_CALLTYPE
operator+ (char s1
, const String
& s2
) { return String::charToString ((juce_wchar
) (uint8
) s1
) + s2
; }
816 JUCE_API String JUCE_CALLTYPE
operator+ (wchar_t s1
, const String
& s2
) { return String::charToString (s1
) + s2
; }
818 JUCE_API String JUCE_CALLTYPE
operator+ (String s1
, const String
& s2
) { return s1
+= s2
; }
819 JUCE_API String JUCE_CALLTYPE
operator+ (String s1
, const char* s2
) { return s1
+= s2
; }
820 JUCE_API String JUCE_CALLTYPE
operator+ (String s1
, const wchar_t* s2
) { return s1
+= s2
; }
821 JUCE_API String JUCE_CALLTYPE
operator+ (String s1
, const std::string
& s2
) { return s1
+= s2
.c_str(); }
823 JUCE_API String JUCE_CALLTYPE
operator+ (String s1
, char s2
) { return s1
+= s2
; }
824 JUCE_API String JUCE_CALLTYPE
operator+ (String s1
, wchar_t s2
) { return s1
+= s2
; }
826 #if ! JUCE_NATIVE_WCHAR_IS_UTF32
827 JUCE_API String JUCE_CALLTYPE
operator+ (juce_wchar s1
, const String
& s2
) { return String::charToString (s1
) + s2
; }
828 JUCE_API String JUCE_CALLTYPE
operator+ (String s1
, juce_wchar s2
) { return s1
+= s2
; }
829 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& s1
, juce_wchar s2
) { return s1
+= s2
; }
832 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& s1
, char s2
) { return s1
+= s2
; }
833 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& s1
, wchar_t s2
) { return s1
+= s2
; }
835 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& s1
, const char* s2
) { return s1
+= s2
; }
836 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& s1
, const wchar_t* s2
) { return s1
+= s2
; }
837 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& s1
, const String
& s2
) { return s1
+= s2
; }
838 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& s1
, StringRef s2
) { return s1
+= s2
; }
839 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& s1
, const std::string
& s2
) { return s1
+= s2
.c_str(); }
841 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& s1
, uint8 number
) { return s1
+= (int) number
; }
842 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& s1
, short number
) { return s1
+= (int) number
; }
843 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& s1
, int number
) { return s1
+= number
; }
844 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& s1
, long number
) { return s1
+= String (number
); }
845 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& s1
, unsigned long number
) { return s1
+= String (number
); }
846 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& s1
, int64 number
) { return s1
+= String (number
); }
847 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& s1
, uint64 number
) { return s1
+= String (number
); }
848 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& s1
, float number
) { return s1
+= String (number
); }
849 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& s1
, double number
) { return s1
+= String (number
); }
851 JUCE_API OutputStream
& JUCE_CALLTYPE
operator<< (OutputStream
& stream
, const String
& text
)
853 return operator<< (stream
, StringRef (text
));
856 JUCE_API OutputStream
& JUCE_CALLTYPE
operator<< (OutputStream
& stream
, StringRef text
)
858 auto numBytes
= CharPointer_UTF8::getBytesRequiredFor (text
.text
);
860 #if (JUCE_STRING_UTF_TYPE == 8)
861 stream
.write (text
.text
.getAddress(), numBytes
);
863 // (This avoids using toUTF8() to prevent the memory bloat that it would leave behind
864 // if lots of large, persistent strings were to be written to streams).
865 HeapBlock
<char> temp (numBytes
+ 1);
866 CharPointer_UTF8 (temp
).writeAll (text
.text
);
867 stream
.write (temp
, numBytes
);
873 //==============================================================================
874 int String::indexOfChar (juce_wchar character
) const noexcept
876 return text
.indexOf (character
);
879 int String::indexOfChar (int startIndex
, juce_wchar character
) const noexcept
883 for (int i
= 0; ! t
.isEmpty(); ++i
)
887 if (t
.getAndAdvance() == character
)
899 int String::lastIndexOfChar (juce_wchar character
) const noexcept
904 for (int i
= 0; ! t
.isEmpty(); ++i
)
905 if (t
.getAndAdvance() == character
)
911 int String::indexOfAnyOf (StringRef charactersToLookFor
, int startIndex
, bool ignoreCase
) const noexcept
915 for (int i
= 0; ! t
.isEmpty(); ++i
)
919 if (charactersToLookFor
.text
.indexOf (t
.getAndAdvance(), ignoreCase
) >= 0)
931 int String::indexOf (StringRef other
) const noexcept
933 return other
.isEmpty() ? 0 : text
.indexOf (other
.text
);
936 int String::indexOfIgnoreCase (StringRef other
) const noexcept
938 return other
.isEmpty() ? 0 : CharacterFunctions::indexOfIgnoreCase (text
, other
.text
);
941 int String::indexOf (int startIndex
, StringRef other
) const noexcept
948 for (int i
= startIndex
; --i
>= 0;)
956 auto found
= t
.indexOf (other
.text
);
957 return found
>= 0 ? found
+ startIndex
: found
;
960 int String::indexOfIgnoreCase (const int startIndex
, StringRef other
) const noexcept
967 for (int i
= startIndex
; --i
>= 0;)
975 auto found
= CharacterFunctions::indexOfIgnoreCase (t
, other
.text
);
976 return found
>= 0 ? found
+ startIndex
: found
;
979 int String::lastIndexOf (StringRef other
) const noexcept
981 if (other
.isNotEmpty())
983 auto len
= other
.length();
984 int i
= length() - len
;
988 for (auto n
= text
+ i
; i
>= 0; --i
)
990 if (n
.compareUpTo (other
.text
, len
) == 0)
1001 int String::lastIndexOfIgnoreCase (StringRef other
) const noexcept
1003 if (other
.isNotEmpty())
1005 auto len
= other
.length();
1006 int i
= length() - len
;
1010 for (auto n
= text
+ i
; i
>= 0; --i
)
1012 if (n
.compareIgnoreCaseUpTo (other
.text
, len
) == 0)
1023 int String::lastIndexOfAnyOf (StringRef charactersToLookFor
, const bool ignoreCase
) const noexcept
1028 for (int i
= 0; ! t
.isEmpty(); ++i
)
1029 if (charactersToLookFor
.text
.indexOf (t
.getAndAdvance(), ignoreCase
) >= 0)
1035 bool String::contains (StringRef other
) const noexcept
1037 return indexOf (other
) >= 0;
1040 bool String::containsChar (const juce_wchar character
) const noexcept
1042 return text
.indexOf (character
) >= 0;
1045 bool String::containsIgnoreCase (StringRef t
) const noexcept
1047 return indexOfIgnoreCase (t
) >= 0;
1050 int String::indexOfWholeWord (StringRef word
) const noexcept
1052 if (word
.isNotEmpty())
1055 auto wordLen
= word
.length();
1056 auto end
= (int) t
.length() - wordLen
;
1058 for (int i
= 0; i
<= end
; ++i
)
1060 if (t
.compareUpTo (word
.text
, wordLen
) == 0
1061 && (i
== 0 || ! (t
- 1).isLetterOrDigit())
1062 && ! (t
+ wordLen
).isLetterOrDigit())
1072 int String::indexOfWholeWordIgnoreCase (StringRef word
) const noexcept
1074 if (word
.isNotEmpty())
1077 auto wordLen
= word
.length();
1078 auto end
= (int) t
.length() - wordLen
;
1080 for (int i
= 0; i
<= end
; ++i
)
1082 if (t
.compareIgnoreCaseUpTo (word
.text
, wordLen
) == 0
1083 && (i
== 0 || ! (t
- 1).isLetterOrDigit())
1084 && ! (t
+ wordLen
).isLetterOrDigit())
1094 bool String::containsWholeWord (StringRef wordToLookFor
) const noexcept
1096 return indexOfWholeWord (wordToLookFor
) >= 0;
1099 bool String::containsWholeWordIgnoreCase (StringRef wordToLookFor
) const noexcept
1101 return indexOfWholeWordIgnoreCase (wordToLookFor
) >= 0;
1104 //==============================================================================
1105 template <typename CharPointer
>
1106 struct WildCardMatcher
1108 static bool matches (CharPointer wildcard
, CharPointer test
, const bool ignoreCase
) noexcept
1112 auto wc
= wildcard
.getAndAdvance();
1115 return wildcard
.isEmpty() || matchesAnywhere (wildcard
, test
, ignoreCase
);
1117 if (! characterMatches (wc
, test
.getAndAdvance(), ignoreCase
))
1125 static bool characterMatches (const juce_wchar wc
, const juce_wchar tc
, const bool ignoreCase
) noexcept
1127 return (wc
== tc
) || (wc
== '?' && tc
!= 0)
1128 || (ignoreCase
&& CharacterFunctions::toLowerCase (wc
) == CharacterFunctions::toLowerCase (tc
));
1131 static bool matchesAnywhere (const CharPointer wildcard
, CharPointer test
, const bool ignoreCase
) noexcept
1133 for (; ! test
.isEmpty(); ++test
)
1134 if (matches (wildcard
, test
, ignoreCase
))
1141 bool String::matchesWildcard (StringRef wildcard
, const bool ignoreCase
) const noexcept
1143 return WildCardMatcher
<CharPointerType
>::matches (wildcard
.text
, text
, ignoreCase
);
1146 //==============================================================================
1147 String
String::repeatedString (StringRef stringToRepeat
, int numberOfTimesToRepeat
)
1149 if (numberOfTimesToRepeat
<= 0)
1152 String
result (PreallocationBytes (findByteOffsetOfEnd (stringToRepeat
) * (size_t) numberOfTimesToRepeat
));
1153 auto n
= result
.text
;
1155 while (--numberOfTimesToRepeat
>= 0)
1156 n
.writeAll (stringToRepeat
.text
);
1161 String
String::paddedLeft (const juce_wchar padCharacter
, int minimumLength
) const
1163 jassert (padCharacter
!= 0);
1165 auto extraChars
= minimumLength
;
1168 while (! end
.isEmpty())
1174 if (extraChars
<= 0 || padCharacter
== 0)
1177 auto currentByteSize
= (size_t) (((char*) end
.getAddress()) - (char*) text
.getAddress());
1178 String
result (PreallocationBytes (currentByteSize
+ (size_t) extraChars
* CharPointerType::getBytesRequiredFor (padCharacter
)));
1179 auto n
= result
.text
;
1181 while (--extraChars
>= 0)
1182 n
.write (padCharacter
);
1188 String
String::paddedRight (const juce_wchar padCharacter
, int minimumLength
) const
1190 jassert (padCharacter
!= 0);
1192 auto extraChars
= minimumLength
;
1193 CharPointerType
end (text
);
1195 while (! end
.isEmpty())
1201 if (extraChars
<= 0 || padCharacter
== 0)
1204 auto currentByteSize
= (size_t) (((char*) end
.getAddress()) - (char*) text
.getAddress());
1205 String
result (PreallocationBytes (currentByteSize
+ (size_t) extraChars
* CharPointerType::getBytesRequiredFor (padCharacter
)));
1206 auto n
= result
.text
;
1210 while (--extraChars
>= 0)
1211 n
.write (padCharacter
);
1217 //==============================================================================
1218 String
String::replaceSection (int index
, int numCharsToReplace
, StringRef stringToInsert
) const
1222 // a negative index to replace from?
1227 if (numCharsToReplace
< 0)
1229 // replacing a negative number of characters?
1230 numCharsToReplace
= 0;
1234 auto insertPoint
= text
;
1236 for (int i
= 0; i
< index
; ++i
)
1238 if (insertPoint
.isEmpty())
1240 // replacing beyond the end of the string?
1242 return *this + stringToInsert
;
1248 auto startOfRemainder
= insertPoint
;
1250 for (int i
= 0; i
< numCharsToReplace
&& ! startOfRemainder
.isEmpty(); ++i
)
1253 if (insertPoint
== text
&& startOfRemainder
.isEmpty())
1254 return stringToInsert
.text
;
1256 auto initialBytes
= (size_t) (((char*) insertPoint
.getAddress()) - (char*) text
.getAddress());
1257 auto newStringBytes
= findByteOffsetOfEnd (stringToInsert
);
1258 auto remainderBytes
= (size_t) (((char*) startOfRemainder
.findTerminatingNull().getAddress()) - (char*) startOfRemainder
.getAddress());
1260 auto newTotalBytes
= initialBytes
+ newStringBytes
+ remainderBytes
;
1262 if (newTotalBytes
<= 0)
1265 String
result (PreallocationBytes ((size_t) newTotalBytes
));
1267 auto* dest
= (char*) result
.text
.getAddress();
1268 memcpy (dest
, text
.getAddress(), initialBytes
);
1269 dest
+= initialBytes
;
1270 memcpy (dest
, stringToInsert
.text
.getAddress(), newStringBytes
);
1271 dest
+= newStringBytes
;
1272 memcpy (dest
, startOfRemainder
.getAddress(), remainderBytes
);
1273 dest
+= remainderBytes
;
1274 CharPointerType (unalignedPointerCast
<CharPointerType::CharType
*> (dest
)).writeNull();
1279 String
String::replace (StringRef stringToReplace
, StringRef stringToInsert
, const bool ignoreCase
) const
1281 auto stringToReplaceLen
= stringToReplace
.length();
1282 auto stringToInsertLen
= stringToInsert
.length();
1285 String
result (*this);
1287 while ((i
= (ignoreCase
? result
.indexOfIgnoreCase (i
, stringToReplace
)
1288 : result
.indexOf (i
, stringToReplace
))) >= 0)
1290 result
= result
.replaceSection (i
, stringToReplaceLen
, stringToInsert
);
1291 i
+= stringToInsertLen
;
1297 String
String::replaceFirstOccurrenceOf (StringRef stringToReplace
, StringRef stringToInsert
, const bool ignoreCase
) const
1299 auto stringToReplaceLen
= stringToReplace
.length();
1300 auto index
= ignoreCase
? indexOfIgnoreCase (stringToReplace
)
1301 : indexOf (stringToReplace
);
1304 return replaceSection (index
, stringToReplaceLen
, stringToInsert
);
1309 struct StringCreationHelper
1311 StringCreationHelper (size_t initialBytes
) : allocatedBytes (initialBytes
)
1313 result
.preallocateBytes (allocatedBytes
);
1314 dest
= result
.getCharPointer();
1317 StringCreationHelper (const String::CharPointerType s
)
1318 : source (s
), allocatedBytes (StringHolderUtils::getAllocatedNumBytes (s
))
1320 result
.preallocateBytes (allocatedBytes
);
1321 dest
= result
.getCharPointer();
1324 void write (juce_wchar c
)
1326 bytesWritten
+= String::CharPointerType::getBytesRequiredFor (c
);
1328 if (bytesWritten
> allocatedBytes
)
1330 allocatedBytes
+= jmax ((size_t) 8, allocatedBytes
/ 16);
1331 auto destOffset
= (size_t) (((char*) dest
.getAddress()) - (char*) result
.getCharPointer().getAddress());
1332 result
.preallocateBytes (allocatedBytes
);
1333 dest
= addBytesToPointer (result
.getCharPointer().getAddress(), (int) destOffset
);
1340 String::CharPointerType source
{ nullptr }, dest
{ nullptr };
1341 size_t allocatedBytes
, bytesWritten
= 0;
1344 String
String::replaceCharacter (const juce_wchar charToReplace
, const juce_wchar charToInsert
) const
1346 if (! containsChar (charToReplace
))
1349 StringCreationHelper
builder (text
);
1353 auto c
= builder
.source
.getAndAdvance();
1355 if (c
== charToReplace
)
1364 return std::move (builder
.result
);
1367 String
String::replaceCharacters (StringRef charactersToReplace
, StringRef charactersToInsertInstead
) const
1369 // Each character in the first string must have a matching one in the
1370 // second, so the two strings must be the same length.
1371 jassert (charactersToReplace
.length() == charactersToInsertInstead
.length());
1373 StringCreationHelper
builder (text
);
1377 auto c
= builder
.source
.getAndAdvance();
1378 auto index
= charactersToReplace
.text
.indexOf (c
);
1381 c
= charactersToInsertInstead
[index
];
1389 return std::move (builder
.result
);
1392 //==============================================================================
1393 bool String::startsWith (StringRef other
) const noexcept
1395 return text
.compareUpTo (other
.text
, other
.length()) == 0;
1398 bool String::startsWithIgnoreCase (StringRef other
) const noexcept
1400 return text
.compareIgnoreCaseUpTo (other
.text
, other
.length()) == 0;
1403 bool String::startsWithChar (const juce_wchar character
) const noexcept
1405 jassert (character
!= 0); // strings can't contain a null character!
1407 return *text
== character
;
1410 bool String::endsWithChar (const juce_wchar character
) const noexcept
1412 jassert (character
!= 0); // strings can't contain a null character!
1417 auto t
= text
.findTerminatingNull();
1418 return *--t
== character
;
1421 bool String::endsWith (StringRef other
) const noexcept
1423 auto end
= text
.findTerminatingNull();
1424 auto otherEnd
= other
.text
.findTerminatingNull();
1426 while (end
> text
&& otherEnd
> other
.text
)
1431 if (*end
!= *otherEnd
)
1435 return otherEnd
== other
.text
;
1438 bool String::endsWithIgnoreCase (StringRef other
) const noexcept
1440 auto end
= text
.findTerminatingNull();
1441 auto otherEnd
= other
.text
.findTerminatingNull();
1443 while (end
> text
&& otherEnd
> other
.text
)
1448 if (end
.toLowerCase() != otherEnd
.toLowerCase())
1452 return otherEnd
== other
.text
;
1455 //==============================================================================
1456 String
String::toUpperCase() const
1458 StringCreationHelper
builder (text
);
1462 auto c
= builder
.source
.toUpperCase();
1471 return std::move (builder
.result
);
1474 String
String::toLowerCase() const
1476 StringCreationHelper
builder (text
);
1480 auto c
= builder
.source
.toLowerCase();
1489 return std::move (builder
.result
);
1492 //==============================================================================
1493 juce_wchar
String::getLastCharacter() const noexcept
1495 return isEmpty() ? juce_wchar() : text
[length() - 1];
1498 String
String::substring (int start
, const int end
) const
1534 return String (t1
, t2
);
1537 String
String::substring (int start
) const
1544 while (--start
>= 0)
1555 String
String::dropLastCharacters (const int numberToDrop
) const
1557 return String (text
, (size_t) jmax (0, length() - numberToDrop
));
1560 String
String::getLastCharacters (const int numCharacters
) const
1562 return String (text
+ jmax (0, length() - jmax (0, numCharacters
)));
1565 String
String::fromFirstOccurrenceOf (StringRef sub
, bool includeSubString
, bool ignoreCase
) const
1567 auto i
= ignoreCase
? indexOfIgnoreCase (sub
)
1572 return substring (includeSubString
? i
: i
+ sub
.length());
1575 String
String::fromLastOccurrenceOf (StringRef sub
, bool includeSubString
, bool ignoreCase
) const
1577 auto i
= ignoreCase
? lastIndexOfIgnoreCase (sub
)
1578 : lastIndexOf (sub
);
1582 return substring (includeSubString
? i
: i
+ sub
.length());
1585 String
String::upToFirstOccurrenceOf (StringRef sub
, bool includeSubString
, bool ignoreCase
) const
1587 auto i
= ignoreCase
? indexOfIgnoreCase (sub
)
1592 return substring (0, includeSubString
? i
+ sub
.length() : i
);
1595 String
String::upToLastOccurrenceOf (StringRef sub
, bool includeSubString
, bool ignoreCase
) const
1597 auto i
= ignoreCase
? lastIndexOfIgnoreCase (sub
)
1598 : lastIndexOf (sub
);
1602 return substring (0, includeSubString
? i
+ sub
.length() : i
);
1605 static bool isQuoteCharacter (juce_wchar c
) noexcept
1607 return c
== '"' || c
== '\'';
1610 bool String::isQuotedString() const
1612 return isQuoteCharacter (*text
.findEndOfWhitespace());
1615 String
String::unquoted() const
1617 if (! isQuoteCharacter (*text
))
1620 auto len
= length();
1621 return substring (1, len
- (isQuoteCharacter (text
[len
- 1]) ? 1 : 0));
1624 String
String::quoted (juce_wchar quoteCharacter
) const
1627 return charToString (quoteCharacter
) + quoteCharacter
;
1631 if (! t
.startsWithChar (quoteCharacter
))
1632 t
= charToString (quoteCharacter
) + t
;
1634 if (! t
.endsWithChar (quoteCharacter
))
1635 t
+= quoteCharacter
;
1640 //==============================================================================
1641 static String::CharPointerType
findTrimmedEnd (const String::CharPointerType start
,
1642 String::CharPointerType end
)
1646 if (! (--end
).isWhitespace())
1656 String
String::trim() const
1660 auto start
= text
.findEndOfWhitespace();
1661 auto end
= start
.findTerminatingNull();
1662 auto trimmedEnd
= findTrimmedEnd (start
, end
);
1664 if (trimmedEnd
<= start
)
1667 if (text
< start
|| trimmedEnd
< end
)
1668 return String (start
, trimmedEnd
);
1674 String
String::trimStart() const
1678 auto t
= text
.findEndOfWhitespace();
1687 String
String::trimEnd() const
1691 auto end
= text
.findTerminatingNull();
1692 auto trimmedEnd
= findTrimmedEnd (text
, end
);
1694 if (trimmedEnd
< end
)
1695 return String (text
, trimmedEnd
);
1701 String
String::trimCharactersAtStart (StringRef charactersToTrim
) const
1705 while (charactersToTrim
.text
.indexOf (*t
) >= 0)
1708 return t
== text
? *this : String (t
);
1711 String
String::trimCharactersAtEnd (StringRef charactersToTrim
) const
1715 auto end
= text
.findTerminatingNull();
1716 auto trimmedEnd
= end
;
1718 while (trimmedEnd
> text
)
1720 if (charactersToTrim
.text
.indexOf (*--trimmedEnd
) < 0)
1727 if (trimmedEnd
< end
)
1728 return String (text
, trimmedEnd
);
1734 //==============================================================================
1735 String
String::retainCharacters (StringRef charactersToRetain
) const
1740 StringCreationHelper
builder (text
);
1744 auto c
= builder
.source
.getAndAdvance();
1746 if (charactersToRetain
.text
.indexOf (c
) >= 0)
1754 return std::move (builder
.result
);
1757 String
String::removeCharacters (StringRef charactersToRemove
) const
1762 StringCreationHelper
builder (text
);
1766 auto c
= builder
.source
.getAndAdvance();
1768 if (charactersToRemove
.text
.indexOf (c
) < 0)
1775 return std::move (builder
.result
);
1778 String
String::initialSectionContainingOnly (StringRef permittedCharacters
) const
1780 for (auto t
= text
; ! t
.isEmpty(); ++t
)
1781 if (permittedCharacters
.text
.indexOf (*t
) < 0)
1782 return String (text
, t
);
1787 String
String::initialSectionNotContaining (StringRef charactersToStopAt
) const
1789 for (auto t
= text
; ! t
.isEmpty(); ++t
)
1790 if (charactersToStopAt
.text
.indexOf (*t
) >= 0)
1791 return String (text
, t
);
1796 bool String::containsOnly (StringRef chars
) const noexcept
1798 for (auto t
= text
; ! t
.isEmpty();)
1799 if (chars
.text
.indexOf (t
.getAndAdvance()) < 0)
1805 bool String::containsAnyOf (StringRef chars
) const noexcept
1807 for (auto t
= text
; ! t
.isEmpty();)
1808 if (chars
.text
.indexOf (t
.getAndAdvance()) >= 0)
1814 bool String::containsNonWhitespaceChars() const noexcept
1816 for (auto t
= text
; ! t
.isEmpty(); ++t
)
1817 if (! t
.isWhitespace())
1823 String
String::formattedRaw (const char* pf
, ...)
1825 size_t bufferSize
= 256;
1830 va_start (args
, pf
);
1833 JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
1837 HeapBlock
<char> temp (bufferSize
);
1838 int num
= (int) vsnprintf (temp
.get(), bufferSize
- 1, pf
, args
);
1839 if (num
>= static_cast<int> (bufferSize
))
1842 String
wideCharVersion (pf
);
1843 HeapBlock
<wchar_t> temp (bufferSize
);
1844 const int num
= (int)
1850 (temp
.get(), bufferSize
- 1, wideCharVersion
.toWideCharPointer(), args
);
1854 JUCE_END_IGNORE_WARNINGS_GCC_LIKE
1859 return String (temp
.get());
1863 if (num
== 0 || bufferSize
> 65536) // the upper limit is a sanity check to avoid situations where vprintf repeatedly
1864 break; // returns -1 because of an error rather than because it needs more space.
1870 //==============================================================================
1871 int String::getIntValue() const noexcept
{ return text
.getIntValue32(); }
1872 int64
String::getLargeIntValue() const noexcept
{ return text
.getIntValue64(); }
1873 float String::getFloatValue() const noexcept
{ return (float) getDoubleValue(); }
1874 double String::getDoubleValue() const noexcept
{ return text
.getDoubleValue(); }
1876 int String::getTrailingIntValue() const noexcept
1880 auto t
= text
.findTerminatingNull();
1892 n
+= (int) (((juce_wchar
) mult
) * (*t
- '0'));
1899 static const char hexDigits
[] = "0123456789abcdef";
1901 template <typename Type
>
1902 static String
hexToString (Type v
)
1904 String::CharPointerType::CharType buffer
[32];
1905 auto* end
= buffer
+ numElementsInArray (buffer
) - 1;
1911 *--t
= hexDigits
[(int) (v
& 15)];
1912 v
= static_cast<Type
> (v
>> 4);
1916 return String (String::CharPointerType (t
),
1917 String::CharPointerType (end
));
1920 String
String::createHex (uint8 n
) { return hexToString (n
); }
1921 String
String::createHex (uint16 n
) { return hexToString (n
); }
1922 String
String::createHex (uint32 n
) { return hexToString (n
); }
1923 String
String::createHex (uint64 n
) { return hexToString (n
); }
1925 String
String::toHexString (const void* const d
, const int size
, const int groupSize
)
1930 int numChars
= (size
* 2) + 2;
1932 numChars
+= size
/ groupSize
;
1934 String
s (PreallocationBytes ((size_t) numChars
* sizeof (CharPointerType::CharType
)));
1936 auto* data
= static_cast<const unsigned char*> (d
);
1939 for (int i
= 0; i
< size
; ++i
)
1941 const unsigned char nextByte
= *data
++;
1942 dest
.write ((juce_wchar
) hexDigits
[nextByte
>> 4]);
1943 dest
.write ((juce_wchar
) hexDigits
[nextByte
& 0xf]);
1945 if (groupSize
> 0 && (i
% groupSize
) == (groupSize
- 1) && i
< (size
- 1))
1946 dest
.write ((juce_wchar
) ' ');
1953 int String::getHexValue32() const noexcept
{ return (int32
) CharacterFunctions::HexParser
<uint32
>::parse (text
); }
1954 int64
String::getHexValue64() const noexcept
{ return (int64
) CharacterFunctions::HexParser
<uint64
>::parse (text
); }
1956 //==============================================================================
1957 static String
getStringFromWindows1252Codepage (const char* data
, size_t num
)
1959 HeapBlock
<juce_wchar
> unicode (num
+ 1);
1961 for (size_t i
= 0; i
< num
; ++i
)
1962 unicode
[i
] = CharacterFunctions::getUnicodeCharFromWindows1252Codepage ((uint8
) data
[i
]);
1965 return CharPointer_UTF32 (unicode
);
1968 String
String::createStringFromData (const void* const unknownData
, int size
)
1970 auto* data
= static_cast<const uint8
*> (unknownData
);
1972 if (size
<= 0 || data
== nullptr)
1976 return charToString ((juce_wchar
) data
[0]);
1978 if (CharPointer_UTF16::isByteOrderMarkBigEndian (data
)
1979 || CharPointer_UTF16::isByteOrderMarkLittleEndian (data
))
1981 const int numChars
= size
/ 2 - 1;
1983 StringCreationHelper
builder ((size_t) numChars
);
1985 auto src
= unalignedPointerCast
<const uint16
*> (data
+ 2);
1987 if (CharPointer_UTF16::isByteOrderMarkBigEndian (data
))
1989 for (int i
= 0; i
< numChars
; ++i
)
1990 builder
.write ((juce_wchar
) ByteOrder::swapIfLittleEndian (src
[i
]));
1994 for (int i
= 0; i
< numChars
; ++i
)
1995 builder
.write ((juce_wchar
) ByteOrder::swapIfBigEndian (src
[i
]));
1999 return std::move (builder
.result
);
2002 auto* start
= (const char*) data
;
2004 if (size
>= 3 && CharPointer_UTF8::isByteOrderMark (data
))
2010 if (CharPointer_UTF8::isValidString (start
, size
))
2011 return String (CharPointer_UTF8 (start
),
2012 CharPointer_UTF8 (start
+ size
));
2014 return getStringFromWindows1252Codepage (start
, (size_t) size
);
2017 //==============================================================================
2018 static const juce_wchar emptyChar
= 0;
2020 template <class CharPointerType_Src
, class CharPointerType_Dest
>
2021 struct StringEncodingConverter
2023 static CharPointerType_Dest
convert (const String
& s
)
2025 auto& source
= const_cast<String
&> (s
);
2027 using DestChar
= typename
CharPointerType_Dest::CharType
;
2029 if (source
.isEmpty())
2030 return CharPointerType_Dest (reinterpret_cast<const DestChar
*> (&emptyChar
));
2032 CharPointerType_Src
text (source
.getCharPointer());
2033 auto extraBytesNeeded
= CharPointerType_Dest::getBytesRequiredFor (text
) + sizeof (typename
CharPointerType_Dest::CharType
);
2034 auto endOffset
= (text
.sizeInBytes() + 3) & ~3u; // the new string must be word-aligned or many Windows
2035 // functions will fail to read it correctly!
2036 source
.preallocateBytes (endOffset
+ extraBytesNeeded
);
2037 text
= source
.getCharPointer();
2039 void* const newSpace
= addBytesToPointer (text
.getAddress(), (int) endOffset
);
2040 const CharPointerType_Dest
extraSpace (static_cast<DestChar
*> (newSpace
));
2042 #if JUCE_DEBUG // (This just avoids spurious warnings from valgrind about the uninitialised bytes at the end of the buffer..)
2043 auto bytesToClear
= (size_t) jmin ((int) extraBytesNeeded
, 4);
2044 zeromem (addBytesToPointer (newSpace
, extraBytesNeeded
- bytesToClear
), bytesToClear
);
2047 CharPointerType_Dest (extraSpace
).writeAll (text
);
2053 struct StringEncodingConverter
<CharPointer_UTF8
, CharPointer_UTF8
>
2055 static CharPointer_UTF8
convert (const String
& source
) noexcept
{ return CharPointer_UTF8 (unalignedPointerCast
<CharPointer_UTF8::CharType
*> (source
.getCharPointer().getAddress())); }
2059 struct StringEncodingConverter
<CharPointer_UTF16
, CharPointer_UTF16
>
2061 static CharPointer_UTF16
convert (const String
& source
) noexcept
{ return CharPointer_UTF16 (unalignedPointerCast
<CharPointer_UTF16::CharType
*> (source
.getCharPointer().getAddress())); }
2065 struct StringEncodingConverter
<CharPointer_UTF32
, CharPointer_UTF32
>
2067 static CharPointer_UTF32
convert (const String
& source
) noexcept
{ return CharPointer_UTF32 (unalignedPointerCast
<CharPointer_UTF32::CharType
*> (source
.getCharPointer().getAddress())); }
2070 CharPointer_UTF8
String::toUTF8() const { return StringEncodingConverter
<CharPointerType
, CharPointer_UTF8
>::convert (*this); }
2071 CharPointer_UTF16
String::toUTF16() const { return StringEncodingConverter
<CharPointerType
, CharPointer_UTF16
>::convert (*this); }
2072 CharPointer_UTF32
String::toUTF32() const { return StringEncodingConverter
<CharPointerType
, CharPointer_UTF32
>::convert (*this); }
2074 const char* String::toRawUTF8() const
2076 return toUTF8().getAddress();
2079 const wchar_t* String::toWideCharPointer() const
2081 return StringEncodingConverter
<CharPointerType
, CharPointer_wchar_t
>::convert (*this).getAddress();
2084 std::string
String::toStdString() const
2086 return std::string (toRawUTF8());
2089 //==============================================================================
2090 template <class CharPointerType_Src
, class CharPointerType_Dest
>
2093 static size_t copyToBuffer (const CharPointerType_Src source
, typename
CharPointerType_Dest::CharType
* const buffer
, const size_t maxBufferSizeBytes
)
2095 jassert (((ssize_t
) maxBufferSizeBytes
) >= 0); // keep this value positive!
2097 if (buffer
== nullptr)
2098 return CharPointerType_Dest::getBytesRequiredFor (source
) + sizeof (typename
CharPointerType_Dest::CharType
);
2100 return CharPointerType_Dest (buffer
).writeWithDestByteLimit (source
, maxBufferSizeBytes
);
2104 size_t String::copyToUTF8 (CharPointer_UTF8::CharType
* const buffer
, size_t maxBufferSizeBytes
) const noexcept
2106 return StringCopier
<CharPointerType
, CharPointer_UTF8
>::copyToBuffer (text
, buffer
, maxBufferSizeBytes
);
2109 size_t String::copyToUTF16 (CharPointer_UTF16::CharType
* const buffer
, size_t maxBufferSizeBytes
) const noexcept
2111 return StringCopier
<CharPointerType
, CharPointer_UTF16
>::copyToBuffer (text
, buffer
, maxBufferSizeBytes
);
2114 size_t String::copyToUTF32 (CharPointer_UTF32::CharType
* const buffer
, size_t maxBufferSizeBytes
) const noexcept
2116 return StringCopier
<CharPointerType
, CharPointer_UTF32
>::copyToBuffer (text
, buffer
, maxBufferSizeBytes
);
2119 //==============================================================================
2120 size_t String::getNumBytesAsUTF8() const noexcept
2122 return CharPointer_UTF8::getBytesRequiredFor (text
);
2125 String
String::fromUTF8 (const char* const buffer
, int bufferSizeBytes
)
2127 if (buffer
!= nullptr)
2129 if (bufferSizeBytes
< 0)
2130 return String (CharPointer_UTF8 (buffer
));
2132 if (bufferSizeBytes
> 0)
2134 jassert (CharPointer_UTF8::isValidString (buffer
, bufferSizeBytes
));
2135 return String (CharPointer_UTF8 (buffer
), CharPointer_UTF8 (buffer
+ bufferSizeBytes
));
2142 JUCE_END_IGNORE_WARNINGS_MSVC
2144 //==============================================================================
2145 StringRef::StringRef() noexcept
: text (unalignedPointerCast
<const String::CharPointerType::CharType
*> ("\0\0\0"))
2149 StringRef::StringRef (const char* stringLiteral
) noexcept
2150 #if JUCE_STRING_UTF_TYPE != 8
2151 : text (nullptr), stringCopy (stringLiteral
)
2153 : text (stringLiteral
)
2156 #if JUCE_STRING_UTF_TYPE != 8
2157 text
= stringCopy
.getCharPointer();
2160 jassert (stringLiteral
!= nullptr); // This must be a valid string literal, not a null pointer!!
2162 #if JUCE_NATIVE_WCHAR_IS_UTF8
2163 /* If you get an assertion here, then you're trying to create a string from 8-bit data
2164 that contains values greater than 127. These can NOT be correctly converted to unicode
2165 because there's no way for the String class to know what encoding was used to
2166 create them. The source data could be UTF-8, ASCII or one of many local code-pages.
2168 To get around this problem, you must be more explicit when you pass an ambiguous 8-bit
2169 string to the StringRef class - so for example if your source data is actually UTF-8,
2170 you'd call StringRef (CharPointer_UTF8 ("my utf8 string..")), and it would be able to
2171 correctly convert the multi-byte characters to unicode. It's *highly* recommended that
2172 you use UTF-8 with escape characters in your source code to represent extended characters,
2173 because there's no other way to represent these strings in a way that isn't dependent on
2174 the compiler, source code editor and platform.
2176 jassert (CharPointer_ASCII::isValidString (stringLiteral
, std::numeric_limits
<int>::max()));
2180 StringRef::StringRef (String::CharPointerType stringLiteral
) noexcept
: text (stringLiteral
)
2182 jassert (stringLiteral
.getAddress() != nullptr); // This must be a valid string literal, not a null pointer!!
2185 StringRef::StringRef (const String
& string
) noexcept
: text (string
.getCharPointer()) {}
2186 StringRef::StringRef (const std::string
& string
) : StringRef (string
.c_str()) {}
2188 //==============================================================================
2189 static String
reduceLengthOfFloatString (const String
& input
)
2191 const auto start
= input
.getCharPointer();
2192 const auto end
= start
+ (int) input
.length();
2193 auto trimStart
= end
;
2194 auto trimEnd
= trimStart
;
2195 auto exponentTrimStart
= end
;
2196 auto exponentTrimEnd
= exponentTrimStart
;
2198 decltype (*start
) currentChar
= '\0';
2200 for (auto c
= end
- 1; c
> start
; --c
)
2204 if (currentChar
== '0' && c
+ 1 == trimStart
)
2208 else if (currentChar
== '.')
2210 if (trimStart
== c
+ 1 && trimStart
!= end
&& *trimStart
== '0')
2215 else if (currentChar
== 'e' || currentChar
== 'E')
2224 exponentTrimStart
= cNext
;
2226 if (cNext
!= end
&& *cNext
== '+')
2229 exponentTrimEnd
= cNext
;
2232 while (cNext
!= end
&& *cNext
++ == '0')
2233 exponentTrimEnd
= cNext
;
2235 if (exponentTrimEnd
== end
)
2236 exponentTrimStart
= c
;
2239 trimEnd
= trimStart
;
2243 if ((trimStart
!= trimEnd
&& currentChar
== '.') || exponentTrimStart
!= exponentTrimEnd
)
2245 if (trimStart
== trimEnd
)
2246 return String (start
, exponentTrimStart
) + String (exponentTrimEnd
, end
);
2248 if (exponentTrimStart
== exponentTrimEnd
)
2249 return String (start
, trimStart
) + String (trimEnd
, end
);
2251 if (trimEnd
== exponentTrimStart
)
2252 return String (start
, trimStart
) + String (exponentTrimEnd
, end
);
2254 return String (start
, trimStart
) + String (trimEnd
, exponentTrimStart
) + String (exponentTrimEnd
, end
);
2260 static String
serialiseDouble (double input
)
2262 auto absInput
= std::abs (input
);
2264 if (absInput
>= 1.0e6
|| absInput
<= 1.0e-5)
2265 return reduceLengthOfFloatString ({ input
, 15, true });
2267 int intInput
= (int) input
;
2269 if ((double) intInput
== input
)
2270 return { input
, 1 };
2272 auto numberOfDecimalPlaces
= [absInput
]
2276 if (absInput
>= 1.0e-3)
2278 if (absInput
>= 1.0e-1) return 16;
2279 if (absInput
>= 1.0e-2) return 17;
2283 if (absInput
>= 1.0e-4) return 19;
2287 if (absInput
< 1.0e3
)
2289 if (absInput
< 1.0e1
) return 15;
2290 if (absInput
< 1.0e2
) return 14;
2294 if (absInput
< 1.0e4
) return 12;
2295 if (absInput
< 1.0e5
) return 11;
2299 return reduceLengthOfFloatString (String (input
, numberOfDecimalPlaces
));
2302 //==============================================================================
2303 #if JUCE_ALLOW_STATIC_NULL_VARIABLES
2305 JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
2306 JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996)
2308 const String
String::empty
;
2310 JUCE_END_IGNORE_WARNINGS_GCC_LIKE
2311 JUCE_END_IGNORE_WARNINGS_MSVC
2315 //==============================================================================
2316 //==============================================================================
2319 #define STRINGIFY2(X) #X
2320 #define STRINGIFY(X) STRINGIFY2(X)
2322 class StringTests
: public UnitTest
2326 : UnitTest ("String class", UnitTestCategories::text
)
2329 template <class CharPointerType
>
2330 struct TestUTFConversion
2332 static void test (UnitTest
& test
, Random
& r
)
2334 String
s (createRandomWideCharString (r
));
2336 typename
CharPointerType::CharType buffer
[300];
2338 memset (buffer
, 0xff, sizeof (buffer
));
2339 CharPointerType (buffer
).writeAll (s
.toUTF32());
2340 test
.expectEquals (String (CharPointerType (buffer
)), s
);
2342 memset (buffer
, 0xff, sizeof (buffer
));
2343 CharPointerType (buffer
).writeAll (s
.toUTF16());
2344 test
.expectEquals (String (CharPointerType (buffer
)), s
);
2346 memset (buffer
, 0xff, sizeof (buffer
));
2347 CharPointerType (buffer
).writeAll (s
.toUTF8());
2348 test
.expectEquals (String (CharPointerType (buffer
)), s
);
2350 test
.expect (CharPointerType::isValidString (buffer
, (int) strlen ((const char*) buffer
)));
2354 static String
createRandomWideCharString (Random
& r
)
2356 juce_wchar buffer
[50] = { 0 };
2358 for (int i
= 0; i
< numElementsInArray (buffer
) - 1; ++i
)
2364 buffer
[i
] = (juce_wchar
) (1 + r
.nextInt (0x10ffff - 1));
2366 while (! CharPointer_UTF16::canRepresent (buffer
[i
]));
2369 buffer
[i
] = (juce_wchar
) (1 + r
.nextInt (0xff));
2372 return CharPointer_UTF32 (buffer
);
2375 void runTest() override
2377 Random r
= getRandom();
2380 beginTest ("Basics");
2382 expect (String().length() == 0);
2383 expect (String() == String());
2384 String s1
, s2 ("abcd");
2385 expect (s1
.isEmpty() && ! s1
.isNotEmpty());
2386 expect (s2
.isNotEmpty() && ! s2
.isEmpty());
2387 expect (s2
.length() == 4);
2389 expect (s2
== s1
&& s1
== s2
);
2390 expect (s1
== "abcd" && s1
== L
"abcd");
2391 expect (String ("abcd") == String (L
"abcd"));
2392 expect (String ("abcdefg", 4) == L
"abcd");
2393 expect (String ("abcdefg", 4) == String (L
"abcdefg", 4));
2394 expect (String::charToString ('x') == "x");
2395 expect (String::charToString (0) == String());
2396 expect (s2
+ "e" == "abcde" && s2
+ 'e' == "abcde");
2397 expect (s2
+ L
'e' == "abcde" && s2
+ L
"e" == "abcde");
2398 expect (s1
.equalsIgnoreCase ("abcD") && s1
< "abce" && s1
> "abbb");
2399 expect (s1
.startsWith ("ab") && s1
.startsWith ("abcd") && ! s1
.startsWith ("abcde"));
2400 expect (s1
.startsWithIgnoreCase ("aB") && s1
.endsWithIgnoreCase ("CD"));
2401 expect (s1
.endsWith ("bcd") && ! s1
.endsWith ("aabcd"));
2402 expectEquals (s1
.indexOf (String()), 0);
2403 expectEquals (s1
.indexOfIgnoreCase (String()), 0);
2404 expect (s1
.startsWith (String()) && s1
.endsWith (String()) && s1
.contains (String()));
2405 expect (s1
.contains ("cd") && s1
.contains ("ab") && s1
.contains ("abcd"));
2406 expect (s1
.containsChar ('a'));
2407 expect (! s1
.containsChar ('x'));
2408 expect (! s1
.containsChar (0));
2409 expect (String ("abc foo bar").containsWholeWord ("abc") && String ("abc foo bar").containsWholeWord ("abc"));
2413 beginTest ("Operations");
2415 String
s ("012345678");
2416 expect (s
.hashCode() != 0);
2417 expect (s
.hashCode64() != 0);
2418 expect (s
.hashCode() != (s
+ s
).hashCode());
2419 expect (s
.hashCode64() != (s
+ s
).hashCode64());
2420 expect (s
.compare (String ("012345678")) == 0);
2421 expect (s
.compare (String ("012345679")) < 0);
2422 expect (s
.compare (String ("012345676")) > 0);
2423 expect (String("a").compareNatural ("A") == 0);
2424 expect (String("A").compareNatural ("B") < 0);
2425 expect (String("a").compareNatural ("B") < 0);
2426 expect (String("10").compareNatural ("2") > 0);
2427 expect (String("Abc 10").compareNatural ("aBC 2") > 0);
2428 expect (String("Abc 1").compareNatural ("aBC 2") < 0);
2429 expect (s
.substring (2, 3) == String::charToString (s
[2]));
2430 expect (s
.substring (0, 1) == String::charToString (s
[0]));
2431 expect (s
.getLastCharacter() == s
[s
.length() - 1]);
2432 expect (String::charToString (s
.getLastCharacter()) == s
.getLastCharacters (1));
2433 expect (s
.substring (0, 3) == L
"012");
2434 expect (s
.substring (0, 100) == s
);
2435 expect (s
.substring (-1, 100) == s
);
2436 expect (s
.substring (3) == "345678");
2437 expect (s
.indexOf (String (L
"45")) == 4);
2438 expect (String ("444445").indexOf ("45") == 4);
2439 expect (String ("444445").lastIndexOfChar ('4') == 4);
2440 expect (String ("45454545x").lastIndexOf (String (L
"45")) == 6);
2441 expect (String ("45454545x").lastIndexOfAnyOf ("456") == 7);
2442 expect (String ("45454545x").lastIndexOfAnyOf (String (L
"456x")) == 8);
2443 expect (String ("abABaBaBa").lastIndexOfIgnoreCase ("aB") == 6);
2444 expect (s
.indexOfChar (L
'4') == 4);
2445 expect (s
+ s
== "012345678012345678");
2446 expect (s
.startsWith (s
));
2447 expect (s
.startsWith (s
.substring (0, 4)));
2448 expect (s
.startsWith (s
.dropLastCharacters (4)));
2449 expect (s
.endsWith (s
.substring (5)));
2450 expect (s
.endsWith (s
));
2451 expect (s
.contains (s
.substring (3, 6)));
2452 expect (s
.contains (s
.substring (3)));
2453 expect (s
.startsWithChar (s
[0]));
2454 expect (s
.endsWithChar (s
.getLastCharacter()));
2455 expect (s
[s
.length()] == 0);
2456 expect (String ("abcdEFGH").toLowerCase() == String ("abcdefgh"));
2457 expect (String ("abcdEFGH").toUpperCase() == String ("ABCDEFGH"));
2459 expect (String (StringRef ("abc")) == "abc");
2460 expect (String (StringRef ("abc")) == StringRef ("abc"));
2461 expect (String ("abc") + StringRef ("def") == "abcdef");
2463 expect (String ("0x00").getHexValue32() == 0);
2464 expect (String ("0x100").getHexValue32() == 256);
2467 s2
<< ((int) 4) << ((short) 5) << "678" << L
"9" << '0';
2469 expect (s2
== "1234567890xyz");
2471 expect (s2
== "1234567890xyz123");
2473 expect (s2
== "1234567890xyz123123");
2474 s2
<< StringRef ("def");
2475 expect (s2
== "1234567890xyz123123def");
2479 String
numStr (std::numeric_limits
<int16
>::max());
2480 expect (numStr
== "32767");
2483 String
numStr (std::numeric_limits
<int16
>::min());
2484 expect (numStr
== "-32768");
2488 numStr
<< std::numeric_limits
<int16
>::max();
2489 expect (numStr
== "32767");
2493 numStr
<< std::numeric_limits
<int16
>::min();
2494 expect (numStr
== "-32768");
2498 String
numStr (std::numeric_limits
<int32
>::max());
2499 expect (numStr
== "2147483647");
2502 String
numStr (std::numeric_limits
<int32
>::min());
2503 expect (numStr
== "-2147483648");
2507 numStr
<< std::numeric_limits
<int32
>::max();
2508 expect (numStr
== "2147483647");
2512 numStr
<< std::numeric_limits
<int32
>::min();
2513 expect (numStr
== "-2147483648");
2517 String
numStr (std::numeric_limits
<uint32
>::max());
2518 expect (numStr
== "4294967295");
2521 String
numStr (std::numeric_limits
<uint32
>::min());
2522 expect (numStr
== "0");
2526 String
numStr (std::numeric_limits
<int64
>::max());
2527 expect (numStr
== "9223372036854775807");
2530 String
numStr (std::numeric_limits
<int64
>::min());
2531 expect (numStr
== "-9223372036854775808");
2535 numStr
<< std::numeric_limits
<int64
>::max();
2536 expect (numStr
== "9223372036854775807");
2540 numStr
<< std::numeric_limits
<int64
>::min();
2541 expect (numStr
== "-9223372036854775808");
2545 String
numStr (std::numeric_limits
<uint64
>::max());
2546 expect (numStr
== "18446744073709551615");
2549 String
numStr (std::numeric_limits
<uint64
>::min());
2550 expect (numStr
== "0");
2554 numStr
<< std::numeric_limits
<uint64
>::max();
2555 expect (numStr
== "18446744073709551615");
2559 numStr
<< std::numeric_limits
<uint64
>::min();
2560 expect (numStr
== "0");
2564 String
numStr (std::numeric_limits
<size_t>::min());
2565 expect (numStr
== "0");
2568 beginTest ("Numeric conversions");
2569 expect (String().getIntValue() == 0);
2570 expect (String().getDoubleValue() == 0.0);
2571 expect (String().getFloatValue() == 0.0f
);
2572 expect (s
.getIntValue() == 12345678);
2573 expect (s
.getLargeIntValue() == (int64
) 12345678);
2574 expect (s
.getDoubleValue() == 12345678.0);
2575 expect (s
.getFloatValue() == 12345678.0f
);
2576 expect (String (-1234).getIntValue() == -1234);
2577 expect (String ((int64
) -1234).getLargeIntValue() == -1234);
2578 expect (String (-1234.56).getDoubleValue() == -1234.56);
2579 expect (String (-1234.56f
).getFloatValue() == -1234.56f
);
2580 expect (String (std::numeric_limits
<int>::max()).getIntValue() == std::numeric_limits
<int>::max());
2581 expect (String (std::numeric_limits
<int>::min()).getIntValue() == std::numeric_limits
<int>::min());
2582 expect (String (std::numeric_limits
<int64
>::max()).getLargeIntValue() == std::numeric_limits
<int64
>::max());
2583 expect (String (std::numeric_limits
<int64
>::min()).getLargeIntValue() == std::numeric_limits
<int64
>::min());
2584 expect (("xyz" + s
).getTrailingIntValue() == s
.getIntValue());
2585 expect (String ("xyz-5").getTrailingIntValue() == -5);
2586 expect (String ("-12345").getTrailingIntValue() == -12345);
2587 expect (s
.getHexValue32() == 0x12345678);
2588 expect (s
.getHexValue64() == (int64
) 0x12345678);
2589 expect (String::toHexString (0x1234abcd).equalsIgnoreCase ("1234abcd"));
2590 expect (String::toHexString ((int64
) 0x1234abcd).equalsIgnoreCase ("1234abcd"));
2591 expect (String::toHexString ((short) 0x12ab).equalsIgnoreCase ("12ab"));
2592 expect (String::toHexString ((size_t) 0x12ab).equalsIgnoreCase ("12ab"));
2593 expect (String::toHexString ((long) 0x12ab).equalsIgnoreCase ("12ab"));
2594 expect (String::toHexString ((int8
) -1).equalsIgnoreCase ("ff"));
2595 expect (String::toHexString ((int16
) -1).equalsIgnoreCase ("ffff"));
2596 expect (String::toHexString ((int32
) -1).equalsIgnoreCase ("ffffffff"));
2597 expect (String::toHexString ((int64
) -1).equalsIgnoreCase ("ffffffffffffffff"));
2599 unsigned char data
[] = { 1, 2, 3, 4, 0xa, 0xb, 0xc, 0xd };
2600 expect (String::toHexString (data
, 8, 0).equalsIgnoreCase ("010203040a0b0c0d"));
2601 expect (String::toHexString (data
, 8, 1).equalsIgnoreCase ("01 02 03 04 0a 0b 0c 0d"));
2602 expect (String::toHexString (data
, 8, 2).equalsIgnoreCase ("0102 0304 0a0b 0c0d"));
2604 expectEquals (String (12345.67, 4), String ("12345.6700"));
2605 expectEquals (String (12345.67, 6), String ("12345.670000"));
2606 expectEquals (String (2589410.5894, 7), String ("2589410.5894000"));
2607 expectEquals (String (12345.67, 8), String ("12345.67000000"));
2608 expectEquals (String (1e19
, 4), String ("10000000000000000000.0000"));
2609 expectEquals (String (1e-34, 36), String ("0.000000000000000000000000000000000100"));
2610 expectEquals (String (1.39, 1), String ("1.4"));
2612 expectEquals (String (12345.67, 4, true), String ("1.2346e+04"));
2613 expectEquals (String (12345.67, 6, true), String ("1.234567e+04"));
2614 expectEquals (String (2589410.5894, 7, true), String ("2.5894106e+06"));
2615 expectEquals (String (12345.67, 8, true), String ("1.23456700e+04"));
2616 expectEquals (String (1e19
, 4, true), String ("1.0000e+19"));
2617 expectEquals (String (1e-34, 5, true), String ("1.00000e-34"));
2618 expectEquals (String (1.39, 1, true), String ("1.4e+00"));
2620 beginTest ("Subsections");
2623 expect (s3
.equalsIgnoreCase ("ABCdeFGhiJ"));
2624 expect (s3
.compareIgnoreCase (L
"ABCdeFGhiJ") == 0);
2625 expect (s3
.containsIgnoreCase (s3
.substring (3)));
2626 expect (s3
.indexOfAnyOf ("xyzf", 2, true) == 5);
2627 expect (s3
.indexOfAnyOf (String (L
"xyzf"), 2, false) == -1);
2628 expect (s3
.indexOfAnyOf ("xyzF", 2, false) == 5);
2629 expect (s3
.containsAnyOf (String (L
"zzzFs")));
2630 expect (s3
.startsWith ("abcd"));
2631 expect (s3
.startsWithIgnoreCase (String (L
"abCD")));
2632 expect (s3
.startsWith (String()));
2633 expect (s3
.startsWithChar ('a'));
2634 expect (s3
.endsWith (String ("HIJ")));
2635 expect (s3
.endsWithIgnoreCase (String (L
"Hij")));
2636 expect (s3
.endsWith (String()));
2637 expect (s3
.endsWithChar (L
'J'));
2638 expect (s3
.indexOf ("HIJ") == 7);
2639 expect (s3
.indexOf (String (L
"HIJK")) == -1);
2640 expect (s3
.indexOfIgnoreCase ("hij") == 7);
2641 expect (s3
.indexOfIgnoreCase (String (L
"hijk")) == -1);
2642 expect (s3
.toStdString() == s3
.toRawUTF8());
2645 s4
.append (String ("xyz123"), 3);
2646 expect (s4
== s3
+ "xyz");
2648 expect (String (1234) < String (1235));
2649 expect (String (1235) > String (1234));
2650 expect (String (1234) >= String (1234));
2651 expect (String (1234) <= String (1234));
2652 expect (String (1235) >= String (1234));
2653 expect (String (1234) <= String (1235));
2655 String
s5 ("word word2 word3");
2656 expect (s5
.containsWholeWord (String ("word2")));
2657 expect (s5
.indexOfWholeWord ("word2") == 5);
2658 expect (s5
.containsWholeWord (String (L
"word")));
2659 expect (s5
.containsWholeWord ("word3"));
2660 expect (s5
.containsWholeWord (s5
));
2661 expect (s5
.containsWholeWordIgnoreCase (String (L
"Word2")));
2662 expect (s5
.indexOfWholeWordIgnoreCase ("Word2") == 5);
2663 expect (s5
.containsWholeWordIgnoreCase (String (L
"Word")));
2664 expect (s5
.containsWholeWordIgnoreCase ("Word3"));
2665 expect (! s5
.containsWholeWordIgnoreCase (String (L
"Wordx")));
2666 expect (! s5
.containsWholeWordIgnoreCase ("xWord2"));
2667 expect (s5
.containsNonWhitespaceChars());
2668 expect (s5
.containsOnly ("ordw23 "));
2669 expect (! String (" \n\r\t").containsNonWhitespaceChars());
2671 expect (s5
.matchesWildcard (String (L
"wor*"), false));
2672 expect (s5
.matchesWildcard ("wOr*", true));
2673 expect (s5
.matchesWildcard (String (L
"*word3"), true));
2674 expect (s5
.matchesWildcard ("*word?", true));
2675 expect (s5
.matchesWildcard (String (L
"Word*3"), true));
2676 expect (! s5
.matchesWildcard (String (L
"*34"), true));
2677 expect (String ("xx**y").matchesWildcard ("*y", true));
2678 expect (String ("xx**y").matchesWildcard ("x*y", true));
2679 expect (String ("xx**y").matchesWildcard ("xx*y", true));
2680 expect (String ("xx**y").matchesWildcard ("xx*", true));
2681 expect (String ("xx?y").matchesWildcard ("x??y", true));
2682 expect (String ("xx?y").matchesWildcard ("xx?y", true));
2683 expect (! String ("xx?y").matchesWildcard ("xx?y?", true));
2684 expect (String ("xx?y").matchesWildcard ("xx??", true));
2686 expectEquals (s5
.fromFirstOccurrenceOf (String(), true, false), s5
);
2687 expectEquals (s5
.fromFirstOccurrenceOf ("xword2", true, false), s5
.substring (100));
2688 expectEquals (s5
.fromFirstOccurrenceOf (String (L
"word2"), true, false), s5
.substring (5));
2689 expectEquals (s5
.fromFirstOccurrenceOf ("Word2", true, true), s5
.substring (5));
2690 expectEquals (s5
.fromFirstOccurrenceOf ("word2", false, false), s5
.getLastCharacters (6));
2691 expectEquals (s5
.fromFirstOccurrenceOf ("Word2", false, true), s5
.getLastCharacters (6));
2693 expectEquals (s5
.fromLastOccurrenceOf (String(), true, false), s5
);
2694 expectEquals (s5
.fromLastOccurrenceOf ("wordx", true, false), s5
);
2695 expectEquals (s5
.fromLastOccurrenceOf ("word", true, false), s5
.getLastCharacters (5));
2696 expectEquals (s5
.fromLastOccurrenceOf ("worD", true, true), s5
.getLastCharacters (5));
2697 expectEquals (s5
.fromLastOccurrenceOf ("word", false, false), s5
.getLastCharacters (1));
2698 expectEquals (s5
.fromLastOccurrenceOf ("worD", false, true), s5
.getLastCharacters (1));
2700 expect (s5
.upToFirstOccurrenceOf (String(), true, false).isEmpty());
2701 expectEquals (s5
.upToFirstOccurrenceOf ("word4", true, false), s5
);
2702 expectEquals (s5
.upToFirstOccurrenceOf ("word2", true, false), s5
.substring (0, 10));
2703 expectEquals (s5
.upToFirstOccurrenceOf ("Word2", true, true), s5
.substring (0, 10));
2704 expectEquals (s5
.upToFirstOccurrenceOf ("word2", false, false), s5
.substring (0, 5));
2705 expectEquals (s5
.upToFirstOccurrenceOf ("Word2", false, true), s5
.substring (0, 5));
2707 expectEquals (s5
.upToLastOccurrenceOf (String(), true, false), s5
);
2708 expectEquals (s5
.upToLastOccurrenceOf ("zword", true, false), s5
);
2709 expectEquals (s5
.upToLastOccurrenceOf ("word", true, false), s5
.dropLastCharacters (1));
2710 expectEquals (s5
.dropLastCharacters(1).upToLastOccurrenceOf ("word", true, false), s5
.dropLastCharacters (1));
2711 expectEquals (s5
.upToLastOccurrenceOf ("Word", true, true), s5
.dropLastCharacters (1));
2712 expectEquals (s5
.upToLastOccurrenceOf ("word", false, false), s5
.dropLastCharacters (5));
2713 expectEquals (s5
.upToLastOccurrenceOf ("Word", false, true), s5
.dropLastCharacters (5));
2715 expectEquals (s5
.replace ("word", "xyz", false), String ("xyz xyz2 xyz3"));
2716 expect (s5
.replace ("Word", "xyz", true) == "xyz xyz2 xyz3");
2717 expect (s5
.dropLastCharacters (1).replace ("Word", String ("xyz"), true) == L
"xyz xyz2 xyz");
2718 expect (s5
.replace ("Word", "", true) == " 2 3");
2719 expectEquals (s5
.replace ("Word2", "xyz", true), String ("word xyz word3"));
2720 expect (s5
.replaceCharacter (L
'w', 'x') != s5
);
2721 expectEquals (s5
.replaceCharacter ('w', L
'x').replaceCharacter ('x', 'w'), s5
);
2722 expect (s5
.replaceCharacters ("wo", "xy") != s5
);
2723 expectEquals (s5
.replaceCharacters ("wo", "xy").replaceCharacters ("xy", "wo"), s5
);
2724 expectEquals (s5
.retainCharacters ("1wordxya"), String ("wordwordword"));
2725 expect (s5
.retainCharacters (String()).isEmpty());
2726 expect (s5
.removeCharacters ("1wordxya") == " 2 3");
2727 expectEquals (s5
.removeCharacters (String()), s5
);
2728 expect (s5
.initialSectionContainingOnly ("word") == L
"word");
2729 expect (String ("word").initialSectionContainingOnly ("word") == L
"word");
2730 expectEquals (s5
.initialSectionNotContaining (String ("xyz ")), String ("word"));
2731 expectEquals (s5
.initialSectionNotContaining (String (";[:'/")), s5
);
2732 expect (! s5
.isQuotedString());
2733 expect (s5
.quoted().isQuotedString());
2734 expect (! s5
.quoted().unquoted().isQuotedString());
2735 expect (! String ("x'").isQuotedString());
2736 expect (String ("'x").isQuotedString());
2738 String
s6 (" \t xyz \t\r\n");
2739 expectEquals (s6
.trim(), String ("xyz"));
2740 expect (s6
.trim().trim() == "xyz");
2741 expectEquals (s5
.trim(), s5
);
2742 expectEquals (s6
.trimStart().trimEnd(), s6
.trim());
2743 expectEquals (s6
.trimStart().trimEnd(), s6
.trimEnd().trimStart());
2744 expectEquals (s6
.trimStart().trimStart().trimEnd().trimEnd(), s6
.trimEnd().trimStart());
2745 expect (s6
.trimStart() != s6
.trimEnd());
2746 expectEquals (("\t\r\n " + s6
+ "\t\n \r").trim(), s6
.trim());
2747 expect (String::repeatedString ("xyz", 3) == L
"xyzxyzxyz");
2751 beginTest ("UTF conversions");
2753 TestUTFConversion
<CharPointer_UTF32
>::test (*this, r
);
2754 TestUTFConversion
<CharPointer_UTF8
>::test (*this, r
);
2755 TestUTFConversion
<CharPointer_UTF16
>::test (*this, r
);
2759 beginTest ("StringArray");
2762 s
.addTokens ("4,3,2,1,0", ";,", "x");
2763 expectEquals (s
.size(), 5);
2765 expectEquals (s
.joinIntoString ("-"), String ("4-3-2-1-0"));
2767 expectEquals (s
.joinIntoString ("--"), String ("4--3--1--0"));
2768 expectEquals (s
.joinIntoString (StringRef()), String ("4310"));
2770 expectEquals (s
.joinIntoString ("x"), String());
2773 toks
.addTokens ("x,,", ";,", "");
2774 expectEquals (toks
.size(), 3);
2775 expectEquals (toks
.joinIntoString ("-"), String ("x--"));
2778 toks
.addTokens (",x,", ";,", "");
2779 expectEquals (toks
.size(), 3);
2780 expectEquals (toks
.joinIntoString ("-"), String ("-x-"));
2783 toks
.addTokens ("x,'y,z',", ";,", "'");
2784 expectEquals (toks
.size(), 3);
2785 expectEquals (toks
.joinIntoString ("-"), String ("x-'y,z'-"));
2796 expect (! v2
.equals (v1
));
2797 expect (! v1
.equals (v2
));
2798 expect (v2
.equals (v3
));
2799 expect (! v3
.equals (v1
));
2800 expect (! v1
.equals (v3
));
2801 expect (v1
.equals (v4
));
2802 expect (v4
.equals (v1
));
2803 expect (v5
.equals (v4
));
2804 expect (v4
.equals (v5
));
2805 expect (! v2
.equals (v4
));
2806 expect (! v4
.equals (v2
));
2810 beginTest ("Significant figures");
2814 expectEquals (String::toDecimalStringWithSignificantFigures (13, 1), String ("10"));
2815 expectEquals (String::toDecimalStringWithSignificantFigures (13, 2), String ("13"));
2816 expectEquals (String::toDecimalStringWithSignificantFigures (13, 3), String ("13.0"));
2817 expectEquals (String::toDecimalStringWithSignificantFigures (13, 4), String ("13.00"));
2819 expectEquals (String::toDecimalStringWithSignificantFigures (19368, 1), String ("20000"));
2820 expectEquals (String::toDecimalStringWithSignificantFigures (19348, 3), String ("19300"));
2822 expectEquals (String::toDecimalStringWithSignificantFigures (-5, 1), String ("-5"));
2823 expectEquals (String::toDecimalStringWithSignificantFigures (-5, 3), String ("-5.00"));
2827 expectEquals (String::toDecimalStringWithSignificantFigures (0, 1), String ("0"));
2828 expectEquals (String::toDecimalStringWithSignificantFigures (0, 2), String ("0.0"));
2829 expectEquals (String::toDecimalStringWithSignificantFigures (0, 3), String ("0.00"));
2833 expectEquals (String::toDecimalStringWithSignificantFigures (19.0, 1), String ("20"));
2834 expectEquals (String::toDecimalStringWithSignificantFigures (19.0, 2), String ("19"));
2835 expectEquals (String::toDecimalStringWithSignificantFigures (19.0, 3), String ("19.0"));
2836 expectEquals (String::toDecimalStringWithSignificantFigures (19.0, 4), String ("19.00"));
2838 expectEquals (String::toDecimalStringWithSignificantFigures (-5.45, 1), String ("-5"));
2839 expectEquals (String::toDecimalStringWithSignificantFigures (-5.45, 3), String ("-5.45"));
2841 expectEquals (String::toDecimalStringWithSignificantFigures (12345.6789, 9), String ("12345.6789"));
2842 expectEquals (String::toDecimalStringWithSignificantFigures (12345.6789, 8), String ("12345.679"));
2843 expectEquals (String::toDecimalStringWithSignificantFigures (12345.6789, 5), String ("12346"));
2845 expectEquals (String::toDecimalStringWithSignificantFigures (0.00028647, 6), String ("0.000286470"));
2846 expectEquals (String::toDecimalStringWithSignificantFigures (0.0028647, 6), String ("0.00286470"));
2847 expectEquals (String::toDecimalStringWithSignificantFigures (2.8647, 6), String ("2.86470"));
2849 expectEquals (String::toDecimalStringWithSignificantFigures (-0.0000000000019, 1), String ("-0.000000000002"));
2853 beginTest ("Float trimming");
2856 StringPairArray tests
;
2857 tests
.set ("1", "1");
2858 tests
.set ("1.0", "1.0");
2859 tests
.set ("-1", "-1");
2860 tests
.set ("-100", "-100");
2861 tests
.set ("110", "110");
2862 tests
.set ("9090", "9090");
2863 tests
.set ("1000.0", "1000.0");
2864 tests
.set ("1.0", "1.0");
2865 tests
.set ("-1.00", "-1.0");
2866 tests
.set ("1.20", "1.2");
2867 tests
.set ("1.300", "1.3");
2868 tests
.set ("1.301", "1.301");
2869 tests
.set ("1e", "1");
2870 tests
.set ("-1e+", "-1");
2871 tests
.set ("1e-", "1");
2872 tests
.set ("1e0", "1");
2873 tests
.set ("1e+0", "1");
2874 tests
.set ("1e-0", "1");
2875 tests
.set ("1e000", "1");
2876 tests
.set ("1e+000", "1");
2877 tests
.set ("-1e-000", "-1");
2878 tests
.set ("1e100", "1e100");
2879 tests
.set ("100e100", "100e100");
2880 tests
.set ("100.0e0100", "100.0e100");
2881 tests
.set ("-1e1", "-1e1");
2882 tests
.set ("1e10", "1e10");
2883 tests
.set ("-1e+10", "-1e10");
2884 tests
.set ("1e-10", "1e-10");
2885 tests
.set ("1e0010", "1e10");
2886 tests
.set ("1e-0010", "1e-10");
2887 tests
.set ("1e-1", "1e-1");
2888 tests
.set ("-1.0e1", "-1.0e1");
2889 tests
.set ("1.0e-1", "1.0e-1");
2890 tests
.set ("1.00e-1", "1.0e-1");
2891 tests
.set ("1.001e1", "1.001e1");
2892 tests
.set ("1.010e+1", "1.01e1");
2893 tests
.set ("-1.1000e1", "-1.1e1");
2895 for (auto& input
: tests
.getAllKeys())
2896 expectEquals (reduceLengthOfFloatString (input
), tests
[input
]);
2900 std::map
<double, String
> tests
;
2903 tests
[1.01] = "1.01";
2904 tests
[0.76378] = "7.6378e-1";
2905 tests
[-10] = "-1.0e1";
2906 tests
[10.01] = "1.001e1";
2907 tests
[10691.01] = "1.069101e4";
2908 tests
[0.0123] = "1.23e-2";
2909 tests
[-3.7e-27] = "-3.7e-27";
2910 tests
[1e+40] = "1.0e40";
2912 for (auto& test
: tests
)
2913 expectEquals (reduceLengthOfFloatString (String (test
.first
, 15, true)), test
.second
);
2918 beginTest ("Serialisation");
2920 std::map
<double, String
> tests
;
2922 tests
[364] = "364.0";
2923 tests
[1e7
] = "1.0e7";
2924 tests
[12345678901] = "1.2345678901e10";
2926 tests
[1234567890123456.7] = "1.234567890123457e15";
2927 tests
[12345678.901234567] = "1.234567890123457e7";
2928 tests
[1234567.8901234567] = "1.234567890123457e6";
2929 tests
[123456.78901234567] = "123456.7890123457";
2930 tests
[12345.678901234567] = "12345.67890123457";
2931 tests
[1234.5678901234567] = "1234.567890123457";
2932 tests
[123.45678901234567] = "123.4567890123457";
2933 tests
[12.345678901234567] = "12.34567890123457";
2934 tests
[1.2345678901234567] = "1.234567890123457";
2935 tests
[0.12345678901234567] = "0.1234567890123457";
2936 tests
[0.012345678901234567] = "0.01234567890123457";
2937 tests
[0.0012345678901234567] = "0.001234567890123457";
2938 tests
[0.00012345678901234567] = "0.0001234567890123457";
2939 tests
[0.000012345678901234567] = "0.00001234567890123457";
2940 tests
[0.0000012345678901234567] = "1.234567890123457e-6";
2941 tests
[0.00000012345678901234567] = "1.234567890123457e-7";
2943 for (auto& test
: tests
)
2945 expectEquals (serialiseDouble (test
.first
), test
.second
);
2946 expectEquals (serialiseDouble (-test
.first
), "-" + test
.second
);
2951 beginTest ("Loops");
2953 String
str (CharPointer_UTF8 ("\xc2\xaf\\_(\xe3\x83\x84)_/\xc2\xaf"));
2954 std::vector
<juce_wchar
> parts
{ 175, 92, 95, 40, 12484, 41, 95, 47, 175 };
2958 expectEquals (c
, parts
[index
++]);
2963 static StringTests stringUnitTests
;