Cleanup
[carla.git] / source / utils / CarlaString.hpp
blob438495a7c5ee933f50934ca312c067789f623f46
1 // SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
2 // SPDX-License-Identifier: GPL-2.0-or-later
4 #ifndef CARLA_STRING_HPP_INCLUDED
5 #define CARLA_STRING_HPP_INCLUDED
7 #include "CarlaMathUtils.hpp"
8 #include "CarlaScopeUtils.hpp"
10 #include <algorithm>
12 // -----------------------------------------------------------------------
13 // CarlaString class
15 class CARLA_API CarlaString
17 public:
18 // -------------------------------------------------------------------
19 // constructors (no explicit conversions allowed)
22 * Empty string.
24 explicit CarlaString() noexcept
25 : fBuffer(_null()),
26 fBufferLen(0),
27 fBufferAlloc(false) {}
30 * Simple character.
32 explicit CarlaString(const char c) noexcept
33 : fBuffer(_null()),
34 fBufferLen(0),
35 fBufferAlloc(false)
37 char ch[2];
38 ch[0] = c;
39 ch[1] = '\0';
41 _dup(ch);
45 * Simple char string.
47 explicit CarlaString(char* const strBuf, const bool reallocData = true) noexcept
48 : fBuffer(_null()),
49 fBufferLen(0),
50 fBufferAlloc(false)
52 if (reallocData || strBuf == nullptr)
54 _dup(strBuf);
56 else
58 fBuffer = strBuf;
59 fBufferLen = std::strlen(strBuf);
60 fBufferAlloc = true;
65 * Simple const char string.
67 explicit CarlaString(const char* const strBuf) noexcept
68 : fBuffer(_null()),
69 fBufferLen(0),
70 fBufferAlloc(false)
72 _dup(strBuf);
76 * Integer.
78 explicit CarlaString(const int value) noexcept
79 : fBuffer(_null()),
80 fBufferLen(0),
81 fBufferAlloc(false)
83 char strBuf[0xff+1];
84 std::snprintf(strBuf, 0xff, "%d", value);
85 strBuf[0xff] = '\0';
87 _dup(strBuf);
91 * Unsigned integer, possibly in hexadecimal.
93 explicit CarlaString(const unsigned int value, const bool hexadecimal = false) noexcept
94 : fBuffer(_null()),
95 fBufferLen(0),
96 fBufferAlloc(false)
98 char strBuf[0xff+1];
99 std::snprintf(strBuf, 0xff, hexadecimal ? "0x%x" : "%u", value);
100 strBuf[0xff] = '\0';
102 _dup(strBuf);
106 * Long integer.
108 explicit CarlaString(const long value) noexcept
109 : fBuffer(_null()),
110 fBufferLen(0),
111 fBufferAlloc(false)
113 char strBuf[0xff+1];
114 std::snprintf(strBuf, 0xff, "%ld", value);
115 strBuf[0xff] = '\0';
117 _dup(strBuf);
121 * Long unsigned integer, possibly hexadecimal.
123 explicit CarlaString(const unsigned long value, const bool hexadecimal = false) noexcept
124 : fBuffer(_null()),
125 fBufferLen(0),
126 fBufferAlloc(false)
128 char strBuf[0xff+1];
129 std::snprintf(strBuf, 0xff, hexadecimal ? "0x%lx" : "%lu", value);
130 strBuf[0xff] = '\0';
132 _dup(strBuf);
136 * Long long integer.
138 explicit CarlaString(const long long value) noexcept
139 : fBuffer(_null()),
140 fBufferLen(0),
141 fBufferAlloc(false)
143 char strBuf[0xff+1];
144 std::snprintf(strBuf, 0xff, "%lld", value);
145 strBuf[0xff] = '\0';
147 _dup(strBuf);
151 * Long long unsigned integer, possibly hexadecimal.
153 explicit CarlaString(const unsigned long long value, const bool hexadecimal = false) noexcept
154 : fBuffer(_null()),
155 fBufferLen(0),
156 fBufferAlloc(false)
158 char strBuf[0xff+1];
159 std::snprintf(strBuf, 0xff, hexadecimal ? "0x%llx" : "%llu", value);
160 strBuf[0xff] = '\0';
162 _dup(strBuf);
166 * Single-precision floating point number.
168 explicit CarlaString(const float value) noexcept
169 : fBuffer(_null()),
170 fBufferLen(0),
171 fBufferAlloc(false)
173 char strBuf[0xff+1];
176 const CarlaScopedLocale csl;
177 std::snprintf(strBuf, 0xff, "%.12g", static_cast<double>(value));
180 strBuf[0xff] = '\0';
182 _dup(strBuf);
186 * Double-precision floating point number.
188 explicit CarlaString(const double value) noexcept
189 : fBuffer(_null()),
190 fBufferLen(0),
191 fBufferAlloc(false)
193 char strBuf[0xff+1];
196 const CarlaScopedLocale csl;
197 std::snprintf(strBuf, 0xff, "%.24g", value);
200 strBuf[0xff] = '\0';
202 _dup(strBuf);
205 // -------------------------------------------------------------------
206 // non-explicit constructor
209 * Create string from another string.
211 CarlaString(const CarlaString& str) noexcept
212 : fBuffer(_null()),
213 fBufferLen(0),
214 fBufferAlloc(false)
216 _dup(str.fBuffer);
219 // -------------------------------------------------------------------
220 // destructor
223 * Destructor.
225 ~CarlaString() noexcept
227 CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr,);
229 if (fBufferAlloc)
230 std::free(fBuffer);
232 fBuffer = nullptr;
233 fBufferLen = 0;
234 fBufferAlloc = false;
237 // -------------------------------------------------------------------
238 // public methods
241 * Get length of the string.
243 std::size_t length() const noexcept
245 return fBufferLen;
249 * Check if the string is empty.
251 bool isEmpty() const noexcept
253 return (fBufferLen == 0);
257 * Check if the string is not empty.
259 bool isNotEmpty() const noexcept
261 return (fBufferLen != 0);
265 * Check if the string contains a specific character, case-sensitive.
267 bool contains(const char c) const noexcept
269 for (std::size_t i=0; i<fBufferLen; ++i)
271 if (fBuffer[i] == c)
272 return true;
275 return false;
279 * Check if the string contains another string, optionally ignoring case.
281 bool contains(const char* const strBuf, const bool ignoreCase = false) const noexcept
283 CARLA_SAFE_ASSERT_RETURN(strBuf != nullptr, false);
285 if (ignoreCase)
286 return carla_strcasestr(fBuffer, strBuf) != nullptr;
288 return std::strstr(fBuffer, strBuf) != nullptr;
292 * Check if character at 'pos' is a digit.
294 bool isDigit(const std::size_t pos) const noexcept
296 CARLA_SAFE_ASSERT_RETURN(pos < fBufferLen, false);
298 return (fBuffer[pos] >= '0' && fBuffer[pos] <= '9');
302 * Check if the string starts with the character 'c'.
304 bool startsWith(const char c) const noexcept
306 CARLA_SAFE_ASSERT_RETURN(c != '\0', false);
308 return (fBufferLen > 0 && fBuffer[0] == c);
312 * Check if the string starts with the string 'prefix'.
314 bool startsWith(const char* const prefix) const noexcept
316 CARLA_SAFE_ASSERT_RETURN(prefix != nullptr, false);
318 const std::size_t prefixLen(std::strlen(prefix));
320 if (fBufferLen < prefixLen)
321 return false;
323 return (std::strncmp(fBuffer, prefix, prefixLen) == 0);
327 * Check if the string ends with the character 'c'.
329 bool endsWith(const char c) const noexcept
331 CARLA_SAFE_ASSERT_RETURN(c != '\0', false);
333 return (fBufferLen > 0 && fBuffer[fBufferLen-1] == c);
337 * Check if the string ends with the string 'suffix'.
339 bool endsWith(const char* const suffix) const noexcept
341 CARLA_SAFE_ASSERT_RETURN(suffix != nullptr, false);
343 const std::size_t suffixLen(std::strlen(suffix));
345 if (fBufferLen < suffixLen)
346 return false;
348 return (std::strncmp(fBuffer + (fBufferLen-suffixLen), suffix, suffixLen) == 0);
352 * Find the first occurrence of character 'c' in the string.
353 * Returns "length()" if the character is not found.
355 std::size_t find(const char c, bool* const found = nullptr) const noexcept
357 if (fBufferLen == 0 || c == '\0')
359 if (found != nullptr)
360 *found = false;
361 return fBufferLen;
364 for (std::size_t i=0; i < fBufferLen; ++i)
366 if (fBuffer[i] == c)
368 if (found != nullptr)
369 *found = true;
370 return i;
374 if (found != nullptr)
375 *found = false;
376 return fBufferLen;
380 * Find the first occurrence of string 'strBuf' in the string.
381 * Returns "length()" if the string is not found.
383 std::size_t find(const char* const strBuf, bool* const found = nullptr) const noexcept
385 if (fBufferLen == 0 || strBuf == nullptr || strBuf[0] == '\0')
387 if (found != nullptr)
388 *found = false;
389 return fBufferLen;
392 if (char* const subStrBuf = std::strstr(fBuffer, strBuf))
394 const ssize_t ret = subStrBuf - fBuffer;
396 if (ret < 0)
398 // should never happen!
399 carla_safe_assert_int("ret >= 0", __FILE__, __LINE__, int(ret));
401 if (found != nullptr)
402 *found = false;
403 return fBufferLen;
406 if (found != nullptr)
407 *found = true;
408 return static_cast<std::size_t>(ret);
411 if (found != nullptr)
412 *found = false;
413 return fBufferLen;
417 * Find the last occurrence of character 'c' in the string.
418 * Returns "length()" if the character is not found.
420 std::size_t rfind(const char c, bool* const found = nullptr) const noexcept
422 if (fBufferLen == 0 || c == '\0')
424 if (found != nullptr)
425 *found = false;
426 return fBufferLen;
429 for (std::size_t i=fBufferLen; i > 0; --i)
431 if (fBuffer[i-1] == c)
433 if (found != nullptr)
434 *found = true;
435 return i-1;
439 if (found != nullptr)
440 *found = false;
441 return fBufferLen;
445 * Find the last occurrence of string 'strBuf' in the string.
446 * Returns "length()" if the string is not found.
448 std::size_t rfind(const char* const strBuf, bool* const found = nullptr) const noexcept
450 if (found != nullptr)
451 *found = false;
453 if (fBufferLen == 0 || strBuf == nullptr || strBuf[0] == '\0')
454 return fBufferLen;
456 const std::size_t strBufLen(std::strlen(strBuf));
458 std::size_t ret = fBufferLen;
459 const char* tmpBuf = fBuffer;
461 for (std::size_t i=0; i < fBufferLen; ++i)
463 if (std::strstr(tmpBuf+1, strBuf) == nullptr && std::strncmp(tmpBuf, strBuf, strBufLen) == 0)
465 if (found != nullptr)
466 *found = true;
467 break;
470 --ret;
471 ++tmpBuf;
474 return fBufferLen-ret;
478 * Clear the string.
480 void clear() noexcept
482 truncate(0);
486 * Replace all occurrences of character 'before' with character 'after'.
488 CarlaString& replace(const char before, const char after) noexcept
490 CARLA_SAFE_ASSERT_RETURN(before != '\0' && after != '\0', *this);
492 for (std::size_t i=0; i < fBufferLen; ++i)
494 if (fBuffer[i] == before)
495 fBuffer[i] = after;
498 return *this;
502 * Truncate the string to size 'n'.
504 CarlaString& truncate(const std::size_t n) noexcept
506 if (n >= fBufferLen)
507 return *this;
509 fBuffer[n] = '\0';
510 fBufferLen = n;
512 return *this;
516 * Convert all non-basic characters to '_'.
518 CarlaString& toBasic() noexcept
520 for (std::size_t i=0; i < fBufferLen; ++i)
522 if (fBuffer[i] >= '0' && fBuffer[i] <= '9')
523 continue;
524 if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z')
525 continue;
526 if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z')
527 continue;
528 if (fBuffer[i] == '_')
529 continue;
531 fBuffer[i] = '_';
534 return *this;
538 * Convert all ascii characters to lowercase.
540 CarlaString& toLower() noexcept
542 static const char kCharDiff('a' - 'A');
544 for (std::size_t i=0; i < fBufferLen; ++i)
546 if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z')
547 fBuffer[i] = static_cast<char>(fBuffer[i] + kCharDiff);
550 return *this;
554 * Convert all ascii characters to uppercase.
556 CarlaString& toUpper() noexcept
558 static const char kCharDiff('a' - 'A');
560 for (std::size_t i=0; i < fBufferLen; ++i)
562 if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z')
563 fBuffer[i] = static_cast<char>(fBuffer[i] - kCharDiff);
566 return *this;
570 * Direct access to the string buffer (read-only).
572 const char* buffer() const noexcept
574 return fBuffer;
578 * Return a duplicate string buffer.
579 * May throw.
581 const char* dup() const
583 return carla_strdup(fBuffer);
587 * Return a duplicate string buffer or null.
589 const char* dupSafe() const noexcept
591 return carla_strdup_safe(fBuffer);
595 * Release the buffer pointer while clearing this string.
596 * This allows to keep a pointer to the buffer after this object is deleted.
598 char* releaseBufferPointer() noexcept
600 char* ret = fBufferLen > 0 ? fBuffer : nullptr;
601 fBuffer = _null();
602 fBufferLen = 0;
603 fBufferAlloc = false;
604 return ret;
607 // -------------------------------------------------------------------
608 // base64 stuff, based on http://www.adp-gmbh.ch/cpp/common/base64.html
609 // Copyright (C) 2004-2008 René Nyffenegger
611 static CarlaString asBase64(const void* const data, const std::size_t dataSize)
613 static const char* const kBase64Chars =
614 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
615 "abcdefghijklmnopqrstuvwxyz"
616 "0123456789+/";
618 static constexpr const std::size_t kTmpBufSize = 65536U;
620 const uchar* bytesToEncode((const uchar*)data);
622 uint i=0, j=0;
623 uint charArray3[3], charArray4[4];
625 char strBuf[kTmpBufSize+1];
626 strBuf[kTmpBufSize] = '\0';
627 std::size_t strBufIndex = 0;
629 CarlaString ret;
631 for (std::size_t s=0; s<dataSize; ++s)
633 charArray3[i++] = *(bytesToEncode++);
635 if (i == 3)
637 charArray4[0] = (charArray3[0] & 0xfc) >> 2;
638 charArray4[1] = ((charArray3[0] & 0x03) << 4) + ((charArray3[1] & 0xf0) >> 4);
639 charArray4[2] = ((charArray3[1] & 0x0f) << 2) + ((charArray3[2] & 0xc0) >> 6);
640 charArray4[3] = charArray3[2] & 0x3f;
642 for (i=0; i<4; ++i)
643 strBuf[strBufIndex++] = kBase64Chars[charArray4[i]];
645 if (strBufIndex >= kTmpBufSize-7)
647 strBuf[strBufIndex] = '\0';
648 strBufIndex = 0;
649 ret += strBuf;
652 i = 0;
656 if (i != 0)
658 for (j=i; j<3; ++j)
659 charArray3[j] = '\0';
661 charArray4[0] = (charArray3[0] & 0xfc) >> 2;
662 charArray4[1] = ((charArray3[0] & 0x03) << 4) + ((charArray3[1] & 0xf0) >> 4);
663 charArray4[2] = ((charArray3[1] & 0x0f) << 2) + ((charArray3[2] & 0xc0) >> 6);
664 charArray4[3] = charArray3[2] & 0x3f;
666 for (j=0; j<4 && i<3 && j<i+1; ++j)
667 strBuf[strBufIndex++] = kBase64Chars[charArray4[j]];
669 for (; i++ < 3;)
670 strBuf[strBufIndex++] = '=';
673 if (strBufIndex != 0)
675 strBuf[strBufIndex] = '\0';
676 ret += strBuf;
679 return ret;
682 // -------------------------------------------------------------------
683 // public operators
685 operator const char*() const noexcept
687 return fBuffer;
690 char operator[](const std::size_t pos) const noexcept
692 if (pos < fBufferLen)
693 return fBuffer[pos];
695 carla_safe_assert("pos < fBufferLen", __FILE__, __LINE__);
697 static char fallback = '\0';
698 return fallback;
701 char& operator[](const std::size_t pos) noexcept
703 if (pos < fBufferLen)
704 return fBuffer[pos];
706 carla_safe_assert("pos < fBufferLen", __FILE__, __LINE__);
708 static char fallback = '\0';
709 return fallback;
712 bool operator==(const char* const strBuf) const noexcept
714 return (strBuf != nullptr && std::strcmp(fBuffer, strBuf) == 0);
717 bool operator==(const CarlaString& str) const noexcept
719 return operator==(str.fBuffer);
722 bool operator!=(const char* const strBuf) const noexcept
724 return !operator==(strBuf);
727 bool operator!=(const CarlaString& str) const noexcept
729 return !operator==(str.fBuffer);
732 CarlaString& operator=(const char* const strBuf) noexcept
734 _dup(strBuf);
736 return *this;
739 CarlaString& operator=(const CarlaString& str) noexcept
741 _dup(str.fBuffer);
743 return *this;
746 CarlaString& operator+=(const char* const strBuf) noexcept
748 if (strBuf == nullptr || strBuf[0] == '\0')
749 return *this;
751 const std::size_t strBufLen = std::strlen(strBuf);
753 // for empty strings, we can just take the appended string as our entire data
754 if (isEmpty())
756 _dup(strBuf, strBufLen);
757 return *this;
760 // we have some data ourselves, reallocate to add the new stuff
761 char* const newBuf = (char*)realloc(fBuffer, fBufferLen + strBufLen + 1);
762 CARLA_SAFE_ASSERT_RETURN(newBuf != nullptr, *this);
764 std::memcpy(newBuf + fBufferLen, strBuf, strBufLen + 1);
766 fBuffer = newBuf;
767 fBufferLen += strBufLen;
769 return *this;
772 CarlaString& operator+=(const CarlaString& str) noexcept
774 return operator+=(str.fBuffer);
777 CarlaString operator+(const char* const strBuf) noexcept
779 if (strBuf == nullptr || strBuf[0] == '\0')
780 return *this;
781 if (isEmpty())
782 return CarlaString(strBuf);
784 const std::size_t strBufLen = std::strlen(strBuf);
785 const std::size_t newBufSize = fBufferLen + strBufLen;
786 char* const newBuf = (char*)std::malloc(newBufSize + 1);
787 CARLA_SAFE_ASSERT_RETURN(newBuf != nullptr, CarlaString());
789 std::memcpy(newBuf, fBuffer, fBufferLen);
790 std::memcpy(newBuf + fBufferLen, strBuf, strBufLen + 1);
792 return CarlaString(newBuf, false);
795 CarlaString operator+(const CarlaString& str) noexcept
797 return operator+(str.fBuffer);
800 // needed for std::map compatibility
801 bool operator<(const CarlaString& str) const noexcept
803 return std::strcmp(fBuffer, str.fBuffer) < 0;
806 // -------------------------------------------------------------------
808 private:
809 char* fBuffer; // the actual string buffer
810 std::size_t fBufferLen; // string length
811 bool fBufferAlloc; // wherever the buffer is allocated, not using _null()
814 * Static null string.
815 * Prevents allocation for new and/or empty strings.
817 static char* _null() noexcept
819 static char sNull = '\0';
820 return &sNull;
824 * Helper function.
825 * Called whenever the string needs to be allocated.
827 * Notes:
828 * - Allocates string only if 'strBuf' is not null and new string contents are different
829 * - If 'strBuf' is null, 'size' must be 0
831 void _dup(const char* const strBuf, const std::size_t size = 0) noexcept
833 if (strBuf != nullptr)
835 // don't recreate string if contents match
836 if (std::strcmp(fBuffer, strBuf) == 0)
837 return;
839 if (fBufferAlloc)
840 std::free(fBuffer);
842 fBufferLen = (size > 0) ? size : std::strlen(strBuf);
843 fBuffer = (char*)std::malloc(fBufferLen+1);
845 if (fBuffer == nullptr)
847 fBuffer = _null();
848 fBufferLen = 0;
849 fBufferAlloc = false;
850 return;
853 fBufferAlloc = true;
855 std::strcpy(fBuffer, strBuf);
856 fBuffer[fBufferLen] = '\0';
858 else
860 CARLA_SAFE_ASSERT_UINT(size == 0, static_cast<uint>(size));
862 // don't recreate null string
863 if (! fBufferAlloc)
864 return;
866 CARLA_SAFE_ASSERT(fBuffer != nullptr);
867 std::free(fBuffer);
869 fBuffer = _null();
870 fBufferLen = 0;
871 fBufferAlloc = false;
875 CARLA_PREVENT_HEAP_ALLOCATION
878 // -----------------------------------------------------------------------
880 static inline
881 CarlaString operator+(const CarlaString& strBefore, const char* const strBufAfter) noexcept
883 if (strBufAfter == nullptr || strBufAfter[0] == '\0')
884 return strBefore;
885 if (strBefore.isEmpty())
886 return CarlaString(strBufAfter);
888 const std::size_t strBeforeLen = strBefore.length();
889 const std::size_t strBufAfterLen = std::strlen(strBufAfter);
890 const std::size_t newBufSize = strBeforeLen + strBufAfterLen;
891 char* const newBuf = (char*)std::malloc(newBufSize + 1);
892 CARLA_SAFE_ASSERT_RETURN(newBuf != nullptr, CarlaString());
894 std::memcpy(newBuf, strBefore.buffer(), strBeforeLen);
895 std::memcpy(newBuf + strBeforeLen, strBufAfter, strBufAfterLen + 1);
897 return CarlaString(newBuf, false);
900 static inline
901 CarlaString operator+(const char* const strBufBefore, const CarlaString& strAfter) noexcept
903 if (strAfter.isEmpty())
904 return CarlaString(strBufBefore);
905 if (strBufBefore == nullptr || strBufBefore[0] == '\0')
906 return strAfter;
908 const std::size_t strBufBeforeLen = std::strlen(strBufBefore);
909 const std::size_t strAfterLen = strAfter.length();
910 const std::size_t newBufSize = strBufBeforeLen + strAfterLen;
911 char* const newBuf = (char*)std::malloc(newBufSize + 1);
912 CARLA_SAFE_ASSERT_RETURN(newBuf != nullptr, CarlaString());
914 std::memcpy(newBuf, strBufBefore, strBufBeforeLen);
915 std::memcpy(newBuf + strBufBeforeLen, strAfter.buffer(), strAfterLen + 1);
917 return CarlaString(newBuf, false);
920 // -----------------------------------------------------------------------
922 #endif // CARLA_STRING_HPP_INCLUDED