OpenShot Audio Library | OpenShotAudio  0.3.1
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 
23 namespace juce
24 {
25 
26 #if JUCE_MSVC
27  #pragma warning (push)
28  #pragma warning (disable: 4514 4996)
29 #endif
30 
31 NewLine 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 
45 static 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)
52 struct EmptyString
53 {
54  int refCount;
55  size_t allocatedBytes;
56  String::CharPointerType::CharType text;
57 };
58 
59 static const EmptyString emptyString { 0x3fffffff, sizeof (String::CharPointerType::CharType), 0 };
60 
61 //==============================================================================
62 class StringHolder
63 {
64 public:
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 
212 private:
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 
243 JUCE_DECLARE_DEPRECATED_STATIC (const String String::empty;)
244 
245 //==============================================================================
246 String::String() noexcept : text (&(emptyString.text))
247 {
248 }
249 
250 String::~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 
289 inline 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 //==============================================================================
381 namespace 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 
528 static size_t findByteOffsetOfEnd (String::CharPointerType text) noexcept
529 {
530  return (size_t) (((char*) text.findTerminatingNull().getAddress()) - (char*) text.getAddress());
531 }
532 
533 size_t String::getByteOffsetOfEnd() const noexcept
534 {
535  return findByteOffsetOfEnd (text);
536 }
537 
538 juce_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 
544 template <typename Type>
545 struct 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); }
562 int64 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 //==============================================================================
566 JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const String& s2) noexcept { return s1.compare (s2) == 0; }
567 JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const String& s2) noexcept { return s1.compare (s2) != 0; }
568 JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const char* s2) noexcept { return s1.compare (s2) == 0; }
569 JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const char* s2) noexcept { return s1.compare (s2) != 0; }
570 JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const wchar_t* s2) noexcept { return s1.compare (s2) == 0; }
571 JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const wchar_t* s2) noexcept { return s1.compare (s2) != 0; }
572 JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, StringRef s2) noexcept { return s1.getCharPointer().compare (s2.text) == 0; }
573 JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, StringRef s2) noexcept { return s1.getCharPointer().compare (s2.text) != 0; }
574 JUCE_API bool JUCE_CALLTYPE operator< (const String& s1, StringRef s2) noexcept { return s1.getCharPointer().compare (s2.text) < 0; }
575 JUCE_API bool JUCE_CALLTYPE operator<= (const String& s1, StringRef s2) noexcept { return s1.getCharPointer().compare (s2.text) <= 0; }
576 JUCE_API bool JUCE_CALLTYPE operator> (const String& s1, StringRef s2) noexcept { return s1.getCharPointer().compare (s2.text) > 0; }
577 JUCE_API bool JUCE_CALLTYPE operator>= (const String& s1, StringRef s2) noexcept { return s1.getCharPointer().compare (s2.text) >= 0; }
578 JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const CharPointer_UTF8 s2) noexcept { return s1.getCharPointer().compare (s2) == 0; }
579 JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const CharPointer_UTF8 s2) noexcept { return s1.getCharPointer().compare (s2) != 0; }
580 JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const CharPointer_UTF16 s2) noexcept { return s1.getCharPointer().compare (s2) == 0; }
581 JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const CharPointer_UTF16 s2) noexcept { return s1.getCharPointer().compare (s2) != 0; }
582 JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const CharPointer_UTF32 s2) noexcept { return s1.getCharPointer().compare (s2) == 0; }
583 JUCE_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 
613 static 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 
634 static 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 
652 static 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  {
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 
756 {
757  appendCharPointer (CharPointer_UTF8 (t)); // (using UTF8 here triggers a faster code-path than ascii)
758  return *this;
759 }
760 
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 
774 {
775  return operator+= (String (other));
776 }
777 
779 {
780  const char asString[] = { ch, 0 };
781  return operator+= (asString);
782 }
783 
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 
799 namespace 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 //==============================================================================
823 JUCE_API String JUCE_CALLTYPE operator+ (const char* s1, const String& s2) { String s (s1); return s += s2; }
824 JUCE_API String JUCE_CALLTYPE operator+ (const wchar_t* s1, const String& s2) { String s (s1); return s += s2; }
825 
826 JUCE_API String JUCE_CALLTYPE operator+ (char s1, const String& s2) { return String::charToString ((juce_wchar) (uint8) s1) + s2; }
827 JUCE_API String JUCE_CALLTYPE operator+ (wchar_t s1, const String& s2) { return String::charToString (s1) + s2; }
828 
829 JUCE_API String JUCE_CALLTYPE operator+ (String s1, const String& s2) { return s1 += s2; }
830 JUCE_API String JUCE_CALLTYPE operator+ (String s1, const char* s2) { return s1 += s2; }
831 JUCE_API String JUCE_CALLTYPE operator+ (String s1, const wchar_t* s2) { return s1 += s2; }
832 JUCE_API String JUCE_CALLTYPE operator+ (String s1, const std::string& s2) { return s1 += s2.c_str(); }
833 
834 JUCE_API String JUCE_CALLTYPE operator+ (String s1, char s2) { return s1 += s2; }
835 JUCE_API String JUCE_CALLTYPE operator+ (String s1, wchar_t s2) { return s1 += s2; }
836 
837 #if ! JUCE_NATIVE_WCHAR_IS_UTF32
838 JUCE_API String JUCE_CALLTYPE operator+ (juce_wchar s1, const String& s2) { return String::charToString (s1) + s2; }
839 JUCE_API String JUCE_CALLTYPE operator+ (String s1, juce_wchar s2) { return s1 += s2; }
840 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, juce_wchar s2) { return s1 += s2; }
841 #endif
842 
843 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, char s2) { return s1 += s2; }
844 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, wchar_t s2) { return s1 += s2; }
845 
846 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, const char* s2) { return s1 += s2; }
847 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, const wchar_t* s2) { return s1 += s2; }
848 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, const String& s2) { return s1 += s2; }
849 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, StringRef s2) { return s1 += s2; }
850 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, const std::string& s2) { return s1 += s2.c_str(); }
851 
852 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, uint8 number) { return s1 += (int) number; }
853 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, short number) { return s1 += (int) number; }
854 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, int number) { return s1 += number; }
855 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, long number) { return s1 += String (number); }
856 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, unsigned long number) { return s1 += String (number); }
857 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, int64 number) { return s1 += String (number); }
858 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, uint64 number) { return s1 += String (number); }
859 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, float number) { return s1 += String (number); }
860 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, double number) { return s1 += String (number); }
861 
862 JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const String& text)
863 {
864  return operator<< (stream, StringRef (text));
865 }
866 
867 JUCE_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 
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 //==============================================================================
1116 template <typename CharPointer>
1117 struct 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 
1320 struct 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 //==============================================================================
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 
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 //==============================================================================
1504 juce_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 
1616 static bool isQuoteCharacter (juce_wchar c) noexcept
1617 {
1618  return c == '"' || c == '\'';
1619 }
1620 
1622 {
1623  return isQuoteCharacter (*text.findEndOfWhitespace());
1624 }
1625 
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 //==============================================================================
1652 static 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 
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 
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 
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 
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 
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 
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 
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 
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(); }
1875 int64 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 
1902 static const char hexDigits[] = "0123456789abcdef";
1903 
1904 template <typename Type>
1905 static 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 
1923 String String::createHex (uint8 n) { return hexToString (n); }
1924 String String::createHex (uint16 n) { return hexToString (n); }
1925 String String::createHex (uint32 n) { return hexToString (n); }
1926 String 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 
1958 
1959 //==============================================================================
1960 static 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 
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 
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 //==============================================================================
2021 static const juce_wchar emptyChar = 0;
2022 
2023 template <class CharPointerType_Src, class CharPointerType_Dest>
2024 struct 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 
2055 template <>
2056 struct 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 
2061 template <>
2062 struct 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 
2067 template <>
2068 struct 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 
2087 std::string String::toStdString() const
2088 {
2089  return std::string (toRawUTF8());
2090 }
2091 
2092 //==============================================================================
2093 template <class CharPointerType_Src, class CharPointerType_Dest>
2094 struct 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 {
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 //==============================================================================
2150 StringRef::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 
2195 static 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 
2266 static 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 
2316 class StringTests : public UnitTest
2317 {
2318 public:
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]);
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 
2941 static StringTests stringUnitTests;
2942 
2943 #endif
2944 
2945 } // namespace juce
static Type swapIfLittleEndian(Type value) noexcept
static Type swapIfBigEndian(Type value) noexcept
static bool isValidString(const CharType *dataToTest, int maxBytesToRead)
static bool canRepresent(juce_wchar character) noexcept
static bool isByteOrderMarkBigEndian(const void *possibleByteOrder) noexcept
static bool isByteOrderMarkLittleEndian(const void *possibleByteOrder) noexcept
static size_t getBytesRequiredFor(const juce_wchar charToWrite) noexcept
CharType * getAddress() const noexcept
static bool isByteOrderMark(const void *possibleByteOrder) noexcept
static bool isValidString(const CharType *dataToTest, int maxBytesToRead)
static int indexOfIgnoreCase(CharPointerType1 haystack, const CharPointerType2 needle) noexcept
static juce_wchar toLowerCase(juce_wchar character) noexcept
static bool isDigit(char character) noexcept
static bool isLetterOrDigit(char character) noexcept
static juce_wchar toUpperCase(juce_wchar character) noexcept
static juce_wchar getUnicodeCharFromWindows1252Codepage(uint8 windows1252Char) noexcept
int length() const noexcept
String::CharPointerType text
StringRef() noexcept
CharPointerType getCharPointer() const noexcept
Definition: juce_String.h:1198
bool equalsIgnoreCase(const String &other) const noexcept
static String repeatedString(StringRef stringToRepeat, int numberOfTimesToRepeat)
int indexOfChar(juce_wchar characterToLookFor) const noexcept
String upToFirstOccurrenceOf(StringRef substringToEndWith, bool includeSubStringInResult, bool ignoreCase) const
int length() const noexcept
String trim() const
int compareNatural(StringRef other, bool isCaseSensitive=false) const noexcept
bool endsWithChar(juce_wchar character) const noexcept
String trimCharactersAtStart(StringRef charactersToTrim) const
String toUpperCase() const
bool isEmpty() const noexcept
Definition: juce_String.h:296
String() noexcept
CharPointer_UTF16 toUTF16() const
bool isQuotedString() const
void append(const String &textToAppend, size_t maxCharsToTake)
~String() noexcept
float getFloatValue() const noexcept
const char * toRawUTF8() const
static String toDecimalStringWithSignificantFigures(DecimalType number, int numberOfSignificantFigures)
Definition: juce_String.h:1072
bool containsIgnoreCase(StringRef text) const noexcept
bool startsWithChar(juce_wchar character) const noexcept
bool startsWith(StringRef text) const noexcept
int64 hashCode64() const noexcept
bool containsChar(juce_wchar character) const noexcept
String paddedLeft(juce_wchar padCharacter, int minimumLength) const
bool startsWithIgnoreCase(StringRef text) const noexcept
int compareIgnoreCase(const String &other) const noexcept
String removeCharacters(StringRef charactersToRemove) const
bool endsWithIgnoreCase(StringRef text) const noexcept
bool matchesWildcard(StringRef wildcard, bool ignoreCase) const noexcept
void appendCharPointer(CharPointerType startOfTextToAppend, CharPointerType endOfTextToAppend)
String quoted(juce_wchar quoteCharacter='"') const
String & operator+=(const String &stringToAppend)
int indexOf(StringRef textToLookFor) const noexcept
size_t getNumBytesAsUTF8() const noexcept
String initialSectionContainingOnly(StringRef permittedCharacters) const
static String createStringFromData(const void *data, int size)
int lastIndexOf(StringRef textToLookFor) const noexcept
String retainCharacters(StringRef charactersToRetain) const
void clear() noexcept
int indexOfAnyOf(StringRef charactersToLookFor, int startIndex=0, bool ignoreCase=false) const noexcept
size_t copyToUTF16(CharPointer_UTF16::CharType *destBuffer, size_t maxBufferSizeBytes) const noexcept
void preallocateBytes(size_t numBytesNeeded)
int lastIndexOfAnyOf(StringRef charactersToLookFor, bool ignoreCase=false) const noexcept
size_t hash() const noexcept
String dropLastCharacters(int numberToDrop) const
juce_wchar operator[](int index) const noexcept
bool contains(StringRef text) const noexcept
String trimStart() const
String trimEnd() const
String toLowerCase() const
String replaceFirstOccurrenceOf(StringRef stringToReplace, StringRef stringToInsertInstead, bool ignoreCase=false) const
double getDoubleValue() const noexcept
int getTrailingIntValue() const noexcept
static String toHexString(IntegerType number)
Definition: juce_String.h:1053
int indexOfWholeWord(StringRef wordToLookFor) const noexcept
int lastIndexOfChar(juce_wchar character) const noexcept
size_t copyToUTF32(CharPointer_UTF32::CharType *destBuffer, size_t maxBufferSizeBytes) const noexcept
const wchar_t * toWideCharPointer() const
size_t copyToUTF8(CharPointer_UTF8::CharType *destBuffer, size_t maxBufferSizeBytes) const noexcept
String replace(StringRef stringToReplace, StringRef stringToInsertInstead, bool ignoreCase=false) const
int lastIndexOfIgnoreCase(StringRef textToLookFor) const noexcept
String getLastCharacters(int numCharacters) const
String replaceCharacters(StringRef charactersToReplace, StringRef charactersToInsertInstead) const
String upToLastOccurrenceOf(StringRef substringToFind, bool includeSubStringInResult, bool ignoreCase) const
String unquoted() const
String trimCharactersAtEnd(StringRef charactersToTrim) const
bool containsWholeWord(StringRef wordToLookFor) const noexcept
static String charToString(juce_wchar character)
String paddedRight(juce_wchar padCharacter, int minimumLength) const
String replaceCharacter(juce_wchar characterToReplace, juce_wchar characterToInsertInstead) const
juce_wchar getLastCharacter() const noexcept
String substring(int startIndex, int endIndex) const
String fromLastOccurrenceOf(StringRef substringToFind, bool includeSubStringInResult, bool ignoreCase) const
int hashCode() const noexcept
bool containsNonWhitespaceChars() const noexcept
String replaceSection(int startIndex, int numCharactersToReplace, StringRef stringToInsert) const
String & operator=(const String &other) noexcept
String initialSectionNotContaining(StringRef charactersToStopAt) const
static String fromUTF8(const char *utf8buffer, int bufferSizeBytes=-1)
int64 getLargeIntValue() const noexcept
int64 getHexValue64() const noexcept
bool containsAnyOf(StringRef charactersItMightContain) const noexcept
bool endsWith(StringRef text) const noexcept
int indexOfIgnoreCase(StringRef textToLookFor) const noexcept
bool containsWholeWordIgnoreCase(StringRef wordToLookFor) const noexcept
CharPointer_UTF8 toUTF8() const
int getReferenceCount() const noexcept
int indexOfWholeWordIgnoreCase(StringRef wordToLookFor) const noexcept
int compare(const String &other) const noexcept
int getIntValue() const noexcept
bool containsOnly(StringRef charactersItMightContain) const noexcept
bool isNotEmpty() const noexcept
Definition: juce_String.h:302
CharPointer_UTF32 toUTF32() const
String fromFirstOccurrenceOf(StringRef substringToStartFrom, bool includeSubStringInResult, bool ignoreCase) const
void swapWith(String &other) noexcept
int getHexValue32() const noexcept