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.

512 lines
12KB

  1. /*
  2. * Carla String
  3. * Copyright (C) 2013 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. // -----------------------------------------------------------------------
  21. // CarlaString class
  22. class CarlaString
  23. {
  24. public:
  25. // -------------------------------------------------------------------
  26. // constructors (no explicit conversions allowed)
  27. explicit CarlaString()
  28. {
  29. _init();
  30. _dup(nullptr);
  31. }
  32. explicit CarlaString(char* const strBuf)
  33. {
  34. _init();
  35. _dup(strBuf);
  36. }
  37. explicit CarlaString(const char* const strBuf)
  38. {
  39. _init();
  40. _dup(strBuf);
  41. }
  42. explicit CarlaString(const int value)
  43. {
  44. char strBuf[0xff+1];
  45. carla_zeroChar(strBuf, 0xff+1);
  46. std::snprintf(strBuf, 0xff, "%d", value);
  47. _init();
  48. _dup(strBuf);
  49. }
  50. explicit CarlaString(const unsigned int value, const bool hexadecimal = false)
  51. {
  52. char strBuf[0xff+1];
  53. carla_zeroChar(strBuf, 0xff+1);
  54. std::snprintf(strBuf, 0xff, hexadecimal ? "0x%x" : "%u", value);
  55. _init();
  56. _dup(strBuf);
  57. }
  58. explicit CarlaString(const long int value)
  59. {
  60. char strBuf[0xff+1];
  61. carla_zeroChar(strBuf, 0xff+1);
  62. std::snprintf(strBuf, 0xff, "%ld", value);
  63. _init();
  64. _dup(strBuf);
  65. }
  66. explicit CarlaString(const unsigned long int value, const bool hexadecimal = false)
  67. {
  68. char strBuf[0xff+1];
  69. carla_zeroChar(strBuf, 0xff+1);
  70. std::snprintf(strBuf, 0xff, hexadecimal ? "0x%lx" : "%lu", value);
  71. _init();
  72. _dup(strBuf);
  73. }
  74. explicit CarlaString(const float value)
  75. {
  76. char strBuf[0xff+1];
  77. carla_zeroChar(strBuf, 0xff+1);
  78. std::snprintf(strBuf, 0xff, "%f", value);
  79. _init();
  80. _dup(strBuf);
  81. }
  82. explicit CarlaString(const double value)
  83. {
  84. char strBuf[0xff+1];
  85. carla_zeroChar(strBuf, 0xff+1);
  86. std::snprintf(strBuf, 0xff, "%g", value);
  87. _init();
  88. _dup(strBuf);
  89. }
  90. // -------------------------------------------------------------------
  91. // non-explicit constructor
  92. CarlaString(const CarlaString& str)
  93. {
  94. _init();
  95. _dup(str.fBuffer);
  96. }
  97. // -------------------------------------------------------------------
  98. // destructor
  99. ~CarlaString()
  100. {
  101. CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr,);
  102. delete[] fBuffer;
  103. fBuffer = nullptr;
  104. }
  105. // -------------------------------------------------------------------
  106. // public methods
  107. size_t length() const noexcept
  108. {
  109. return fBufferLen;
  110. }
  111. bool isEmpty() const noexcept
  112. {
  113. return (fBufferLen == 0);
  114. }
  115. bool isNotEmpty() const noexcept
  116. {
  117. return (fBufferLen != 0);
  118. }
  119. #ifdef __USE_GNU
  120. bool contains(const char* const strBuf, const bool ignoreCase = false) const
  121. {
  122. CARLA_SAFE_ASSERT_RETURN(strBuf != nullptr, false);
  123. if (ignoreCase)
  124. return (strcasestr(fBuffer, strBuf) != nullptr);
  125. else
  126. return (std::strstr(fBuffer, strBuf) != nullptr);
  127. }
  128. bool contains(const CarlaString& str, const bool ignoreCase = false) const
  129. {
  130. return contains(str.fBuffer, ignoreCase);
  131. }
  132. #else
  133. bool contains(const char* const strBuf) const
  134. {
  135. CARLA_SAFE_ASSERT_RETURN(strBuf != nullptr, false);
  136. return (std::strstr(fBuffer, strBuf) != nullptr);
  137. }
  138. bool contains(const CarlaString& str) const
  139. {
  140. return contains(str.fBuffer);
  141. }
  142. #endif
  143. bool isDigit(const size_t pos) const noexcept
  144. {
  145. CARLA_SAFE_ASSERT_RETURN(pos < fBufferLen, false);
  146. return (fBuffer[pos] >= '0' && fBuffer[pos] <= '9');
  147. }
  148. bool startsWith(const char c) const
  149. {
  150. CARLA_SAFE_ASSERT_RETURN(c != '\0', false);
  151. return (fBufferLen > 0 && fBuffer[0] == c);
  152. }
  153. bool startsWith(const char* const prefix) const
  154. {
  155. CARLA_SAFE_ASSERT_RETURN(prefix != nullptr, false);
  156. const size_t prefixLen(std::strlen(prefix));
  157. if (fBufferLen < prefixLen)
  158. return false;
  159. return (std::strncmp(fBuffer + (fBufferLen-prefixLen), prefix, prefixLen) == 0);
  160. }
  161. bool endsWith(const char c) const
  162. {
  163. CARLA_SAFE_ASSERT_RETURN(c != '\0', false);
  164. return (fBufferLen > 0 && fBuffer[fBufferLen] == c);
  165. }
  166. bool endsWith(const char* const suffix) const
  167. {
  168. CARLA_SAFE_ASSERT_RETURN(suffix != nullptr, false);
  169. const size_t suffixLen(std::strlen(suffix));
  170. if (fBufferLen < suffixLen)
  171. return false;
  172. return (std::strncmp(fBuffer + (fBufferLen-suffixLen), suffix, suffixLen) == 0);
  173. }
  174. void clear() noexcept
  175. {
  176. truncate(0);
  177. }
  178. size_t find(const char c) const noexcept
  179. {
  180. for (size_t i=0; i < fBufferLen; ++i)
  181. {
  182. if (fBuffer[i] == c)
  183. return i;
  184. }
  185. return 0;
  186. }
  187. size_t rfind(const char c) const noexcept
  188. {
  189. for (size_t i=fBufferLen; i > 0; --i)
  190. {
  191. if (fBuffer[i-1] == c)
  192. return i-1;
  193. }
  194. return 0;
  195. }
  196. size_t rfind(const char* const strBuf) const
  197. {
  198. CARLA_SAFE_ASSERT_RETURN(strBuf != nullptr && strBuf[0] != '\0', fBufferLen);
  199. size_t ret = fBufferLen+1;
  200. const char* tmpBuf = fBuffer;
  201. for (size_t i=0; i < fBufferLen; ++i)
  202. {
  203. if (std::strstr(tmpBuf, strBuf) == nullptr)
  204. break;
  205. --ret;
  206. ++tmpBuf;
  207. }
  208. return (ret > fBufferLen) ? fBufferLen : fBufferLen-ret;
  209. }
  210. void replace(const char before, const char after)
  211. {
  212. CARLA_SAFE_ASSERT_RETURN(before != '\0' && after != '\0',);
  213. for (size_t i=0; i < fBufferLen; ++i)
  214. {
  215. if (fBuffer[i] == before)
  216. fBuffer[i] = after;
  217. else if (fBuffer[i] == '\0')
  218. break;
  219. }
  220. }
  221. void truncate(const size_t n) noexcept
  222. {
  223. if (n >= fBufferLen)
  224. return;
  225. for (size_t i=n; i < fBufferLen; ++i)
  226. fBuffer[i] = '\0';
  227. fBufferLen = n;
  228. }
  229. void toBasic() noexcept
  230. {
  231. for (size_t i=0; i < fBufferLen; ++i)
  232. {
  233. if (fBuffer[i] >= '0' && fBuffer[i] <= '9')
  234. continue;
  235. if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z')
  236. continue;
  237. if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z')
  238. continue;
  239. if (fBuffer[i] == '_')
  240. continue;
  241. fBuffer[i] = '_';
  242. }
  243. }
  244. void toLower() noexcept
  245. {
  246. #ifndef BUILD_ANSI_TEST
  247. // Using '+=' temporarily converts char into int
  248. static const char kCharDiff('a' - 'A');
  249. for (size_t i=0; i < fBufferLen; ++i)
  250. {
  251. if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z')
  252. fBuffer[i] += kCharDiff;
  253. }
  254. #endif
  255. }
  256. void toUpper() noexcept
  257. {
  258. #ifndef BUILD_ANSI_TEST
  259. // Using '-=' temporarily converts char into int
  260. static const char kCharDiff('a' - 'A');
  261. for (size_t i=0; i < fBufferLen; ++i)
  262. {
  263. if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z')
  264. fBuffer[i] -= kCharDiff;
  265. }
  266. #endif
  267. }
  268. // -------------------------------------------------------------------
  269. // public operators
  270. operator const char*() const noexcept
  271. {
  272. return fBuffer;
  273. }
  274. char& operator[](const size_t pos) const noexcept
  275. {
  276. return fBuffer[pos];
  277. }
  278. bool operator==(const char* const strBuf) const
  279. {
  280. return (strBuf != nullptr && std::strcmp(fBuffer, strBuf) == 0);
  281. }
  282. bool operator==(const CarlaString& str) const
  283. {
  284. return operator==(str.fBuffer);
  285. }
  286. bool operator!=(const char* const strBuf) const
  287. {
  288. return !operator==(strBuf);
  289. }
  290. bool operator!=(const CarlaString& str) const
  291. {
  292. return !operator==(str.fBuffer);
  293. }
  294. CarlaString& operator=(const char* const strBuf)
  295. {
  296. _dup(strBuf);
  297. return *this;
  298. }
  299. CarlaString& operator=(const CarlaString& str)
  300. {
  301. return operator=(str.fBuffer);
  302. }
  303. CarlaString& operator+=(const char* const strBuf)
  304. {
  305. const size_t newBufSize = fBufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1;
  306. char newBuf[newBufSize];
  307. std::strcpy(newBuf, fBuffer);
  308. std::strcat(newBuf, strBuf);
  309. _dup(newBuf, newBufSize-1);
  310. return *this;
  311. }
  312. CarlaString& operator+=(const CarlaString& str)
  313. {
  314. return operator+=(str.fBuffer);
  315. }
  316. CarlaString operator+(const char* const strBuf)
  317. {
  318. const size_t newBufSize = fBufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1;
  319. char newBuf[newBufSize];
  320. std::strcpy(newBuf, fBuffer);
  321. std::strcat(newBuf, strBuf);
  322. return CarlaString(newBuf);
  323. }
  324. CarlaString operator+(const CarlaString& str)
  325. {
  326. return operator+(str.fBuffer);
  327. }
  328. // -------------------------------------------------------------------
  329. private:
  330. char* fBuffer;
  331. size_t fBufferLen;
  332. bool fFirstInit;
  333. void _init() noexcept
  334. {
  335. fBuffer = nullptr;
  336. fBufferLen = 0;
  337. fFirstInit = true;
  338. }
  339. // allocate string strBuf if not null
  340. // size > 0 only if strBuf is valid
  341. void _dup(const char* const strBuf, const size_t size = 0)
  342. {
  343. if (strBuf != nullptr)
  344. {
  345. // don't recreate string if contents match
  346. if (fFirstInit || std::strcmp(fBuffer, strBuf) != 0)
  347. {
  348. if (! fFirstInit)
  349. {
  350. CARLA_ASSERT(fBuffer != nullptr);
  351. delete[] fBuffer;
  352. }
  353. fBufferLen = (size > 0) ? size : std::strlen(strBuf);
  354. fBuffer = new char[fBufferLen+1];
  355. std::strcpy(fBuffer, strBuf);
  356. fBuffer[fBufferLen] = '\0';
  357. fFirstInit = false;
  358. }
  359. }
  360. else
  361. {
  362. CARLA_ASSERT(size == 0);
  363. // don't recreate null string
  364. if (fFirstInit || fBufferLen != 0)
  365. {
  366. if (! fFirstInit)
  367. {
  368. CARLA_ASSERT(fBuffer != nullptr);
  369. delete[] fBuffer;
  370. }
  371. fBufferLen = 0;
  372. fBuffer = new char[1];
  373. fBuffer[0] = '\0';
  374. fFirstInit = false;
  375. }
  376. }
  377. }
  378. CARLA_PREVENT_HEAP_ALLOCATION
  379. CARLA_LEAK_DETECTOR(CarlaString)
  380. };
  381. // -----------------------------------------------------------------------
  382. static inline
  383. CarlaString operator+(const CarlaString& strBefore, const char* const strBufAfter)
  384. {
  385. const char* const strBufBefore = (const char*)strBefore;
  386. const size_t newBufSize = strBefore.length() + ((strBufAfter != nullptr) ? std::strlen(strBufAfter) : 0) + 1;
  387. char newBuf[newBufSize];
  388. std::strcpy(newBuf, strBufBefore);
  389. std::strcat(newBuf, strBufAfter);
  390. return CarlaString(newBuf);
  391. }
  392. static inline
  393. CarlaString operator+(const char* const strBufBefore, const CarlaString& strAfter)
  394. {
  395. const char* const strBufAfter = (const char*)strAfter;
  396. const size_t newBufSize = ((strBufBefore != nullptr) ? std::strlen(strBufBefore) : 0) + strAfter.length() + 1;
  397. char newBuf[newBufSize];
  398. std::strcpy(newBuf, strBufBefore);
  399. std::strcat(newBuf, strBufAfter);
  400. return CarlaString(newBuf);
  401. }
  402. // -----------------------------------------------------------------------
  403. #endif // CARLA_STRING_HPP_INCLUDED