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