17 #ifndef DISTRHO_STRING_HPP_INCLUDED
18 #define DISTRHO_STRING_HPP_INCLUDED
20 #include "../DistrhoUtils.hpp"
24 START_NAMESPACE_DISTRHO
45 explicit String(
const char c) noexcept
59 explicit String(
char*
const strBuf,
const bool copyData =
true) noexcept
63 if (copyData || strBuf ==
nullptr)
70 fBufferLen = std::strlen(strBuf);
78 explicit String(
const char*
const strBuf) noexcept
88 explicit String(
const int value) noexcept
93 std::snprintf(strBuf, 0xff,
"%d", value);
102 explicit String(
const unsigned int value,
const bool hexadecimal =
false) noexcept
107 std::snprintf(strBuf, 0xff, hexadecimal ?
"0x%x" :
"%u", value);
116 explicit String(
const long value) noexcept
121 std::snprintf(strBuf, 0xff,
"%ld", value);
130 explicit String(
const unsigned long value,
const bool hexadecimal =
false) noexcept
135 std::snprintf(strBuf, 0xff, hexadecimal ?
"0x%lx" :
"%lu", value);
144 explicit String(
const long long value) noexcept
149 std::snprintf(strBuf, 0xff,
"%lld", value);
158 explicit String(
const unsigned long long value,
const bool hexadecimal =
false) noexcept
163 std::snprintf(strBuf, 0xff, hexadecimal ?
"0x%llx" :
"%llu", value);
172 explicit String(
const float value) noexcept
177 std::snprintf(strBuf, 0xff,
"%.12g",
static_cast<double>(value));
186 explicit String(
const double value) noexcept
191 std::snprintf(strBuf, 0xff,
"%.24g", value);
218 DISTRHO_SAFE_ASSERT_RETURN(fBuffer !=
nullptr,);
220 if (fBuffer == _null())
235 std::size_t length()
const noexcept
243 bool isEmpty()
const noexcept
245 return (fBufferLen == 0);
251 bool isNotEmpty()
const noexcept
253 return (fBufferLen != 0);
259 bool contains(
const char*
const strBuf,
const bool ignoreCase =
false)
const noexcept
261 DISTRHO_SAFE_ASSERT_RETURN(strBuf !=
nullptr,
false);
266 return (strcasestr(fBuffer, strBuf) !=
nullptr);
268 String tmp1(fBuffer), tmp2(strBuf);
271 if (tmp1.fBuffer == _null() || tmp2.fBuffer == _null())
276 return (std::strstr(tmp1, tmp2) !=
nullptr);
280 return (std::strstr(fBuffer, strBuf) !=
nullptr);
286 bool isDigit(
const std::size_t pos)
const noexcept
288 DISTRHO_SAFE_ASSERT_RETURN(pos < fBufferLen,
false);
290 return (fBuffer[pos] >=
'0' && fBuffer[pos] <=
'9');
296 bool startsWith(
const char c)
const noexcept
298 DISTRHO_SAFE_ASSERT_RETURN(c !=
'\0',
false);
300 return (fBufferLen > 0 && fBuffer[0] == c);
306 bool startsWith(
const char*
const prefix)
const noexcept
308 DISTRHO_SAFE_ASSERT_RETURN(prefix !=
nullptr,
false);
310 const std::size_t prefixLen(std::strlen(prefix));
312 if (fBufferLen < prefixLen)
315 return (std::strncmp(fBuffer, prefix, prefixLen) == 0);
321 bool endsWith(
const char c)
const noexcept
323 DISTRHO_SAFE_ASSERT_RETURN(c !=
'\0',
false);
325 return (fBufferLen > 0 && fBuffer[fBufferLen-1] == c);
331 bool endsWith(
const char*
const suffix)
const noexcept
333 DISTRHO_SAFE_ASSERT_RETURN(suffix !=
nullptr,
false);
335 const std::size_t suffixLen(std::strlen(suffix));
337 if (fBufferLen < suffixLen)
340 return (std::strncmp(fBuffer + (fBufferLen-suffixLen), suffix, suffixLen) == 0);
347 std::size_t find(
const char c,
bool*
const found =
nullptr)
const noexcept
349 if (fBufferLen == 0 || c ==
'\0')
351 if (found !=
nullptr)
356 for (std::size_t i=0; i < fBufferLen; ++i)
360 if (found !=
nullptr)
366 if (found !=
nullptr)
375 std::size_t find(
const char*
const strBuf,
bool*
const found =
nullptr)
const noexcept
377 if (fBufferLen == 0 || strBuf ==
nullptr || strBuf[0] ==
'\0')
379 if (found !=
nullptr)
384 if (
char*
const subStrBuf = std::strstr(fBuffer, strBuf))
386 const ssize_t ret(subStrBuf - fBuffer);
391 d_safe_assert(
"ret >= 0", __FILE__, __LINE__);
393 if (found !=
nullptr)
398 if (found !=
nullptr)
400 return static_cast<std::size_t
>(ret);
403 if (found !=
nullptr)
412 std::size_t rfind(
const char c,
bool*
const found =
nullptr)
const noexcept
414 if (fBufferLen == 0 || c ==
'\0')
416 if (found !=
nullptr)
421 for (std::size_t i=fBufferLen; i > 0; --i)
423 if (fBuffer[i-1] == c)
425 if (found !=
nullptr)
431 if (found !=
nullptr)
440 std::size_t rfind(
const char*
const strBuf,
bool*
const found =
nullptr)
const noexcept
442 if (found !=
nullptr)
445 if (fBufferLen == 0 || strBuf ==
nullptr || strBuf[0] ==
'\0')
448 const std::size_t strBufLen(std::strlen(strBuf));
450 std::size_t ret = fBufferLen;
451 const char* tmpBuf = fBuffer;
453 for (std::size_t i=0; i < fBufferLen; ++i)
455 if (std::strstr(tmpBuf+1, strBuf) ==
nullptr && std::strncmp(tmpBuf, strBuf, strBufLen) == 0)
457 if (found !=
nullptr)
466 return fBufferLen-ret;
472 void clear() noexcept
480 String& replace(
const char before,
const char after) noexcept
482 DISTRHO_SAFE_ASSERT_RETURN(before !=
'\0' && after !=
'\0', *
this);
484 for (std::size_t i=0; i < fBufferLen; ++i)
486 if (fBuffer[i] == before)
496 String& truncate(
const std::size_t n) noexcept
501 for (std::size_t i=n; i < fBufferLen; ++i)
512 String& toBasic() noexcept
514 for (std::size_t i=0; i < fBufferLen; ++i)
516 if (fBuffer[i] >=
'0' && fBuffer[i] <=
'9')
518 if (fBuffer[i] >=
'A' && fBuffer[i] <=
'Z')
520 if (fBuffer[i] >=
'a' && fBuffer[i] <=
'z')
522 if (fBuffer[i] ==
'_')
534 String& toLower() noexcept
536 static const char kCharDiff(
'a' -
'A');
538 for (std::size_t i=0; i < fBufferLen; ++i)
540 if (fBuffer[i] >=
'A' && fBuffer[i] <=
'Z')
541 fBuffer[i] =
static_cast<char>(fBuffer[i] + kCharDiff);
550 String& toUpper() noexcept
552 static const char kCharDiff(
'a' -
'A');
554 for (std::size_t i=0; i < fBufferLen; ++i)
556 if (fBuffer[i] >=
'a' && fBuffer[i] <=
'z')
557 fBuffer[i] =
static_cast<char>(fBuffer[i] - kCharDiff);
566 const char* buffer()
const noexcept
575 char* getAndReleaseBuffer() noexcept
577 char*
const ret = fBuffer;
587 static String asBase64(
const void*
const data,
const std::size_t dataSize)
589 static const char*
const kBase64Chars =
590 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
591 "abcdefghijklmnopqrstuvwxyz"
594 const std::size_t kTmpBufSize = std::min(d_nextPowerOf2(dataSize/3), 65536U);
596 const uchar* bytesToEncode((
const uchar*)data);
599 uint charArray3[3], charArray4[4];
601 char strBuf[kTmpBufSize+1];
602 strBuf[kTmpBufSize] =
'\0';
603 std::size_t strBufIndex = 0;
607 for (std::size_t s=0; s<dataSize; ++s)
609 charArray3[i++] = *(bytesToEncode++);
613 charArray4[0] = (charArray3[0] & 0xfc) >> 2;
614 charArray4[1] = ((charArray3[0] & 0x03) << 4) + ((charArray3[1] & 0xf0) >> 4);
615 charArray4[2] = ((charArray3[1] & 0x0f) << 2) + ((charArray3[2] & 0xc0) >> 6);
616 charArray4[3] = charArray3[2] & 0x3f;
619 strBuf[strBufIndex++] = kBase64Chars[charArray4[i]];
621 if (strBufIndex >= kTmpBufSize-7)
623 strBuf[strBufIndex] =
'\0';
635 charArray3[j] =
'\0';
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 (j=0; j<4 && i<3 && j<i+1; ++j)
643 strBuf[strBufIndex++] = kBase64Chars[charArray4[j]];
646 strBuf[strBufIndex++] =
'=';
649 if (strBufIndex != 0)
651 strBuf[strBufIndex] =
'\0';
661 operator const char*()
const noexcept
666 char operator[](
const std::size_t pos)
const noexcept
668 if (pos < fBufferLen)
671 d_safe_assert(
"pos < fBufferLen", __FILE__, __LINE__);
673 static char fallback;
678 char& operator[](
const std::size_t pos) noexcept
680 if (pos < fBufferLen)
683 d_safe_assert(
"pos < fBufferLen", __FILE__, __LINE__);
685 static char fallback;
690 bool operator==(
const char*
const strBuf)
const noexcept
692 return (strBuf !=
nullptr && std::strcmp(fBuffer, strBuf) == 0);
695 bool operator==(
const String& str)
const noexcept
697 return operator==(str.fBuffer);
700 bool operator!=(
const char*
const strBuf)
const noexcept
702 return !operator==(strBuf);
705 bool operator!=(
const String& str)
const noexcept
707 return !operator==(str.fBuffer);
710 String& operator=(
const char*
const strBuf) noexcept
724 String& operator+=(
const char*
const strBuf) noexcept
726 if (strBuf ==
nullptr)
729 const std::size_t newBufSize = fBufferLen + std::strlen(strBuf) + 1;
730 char newBuf[newBufSize];
732 std::strcpy(newBuf, fBuffer);
733 std::strcat(newBuf, strBuf);
735 _dup(newBuf, newBufSize-1);
742 return operator+=(str.fBuffer);
745 String operator+(
const char*
const strBuf) noexcept
747 const std::size_t newBufSize = fBufferLen + ((strBuf !=
nullptr) ? std::strlen(strBuf) : 0) + 1;
748 char newBuf[newBufSize];
750 std::strcpy(newBuf, fBuffer);
752 if (strBuf !=
nullptr)
753 std::strcat(newBuf, strBuf);
760 return operator+(str.fBuffer);
767 std::size_t fBufferLen;
773 static char* _null() noexcept
775 static char sNull =
'\0';
787 void _dup(
const char*
const strBuf,
const std::size_t size = 0) noexcept
789 if (strBuf !=
nullptr)
792 if (std::strcmp(fBuffer, strBuf) == 0)
795 if (fBuffer != _null())
798 fBufferLen = (size > 0) ? size : std::strlen(strBuf);
799 fBuffer = (
char*)std::malloc(fBufferLen+1);
801 if (fBuffer ==
nullptr)
808 std::strcpy(fBuffer, strBuf);
810 fBuffer[fBufferLen] =
'\0';
814 DISTRHO_SAFE_ASSERT(size == 0);
817 if (fBuffer == _null())
820 DISTRHO_SAFE_ASSERT(fBuffer !=
nullptr);
828 DISTRHO_PREVENT_HEAP_ALLOCATION
834 String operator+(
const String& strBefore,
const char*
const strBufAfter) noexcept
836 const char*
const strBufBefore = strBefore.buffer();
837 const std::size_t newBufSize = strBefore.length() + ((strBufAfter !=
nullptr) ? std::strlen(strBufAfter) : 0) + 1;
838 char newBuf[newBufSize];
840 std::strcpy(newBuf, strBufBefore);
841 std::strcat(newBuf, strBufAfter);
847 String operator+(
const char*
const strBufBefore,
const String& strAfter) noexcept
849 const char*
const strBufAfter = strAfter.buffer();
850 const std::size_t newBufSize = ((strBufBefore !=
nullptr) ? std::strlen(strBufBefore) : 0) + strAfter.length() + 1;
851 char newBuf[newBufSize];
853 std::strcpy(newBuf, strBufBefore);
854 std::strcat(newBuf, strBufAfter);
861 END_NAMESPACE_DISTRHO
863 #endif // DISTRHO_STRING_HPP_INCLUDED