Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

860 lines
21KB

  1. /*
  2. * Carla String
  3. * Copyright (C) 2013-2014 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the doc/GPL.txt file.
  16. */
  17. #ifndef CARLA_STRING_HPP_INCLUDED
  18. #define CARLA_STRING_HPP_INCLUDED
  19. #include "CarlaJuceUtils.hpp"
  20. namespace std {
  21. #ifdef CARLA_OS_HAIKU
  22. using ::snprintf;
  23. #endif
  24. using ::ssize_t; // FIXME?
  25. }
  26. // -----------------------------------------------------------------------
  27. // CarlaString class
  28. class CarlaString
  29. {
  30. public:
  31. // -------------------------------------------------------------------
  32. // constructors (no explicit conversions allowed)
  33. /*
  34. * Empty string.
  35. */
  36. explicit CarlaString() noexcept
  37. : fBuffer(_null()),
  38. fBufferLen(0) {}
  39. /*
  40. * Simple character.
  41. */
  42. explicit CarlaString(const char c) noexcept
  43. : fBuffer(_null()),
  44. fBufferLen(0)
  45. {
  46. char ch[2];
  47. ch[0] = c;
  48. ch[1] = '\0';
  49. _dup(ch);
  50. }
  51. /*
  52. * Simple char string.
  53. */
  54. explicit CarlaString(char* const strBuf) noexcept
  55. : fBuffer(_null()),
  56. fBufferLen(0)
  57. {
  58. _dup(strBuf);
  59. }
  60. /*
  61. * Simple const char string.
  62. */
  63. explicit CarlaString(const char* const strBuf) noexcept
  64. : fBuffer(_null()),
  65. fBufferLen(0)
  66. {
  67. _dup(strBuf);
  68. }
  69. /*
  70. * Integer.
  71. */
  72. explicit CarlaString(const int value) noexcept
  73. : fBuffer(_null()),
  74. fBufferLen(0)
  75. {
  76. char strBuf[0xff+1];
  77. std::snprintf(strBuf, 0xff, "%d", value);
  78. strBuf[0xff] = '\0';
  79. _dup(strBuf);
  80. }
  81. /*
  82. * Unsigned integer, possibly in hexadecimal.
  83. */
  84. explicit CarlaString(const unsigned int value, const bool hexadecimal = false) noexcept
  85. : fBuffer(_null()),
  86. fBufferLen(0)
  87. {
  88. char strBuf[0xff+1];
  89. std::snprintf(strBuf, 0xff, hexadecimal ? "0x%x" : "%u", value);
  90. strBuf[0xff] = '\0';
  91. _dup(strBuf);
  92. }
  93. /*
  94. * Long integer.
  95. */
  96. explicit CarlaString(const long value) noexcept
  97. : fBuffer(_null()),
  98. fBufferLen(0)
  99. {
  100. char strBuf[0xff+1];
  101. std::snprintf(strBuf, 0xff, "%ld", value);
  102. strBuf[0xff] = '\0';
  103. _dup(strBuf);
  104. }
  105. /*
  106. * Long unsigned integer, possibly hexadecimal.
  107. */
  108. explicit CarlaString(const unsigned long value, const bool hexadecimal = false) noexcept
  109. : fBuffer(_null()),
  110. fBufferLen(0)
  111. {
  112. char strBuf[0xff+1];
  113. std::snprintf(strBuf, 0xff, hexadecimal ? "0x%lx" : "%lu", value);
  114. strBuf[0xff] = '\0';
  115. _dup(strBuf);
  116. }
  117. /*
  118. * Long long integer.
  119. */
  120. explicit CarlaString(const long long value) noexcept
  121. : fBuffer(_null()),
  122. fBufferLen(0)
  123. {
  124. char strBuf[0xff+1];
  125. std::snprintf(strBuf, 0xff, "%lld", value);
  126. strBuf[0xff] = '\0';
  127. _dup(strBuf);
  128. }
  129. /*
  130. * Long long unsigned integer, possibly hexadecimal.
  131. */
  132. explicit CarlaString(const unsigned long long value, const bool hexadecimal = false) noexcept
  133. : fBuffer(_null()),
  134. fBufferLen(0)
  135. {
  136. char strBuf[0xff+1];
  137. std::snprintf(strBuf, 0xff, hexadecimal ? "0x%llx" : "%llu", value);
  138. strBuf[0xff] = '\0';
  139. _dup(strBuf);
  140. }
  141. /*
  142. * Single-precision floating point number.
  143. */
  144. explicit CarlaString(const float value) noexcept
  145. : fBuffer(_null()),
  146. fBufferLen(0)
  147. {
  148. char strBuf[0xff+1];
  149. std::snprintf(strBuf, 0xff, "%f", value);
  150. strBuf[0xff] = '\0';
  151. _dup(strBuf);
  152. }
  153. /*
  154. * Double-precision floating point number.
  155. */
  156. explicit CarlaString(const double value) noexcept
  157. : fBuffer(_null()),
  158. fBufferLen(0)
  159. {
  160. char strBuf[0xff+1];
  161. std::snprintf(strBuf, 0xff, "%g", value);
  162. strBuf[0xff] = '\0';
  163. _dup(strBuf);
  164. }
  165. // -------------------------------------------------------------------
  166. // non-explicit constructor
  167. /*
  168. * Create string from another string.
  169. */
  170. CarlaString(const CarlaString& str) noexcept
  171. : fBuffer(_null()),
  172. fBufferLen(0)
  173. {
  174. _dup(str.fBuffer);
  175. }
  176. // -------------------------------------------------------------------
  177. // destructor
  178. /*
  179. * Destructor.
  180. */
  181. ~CarlaString() noexcept
  182. {
  183. CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr,);
  184. if (fBuffer == _null())
  185. return;
  186. std::free(fBuffer);
  187. fBuffer = nullptr;
  188. fBufferLen = 0;
  189. }
  190. // -------------------------------------------------------------------
  191. // public methods
  192. /*
  193. * Get length of the string.
  194. */
  195. std::size_t length() const noexcept
  196. {
  197. return fBufferLen;
  198. }
  199. /*
  200. * Check if the string is empty.
  201. */
  202. bool isEmpty() const noexcept
  203. {
  204. return (fBufferLen == 0);
  205. }
  206. /*
  207. * Check if the string is not empty.
  208. */
  209. bool isNotEmpty() const noexcept
  210. {
  211. return (fBufferLen != 0);
  212. }
  213. /*
  214. * Check if the string contains another string, optionally ignoring case.
  215. */
  216. bool contains(const char* const strBuf, const bool ignoreCase = false) const noexcept
  217. {
  218. CARLA_SAFE_ASSERT_RETURN(strBuf != nullptr, false);
  219. if (ignoreCase)
  220. {
  221. #ifdef __USE_GNU
  222. return (strcasestr(fBuffer, strBuf) != nullptr);
  223. #else
  224. CarlaString tmp1(fBuffer), tmp2(strBuf);
  225. // memory allocation failed or empty string(s)
  226. if (tmp1.fBuffer == _null() || tmp2.fBuffer == _null())
  227. return false;
  228. tmp1.toLower();
  229. tmp2.toLower();
  230. return (std::strstr(tmp1, tmp2) != nullptr);
  231. #endif
  232. }
  233. return (std::strstr(fBuffer, strBuf) != nullptr);
  234. }
  235. /*
  236. * Check if character at 'pos' is a digit.
  237. */
  238. bool isDigit(const std::size_t pos) const noexcept
  239. {
  240. CARLA_SAFE_ASSERT_RETURN(pos < fBufferLen, false);
  241. return (fBuffer[pos] >= '0' && fBuffer[pos] <= '9');
  242. }
  243. /*
  244. * Check if the string starts with the character 'c'.
  245. */
  246. bool startsWith(const char c) const noexcept
  247. {
  248. CARLA_SAFE_ASSERT_RETURN(c != '\0', false);
  249. return (fBufferLen > 0 && fBuffer[0] == c);
  250. }
  251. /*
  252. * Check if the string starts with the string 'prefix'.
  253. */
  254. bool startsWith(const char* const prefix) const noexcept
  255. {
  256. CARLA_SAFE_ASSERT_RETURN(prefix != nullptr, false);
  257. const std::size_t prefixLen(std::strlen(prefix));
  258. if (fBufferLen < prefixLen)
  259. return false;
  260. return (std::strncmp(fBuffer, prefix, prefixLen) == 0);
  261. }
  262. /*
  263. * Check if the string ends with the character 'c'.
  264. */
  265. bool endsWith(const char c) const noexcept
  266. {
  267. CARLA_SAFE_ASSERT_RETURN(c != '\0', false);
  268. return (fBufferLen > 0 && fBuffer[fBufferLen-1] == c);
  269. }
  270. /*
  271. * Check if the string ends with the string 'suffix'.
  272. */
  273. bool endsWith(const char* const suffix) const noexcept
  274. {
  275. CARLA_SAFE_ASSERT_RETURN(suffix != nullptr, false);
  276. const std::size_t suffixLen(std::strlen(suffix));
  277. if (fBufferLen < suffixLen)
  278. return false;
  279. return (std::strncmp(fBuffer + (fBufferLen-suffixLen), suffix, suffixLen) == 0);
  280. }
  281. /*
  282. * Find the first occurrence of character 'c' in the string.
  283. * Returns "length()" if the character is not found.
  284. */
  285. std::size_t find(const char c, bool* const found = nullptr) const noexcept
  286. {
  287. if (fBufferLen == 0 || c == '\0')
  288. {
  289. if (found != nullptr)
  290. *found = false;
  291. return fBufferLen;
  292. }
  293. for (std::size_t i=0; i < fBufferLen; ++i)
  294. {
  295. if (fBuffer[i] == c)
  296. {
  297. if (found != nullptr)
  298. *found = true;
  299. return i;
  300. }
  301. }
  302. if (found != nullptr)
  303. *found = false;
  304. return fBufferLen;
  305. }
  306. /*
  307. * Find the first occurrence of string 'strBuf' in the string.
  308. * Returns "length()" if the string is not found.
  309. */
  310. std::size_t find(const char* const strBuf, bool* const found = nullptr) const noexcept
  311. {
  312. if (fBufferLen == 0 || strBuf == nullptr || strBuf[0] == '\0')
  313. {
  314. if (found != nullptr)
  315. *found = false;
  316. return fBufferLen;
  317. }
  318. if (char* const subStrBuf = std::strstr(fBuffer, strBuf))
  319. {
  320. const std::ssize_t ret(subStrBuf - fBuffer);
  321. if (ret < 0)
  322. {
  323. // should never happen!
  324. carla_safe_assert_int("ret >= 0", __FILE__, __LINE__, int(ret));
  325. if (found != nullptr)
  326. *found = false;
  327. return fBufferLen;
  328. }
  329. if (found != nullptr)
  330. *found = true;
  331. return static_cast<std::size_t>(ret);
  332. }
  333. if (found != nullptr)
  334. *found = false;
  335. return fBufferLen;
  336. }
  337. /*
  338. * Find the last occurrence of character 'c' in the string.
  339. * Returns "length()" if the character is not found.
  340. */
  341. std::size_t rfind(const char c, bool* const found = nullptr) const noexcept
  342. {
  343. if (fBufferLen == 0 || c == '\0')
  344. {
  345. if (found != nullptr)
  346. *found = false;
  347. return fBufferLen;
  348. }
  349. for (std::size_t i=fBufferLen; i > 0; --i)
  350. {
  351. if (fBuffer[i-1] == c)
  352. {
  353. if (found != nullptr)
  354. *found = true;
  355. return i-1;
  356. }
  357. }
  358. if (found != nullptr)
  359. *found = false;
  360. return fBufferLen;
  361. }
  362. /*
  363. * Find the last occurrence of string 'strBuf' in the string.
  364. * Returns "length()" if the string is not found.
  365. */
  366. std::size_t rfind(const char* const strBuf, bool* const found = nullptr) const noexcept
  367. {
  368. if (found != nullptr)
  369. *found = false;
  370. if (fBufferLen == 0 || strBuf == nullptr || strBuf[0] == '\0')
  371. return fBufferLen;
  372. const std::size_t strBufLen(std::strlen(strBuf));
  373. std::size_t ret = fBufferLen;
  374. const char* tmpBuf = fBuffer;
  375. for (std::size_t i=0; i < fBufferLen; ++i)
  376. {
  377. if (std::strstr(tmpBuf+1, strBuf) == nullptr && std::strncmp(tmpBuf, strBuf, strBufLen) == 0)
  378. {
  379. if (found != nullptr)
  380. *found = true;
  381. break;
  382. }
  383. --ret;
  384. ++tmpBuf;
  385. }
  386. return fBufferLen-ret;
  387. }
  388. /*
  389. * Clear the string.
  390. */
  391. void clear() noexcept
  392. {
  393. truncate(0);
  394. }
  395. /*
  396. * Replace all occurrences of character 'before' with character 'after'.
  397. */
  398. CarlaString& replace(const char before, const char after) noexcept
  399. {
  400. CARLA_SAFE_ASSERT_RETURN(before != '\0' && after != '\0', *this);
  401. for (std::size_t i=0; i < fBufferLen; ++i)
  402. {
  403. if (fBuffer[i] == before)
  404. fBuffer[i] = after;
  405. }
  406. return *this;
  407. }
  408. /*
  409. * Truncate the string to size 'n'.
  410. */
  411. CarlaString& truncate(const std::size_t n) noexcept
  412. {
  413. if (n >= fBufferLen)
  414. return *this;
  415. for (std::size_t i=n; i < fBufferLen; ++i)
  416. fBuffer[i] = '\0';
  417. fBufferLen = n;
  418. return *this;
  419. }
  420. /*
  421. * Convert all non-basic characters to '_'.
  422. */
  423. CarlaString& toBasic() noexcept
  424. {
  425. for (std::size_t i=0; i < fBufferLen; ++i)
  426. {
  427. if (fBuffer[i] >= '0' && fBuffer[i] <= '9')
  428. continue;
  429. if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z')
  430. continue;
  431. if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z')
  432. continue;
  433. if (fBuffer[i] == '_')
  434. continue;
  435. fBuffer[i] = '_';
  436. }
  437. return *this;
  438. }
  439. /*
  440. * Convert to all ascii characters to lowercase.
  441. */
  442. CarlaString& toLower() noexcept
  443. {
  444. static const char kCharDiff('a' - 'A');
  445. for (std::size_t i=0; i < fBufferLen; ++i)
  446. {
  447. if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z')
  448. fBuffer[i] = static_cast<char>(fBuffer[i] + kCharDiff);
  449. }
  450. return *this;
  451. }
  452. /*
  453. * Convert to all ascii characters to uppercase.
  454. */
  455. CarlaString& toUpper() noexcept
  456. {
  457. static const char kCharDiff('a' - 'A');
  458. for (std::size_t i=0; i < fBufferLen; ++i)
  459. {
  460. if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z')
  461. fBuffer[i] = static_cast<char>(fBuffer[i] - kCharDiff);
  462. }
  463. return *this;
  464. }
  465. /*
  466. * Direct access to the string buffer (read-only).
  467. */
  468. const char* buffer() const noexcept
  469. {
  470. return fBuffer;
  471. }
  472. /*
  473. * Return a duplicate string buffer.
  474. * May throw.
  475. */
  476. const char* dup() const
  477. {
  478. return carla_strdup(fBuffer);
  479. }
  480. /*
  481. * Return a duplicate string buffer or null.
  482. */
  483. const char* dupSafe() const noexcept
  484. {
  485. return carla_strdup_safe(fBuffer);
  486. }
  487. // -------------------------------------------------------------------
  488. // base64 stuff, based on http://www.adp-gmbh.ch/cpp/common/base64.html
  489. // Copyright (C) 2004-2008 René Nyffenegger
  490. static CarlaString asBase64(const void* const data, const std::size_t dataSize)
  491. {
  492. static const char* const kBase64Chars =
  493. "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  494. "abcdefghijklmnopqrstuvwxyz"
  495. "0123456789+/";
  496. const uchar* bytesToEncode((const uchar*)data);
  497. uint i=0, j=0;
  498. uint charArray3[3], charArray4[4];
  499. char strBuf[0xff+1];
  500. strBuf[0xff] = '\0';
  501. int strBufIndex = 0;
  502. CarlaString ret;
  503. for (std::size_t s=0; s<dataSize; ++s)
  504. {
  505. charArray3[i++] = *(bytesToEncode++);
  506. if (i == 3)
  507. {
  508. charArray4[0] = (charArray3[0] & 0xfc) >> 2;
  509. charArray4[1] = ((charArray3[0] & 0x03) << 4) + ((charArray3[1] & 0xf0) >> 4);
  510. charArray4[2] = ((charArray3[1] & 0x0f) << 2) + ((charArray3[2] & 0xc0) >> 6);
  511. charArray4[3] = charArray3[2] & 0x3f;
  512. for (i=0; i<4; ++i)
  513. strBuf[strBufIndex++] = kBase64Chars[charArray4[i]];
  514. if (strBufIndex >= 0xff-7)
  515. {
  516. strBuf[strBufIndex] = '\0';
  517. strBufIndex = 0;
  518. ret += strBuf;
  519. }
  520. i = 0;
  521. }
  522. }
  523. if (i != 0)
  524. {
  525. for (j=i; j<3; ++j)
  526. charArray3[j] = '\0';
  527. charArray4[0] = (charArray3[0] & 0xfc) >> 2;
  528. charArray4[1] = ((charArray3[0] & 0x03) << 4) + ((charArray3[1] & 0xf0) >> 4);
  529. charArray4[2] = ((charArray3[1] & 0x0f) << 2) + ((charArray3[2] & 0xc0) >> 6);
  530. charArray4[3] = charArray3[2] & 0x3f;
  531. for (j=0; j<4 && i<3 && j<i+1; ++j)
  532. strBuf[strBufIndex++] = kBase64Chars[charArray4[j]];
  533. for (; i++ < 3;)
  534. strBuf[strBufIndex++] = '=';
  535. }
  536. if (strBufIndex != 0)
  537. {
  538. strBuf[strBufIndex] = '\0';
  539. ret += strBuf;
  540. }
  541. return ret;
  542. }
  543. // -------------------------------------------------------------------
  544. // public operators
  545. operator const char*() const noexcept
  546. {
  547. return fBuffer;
  548. }
  549. char operator[](const std::size_t pos) const noexcept
  550. {
  551. if (pos < fBufferLen)
  552. return fBuffer[pos];
  553. carla_safe_assert("pos < fBufferLen", __FILE__, __LINE__);
  554. static char fallback;
  555. fallback = '\0';
  556. return fallback;
  557. }
  558. char& operator[](const std::size_t pos) noexcept
  559. {
  560. if (pos < fBufferLen)
  561. return fBuffer[pos];
  562. carla_safe_assert("pos < fBufferLen", __FILE__, __LINE__);
  563. static char fallback;
  564. fallback = '\0';
  565. return fallback;
  566. }
  567. bool operator==(const char* const strBuf) const noexcept
  568. {
  569. return (strBuf != nullptr && std::strcmp(fBuffer, strBuf) == 0);
  570. }
  571. bool operator==(const CarlaString& str) const noexcept
  572. {
  573. return operator==(str.fBuffer);
  574. }
  575. bool operator!=(const char* const strBuf) const noexcept
  576. {
  577. return !operator==(strBuf);
  578. }
  579. bool operator!=(const CarlaString& str) const noexcept
  580. {
  581. return !operator==(str.fBuffer);
  582. }
  583. CarlaString& operator=(const char* const strBuf) noexcept
  584. {
  585. _dup(strBuf);
  586. return *this;
  587. }
  588. CarlaString& operator=(const CarlaString& str) noexcept
  589. {
  590. _dup(str.fBuffer);
  591. return *this;
  592. }
  593. CarlaString& operator+=(const char* const strBuf) noexcept
  594. {
  595. if (strBuf == nullptr)
  596. return *this;
  597. const std::size_t newBufSize = fBufferLen + std::strlen(strBuf) + 1;
  598. char newBuf[newBufSize];
  599. std::strcpy(newBuf, fBuffer);
  600. std::strcat(newBuf, strBuf);
  601. _dup(newBuf, newBufSize-1);
  602. return *this;
  603. }
  604. CarlaString& operator+=(const CarlaString& str) noexcept
  605. {
  606. return operator+=(str.fBuffer);
  607. }
  608. CarlaString operator+(const char* const strBuf) noexcept
  609. {
  610. const std::size_t newBufSize = fBufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1;
  611. char newBuf[newBufSize];
  612. std::strcpy(newBuf, fBuffer);
  613. if (strBuf != nullptr)
  614. std::strcat(newBuf, strBuf);
  615. return CarlaString(newBuf);
  616. }
  617. CarlaString operator+(const CarlaString& str) noexcept
  618. {
  619. return operator+(str.fBuffer);
  620. }
  621. // -------------------------------------------------------------------
  622. private:
  623. char* fBuffer; // the actual string buffer
  624. std::size_t fBufferLen; // string length
  625. /*
  626. * Static null string.
  627. * Prevents allocation for new and/or empty strings.
  628. */
  629. static char* _null() noexcept
  630. {
  631. static char sNull = '\0';
  632. return &sNull;
  633. }
  634. /*
  635. * Helper function.
  636. * Called whenever the string needs to be allocated.
  637. *
  638. * Notes:
  639. * - Allocates string only if 'strBuf' is not null and new string contents are different
  640. * - If 'strBuf' is null, 'size' must be 0
  641. */
  642. void _dup(const char* const strBuf, const std::size_t size = 0) noexcept
  643. {
  644. if (strBuf != nullptr)
  645. {
  646. // don't recreate string if contents match
  647. if (std::strcmp(fBuffer, strBuf) == 0)
  648. return;
  649. if (fBuffer != _null())
  650. std::free(fBuffer);
  651. fBufferLen = (size > 0) ? size : std::strlen(strBuf);
  652. fBuffer = (char*)std::malloc(fBufferLen+1);
  653. if (fBuffer == nullptr)
  654. {
  655. fBuffer = _null();
  656. fBufferLen = 0;
  657. return;
  658. }
  659. std::strcpy(fBuffer, strBuf);
  660. fBuffer[fBufferLen] = '\0';
  661. }
  662. else
  663. {
  664. CARLA_SAFE_ASSERT(size == 0);
  665. // don't recreate null string
  666. if (fBuffer == _null())
  667. return;
  668. CARLA_SAFE_ASSERT(fBuffer != nullptr);
  669. std::free(fBuffer);
  670. fBuffer = _null();
  671. fBufferLen = 0;
  672. }
  673. }
  674. CARLA_PREVENT_HEAP_ALLOCATION
  675. };
  676. // -----------------------------------------------------------------------
  677. static inline
  678. CarlaString operator+(const CarlaString& strBefore, const char* const strBufAfter) noexcept
  679. {
  680. const char* const strBufBefore = strBefore.buffer();
  681. const std::size_t newBufSize = strBefore.length() + ((strBufAfter != nullptr) ? std::strlen(strBufAfter) : 0) + 1;
  682. char newBuf[newBufSize];
  683. std::strcpy(newBuf, strBufBefore);
  684. std::strcat(newBuf, strBufAfter);
  685. return CarlaString(newBuf);
  686. }
  687. static inline
  688. CarlaString operator+(const char* const strBufBefore, const CarlaString& strAfter) noexcept
  689. {
  690. const char* const strBufAfter = strAfter.buffer();
  691. const std::size_t newBufSize = ((strBufBefore != nullptr) ? std::strlen(strBufBefore) : 0) + strAfter.length() + 1;
  692. char newBuf[newBufSize];
  693. std::strcpy(newBuf, strBufBefore);
  694. std::strcat(newBuf, strBufAfter);
  695. return CarlaString(newBuf);
  696. }
  697. // -----------------------------------------------------------------------
  698. #endif // CARLA_STRING_HPP_INCLUDED