17 #ifndef DISTRHO_STRING_HPP_INCLUDED
18 #define DISTRHO_STRING_HPP_INCLUDED
20 #include "../DistrhoUtils.hpp"
21 #include "../extra/ScopedSafeLocale.hpp"
25 START_NAMESPACE_DISTRHO
42 fBufferAlloc(
false) {}
47 explicit String(
const char c) noexcept
62 explicit String(
char*
const strBuf,
const bool copyData =
true) noexcept
67 if (copyData || strBuf ==
nullptr)
74 fBufferLen = std::strlen(strBuf);
82 explicit String(
const char*
const strBuf) noexcept
93 explicit String(
const int value) noexcept
99 std::snprintf(strBuf, 0xff,
"%d", value);
108 explicit String(
const unsigned int value,
const bool hexadecimal =
false) noexcept
114 std::snprintf(strBuf, 0xff, hexadecimal ?
"0x%x" :
"%u", value);
123 explicit String(
const long value) noexcept
129 std::snprintf(strBuf, 0xff,
"%ld", value);
138 explicit String(
const unsigned long value,
const bool hexadecimal =
false) noexcept
144 std::snprintf(strBuf, 0xff, hexadecimal ?
"0x%lx" :
"%lu", value);
153 explicit String(
const long long value) noexcept
159 std::snprintf(strBuf, 0xff,
"%lld", value);
168 explicit String(
const unsigned long long value,
const bool hexadecimal =
false) noexcept
174 std::snprintf(strBuf, 0xff, hexadecimal ?
"0x%llx" :
"%llu", value);
183 explicit String(
const float value) noexcept
192 std::snprintf(strBuf, 0xff,
"%.12g",
static_cast<double>(value));
203 explicit String(
const double value) noexcept
212 std::snprintf(strBuf, 0xff,
"%.24g", value);
242 DISTRHO_SAFE_ASSERT_RETURN(fBuffer !=
nullptr,);
249 fBufferAlloc =
false;
258 std::size_t length()
const noexcept
266 bool isEmpty()
const noexcept
268 return (fBufferLen == 0);
274 bool isNotEmpty()
const noexcept
276 return (fBufferLen != 0);
282 bool contains(
const char c)
const noexcept
284 for (std::size_t i=0; i<fBufferLen; ++i)
296 bool contains(
const char*
const strBuf,
const bool ignoreCase =
false)
const noexcept
298 DISTRHO_SAFE_ASSERT_RETURN(strBuf !=
nullptr,
false);
303 return (strcasestr(fBuffer, strBuf) !=
nullptr);
305 String tmp1(fBuffer), tmp2(strBuf);
308 if (tmp1.fBuffer == _null() || tmp2.fBuffer == _null())
313 return (std::strstr(tmp1, tmp2) !=
nullptr);
317 return (std::strstr(fBuffer, strBuf) !=
nullptr);
323 bool isDigit(
const std::size_t pos)
const noexcept
325 DISTRHO_SAFE_ASSERT_RETURN(pos < fBufferLen,
false);
327 return (fBuffer[pos] >=
'0' && fBuffer[pos] <=
'9');
333 bool startsWith(
const char c)
const noexcept
335 DISTRHO_SAFE_ASSERT_RETURN(c !=
'\0',
false);
337 return (fBufferLen > 0 && fBuffer[0] == c);
343 bool startsWith(
const char*
const prefix)
const noexcept
345 DISTRHO_SAFE_ASSERT_RETURN(prefix !=
nullptr,
false);
347 const std::size_t prefixLen(std::strlen(prefix));
349 if (fBufferLen < prefixLen)
352 return (std::strncmp(fBuffer, prefix, prefixLen) == 0);
358 bool endsWith(
const char c)
const noexcept
360 DISTRHO_SAFE_ASSERT_RETURN(c !=
'\0',
false);
362 return (fBufferLen > 0 && fBuffer[fBufferLen-1] == c);
368 bool endsWith(
const char*
const suffix)
const noexcept
370 DISTRHO_SAFE_ASSERT_RETURN(suffix !=
nullptr,
false);
372 const std::size_t suffixLen(std::strlen(suffix));
374 if (fBufferLen < suffixLen)
377 return (std::strncmp(fBuffer + (fBufferLen-suffixLen), suffix, suffixLen) == 0);
384 std::size_t find(
const char c,
bool*
const found =
nullptr)
const noexcept
386 if (fBufferLen == 0 || c ==
'\0')
388 if (found !=
nullptr)
393 for (std::size_t i=0; i < fBufferLen; ++i)
397 if (found !=
nullptr)
403 if (found !=
nullptr)
412 std::size_t find(
const char*
const strBuf,
bool*
const found =
nullptr)
const noexcept
414 if (fBufferLen == 0 || strBuf ==
nullptr || strBuf[0] ==
'\0')
416 if (found !=
nullptr)
421 if (
char*
const subStrBuf = std::strstr(fBuffer, strBuf))
423 const ssize_t ret(subStrBuf - fBuffer);
428 d_safe_assert_int(
"ret >= 0", __FILE__, __LINE__,
int(ret));
430 if (found !=
nullptr)
435 if (found !=
nullptr)
437 return static_cast<std::size_t
>(ret);
440 if (found !=
nullptr)
449 std::size_t rfind(
const char c,
bool*
const found =
nullptr)
const noexcept
451 if (fBufferLen == 0 || c ==
'\0')
453 if (found !=
nullptr)
458 for (std::size_t i=fBufferLen; i > 0; --i)
460 if (fBuffer[i-1] == c)
462 if (found !=
nullptr)
468 if (found !=
nullptr)
477 std::size_t rfind(
const char*
const strBuf,
bool*
const found =
nullptr)
const noexcept
479 if (found !=
nullptr)
482 if (fBufferLen == 0 || strBuf ==
nullptr || strBuf[0] ==
'\0')
485 const std::size_t strBufLen(std::strlen(strBuf));
487 std::size_t ret = fBufferLen;
488 const char* tmpBuf = fBuffer;
490 for (std::size_t i=0; i < fBufferLen; ++i)
492 if (std::strstr(tmpBuf+1, strBuf) ==
nullptr && std::strncmp(tmpBuf, strBuf, strBufLen) == 0)
494 if (found !=
nullptr)
503 return fBufferLen-ret;
509 void clear() noexcept
517 String& replace(
const char before,
const char after) noexcept
519 DISTRHO_SAFE_ASSERT_RETURN(before !=
'\0' && after !=
'\0', *
this);
521 for (std::size_t i=0; i < fBufferLen; ++i)
523 if (fBuffer[i] == before)
533 String& remove(
const char c) noexcept
535 DISTRHO_SAFE_ASSERT_RETURN(c !=
'\0', *
this);
540 for (std::size_t i=0; i < fBufferLen; ++i)
545 std::memmove(fBuffer+i, fBuffer+i+1, fBufferLen-i);
549 fBuffer[fBufferLen] =
'\0';
556 String& truncate(
const std::size_t n) noexcept
570 String& toBasic() noexcept
572 for (std::size_t i=0; i < fBufferLen; ++i)
574 if (fBuffer[i] >=
'0' && fBuffer[i] <=
'9')
576 if (fBuffer[i] >=
'A' && fBuffer[i] <=
'Z')
578 if (fBuffer[i] >=
'a' && fBuffer[i] <=
'z')
580 if (fBuffer[i] ==
'_')
592 String& toLower() noexcept
594 static const char kCharDiff(
'a' -
'A');
596 for (std::size_t i=0; i < fBufferLen; ++i)
598 if (fBuffer[i] >=
'A' && fBuffer[i] <=
'Z')
599 fBuffer[i] =
static_cast<char>(fBuffer[i] + kCharDiff);
608 String& toUpper() noexcept
610 static const char kCharDiff(
'a' -
'A');
612 for (std::size_t i=0; i < fBufferLen; ++i)
614 if (fBuffer[i] >=
'a' && fBuffer[i] <=
'z')
615 fBuffer[i] =
static_cast<char>(fBuffer[i] - kCharDiff);
624 const char* buffer()
const noexcept
634 char* getAndReleaseBuffer() noexcept
636 char* ret = fBufferLen > 0 ? fBuffer :
nullptr;
639 fBufferAlloc =
false;
647 static String asBase64(
const void*
const data,
const std::size_t dataSize)
649 static const char*
const kBase64Chars =
650 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
651 "abcdefghijklmnopqrstuvwxyz"
655 const std::size_t kTmpBufSize = std::min(d_nextPowerOf2(
static_cast<uint32_t
>(dataSize/3)), 65536U);
657 constexpr std::size_t kTmpBufSize = 65536U;
660 const uchar* bytesToEncode((
const uchar*)data);
663 uint charArray3[3], charArray4[4];
665 char strBuf[kTmpBufSize + 1];
666 strBuf[kTmpBufSize] =
'\0';
667 std::size_t strBufIndex = 0;
671 for (std::size_t s=0; s<dataSize; ++s)
673 charArray3[i++] = *(bytesToEncode++);
677 charArray4[0] = (charArray3[0] & 0xfc) >> 2;
678 charArray4[1] = ((charArray3[0] & 0x03) << 4) + ((charArray3[1] & 0xf0) >> 4);
679 charArray4[2] = ((charArray3[1] & 0x0f) << 2) + ((charArray3[2] & 0xc0) >> 6);
680 charArray4[3] = charArray3[2] & 0x3f;
683 strBuf[strBufIndex++] = kBase64Chars[charArray4[i]];
685 if (strBufIndex >= kTmpBufSize-7)
687 strBuf[strBufIndex] =
'\0';
699 charArray3[j] =
'\0';
701 charArray4[0] = (charArray3[0] & 0xfc) >> 2;
702 charArray4[1] = ((charArray3[0] & 0x03) << 4) + ((charArray3[1] & 0xf0) >> 4);
703 charArray4[2] = ((charArray3[1] & 0x0f) << 2) + ((charArray3[2] & 0xc0) >> 6);
704 charArray4[3] = charArray3[2] & 0x3f;
706 for (j=0; j<4 && i<3 && j<i+1; ++j)
707 strBuf[strBufIndex++] = kBase64Chars[charArray4[j]];
710 strBuf[strBufIndex++] =
'=';
713 if (strBufIndex != 0)
715 strBuf[strBufIndex] =
'\0';
725 operator const char*()
const noexcept
730 char operator[](
const std::size_t pos)
const noexcept
732 if (pos < fBufferLen)
735 d_safe_assert(
"pos < fBufferLen", __FILE__, __LINE__);
737 static char fallback;
742 char& operator[](
const std::size_t pos) noexcept
744 if (pos < fBufferLen)
747 d_safe_assert(
"pos < fBufferLen", __FILE__, __LINE__);
749 static char fallback;
754 bool operator==(
const char*
const strBuf)
const noexcept
756 return (strBuf !=
nullptr && std::strcmp(fBuffer, strBuf) == 0);
759 bool operator==(
const String& str)
const noexcept
761 return operator==(str.fBuffer);
764 bool operator!=(
const char*
const strBuf)
const noexcept
766 return !operator==(strBuf);
769 bool operator!=(
const String& str)
const noexcept
771 return !operator==(str.fBuffer);
774 String& operator=(
const char*
const strBuf) noexcept
788 String& operator+=(
const char*
const strBuf) noexcept
790 if (strBuf ==
nullptr || strBuf[0] ==
'\0')
793 const std::size_t strBufLen = std::strlen(strBuf);
798 _dup(strBuf, strBufLen);
803 char*
const newBuf = (
char*)realloc(fBuffer, fBufferLen + strBufLen + 1);
804 DISTRHO_SAFE_ASSERT_RETURN(newBuf !=
nullptr, *
this);
806 std::memcpy(newBuf + fBufferLen, strBuf, strBufLen + 1);
809 fBufferLen += strBufLen;
816 return operator+=(str.fBuffer);
819 String operator+(
const char*
const strBuf) noexcept
821 if (strBuf ==
nullptr || strBuf[0] ==
'\0')
826 const std::size_t strBufLen = std::strlen(strBuf);
827 const std::size_t newBufSize = fBufferLen + strBufLen;
828 char*
const newBuf = (
char*)malloc(newBufSize + 1);
829 DISTRHO_SAFE_ASSERT_RETURN(newBuf !=
nullptr,
String());
831 std::memcpy(newBuf, fBuffer, fBufferLen);
832 std::memcpy(newBuf + fBufferLen, strBuf, strBufLen + 1);
839 return operator+(str.fBuffer);
846 std::size_t fBufferLen;
853 static char* _null() noexcept
855 static char sNull =
'\0';
867 void _dup(
const char*
const strBuf,
const std::size_t size = 0) noexcept
869 if (strBuf !=
nullptr)
872 if (std::strcmp(fBuffer, strBuf) == 0)
878 fBufferLen = (size > 0) ? size : std::strlen(strBuf);
879 fBuffer = (
char*)std::malloc(fBufferLen+1);
881 if (fBuffer ==
nullptr)
885 fBufferAlloc =
false;
891 std::strcpy(fBuffer, strBuf);
892 fBuffer[fBufferLen] =
'\0';
896 DISTRHO_SAFE_ASSERT_UINT(size == 0,
static_cast<uint
>(size));
902 DISTRHO_SAFE_ASSERT(fBuffer !=
nullptr);
907 fBufferAlloc =
false;
911 DISTRHO_PREVENT_HEAP_ALLOCATION
917 String operator+(
const String& strBefore,
const char*
const strBufAfter) noexcept
919 if (strBufAfter ==
nullptr || strBufAfter[0] ==
'\0')
921 if (strBefore.isEmpty())
922 return String(strBufAfter);
924 const std::size_t strBeforeLen = strBefore.length();
925 const std::size_t strBufAfterLen = std::strlen(strBufAfter);
926 const std::size_t newBufSize = strBeforeLen + strBufAfterLen;
927 char*
const newBuf = (
char*)malloc(newBufSize + 1);
928 DISTRHO_SAFE_ASSERT_RETURN(newBuf !=
nullptr,
String());
930 std::memcpy(newBuf, strBefore.buffer(), strBeforeLen);
931 std::memcpy(newBuf + strBeforeLen, strBufAfter, strBufAfterLen + 1);
937 String operator+(
const char*
const strBufBefore,
const String& strAfter) noexcept
939 if (strAfter.isEmpty())
940 return String(strBufBefore);
941 if (strBufBefore ==
nullptr || strBufBefore[0] ==
'\0')
944 const std::size_t strBufBeforeLen = std::strlen(strBufBefore);
945 const std::size_t strAfterLen = strAfter.length();
946 const std::size_t newBufSize = strBufBeforeLen + strAfterLen;
947 char*
const newBuf = (
char*)malloc(newBufSize + 1);
948 DISTRHO_SAFE_ASSERT_RETURN(newBuf !=
nullptr,
String());
950 std::memcpy(newBuf, strBufBefore, strBufBeforeLen);
951 std::memcpy(newBuf + strBufBeforeLen, strAfter.buffer(), strAfterLen + 1);
958 END_NAMESPACE_DISTRHO
960 #endif // DISTRHO_STRING_HPP_INCLUDED