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.

505 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_ASSERT(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. if (strBuf == nullptr)
  123. return false;
  124. if (ignoreCase)
  125. return (strcasestr(fBuffer, strBuf) != nullptr);
  126. else
  127. return (std::strstr(fBuffer, strBuf) != nullptr);
  128. }
  129. bool contains(const CarlaString& str, const bool ignoreCase = false) const
  130. {
  131. return contains(str.fBuffer, ignoreCase);
  132. }
  133. #else
  134. bool contains(const char* const strBuf) const
  135. {
  136. if (strBuf == nullptr)
  137. return false;
  138. return (std::strstr(fBuffer, strBuf) != nullptr);
  139. }
  140. bool contains(const CarlaString& str) const
  141. {
  142. return contains(str.fBuffer);
  143. }
  144. #endif
  145. bool isDigit(const size_t pos) const noexcept
  146. {
  147. if (pos >= fBufferLen)
  148. return false;
  149. return (fBuffer[pos] >= '0' && fBuffer[pos] <= '9');
  150. }
  151. bool startsWith(const char* const prefix) const
  152. {
  153. if (prefix == nullptr)
  154. return false;
  155. const size_t prefixLen(std::strlen(prefix));
  156. if (fBufferLen < prefixLen)
  157. return false;
  158. return (std::strncmp(fBuffer + (fBufferLen-prefixLen), prefix, prefixLen) == 0);
  159. }
  160. bool endsWith(const char* const suffix) const
  161. {
  162. if (suffix == nullptr)
  163. return false;
  164. const size_t suffixLen(std::strlen(suffix));
  165. if (fBufferLen < suffixLen)
  166. return false;
  167. return (std::strncmp(fBuffer + (fBufferLen-suffixLen), suffix, suffixLen) == 0);
  168. }
  169. void clear() noexcept
  170. {
  171. truncate(0);
  172. }
  173. size_t find(const char c) const noexcept
  174. {
  175. for (size_t i=0; i < fBufferLen; ++i)
  176. {
  177. if (fBuffer[i] == c)
  178. return i;
  179. }
  180. return 0;
  181. }
  182. size_t rfind(const char c) const noexcept
  183. {
  184. for (size_t i=fBufferLen; i > 0; --i)
  185. {
  186. if (fBuffer[i-1] == c)
  187. return i-1;
  188. }
  189. return 0;
  190. }
  191. size_t rfind(const char* const strBuf) const
  192. {
  193. if (strBuf == nullptr || strBuf[0] == '\0')
  194. return fBufferLen;
  195. size_t ret = fBufferLen+1;
  196. const char* tmpBuf = fBuffer;
  197. for (size_t i=0; i < fBufferLen; ++i)
  198. {
  199. if (std::strstr(tmpBuf, strBuf) == nullptr)
  200. break;
  201. --ret;
  202. ++tmpBuf;
  203. }
  204. return (ret > fBufferLen) ? fBufferLen : fBufferLen-ret;
  205. }
  206. void replace(const char before, const char after) noexcept
  207. {
  208. if (after == '\0')
  209. return;
  210. for (size_t i=0; i < fBufferLen; ++i)
  211. {
  212. if (fBuffer[i] == before)
  213. fBuffer[i] = after;
  214. else if (fBuffer[i] == '\0')
  215. break;
  216. }
  217. }
  218. void truncate(const size_t n) noexcept
  219. {
  220. if (n >= fBufferLen)
  221. return;
  222. for (size_t i=n; i < fBufferLen; ++i)
  223. fBuffer[i] = '\0';
  224. fBufferLen = n;
  225. }
  226. void toBasic() noexcept
  227. {
  228. for (size_t i=0; i < fBufferLen; ++i)
  229. {
  230. if (fBuffer[i] >= '0' && fBuffer[i] <= '9')
  231. continue;
  232. if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z')
  233. continue;
  234. if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z')
  235. continue;
  236. if (fBuffer[i] == '_')
  237. continue;
  238. fBuffer[i] = '_';
  239. }
  240. }
  241. void toLower() noexcept
  242. {
  243. #ifndef BUILD_ANSI_TEST
  244. // Using '+=' temporarily converts char into int
  245. static const char kCharDiff('a' - 'A');
  246. for (size_t i=0; i < fBufferLen; ++i)
  247. {
  248. if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z')
  249. fBuffer[i] += kCharDiff;
  250. }
  251. #endif
  252. }
  253. void toUpper() noexcept
  254. {
  255. #ifndef BUILD_ANSI_TEST
  256. // Using '-=' temporarily converts char into int
  257. static const char kCharDiff('a' - 'A');
  258. for (size_t i=0; i < fBufferLen; ++i)
  259. {
  260. if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z')
  261. fBuffer[i] -= kCharDiff;
  262. }
  263. #endif
  264. }
  265. // -------------------------------------------------------------------
  266. // public operators
  267. operator const char*() const noexcept
  268. {
  269. return fBuffer;
  270. }
  271. char& operator[](const size_t pos) const noexcept
  272. {
  273. return fBuffer[pos];
  274. }
  275. bool operator==(const char* const strBuf) const
  276. {
  277. return (strBuf != nullptr && std::strcmp(fBuffer, strBuf) == 0);
  278. }
  279. bool operator==(const CarlaString& str) const
  280. {
  281. return operator==(str.fBuffer);
  282. }
  283. bool operator!=(const char* const strBuf) const
  284. {
  285. return !operator==(strBuf);
  286. }
  287. bool operator!=(const CarlaString& str) const
  288. {
  289. return !operator==(str.fBuffer);
  290. }
  291. CarlaString& operator=(const char* const strBuf)
  292. {
  293. _dup(strBuf);
  294. return *this;
  295. }
  296. CarlaString& operator=(const CarlaString& str)
  297. {
  298. return operator=(str.fBuffer);
  299. }
  300. CarlaString& operator+=(const char* const strBuf)
  301. {
  302. const size_t newBufSize = fBufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1;
  303. char newBuf[newBufSize];
  304. std::strcpy(newBuf, fBuffer);
  305. std::strcat(newBuf, strBuf);
  306. _dup(newBuf, newBufSize-1);
  307. return *this;
  308. }
  309. CarlaString& operator+=(const CarlaString& str)
  310. {
  311. return operator+=(str.fBuffer);
  312. }
  313. CarlaString operator+(const char* const strBuf)
  314. {
  315. const size_t newBufSize = fBufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1;
  316. char newBuf[newBufSize];
  317. std::strcpy(newBuf, fBuffer);
  318. std::strcat(newBuf, strBuf);
  319. return CarlaString(newBuf);
  320. }
  321. CarlaString operator+(const CarlaString& str)
  322. {
  323. return operator+(str.fBuffer);
  324. }
  325. // -------------------------------------------------------------------
  326. private:
  327. char* fBuffer;
  328. size_t fBufferLen;
  329. bool fFirstInit;
  330. void _init() noexcept
  331. {
  332. fBuffer = nullptr;
  333. fBufferLen = 0;
  334. fFirstInit = true;
  335. }
  336. // allocate string strBuf if not null
  337. // size > 0 only if strBuf is valid
  338. void _dup(const char* const strBuf, const size_t size = 0)
  339. {
  340. if (strBuf != nullptr)
  341. {
  342. // don't recreate string if contents match
  343. if (fFirstInit || std::strcmp(fBuffer, strBuf) != 0)
  344. {
  345. if (! fFirstInit)
  346. {
  347. CARLA_ASSERT(fBuffer != nullptr);
  348. delete[] fBuffer;
  349. }
  350. fBufferLen = (size > 0) ? size : std::strlen(strBuf);
  351. fBuffer = new char[fBufferLen+1];
  352. std::strcpy(fBuffer, strBuf);
  353. fBuffer[fBufferLen] = '\0';
  354. fFirstInit = false;
  355. }
  356. }
  357. else
  358. {
  359. CARLA_ASSERT(size == 0);
  360. // don't recreate null string
  361. if (fFirstInit || fBufferLen != 0)
  362. {
  363. if (! fFirstInit)
  364. {
  365. CARLA_ASSERT(fBuffer != nullptr);
  366. delete[] fBuffer;
  367. }
  368. fBufferLen = 0;
  369. fBuffer = new char[1];
  370. fBuffer[0] = '\0';
  371. fFirstInit = false;
  372. }
  373. }
  374. }
  375. CARLA_PREVENT_HEAP_ALLOCATION
  376. CARLA_LEAK_DETECTOR(CarlaString)
  377. };
  378. // -----------------------------------------------------------------------
  379. static inline
  380. CarlaString operator+(const CarlaString& strBefore, const char* const strBufAfter)
  381. {
  382. const char* const strBufBefore = (const char*)strBefore;
  383. const size_t newBufSize = strBefore.length() + ((strBufAfter != nullptr) ? std::strlen(strBufAfter) : 0) + 1;
  384. char newBuf[newBufSize];
  385. std::strcpy(newBuf, strBufBefore);
  386. std::strcat(newBuf, strBufAfter);
  387. return CarlaString(newBuf);
  388. }
  389. static inline
  390. CarlaString operator+(const char* const strBufBefore, const CarlaString& strAfter)
  391. {
  392. const char* const strBufAfter = (const char*)strAfter;
  393. const size_t newBufSize = ((strBufBefore != nullptr) ? std::strlen(strBufBefore) : 0) + strAfter.length() + 1;
  394. char newBuf[newBufSize];
  395. std::strcpy(newBuf, strBufBefore);
  396. std::strcat(newBuf, strBufAfter);
  397. return CarlaString(newBuf);
  398. }
  399. // -----------------------------------------------------------------------
  400. #endif // CARLA_STRING_HPP_INCLUDED