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