17 #ifndef DISTRHO_STRING_HPP_INCLUDED
18 #define DISTRHO_STRING_HPP_INCLUDED
20 #include "../DistrhoUtils.hpp"
22 START_NAMESPACE_DISTRHO
43 explicit String(
const char c) noexcept
57 explicit String(
char*
const strBuf) noexcept
67 explicit String(
const char*
const strBuf) noexcept
77 explicit String(
const int value) noexcept
82 std::snprintf(strBuf, 0xff,
"%d", value);
91 explicit String(
const unsigned int value,
const bool hexadecimal =
false) noexcept
96 std::snprintf(strBuf, 0xff, hexadecimal ?
"0x%x" :
"%u", value);
105 explicit String(
const long value) noexcept
110 std::snprintf(strBuf, 0xff,
"%ld", value);
119 explicit String(
const unsigned long value,
const bool hexadecimal =
false) noexcept
124 std::snprintf(strBuf, 0xff, hexadecimal ?
"0x%lx" :
"%lu", value);
133 explicit String(
const long long value) noexcept
138 std::snprintf(strBuf, 0xff,
"%lld", value);
147 explicit String(
const unsigned long long value,
const bool hexadecimal =
false) noexcept
152 std::snprintf(strBuf, 0xff, hexadecimal ?
"0x%llx" :
"%llu", value);
161 explicit String(
const float value) noexcept
166 std::snprintf(strBuf, 0xff,
"%f", value);
175 explicit String(
const double value) noexcept
180 std::snprintf(strBuf, 0xff,
"%g", value);
207 DISTRHO_SAFE_ASSERT_RETURN(fBuffer !=
nullptr,);
209 if (fBuffer == _null())
224 std::size_t length()
const noexcept
232 bool isEmpty()
const noexcept
234 return (fBufferLen == 0);
240 bool isNotEmpty()
const noexcept
242 return (fBufferLen != 0);
248 bool contains(
const char*
const strBuf,
const bool ignoreCase =
false)
const noexcept
250 DISTRHO_SAFE_ASSERT_RETURN(strBuf !=
nullptr,
false);
255 return (strcasestr(fBuffer, strBuf) !=
nullptr);
257 String tmp1(fBuffer), tmp2(strBuf);
260 if (tmp1.fBuffer == _null() || tmp2.fBuffer == _null())
265 return (std::strstr(tmp1, tmp2) !=
nullptr);
269 return (std::strstr(fBuffer, strBuf) !=
nullptr);
275 bool isDigit(
const std::size_t pos)
const noexcept
277 DISTRHO_SAFE_ASSERT_RETURN(pos < fBufferLen,
false);
279 return (fBuffer[pos] >=
'0' && fBuffer[pos] <=
'9');
285 bool startsWith(
const char c)
const noexcept
287 DISTRHO_SAFE_ASSERT_RETURN(c !=
'\0',
false);
289 return (fBufferLen > 0 && fBuffer[0] == c);
295 bool startsWith(
const char*
const prefix)
const noexcept
297 DISTRHO_SAFE_ASSERT_RETURN(prefix !=
nullptr,
false);
299 const std::size_t prefixLen(std::strlen(prefix));
301 if (fBufferLen < prefixLen)
304 return (std::strncmp(fBuffer, prefix, prefixLen) == 0);
310 bool endsWith(
const char c)
const noexcept
312 DISTRHO_SAFE_ASSERT_RETURN(c !=
'\0',
false);
314 return (fBufferLen > 0 && fBuffer[fBufferLen-1] == c);
320 bool endsWith(
const char*
const suffix)
const noexcept
322 DISTRHO_SAFE_ASSERT_RETURN(suffix !=
nullptr,
false);
324 const std::size_t suffixLen(std::strlen(suffix));
326 if (fBufferLen < suffixLen)
329 return (std::strncmp(fBuffer + (fBufferLen-suffixLen), suffix, suffixLen) == 0);
336 std::size_t find(
const char c,
bool*
const found =
nullptr)
const noexcept
338 if (fBufferLen == 0 || c ==
'\0')
340 if (found !=
nullptr)
345 for (std::size_t i=0; i < fBufferLen; ++i)
349 if (found !=
nullptr)
355 if (found !=
nullptr)
364 std::size_t find(
const char*
const strBuf,
bool*
const found =
nullptr)
const noexcept
366 if (fBufferLen == 0 || strBuf ==
nullptr || strBuf[0] ==
'\0')
368 if (found !=
nullptr)
373 if (
char*
const subStrBuf = std::strstr(fBuffer, strBuf))
375 const ssize_t ret(subStrBuf - fBuffer);
380 d_safe_assert(
"ret >= 0", __FILE__, __LINE__);
382 if (found !=
nullptr)
387 if (found !=
nullptr)
389 return static_cast<std::size_t
>(ret);
392 if (found !=
nullptr)
401 std::size_t rfind(
const char c,
bool*
const found =
nullptr)
const noexcept
403 if (fBufferLen == 0 || c ==
'\0')
405 if (found !=
nullptr)
410 for (std::size_t i=fBufferLen; i > 0; --i)
412 if (fBuffer[i-1] == c)
414 if (found !=
nullptr)
420 if (found !=
nullptr)
429 std::size_t rfind(
const char*
const strBuf,
bool*
const found =
nullptr)
const noexcept
431 if (found !=
nullptr)
434 if (fBufferLen == 0 || strBuf ==
nullptr || strBuf[0] ==
'\0')
437 const std::size_t strBufLen(std::strlen(strBuf));
439 std::size_t ret = fBufferLen;
440 const char* tmpBuf = fBuffer;
442 for (std::size_t i=0; i < fBufferLen; ++i)
444 if (std::strstr(tmpBuf+1, strBuf) ==
nullptr && std::strncmp(tmpBuf, strBuf, strBufLen) == 0)
446 if (found !=
nullptr)
455 return fBufferLen-ret;
461 void clear() noexcept
469 String& replace(
const char before,
const char after) noexcept
471 DISTRHO_SAFE_ASSERT_RETURN(before !=
'\0' && after !=
'\0', *
this);
473 for (std::size_t i=0; i < fBufferLen; ++i)
475 if (fBuffer[i] == before)
485 String& truncate(
const std::size_t n) noexcept
490 for (std::size_t i=n; i < fBufferLen; ++i)
501 String& toBasic() noexcept
503 for (std::size_t i=0; i < fBufferLen; ++i)
505 if (fBuffer[i] >=
'0' && fBuffer[i] <=
'9')
507 if (fBuffer[i] >=
'A' && fBuffer[i] <=
'Z')
509 if (fBuffer[i] >=
'a' && fBuffer[i] <=
'z')
511 if (fBuffer[i] ==
'_')
523 String& toLower() noexcept
525 static const char kCharDiff(
'a' -
'A');
527 for (std::size_t i=0; i < fBufferLen; ++i)
529 if (fBuffer[i] >=
'A' && fBuffer[i] <=
'Z')
530 fBuffer[i] =
static_cast<char>(fBuffer[i] + kCharDiff);
539 String& toUpper() noexcept
541 static const char kCharDiff(
'a' -
'A');
543 for (std::size_t i=0; i < fBufferLen; ++i)
545 if (fBuffer[i] >=
'a' && fBuffer[i] <=
'z')
546 fBuffer[i] =
static_cast<char>(fBuffer[i] - kCharDiff);
555 const char* buffer()
const noexcept
564 static String asBase64(
const void*
const data,
const std::size_t dataSize)
566 static const char*
const kBase64Chars =
567 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
568 "abcdefghijklmnopqrstuvwxyz"
571 const std::size_t kTmpBufSize = d_nextPowerOf2(dataSize/3);
573 const uchar* bytesToEncode((
const uchar*)data);
576 uint charArray3[3], charArray4[4];
578 char strBuf[kTmpBufSize+1];
579 strBuf[kTmpBufSize] =
'\0';
580 std::size_t strBufIndex = 0;
584 for (std::size_t s=0; s<dataSize; ++s)
586 charArray3[i++] = *(bytesToEncode++);
590 charArray4[0] = (charArray3[0] & 0xfc) >> 2;
591 charArray4[1] = ((charArray3[0] & 0x03) << 4) + ((charArray3[1] & 0xf0) >> 4);
592 charArray4[2] = ((charArray3[1] & 0x0f) << 2) + ((charArray3[2] & 0xc0) >> 6);
593 charArray4[3] = charArray3[2] & 0x3f;
596 strBuf[strBufIndex++] = kBase64Chars[charArray4[i]];
598 if (strBufIndex >= kTmpBufSize-7)
600 strBuf[strBufIndex] =
'\0';
612 charArray3[j] =
'\0';
614 charArray4[0] = (charArray3[0] & 0xfc) >> 2;
615 charArray4[1] = ((charArray3[0] & 0x03) << 4) + ((charArray3[1] & 0xf0) >> 4);
616 charArray4[2] = ((charArray3[1] & 0x0f) << 2) + ((charArray3[2] & 0xc0) >> 6);
617 charArray4[3] = charArray3[2] & 0x3f;
619 for (j=0; j<4 && i<3 && j<i+1; ++j)
620 strBuf[strBufIndex++] = kBase64Chars[charArray4[j]];
623 strBuf[strBufIndex++] =
'=';
626 if (strBufIndex != 0)
628 strBuf[strBufIndex] =
'\0';
638 operator const char*()
const noexcept
643 char operator[](
const std::size_t pos)
const noexcept
645 if (pos < fBufferLen)
648 d_safe_assert(
"pos < fBufferLen", __FILE__, __LINE__);
650 static char fallback;
655 char& operator[](
const std::size_t pos) noexcept
657 if (pos < fBufferLen)
660 d_safe_assert(
"pos < fBufferLen", __FILE__, __LINE__);
662 static char fallback;
667 bool operator==(
const char*
const strBuf)
const noexcept
669 return (strBuf !=
nullptr && std::strcmp(fBuffer, strBuf) == 0);
672 bool operator==(
const String& str)
const noexcept
674 return operator==(str.fBuffer);
677 bool operator!=(
const char*
const strBuf)
const noexcept
679 return !operator==(strBuf);
682 bool operator!=(
const String& str)
const noexcept
684 return !operator==(str.fBuffer);
687 String& operator=(
const char*
const strBuf) noexcept
701 String& operator+=(
const char*
const strBuf) noexcept
703 if (strBuf ==
nullptr)
706 const std::size_t newBufSize = fBufferLen + std::strlen(strBuf) + 1;
707 char newBuf[newBufSize];
709 std::strcpy(newBuf, fBuffer);
710 std::strcat(newBuf, strBuf);
712 _dup(newBuf, newBufSize-1);
719 return operator+=(str.fBuffer);
722 String operator+(
const char*
const strBuf) noexcept
724 const std::size_t newBufSize = fBufferLen + ((strBuf !=
nullptr) ? std::strlen(strBuf) : 0) + 1;
725 char newBuf[newBufSize];
727 std::strcpy(newBuf, fBuffer);
729 if (strBuf !=
nullptr)
730 std::strcat(newBuf, strBuf);
737 return operator+(str.fBuffer);
744 std::size_t fBufferLen;
750 static char* _null() noexcept
752 static char sNull =
'\0';
764 void _dup(
const char*
const strBuf,
const std::size_t size = 0) noexcept
766 if (strBuf !=
nullptr)
769 if (std::strcmp(fBuffer, strBuf) == 0)
772 if (fBuffer != _null())
775 fBufferLen = (size > 0) ? size : std::strlen(strBuf);
776 fBuffer = (
char*)std::malloc(fBufferLen+1);
778 if (fBuffer ==
nullptr)
785 std::strcpy(fBuffer, strBuf);
787 fBuffer[fBufferLen] =
'\0';
791 DISTRHO_SAFE_ASSERT(size == 0);
794 if (fBuffer == _null())
797 DISTRHO_SAFE_ASSERT(fBuffer !=
nullptr);
805 DISTRHO_PREVENT_HEAP_ALLOCATION
811 String operator+(
const String& strBefore,
const char*
const strBufAfter) noexcept
813 const char*
const strBufBefore = strBefore.buffer();
814 const std::size_t newBufSize = strBefore.length() + ((strBufAfter !=
nullptr) ? std::strlen(strBufAfter) : 0) + 1;
815 char newBuf[newBufSize];
817 std::strcpy(newBuf, strBufBefore);
818 std::strcat(newBuf, strBufAfter);
824 String operator+(
const char*
const strBufBefore,
const String& strAfter) noexcept
826 const char*
const strBufAfter = strAfter.buffer();
827 const std::size_t newBufSize = ((strBufBefore !=
nullptr) ? std::strlen(strBufBefore) : 0) + strAfter.length() + 1;
828 char newBuf[newBufSize];
830 std::strcpy(newBuf, strBufBefore);
831 std::strcat(newBuf, strBufAfter);
838 END_NAMESPACE_DISTRHO
840 #endif // DISTRHO_STRING_HPP_INCLUDED
Definition: String.hpp:27