OpenShot Audio Library | OpenShotAudio: juce_String.cpp Source File

OpenShot Audio Library | OpenShotAudio 0.3.2

Loading...
Searching...
No Matches
juce_String.cpp
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2017 - ROLI Ltd.
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
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.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23namespace juce
24{
25
26#if JUCE_MSVC
27 #pragma warning (push)
28 #pragma warning (disable: 4514 4996)
29#endif
30
31NewLine newLine;
32
33#if defined (JUCE_STRINGS_ARE_UNICODE) && ! JUCE_STRINGS_ARE_UNICODE
34 #error "JUCE_STRINGS_ARE_UNICODE is deprecated! All strings are now unicode by default."
35#endif
36
37#if JUCE_NATIVE_WCHAR_IS_UTF8
38 using CharPointer_wchar_t = CharPointer_UTF8;
39#elif JUCE_NATIVE_WCHAR_IS_UTF16
40 using CharPointer_wchar_t = CharPointer_UTF16;
41#else
42 using CharPointer_wchar_t = CharPointer_UTF32;
43#endif
44
45static inline CharPointer_wchar_t castToCharPointer_wchar_t (const void* t) noexcept
46{
47 return CharPointer_wchar_t (static_cast<const CharPointer_wchar_t::CharType*> (t));
48}
49
50//==============================================================================
51// (Mirrors the structure of StringHolder, but without the atomic member, so can be statically constructed)
52struct EmptyString
53{
54 int refCount;
55 size_t allocatedBytes;
56 String::CharPointerType::CharType text;
57};
58
59static const EmptyString emptyString { 0x3fffffff, sizeof (String::CharPointerType::CharType), 0 };
60
61//==============================================================================
62class StringHolder
63{
64public:
65 StringHolder() = delete;
66
67 using CharPointerType = String::CharPointerType;
68 using CharType = String::CharPointerType::CharType;
69
70 //==============================================================================
71 static CharPointerType createUninitialisedBytes (size_t numBytes)
72 {
73 numBytes = (numBytes + 3) & ~(size_t) 3;
74 auto s = reinterpret_cast<StringHolder*> (new char [sizeof (StringHolder) - sizeof (CharType) + numBytes]);
75 s->refCount.value = 0;
76 s->allocatedNumBytes = numBytes;
77 return CharPointerType (s->text);
78 }
79
80 template <class CharPointer>
81 static CharPointerType createFromCharPointer (const CharPointer text)
82 {
83 if (text.getAddress() == nullptr || text.isEmpty())
84 return CharPointerType (&(emptyString.text));
85
86 auto bytesNeeded = sizeof (CharType) + CharPointerType::getBytesRequiredFor (text);
87 auto dest = createUninitialisedBytes (bytesNeeded);
88 CharPointerType (dest).writeAll (text);
89 return dest;
90 }
91
92 template <class CharPointer>
93 static CharPointerType createFromCharPointer (const CharPointer text, size_t maxChars)
94 {
95 if (text.getAddress() == nullptr || text.isEmpty() || maxChars == 0)
96 return CharPointerType (&(emptyString.text));
97
98 auto end = text;
99 size_t numChars = 0;
100 size_t bytesNeeded = sizeof (CharType);
101
102 while (numChars < maxChars && ! end.isEmpty())
103 {
104 bytesNeeded += CharPointerType::getBytesRequiredFor (end.getAndAdvance());
105 ++numChars;
106 }
107
108 auto dest = createUninitialisedBytes (bytesNeeded);
109 CharPointerType (dest).writeWithCharLimit (text, (int) numChars + 1);
110 return dest;
111 }
112
113 template <class CharPointer>
114 static CharPointerType createFromCharPointer (const CharPointer start, const CharPointer end)
115 {
116 if (start.getAddress() == nullptr || start.isEmpty())
117 return CharPointerType (&(emptyString.text));
118
119 auto e = start;
120 int numChars = 0;
121 auto bytesNeeded = sizeof (CharType);
122
123 while (e < end && ! e.isEmpty())
124 {
125 bytesNeeded += CharPointerType::getBytesRequiredFor (e.getAndAdvance());
126 ++numChars;
127 }
128
129 auto dest = createUninitialisedBytes (bytesNeeded);
130 CharPointerType (dest).writeWithCharLimit (start, numChars + 1);
131 return dest;
132 }
133
134 static CharPointerType createFromCharPointer (const CharPointerType start, const CharPointerType end)
135 {
136 if (start.getAddress() == nullptr || start.isEmpty())
137 return CharPointerType (&(emptyString.text));
138
139 auto numBytes = (size_t) (reinterpret_cast<const char*> (end.getAddress())
140 - reinterpret_cast<const char*> (start.getAddress()));
141 auto dest = createUninitialisedBytes (numBytes + sizeof (CharType));
142 memcpy (dest.getAddress(), start, numBytes);
143 dest.getAddress()[numBytes / sizeof (CharType)] = 0;
144 return dest;
145 }
146
147 static CharPointerType createFromFixedLength (const char* const src, const size_t numChars)
148 {
149 auto dest = createUninitialisedBytes (numChars * sizeof (CharType) + sizeof (CharType));
150 CharPointerType (dest).writeWithCharLimit (CharPointer_UTF8 (src), (int) (numChars + 1));
151 return dest;
152 }
153
154 //==============================================================================
155 static void retain (const CharPointerType text) noexcept
156 {
157 auto* b = bufferFromText (text);
158
159 if (! isEmptyString (b))
160 ++(b->refCount);
161 }
162
163 static inline void release (StringHolder* const b) noexcept
164 {
165 if (! isEmptyString (b))
166 if (--(b->refCount) == -1)
167 delete[] reinterpret_cast<char*> (b);
168 }
169
170 static void release (const CharPointerType text) noexcept
171 {
172 release (bufferFromText (text));
173 }
174
175 static inline int getReferenceCount (const CharPointerType text) noexcept
176 {
177 return bufferFromText (text)->refCount.get() + 1;
178 }
179
180 //==============================================================================
181 static CharPointerType makeUniqueWithByteSize (const CharPointerType text, size_t numBytes)
182 {
183 auto* b = bufferFromText (text);
184
185 if (isEmptyString (b))
186 {
187 auto newText = createUninitialisedBytes (numBytes);
188 newText.writeNull();
189 return newText;
190 }
191
192 if (b->allocatedNumBytes >= numBytes && b->refCount.get() <= 0)
193 return text;
194
195 auto newText = createUninitialisedBytes (jmax (b->allocatedNumBytes, numBytes));
196 memcpy (newText.getAddress(), text.getAddress(), b->allocatedNumBytes);
197 release (b);
198
199 return newText;
200 }
201
202 static size_t getAllocatedNumBytes (const CharPointerType text) noexcept
203 {
204 return bufferFromText (text)->allocatedNumBytes;
205 }
206
207 //==============================================================================
208 Atomic<int> refCount;
209 size_t allocatedNumBytes;
210 CharType text[1];
211
212private:
213 static inline StringHolder* bufferFromText (const CharPointerType text) noexcept
214 {
215 // (Can't use offsetof() here because of warnings about this not being a POD)
216 return reinterpret_cast<StringHolder*> (reinterpret_cast<char*> (text.getAddress())
217 - (reinterpret_cast<size_t> (reinterpret_cast<StringHolder*> (128)->text) - 128));
218 }
219
220 static inline bool isEmptyString (StringHolder* other)
221 {
222 return (other->refCount.get() & 0x30000000) != 0;
223 }
224
225 void compileTimeChecks()
226 {
227 // Let me know if any of these assertions fail on your system!
228 #if JUCE_NATIVE_WCHAR_IS_UTF8
229 static_assert (sizeof (wchar_t) == 1, "JUCE_NATIVE_WCHAR_IS_* macro has incorrect value");
230 #elif JUCE_NATIVE_WCHAR_IS_UTF16
231 static_assert (sizeof (wchar_t) == 2, "JUCE_NATIVE_WCHAR_IS_* macro has incorrect value");
232 #elif JUCE_NATIVE_WCHAR_IS_UTF32
233 static_assert (sizeof (wchar_t) == 4, "JUCE_NATIVE_WCHAR_IS_* macro has incorrect value");
234 #else
235 #error "native wchar_t size is unknown"
236 #endif
237
238 static_assert (sizeof (EmptyString) == sizeof (StringHolder),
239 "StringHolder is not large enough to hold an empty String");
240 }
241};
242
243JUCE_DECLARE_DEPRECATED_STATIC (const String String::empty;)
244
245//==============================================================================
246String::String() noexcept : text (&(emptyString.text))
247{
248}
249
250String::~String() noexcept
251{
252 StringHolder::release (text);
253}
254
255 String::String (const String& other) noexcept : text (other.text)
256{
257 StringHolder::retain (text);
258}
259
260 void String::swapWith (String& other) noexcept
261{
262 std::swap (text, other.text);
263}
264
265 void String::clear() noexcept
266{
267 StringHolder::release (text);
268 text = &(emptyString.text);
269}
270
271 String& String::operator= (const String& other) noexcept
272{
273 StringHolder::retain (other.text);
274 StringHolder::release (text.atomicSwap (other.text));
275 return *this;
276}
277
278 String::String (String&& other) noexcept : text (other.text)
279{
280 other.text = &(emptyString.text);
281}
282
283 String& String::operator= (String&& other) noexcept
284{
285 std::swap (text, other.text);
286 return *this;
287}
288
289inline String::PreallocationBytes::PreallocationBytes (const size_t num) noexcept : numBytes (num) {}
290
291 String::String (const PreallocationBytes& preallocationSize)
292 : text (StringHolder::createUninitialisedBytes (preallocationSize.numBytes + sizeof (CharPointerType::CharType)))
293{
294}
295
296 void String::preallocateBytes (const size_t numBytesNeeded)
297{
298 text = StringHolder::makeUniqueWithByteSize (text, numBytesNeeded + sizeof (CharPointerType::CharType));
299}
300
301 int String::getReferenceCount() const noexcept
302{
303 return StringHolder::getReferenceCount (text);
304}
305
306//==============================================================================
307 String::String (const char* const t)
308 : text (StringHolder::createFromCharPointer (CharPointer_ASCII (t)))
309{
310 /* If you get an assertion here, then you're trying to create a string from 8-bit data
311 that contains values greater than 127. These can NOT be correctly converted to unicode
312 because there's no way for the String class to know what encoding was used to
313 create them. The source data could be UTF-8, ASCII or one of many local code-pages.
314
315 To get around this problem, you must be more explicit when you pass an ambiguous 8-bit
316 string to the String class - so for example if your source data is actually UTF-8,
317 you'd call String (CharPointer_UTF8 ("my utf8 string..")), and it would be able to
318 correctly convert the multi-byte characters to unicode. It's *highly* recommended that
319 you use UTF-8 with escape characters in your source code to represent extended characters,
320 because there's no other way to represent these strings in a way that isn't dependent on
321 the compiler, source code editor and platform.
322
323 Note that the Projucer has a handy string literal generator utility that will convert
324 any unicode string to a valid C++ string literal, creating ascii escape sequences that will
325 work in any compiler.
326 */
327 jassert (t == nullptr || CharPointer_ASCII::isValidString (t, std::numeric_limits<int>::max()));
328}
329
330 String::String (const char* const t, const size_t maxChars)
331 : text (StringHolder::createFromCharPointer (CharPointer_ASCII (t), maxChars))
332{
333 /* If you get an assertion here, then you're trying to create a string from 8-bit data
334 that contains values greater than 127. These can NOT be correctly converted to unicode
335 because there's no way for the String class to know what encoding was used to
336 create them. The source data could be UTF-8, ASCII or one of many local code-pages.
337
338 To get around this problem, you must be more explicit when you pass an ambiguous 8-bit
339 string to the String class - so for example if your source data is actually UTF-8,
340 you'd call String (CharPointer_UTF8 ("my utf8 string..")), and it would be able to
341 correctly convert the multi-byte characters to unicode. It's *highly* recommended that
342 you use UTF-8 with escape characters in your source code to represent extended characters,
343 because there's no other way to represent these strings in a way that isn't dependent on
344 the compiler, source code editor and platform.
345
346 Note that the Projucer has a handy string literal generator utility that will convert
347 any unicode string to a valid C++ string literal, creating ascii escape sequences that will
348 work in any compiler.
349 */
350 jassert (t == nullptr || CharPointer_ASCII::isValidString (t, (int) maxChars));
351}
352
353 String::String (const wchar_t* const t) : text (StringHolder::createFromCharPointer (castToCharPointer_wchar_t (t))) {}
354 String::String (const CharPointer_UTF8 t) : text (StringHolder::createFromCharPointer (t)) {}
355 String::String (const CharPointer_UTF16 t) : text (StringHolder::createFromCharPointer (t)) {}
356 String::String (const CharPointer_UTF32 t) : text (StringHolder::createFromCharPointer (t)) {}
357 String::String (const CharPointer_ASCII t) : text (StringHolder::createFromCharPointer (t)) {}
358
359 String::String (CharPointer_UTF8 t, size_t maxChars) : text (StringHolder::createFromCharPointer (t, maxChars)) {}
360 String::String (CharPointer_UTF16 t, size_t maxChars) : text (StringHolder::createFromCharPointer (t, maxChars)) {}
361 String::String (CharPointer_UTF32 t, size_t maxChars) : text (StringHolder::createFromCharPointer (t, maxChars)) {}
362 String::String (const wchar_t* t, size_t maxChars) : text (StringHolder::createFromCharPointer (castToCharPointer_wchar_t (t), maxChars)) {}
363
364 String::String (CharPointer_UTF8 start, CharPointer_UTF8 end) : text (StringHolder::createFromCharPointer (start, end)) {}
365 String::String (CharPointer_UTF16 start, CharPointer_UTF16 end) : text (StringHolder::createFromCharPointer (start, end)) {}
366 String::String (CharPointer_UTF32 start, CharPointer_UTF32 end) : text (StringHolder::createFromCharPointer (start, end)) {}
367
368 String::String (const std::string& s) : text (StringHolder::createFromFixedLength (s.data(), s.size())) {}
369 String::String (StringRef s) : text (StringHolder::createFromCharPointer (s.text)) {}
370
371 String String::charToString (juce_wchar character)
372{
373 String result (PreallocationBytes (CharPointerType::getBytesRequiredFor (character)));
374 CharPointerType t (result.text);
375 t.write (character);
376 t.writeNull();
377 return result;
378}
379
380//==============================================================================
381namespace NumberToStringConverters
382{
383 enum
384 {
385 charsNeededForInt = 32,
386 charsNeededForDouble = 48
387 };
388
389 template <typename Type>
390 static char* printDigits (char* t, Type v) noexcept
391 {
392 *--t = 0;
393
394 do
395 {
396 *--t = '0' + (char) (v % 10);
397 v /= 10;
398
399 } while (v > 0);
400
401 return t;
402 }
403
404 // pass in a pointer to the END of a buffer..
405 static char* numberToString (char* t, int64 n) noexcept
406 {
407 if (n >= 0)
408 return printDigits (t, static_cast<uint64> (n));
409
410 // NB: this needs to be careful not to call -std::numeric_limits<int64>::min(),
411 // which has undefined behaviour
412 t = printDigits (t, static_cast<uint64> (-(n + 1)) + 1);
413 *--t = '-';
414 return t;
415 }
416
417 static char* numberToString (char* t, uint64 v) noexcept
418 {
419 return printDigits (t, v);
420 }
421
422 static char* numberToString (char* t, int n) noexcept
423 {
424 if (n >= 0)
425 return printDigits (t, static_cast<unsigned int> (n));
426
427 // NB: this needs to be careful not to call -std::numeric_limits<int>::min(),
428 // which has undefined behaviour
429 t = printDigits (t, static_cast<unsigned int> (-(n + 1)) + 1);
430 *--t = '-';
431 return t;
432 }
433
434 static char* numberToString (char* t, unsigned int v) noexcept
435 {
436 return printDigits (t, v);
437 }
438
439 static char* numberToString (char* t, long n) noexcept
440 {
441 if (n >= 0)
442 return printDigits (t, static_cast<unsigned long> (n));
443
444 t = printDigits (t, static_cast<unsigned long> (-(n + 1)) + 1);
445 *--t = '-';
446 return t;
447 }
448
449 static char* numberToString (char* t, unsigned long v) noexcept
450 {
451 return printDigits (t, v);
452 }
453
454 struct StackArrayStream : public std::basic_streambuf<char, std::char_traits<char>>
455 {
456 explicit StackArrayStream (char* d)
457 {
458 static const std::locale classicLocale (std::locale::classic());
459 imbue (classicLocale);
460 setp (d, d + charsNeededForDouble);
461 }
462
463 size_t writeDouble (double n, int numDecPlaces, bool useScientificNotation)
464 {
465 {
466 std::ostream o (this);
467
468 if (numDecPlaces > 0)
469 {
470 o.setf (useScientificNotation ? std::ios_base::scientific : std::ios_base::fixed);
471 o.precision ((std::streamsize) numDecPlaces);
472 }
473
474 o << n;
475 }
476
477 return (size_t) (pptr() - pbase());
478 }
479 };
480
481 static char* doubleToString (char* buffer, double n, int numDecPlaces, bool useScientificNotation, size_t& len) noexcept
482 {
483 StackArrayStream strm (buffer);
484 len = strm.writeDouble (n, numDecPlaces, useScientificNotation);
485 jassert (len <= charsNeededForDouble);
486 return buffer;
487 }
488
489 template <typename IntegerType>
490 static String::CharPointerType createFromInteger (IntegerType number)
491 {
492 char buffer [charsNeededForInt];
493 auto* end = buffer + numElementsInArray (buffer);
494 auto* start = numberToString (end, number);
495 return StringHolder::createFromFixedLength (start, (size_t) (end - start - 1));
496 }
497
498 static String::CharPointerType createFromDouble (double number, int numberOfDecimalPlaces, bool useScientificNotation)
499 {
500 char buffer [charsNeededForDouble];
501 size_t len;
502 auto start = doubleToString (buffer, number, numberOfDecimalPlaces, useScientificNotation, len);
503 return StringHolder::createFromFixedLength (start, len);
504 }
505}
506
507//==============================================================================
508 String::String (int number) : text (NumberToStringConverters::createFromInteger (number)) {}
509 String::String (unsigned int number) : text (NumberToStringConverters::createFromInteger (number)) {}
510 String::String (short number) : text (NumberToStringConverters::createFromInteger ((int) number)) {}
511 String::String (unsigned short number) : text (NumberToStringConverters::createFromInteger ((unsigned int) number)) {}
512 String::String (int64 number) : text (NumberToStringConverters::createFromInteger (number)) {}
513 String::String (uint64 number) : text (NumberToStringConverters::createFromInteger (number)) {}
514 String::String (long number) : text (NumberToStringConverters::createFromInteger (number)) {}
515 String::String (unsigned long number) : text (NumberToStringConverters::createFromInteger (number)) {}
516
517 String::String (float number) : text (NumberToStringConverters::createFromDouble ((double) number, 0, false)) {}
518 String::String (double number) : text (NumberToStringConverters::createFromDouble ( number, 0, false)) {}
519 String::String (float number, int numberOfDecimalPlaces, bool useScientificNotation) : text (NumberToStringConverters::createFromDouble ((double) number, numberOfDecimalPlaces, useScientificNotation)) {}
520 String::String (double number, int numberOfDecimalPlaces, bool useScientificNotation) : text (NumberToStringConverters::createFromDouble ( number, numberOfDecimalPlaces, useScientificNotation)) {}
521
522//==============================================================================
523 int String::length() const noexcept
524{
525 return (int) text.length();
526}
527
528static size_t findByteOffsetOfEnd (String::CharPointerType text) noexcept
529{
530 return (size_t) (((char*) text.findTerminatingNull().getAddress()) - (char*) text.getAddress());
531}
532
533size_t String::getByteOffsetOfEnd() const noexcept
534{
535 return findByteOffsetOfEnd (text);
536}
537
538juce_wchar String::operator[] (int index) const noexcept
539{
540 jassert (index == 0 || (index > 0 && index <= (int) text.lengthUpTo ((size_t) index + 1)));
541 return text [index];
542}
543
544template <typename Type>
545struct HashGenerator
546{
547 template <typename CharPointer>
548 static Type calculate (CharPointer t) noexcept
549 {
550 Type result = {};
551
552 while (! t.isEmpty())
553 result = ((Type) multiplier) * result + (Type) t.getAndAdvance();
554
555 return result;
556 }
557
558 enum { multiplier = sizeof (Type) > 4 ? 101 : 31 };
559};
560
561 int String::hashCode() const noexcept { return (int) HashGenerator<uint32> ::calculate (text); }
562int64 String::hashCode64() const noexcept { return (int64) HashGenerator<uint64> ::calculate (text); }
563 size_t String::hash() const noexcept { return HashGenerator<size_t> ::calculate (text); }
564
565//==============================================================================
566JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const String& s2) noexcept { return s1.compare (s2) == 0; }
567JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const String& s2) noexcept { return s1.compare (s2) != 0; }
568JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const char* s2) noexcept { return s1.compare (s2) == 0; }
569JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const char* s2) noexcept { return s1.compare (s2) != 0; }
570JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const wchar_t* s2) noexcept { return s1.compare (s2) == 0; }
571JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const wchar_t* s2) noexcept { return s1.compare (s2) != 0; }
572JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, StringRef s2) noexcept { return s1.getCharPointer().compare (s2.text) == 0; }
573JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, StringRef s2) noexcept { return s1.getCharPointer().compare (s2.text) != 0; }
574JUCE_API bool JUCE_CALLTYPE operator< (const String& s1, StringRef s2) noexcept { return s1.getCharPointer().compare (s2.text) < 0; }
575JUCE_API bool JUCE_CALLTYPE operator<= (const String& s1, StringRef s2) noexcept { return s1.getCharPointer().compare (s2.text) <= 0; }
576JUCE_API bool JUCE_CALLTYPE operator> (const String& s1, StringRef s2) noexcept { return s1.getCharPointer().compare (s2.text) > 0; }
577JUCE_API bool JUCE_CALLTYPE operator>= (const String& s1, StringRef s2) noexcept { return s1.getCharPointer().compare (s2.text) >= 0; }
578JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const CharPointer_UTF8 s2) noexcept { return s1.getCharPointer().compare (s2) == 0; }
579JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const CharPointer_UTF8 s2) noexcept { return s1.getCharPointer().compare (s2) != 0; }
580JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const CharPointer_UTF16 s2) noexcept { return s1.getCharPointer().compare (s2) == 0; }
581JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const CharPointer_UTF16 s2) noexcept { return s1.getCharPointer().compare (s2) != 0; }
582JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const CharPointer_UTF32 s2) noexcept { return s1.getCharPointer().compare (s2) == 0; }
583JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const CharPointer_UTF32 s2) noexcept { return s1.getCharPointer().compare (s2) != 0; }
584
585 bool String::equalsIgnoreCase (const wchar_t* const t) const noexcept
586{
587 return t != nullptr ? text.compareIgnoreCase (castToCharPointer_wchar_t (t)) == 0
588 : isEmpty();
589}
590
591 bool String::equalsIgnoreCase (const char* const t) const noexcept
592{
593 return t != nullptr ? text.compareIgnoreCase (CharPointer_UTF8 (t)) == 0
594 : isEmpty();
595}
596
597 bool String::equalsIgnoreCase (StringRef t) const noexcept
598{
599 return text.compareIgnoreCase (t.text) == 0;
600}
601
602 bool String::equalsIgnoreCase (const String& other) const noexcept
603{
604 return text == other.text
605 || text.compareIgnoreCase (other.text) == 0;
606}
607
608 int String::compare (const String& other) const noexcept { return (text == other.text) ? 0 : text.compare (other.text); }
609 int String::compare (const char* const other) const noexcept { return text.compare (CharPointer_UTF8 (other)); }
610 int String::compare (const wchar_t* const other) const noexcept { return text.compare (castToCharPointer_wchar_t (other)); }
611 int String::compareIgnoreCase (const String& other) const noexcept { return (text == other.text) ? 0 : text.compareIgnoreCase (other.text); }
612
613static int stringCompareRight (String::CharPointerType s1, String::CharPointerType s2) noexcept
614{
615 for (int bias = 0;;)
616 {
617 auto c1 = s1.getAndAdvance();
618 bool isDigit1 = CharacterFunctions::isDigit (c1);
619
620 auto c2 = s2.getAndAdvance();
621 bool isDigit2 = CharacterFunctions::isDigit (c2);
622
623 if (! (isDigit1 || isDigit2)) return bias;
624 if (! isDigit1) return -1;
625 if (! isDigit2) return 1;
626
627 if (c1 != c2 && bias == 0)
628 bias = c1 < c2 ? -1 : 1;
629
630 jassert (c1 != 0 && c2 != 0);
631 }
632}
633
634static int stringCompareLeft (String::CharPointerType s1, String::CharPointerType s2) noexcept
635{
636 for (;;)
637 {
638 auto c1 = s1.getAndAdvance();
639 bool isDigit1 = CharacterFunctions::isDigit (c1);
640
641 auto c2 = s2.getAndAdvance();
642 bool isDigit2 = CharacterFunctions::isDigit (c2);
643
644 if (! (isDigit1 || isDigit2)) return 0;
645 if (! isDigit1) return -1;
646 if (! isDigit2) return 1;
647 if (c1 < c2) return -1;
648 if (c1 > c2) return 1;
649 }
650}
651
652static int naturalStringCompare (String::CharPointerType s1, String::CharPointerType s2, bool isCaseSensitive) noexcept
653{
654 bool firstLoop = true;
655
656 for (;;)
657 {
658 const bool hasSpace1 = s1.isWhitespace();
659 const bool hasSpace2 = s2.isWhitespace();
660
661 if ((! firstLoop) && (hasSpace1 ^ hasSpace2))
662 {
663 if (s1.isEmpty()) return -1;
664 if (s2.isEmpty()) return 1;
665
666 return hasSpace2 ? 1 : -1;
667 }
668
669 firstLoop = false;
670
671 if (hasSpace1) s1 = s1.findEndOfWhitespace();
672 if (hasSpace2) s2 = s2.findEndOfWhitespace();
673
674 if (s1.isDigit() && s2.isDigit())
675 {
676 auto result = (*s1 == '0' || *s2 == '0') ? stringCompareLeft (s1, s2)
677 : stringCompareRight (s1, s2);
678
679 if (result != 0)
680 return result;
681 }
682
683 auto c1 = s1.getAndAdvance();
684 auto c2 = s2.getAndAdvance();
685
686 if (c1 != c2 && ! isCaseSensitive)
687 {
688 c1 = CharacterFunctions::toUpperCase (c1);
689 c2 = CharacterFunctions::toUpperCase (c2);
690 }
691
692 if (c1 == c2)
693 {
694 if (c1 == 0)
695 return 0;
696 }
697 else
698 {
699 const bool isAlphaNum1 = CharacterFunctions::isLetterOrDigit (c1);
700 const bool isAlphaNum2 = CharacterFunctions::isLetterOrDigit (c2);
701
702 if (isAlphaNum2 && ! isAlphaNum1) return -1;
703 if (isAlphaNum1 && ! isAlphaNum2) return 1;
704
705 return c1 < c2 ? -1 : 1;
706 }
707
708 jassert (c1 != 0 && c2 != 0);
709 }
710}
711
712 int String::compareNatural (StringRef other, bool isCaseSensitive) const noexcept
713{
714 return naturalStringCompare (getCharPointer(), other.text, isCaseSensitive);
715}
716
717//==============================================================================
718 void String::append (const String& textToAppend, size_t maxCharsToTake)
719{
720 appendCharPointer (this == &textToAppend ? String (textToAppend).text
721 : textToAppend.text, maxCharsToTake);
722}
723
724 void String::appendCharPointer (const CharPointerType textToAppend)
725{
726 appendCharPointer (textToAppend, textToAppend.findTerminatingNull());
727}
728
729 void String::appendCharPointer (const CharPointerType startOfTextToAppend,
730 const CharPointerType endOfTextToAppend)
731{
732 jassert (startOfTextToAppend.getAddress() != nullptr && endOfTextToAppend.getAddress() != nullptr);
733
734 auto extraBytesNeeded = getAddressDifference (endOfTextToAppend.getAddress(),
735 startOfTextToAppend.getAddress());
736 jassert (extraBytesNeeded >= 0);
737
738 if (extraBytesNeeded > 0)
739 {
740 auto byteOffsetOfNull = getByteOffsetOfEnd();
741 preallocateBytes ((size_t) extraBytesNeeded + byteOffsetOfNull);
742
743 auto* newStringStart = addBytesToPointer (text.getAddress(), (int) byteOffsetOfNull);
744 memcpy (newStringStart, startOfTextToAppend.getAddress(), (size_t) extraBytesNeeded);
745 CharPointerType (addBytesToPointer (newStringStart, extraBytesNeeded)).writeNull();
746 }
747}
748
749 String& String::operator+= (const wchar_t* t)
750{
751 appendCharPointer (castToCharPointer_wchar_t (t));
752 return *this;
753}
754
755 String& String::operator+= (const char* t)
756{
757 appendCharPointer (CharPointer_UTF8 (t)); // (using UTF8 here triggers a faster code-path than ascii)
758 return *this;
759}
760
761 String& String::operator+= (const String& other)
762{
763 if (isEmpty())
764 return operator= (other);
765
766 if (this == &other)
767 return operator+= (String (*this));
768
769 appendCharPointer (other.text);
770 return *this;
771}
772
773 String& String::operator+= (StringRef other)
774{
775 return operator+= (String (other));
776}
777
778 String& String::operator+= (char ch)
779{
780 const char asString[] = { ch, 0 };
781 return operator+= (asString);
782}
783
784 String& String::operator+= (wchar_t ch)
785{
786 const wchar_t asString[] = { ch, 0 };
787 return operator+= (asString);
788}
789
790#if ! JUCE_NATIVE_WCHAR_IS_UTF32
791 String& String::operator+= (juce_wchar ch)
792{
793 const juce_wchar asString[] = { ch, 0 };
794 appendCharPointer (CharPointer_UTF32 (asString));
795 return *this;
796}
797#endif
798
799namespace StringHelpers
800{
801 template <typename T>
802 inline String& operationAddAssign (String& str, const T number)
803 {
804 char buffer [(sizeof(T) * 8) / 2];
805 auto* end = buffer + numElementsInArray (buffer);
806 auto* start = NumberToStringConverters::numberToString (end, number);
807
808 #if JUCE_STRING_UTF_TYPE == 8
809 str.appendCharPointer (String::CharPointerType (start), String::CharPointerType (end));
810 #else
811 str.appendCharPointer (CharPointer_ASCII (start), CharPointer_ASCII (end));
812 #endif
813
814 return str;
815 }
816}
817
818 String& String::operator+= (const int number) { return StringHelpers::operationAddAssign<int> (*this, number); }
819 String& String::operator+= (const int64 number) { return StringHelpers::operationAddAssign<int64> (*this, number); }
820 String& String::operator+= (const uint64 number) { return StringHelpers::operationAddAssign<uint64> (*this, number); }
821
822//==============================================================================
823JUCE_API String JUCE_CALLTYPE operator+ (const char* s1, const String& s2) { String s (s1); return s += s2; }
824JUCE_API String JUCE_CALLTYPE operator+ (const wchar_t* s1, const String& s2) { String s (s1); return s += s2; }
825
826JUCE_API String JUCE_CALLTYPE operator+ (char s1, const String& s2) { return String::charToString ((juce_wchar) (uint8) s1) + s2; }
827JUCE_API String JUCE_CALLTYPE operator+ (wchar_t s1, const String& s2) { return String::charToString (s1) + s2; }
828
829JUCE_API String JUCE_CALLTYPE operator+ (String s1, const String& s2) { return s1 += s2; }
830JUCE_API String JUCE_CALLTYPE operator+ (String s1, const char* s2) { return s1 += s2; }
831JUCE_API String JUCE_CALLTYPE operator+ (String s1, const wchar_t* s2) { return s1 += s2; }
832JUCE_API String JUCE_CALLTYPE operator+ (String s1, const std::string& s2) { return s1 += s2.c_str(); }
833
834JUCE_API String JUCE_CALLTYPE operator+ (String s1, char s2) { return s1 += s2; }
835JUCE_API String JUCE_CALLTYPE operator+ (String s1, wchar_t s2) { return s1 += s2; }
836
837#if ! JUCE_NATIVE_WCHAR_IS_UTF32
838JUCE_API String JUCE_CALLTYPE operator+ (juce_wchar s1, const String& s2) { return String::charToString (s1) + s2; }
839JUCE_API String JUCE_CALLTYPE operator+ (String s1, juce_wchar s2) { return s1 += s2; }
840JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, juce_wchar s2) { return s1 += s2; }
841#endif
842
843JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, char s2) { return s1 += s2; }
844JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, wchar_t s2) { return s1 += s2; }
845
846JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, const char* s2) { return s1 += s2; }
847JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, const wchar_t* s2) { return s1 += s2; }
848JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, const String& s2) { return s1 += s2; }
849JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, StringRef s2) { return s1 += s2; }
850JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, const std::string& s2) { return s1 += s2.c_str(); }
851
852JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, uint8 number) { return s1 += (int) number; }
853JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, short number) { return s1 += (int) number; }
854JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, int number) { return s1 += number; }
855JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, long number) { return s1 += String (number); }
856JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, unsigned long number) { return s1 += String (number); }
857JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, int64 number) { return s1 += String (number); }
858JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, uint64 number) { return s1 += String (number); }
859JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, float number) { return s1 += String (number); }
860JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, double number) { return s1 += String (number); }
861
862JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const String& text)
863{
864 return operator<< (stream, StringRef (text));
865}
866
867JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, StringRef text)
868{
869 auto numBytes = CharPointer_UTF8::getBytesRequiredFor (text.text);
870
871 #if (JUCE_STRING_UTF_TYPE == 8)
872 stream.write (text.text.getAddress(), numBytes);
873 #else
874 // (This avoids using toUTF8() to prevent the memory bloat that it would leave behind
875 // if lots of large, persistent strings were to be written to streams).
876 HeapBlock<char> temp (numBytes + 1);
877 CharPointer_UTF8 (temp).writeAll (text.text);
878 stream.write (temp, numBytes);
879 #endif
880
881 return stream;
882}
883
884//==============================================================================
885 int String::indexOfChar (juce_wchar character) const noexcept
886{
887 return text.indexOf (character);
888}
889
890 int String::indexOfChar (int startIndex, juce_wchar character) const noexcept
891{
892 auto t = text;
893
894 for (int i = 0; ! t.isEmpty(); ++i)
895 {
896 if (i >= startIndex)
897 {
898 if (t.getAndAdvance() == character)
899 return i;
900 }
901 else
902 {
903 ++t;
904 }
905 }
906
907 return -1;
908}
909
910 int String::lastIndexOfChar (juce_wchar character) const noexcept
911{
912 auto t = text;
913 int last = -1;
914
915 for (int i = 0; ! t.isEmpty(); ++i)
916 if (t.getAndAdvance() == character)
917 last = i;
918
919 return last;
920}
921
922 int String::indexOfAnyOf (StringRef charactersToLookFor, int startIndex, bool ignoreCase) const noexcept
923{
924 auto t = text;
925
926 for (int i = 0; ! t.isEmpty(); ++i)
927 {
928 if (i >= startIndex)
929 {
930 if (charactersToLookFor.text.indexOf (t.getAndAdvance(), ignoreCase) >= 0)
931 return i;
932 }
933 else
934 {
935 ++t;
936 }
937 }
938
939 return -1;
940}
941
942 int String::indexOf (StringRef other) const noexcept
943{
944 return other.isEmpty() ? 0 : text.indexOf (other.text);
945}
946
947 int String::indexOfIgnoreCase (StringRef other) const noexcept
948{
949 return other.isEmpty() ? 0 : CharacterFunctions::indexOfIgnoreCase (text, other.text);
950}
951
952 int String::indexOf (int startIndex, StringRef other) const noexcept
953{
954 if (other.isEmpty())
955 return -1;
956
957 auto t = text;
958
959 for (int i = startIndex; --i >= 0;)
960 {
961 if (t.isEmpty())
962 return -1;
963
964 ++t;
965 }
966
967 auto found = t.indexOf (other.text);
968 return found >= 0 ? found + startIndex : found;
969}
970
971 int String::indexOfIgnoreCase (const int startIndex, StringRef other) const noexcept
972{
973 if (other.isEmpty())
974 return -1;
975
976 auto t = text;
977
978 for (int i = startIndex; --i >= 0;)
979 {
980 if (t.isEmpty())
981 return -1;
982
983 ++t;
984 }
985
986 auto found = CharacterFunctions::indexOfIgnoreCase (t, other.text);
987 return found >= 0 ? found + startIndex : found;
988}
989
990 int String::lastIndexOf (StringRef other) const noexcept
991{
992 if (other.isNotEmpty())
993 {
994 auto len = other.length();
995 int i = length() - len;
996
997 if (i >= 0)
998 {
999 for (auto n = text + i; i >= 0; --i)
1000 {
1001 if (n.compareUpTo (other.text, len) == 0)
1002 return i;
1003
1004 --n;
1005 }
1006 }
1007 }
1008
1009 return -1;
1010}
1011
1012 int String::lastIndexOfIgnoreCase (StringRef other) const noexcept
1013{
1014 if (other.isNotEmpty())
1015 {
1016 auto len = other.length();
1017 int i = length() - len;
1018
1019 if (i >= 0)
1020 {
1021 for (auto n = text + i; i >= 0; --i)
1022 {
1023 if (n.compareIgnoreCaseUpTo (other.text, len) == 0)
1024 return i;
1025
1026 --n;
1027 }
1028 }
1029 }
1030
1031 return -1;
1032}
1033
1034 int String::lastIndexOfAnyOf (StringRef charactersToLookFor, const bool ignoreCase) const noexcept
1035{
1036 auto t = text;
1037 int last = -1;
1038
1039 for (int i = 0; ! t.isEmpty(); ++i)
1040 if (charactersToLookFor.text.indexOf (t.getAndAdvance(), ignoreCase) >= 0)
1041 last = i;
1042
1043 return last;
1044}
1045
1046 bool String::contains (StringRef other) const noexcept
1047{
1048 return indexOf (other) >= 0;
1049}
1050
1051 bool String::containsChar (const juce_wchar character) const noexcept
1052{
1053 return text.indexOf (character) >= 0;
1054}
1055
1056 bool String::containsIgnoreCase (StringRef t) const noexcept
1057{
1058 return indexOfIgnoreCase (t) >= 0;
1059}
1060
1061 int String::indexOfWholeWord (StringRef word) const noexcept
1062{
1063 if (word.isNotEmpty())
1064 {
1065 auto t = text;
1066 auto wordLen = word.length();
1067 auto end = (int) t.length() - wordLen;
1068
1069 for (int i = 0; i <= end; ++i)
1070 {
1071 if (t.compareUpTo (word.text, wordLen) == 0
1072 && (i == 0 || ! (t - 1).isLetterOrDigit())
1073 && ! (t + wordLen).isLetterOrDigit())
1074 return i;
1075
1076 ++t;
1077 }
1078 }
1079
1080 return -1;
1081}
1082
1083 int String::indexOfWholeWordIgnoreCase (StringRef word) const noexcept
1084{
1085 if (word.isNotEmpty())
1086 {
1087 auto t = text;
1088 auto wordLen = word.length();
1089 auto end = (int) t.length() - wordLen;
1090
1091 for (int i = 0; i <= end; ++i)
1092 {
1093 if (t.compareIgnoreCaseUpTo (word.text, wordLen) == 0
1094 && (i == 0 || ! (t - 1).isLetterOrDigit())
1095 && ! (t + wordLen).isLetterOrDigit())
1096 return i;
1097
1098 ++t;
1099 }
1100 }
1101
1102 return -1;
1103}
1104
1105 bool String::containsWholeWord (StringRef wordToLookFor) const noexcept
1106{
1107 return indexOfWholeWord (wordToLookFor) >= 0;
1108}
1109
1110 bool String::containsWholeWordIgnoreCase (StringRef wordToLookFor) const noexcept
1111{
1112 return indexOfWholeWordIgnoreCase (wordToLookFor) >= 0;
1113}
1114
1115//==============================================================================
1116template <typename CharPointer>
1117struct WildCardMatcher
1118{
1119 static bool matches (CharPointer wildcard, CharPointer test, const bool ignoreCase) noexcept
1120 {
1121 for (;;)
1122 {
1123 auto wc = wildcard.getAndAdvance();
1124
1125 if (wc == '*')
1126 return wildcard.isEmpty() || matchesAnywhere (wildcard, test, ignoreCase);
1127
1128 if (! characterMatches (wc, test.getAndAdvance(), ignoreCase))
1129 return false;
1130
1131 if (wc == 0)
1132 return true;
1133 }
1134 }
1135
1136 static bool characterMatches (const juce_wchar wc, const juce_wchar tc, const bool ignoreCase) noexcept
1137 {
1138 return (wc == tc) || (wc == '?' && tc != 0)
1139 || (ignoreCase && CharacterFunctions::toLowerCase (wc) == CharacterFunctions::toLowerCase (tc));
1140 }
1141
1142 static bool matchesAnywhere (const CharPointer wildcard, CharPointer test, const bool ignoreCase) noexcept
1143 {
1144 for (; ! test.isEmpty(); ++test)
1145 if (matches (wildcard, test, ignoreCase))
1146 return true;
1147
1148 return false;
1149 }
1150};
1151
1152 bool String::matchesWildcard (StringRef wildcard, const bool ignoreCase) const noexcept
1153{
1154 return WildCardMatcher<CharPointerType>::matches (wildcard.text, text, ignoreCase);
1155}
1156
1157//==============================================================================
1158 String String::repeatedString (StringRef stringToRepeat, int numberOfTimesToRepeat)
1159{
1160 if (numberOfTimesToRepeat <= 0)
1161 return {};
1162
1163 String result (PreallocationBytes (findByteOffsetOfEnd (stringToRepeat) * (size_t) numberOfTimesToRepeat));
1164 auto n = result.text;
1165
1166 while (--numberOfTimesToRepeat >= 0)
1167 n.writeAll (stringToRepeat.text);
1168
1169 return result;
1170}
1171
1172 String String::paddedLeft (const juce_wchar padCharacter, int minimumLength) const
1173{
1174 jassert (padCharacter != 0);
1175
1176 auto extraChars = minimumLength;
1177 auto end = text;
1178
1179 while (! end.isEmpty())
1180 {
1181 --extraChars;
1182 ++end;
1183 }
1184
1185 if (extraChars <= 0 || padCharacter == 0)
1186 return *this;
1187
1188 auto currentByteSize = (size_t) (((char*) end.getAddress()) - (char*) text.getAddress());
1189 String result (PreallocationBytes (currentByteSize + (size_t) extraChars * CharPointerType::getBytesRequiredFor (padCharacter)));
1190 auto n = result.text;
1191
1192 while (--extraChars >= 0)
1193 n.write (padCharacter);
1194
1195 n.writeAll (text);
1196 return result;
1197}
1198
1199 String String::paddedRight (const juce_wchar padCharacter, int minimumLength) const
1200{
1201 jassert (padCharacter != 0);
1202
1203 auto extraChars = minimumLength;
1204 CharPointerType end (text);
1205
1206 while (! end.isEmpty())
1207 {
1208 --extraChars;
1209 ++end;
1210 }
1211
1212 if (extraChars <= 0 || padCharacter == 0)
1213 return *this;
1214
1215 auto currentByteSize = (size_t) (((char*) end.getAddress()) - (char*) text.getAddress());
1216 String result (PreallocationBytes (currentByteSize + (size_t) extraChars * CharPointerType::getBytesRequiredFor (padCharacter)));
1217 auto n = result.text;
1218
1219 n.writeAll (text);
1220
1221 while (--extraChars >= 0)
1222 n.write (padCharacter);
1223
1224 n.writeNull();
1225 return result;
1226}
1227
1228//==============================================================================
1229 String String::replaceSection (int index, int numCharsToReplace, StringRef stringToInsert) const
1230{
1231 if (index < 0)
1232 {
1233 // a negative index to replace from?
1234 jassertfalse;
1235 index = 0;
1236 }
1237
1238 if (numCharsToReplace < 0)
1239 {
1240 // replacing a negative number of characters?
1241 numCharsToReplace = 0;
1242 jassertfalse;
1243 }
1244
1245 auto insertPoint = text;
1246
1247 for (int i = 0; i < index; ++i)
1248 {
1249 if (insertPoint.isEmpty())
1250 {
1251 // replacing beyond the end of the string?
1252 jassertfalse;
1253 return *this + stringToInsert;
1254 }
1255
1256 ++insertPoint;
1257 }
1258
1259 auto startOfRemainder = insertPoint;
1260
1261 for (int i = 0; i < numCharsToReplace && ! startOfRemainder.isEmpty(); ++i)
1262 ++startOfRemainder;
1263
1264 if (insertPoint == text && startOfRemainder.isEmpty())
1265 return stringToInsert.text;
1266
1267 auto initialBytes = (size_t) (((char*) insertPoint.getAddress()) - (char*) text.getAddress());
1268 auto newStringBytes = findByteOffsetOfEnd (stringToInsert);
1269 auto remainderBytes = (size_t) (((char*) startOfRemainder.findTerminatingNull().getAddress()) - (char*) startOfRemainder.getAddress());
1270
1271 auto newTotalBytes = initialBytes + newStringBytes + remainderBytes;
1272
1273 if (newTotalBytes <= 0)
1274 return {};
1275
1276 String result (PreallocationBytes ((size_t) newTotalBytes));
1277
1278 auto* dest = (char*) result.text.getAddress();
1279 memcpy (dest, text.getAddress(), initialBytes);
1280 dest += initialBytes;
1281 memcpy (dest, stringToInsert.text.getAddress(), newStringBytes);
1282 dest += newStringBytes;
1283 memcpy (dest, startOfRemainder.getAddress(), remainderBytes);
1284 dest += remainderBytes;
1285 CharPointerType ((CharPointerType::CharType*) dest).writeNull();
1286
1287 return result;
1288}
1289
1290 String String::replace (StringRef stringToReplace, StringRef stringToInsert, const bool ignoreCase) const
1291{
1292 auto stringToReplaceLen = stringToReplace.length();
1293 auto stringToInsertLen = stringToInsert.length();
1294
1295 int i = 0;
1296 String result (*this);
1297
1298 while ((i = (ignoreCase ? result.indexOfIgnoreCase (i, stringToReplace)
1299 : result.indexOf (i, stringToReplace))) >= 0)
1300 {
1301 result = result.replaceSection (i, stringToReplaceLen, stringToInsert);
1302 i += stringToInsertLen;
1303 }
1304
1305 return result;
1306}
1307
1308 String String::replaceFirstOccurrenceOf (StringRef stringToReplace, StringRef stringToInsert, const bool ignoreCase) const
1309{
1310 auto stringToReplaceLen = stringToReplace.length();
1311 auto index = ignoreCase ? indexOfIgnoreCase (stringToReplace)
1312 : indexOf (stringToReplace);
1313
1314 if (index >= 0)
1315 return replaceSection (index, stringToReplaceLen, stringToInsert);
1316
1317 return *this;
1318}
1319
1320struct StringCreationHelper
1321{
1322 StringCreationHelper (size_t initialBytes) : allocatedBytes (initialBytes)
1323 {
1324 result.preallocateBytes (allocatedBytes);
1325 dest = result.getCharPointer();
1326 }
1327
1328 StringCreationHelper (const String::CharPointerType s)
1329 : source (s), allocatedBytes (StringHolder::getAllocatedNumBytes (s))
1330 {
1331 result.preallocateBytes (allocatedBytes);
1332 dest = result.getCharPointer();
1333 }
1334
1335 void write (juce_wchar c)
1336 {
1337 bytesWritten += String::CharPointerType::getBytesRequiredFor (c);
1338
1339 if (bytesWritten > allocatedBytes)
1340 {
1341 allocatedBytes += jmax ((size_t) 8, allocatedBytes / 16);
1342 auto destOffset = (size_t) (((char*) dest.getAddress()) - (char*) result.getCharPointer().getAddress());
1343 result.preallocateBytes (allocatedBytes);
1344 dest = addBytesToPointer (result.getCharPointer().getAddress(), (int) destOffset);
1345 }
1346
1347 dest.write (c);
1348 }
1349
1350 String result;
1351 String::CharPointerType source { nullptr }, dest { nullptr };
1352 size_t allocatedBytes, bytesWritten = 0;
1353};
1354
1355 String String::replaceCharacter (const juce_wchar charToReplace, const juce_wchar charToInsert) const
1356{
1357 if (! containsChar (charToReplace))
1358 return *this;
1359
1360 StringCreationHelper builder (text);
1361
1362 for (;;)
1363 {
1364 auto c = builder.source.getAndAdvance();
1365
1366 if (c == charToReplace)
1367 c = charToInsert;
1368
1369 builder.write (c);
1370
1371 if (c == 0)
1372 break;
1373 }
1374
1375 return std::move (builder.result);
1376}
1377
1378 String String::replaceCharacters (StringRef charactersToReplace, StringRef charactersToInsertInstead) const
1379{
1380 // Each character in the first string must have a matching one in the
1381 // second, so the two strings must be the same length.
1382 jassert (charactersToReplace.length() == charactersToInsertInstead.length());
1383
1384 StringCreationHelper builder (text);
1385
1386 for (;;)
1387 {
1388 auto c = builder.source.getAndAdvance();
1389 auto index = charactersToReplace.text.indexOf (c);
1390
1391 if (index >= 0)
1392 c = charactersToInsertInstead [index];
1393
1394 builder.write (c);
1395
1396 if (c == 0)
1397 break;
1398 }
1399
1400 return std::move (builder.result);
1401}
1402
1403//==============================================================================
1404 bool String::startsWith (StringRef other) const noexcept
1405{
1406 return text.compareUpTo (other.text, other.length()) == 0;
1407}
1408
1409 bool String::startsWithIgnoreCase (StringRef other) const noexcept
1410{
1411 return text.compareIgnoreCaseUpTo (other.text, other.length()) == 0;
1412}
1413
1414 bool String::startsWithChar (const juce_wchar character) const noexcept
1415{
1416 jassert (character != 0); // strings can't contain a null character!
1417
1418 return *text == character;
1419}
1420
1421 bool String::endsWithChar (const juce_wchar character) const noexcept
1422{
1423 jassert (character != 0); // strings can't contain a null character!
1424
1425 if (text.isEmpty())
1426 return false;
1427
1428 auto t = text.findTerminatingNull();
1429 return *--t == character;
1430}
1431
1432 bool String::endsWith (StringRef other) const noexcept
1433{
1434 auto end = text.findTerminatingNull();
1435 auto otherEnd = other.text.findTerminatingNull();
1436
1437 while (end > text && otherEnd > other.text)
1438 {
1439 --end;
1440 --otherEnd;
1441
1442 if (*end != *otherEnd)
1443 return false;
1444 }
1445
1446 return otherEnd == other.text;
1447}
1448
1449 bool String::endsWithIgnoreCase (StringRef other) const noexcept
1450{
1451 auto end = text.findTerminatingNull();
1452 auto otherEnd = other.text.findTerminatingNull();
1453
1454 while (end > text && otherEnd > other.text)
1455 {
1456 --end;
1457 --otherEnd;
1458
1459 if (end.toLowerCase() != otherEnd.toLowerCase())
1460 return false;
1461 }
1462
1463 return otherEnd == other.text;
1464}
1465
1466//==============================================================================
1467 String String::toUpperCase() const
1468{
1469 StringCreationHelper builder (text);
1470
1471 for (;;)
1472 {
1473 auto c = builder.source.toUpperCase();
1474 builder.write (c);
1475
1476 if (c == 0)
1477 break;
1478
1479 ++(builder.source);
1480 }
1481
1482 return std::move (builder.result);
1483}
1484
1485 String String::toLowerCase() const
1486{
1487 StringCreationHelper builder (text);
1488
1489 for (;;)
1490 {
1491 auto c = builder.source.toLowerCase();
1492 builder.write (c);
1493
1494 if (c == 0)
1495 break;
1496
1497 ++(builder.source);
1498 }
1499
1500 return std::move (builder.result);
1501}
1502
1503//==============================================================================
1504juce_wchar String::getLastCharacter() const noexcept
1505{
1506 return isEmpty() ? juce_wchar() : text [length() - 1];
1507}
1508
1509 String String::substring (int start, const int end) const
1510{
1511 if (start < 0)
1512 start = 0;
1513
1514 if (end <= start)
1515 return {};
1516
1517 int i = 0;
1518 auto t1 = text;
1519
1520 while (i < start)
1521 {
1522 if (t1.isEmpty())
1523 return {};
1524
1525 ++i;
1526 ++t1;
1527 }
1528
1529 auto t2 = t1;
1530
1531 while (i < end)
1532 {
1533 if (t2.isEmpty())
1534 {
1535 if (start == 0)
1536 return *this;
1537
1538 break;
1539 }
1540
1541 ++i;
1542 ++t2;
1543 }
1544
1545 return String (t1, t2);
1546}
1547
1548 String String::substring (int start) const
1549{
1550 if (start <= 0)
1551 return *this;
1552
1553 auto t = text;
1554
1555 while (--start >= 0)
1556 {
1557 if (t.isEmpty())
1558 return {};
1559
1560 ++t;
1561 }
1562
1563 return String (t);
1564}
1565
1566 String String::dropLastCharacters (const int numberToDrop) const
1567{
1568 return String (text, (size_t) jmax (0, length() - numberToDrop));
1569}
1570
1571 String String::getLastCharacters (const int numCharacters) const
1572{
1573 return String (text + jmax (0, length() - jmax (0, numCharacters)));
1574}
1575
1576 String String::fromFirstOccurrenceOf (StringRef sub, bool includeSubString, bool ignoreCase) const
1577{
1578 auto i = ignoreCase ? indexOfIgnoreCase (sub)
1579 : indexOf (sub);
1580 if (i < 0)
1581 return {};
1582
1583 return substring (includeSubString ? i : i + sub.length());
1584}
1585
1586 String String::fromLastOccurrenceOf (StringRef sub, bool includeSubString, bool ignoreCase) const
1587{
1588 auto i = ignoreCase ? lastIndexOfIgnoreCase (sub)
1589 : lastIndexOf (sub);
1590 if (i < 0)
1591 return *this;
1592
1593 return substring (includeSubString ? i : i + sub.length());
1594}
1595
1596 String String::upToFirstOccurrenceOf (StringRef sub, bool includeSubString, bool ignoreCase) const
1597{
1598 auto i = ignoreCase ? indexOfIgnoreCase (sub)
1599 : indexOf (sub);
1600 if (i < 0)
1601 return *this;
1602
1603 return substring (0, includeSubString ? i + sub.length() : i);
1604}
1605
1606 String String::upToLastOccurrenceOf (StringRef sub, bool includeSubString, bool ignoreCase) const
1607{
1608 auto i = ignoreCase ? lastIndexOfIgnoreCase (sub)
1609 : lastIndexOf (sub);
1610 if (i < 0)
1611 return *this;
1612
1613 return substring (0, includeSubString ? i + sub.length() : i);
1614}
1615
1616static bool isQuoteCharacter (juce_wchar c) noexcept
1617{
1618 return c == '"' || c == '\'';
1619}
1620
1621 bool String::isQuotedString() const
1622{
1623 return isQuoteCharacter (*text.findEndOfWhitespace());
1624}
1625
1626 String String::unquoted() const
1627{
1628 if (! isQuoteCharacter (*text))
1629 return *this;
1630
1631 auto len = length();
1632 return substring (1, len - (isQuoteCharacter (text[len - 1]) ? 1 : 0));
1633}
1634
1635 String String::quoted (juce_wchar quoteCharacter) const
1636{
1637 if (isEmpty())
1638 return charToString (quoteCharacter) + quoteCharacter;
1639
1640 String t (*this);
1641
1642 if (! t.startsWithChar (quoteCharacter))
1643 t = charToString (quoteCharacter) + t;
1644
1645 if (! t.endsWithChar (quoteCharacter))
1646 t += quoteCharacter;
1647
1648 return t;
1649}
1650
1651//==============================================================================
1652static String::CharPointerType findTrimmedEnd (const String::CharPointerType start,
1653 String::CharPointerType end)
1654{
1655 while (end > start)
1656 {
1657 if (! (--end).isWhitespace())
1658 {
1659 ++end;
1660 break;
1661 }
1662 }
1663
1664 return end;
1665}
1666
1667 String String::trim() const
1668{
1669 if (isNotEmpty())
1670 {
1671 auto start = text.findEndOfWhitespace();
1672 auto end = start.findTerminatingNull();
1673 auto trimmedEnd = findTrimmedEnd (start, end);
1674
1675 if (trimmedEnd <= start)
1676 return {};
1677
1678 if (text < start || trimmedEnd < end)
1679 return String (start, trimmedEnd);
1680 }
1681
1682 return *this;
1683}
1684
1685 String String::trimStart() const
1686{
1687 if (isNotEmpty())
1688 {
1689 auto t = text.findEndOfWhitespace();
1690
1691 if (t != text)
1692 return String (t);
1693 }
1694
1695 return *this;
1696}
1697
1698 String String::trimEnd() const
1699{
1700 if (isNotEmpty())
1701 {
1702 auto end = text.findTerminatingNull();
1703 auto trimmedEnd = findTrimmedEnd (text, end);
1704
1705 if (trimmedEnd < end)
1706 return String (text, trimmedEnd);
1707 }
1708
1709 return *this;
1710}
1711
1712 String String::trimCharactersAtStart (StringRef charactersToTrim) const
1713{
1714 auto t = text;
1715
1716 while (charactersToTrim.text.indexOf (*t) >= 0)
1717 ++t;
1718
1719 return t == text ? *this : String (t);
1720}
1721
1722 String String::trimCharactersAtEnd (StringRef charactersToTrim) const
1723{
1724 if (isNotEmpty())
1725 {
1726 auto end = text.findTerminatingNull();
1727 auto trimmedEnd = end;
1728
1729 while (trimmedEnd > text)
1730 {
1731 if (charactersToTrim.text.indexOf (*--trimmedEnd) < 0)
1732 {
1733 ++trimmedEnd;
1734 break;
1735 }
1736 }
1737
1738 if (trimmedEnd < end)
1739 return String (text, trimmedEnd);
1740 }
1741
1742 return *this;
1743}
1744
1745//==============================================================================
1746 String String::retainCharacters (StringRef charactersToRetain) const
1747{
1748 if (isEmpty())
1749 return {};
1750
1751 StringCreationHelper builder (text);
1752
1753 for (;;)
1754 {
1755 auto c = builder.source.getAndAdvance();
1756
1757 if (charactersToRetain.text.indexOf (c) >= 0)
1758 builder.write (c);
1759
1760 if (c == 0)
1761 break;
1762 }
1763
1764 builder.write (0);
1765 return std::move (builder.result);
1766}
1767
1768 String String::removeCharacters (StringRef charactersToRemove) const
1769{
1770 if (isEmpty())
1771 return {};
1772
1773 StringCreationHelper builder (text);
1774
1775 for (;;)
1776 {
1777 auto c = builder.source.getAndAdvance();
1778
1779 if (charactersToRemove.text.indexOf (c) < 0)
1780 builder.write (c);
1781
1782 if (c == 0)
1783 break;
1784 }
1785
1786 return std::move (builder.result);
1787}
1788
1789 String String::initialSectionContainingOnly (StringRef permittedCharacters) const
1790{
1791 for (auto t = text; ! t.isEmpty(); ++t)
1792 if (permittedCharacters.text.indexOf (*t) < 0)
1793 return String (text, t);
1794
1795 return *this;
1796}
1797
1798 String String::initialSectionNotContaining (StringRef charactersToStopAt) const
1799{
1800 for (auto t = text; ! t.isEmpty(); ++t)
1801 if (charactersToStopAt.text.indexOf (*t) >= 0)
1802 return String (text, t);
1803
1804 return *this;
1805}
1806
1807 bool String::containsOnly (StringRef chars) const noexcept
1808{
1809 for (auto t = text; ! t.isEmpty();)
1810 if (chars.text.indexOf (t.getAndAdvance()) < 0)
1811 return false;
1812
1813 return true;
1814}
1815
1816 bool String::containsAnyOf (StringRef chars) const noexcept
1817{
1818 for (auto t = text; ! t.isEmpty();)
1819 if (chars.text.indexOf (t.getAndAdvance()) >= 0)
1820 return true;
1821
1822 return false;
1823}
1824
1825 bool String::containsNonWhitespaceChars() const noexcept
1826{
1827 for (auto t = text; ! t.isEmpty(); ++t)
1828 if (! t.isWhitespace())
1829 return true;
1830
1831 return false;
1832}
1833
1834 String String::formattedRaw (const char* pf, ...)
1835{
1836 size_t bufferSize = 256;
1837
1838 for (;;)
1839 {
1840 va_list args;
1841 va_start (args, pf);
1842
1843 #if JUCE_ANDROID
1844 HeapBlock<char> temp (bufferSize);
1845 int num = (int) vsnprintf (temp.get(), bufferSize - 1, pf, args);
1846 if (num >= static_cast<int> (bufferSize))
1847 num = -1;
1848 #else
1849 String wideCharVersion (pf);
1850 HeapBlock<wchar_t> temp (bufferSize);
1851 const int num = (int)
1852 #if JUCE_WINDOWS
1853 _vsnwprintf
1854 #else
1855 vswprintf
1856 #endif
1857 (temp.get(), bufferSize - 1, wideCharVersion.toWideCharPointer(), args);
1858 #endif
1859 va_end (args);
1860
1861 if (num > 0)
1862 return String (temp.get());
1863
1864 bufferSize += 256;
1865
1866 if (num == 0 || bufferSize > 65536) // the upper limit is a sanity check to avoid situations where vprintf repeatedly
1867 break; // returns -1 because of an error rather than because it needs more space.
1868 }
1869
1870 return {};
1871}
1872
1873//==============================================================================
1874 int String::getIntValue() const noexcept { return text.getIntValue32(); }
1875int64 String::getLargeIntValue() const noexcept { return text.getIntValue64(); }
1876 float String::getFloatValue() const noexcept { return (float) getDoubleValue(); }
1877 double String::getDoubleValue() const noexcept { return text.getDoubleValue(); }
1878
1879 int String::getTrailingIntValue() const noexcept
1880{
1881 int n = 0;
1882 int mult = 1;
1883 auto t = text.findTerminatingNull();
1884
1885 while (--t >= text)
1886 {
1887 if (! t.isDigit())
1888 {
1889 if (*t == '-')
1890 n = -n;
1891
1892 break;
1893 }
1894
1895 n += static_cast<juce_wchar> (mult) * (*t - '0');
1896 mult *= 10;
1897 }
1898
1899 return n;
1900}
1901
1902static const char hexDigits[] = "0123456789abcdef";
1903
1904template <typename Type>
1905static String hexToString (Type v)
1906{
1907 String::CharPointerType::CharType buffer[32];
1908 auto* end = buffer + numElementsInArray (buffer) - 1;
1909 auto* t = end;
1910 *t = 0;
1911
1912 do
1913 {
1914 *--t = hexDigits [(int) (v & 15)];
1915 v >>= 4;
1916
1917 } while (v != 0);
1918
1919 return String (String::CharPointerType (t),
1920 String::CharPointerType (end));
1921}
1922
1923String String::createHex (uint8 n) { return hexToString (n); }
1924String String::createHex (uint16 n) { return hexToString (n); }
1925String String::createHex (uint32 n) { return hexToString (n); }
1926String String::createHex (uint64 n) { return hexToString (n); }
1927
1928 String String::toHexString (const void* const d, const int size, const int groupSize)
1929{
1930 if (size <= 0)
1931 return {};
1932
1933 int numChars = (size * 2) + 2;
1934 if (groupSize > 0)
1935 numChars += size / groupSize;
1936
1937 String s (PreallocationBytes ((size_t) numChars * sizeof (CharPointerType::CharType)));
1938
1939 auto* data = static_cast<const unsigned char*> (d);
1940 auto dest = s.text;
1941
1942 for (int i = 0; i < size; ++i)
1943 {
1944 const unsigned char nextByte = *data++;
1945 dest.write ((juce_wchar) hexDigits [nextByte >> 4]);
1946 dest.write ((juce_wchar) hexDigits [nextByte & 0xf]);
1947
1948 if (groupSize > 0 && (i % groupSize) == (groupSize - 1) && i < (size - 1))
1949 dest.write ((juce_wchar) ' ');
1950 }
1951
1952 dest.writeNull();
1953 return s;
1954}
1955
1956 int String::getHexValue32() const noexcept { return CharacterFunctions::HexParser<int> ::parse (text); }
1957int64 String::getHexValue64() const noexcept { return CharacterFunctions::HexParser<int64>::parse (text); }
1958
1959//==============================================================================
1960static String getStringFromWindows1252Codepage (const char* data, size_t num)
1961{
1962 HeapBlock<juce_wchar> unicode (num + 1);
1963
1964 for (size_t i = 0; i < num; ++i)
1965 unicode[i] = CharacterFunctions::getUnicodeCharFromWindows1252Codepage ((uint8) data[i]);
1966
1967 unicode[num] = 0;
1968 return CharPointer_UTF32 (unicode);
1969}
1970
1971 String String::createStringFromData (const void* const unknownData, int size)
1972{
1973 auto* data = static_cast<const uint8*> (unknownData);
1974
1975 if (size <= 0 || data == nullptr)
1976 return {};
1977
1978 if (size == 1)
1979 return charToString ((juce_wchar) data[0]);
1980
1981 if (CharPointer_UTF16::isByteOrderMarkBigEndian (data)
1982 || CharPointer_UTF16::isByteOrderMarkLittleEndian (data))
1983 {
1984 const int numChars = size / 2 - 1;
1985
1986 StringCreationHelper builder ((size_t) numChars);
1987
1988 auto src = reinterpret_cast<const uint16*> (data + 2);
1989
1990 if (CharPointer_UTF16::isByteOrderMarkBigEndian (data))
1991 {
1992 for (int i = 0; i < numChars; ++i)
1993 builder.write ((juce_wchar) ByteOrder::swapIfLittleEndian (src[i]));
1994 }
1995 else
1996 {
1997 for (int i = 0; i < numChars; ++i)
1998 builder.write ((juce_wchar) ByteOrder::swapIfBigEndian (src[i]));
1999 }
2000
2001 builder.write (0);
2002 return std::move (builder.result);
2003 }
2004
2005 auto* start = (const char*) data;
2006
2007 if (size >= 3 && CharPointer_UTF8::isByteOrderMark (data))
2008 {
2009 start += 3;
2010 size -= 3;
2011 }
2012
2013 if (CharPointer_UTF8::isValidString (start, size))
2014 return String (CharPointer_UTF8 (start),
2015 CharPointer_UTF8 (start + size));
2016
2017 return getStringFromWindows1252Codepage (start, (size_t) size);
2018}
2019
2020//==============================================================================
2021static const juce_wchar emptyChar = 0;
2022
2023template <class CharPointerType_Src, class CharPointerType_Dest>
2024struct StringEncodingConverter
2025{
2026 static CharPointerType_Dest convert (const String& s)
2027 {
2028 auto& source = const_cast<String&> (s);
2029
2030 using DestChar = typename CharPointerType_Dest::CharType;
2031
2032 if (source.isEmpty())
2033 return CharPointerType_Dest (reinterpret_cast<const DestChar*> (&emptyChar));
2034
2035 CharPointerType_Src text (source.getCharPointer());
2036 auto extraBytesNeeded = CharPointerType_Dest::getBytesRequiredFor (text) + sizeof (typename CharPointerType_Dest::CharType);
2037 auto endOffset = (text.sizeInBytes() + 3) & ~3u; // the new string must be word-aligned or many Windows
2038 // functions will fail to read it correctly!
2039 source.preallocateBytes (endOffset + extraBytesNeeded);
2040 text = source.getCharPointer();
2041
2042 void* const newSpace = addBytesToPointer (text.getAddress(), (int) endOffset);
2043 const CharPointerType_Dest extraSpace (static_cast<DestChar*> (newSpace));
2044
2045 #if JUCE_DEBUG // (This just avoids spurious warnings from valgrind about the uninitialised bytes at the end of the buffer..)
2046 auto bytesToClear = (size_t) jmin ((int) extraBytesNeeded, 4);
2047 zeromem (addBytesToPointer (newSpace, extraBytesNeeded - bytesToClear), bytesToClear);
2048 #endif
2049
2050 CharPointerType_Dest (extraSpace).writeAll (text);
2051 return extraSpace;
2052 }
2053};
2054
2055template <>
2056struct StringEncodingConverter<CharPointer_UTF8, CharPointer_UTF8>
2057{
2058 static CharPointer_UTF8 convert (const String& source) noexcept { return CharPointer_UTF8 (reinterpret_cast<CharPointer_UTF8::CharType*> (source.getCharPointer().getAddress())); }
2059};
2060
2061template <>
2062struct StringEncodingConverter<CharPointer_UTF16, CharPointer_UTF16>
2063{
2064 static CharPointer_UTF16 convert (const String& source) noexcept { return CharPointer_UTF16 (reinterpret_cast<CharPointer_UTF16::CharType*> (source.getCharPointer().getAddress())); }
2065};
2066
2067template <>
2068struct StringEncodingConverter<CharPointer_UTF32, CharPointer_UTF32>
2069{
2070 static CharPointer_UTF32 convert (const String& source) noexcept { return CharPointer_UTF32 (reinterpret_cast<CharPointer_UTF32::CharType*> (source.getCharPointer().getAddress())); }
2071};
2072
2073 CharPointer_UTF8 String::toUTF8() const { return StringEncodingConverter<CharPointerType, CharPointer_UTF8 >::convert (*this); }
2074 CharPointer_UTF16 String::toUTF16() const { return StringEncodingConverter<CharPointerType, CharPointer_UTF16>::convert (*this); }
2075 CharPointer_UTF32 String::toUTF32() const { return StringEncodingConverter<CharPointerType, CharPointer_UTF32>::convert (*this); }
2076
2077 const char* String::toRawUTF8() const
2078{
2079 return toUTF8().getAddress();
2080}
2081
2082 const wchar_t* String::toWideCharPointer() const
2083{
2084 return StringEncodingConverter<CharPointerType, CharPointer_wchar_t>::convert (*this).getAddress();
2085}
2086
2087std::string String::toStdString() const
2088{
2089 return std::string (toRawUTF8());
2090}
2091
2092//==============================================================================
2093template <class CharPointerType_Src, class CharPointerType_Dest>
2094struct StringCopier
2095{
2096 static size_t copyToBuffer (const CharPointerType_Src source, typename CharPointerType_Dest::CharType* const buffer, const size_t maxBufferSizeBytes)
2097 {
2098 jassert (((ssize_t) maxBufferSizeBytes) >= 0); // keep this value positive!
2099
2100 if (buffer == nullptr)
2101 return CharPointerType_Dest::getBytesRequiredFor (source) + sizeof (typename CharPointerType_Dest::CharType);
2102
2103 return CharPointerType_Dest (buffer).writeWithDestByteLimit (source, maxBufferSizeBytes);
2104 }
2105};
2106
2107 size_t String::copyToUTF8 (CharPointer_UTF8::CharType* const buffer, size_t maxBufferSizeBytes) const noexcept
2108{
2109 return StringCopier<CharPointerType, CharPointer_UTF8>::copyToBuffer (text, buffer, maxBufferSizeBytes);
2110}
2111
2112 size_t String::copyToUTF16 (CharPointer_UTF16::CharType* const buffer, size_t maxBufferSizeBytes) const noexcept
2113{
2114 return StringCopier<CharPointerType, CharPointer_UTF16>::copyToBuffer (text, buffer, maxBufferSizeBytes);
2115}
2116
2117 size_t String::copyToUTF32 (CharPointer_UTF32::CharType* const buffer, size_t maxBufferSizeBytes) const noexcept
2118{
2119 return StringCopier<CharPointerType, CharPointer_UTF32>::copyToBuffer (text, buffer, maxBufferSizeBytes);
2120}
2121
2122//==============================================================================
2123 size_t String::getNumBytesAsUTF8() const noexcept
2124{
2125 return CharPointer_UTF8::getBytesRequiredFor (text);
2126}
2127
2128 String String::fromUTF8 (const char* const buffer, int bufferSizeBytes)
2129{
2130 if (buffer != nullptr)
2131 {
2132 if (bufferSizeBytes < 0)
2133 return String (CharPointer_UTF8 (buffer));
2134
2135 if (bufferSizeBytes > 0)
2136 {
2137 jassert (CharPointer_UTF8::isValidString (buffer, bufferSizeBytes));
2138 return String (CharPointer_UTF8 (buffer), CharPointer_UTF8 (buffer + bufferSizeBytes));
2139 }
2140 }
2141
2142 return {};
2143}
2144
2145#if JUCE_MSVC
2146 #pragma warning (pop)
2147#endif
2148
2149//==============================================================================
2150StringRef::StringRef() noexcept : text ((const String::CharPointerType::CharType*) "\0\0\0")
2151{
2152}
2153
2154 StringRef::StringRef (const char* stringLiteral) noexcept
2155 #if JUCE_STRING_UTF_TYPE != 8
2156 : text (nullptr), stringCopy (stringLiteral)
2157 #else
2158 : text (stringLiteral)
2159 #endif
2160{
2161 #if JUCE_STRING_UTF_TYPE != 8
2162 text = stringCopy.getCharPointer();
2163 #endif
2164
2165 jassert (stringLiteral != nullptr); // This must be a valid string literal, not a null pointer!!
2166
2167 #if JUCE_NATIVE_WCHAR_IS_UTF8
2168 /* If you get an assertion here, then you're trying to create a string from 8-bit data
2169 that contains values greater than 127. These can NOT be correctly converted to unicode
2170 because there's no way for the String class to know what encoding was used to
2171 create them. The source data could be UTF-8, ASCII or one of many local code-pages.
2172
2173 To get around this problem, you must be more explicit when you pass an ambiguous 8-bit
2174 string to the StringRef class - so for example if your source data is actually UTF-8,
2175 you'd call StringRef (CharPointer_UTF8 ("my utf8 string..")), and it would be able to
2176 correctly convert the multi-byte characters to unicode. It's *highly* recommended that
2177 you use UTF-8 with escape characters in your source code to represent extended characters,
2178 because there's no other way to represent these strings in a way that isn't dependent on
2179 the compiler, source code editor and platform.
2180 */
2181 jassert (CharPointer_ASCII::isValidString (stringLiteral, std::numeric_limits<int>::max()));
2182 #endif
2183}
2184
2185 StringRef::StringRef (String::CharPointerType stringLiteral) noexcept : text (stringLiteral)
2186{
2187 jassert (stringLiteral.getAddress() != nullptr); // This must be a valid string literal, not a null pointer!!
2188}
2189
2190 StringRef::StringRef (const String& string) noexcept : text (string.getCharPointer()) {}
2191 StringRef::StringRef (const std::string& string) : StringRef (string.c_str()) {}
2192
2193//==============================================================================
2194
2195static String reduceLengthOfFloatString (const String& input)
2196{
2197 const auto start = input.getCharPointer();
2198 const auto end = start + (int) input.length();
2199 auto trimStart = end;
2200 auto trimEnd = trimStart;
2201 auto exponentTrimStart = end;
2202 auto exponentTrimEnd = exponentTrimStart;
2203
2204 decltype (*start) currentChar = '\0';
2205
2206 for (auto c = end - 1; c > start; --c)
2207 {
2208 currentChar = *c;
2209
2210 if (currentChar == '0' && c + 1 == trimStart)
2211 {
2212 --trimStart;
2213 }
2214 else if (currentChar == '.')
2215 {
2216 if (trimStart == c + 1 && trimStart != end && *trimStart == '0')
2217 ++trimStart;
2218
2219 break;
2220 }
2221 else if (currentChar == 'e' || currentChar == 'E')
2222 {
2223 auto cNext = c + 1;
2224
2225 if (cNext != end)
2226 {
2227 if (*cNext == '-')
2228 ++cNext;
2229
2230 exponentTrimStart = cNext;
2231
2232 if (cNext != end && *cNext == '+')
2233 ++cNext;
2234
2235 exponentTrimEnd = cNext;
2236 }
2237
2238 while (cNext != end && *cNext++ == '0')
2239 exponentTrimEnd = cNext;
2240
2241 if (exponentTrimEnd == end)
2242 exponentTrimStart = c;
2243
2244 trimStart = c;
2245 trimEnd = trimStart;
2246 }
2247 }
2248
2249 if ((trimStart != trimEnd && currentChar == '.') || exponentTrimStart != exponentTrimEnd)
2250 {
2251 if (trimStart == trimEnd)
2252 return String (start, exponentTrimStart) + String (exponentTrimEnd, end);
2253
2254 if (exponentTrimStart == exponentTrimEnd)
2255 return String (start, trimStart) + String (trimEnd, end);
2256
2257 if (trimEnd == exponentTrimStart)
2258 return String (start, trimStart) + String (exponentTrimEnd, end);
2259
2260 return String (start, trimStart) + String (trimEnd, exponentTrimStart) + String (exponentTrimEnd, end);
2261 }
2262
2263 return input;
2264}
2265
2266static String serialiseDouble (double input)
2267{
2268 auto absInput = std::abs (input);
2269
2270 if (absInput >= 1.0e6 || absInput <= 1.0e-5)
2271 return reduceLengthOfFloatString ({ input, 15, true });
2272
2273 int intInput = (int) input;
2274
2275 if ((double) intInput == input)
2276 return { input, 1 };
2277
2278 auto numberOfDecimalPlaces = [absInput]
2279 {
2280 if (absInput < 1.0)
2281 {
2282 if (absInput >= 1.0e-3)
2283 {
2284 if (absInput >= 1.0e-1) return 16;
2285 if (absInput >= 1.0e-2) return 17;
2286 return 18;
2287 }
2288
2289 if (absInput >= 1.0e-4) return 19;
2290 return 20;
2291 }
2292
2293 if (absInput < 1.0e3)
2294 {
2295 if (absInput < 1.0e1) return 15;
2296 if (absInput < 1.0e2) return 14;
2297 return 13;
2298 }
2299
2300 if (absInput < 1.0e4) return 12;
2301 if (absInput < 1.0e5) return 11;
2302 return 10;
2303 }();
2304
2305 return reduceLengthOfFloatString (String (input, numberOfDecimalPlaces));
2306}
2307
2308
2309//==============================================================================
2310//==============================================================================
2311#if JUCE_UNIT_TESTS
2312
2313#define STRINGIFY2(X) #X
2314#define STRINGIFY(X) STRINGIFY2(X)
2315
2316class StringTests : public UnitTest
2317{
2318public:
2319 StringTests()
2320 : UnitTest ("String class", UnitTestCategories::text)
2321 {}
2322
2323 template <class CharPointerType>
2324 struct TestUTFConversion
2325 {
2326 static void test (UnitTest& test, Random& r)
2327 {
2328 String s (createRandomWideCharString (r));
2329
2330 typename CharPointerType::CharType buffer [300];
2331
2332 memset (buffer, 0xff, sizeof (buffer));
2333 CharPointerType (buffer).writeAll (s.toUTF32());
2334 test.expectEquals (String (CharPointerType (buffer)), s);
2335
2336 memset (buffer, 0xff, sizeof (buffer));
2337 CharPointerType (buffer).writeAll (s.toUTF16());
2338 test.expectEquals (String (CharPointerType (buffer)), s);
2339
2340 memset (buffer, 0xff, sizeof (buffer));
2341 CharPointerType (buffer).writeAll (s.toUTF8());
2342 test.expectEquals (String (CharPointerType (buffer)), s);
2343
2344 test.expect (CharPointerType::isValidString (buffer, (int) strlen ((const char*) buffer)));
2345 }
2346 };
2347
2348 static String createRandomWideCharString (Random& r)
2349 {
2350 juce_wchar buffer[50] = { 0 };
2351
2352 for (int i = 0; i < numElementsInArray (buffer) - 1; ++i)
2353 {
2354 if (r.nextBool())
2355 {
2356 do
2357 {
2358 buffer[i] = (juce_wchar) (1 + r.nextInt (0x10ffff - 1));
2359 }
2360 while (! CharPointer_UTF16::canRepresent (buffer[i]));
2361 }
2362 else
2363 buffer[i] = (juce_wchar) (1 + r.nextInt (0xff));
2364 }
2365
2366 return CharPointer_UTF32 (buffer);
2367 }
2368
2369 void runTest() override
2370 {
2371 Random r = getRandom();
2372
2373 {
2374 beginTest ("Basics");
2375
2376 expect (String().length() == 0);
2377 expect (String() == String());
2378 String s1, s2 ("abcd");
2379 expect (s1.isEmpty() && ! s1.isNotEmpty());
2380 expect (s2.isNotEmpty() && ! s2.isEmpty());
2381 expect (s2.length() == 4);
2382 s1 = "abcd";
2383 expect (s2 == s1 && s1 == s2);
2384 expect (s1 == "abcd" && s1 == L"abcd");
2385 expect (String ("abcd") == String (L"abcd"));
2386 expect (String ("abcdefg", 4) == L"abcd");
2387 expect (String ("abcdefg", 4) == String (L"abcdefg", 4));
2388 expect (String::charToString ('x') == "x");
2389 expect (String::charToString (0) == String());
2390 expect (s2 + "e" == "abcde" && s2 + 'e' == "abcde");
2391 expect (s2 + L'e' == "abcde" && s2 + L"e" == "abcde");
2392 expect (s1.equalsIgnoreCase ("abcD") && s1 < "abce" && s1 > "abbb");
2393 expect (s1.startsWith ("ab") && s1.startsWith ("abcd") && ! s1.startsWith ("abcde"));
2394 expect (s1.startsWithIgnoreCase ("aB") && s1.endsWithIgnoreCase ("CD"));
2395 expect (s1.endsWith ("bcd") && ! s1.endsWith ("aabcd"));
2396 expectEquals (s1.indexOf (String()), 0);
2397 expectEquals (s1.indexOfIgnoreCase (String()), 0);
2398 expect (s1.startsWith (String()) && s1.endsWith (String()) && s1.contains (String()));
2399 expect (s1.contains ("cd") && s1.contains ("ab") && s1.contains ("abcd"));
2400 expect (s1.containsChar ('a'));
2401 expect (! s1.containsChar ('x'));
2402 expect (! s1.containsChar (0));
2403 expect (String ("abc foo bar").containsWholeWord ("abc") && String ("abc foo bar").containsWholeWord ("abc"));
2404 }
2405
2406 {
2407 beginTest ("Operations");
2408
2409 String s ("012345678");
2410 expect (s.hashCode() != 0);
2411 expect (s.hashCode64() != 0);
2412 expect (s.hashCode() != (s + s).hashCode());
2413 expect (s.hashCode64() != (s + s).hashCode64());
2414 expect (s.compare (String ("012345678")) == 0);
2415 expect (s.compare (String ("012345679")) < 0);
2416 expect (s.compare (String ("012345676")) > 0);
2417 expect (String("a").compareNatural ("A") == 0);
2418 expect (String("A").compareNatural ("B") < 0);
2419 expect (String("a").compareNatural ("B") < 0);
2420 expect (String("10").compareNatural ("2") > 0);
2421 expect (String("Abc 10").compareNatural ("aBC 2") > 0);
2422 expect (String("Abc 1").compareNatural ("aBC 2") < 0);
2423 expect (s.substring (2, 3) == String::charToString (s[2]));
2424 expect (s.substring (0, 1) == String::charToString (s[0]));
2425 expect (s.getLastCharacter() == s [s.length() - 1]);
2426 expect (String::charToString (s.getLastCharacter()) == s.getLastCharacters (1));
2427 expect (s.substring (0, 3) == L"012");
2428 expect (s.substring (0, 100) == s);
2429 expect (s.substring (-1, 100) == s);
2430 expect (s.substring (3) == "345678");
2431 expect (s.indexOf (String (L"45")) == 4);
2432 expect (String ("444445").indexOf ("45") == 4);
2433 expect (String ("444445").lastIndexOfChar ('4') == 4);
2434 expect (String ("45454545x").lastIndexOf (String (L"45")) == 6);
2435 expect (String ("45454545x").lastIndexOfAnyOf ("456") == 7);
2436 expect (String ("45454545x").lastIndexOfAnyOf (String (L"456x")) == 8);
2437 expect (String ("abABaBaBa").lastIndexOfIgnoreCase ("aB") == 6);
2438 expect (s.indexOfChar (L'4') == 4);
2439 expect (s + s == "012345678012345678");
2440 expect (s.startsWith (s));
2441 expect (s.startsWith (s.substring (0, 4)));
2442 expect (s.startsWith (s.dropLastCharacters (4)));
2443 expect (s.endsWith (s.substring (5)));
2444 expect (s.endsWith (s));
2445 expect (s.contains (s.substring (3, 6)));
2446 expect (s.contains (s.substring (3)));
2447 expect (s.startsWithChar (s[0]));
2448 expect (s.endsWithChar (s.getLastCharacter()));
2449 expect (s [s.length()] == 0);
2450 expect (String ("abcdEFGH").toLowerCase() == String ("abcdefgh"));
2451 expect (String ("abcdEFGH").toUpperCase() == String ("ABCDEFGH"));
2452
2453 expect (String (StringRef ("abc")) == "abc");
2454 expect (String (StringRef ("abc")) == StringRef ("abc"));
2455 expect (String ("abc") + StringRef ("def") == "abcdef");
2456
2457 String s2 ("123");
2458 s2 << ((int) 4) << ((short) 5) << "678" << L"9" << '0';
2459 s2 += "xyz";
2460 expect (s2 == "1234567890xyz");
2461 s2 += (int) 123;
2462 expect (s2 == "1234567890xyz123");
2463 s2 += (int64) 123;
2464 expect (s2 == "1234567890xyz123123");
2465 s2 << StringRef ("def");
2466 expect (s2 == "1234567890xyz123123def");
2467
2468 // int16
2469 {
2470 String numStr (std::numeric_limits<int16>::max());
2471 expect (numStr == "32767");
2472 }
2473 {
2474 String numStr (std::numeric_limits<int16>::min());
2475 expect (numStr == "-32768");
2476 }
2477 {
2478 String numStr;
2479 numStr << std::numeric_limits<int16>::max();
2480 expect (numStr == "32767");
2481 }
2482 {
2483 String numStr;
2484 numStr << std::numeric_limits<int16>::min();
2485 expect (numStr == "-32768");
2486 }
2487 // int32
2488 {
2489 String numStr (std::numeric_limits<int32>::max());
2490 expect (numStr == "2147483647");
2491 }
2492 {
2493 String numStr (std::numeric_limits<int32>::min());
2494 expect (numStr == "-2147483648");
2495 }
2496 {
2497 String numStr;
2498 numStr << std::numeric_limits<int32>::max();
2499 expect (numStr == "2147483647");
2500 }
2501 {
2502 String numStr;
2503 numStr << std::numeric_limits<int32>::min();
2504 expect (numStr == "-2147483648");
2505 }
2506 // uint32
2507 {
2508 String numStr (std::numeric_limits<uint32>::max());
2509 expect (numStr == "4294967295");
2510 }
2511 {
2512 String numStr (std::numeric_limits<uint32>::min());
2513 expect (numStr == "0");
2514 }
2515 // int64
2516 {
2517 String numStr (std::numeric_limits<int64>::max());
2518 expect (numStr == "9223372036854775807");
2519 }
2520 {
2521 String numStr (std::numeric_limits<int64>::min());
2522 expect (numStr == "-9223372036854775808");
2523 }
2524 {
2525 String numStr;
2526 numStr << std::numeric_limits<int64>::max();
2527 expect (numStr == "9223372036854775807");
2528 }
2529 {
2530 String numStr;
2531 numStr << std::numeric_limits<int64>::min();
2532 expect (numStr == "-9223372036854775808");
2533 }
2534 // uint64
2535 {
2536 String numStr (std::numeric_limits<uint64>::max());
2537 expect (numStr == "18446744073709551615");
2538 }
2539 {
2540 String numStr (std::numeric_limits<uint64>::min());
2541 expect (numStr == "0");
2542 }
2543 {
2544 String numStr;
2545 numStr << std::numeric_limits<uint64>::max();
2546 expect (numStr == "18446744073709551615");
2547 }
2548 {
2549 String numStr;
2550 numStr << std::numeric_limits<uint64>::min();
2551 expect (numStr == "0");
2552 }
2553 // size_t
2554 {
2555 String numStr (std::numeric_limits<size_t>::min());
2556 expect (numStr == "0");
2557 }
2558
2559 beginTest ("Numeric conversions");
2560 expect (String().getIntValue() == 0);
2561 expect (String().getDoubleValue() == 0.0);
2562 expect (String().getFloatValue() == 0.0f);
2563 expect (s.getIntValue() == 12345678);
2564 expect (s.getLargeIntValue() == (int64) 12345678);
2565 expect (s.getDoubleValue() == 12345678.0);
2566 expect (s.getFloatValue() == 12345678.0f);
2567 expect (String (-1234).getIntValue() == -1234);
2568 expect (String ((int64) -1234).getLargeIntValue() == -1234);
2569 expect (String (-1234.56).getDoubleValue() == -1234.56);
2570 expect (String (-1234.56f).getFloatValue() == -1234.56f);
2571 expect (String (std::numeric_limits<int>::max()).getIntValue() == std::numeric_limits<int>::max());
2572 expect (String (std::numeric_limits<int>::min()).getIntValue() == std::numeric_limits<int>::min());
2573 expect (String (std::numeric_limits<int64>::max()).getLargeIntValue() == std::numeric_limits<int64>::max());
2574 expect (String (std::numeric_limits<int64>::min()).getLargeIntValue() == std::numeric_limits<int64>::min());
2575 expect (("xyz" + s).getTrailingIntValue() == s.getIntValue());
2576 expect (s.getHexValue32() == 0x12345678);
2577 expect (s.getHexValue64() == (int64) 0x12345678);
2578 expect (String::toHexString (0x1234abcd).equalsIgnoreCase ("1234abcd"));
2579 expect (String::toHexString ((int64) 0x1234abcd).equalsIgnoreCase ("1234abcd"));
2580 expect (String::toHexString ((short) 0x12ab).equalsIgnoreCase ("12ab"));
2581 expect (String::toHexString ((size_t) 0x12ab).equalsIgnoreCase ("12ab"));
2582 expect (String::toHexString ((long) 0x12ab).equalsIgnoreCase ("12ab"));
2583 expect (String::toHexString ((int8) -1).equalsIgnoreCase ("ff"));
2584 expect (String::toHexString ((int16) -1).equalsIgnoreCase ("ffff"));
2585 expect (String::toHexString ((int32) -1).equalsIgnoreCase ("ffffffff"));
2586 expect (String::toHexString ((int64) -1).equalsIgnoreCase ("ffffffffffffffff"));
2587
2588 unsigned char data[] = { 1, 2, 3, 4, 0xa, 0xb, 0xc, 0xd };
2589 expect (String::toHexString (data, 8, 0).equalsIgnoreCase ("010203040a0b0c0d"));
2590 expect (String::toHexString (data, 8, 1).equalsIgnoreCase ("01 02 03 04 0a 0b 0c 0d"));
2591 expect (String::toHexString (data, 8, 2).equalsIgnoreCase ("0102 0304 0a0b 0c0d"));
2592
2593 expectEquals (String (12345.67, 4), String ("12345.6700"));
2594 expectEquals (String (12345.67, 6), String ("12345.670000"));
2595 expectEquals (String (2589410.5894, 7), String ("2589410.5894000"));
2596 expectEquals (String (12345.67, 8), String ("12345.67000000"));
2597 expectEquals (String (1e19, 4), String ("10000000000000000000.0000"));
2598 expectEquals (String (1e-34, 36), String ("0.000000000000000000000000000000000100"));
2599 expectEquals (String (1.39, 1), String ("1.4"));
2600
2601 expectEquals (String (12345.67, 4, true), String ("1.2346e+04"));
2602 expectEquals (String (12345.67, 6, true), String ("1.234567e+04"));
2603 expectEquals (String (2589410.5894, 7, true), String ("2.5894106e+06"));
2604 expectEquals (String (12345.67, 8, true), String ("1.23456700e+04"));
2605 expectEquals (String (1e19, 4, true), String ("1.0000e+19"));
2606 expectEquals (String (1e-34, 5, true), String ("1.00000e-34"));
2607 expectEquals (String (1.39, 1, true), String ("1.4e+00"));
2608
2609 beginTest ("Subsections");
2610 String s3;
2611 s3 = "abcdeFGHIJ";
2612 expect (s3.equalsIgnoreCase ("ABCdeFGhiJ"));
2613 expect (s3.compareIgnoreCase (L"ABCdeFGhiJ") == 0);
2614 expect (s3.containsIgnoreCase (s3.substring (3)));
2615 expect (s3.indexOfAnyOf ("xyzf", 2, true) == 5);
2616 expect (s3.indexOfAnyOf (String (L"xyzf"), 2, false) == -1);
2617 expect (s3.indexOfAnyOf ("xyzF", 2, false) == 5);
2618 expect (s3.containsAnyOf (String (L"zzzFs")));
2619 expect (s3.startsWith ("abcd"));
2620 expect (s3.startsWithIgnoreCase (String (L"abCD")));
2621 expect (s3.startsWith (String()));
2622 expect (s3.startsWithChar ('a'));
2623 expect (s3.endsWith (String ("HIJ")));
2624 expect (s3.endsWithIgnoreCase (String (L"Hij")));
2625 expect (s3.endsWith (String()));
2626 expect (s3.endsWithChar (L'J'));
2627 expect (s3.indexOf ("HIJ") == 7);
2628 expect (s3.indexOf (String (L"HIJK")) == -1);
2629 expect (s3.indexOfIgnoreCase ("hij") == 7);
2630 expect (s3.indexOfIgnoreCase (String (L"hijk")) == -1);
2631 expect (s3.toStdString() == s3.toRawUTF8());
2632
2633 String s4 (s3);
2634 s4.append (String ("xyz123"), 3);
2635 expect (s4 == s3 + "xyz");
2636
2637 expect (String (1234) < String (1235));
2638 expect (String (1235) > String (1234));
2639 expect (String (1234) >= String (1234));
2640 expect (String (1234) <= String (1234));
2641 expect (String (1235) >= String (1234));
2642 expect (String (1234) <= String (1235));
2643
2644 String s5 ("word word2 word3");
2645 expect (s5.containsWholeWord (String ("word2")));
2646 expect (s5.indexOfWholeWord ("word2") == 5);
2647 expect (s5.containsWholeWord (String (L"word")));
2648 expect (s5.containsWholeWord ("word3"));
2649 expect (s5.containsWholeWord (s5));
2650 expect (s5.containsWholeWordIgnoreCase (String (L"Word2")));
2651 expect (s5.indexOfWholeWordIgnoreCase ("Word2") == 5);
2652 expect (s5.containsWholeWordIgnoreCase (String (L"Word")));
2653 expect (s5.containsWholeWordIgnoreCase ("Word3"));
2654 expect (! s5.containsWholeWordIgnoreCase (String (L"Wordx")));
2655 expect (! s5.containsWholeWordIgnoreCase ("xWord2"));
2656 expect (s5.containsNonWhitespaceChars());
2657 expect (s5.containsOnly ("ordw23 "));
2658 expect (! String (" \n\r\t").containsNonWhitespaceChars());
2659
2660 expect (s5.matchesWildcard (String (L"wor*"), false));
2661 expect (s5.matchesWildcard ("wOr*", true));
2662 expect (s5.matchesWildcard (String (L"*word3"), true));
2663 expect (s5.matchesWildcard ("*word?", true));
2664 expect (s5.matchesWildcard (String (L"Word*3"), true));
2665 expect (! s5.matchesWildcard (String (L"*34"), true));
2666 expect (String ("xx**y").matchesWildcard ("*y", true));
2667 expect (String ("xx**y").matchesWildcard ("x*y", true));
2668 expect (String ("xx**y").matchesWildcard ("xx*y", true));
2669 expect (String ("xx**y").matchesWildcard ("xx*", true));
2670 expect (String ("xx?y").matchesWildcard ("x??y", true));
2671 expect (String ("xx?y").matchesWildcard ("xx?y", true));
2672 expect (! String ("xx?y").matchesWildcard ("xx?y?", true));
2673 expect (String ("xx?y").matchesWildcard ("xx??", true));
2674
2675 expectEquals (s5.fromFirstOccurrenceOf (String(), true, false), s5);
2676 expectEquals (s5.fromFirstOccurrenceOf ("xword2", true, false), s5.substring (100));
2677 expectEquals (s5.fromFirstOccurrenceOf (String (L"word2"), true, false), s5.substring (5));
2678 expectEquals (s5.fromFirstOccurrenceOf ("Word2", true, true), s5.substring (5));
2679 expectEquals (s5.fromFirstOccurrenceOf ("word2", false, false), s5.getLastCharacters (6));
2680 expectEquals (s5.fromFirstOccurrenceOf ("Word2", false, true), s5.getLastCharacters (6));
2681
2682 expectEquals (s5.fromLastOccurrenceOf (String(), true, false), s5);
2683 expectEquals (s5.fromLastOccurrenceOf ("wordx", true, false), s5);
2684 expectEquals (s5.fromLastOccurrenceOf ("word", true, false), s5.getLastCharacters (5));
2685 expectEquals (s5.fromLastOccurrenceOf ("worD", true, true), s5.getLastCharacters (5));
2686 expectEquals (s5.fromLastOccurrenceOf ("word", false, false), s5.getLastCharacters (1));
2687 expectEquals (s5.fromLastOccurrenceOf ("worD", false, true), s5.getLastCharacters (1));
2688
2689 expect (s5.upToFirstOccurrenceOf (String(), true, false).isEmpty());
2690 expectEquals (s5.upToFirstOccurrenceOf ("word4", true, false), s5);
2691 expectEquals (s5.upToFirstOccurrenceOf ("word2", true, false), s5.substring (0, 10));
2692 expectEquals (s5.upToFirstOccurrenceOf ("Word2", true, true), s5.substring (0, 10));
2693 expectEquals (s5.upToFirstOccurrenceOf ("word2", false, false), s5.substring (0, 5));
2694 expectEquals (s5.upToFirstOccurrenceOf ("Word2", false, true), s5.substring (0, 5));
2695
2696 expectEquals (s5.upToLastOccurrenceOf (String(), true, false), s5);
2697 expectEquals (s5.upToLastOccurrenceOf ("zword", true, false), s5);
2698 expectEquals (s5.upToLastOccurrenceOf ("word", true, false), s5.dropLastCharacters (1));
2699 expectEquals (s5.dropLastCharacters(1).upToLastOccurrenceOf ("word", true, false), s5.dropLastCharacters (1));
2700 expectEquals (s5.upToLastOccurrenceOf ("Word", true, true), s5.dropLastCharacters (1));
2701 expectEquals (s5.upToLastOccurrenceOf ("word", false, false), s5.dropLastCharacters (5));
2702 expectEquals (s5.upToLastOccurrenceOf ("Word", false, true), s5.dropLastCharacters (5));
2703
2704 expectEquals (s5.replace ("word", "xyz", false), String ("xyz xyz2 xyz3"));
2705 expect (s5.replace ("Word", "xyz", true) == "xyz xyz2 xyz3");
2706 expect (s5.dropLastCharacters (1).replace ("Word", String ("xyz"), true) == L"xyz xyz2 xyz");
2707 expect (s5.replace ("Word", "", true) == " 2 3");
2708 expectEquals (s5.replace ("Word2", "xyz", true), String ("word xyz word3"));
2709 expect (s5.replaceCharacter (L'w', 'x') != s5);
2710 expectEquals (s5.replaceCharacter ('w', L'x').replaceCharacter ('x', 'w'), s5);
2711 expect (s5.replaceCharacters ("wo", "xy") != s5);
2712 expectEquals (s5.replaceCharacters ("wo", "xy").replaceCharacters ("xy", "wo"), s5);
2713 expectEquals (s5.retainCharacters ("1wordxya"), String ("wordwordword"));
2714 expect (s5.retainCharacters (String()).isEmpty());
2715 expect (s5.removeCharacters ("1wordxya") == " 2 3");
2716 expectEquals (s5.removeCharacters (String()), s5);
2717 expect (s5.initialSectionContainingOnly ("word") == L"word");
2718 expect (String ("word").initialSectionContainingOnly ("word") == L"word");
2719 expectEquals (s5.initialSectionNotContaining (String ("xyz ")), String ("word"));
2720 expectEquals (s5.initialSectionNotContaining (String (";[:'/")), s5);
2721 expect (! s5.isQuotedString());
2722 expect (s5.quoted().isQuotedString());
2723 expect (! s5.quoted().unquoted().isQuotedString());
2724 expect (! String ("x'").isQuotedString());
2725 expect (String ("'x").isQuotedString());
2726
2727 String s6 (" \t xyz \t\r\n");
2728 expectEquals (s6.trim(), String ("xyz"));
2729 expect (s6.trim().trim() == "xyz");
2730 expectEquals (s5.trim(), s5);
2731 expectEquals (s6.trimStart().trimEnd(), s6.trim());
2732 expectEquals (s6.trimStart().trimEnd(), s6.trimEnd().trimStart());
2733 expectEquals (s6.trimStart().trimStart().trimEnd().trimEnd(), s6.trimEnd().trimStart());
2734 expect (s6.trimStart() != s6.trimEnd());
2735 expectEquals (("\t\r\n " + s6 + "\t\n \r").trim(), s6.trim());
2736 expect (String::repeatedString ("xyz", 3) == L"xyzxyzxyz");
2737 }
2738
2739 {
2740 beginTest ("UTF conversions");
2741
2742 TestUTFConversion <CharPointer_UTF32>::test (*this, r);
2743 TestUTFConversion <CharPointer_UTF8>::test (*this, r);
2744 TestUTFConversion <CharPointer_UTF16>::test (*this, r);
2745 }
2746
2747 {
2748 beginTest ("StringArray");
2749
2750 StringArray s;
2751 s.addTokens ("4,3,2,1,0", ";,", "x");
2752 expectEquals (s.size(), 5);
2753
2754 expectEquals (s.joinIntoString ("-"), String ("4-3-2-1-0"));
2755 s.remove (2);
2756 expectEquals (s.joinIntoString ("--"), String ("4--3--1--0"));
2757 expectEquals (s.joinIntoString (StringRef()), String ("4310"));
2758 s.clear();
2759 expectEquals (s.joinIntoString ("x"), String());
2760
2761 StringArray toks;
2762 toks.addTokens ("x,,", ";,", "");
2763 expectEquals (toks.size(), 3);
2764 expectEquals (toks.joinIntoString ("-"), String ("x--"));
2765 toks.clear();
2766
2767 toks.addTokens (",x,", ";,", "");
2768 expectEquals (toks.size(), 3);
2769 expectEquals (toks.joinIntoString ("-"), String ("-x-"));
2770 toks.clear();
2771
2772 toks.addTokens ("x,'y,z',", ";,", "'");
2773 expectEquals (toks.size(), 3);
2774 expectEquals (toks.joinIntoString ("-"), String ("x-'y,z'-"));
2775 }
2776
2777 {
2778 beginTest ("var");
2779
2780 var v1 = 0;
2781 var v2 = 0.16;
2782 var v3 = "0.16";
2783 var v4 = (int64) 0;
2784 var v5 = 0.0;
2785 expect (! v2.equals (v1));
2786 expect (! v1.equals (v2));
2787 expect (v2.equals (v3));
2788 expect (! v3.equals (v1));
2789 expect (! v1.equals (v3));
2790 expect (v1.equals (v4));
2791 expect (v4.equals (v1));
2792 expect (v5.equals (v4));
2793 expect (v4.equals (v5));
2794 expect (! v2.equals (v4));
2795 expect (! v4.equals (v2));
2796 }
2797
2798 {
2799 beginTest ("Significant figures");
2800
2801 // Integers
2802
2803 expectEquals (String::toDecimalStringWithSignificantFigures (13, 1), String ("10"));
2804 expectEquals (String::toDecimalStringWithSignificantFigures (13, 2), String ("13"));
2805 expectEquals (String::toDecimalStringWithSignificantFigures (13, 3), String ("13.0"));
2806 expectEquals (String::toDecimalStringWithSignificantFigures (13, 4), String ("13.00"));
2807
2808 expectEquals (String::toDecimalStringWithSignificantFigures (19368, 1), String ("20000"));
2809 expectEquals (String::toDecimalStringWithSignificantFigures (19348, 3), String ("19300"));
2810
2811 expectEquals (String::toDecimalStringWithSignificantFigures (-5, 1), String ("-5"));
2812 expectEquals (String::toDecimalStringWithSignificantFigures (-5, 3), String ("-5.00"));
2813
2814 // Zero
2815
2816 expectEquals (String::toDecimalStringWithSignificantFigures (0, 1), String ("0"));
2817 expectEquals (String::toDecimalStringWithSignificantFigures (0, 2), String ("0.0"));
2818 expectEquals (String::toDecimalStringWithSignificantFigures (0, 3), String ("0.00"));
2819
2820 // Floating point
2821
2822 expectEquals (String::toDecimalStringWithSignificantFigures (19.0, 1), String ("20"));
2823 expectEquals (String::toDecimalStringWithSignificantFigures (19.0, 2), String ("19"));
2824 expectEquals (String::toDecimalStringWithSignificantFigures (19.0, 3), String ("19.0"));
2825 expectEquals (String::toDecimalStringWithSignificantFigures (19.0, 4), String ("19.00"));
2826
2827 expectEquals (String::toDecimalStringWithSignificantFigures (-5.45, 1), String ("-5"));
2828 expectEquals (String::toDecimalStringWithSignificantFigures (-5.45, 3), String ("-5.45"));
2829
2830 expectEquals (String::toDecimalStringWithSignificantFigures (12345.6789, 9), String ("12345.6789"));
2831 expectEquals (String::toDecimalStringWithSignificantFigures (12345.6789, 8), String ("12345.679"));
2832 expectEquals (String::toDecimalStringWithSignificantFigures (12345.6789, 5), String ("12346"));
2833
2834 expectEquals (String::toDecimalStringWithSignificantFigures (0.00028647, 6), String ("0.000286470"));
2835 expectEquals (String::toDecimalStringWithSignificantFigures (0.0028647, 6), String ("0.00286470"));
2836 expectEquals (String::toDecimalStringWithSignificantFigures (2.8647, 6), String ("2.86470"));
2837
2838 expectEquals (String::toDecimalStringWithSignificantFigures (-0.0000000000019, 1), String ("-0.000000000002"));
2839 }
2840
2841 {
2842 beginTest ("Float trimming");
2843
2844 {
2845 StringPairArray tests;
2846 tests.set ("1", "1");
2847 tests.set ("1.0", "1.0");
2848 tests.set ("-1", "-1");
2849 tests.set ("-100", "-100");
2850 tests.set ("110", "110");
2851 tests.set ("9090", "9090");
2852 tests.set ("1000.0", "1000.0");
2853 tests.set ("1.0", "1.0");
2854 tests.set ("-1.00", "-1.0");
2855 tests.set ("1.20", "1.2");
2856 tests.set ("1.300", "1.3");
2857 tests.set ("1.301", "1.301");
2858 tests.set ("1e", "1");
2859 tests.set ("-1e+", "-1");
2860 tests.set ("1e-", "1");
2861 tests.set ("1e0", "1");
2862 tests.set ("1e+0", "1");
2863 tests.set ("1e-0", "1");
2864 tests.set ("1e000", "1");
2865 tests.set ("1e+000", "1");
2866 tests.set ("-1e-000", "-1");
2867 tests.set ("1e100", "1e100");
2868 tests.set ("100e100", "100e100");
2869 tests.set ("100.0e0100", "100.0e100");
2870 tests.set ("-1e1", "-1e1");
2871 tests.set ("1e10", "1e10");
2872 tests.set ("-1e+10", "-1e10");
2873 tests.set ("1e-10", "1e-10");
2874 tests.set ("1e0010", "1e10");
2875 tests.set ("1e-0010", "1e-10");
2876 tests.set ("1e-1", "1e-1");
2877 tests.set ("-1.0e1", "-1.0e1");
2878 tests.set ("1.0e-1", "1.0e-1");
2879 tests.set ("1.00e-1", "1.0e-1");
2880 tests.set ("1.001e1", "1.001e1");
2881 tests.set ("1.010e+1", "1.01e1");
2882 tests.set ("-1.1000e1", "-1.1e1");
2883
2884 for (auto& input : tests.getAllKeys())
2885 expectEquals (reduceLengthOfFloatString (input), tests[input]);
2886 }
2887
2888 {
2889 std::map<double, String> tests;
2890 tests[1] = "1.0";
2891 tests[1.1] = "1.1";
2892 tests[1.01] = "1.01";
2893 tests[0.76378] = "7.6378e-1";
2894 tests[-10] = "-1.0e1";
2895 tests[10.01] = "1.001e1";
2896 tests[10691.01] = "1.069101e4";
2897 tests[0.0123] = "1.23e-2";
2898 tests[-3.7e-27] = "-3.7e-27";
2899 tests[1e+40] = "1.0e40";
2900
2901 for (auto& test : tests)
2902 expectEquals (reduceLengthOfFloatString (String (test.first, 15, true)), test.second);
2903 }
2904 }
2905
2906 {
2907 beginTest ("Serialisation");
2908
2909 std::map <double, String> tests;
2910
2911 tests[364] = "364.0";
2912 tests[1e7] = "1.0e7";
2913 tests[12345678901] = "1.2345678901e10";
2914
2915 tests[1234567890123456.7] = "1.234567890123457e15";
2916 tests[12345678.901234567] = "1.234567890123457e7";
2917 tests[1234567.8901234567] = "1.234567890123457e6";
2918 tests[123456.78901234567] = "123456.7890123457";
2919 tests[12345.678901234567] = "12345.67890123457";
2920 tests[1234.5678901234567] = "1234.567890123457";
2921 tests[123.45678901234567] = "123.4567890123457";
2922 tests[12.345678901234567] = "12.34567890123457";
2923 tests[1.2345678901234567] = "1.234567890123457";
2924 tests[0.12345678901234567] = "0.1234567890123457";
2925 tests[0.012345678901234567] = "0.01234567890123457";
2926 tests[0.0012345678901234567] = "0.001234567890123457";
2927 tests[0.00012345678901234567] = "0.0001234567890123457";
2928 tests[0.000012345678901234567] = "0.00001234567890123457";
2929 tests[0.0000012345678901234567] = "1.234567890123457e-6";
2930 tests[0.00000012345678901234567] = "1.234567890123457e-7";
2931
2932 for (auto& test : tests)
2933 {
2934 expectEquals (serialiseDouble (test.first), test.second);
2935 expectEquals (serialiseDouble (-test.first), "-" + test.second);
2936 }
2937 }
2938 }
2939};
2940
2941static StringTests stringUnitTests;
2942
2943#endif
2944
2945} // namespace juce
juce::ByteOrder::swapIfLittleEndian
static Type swapIfLittleEndian(Type value) noexcept
Definition: juce_ByteOrder.h:74
juce::ByteOrder::swapIfBigEndian
static Type swapIfBigEndian(Type value) noexcept
Definition: juce_ByteOrder.h:63
juce::CharPointer_ASCII
Definition: juce_CharPointer_ASCII.h:38
juce::CharPointer_ASCII::isValidString
static bool isValidString(const CharType *dataToTest, int maxBytesToRead)
Definition: juce_CharPointer_ASCII.h:360
juce::CharPointer_UTF16
Definition: juce_CharPointer_UTF16.h:35
juce::CharPointer_UTF16::isByteOrderMarkBigEndian
static bool isByteOrderMarkBigEndian(const void *possibleByteOrder) noexcept
Definition: juce_CharPointer_UTF16.h:484
juce::CharPointer_UTF16::isByteOrderMarkLittleEndian
static bool isByteOrderMarkLittleEndian(const void *possibleByteOrder) noexcept
Definition: juce_CharPointer_UTF16.h:496
juce::CharPointer_UTF32
Definition: juce_CharPointer_UTF32.h:35
juce::CharPointer_UTF8
Definition: juce_CharPointer_UTF8.h:35
juce::CharPointer_UTF8::getBytesRequiredFor
static size_t getBytesRequiredFor(const juce_wchar charToWrite) noexcept
Definition: juce_CharPointer_UTF8.h:284
juce::CharPointer_UTF8::isByteOrderMark
static bool isByteOrderMark(const void *possibleByteOrder) noexcept
Definition: juce_CharPointer_UTF8.h:550
juce::CharPointer_UTF8::isValidString
static bool isValidString(const CharType *dataToTest, int maxBytesToRead)
Definition: juce_CharPointer_UTF8.h:493
juce::CharPointer_UTF8::getAddress
CharType * getAddress() const noexcept
Definition: juce_CharPointer_UTF8.h:67
juce::CharacterFunctions::indexOfIgnoreCase
static int indexOfIgnoreCase(CharPointerType1 haystack, const CharPointerType2 needle) noexcept
Definition: juce_CharacterFunctions.h:693
juce::CharacterFunctions::toLowerCase
static juce_wchar toLowerCase(juce_wchar character) noexcept
Definition: juce_CharacterFunctions.cpp:36
juce::CharacterFunctions::isDigit
static bool isDigit(char character) noexcept
Definition: juce_CharacterFunctions.cpp:74
juce::CharacterFunctions::isLetterOrDigit
static bool isLetterOrDigit(char character) noexcept
Definition: juce_CharacterFunctions.cpp:95
juce::CharacterFunctions::toUpperCase
static juce_wchar toUpperCase(juce_wchar character) noexcept
Definition: juce_CharacterFunctions.cpp:31
juce::CharacterFunctions::getUnicodeCharFromWindows1252Codepage
static juce_wchar getUnicodeCharFromWindows1252Codepage(uint8 windows1252Char) noexcept
Definition: juce_CharacterFunctions.cpp:169
juce::HeapBlock
Definition: juce_HeapBlock.h:87
juce::StringRef
Definition: juce_StringRef.h:62
juce::StringRef::length
int length() const noexcept
Definition: juce_StringRef.h:105
juce::StringRef::text
String::CharPointerType text
Definition: juce_StringRef.h:130
juce::StringRef::StringRef
StringRef() noexcept
Definition: juce_String.cpp:2150
juce::String
Definition: juce_String.h:39
juce::String::getCharPointer
CharPointerType getCharPointer() const noexcept
Definition: juce_String.h:1198
juce::String::equalsIgnoreCase
bool equalsIgnoreCase(const String &other) const noexcept
Definition: juce_String.cpp:602
juce::String::repeatedString
static String repeatedString(StringRef stringToRepeat, int numberOfTimesToRepeat)
Definition: juce_String.cpp:1158
juce::String::indexOfChar
int indexOfChar(juce_wchar characterToLookFor) const noexcept
Definition: juce_String.cpp:885
juce::String::upToFirstOccurrenceOf
String upToFirstOccurrenceOf(StringRef substringToEndWith, bool includeSubStringInResult, bool ignoreCase) const
Definition: juce_String.cpp:1596
juce::String::length
int length() const noexcept
Definition: juce_String.cpp:523
juce::String::trim
String trim() const
Definition: juce_String.cpp:1667
juce::String::compareNatural
int compareNatural(StringRef other, bool isCaseSensitive=false) const noexcept
Definition: juce_String.cpp:712
juce::String::endsWithChar
bool endsWithChar(juce_wchar character) const noexcept
Definition: juce_String.cpp:1421
juce::String::trimCharactersAtStart
String trimCharactersAtStart(StringRef charactersToTrim) const
Definition: juce_String.cpp:1712
juce::String::toUpperCase
String toUpperCase() const
Definition: juce_String.cpp:1467
juce::String::isEmpty
bool isEmpty() const noexcept
Definition: juce_String.h:296
juce::String::String
String() noexcept
Definition: juce_String.cpp:246
juce::String::toUTF16
CharPointer_UTF16 toUTF16() const
Definition: juce_String.cpp:2074
juce::String::isQuotedString
bool isQuotedString() const
Definition: juce_String.cpp:1621
juce::String::append
void append(const String &textToAppend, size_t maxCharsToTake)
Definition: juce_String.cpp:718
juce::String::~String
~String() noexcept
Definition: juce_String.cpp:250
juce::String::getFloatValue
float getFloatValue() const noexcept
Definition: juce_String.cpp:1876
juce::String::toRawUTF8
const char * toRawUTF8() const
Definition: juce_String.cpp:2077
juce::String::containsIgnoreCase
bool containsIgnoreCase(StringRef text) const noexcept
Definition: juce_String.cpp:1056
juce::String::startsWithChar
bool startsWithChar(juce_wchar character) const noexcept
Definition: juce_String.cpp:1414
juce::String::startsWith
bool startsWith(StringRef text) const noexcept
Definition: juce_String.cpp:1404
juce::String::hashCode64
int64 hashCode64() const noexcept
Definition: juce_String.cpp:562
juce::String::containsChar
bool containsChar(juce_wchar character) const noexcept
Definition: juce_String.cpp:1051
juce::String::paddedLeft
String paddedLeft(juce_wchar padCharacter, int minimumLength) const
Definition: juce_String.cpp:1172
juce::String::startsWithIgnoreCase
bool startsWithIgnoreCase(StringRef text) const noexcept
Definition: juce_String.cpp:1409
juce::String::compareIgnoreCase
int compareIgnoreCase(const String &other) const noexcept
Definition: juce_String.cpp:611
juce::String::removeCharacters
String removeCharacters(StringRef charactersToRemove) const
Definition: juce_String.cpp:1768
juce::String::endsWithIgnoreCase
bool endsWithIgnoreCase(StringRef text) const noexcept
Definition: juce_String.cpp:1449
juce::String::matchesWildcard
bool matchesWildcard(StringRef wildcard, bool ignoreCase) const noexcept
Definition: juce_String.cpp:1152
juce::String::appendCharPointer
void appendCharPointer(CharPointerType startOfTextToAppend, CharPointerType endOfTextToAppend)
Definition: juce_String.cpp:729
juce::String::quoted
String quoted(juce_wchar quoteCharacter='"') const
Definition: juce_String.cpp:1635
juce::String::operator+=
String & operator+=(const String &stringToAppend)
Definition: juce_String.cpp:761
juce::String::indexOf
int indexOf(StringRef textToLookFor) const noexcept
Definition: juce_String.cpp:942
juce::String::getNumBytesAsUTF8
size_t getNumBytesAsUTF8() const noexcept
Definition: juce_String.cpp:2123
juce::String::initialSectionContainingOnly
String initialSectionContainingOnly(StringRef permittedCharacters) const
Definition: juce_String.cpp:1789
juce::String::createStringFromData
static String createStringFromData(const void *data, int size)
Definition: juce_String.cpp:1971
juce::String::lastIndexOf
int lastIndexOf(StringRef textToLookFor) const noexcept
Definition: juce_String.cpp:990
juce::String::retainCharacters
String retainCharacters(StringRef charactersToRetain) const
Definition: juce_String.cpp:1746
juce::String::clear
void clear() noexcept
Definition: juce_String.cpp:265
juce::String::indexOfAnyOf
int indexOfAnyOf(StringRef charactersToLookFor, int startIndex=0, bool ignoreCase=false) const noexcept
Definition: juce_String.cpp:922
juce::String::copyToUTF16
size_t copyToUTF16(CharPointer_UTF16::CharType *destBuffer, size_t maxBufferSizeBytes) const noexcept
Definition: juce_String.cpp:2112
juce::String::preallocateBytes
void preallocateBytes(size_t numBytesNeeded)
Definition: juce_String.cpp:296
juce::String::lastIndexOfAnyOf
int lastIndexOfAnyOf(StringRef charactersToLookFor, bool ignoreCase=false) const noexcept
Definition: juce_String.cpp:1034
juce::String::hash
size_t hash() const noexcept
Definition: juce_String.cpp:563
juce::String::dropLastCharacters
String dropLastCharacters(int numberToDrop) const
Definition: juce_String.cpp:1566
juce::String::operator[]
juce_wchar operator[](int index) const noexcept
Definition: juce_String.cpp:538
juce::String::contains
bool contains(StringRef text) const noexcept
Definition: juce_String.cpp:1046
juce::String::trimStart
String trimStart() const
Definition: juce_String.cpp:1685
juce::String::trimEnd
String trimEnd() const
Definition: juce_String.cpp:1698
juce::String::toLowerCase
String toLowerCase() const
Definition: juce_String.cpp:1485
juce::String::replaceFirstOccurrenceOf
String replaceFirstOccurrenceOf(StringRef stringToReplace, StringRef stringToInsertInstead, bool ignoreCase=false) const
Definition: juce_String.cpp:1308
juce::String::getDoubleValue
double getDoubleValue() const noexcept
Definition: juce_String.cpp:1877
juce::String::getTrailingIntValue
int getTrailingIntValue() const noexcept
Definition: juce_String.cpp:1879
juce::String::toHexString
static String toHexString(IntegerType number)
Definition: juce_String.h:1053
juce::String::indexOfWholeWord
int indexOfWholeWord(StringRef wordToLookFor) const noexcept
Definition: juce_String.cpp:1061
juce::String::lastIndexOfChar
int lastIndexOfChar(juce_wchar character) const noexcept
Definition: juce_String.cpp:910
juce::String::copyToUTF32
size_t copyToUTF32(CharPointer_UTF32::CharType *destBuffer, size_t maxBufferSizeBytes) const noexcept
Definition: juce_String.cpp:2117
juce::String::toWideCharPointer
const wchar_t * toWideCharPointer() const
Definition: juce_String.cpp:2082
juce::String::copyToUTF8
size_t copyToUTF8(CharPointer_UTF8::CharType *destBuffer, size_t maxBufferSizeBytes) const noexcept
Definition: juce_String.cpp:2107
juce::String::replace
String replace(StringRef stringToReplace, StringRef stringToInsertInstead, bool ignoreCase=false) const
Definition: juce_String.cpp:1290
juce::String::lastIndexOfIgnoreCase
int lastIndexOfIgnoreCase(StringRef textToLookFor) const noexcept
Definition: juce_String.cpp:1012
juce::String::getLastCharacters
String getLastCharacters(int numCharacters) const
Definition: juce_String.cpp:1571
juce::String::replaceCharacters
String replaceCharacters(StringRef charactersToReplace, StringRef charactersToInsertInstead) const
Definition: juce_String.cpp:1378
juce::String::upToLastOccurrenceOf
String upToLastOccurrenceOf(StringRef substringToFind, bool includeSubStringInResult, bool ignoreCase) const
Definition: juce_String.cpp:1606
juce::String::unquoted
String unquoted() const
Definition: juce_String.cpp:1626
juce::String::trimCharactersAtEnd
String trimCharactersAtEnd(StringRef charactersToTrim) const
Definition: juce_String.cpp:1722
juce::String::containsWholeWord
bool containsWholeWord(StringRef wordToLookFor) const noexcept
Definition: juce_String.cpp:1105
juce::String::charToString
static String charToString(juce_wchar character)
Definition: juce_String.cpp:371
juce::String::paddedRight
String paddedRight(juce_wchar padCharacter, int minimumLength) const
Definition: juce_String.cpp:1199
juce::String::replaceCharacter
String replaceCharacter(juce_wchar characterToReplace, juce_wchar characterToInsertInstead) const
Definition: juce_String.cpp:1355
juce::String::getLastCharacter
juce_wchar getLastCharacter() const noexcept
Definition: juce_String.cpp:1504
juce::String::substring
String substring(int startIndex, int endIndex) const
Definition: juce_String.cpp:1509
juce::String::fromLastOccurrenceOf
String fromLastOccurrenceOf(StringRef substringToFind, bool includeSubStringInResult, bool ignoreCase) const
Definition: juce_String.cpp:1586
juce::String::hashCode
int hashCode() const noexcept
Definition: juce_String.cpp:561
juce::String::containsNonWhitespaceChars
bool containsNonWhitespaceChars() const noexcept
Definition: juce_String.cpp:1825
juce::String::replaceSection
String replaceSection(int startIndex, int numCharactersToReplace, StringRef stringToInsert) const
Definition: juce_String.cpp:1229
juce::String::operator=
String & operator=(const String &other) noexcept
Definition: juce_String.cpp:271
juce::String::initialSectionNotContaining
String initialSectionNotContaining(StringRef charactersToStopAt) const
Definition: juce_String.cpp:1798
juce::String::fromUTF8
static String fromUTF8(const char *utf8buffer, int bufferSizeBytes=-1)
Definition: juce_String.cpp:2128
juce::String::getLargeIntValue
int64 getLargeIntValue() const noexcept
Definition: juce_String.cpp:1875
juce::String::getHexValue64
int64 getHexValue64() const noexcept
Definition: juce_String.cpp:1957
juce::String::containsAnyOf
bool containsAnyOf(StringRef charactersItMightContain) const noexcept
Definition: juce_String.cpp:1816
juce::String::endsWith
bool endsWith(StringRef text) const noexcept
Definition: juce_String.cpp:1432
juce::String::indexOfIgnoreCase
int indexOfIgnoreCase(StringRef textToLookFor) const noexcept
Definition: juce_String.cpp:947
juce::String::containsWholeWordIgnoreCase
bool containsWholeWordIgnoreCase(StringRef wordToLookFor) const noexcept
Definition: juce_String.cpp:1110
juce::String::toUTF8
CharPointer_UTF8 toUTF8() const
Definition: juce_String.cpp:2073
juce::String::getReferenceCount
int getReferenceCount() const noexcept
Definition: juce_String.cpp:301
juce::String::indexOfWholeWordIgnoreCase
int indexOfWholeWordIgnoreCase(StringRef wordToLookFor) const noexcept
Definition: juce_String.cpp:1083
juce::String::compare
int compare(const String &other) const noexcept
Definition: juce_String.cpp:608
juce::String::getIntValue
int getIntValue() const noexcept
Definition: juce_String.cpp:1874
juce::String::containsOnly
bool containsOnly(StringRef charactersItMightContain) const noexcept
Definition: juce_String.cpp:1807
juce::String::isNotEmpty
bool isNotEmpty() const noexcept
Definition: juce_String.h:302
juce::String::toUTF32
CharPointer_UTF32 toUTF32() const
Definition: juce_String.cpp:2075
juce::String::fromFirstOccurrenceOf
String fromFirstOccurrenceOf(StringRef substringToStartFrom, bool includeSubStringInResult, bool ignoreCase) const
Definition: juce_String.cpp:1576
juce::String::swapWith
void swapWith(String &other) noexcept
Definition: juce_String.cpp:260
juce::String::getHexValue32
int getHexValue32() const noexcept
Definition: juce_String.cpp:1956
juce::CharacterFunctions::HexParser
Definition: juce_CharacterFunctions.h:446