LMMS
Loading...
Searching...
No Matches
String.cpp
Go to the documentation of this file.
1/*
2 ==============================================================================
3
4 This file is part of the Water library.
5 Copyright (c) 2016 ROLI Ltd.
6 Copyright (C) 2017-2022 Filipe Coelho <falktx@falktx.com>
7
8 Permission is granted to use this software under the terms of the ISC license
9 http://www.isc.org/downloads/software-support-policy/isc-license/
10
11 Permission to use, copy, modify, and/or distribute this software for any
12 purpose with or without fee is hereby granted, provided that the above
13 copyright notice and this permission notice appear in all copies.
14
15 THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
16 TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
18 OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
19 USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21 OF THIS SOFTWARE.
22
23 ==============================================================================
24*/
25
26#include "String.h"
27#include "NewLine.h"
29#include "../memory/HeapBlock.h"
31
32#include "CarlaJuceUtils.hpp"
33
34#include <locale>
35#include <iostream>
36
37#ifdef CARLA_OS_MAC
38// FIXME
39// # import <CoreData/CoreData.h>
40#endif
41
42// #import <Carbon/UnicodeConverter.h>
43
44namespace water {
45
46//==============================================================================
47// (Mirrors the structure of StringHolder, but without the atomic member, so can be statically constructed)
54
55static const EmptyString emptyString = { 0x3fffffff, sizeof (CharPointer_UTF8::CharType), '\0' };
56
57//==============================================================================
59{
60public:
62
64
65 //==============================================================================
67 {
68 numBytes = (numBytes + 3) & ~(size_t) 3;
69 StringHolder* const s = reinterpret_cast<StringHolder*> (new char [sizeof (StringHolder) - sizeof (CharType) + numBytes]);
70 s->refCount.value = 0;
71 s->allocatedNumBytes = numBytes;
72 return CharPointer_UTF8 (s->text);
73 }
74
75 template <class CharPointer>
76 static CharPointer_UTF8 createFromCharPointer (const CharPointer text)
77 {
78 if (text.getAddress() == nullptr || text.isEmpty())
79 return CharPointer_UTF8 (&(emptyString.text));
80
81 const size_t bytesNeeded = sizeof (CharType) + CharPointer_UTF8::getBytesRequiredFor (text);
82 const CharPointer_UTF8 dest (createUninitialisedBytes (bytesNeeded));
84 return dest;
85 }
86
87 template <class CharPointer>
88 static CharPointer_UTF8 createFromCharPointer (const CharPointer text, size_t maxChars)
89 {
90 if (text.getAddress() == nullptr || text.isEmpty() || maxChars == 0)
91 return CharPointer_UTF8 (&(emptyString.text));
92
93 CharPointer end (text);
94 size_t numChars = 0;
95 size_t bytesNeeded = sizeof (CharType);
96
97 while (numChars < maxChars && ! end.isEmpty())
98 {
99 bytesNeeded += CharPointer_UTF8::getBytesRequiredFor (end.getAndAdvance());
100 ++numChars;
101 }
102
103 const CharPointer_UTF8 dest (createUninitialisedBytes (bytesNeeded));
104 CharPointer_UTF8 (dest).writeWithCharLimit (text, (int) numChars + 1);
105 return dest;
106 }
107
108 template <class CharPointer>
109 static CharPointer_UTF8 createFromCharPointer (const CharPointer start, const CharPointer end)
110 {
111 if (start.getAddress() == nullptr || start.isEmpty())
112 return CharPointer_UTF8 (&(emptyString.text));
113
114 CharPointer e (start);
115 int numChars = 0;
116 size_t bytesNeeded = sizeof (CharType);
117
118 while (e < end && ! e.isEmpty())
119 {
120 bytesNeeded += CharPointer_UTF8::getBytesRequiredFor (e.getAndAdvance());
121 ++numChars;
122 }
123
124 const CharPointer_UTF8 dest (createUninitialisedBytes (bytesNeeded));
125 CharPointer_UTF8 (dest).writeWithCharLimit (start, numChars + 1);
126 return dest;
127 }
128
130 {
131 if (start.getAddress() == nullptr || start.isEmpty())
132 return CharPointer_UTF8 (&(emptyString.text));
133
134 const size_t numBytes = (size_t) (reinterpret_cast<const char*> (end.getAddress())
135 - reinterpret_cast<const char*> (start.getAddress()));
136 const CharPointer_UTF8 dest (createUninitialisedBytes (numBytes + sizeof (CharType)));
137 memcpy (dest.getAddress(), start, numBytes);
138 dest.getAddress()[numBytes / sizeof (CharType)] = 0;
139 return dest;
140 }
141
142 static CharPointer_UTF8 createFromFixedLength (const char* const src, const size_t numChars)
143 {
144 const CharPointer_UTF8 dest (createUninitialisedBytes (numChars * sizeof (CharType) + sizeof (CharType)));
145 CharPointer_UTF8 (dest).writeWithCharLimit (CharPointer_UTF8 (src), (int) (numChars + 1));
146 return dest;
147 }
148
149 //==============================================================================
150 static void retain (const CharPointer_UTF8 text) noexcept
151 {
153
154 if (b != (StringHolder*) &emptyString)
155 ++(b->refCount);
156 }
157
158 static inline void release (StringHolder* const b) noexcept
159 {
160 if (b != (StringHolder*) &emptyString)
161 if (--(b->refCount) == -1)
162 delete[] reinterpret_cast<char*> (b);
163 }
164
165 static void release (const CharPointer_UTF8 text) noexcept
166 {
168 }
169
170 static inline int getReferenceCount (const CharPointer_UTF8 text) noexcept
171 {
172 return bufferFromText (text)->refCount.get() + 1;
173 }
174
175 //==============================================================================
177 {
179
180 if (b == (StringHolder*) &emptyString)
181 {
182 CharPointer_UTF8 newText (createUninitialisedBytes (numBytes));
183 newText.writeNull();
184 return newText;
185 }
186
187 if (b->allocatedNumBytes >= numBytes && b->refCount.get() <= 0)
188 return text;
189
190 CharPointer_UTF8 newText (createUninitialisedBytes (jmax (b->allocatedNumBytes, numBytes)));
191 memcpy (newText.getAddress(), text.getAddress(), b->allocatedNumBytes);
192 release (b);
193
194 return newText;
195 }
196
197 static size_t getAllocatedNumBytes (const CharPointer_UTF8 text) noexcept
198 {
200 }
201
202 //==============================================================================
206
207private:
208 static inline StringHolder* bufferFromText (const CharPointer_UTF8 text) noexcept
209 {
210 // (Can't use offsetof() here because of warnings about this not being a POD)
211 return reinterpret_cast<StringHolder*> (reinterpret_cast<char*> (text.getAddress())
212 - (reinterpret_cast<size_t> (reinterpret_cast<StringHolder*> (1)->text) - 1));
213 }
214};
215
216//==============================================================================
220
225
226String::String (const String& other) noexcept : text (other.text)
227{
229}
230
231void String::swapWith (String& other) noexcept
232{
233 std::swap (text, other.text);
234}
235
237{
239 text = &(emptyString.text);
240}
241
242String& String::operator= (const String& other) noexcept
243{
244 swapWith(const_cast<String&>(other));
245 return *this;
246}
247
249
250String::String (const PreallocationBytes& preallocationSize)
251 : text (StringHolder::createUninitialisedBytes (preallocationSize.numBytes + sizeof (CharPointer_UTF8::CharType)))
252{
253}
254
255void String::preallocateBytes (const size_t numBytesNeeded)
256{
258}
259
264
265//==============================================================================
266String::String (const char* const t)
267 : text (StringHolder::createFromCharPointer (CharPointer_UTF8 (t)))
268{
269 /* If you get an assertion here, then you're trying to create a string from 8-bit data
270 that contains values greater than 127. These can NOT be correctly converted to unicode
271 because there's no way for the String class to know what encoding was used to
272 create them. The source data could be UTF-8, ASCII or one of many local code-pages.
273
274 To get around this problem, you must be more explicit when you pass an ambiguous 8-bit
275 string to the String class - so for example if your source data is actually UTF-8,
276 you'd call String (CharPointer_UTF8 ("my utf8 string..")), and it would be able to
277 correctly convert the multi-byte characters to unicode. It's *highly* recommended that
278 you use UTF-8 with escape characters in your source code to represent extended characters,
279 because there's no other way to represent these strings in a way that isn't dependent on
280 the compiler, source code editor and platform.
281 */
282 CARLA_SAFE_ASSERT (t == nullptr || CharPointer_UTF8::isValidString (t, std::numeric_limits<int>::max()));
283}
284
285String::String (const char* const t, const size_t maxChars)
286 : text (StringHolder::createFromCharPointer (CharPointer_UTF8 (t), maxChars))
287{
288 /* If you get an assertion here, then you're trying to create a string from 8-bit data
289 that contains values greater than 127. These can NOT be correctly converted to unicode
290 because there's no way for the String class to know what encoding was used to
291 create them. The source data could be UTF-8, ASCII or one of many local code-pages.
292
293 To get around this problem, you must be more explicit when you pass an ambiguous 8-bit
294 string to the String class - so for example if your source data is actually UTF-8,
295 you'd call String (CharPointer_UTF8 ("my utf8 string..")), and it would be able to
296 correctly convert the multi-byte characters to unicode. It's *highly* recommended that
297 you use UTF-8 with escape characters in your source code to represent extended characters,
298 because there's no other way to represent these strings in a way that isn't dependent on
299 the compiler, source code editor and platform.
300 */
301 CARLA_SAFE_ASSERT (t == nullptr || CharPointer_UTF8::isValidString (t, (int) maxChars));
302}
303
304String::String (const CharPointer_UTF8 t) : text (StringHolder::createFromCharPointer (t)) {}
305String::String (const CharPointer_UTF8 t, const size_t maxChars) : text (StringHolder::createFromCharPointer (t, maxChars)) {}
306String::String (const CharPointer_UTF8 start, const CharPointer_UTF8 end) : text (StringHolder::createFromCharPointer (start, end)) {}
307
308String::String (const std::string& s) : text (StringHolder::createFromFixedLength (s.data(), s.size())) {}
309String::String (StringRef s) : text (StringHolder::createFromCharPointer (s.text)) {}
310
312{
315 t.write (character);
316 t.writeNull();
317 return result;
318}
319
320//==============================================================================
322{
323 static char* numberToString (char* t, uint64 v) noexcept
324 {
325 return printDigits (t, v);
326 }
327
328 static char* numberToString (char* t, const int n) noexcept
329 {
330 if (n >= 0)
331 return printDigits (t, static_cast<unsigned int> (n));
332
333 // NB: this needs to be careful not to call -std::numeric_limits<int>::min(),
334 // which has undefined behaviour
335 t = printDigits (t, static_cast<unsigned int> (-(n + 1)) + 1);
336 *--t = '-';
337 return t;
338 }
339
340 static char* numberToString (char* t, const unsigned int v) noexcept
341 {
342 return printDigits (t, v);
343 }
344
345 static char* numberToString (char* t, const long n) noexcept
346 {
347 if (n >= 0)
348 return printDigits (t, static_cast<unsigned long> (n));
349
350 t = printDigits (t, static_cast<unsigned long> (-(n + 1)) + 1);
351 *--t = '-';
352 return t;
353 }
354
355 static char* numberToString (char* t, const unsigned long v) noexcept
356 {
357 return printDigits (t, v);
358 }
359
360 struct StackArrayStream : public std::basic_streambuf<char, std::char_traits<char> >
361 {
362 explicit StackArrayStream (char* d)
363 {
364 static const std::locale classicLocale (std::locale::classic());
365 imbue (classicLocale);
366 setp (d, d + charsNeededForDouble);
367 }
368
369 size_t writeDouble (double n, int numDecPlaces)
370 {
371 {
372 std::ostream o (this);
373
374 if (numDecPlaces > 0)
375 o.precision ((std::streamsize) numDecPlaces);
376
377 o << n;
378 }
379
380 return (size_t) (pptr() - pbase());
381 }
382 };
383
384 static char* doubleToString (char* buffer, const int numChars, double n, int numDecPlaces, size_t& len) noexcept
385 {
386 if (numDecPlaces > 0 && numDecPlaces < 7 && n > -1.0e20 && n < 1.0e20)
387 {
388 char* const end = buffer + numChars;
389 char* t = end;
390 int64 v = (int64) (pow (10.0, numDecPlaces) * std::abs (n) + 0.5);
391 *--t = (char) 0;
392
393 while (numDecPlaces >= 0 || v > 0)
394 {
395 if (numDecPlaces == 0)
396 *--t = '.';
397
398 *--t = (char) ('0' + (v % 10));
399
400 v /= 10;
401 --numDecPlaces;
402 }
403
404 if (n < 0)
405 *--t = '-';
406
407 len = (size_t) (end - t - 1);
408 return t;
409 }
410
411 StackArrayStream strm (buffer);
412 len = strm.writeDouble (n, numDecPlaces);
414 return buffer;
415 }
416
417 template <typename IntegerType>
418 static CharPointer_UTF8 createFromInteger (const IntegerType number)
419 {
420 char buffer [charsNeededForInt];
421 char* const end = buffer + numElementsInArray (buffer);
422 char* const start = numberToString (end, number);
423 return StringHolder::createFromFixedLength (start, (size_t) (end - start - 1));
424 }
425
426 static CharPointer_UTF8 createFromDouble (const double number, const int numberOfDecimalPlaces)
427 {
428 char buffer [charsNeededForDouble];
429 size_t len;
430 char* const start = doubleToString (buffer, numElementsInArray (buffer), (double) number, numberOfDecimalPlaces, len);
432 }
433}
434
435//==============================================================================
436String::String (const int number) : text (NumberToStringConverters::createFromInteger (number)) {}
437String::String (const unsigned int number) : text (NumberToStringConverters::createFromInteger (number)) {}
438String::String (const short number) : text (NumberToStringConverters::createFromInteger ((int) number)) {}
439String::String (const unsigned short number) : text (NumberToStringConverters::createFromInteger ((unsigned int) number)) {}
440String::String (const int64 number) : text (NumberToStringConverters::createFromInteger (number)) {}
441String::String (const uint64 number) : text (NumberToStringConverters::createFromInteger (number)) {}
442String::String (const long number) : text (NumberToStringConverters::createFromInteger (number)) {}
443String::String (const unsigned long number) : text (NumberToStringConverters::createFromInteger (number)) {}
444
445String::String (const float number) : text (NumberToStringConverters::createFromDouble ((double) number, 0)) {}
446String::String (const double number) : text (NumberToStringConverters::createFromDouble (number, 0)) {}
447String::String (const float number, const int numberOfDecimalPlaces) : text (NumberToStringConverters::createFromDouble ((double) number, numberOfDecimalPlaces)) {}
448String::String (const double number, const int numberOfDecimalPlaces) : text (NumberToStringConverters::createFromDouble (number, numberOfDecimalPlaces)) {}
449
450//==============================================================================
452{
453 return (int) text.length();
454}
455
457{
458 return (size_t) (((char*) text.findTerminatingNull().getAddress()) - (char*) text.getAddress());
459}
460
465
466water_uchar String::operator[] (int index) const noexcept
467{
468 wassert (index == 0 || (index > 0 && index <= (int) text.lengthUpTo ((size_t) index + 1)));
469 return text [index];
470}
471
472template <typename Type>
474{
475 template <typename CharPointer>
476 static Type calculate (CharPointer t) noexcept
477 {
478 Type result = Type();
479
480 while (! t.isEmpty())
481 result = ((Type) multiplier) * result + (Type) t.getAndAdvance();
482
483 return result;
484 }
485
486 enum { multiplier = sizeof (Type) > 4 ? 101 : 31 };
487};
488
492
493//==============================================================================
494bool operator== (const String& s1, const String& s2) noexcept { return s1.compare (s2) == 0; }
495bool operator!= (const String& s1, const String& s2) noexcept { return s1.compare (s2) != 0; }
496bool operator== (const String& s1, const char* s2) noexcept { return s1.compare (s2) == 0; }
497bool operator!= (const String& s1, const char* s2) noexcept { return s1.compare (s2) != 0; }
498bool operator== (const String& s1, StringRef s2) noexcept { return s1.getCharPointer().compare (s2.text) == 0; }
499bool operator!= (const String& s1, StringRef s2) noexcept { return s1.getCharPointer().compare (s2.text) != 0; }
500bool operator== (const String& s1, const CharPointer_UTF8 s2) noexcept { return s1.getCharPointer().compare (s2) == 0; }
501bool operator!= (const String& s1, const CharPointer_UTF8 s2) noexcept { return s1.getCharPointer().compare (s2) != 0; }
502bool operator> (const String& s1, const String& s2) noexcept { return s1.compare (s2) > 0; }
503bool operator< (const String& s1, const String& s2) noexcept { return s1.compare (s2) < 0; }
504bool operator>= (const String& s1, const String& s2) noexcept { return s1.compare (s2) >= 0; }
505bool operator<= (const String& s1, const String& s2) noexcept { return s1.compare (s2) <= 0; }
506
507bool String::equalsIgnoreCase (const char* const t) const noexcept
508{
509 return t != nullptr ? text.compareIgnoreCase (CharPointer_UTF8 (t)) == 0
510 : isEmpty();
511}
512
514{
515 return text.compareIgnoreCase (t.text) == 0;
516}
517
518bool String::equalsIgnoreCase (const String& other) const noexcept
519{
520 return text == other.text
521 || text.compareIgnoreCase (other.text) == 0;
522}
523
524int String::compare (const String& other) const noexcept { return (text == other.text) ? 0 : text.compare (other.text); }
525int String::compare (const char* const other) const noexcept { return text.compare (CharPointer_UTF8 (other)); }
526int String::compareIgnoreCase (const String& other) const noexcept { return (text == other.text) ? 0 : text.compareIgnoreCase (other.text); }
527
529{
530 for (int bias = 0;;)
531 {
532 const water_uchar c1 = s1.getAndAdvance();
533 const bool isDigit1 = CharacterFunctions::isDigit (c1);
534
535 const water_uchar c2 = s2.getAndAdvance();
536 const bool isDigit2 = CharacterFunctions::isDigit (c2);
537
538 if (! (isDigit1 || isDigit2)) return bias;
539 if (! isDigit1) return -1;
540 if (! isDigit2) return 1;
541
542 if (c1 != c2 && bias == 0)
543 bias = c1 < c2 ? -1 : 1;
544
545 wassert (c1 != 0 && c2 != 0);
546 }
547}
548
550{
551 for (;;)
552 {
553 const water_uchar c1 = s1.getAndAdvance();
554 const bool isDigit1 = CharacterFunctions::isDigit (c1);
555
556 const water_uchar c2 = s2.getAndAdvance();
557 const bool isDigit2 = CharacterFunctions::isDigit (c2);
558
559 if (! (isDigit1 || isDigit2)) return 0;
560 if (! isDigit1) return -1;
561 if (! isDigit2) return 1;
562 if (c1 < c2) return -1;
563 if (c1 > c2) return 1;
564 }
565}
566
567static int naturalStringCompare (CharPointer_UTF8 s1, CharPointer_UTF8 s2, bool isCaseSensitive) noexcept
568{
569 bool firstLoop = true;
570
571 for (;;)
572 {
573 const bool hasSpace1 = s1.isWhitespace();
574 const bool hasSpace2 = s2.isWhitespace();
575
576 if ((! firstLoop) && (hasSpace1 ^ hasSpace2))
577 return hasSpace2 ? 1 : -1;
578
579 firstLoop = false;
580
581 if (hasSpace1) s1 = s1.findEndOfWhitespace();
582 if (hasSpace2) s2 = s2.findEndOfWhitespace();
583
584 if (s1.isDigit() && s2.isDigit())
585 {
586 const int result = (*s1 == '0' || *s2 == '0') ? stringCompareLeft (s1, s2)
587 : stringCompareRight (s1, s2);
588
589 if (result != 0)
590 return result;
591 }
592
593 water_uchar c1 = s1.getAndAdvance();
594 water_uchar c2 = s2.getAndAdvance();
595
596 if (c1 != c2 && ! isCaseSensitive)
597 {
600 }
601
602 if (c1 == c2)
603 {
604 if (c1 == 0)
605 return 0;
606 }
607 else
608 {
609 const bool isAlphaNum1 = CharacterFunctions::isLetterOrDigit (c1);
610 const bool isAlphaNum2 = CharacterFunctions::isLetterOrDigit (c2);
611
612 if (isAlphaNum2 && ! isAlphaNum1) return -1;
613 if (isAlphaNum1 && ! isAlphaNum2) return 1;
614
615 return c1 < c2 ? -1 : 1;
616 }
617
618 wassert (c1 != 0 && c2 != 0);
619 }
620}
621
622int String::compareNatural (StringRef other, bool isCaseSensitive) const noexcept
623{
624 return naturalStringCompare (getCharPointer(), other.text, isCaseSensitive);
625}
626
627//==============================================================================
628void String::append (const String& textToAppend, size_t maxCharsToTake)
629{
630 appendCharPointer (this == &textToAppend ? String (textToAppend).text
631 : textToAppend.text, maxCharsToTake);
632}
633
635{
636 appendCharPointer (textToAppend, textToAppend.findTerminatingNull());
637}
638
639void String::appendCharPointer (const CharPointer_UTF8 startOfTextToAppend,
640 const CharPointer_UTF8 endOfTextToAppend)
641{
642 wassert (startOfTextToAppend.getAddress() != nullptr && endOfTextToAppend.getAddress() != nullptr);
643
644 const int extraBytesNeeded = getAddressDifference (endOfTextToAppend.getAddress(),
645 startOfTextToAppend.getAddress());
646 wassert (extraBytesNeeded >= 0);
647
648 if (extraBytesNeeded > 0)
649 {
650 const size_t byteOffsetOfNull = getByteOffsetOfEnd();
651 preallocateBytes (byteOffsetOfNull + (size_t) extraBytesNeeded);
652
653 CharPointer_UTF8::CharType* const newStringStart = addBytesToPointer (text.getAddress(), (int) byteOffsetOfNull);
654 memcpy (newStringStart, startOfTextToAppend.getAddress(), (size_t) extraBytesNeeded);
655 CharPointer_UTF8 (addBytesToPointer (newStringStart, extraBytesNeeded)).writeNull();
656 }
657}
658
659String& String::operator+= (const char* const t)
660{
661 appendCharPointer (CharPointer_UTF8 (t)); // (using UTF8 here triggers a faster code-path than ascii)
662 return *this;
663}
664
666{
667 if (isEmpty())
668 return operator= (other);
669
670 if (this == &other)
671 return operator+= (String (*this));
672
673 appendCharPointer (other.text);
674 return *this;
675}
676
678{
679 return operator+= (String (other));
680}
681
683{
684 const char asString[] = { ch, 0 };
685 return operator+= (asString);
686}
687
689{
690 return operator+= (charToString(ch));
691}
692
694{
695 template <typename T>
696 inline String& operationAddAssign (String& str, const T number)
697 {
698 char buffer [(sizeof(T) * 8) / 2];
699 char* end = buffer + numElementsInArray (buffer);
701
703 return str;
704 }
705}
706
707String& String::operator+= (const int number) { return StringHelpers::operationAddAssign<int> (*this, number); }
710
711//==============================================================================
712String operator+ (const char* const s1, const String& s2) { String s (s1); return s += s2; }
713String operator+ (const char s1, const String& s2) { return String::charToString ((water_uchar) (uint8) s1) + s2; }
714String operator+ (String s1, const String& s2) { return s1 += s2; }
715String operator+ (String s1, const char* const s2) { return s1 += s2; }
716String operator+ (String s1, const char s2) { return s1 += s2; }
717
718String operator+ (const water_uchar s1, const String& s2) { return String::charToString (s1) + s2; }
719String operator+ (String s1, const water_uchar s2) { return s1 += s2; }
720String& operator<< (String& s1, const water_uchar s2) { return s1 += s2; }
721
722String& operator<< (String& s1, const char s2) { return s1 += s2; }
723String& operator<< (String& s1, const char* const s2) { return s1 += s2; }
724String& operator<< (String& s1, const String& s2) { return s1 += s2; }
725String& operator<< (String& s1, StringRef s2) { return s1 += s2; }
726
727String& operator<< (String& s1, const int number) { return s1 += number; }
728String& operator<< (String& s1, const short number) { return s1 += (int) number; }
729String& operator<< (String& s1, const unsigned short number) { return s1 += (uint64) number; }
730String& operator<< (String& s1, const long number) { return s1 += String (number); }
731String& operator<< (String& s1, const unsigned long number) { return s1 += String (number); }
732String& operator<< (String& s1, const int64 number) { return s1 += String (number); }
733String& operator<< (String& s1, const uint64 number) { return s1 += String (number); }
734String& operator<< (String& s1, const float number) { return s1 += String (number); }
735String& operator<< (String& s1, const double number) { return s1 += String (number); }
736
738{
739 return operator<< (stream, StringRef (text));
740}
741
743{
744 const size_t numBytes = CharPointer_UTF8::getBytesRequiredFor (text.text);
745
746 stream.write (text.text.getAddress(), numBytes);
747 return stream;
748}
749
750//==============================================================================
751int String::indexOfChar (const water_uchar character) const noexcept
752{
753 return text.indexOf (character);
754}
755
756int String::indexOfChar (const int startIndex, const water_uchar character) const noexcept
757{
759
760 for (int i = 0; ! t.isEmpty(); ++i)
761 {
762 if (i >= startIndex)
763 {
764 if (t.getAndAdvance() == character)
765 return i;
766 }
767 else
768 {
769 ++t;
770 }
771 }
772
773 return -1;
774}
775
776int String::lastIndexOfChar (const water_uchar character) const noexcept
777{
779 int last = -1;
780
781 for (int i = 0; ! t.isEmpty(); ++i)
782 if (t.getAndAdvance() == character)
783 last = i;
784
785 return last;
786}
787
788int String::indexOfAnyOf (StringRef charactersToLookFor, const int startIndex, const bool ignoreCase) const noexcept
789{
791
792 for (int i = 0; ! t.isEmpty(); ++i)
793 {
794 if (i >= startIndex)
795 {
796 if (charactersToLookFor.text.indexOf (t.getAndAdvance(), ignoreCase) >= 0)
797 return i;
798 }
799 else
800 {
801 ++t;
802 }
803 }
804
805 return -1;
806}
807
808int String::indexOf (StringRef other) const noexcept
809{
810 return other.isEmpty() ? 0 : text.indexOf (other.text);
811}
812
813int String::indexOfIgnoreCase (StringRef other) const noexcept
814{
815 return other.isEmpty() ? 0 : CharacterFunctions::indexOfIgnoreCase (text, other.text);
816}
817
818int String::indexOf (const int startIndex, StringRef other) const noexcept
819{
820 if (other.isEmpty())
821 return -1;
822
824
825 for (int i = startIndex; --i >= 0;)
826 {
827 if (t.isEmpty())
828 return -1;
829
830 ++t;
831 }
832
833 int found = t.indexOf (other.text);
834 if (found >= 0)
835 found += startIndex;
836 return found;
837}
838
839int String::indexOfIgnoreCase (const int startIndex, StringRef other) const noexcept
840{
841 if (other.isEmpty())
842 return -1;
843
845
846 for (int i = startIndex; --i >= 0;)
847 {
848 if (t.isEmpty())
849 return -1;
850
851 ++t;
852 }
853
854 int found = CharacterFunctions::indexOfIgnoreCase (t, other.text);
855 if (found >= 0)
856 found += startIndex;
857 return found;
858}
859
860int String::lastIndexOf (StringRef other) const noexcept
861{
862 if (other.isNotEmpty())
863 {
864 const int len = other.length();
865 int i = length() - len;
866
867 if (i >= 0)
868 {
869 for (CharPointer_UTF8 n (text + i); i >= 0; --i)
870 {
871 if (n.compareUpTo (other.text, len) == 0)
872 return i;
873
874 --n;
875 }
876 }
877 }
878
879 return -1;
880}
881
882int String::lastIndexOfIgnoreCase (StringRef other) const noexcept
883{
884 if (other.isNotEmpty())
885 {
886 const int len = other.length();
887 int i = length() - len;
888
889 if (i >= 0)
890 {
891 for (CharPointer_UTF8 n (text + i); i >= 0; --i)
892 {
893 if (n.compareIgnoreCaseUpTo (other.text, len) == 0)
894 return i;
895
896 --n;
897 }
898 }
899 }
900
901 return -1;
902}
903
904int String::lastIndexOfAnyOf (StringRef charactersToLookFor, const bool ignoreCase) const noexcept
905{
907 int last = -1;
908
909 for (int i = 0; ! t.isEmpty(); ++i)
910 if (charactersToLookFor.text.indexOf (t.getAndAdvance(), ignoreCase) >= 0)
911 last = i;
912
913 return last;
914}
915
916bool String::contains (StringRef other) const noexcept
917{
918 return indexOf (other) >= 0;
919}
920
921bool String::containsChar (const water_uchar character) const noexcept
922{
923 return text.indexOf (character) >= 0;
924}
925
927{
928 return indexOfIgnoreCase (t) >= 0;
929}
930
932{
933 if (word.isNotEmpty())
934 {
936 const int wordLen = word.length();
937 const int end = (int) t.length() - wordLen;
938
939 for (int i = 0; i <= end; ++i)
940 {
941 if (t.compareUpTo (word.text, wordLen) == 0
942 && (i == 0 || ! (t - 1).isLetterOrDigit())
943 && ! (t + wordLen).isLetterOrDigit())
944 return i;
945
946 ++t;
947 }
948 }
949
950 return -1;
951}
952
954{
955 if (word.isNotEmpty())
956 {
958 const int wordLen = word.length();
959 const int end = (int) t.length() - wordLen;
960
961 for (int i = 0; i <= end; ++i)
962 {
963 if (t.compareIgnoreCaseUpTo (word.text, wordLen) == 0
964 && (i == 0 || ! (t - 1).isLetterOrDigit())
965 && ! (t + wordLen).isLetterOrDigit())
966 return i;
967
968 ++t;
969 }
970 }
971
972 return -1;
973}
974
975bool String::containsWholeWord (StringRef wordToLookFor) const noexcept
976{
977 return indexOfWholeWord (wordToLookFor) >= 0;
978}
979
980bool String::containsWholeWordIgnoreCase (StringRef wordToLookFor) const noexcept
981{
982 return indexOfWholeWordIgnoreCase (wordToLookFor) >= 0;
983}
984
985//==============================================================================
986template <typename CharPointer>
988{
989 static bool matches (CharPointer wildcard, CharPointer test, const bool ignoreCase) noexcept
990 {
991 for (;;)
992 {
993 const water_uchar wc = wildcard.getAndAdvance();
994
995 if (wc == '*')
996 return wildcard.isEmpty() || matchesAnywhere (wildcard, test, ignoreCase);
997
998 if (! characterMatches (wc, test.getAndAdvance(), ignoreCase))
999 return false;
1000
1001 if (wc == 0)
1002 return true;
1003 }
1004 }
1005
1006 static bool characterMatches (const water_uchar wc, const water_uchar tc, const bool ignoreCase) noexcept
1007 {
1008 return (wc == tc) || (wc == '?' && tc != 0)
1010 }
1011
1012 static bool matchesAnywhere (const CharPointer wildcard, CharPointer test, const bool ignoreCase) noexcept
1013 {
1014 for (; ! test.isEmpty(); ++test)
1015 if (matches (wildcard, test, ignoreCase))
1016 return true;
1017
1018 return false;
1019 }
1020};
1021
1022bool String::matchesWildcard (StringRef wildcard, const bool ignoreCase) const noexcept
1023{
1024 return WildCardMatcher<CharPointer_UTF8>::matches (wildcard.text, text, ignoreCase);
1025}
1026
1027//==============================================================================
1028String String::repeatedString (StringRef stringToRepeat, int numberOfTimesToRepeat)
1029{
1030 if (numberOfTimesToRepeat <= 0)
1031 return String();
1032
1033 String result (PreallocationBytes (findByteOffsetOfEnd (stringToRepeat) * (size_t) numberOfTimesToRepeat));
1034 CharPointer_UTF8 n (result.text);
1035
1036 while (--numberOfTimesToRepeat >= 0)
1037 n.writeAll (stringToRepeat.text);
1038
1039 return result;
1040}
1041
1042String String::paddedLeft (const water_uchar padCharacter, int minimumLength) const
1043{
1044 wassert (padCharacter != 0);
1045
1046 int extraChars = minimumLength;
1047 CharPointer_UTF8 end (text);
1048
1049 while (! end.isEmpty())
1050 {
1051 --extraChars;
1052 ++end;
1053 }
1054
1055 if (extraChars <= 0 || padCharacter == 0)
1056 return *this;
1057
1058 const size_t currentByteSize = (size_t) (((char*) end.getAddress()) - (char*) text.getAddress());
1059 String result (PreallocationBytes (currentByteSize + (size_t) extraChars * CharPointer_UTF8::getBytesRequiredFor (padCharacter)));
1060 CharPointer_UTF8 n (result.text);
1061
1062 while (--extraChars >= 0)
1063 n.write (padCharacter);
1064
1065 n.writeAll (text);
1066 return result;
1067}
1068
1069String String::paddedRight (const water_uchar padCharacter, int minimumLength) const
1070{
1071 CARLA_SAFE_ASSERT_RETURN (padCharacter != 0, *this);
1072
1073 int extraChars = minimumLength;
1074 CharPointer_UTF8 end (text);
1075
1076 while (! end.isEmpty())
1077 {
1078 --extraChars;
1079 ++end;
1080 }
1081
1082 if (extraChars <= 0 || padCharacter == 0)
1083 return *this;
1084
1085 const size_t currentByteSize = (size_t) (((char*) end.getAddress()) - (char*) text.getAddress());
1086 String result (PreallocationBytes (currentByteSize + (size_t) extraChars * CharPointer_UTF8::getBytesRequiredFor (padCharacter)));
1087 CharPointer_UTF8 n (result.text);
1088
1089 n.writeAll (text);
1090
1091 while (--extraChars >= 0)
1092 n.write (padCharacter);
1093
1094 n.writeNull();
1095 return result;
1096}
1097
1098//==============================================================================
1099String String::replaceSection (int index, int numCharsToReplace, StringRef stringToInsert) const
1100{
1101 if (index < 0)
1102 {
1103 // a negative index to replace from?
1105 index = 0;
1106 }
1107
1108 if (numCharsToReplace < 0)
1109 {
1110 // replacing a negative number of characters?
1111 numCharsToReplace = 0;
1113 }
1114
1115 CharPointer_UTF8 insertPoint (text);
1116
1117 for (int i = 0; i < index; ++i)
1118 {
1119 if (insertPoint.isEmpty())
1120 {
1121 // replacing beyond the end of the string?
1123 return *this + stringToInsert;
1124 }
1125
1126 ++insertPoint;
1127 }
1128
1129 CharPointer_UTF8 startOfRemainder (insertPoint);
1130
1131 for (int i = 0; i < numCharsToReplace && ! startOfRemainder.isEmpty(); ++i)
1132 ++startOfRemainder;
1133
1134 if (insertPoint == text && startOfRemainder.isEmpty())
1135 return stringToInsert.text;
1136
1137 const size_t initialBytes = (size_t) (((char*) insertPoint.getAddress()) - (char*) text.getAddress());
1138 const size_t newStringBytes = findByteOffsetOfEnd (stringToInsert);
1139 const size_t remainderBytes = (size_t) (((char*) startOfRemainder.findTerminatingNull().getAddress()) - (char*) startOfRemainder.getAddress());
1140
1141 const size_t newTotalBytes = initialBytes + newStringBytes + remainderBytes;
1142 if (newTotalBytes <= 0)
1143 return String();
1144
1145 String result (PreallocationBytes ((size_t) newTotalBytes));
1146
1147 char* dest = (char*) result.text.getAddress();
1148 memcpy (dest, text.getAddress(), initialBytes);
1149 dest += initialBytes;
1150 memcpy (dest, stringToInsert.text.getAddress(), newStringBytes);
1151 dest += newStringBytes;
1152 memcpy (dest, startOfRemainder.getAddress(), remainderBytes);
1153 dest += remainderBytes;
1155
1156 return result;
1157}
1158
1159String String::replace (StringRef stringToReplace, StringRef stringToInsert, const bool ignoreCase) const
1160{
1161 const int stringToReplaceLen = stringToReplace.length();
1162 const int stringToInsertLen = stringToInsert.length();
1163
1164 int i = 0;
1165 String result (*this);
1166
1167 while ((i = (ignoreCase ? result.indexOfIgnoreCase (i, stringToReplace)
1168 : result.indexOf (i, stringToReplace))) >= 0)
1169 {
1170 result = result.replaceSection (i, stringToReplaceLen, stringToInsert);
1171 i += stringToInsertLen;
1172 }
1173
1174 return result;
1175}
1176
1178{
1179public:
1180 StringCreationHelper (const size_t initialBytes)
1181 : source (nullptr), dest (nullptr), allocatedBytes (initialBytes), bytesWritten (0)
1182 {
1183 result.preallocateBytes (allocatedBytes);
1184 dest = result.getCharPointer();
1185 }
1186
1188 : source (s), dest (nullptr), allocatedBytes (StringHolder::getAllocatedNumBytes (s)), bytesWritten (0)
1189 {
1190 result.preallocateBytes (allocatedBytes);
1191 dest = result.getCharPointer();
1192 }
1193
1195 {
1197
1199 {
1200 allocatedBytes += jmax ((size_t) 8, allocatedBytes / 16);
1201 const size_t destOffset = (size_t) (((char*) dest.getAddress()) - (char*) result.getCharPointer().getAddress());
1202 result.preallocateBytes (allocatedBytes);
1203 dest = addBytesToPointer (result.getCharPointer().getAddress(), (int) destOffset);
1204 }
1205
1206 dest.write (c);
1207 }
1208
1211
1212private:
1215};
1216
1217String String::replaceCharacter (const water_uchar charToReplace, const water_uchar charToInsert) const
1218{
1219 if (! containsChar (charToReplace))
1220 return *this;
1221
1222 StringCreationHelper builder (text);
1223
1224 for (;;)
1225 {
1226 water_uchar c = builder.source.getAndAdvance();
1227
1228 if (c == charToReplace)
1229 c = charToInsert;
1230
1231 builder.write (c);
1232
1233 if (c == 0)
1234 break;
1235 }
1236
1237 return builder.result;
1238}
1239
1240String String::replaceCharacters (StringRef charactersToReplace, StringRef charactersToInsertInstead) const
1241{
1242 // Each character in the first string must have a matching one in the
1243 // second, so the two strings must be the same length.
1244 wassert (charactersToReplace.length() == charactersToInsertInstead.length());
1245
1246 StringCreationHelper builder (text);
1247
1248 for (;;)
1249 {
1250 water_uchar c = builder.source.getAndAdvance();
1251
1252 const int index = charactersToReplace.text.indexOf (c);
1253 if (index >= 0)
1254 c = charactersToInsertInstead [index];
1255
1256 builder.write (c);
1257
1258 if (c == 0)
1259 break;
1260 }
1261
1262 return builder.result;
1263}
1264
1265//==============================================================================
1266bool String::startsWith (StringRef other) const noexcept
1267{
1268 return text.compareUpTo (other.text, other.length()) == 0;
1269}
1270
1271bool String::startsWithIgnoreCase (StringRef other) const noexcept
1272{
1273 return text.compareIgnoreCaseUpTo (other.text, other.length()) == 0;
1274}
1275
1276bool String::startsWithChar (const water_uchar character) const noexcept
1277{
1278 // strings can't contain a null character!
1279 CARLA_SAFE_ASSERT_RETURN (character != 0, false);
1280
1281 return *text == character;
1282}
1283
1284bool String::endsWithChar (const water_uchar character) const noexcept
1285{
1286 // strings can't contain a null character!
1287 CARLA_SAFE_ASSERT_RETURN (character != 0, false);
1288
1289 if (text.isEmpty())
1290 return false;
1291
1292 CharPointer_UTF8 t (text.findTerminatingNull());
1293 return *--t == character;
1294}
1295
1296bool String::endsWith (StringRef other) const noexcept
1297{
1298 CharPointer_UTF8 end (text.findTerminatingNull());
1299 CharPointer_UTF8 otherEnd (other.text.findTerminatingNull());
1300
1301 while (end > text && otherEnd > other.text)
1302 {
1303 --end;
1304 --otherEnd;
1305
1306 if (*end != *otherEnd)
1307 return false;
1308 }
1309
1310 return otherEnd == other.text;
1311}
1312
1313bool String::endsWithIgnoreCase (StringRef other) const noexcept
1314{
1315 CharPointer_UTF8 end (text.findTerminatingNull());
1316 CharPointer_UTF8 otherEnd (other.text.findTerminatingNull());
1317
1318 while (end > text && otherEnd > other.text)
1319 {
1320 --end;
1321 --otherEnd;
1322
1323 if (end.toLowerCase() != otherEnd.toLowerCase())
1324 return false;
1325 }
1326
1327 return otherEnd == other.text;
1328}
1329
1330//==============================================================================
1332{
1333 StringCreationHelper builder (text);
1334
1335 for (;;)
1336 {
1337 const water_uchar c = builder.source.toUpperCase();
1338 builder.write (c);
1339
1340 if (c == 0)
1341 break;
1342
1343 ++(builder.source);
1344 }
1345
1346 return builder.result;
1347}
1348
1350{
1351 StringCreationHelper builder (text);
1352
1353 for (;;)
1354 {
1355 const water_uchar c = builder.source.toLowerCase();
1356 builder.write (c);
1357
1358 if (c == 0)
1359 break;
1360
1361 ++(builder.source);
1362 }
1363
1364 return builder.result;
1365}
1366
1367//==============================================================================
1372
1373String String::substring (int start, const int end) const
1374{
1375 if (start < 0)
1376 start = 0;
1377
1378 if (end <= start)
1379 return String();
1380
1381 int i = 0;
1383
1384 while (i < start)
1385 {
1386 if (t1.isEmpty())
1387 return String();
1388
1389 ++i;
1390 ++t1;
1391 }
1392
1393 CharPointer_UTF8 t2 (t1);
1394 while (i < end)
1395 {
1396 if (t2.isEmpty())
1397 {
1398 if (start == 0)
1399 return *this;
1400
1401 break;
1402 }
1403
1404 ++i;
1405 ++t2;
1406 }
1407
1408 return String (t1, t2);
1409}
1410
1412{
1413 if (start <= 0)
1414 return *this;
1415
1417
1418 while (--start >= 0)
1419 {
1420 if (t.isEmpty())
1421 return String();
1422
1423 ++t;
1424 }
1425
1426 return String (t);
1427}
1428
1429String String::dropLastCharacters (const int numberToDrop) const
1430{
1431 return String (text, (size_t) jmax (0, length() - numberToDrop));
1432}
1433
1434String String::getLastCharacters (const int numCharacters) const
1435{
1436 return String (text + jmax (0, length() - jmax (0, numCharacters)));
1437}
1438
1440 const bool includeSubString,
1441 const bool ignoreCase) const
1442{
1443 const int i = ignoreCase ? indexOfIgnoreCase (sub)
1444 : indexOf (sub);
1445 if (i < 0)
1446 return String();
1447
1448 return substring (includeSubString ? i : i + sub.length());
1449}
1450
1452 const bool includeSubString,
1453 const bool ignoreCase) const
1454{
1455 const int i = ignoreCase ? lastIndexOfIgnoreCase (sub)
1456 : lastIndexOf (sub);
1457 if (i < 0)
1458 return *this;
1459
1460 return substring (includeSubString ? i : i + sub.length());
1461}
1462
1464 const bool includeSubString,
1465 const bool ignoreCase) const
1466{
1467 const int i = ignoreCase ? indexOfIgnoreCase (sub)
1468 : indexOf (sub);
1469 if (i < 0)
1470 return *this;
1471
1472 return substring (0, includeSubString ? i + sub.length() : i);
1473}
1474
1476 const bool includeSubString,
1477 const bool ignoreCase) const
1478{
1479 const int i = ignoreCase ? lastIndexOfIgnoreCase (sub)
1480 : lastIndexOf (sub);
1481 if (i < 0)
1482 return *this;
1483
1484 return substring (0, includeSubString ? i + sub.length() : i);
1485}
1486
1488{
1489 const water_uchar trimmedStart = trimStart()[0];
1490
1491 return trimmedStart == '"'
1492 || trimmedStart == '\'';
1493}
1494
1496{
1497 const int len = length();
1498
1499 if (len == 0)
1500 return String();
1501
1502 const water_uchar lastChar = text [len - 1];
1503 const int dropAtStart = (*text == '"' || *text == '\'') ? 1 : 0;
1504 const int dropAtEnd = (lastChar == '"' || lastChar == '\'') ? 1 : 0;
1505
1506 return substring (dropAtStart, len - dropAtEnd);
1507}
1508
1509String String::quoted (water_uchar quoteCharacter) const
1510{
1511 if (isEmpty())
1512 return charToString (quoteCharacter) + quoteCharacter;
1513
1514 String t (*this);
1515
1516 if (! t.startsWithChar (quoteCharacter))
1517 t = charToString (quoteCharacter) + t;
1518
1519 if (! t.endsWithChar (quoteCharacter))
1520 t += quoteCharacter;
1521
1522 return t;
1523}
1524
1525//==============================================================================
1527{
1528 while (end > start)
1529 {
1530 if (! (--end).isWhitespace())
1531 {
1532 ++end;
1533 break;
1534 }
1535 }
1536
1537 return end;
1538}
1539
1541{
1542 if (isNotEmpty())
1543 {
1544 CharPointer_UTF8 start (text.findEndOfWhitespace());
1545
1546 const CharPointer_UTF8 end (start.findTerminatingNull());
1547 CharPointer_UTF8 trimmedEnd (findTrimmedEnd (start, end));
1548
1549 if (trimmedEnd <= start)
1550 return String();
1551
1552 if (text < start || trimmedEnd < end)
1553 return String (start, trimmedEnd);
1554 }
1555
1556 return *this;
1557}
1558
1560{
1561 if (isNotEmpty())
1562 {
1563 const CharPointer_UTF8 t (text.findEndOfWhitespace());
1564
1565 if (t != text)
1566 return String (t);
1567 }
1568
1569 return *this;
1570}
1571
1573{
1574 if (isNotEmpty())
1575 {
1576 const CharPointer_UTF8 end (text.findTerminatingNull());
1577 CharPointer_UTF8 trimmedEnd (findTrimmedEnd (text, end));
1578
1579 if (trimmedEnd < end)
1580 return String (text, trimmedEnd);
1581 }
1582
1583 return *this;
1584}
1585
1587{
1589
1590 while (charactersToTrim.text.indexOf (*t) >= 0)
1591 ++t;
1592
1593 return t == text ? *this : String (t);
1594}
1595
1597{
1598 if (isNotEmpty())
1599 {
1600 const CharPointer_UTF8 end (text.findTerminatingNull());
1601 CharPointer_UTF8 trimmedEnd (end);
1602
1603 while (trimmedEnd > text)
1604 {
1605 if (charactersToTrim.text.indexOf (*--trimmedEnd) < 0)
1606 {
1607 ++trimmedEnd;
1608 break;
1609 }
1610 }
1611
1612 if (trimmedEnd < end)
1613 return String (text, trimmedEnd);
1614 }
1615
1616 return *this;
1617}
1618
1619//==============================================================================
1621{
1622 if (isEmpty())
1623 return String();
1624
1625 StringCreationHelper builder (text);
1626
1627 for (;;)
1628 {
1629 water_uchar c = builder.source.getAndAdvance();
1630
1631 if (charactersToRetain.text.indexOf (c) >= 0)
1632 builder.write (c);
1633
1634 if (c == 0)
1635 break;
1636 }
1637
1638 builder.write (0);
1639 return builder.result;
1640}
1641
1643{
1644 if (isEmpty())
1645 return String();
1646
1647 StringCreationHelper builder (text);
1648
1649 for (;;)
1650 {
1651 water_uchar c = builder.source.getAndAdvance();
1652
1653 if (charactersToRemove.text.indexOf (c) < 0)
1654 builder.write (c);
1655
1656 if (c == 0)
1657 break;
1658 }
1659
1660 return builder.result;
1661}
1662
1664{
1665 for (CharPointer_UTF8 t (text); ! t.isEmpty(); ++t)
1666 if (permittedCharacters.text.indexOf (*t) < 0)
1667 return String (text, t);
1668
1669 return *this;
1670}
1671
1673{
1674 for (CharPointer_UTF8 t (text); ! t.isEmpty(); ++t)
1675 if (charactersToStopAt.text.indexOf (*t) >= 0)
1676 return String (text, t);
1677
1678 return *this;
1679}
1680
1681bool String::containsOnly (StringRef chars) const noexcept
1682{
1683 for (CharPointer_UTF8 t (text); ! t.isEmpty();)
1684 if (chars.text.indexOf (t.getAndAdvance()) < 0)
1685 return false;
1686
1687 return true;
1688}
1689
1690bool String::containsAnyOf (StringRef chars) const noexcept
1691{
1692 for (CharPointer_UTF8 t (text); ! t.isEmpty();)
1693 if (chars.text.indexOf (t.getAndAdvance()) >= 0)
1694 return true;
1695
1696 return false;
1697}
1698
1700{
1701 for (CharPointer_UTF8 t (text); ! t.isEmpty(); ++t)
1702 if (! t.isWhitespace())
1703 return true;
1704
1705 return false;
1706}
1707
1708//=====================================================================================================================
1709static String getStringFromWindows1252Codepage (const char* data, size_t num)
1710{
1711 HeapBlock<char> unicode;
1712 CARLA_SAFE_ASSERT_RETURN(unicode.malloc(num + 1), String());
1713
1714 for (size_t i = 0; i < num; ++i)
1716
1717 unicode[num] = 0;
1718 return CharPointer_UTF8 (unicode);
1719}
1720
1721String String::createStringFromData (const void* const unknownData, int size)
1722{
1723 const uint8* const data = static_cast<const uint8*> (unknownData);
1724
1725 if (size <= 0 || data == nullptr)
1726 return String();
1727
1728 if (size == 1)
1729 return charToString ((water_uchar) data[0]);
1730
1731 const char* start = (const char*) data;
1732
1734 {
1735 start += 3;
1736 size -= 3;
1737 }
1738
1740 return String (CharPointer_UTF8 (start),
1742
1743 return getStringFromWindows1252Codepage (start, (size_t) size);
1744}
1745
1746// Note! The format parameter here MUST NOT be a reference, otherwise MS's va_start macro fails to work (but still compiles).
1748{
1749 size_t bufferSize = 256;
1750
1751 HeapBlock<char> temp;
1752 CARLA_SAFE_ASSERT_RETURN(temp.malloc(bufferSize), String());
1753
1754 for (;;)
1755 {
1756 va_list args;
1757 va_start (args, pf);
1758
1759 // FIXME - needed?
1760 temp.clear (bufferSize);
1761
1762 const int num = vsnprintf (temp.getData(), bufferSize - 1, pf.toRawUTF8(), args);
1763
1764 va_end (args);
1765
1766 if (num > 0)
1767 return String (temp);
1768
1769 bufferSize += 256;
1770
1771 if (num == 0 || bufferSize > 65536) // the upper limit is a sanity check to avoid situations where vsnprintf repeatedly
1772 break; // returns -1 because of an error rather than because it needs more space.
1773
1774 temp.realloc (bufferSize);
1775 }
1776
1777 return String();
1778}
1779
1780//==============================================================================
1781int String::getIntValue() const noexcept { return text.getIntValue32(); }
1782int64 String::getLargeIntValue() const noexcept { return text.getIntValue64(); }
1784double String::getDoubleValue() const noexcept { return text.getDoubleValue(); }
1785
1787{
1788 int n = 0;
1789 int mult = 1;
1790 CharPointer_UTF8 t (text.findTerminatingNull());
1791
1792 while (--t >= text)
1793 {
1794 if (! t.isDigit())
1795 {
1796 if (*t == '-')
1797 n = -n;
1798
1799 break;
1800 }
1801
1802 n += mult * (*t - '0');
1803 mult *= 10;
1804 }
1805
1806 return n;
1807}
1808
1809static const char hexDigits[] = "0123456789abcdef";
1810
1811template <typename Type>
1812static String hexToString (Type v)
1813{
1814 CharPointer_UTF8::CharType buffer[32];
1815 CharPointer_UTF8::CharType* const end = buffer + numElementsInArray (buffer) - 1;
1817 *t = 0;
1818
1819 do
1820 {
1821 *--t = hexDigits [(int) (v & 15)];
1822 v >>= 4;
1823
1824 } while (v != 0);
1825
1826 return String (CharPointer_UTF8 (t),
1827 CharPointer_UTF8 (end));
1828}
1829
1830String String::toHexString (int number) { return hexToString ((unsigned int) number); }
1831String String::toHexString (int64 number) { return hexToString ((uint64) number); }
1832String String::toHexString (short number) { return toHexString ((int) (unsigned short) number); }
1833
1834String String::toHexString (const void* const d, const int size, const int groupSize)
1835{
1836 if (size <= 0)
1837 return String();
1838
1839 int numChars = (size * 2) + 2;
1840 if (groupSize > 0)
1841 numChars += size / groupSize;
1842
1843 String s (PreallocationBytes (sizeof (CharPointer_UTF8::CharType) * (size_t) numChars));
1844
1845 const unsigned char* data = static_cast<const unsigned char*> (d);
1846 CharPointer_UTF8 dest (s.text);
1847
1848 for (int i = 0; i < size; ++i)
1849 {
1850 const unsigned char nextByte = *data++;
1851 dest.write ((water_uchar) hexDigits [nextByte >> 4]);
1852 dest.write ((water_uchar) hexDigits [nextByte & 0xf]);
1853
1854 if (groupSize > 0 && (i % groupSize) == (groupSize - 1) && i < (size - 1))
1855 dest.write ((water_uchar) ' ');
1856 }
1857
1858 dest.writeNull();
1859 return s;
1860}
1861
1864
1865//==============================================================================
1866static const water_uchar emptyChar = 0;
1867
1868template <class CharPointerType_Src, class CharPointerType_Dest>
1870{
1871 static CharPointerType_Dest convert (const String& s)
1872 {
1873 String& source = const_cast<String&> (s);
1874
1875 typedef typename CharPointerType_Dest::CharType DestChar;
1876
1877 if (source.isEmpty())
1878 return CharPointerType_Dest (reinterpret_cast<const DestChar*> (&emptyChar));
1879
1880 CharPointerType_Src text (source.getCharPointer());
1881 const size_t extraBytesNeeded = CharPointerType_Dest::getBytesRequiredFor (text) + sizeof (typename CharPointerType_Dest::CharType);
1882 const size_t endOffset = (text.sizeInBytes() + 3) & ~3u; // the new string must be word-aligned or many Windows
1883 // functions will fail to read it correctly!
1884 source.preallocateBytes (endOffset + extraBytesNeeded);
1885 text = source.getCharPointer();
1886
1887 void* const newSpace = addBytesToPointer (text.getAddress(), (int) endOffset);
1888 const CharPointerType_Dest extraSpace (static_cast<DestChar*> (newSpace));
1889
1890 #ifdef DEBUG // (This just avoids spurious warnings from valgrind about the uninitialised bytes at the end of the buffer..)
1891 const size_t bytesToClear = (size_t) jmin ((int) extraBytesNeeded, 4);
1892 zeromem (addBytesToPointer (newSpace, extraBytesNeeded - bytesToClear), bytesToClear);
1893 #endif
1894
1895 CharPointerType_Dest (extraSpace).writeAll (text);
1896 return extraSpace;
1897 }
1898};
1899
1900template <>
1902{
1903 static CharPointer_UTF8 convert (const String& source) noexcept { return CharPointer_UTF8 ((CharPointer_UTF8::CharType*) source.getCharPointer().getAddress()); }
1904};
1905
1907
1908#ifdef CARLA_OS_WIN
1909std::wstring String::toUTF16() const
1910{
1911 if (isEmpty())
1912 return L"";
1913
1914 const int len = MultiByteToWideChar (CP_UTF8, 0, toUTF8(), length() + 1, nullptr, 0);
1915 CARLA_SAFE_ASSERT_RETURN(len > 0, L"");
1916
1917 std::wstring ret;
1918 ret.resize(len);
1919
1920 MultiByteToWideChar (CP_UTF8, 0, toUTF8(), length(), &ret[0], len);
1921 return ret;
1922}
1923#endif
1924
1925const char* String::toRawUTF8() const
1926{
1927 return toUTF8().getAddress();
1928}
1929
1930std::string String::toStdString() const
1931{
1932 return std::string (toRawUTF8());
1933}
1934
1935//==============================================================================
1936template <class CharPointerType_Src, class CharPointerType_Dest>
1938{
1939 static size_t copyToBuffer (const CharPointerType_Src source, typename CharPointerType_Dest::CharType* const buffer, const size_t maxBufferSizeBytes)
1940 {
1941 wassert (((ssize_t) maxBufferSizeBytes) >= 0); // keep this value positive!
1942
1943 if (buffer == nullptr)
1944 return CharPointerType_Dest::getBytesRequiredFor (source) + sizeof (typename CharPointerType_Dest::CharType);
1945
1946 return CharPointerType_Dest (buffer).writeWithDestByteLimit (source, maxBufferSizeBytes);
1947 }
1948};
1949
1950size_t String::copyToUTF8 (CharPointer_UTF8::CharType* const buffer, size_t maxBufferSizeBytes) const noexcept
1951{
1952 return StringCopier<CharPointer_UTF8, CharPointer_UTF8>::copyToBuffer (text, buffer, maxBufferSizeBytes);
1953}
1954
1955//==============================================================================
1960
1961String String::fromUTF8 (const char* const buffer, int bufferSizeBytes)
1962{
1963 if (buffer != nullptr)
1964 {
1965 if (bufferSizeBytes < 0)
1966 return String (CharPointer_UTF8 (buffer));
1967
1968 if (bufferSizeBytes > 0)
1969 {
1970 wassert (CharPointer_UTF8::isValidString (buffer, bufferSizeBytes));
1971 return String (CharPointer_UTF8 (buffer), CharPointer_UTF8 (buffer + bufferSizeBytes));
1972 }
1973 }
1974
1975 return String();
1976}
1977
1978#ifdef CARLA_OS_MAC
1979
1980String String::convertToPrecomposedUnicode() const
1981{
1982#if 0
1983 UnicodeMapping map;
1984
1985 map.unicodeEncoding = CreateTextEncoding (kTextEncodingUnicodeDefault,
1986 kUnicodeNoSubset,
1987 kTextEncodingDefaultFormat);
1988
1989 map.otherEncoding = CreateTextEncoding (kTextEncodingUnicodeDefault,
1990 kUnicodeCanonicalCompVariant,
1991 kTextEncodingDefaultFormat);
1992
1993 map.mappingVersion = kUnicodeUseLatestMapping;
1994
1995 UnicodeToTextInfo conversionInfo = 0;
1996 String result;
1997
1998 if (CreateUnicodeToTextInfo (&map, &conversionInfo) == noErr)
1999 {
2000 const size_t bytesNeeded = CharPointer_UTF16::getBytesRequiredFor (getCharPointer());
2001
2002 HeapBlock<char> tempOut;
2003 tempOut.calloc (bytesNeeded + 4);
2004
2005 ByteCount bytesRead = 0;
2006 ByteCount outputBufferSize = 0;
2007
2008 if (ConvertFromUnicodeToText (conversionInfo,
2009 bytesNeeded, (ConstUniCharArrayPtr) toUTF16().getAddress(),
2010 kUnicodeDefaultDirectionMask,
2011 0, 0, 0, 0,
2012 bytesNeeded, &bytesRead,
2013 &outputBufferSize, tempOut) == noErr)
2014 {
2015 result = String (CharPointer_UTF16 ((CharPointer_UTF16::CharType*) tempOut.getData()));
2016 }
2017
2018 DisposeUnicodeToTextInfo (&conversionInfo);
2019 }
2020
2021 return result;
2022#else
2023 return *this;
2024#endif
2025}
2026#endif
2027
2028//==============================================================================
2030{
2031}
2032
2033StringRef::StringRef (const char* stringLiteral) noexcept
2034 : text (stringLiteral)
2035{
2036 wassert (stringLiteral != nullptr); // This must be a valid string literal, not a null pointer!!
2037
2038 /* If you get an assertion here, then you're trying to create a string from 8-bit data
2039 that contains values greater than 127. These can NOT be correctly converted to unicode
2040 because there's no way for the String class to know what encoding was used to
2041 create them. The source data could be UTF-8, ASCII or one of many local code-pages.
2042
2043 To get around this problem, you must be more explicit when you pass an ambiguous 8-bit
2044 string to the StringRef class - so for example if your source data is actually UTF-8,
2045 you'd call StringRef (CharPointer_UTF8 ("my utf8 string..")), and it would be able to
2046 correctly convert the multi-byte characters to unicode. It's *highly* recommended that
2047 you use UTF-8 with escape characters in your source code to represent extended characters,
2048 because there's no other way to represent these strings in a way that isn't dependent on
2049 the compiler, source code editor and platform.
2050 */
2051 wassert (CharPointer_UTF8::isValidString (stringLiteral, std::numeric_limits<int>::max()));
2052}
2053
2054StringRef::StringRef (CharPointer_UTF8 stringLiteral) noexcept : text (stringLiteral)
2055{
2056 wassert (stringLiteral.getAddress() != nullptr); // This must be a valid string literal, not a null pointer!!
2057}
2058
2059StringRef::StringRef (const String& string) noexcept : text (string.getCharPointer()) {}
2060
2061}
2062
2063//==============================================================================
#define CARLA_SAFE_ASSERT_RETURN(cond, ret)
Definition CarlaDefines.h:190
#define CARLA_SAFE_ASSERT(cond)
Definition CarlaDefines.h:182
Type jmax(const Type a, const Type b)
Definition MathsFunctions.h:48
#define noexcept
Definition DistrhoDefines.h:72
#define nullptr
Definition DistrhoDefines.h:75
static size_t getBytesRequiredFor(const water_uchar charToWrite) noexcept
Definition CharPointer_UTF8.h:294
Definition Atomic.h:95
int32 get() const noexcept
Definition Atomic.h:245
Definition CharPointer_UTF8.h:45
CharType * getAddress() const noexcept
Definition CharPointer_UTF8.h:80
void writeNull() const noexcept
Definition CharPointer_UTF8.h:361
static bool isValidString(const CharType *dataToTest, int maxBytesToRead)
Definition CharPointer_UTF8.h:502
bool isEmpty() const noexcept
Definition CharPointer_UTF8.h:86
static bool isByteOrderMark(const void *possibleByteOrder) noexcept
Definition CharPointer_UTF8.h:553
CharPointer_UTF8 findTerminatingNull() const noexcept
Definition CharPointer_UTF8.h:329
water_uchar toUpperCase() const noexcept
Definition CharPointer_UTF8.h:473
int indexOf(const CharPointer stringToFind) const noexcept
Definition CharPointer_UTF8.h:441
static size_t getBytesRequiredFor(const water_uchar charToWrite) noexcept
Definition CharPointer_UTF8.h:294
void writeAll(const CharPointer src) noexcept
Definition CharPointer_UTF8.h:368
void write(const water_uchar charToWrite) noexcept
Definition CharPointer_UTF8.h:335
char CharType
Definition CharPointer_UTF8.h:47
void writeWithCharLimit(const CharPointer src, const int maxChars) noexcept
Definition CharPointer_UTF8.h:400
water_uchar getAndAdvance() noexcept
Definition CharPointer_UTF8.h:157
water_uchar toLowerCase() const noexcept
Definition CharPointer_UTF8.h:475
static water_uchar toUpperCase(water_uchar character) noexcept
Definition CharacterFunctions.cpp:34
static bool isLetterOrDigit(char character) noexcept
Definition CharacterFunctions.cpp:94
static bool isDigit(char character) noexcept
Definition CharacterFunctions.cpp:73
static water_uchar toLowerCase(water_uchar character) noexcept
Definition CharacterFunctions.cpp:39
static int indexOfIgnoreCase(CharPointerType1 haystack, const CharPointerType2 needle) noexcept
Definition CharacterFunctions.h:514
static water_uchar getUnicodeCharFromWindows1252Codepage(uint8 windows1252Char) noexcept
Definition CharacterFunctions.cpp:161
Definition HeapBlock.h:77
bool malloc(const size_t newNumElements, const size_t elementSize=sizeof(ElementType)) noexcept
Definition HeapBlock.h:171
ElementType * getData() const noexcept
Definition HeapBlock.h:108
void clear(size_t numElements) noexcept
Definition HeapBlock.h:237
bool calloc(const size_t newNumElements, const size_t elementSize=sizeof(ElementType)) noexcept
Definition HeapBlock.h:182
bool realloc(const size_t newNumElements, const size_t elementSize=sizeof(ElementType)) noexcept
Definition HeapBlock.h:209
Definition OutputStream.h:44
virtual bool write(const void *dataToWrite, size_t numberOfBytes)=0
Definition String.cpp:1178
StringCreationHelper(const CharPointer_UTF8 s)
Definition String.cpp:1187
size_t allocatedBytes
Definition String.cpp:1214
CharPointer_UTF8 source
Definition String.cpp:1210
void write(water_uchar c)
Definition String.cpp:1194
StringCreationHelper(const size_t initialBytes)
Definition String.cpp:1180
CharPointer_UTF8 dest
Definition String.cpp:1213
size_t bytesWritten
Definition String.cpp:1214
String result
Definition String.cpp:1209
Definition String.cpp:59
Atomic< int > refCount
Definition String.cpp:203
static int getReferenceCount(const CharPointer_UTF8 text) noexcept
Definition String.cpp:170
static size_t getAllocatedNumBytes(const CharPointer_UTF8 text) noexcept
Definition String.cpp:197
static CharPointer_UTF8 createFromCharPointer(const CharPointer start, const CharPointer end)
Definition String.cpp:109
size_t allocatedNumBytes
Definition String.cpp:204
static CharPointer_UTF8 makeUniqueWithByteSize(const CharPointer_UTF8 text, size_t numBytes)
Definition String.cpp:176
static CharPointer_UTF8 createFromCharPointer(const CharPointer text, size_t maxChars)
Definition String.cpp:88
static CharPointer_UTF8 createFromCharPointer(const CharPointer_UTF8 start, const CharPointer_UTF8 end)
Definition String.cpp:129
static StringHolder * bufferFromText(const CharPointer_UTF8 text) noexcept
Definition String.cpp:208
static CharPointer_UTF8 createFromCharPointer(const CharPointer text)
Definition String.cpp:76
CharPointer_UTF8::CharType CharType
Definition String.cpp:63
static void release(const CharPointer_UTF8 text) noexcept
Definition String.cpp:165
static CharPointer_UTF8 createUninitialisedBytes(size_t numBytes)
Definition String.cpp:66
StringHolder() WATER_DELETED_FUNCTION
static CharPointer_UTF8 createFromFixedLength(const char *const src, const size_t numChars)
Definition String.cpp:142
static void release(StringHolder *const b) noexcept
Definition String.cpp:158
CharType text[1]
Definition String.cpp:205
static void retain(const CharPointer_UTF8 text) noexcept
Definition String.cpp:150
Definition String.h:48
String replaceSection(int startIndex, int numCharactersToReplace, StringRef stringToInsert) const
Definition String.cpp:1099
~String() noexcept
Definition String.cpp:221
String fromFirstOccurrenceOf(StringRef substringToStartFrom, bool includeSubStringInResult, bool ignoreCase) const
Definition String.cpp:1439
bool isQuotedString() const
Definition String.cpp:1487
static String charToString(water_uchar character)
Definition String.cpp:311
bool startsWithChar(water_uchar character) const noexcept
Definition String.cpp:1276
int indexOfAnyOf(StringRef charactersToLookFor, int startIndex=0, bool ignoreCase=false) const noexcept
Definition String.cpp:788
String trimEnd() const
Definition String.cpp:1572
String trimCharactersAtStart(StringRef charactersToTrim) const
Definition String.cpp:1586
int indexOfWholeWord(StringRef wordToLookFor) const noexcept
Definition String.cpp:931
String trimCharactersAtEnd(StringRef charactersToTrim) const
Definition String.cpp:1596
void append(const String &textToAppend, size_t maxCharsToTake)
Definition String.cpp:628
bool containsChar(water_uchar character) const noexcept
Definition String.cpp:921
static String toHexString(int number)
Definition String.cpp:1830
String upToFirstOccurrenceOf(StringRef substringToEndWith, bool includeSubStringInResult, bool ignoreCase) const
Definition String.cpp:1463
CharPointer_UTF8 toUTF8() const
Definition String.cpp:1906
size_t getByteOffsetOfEnd() const noexcept
Definition String.cpp:461
static String formatted(const String formatString,...)
Definition String.cpp:1747
bool equalsIgnoreCase(const String &other) const noexcept
Definition String.cpp:518
bool isNotEmpty() const noexcept
Definition String.h:244
size_t getNumBytesAsUTF8() const noexcept
Definition String.cpp:1956
bool containsWholeWord(StringRef wordToLookFor) const noexcept
Definition String.cpp:975
float getFloatValue() const noexcept
Definition String.cpp:1783
String retainCharacters(StringRef charactersToRetain) const
Definition String.cpp:1620
bool endsWithIgnoreCase(StringRef text) const noexcept
Definition String.cpp:1313
double getDoubleValue() const noexcept
Definition String.cpp:1784
int length() const noexcept
Definition String.cpp:451
String toUpperCase() const
Definition String.cpp:1331
int64 getLargeIntValue() const noexcept
Definition String.cpp:1782
String substring(int startIndex, int endIndex) const
Definition String.cpp:1373
bool endsWithChar(water_uchar character) const noexcept
Definition String.cpp:1284
String paddedLeft(water_uchar padCharacter, int minimumLength) const
Definition String.cpp:1042
static String createStringFromData(const void *data, int size)
Definition String.cpp:1721
String trimStart() const
Definition String.cpp:1559
bool containsWholeWordIgnoreCase(StringRef wordToLookFor) const noexcept
Definition String.cpp:980
int lastIndexOfAnyOf(StringRef charactersToLookFor, bool ignoreCase=false) const noexcept
Definition String.cpp:904
String & operator+=(const String &stringToAppend)
Definition String.cpp:665
String trim() const
Definition String.cpp:1540
static String repeatedString(StringRef stringToRepeat, int numberOfTimesToRepeat)
Definition String.cpp:1028
String quoted(water_uchar quoteCharacter='"') const
Definition String.cpp:1509
CharPointer_UTF8 text
Definition String.h:1095
String upToLastOccurrenceOf(StringRef substringToFind, bool includeSubStringInResult, bool ignoreCase) const
Definition String.cpp:1475
String unquoted() const
Definition String.cpp:1495
int getHexValue32() const noexcept
Definition String.cpp:1862
void appendCharPointer(const CharPointer_UTF8 startOfTextToAppend, const CharPointer_UTF8 endOfTextToAppend)
Definition String.cpp:639
String dropLastCharacters(int numberToDrop) const
Definition String.cpp:1429
bool endsWith(StringRef text) const noexcept
Definition String.cpp:1296
const char * toRawUTF8() const
Definition String.cpp:1925
String fromLastOccurrenceOf(StringRef substringToFind, bool includeSubStringInResult, bool ignoreCase) const
Definition String.cpp:1451
int indexOfIgnoreCase(StringRef textToLookFor) const noexcept
Definition String.cpp:813
int hashCode() const noexcept
Definition String.cpp:489
bool matchesWildcard(StringRef wildcard, bool ignoreCase) const noexcept
Definition String.cpp:1022
bool startsWithIgnoreCase(StringRef text) const noexcept
Definition String.cpp:1271
int getIntValue() const noexcept
Definition String.cpp:1781
bool startsWith(StringRef text) const noexcept
Definition String.cpp:1266
int compareNatural(StringRef other, bool isCaseSensitive=false) const noexcept
Definition String.cpp:622
String() noexcept
Definition String.cpp:217
void swapWith(String &other) noexcept
Definition String.cpp:231
String replace(StringRef stringToReplace, StringRef stringToInsertInstead, bool ignoreCase=false) const
Definition String.cpp:1159
bool containsNonWhitespaceChars() const noexcept
Definition String.cpp:1699
int lastIndexOfChar(water_uchar character) const noexcept
Definition String.cpp:776
int compare(const String &other) const noexcept
Definition String.cpp:524
void preallocateBytes(size_t numBytesNeeded)
Definition String.cpp:255
bool containsAnyOf(StringRef charactersItMightContain) const noexcept
Definition String.cpp:1690
String getLastCharacters(int numCharacters) const
Definition String.cpp:1434
int getTrailingIntValue() const noexcept
Definition String.cpp:1786
int64 hashCode64() const noexcept
Definition String.cpp:490
water_uchar getLastCharacter() const noexcept
Definition String.cpp:1368
String & operator=(const String &other) noexcept
Definition String.cpp:242
size_t copyToUTF8(CharPointer_UTF8::CharType *destBuffer, size_t maxBufferSizeBytes) const noexcept
Definition String.cpp:1950
bool containsOnly(StringRef charactersItMightContain) const noexcept
Definition String.cpp:1681
static String fromUTF8(const char *utf8buffer, int bufferSizeBytes=-1)
Definition String.cpp:1961
int compareIgnoreCase(const String &other) const noexcept
Definition String.cpp:526
int64 getHexValue64() const noexcept
Definition String.cpp:1863
int lastIndexOf(StringRef textToLookFor) const noexcept
Definition String.cpp:860
int lastIndexOfIgnoreCase(StringRef textToLookFor) const noexcept
Definition String.cpp:882
String toLowerCase() const
Definition String.cpp:1349
void clear() noexcept
Definition String.cpp:236
String replaceCharacters(StringRef charactersToReplace, StringRef charactersToInsertInstead) const
Definition String.cpp:1240
bool containsIgnoreCase(StringRef text) const noexcept
Definition String.cpp:926
int indexOf(StringRef textToLookFor) const noexcept
Definition String.cpp:808
int getReferenceCount() const noexcept
Definition String.cpp:260
String replaceCharacter(water_uchar characterToReplace, water_uchar characterToInsertInstead) const
Definition String.cpp:1217
bool isEmpty() const noexcept
Definition String.h:238
size_t hash() const noexcept
Definition String.cpp:491
bool contains(StringRef text) const noexcept
Definition String.cpp:916
int indexOfChar(water_uchar characterToLookFor) const noexcept
Definition String.cpp:751
String initialSectionContainingOnly(StringRef permittedCharacters) const
Definition String.cpp:1663
String removeCharacters(StringRef charactersToRemove) const
Definition String.cpp:1642
String initialSectionNotContaining(StringRef charactersToStopAt) const
Definition String.cpp:1672
String paddedRight(water_uchar padCharacter, int minimumLength) const
Definition String.cpp:1069
CharPointer_UTF8 getCharPointer() const noexcept
Definition String.h:982
int indexOfWholeWordIgnoreCase(StringRef wordToLookFor) const noexcept
Definition String.cpp:953
water_uchar operator[](int index) const noexcept
Definition String.cpp:466
std::string toStdString() const
Definition String.cpp:1930
Definition StringRef.h:67
int length() const noexcept
Definition StringRef.h:103
CharPointer_UTF8 text
Definition StringRef.h:120
StringRef() noexcept
Definition String.cpp:2029
* e
Definition inflate.c:1404
struct huft * t
Definition inflate.c:943
unsigned v[N_MAX]
Definition inflate.c:1584
unsigned d
Definition inflate.c:940
register unsigned i
Definition inflate.c:1575
unsigned s
Definition inflate.c:1555
static void c2(register WDL_FFT_COMPLEX *a)
Definition fft.c:270
virtual ASIOError start()=0
JSAMPIMAGE data
Definition jpeglib.h:945
#define wassertfalse
#define wassert(expression)
#define WATER_DELETED_FUNCTION
Definition String.cpp:322
static char * doubleToString(char *buffer, const int numChars, double n, int numDecPlaces, size_t &len) noexcept
Definition String.cpp:384
static char * numberToString(char *t, uint64 v) noexcept
Definition String.cpp:323
static char * printDigits(char *t, Type v) noexcept
Definition water.h:127
static CharPointer_UTF8 createFromInteger(const IntegerType number)
Definition String.cpp:418
static CharPointer_UTF8 createFromDouble(const double number, const int numberOfDecimalPlaces)
Definition String.cpp:426
@ charsNeededForDouble
Definition water.h:122
@ charsNeededForInt
Definition water.h:121
Definition String.cpp:694
String & operationAddAssign(String &str, const T number)
Definition String.cpp:696
Definition AudioSampleBuffer.h:33
int getAddressDifference(Type1 *pointer1, Type2 *pointer2) noexcept
Definition Memory.h:62
bool operator<=(const String &s1, const String &s2) noexcept
Definition String.cpp:505
static String getStringFromWindows1252Codepage(const char *data, size_t num)
Definition String.cpp:1709
bool operator==(const ReferenceCountedObjectPtr< ReferenceCountedObjectClass > &object1, ReferenceCountedObjectClass *const object2) noexcept
Definition ReferenceCountedObject.h:359
static int naturalStringCompare(CharPointer_UTF8 s1, CharPointer_UTF8 s2, bool isCaseSensitive) noexcept
Definition String.cpp:567
bool operator<(const String &s1, const String &s2) noexcept
Definition String.cpp:503
Type jmin(const Type a, const Type b)
Definition MathsFunctions.h:60
unsigned long long uint64
Definition water.h:102
String & operator+=(String &s1, const NewLine &)
Definition NewLine.h:71
static CharPointer_UTF8 findTrimmedEnd(const CharPointer_UTF8 start, CharPointer_UTF8 end)
Definition String.cpp:1526
static String hexToString(Type v)
Definition String.cpp:1812
String operator+(const NewLine &, const NewLine &)
Definition NewLine.h:73
static int stringCompareRight(CharPointer_UTF8 s1, CharPointer_UTF8 s2) noexcept
Definition String.cpp:528
OutputStream & operator<<(OutputStream &stream, const MemoryOutputStream &streamToRead)
Definition MemoryOutputStream.cpp:194
static const water_uchar emptyChar
Definition String.cpp:1866
void zeromem(void *memory, size_t numBytes) noexcept
Definition Memory.h:37
static int stringCompareLeft(CharPointer_UTF8 s1, CharPointer_UTF8 s2) noexcept
Definition String.cpp:549
long long int64
Definition water.h:100
unsigned char uint8
Definition water.h:90
static size_t findByteOffsetOfEnd(CharPointer_UTF8 text) noexcept
Definition String.cpp:456
bool operator!=(const ReferenceCountedObjectPtr< ReferenceCountedObjectClass > &object1, const ReferenceCountedObjectClass *object2) noexcept
Definition ReferenceCountedObject.h:380
bool operator>(const String &s1, const String &s2) noexcept
Definition String.cpp:502
Type jmax(const Type a, const Type b)
Definition MathsFunctions.h:48
static const char hexDigits[]
Definition String.cpp:1809
Type * addBytesToPointer(Type *basePointer, IntegerType bytes) noexcept
Definition Memory.h:56
size_t numElementsInArray(Type(&array)[N])
Definition MathsFunctions.h:257
static const EmptyString emptyString
Definition String.cpp:55
uint32 water_uchar
Definition CharacterFunctions.h:38
bool operator>=(const String &s1, const String &s2) noexcept
Definition String.cpp:504
png_uint_32 length
Definition png.c:2247
short word
Definition private.h:22
static int test(SerdEnv *env, bool top_level, bool pretty_numbers)
Definition sratom_test.c:79
Definition CharacterFunctions.h:268
static ResultType parse(CharPointerType t) noexcept
Definition CharacterFunctions.h:270
Definition String.cpp:49
CharPointer_UTF8::CharType text
Definition String.cpp:52
int refCount
Definition String.cpp:50
size_t allocatedBytes
Definition String.cpp:51
Definition String.cpp:474
static Type calculate(CharPointer t) noexcept
Definition String.cpp:476
size_t writeDouble(double n, int numDecPlaces)
Definition String.cpp:369
StackArrayStream(char *d)
Definition String.cpp:362
Definition String.h:1099
PreallocationBytes(size_t) noexcept
Definition String.cpp:248
size_t numBytes
Definition String.h:1101
Definition String.cpp:1938
static size_t copyToBuffer(const CharPointerType_Src source, typename CharPointerType_Dest::CharType *const buffer, const size_t maxBufferSizeBytes)
Definition String.cpp:1939
static CharPointer_UTF8 convert(const String &source) noexcept
Definition String.cpp:1903
Definition String.cpp:1870
static CharPointerType_Dest convert(const String &s)
Definition String.cpp:1871
Definition String.cpp:988
static bool matches(CharPointer wildcard, CharPointer test, const bool ignoreCase) noexcept
Definition String.cpp:989
static bool matchesAnywhere(const CharPointer wildcard, CharPointer test, const bool ignoreCase) noexcept
Definition String.cpp:1012
static bool characterMatches(const water_uchar wc, const water_uchar tc, const bool ignoreCase) noexcept
Definition String.cpp:1006
const char * text
Definition swell-functions.h:167
int n
Definition crypt.c:458
return c
Definition crypt.c:175
memcpy(hh, h, RAND_HEAD_LEN)
b
Definition crypt.c:628
ulg size
Definition extract.c:2350
int result
Definition process.c:1455
typedef int(UZ_EXP MsgFn)()
#define const
Definition zconf.h:137