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.

685 lines
15KB

  1. /*
  2. * DISTRHO Plugin Toolkit (DPT)
  3. * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any purpose with
  6. * or without fee is hereby granted, provided that the above copyright notice and this
  7. * permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
  10. * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
  11. * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  12. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  13. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #ifndef DISTRHO_UTILS_HPP_INCLUDED
  17. #define DISTRHO_UTILS_HPP_INCLUDED
  18. #include "src/DistrhoDefines.h"
  19. #include <cassert>
  20. #include <cstdarg>
  21. #include <cstdio>
  22. #include <cstdlib>
  23. #include <cstring>
  24. #ifdef PROPER_CPP11_SUPPORT
  25. # include <cstdint>
  26. #else
  27. # include <stdint.h>
  28. #endif
  29. #ifdef DISTRHO_OS_WINDOWS
  30. # include <windows.h>
  31. #else
  32. # include <unistd.h>
  33. #endif
  34. #if defined(DISTRHO_OS_MAC) && ! defined(CARLA_OS_MAC)
  35. namespace std {
  36. inline float
  37. fmin(float __x, float __y)
  38. { return __builtin_fminf(__x, __y); }
  39. inline float
  40. fmax(float __x, float __y)
  41. { return __builtin_fmaxf(__x, __y); }
  42. inline float
  43. rint(float __x)
  44. { return __builtin_rintf(__x); }
  45. }
  46. #endif
  47. // -----------------------------------------------------------------------
  48. // misc functions
  49. static inline
  50. long d_cconst(int a, int b, int c, int d) noexcept
  51. {
  52. return (a << 24) | (b << 16) | (c << 8) | (d << 0);
  53. }
  54. // -----------------------------------------------------------------------
  55. // string print functions
  56. #ifndef DEBUG
  57. # define d_debug(...)
  58. #else
  59. static inline
  60. void d_debug(const char* const fmt, ...)
  61. {
  62. va_list args;
  63. va_start(args, fmt);
  64. std::fprintf(stdout, "\x1b[30;1m");
  65. std::vfprintf(stdout, fmt, args);
  66. std::fprintf(stdout, "\x1b[0m\n");
  67. va_end(args);
  68. }
  69. #endif
  70. static inline
  71. void d_stdout(const char* const fmt, ...)
  72. {
  73. va_list args;
  74. va_start(args, fmt);
  75. std::vfprintf(stdout, fmt, args);
  76. std::fprintf(stdout, "\n");
  77. va_end(args);
  78. }
  79. static inline
  80. void d_stderr(const char* const fmt, ...)
  81. {
  82. va_list args;
  83. va_start(args, fmt);
  84. std::vfprintf(stderr, fmt, args);
  85. std::fprintf(stderr, "\n");
  86. va_end(args);
  87. }
  88. static inline
  89. void d_stderr2(const char* const fmt, ...)
  90. {
  91. va_list args;
  92. va_start(args, fmt);
  93. std::fprintf(stderr, "\x1b[31m");
  94. std::vfprintf(stderr, fmt, args);
  95. std::fprintf(stderr, "\x1b[0m\n");
  96. va_end(args);
  97. }
  98. // -----------------------------------------------------------------------
  99. // d_*sleep
  100. static inline
  101. void d_sleep(unsigned int secs)
  102. {
  103. #ifdef DISTRHO_OS_WINDOWS
  104. Sleep(secs * 1000);
  105. #else
  106. sleep(secs);
  107. #endif
  108. }
  109. static inline
  110. void d_msleep(unsigned int msecs)
  111. {
  112. #ifdef DISTRHO_OS_WINDOWS
  113. Sleep(msecs);
  114. #else
  115. usleep(msecs * 1000);
  116. #endif
  117. }
  118. // -----------------------------------------------------------------------
  119. // d_string class
  120. class d_string
  121. {
  122. public:
  123. // -------------------------------------------------------------------
  124. // constructors (no explicit conversions allowed)
  125. /*
  126. * Empty string.
  127. */
  128. explicit d_string()
  129. {
  130. _init();
  131. _dup(nullptr);
  132. }
  133. /*
  134. * Simple character.
  135. */
  136. explicit d_string(const char c)
  137. {
  138. char ch[2];
  139. ch[0] = c;
  140. ch[1] = '\0';
  141. _init();
  142. _dup(ch);
  143. }
  144. /*
  145. * Simple char string.
  146. */
  147. explicit d_string(char* const strBuf)
  148. {
  149. _init();
  150. _dup(strBuf);
  151. }
  152. /*
  153. * Simple const char string.
  154. */
  155. explicit d_string(const char* const strBuf)
  156. {
  157. _init();
  158. _dup(strBuf);
  159. }
  160. /*
  161. * Integer.
  162. */
  163. explicit d_string(const int value)
  164. {
  165. char strBuf[0xff+1];
  166. std::memset(strBuf, 0, (0xff+1)*sizeof(char));
  167. std::snprintf(strBuf, 0xff, "%d", value);
  168. _init();
  169. _dup(strBuf);
  170. }
  171. /*
  172. * Unsigned integer, possibly in hexadecimal.
  173. */
  174. explicit d_string(const unsigned int value, const bool hexadecimal = false)
  175. {
  176. char strBuf[0xff+1];
  177. std::memset(strBuf, 0, (0xff+1)*sizeof(char));
  178. std::snprintf(strBuf, 0xff, hexadecimal ? "0x%x" : "%u", value);
  179. _init();
  180. _dup(strBuf);
  181. }
  182. /*
  183. * Long integer.
  184. */
  185. explicit d_string(const long int value)
  186. {
  187. char strBuf[0xff+1];
  188. std::memset(strBuf, 0, (0xff+1)*sizeof(char));
  189. std::snprintf(strBuf, 0xff, "%ld", value);
  190. _init();
  191. _dup(strBuf);
  192. }
  193. /*
  194. * Long unsigned integer, possibly hexadecimal.
  195. */
  196. explicit d_string(const unsigned long int value, const bool hexadecimal = false)
  197. {
  198. char strBuf[0xff+1];
  199. std::memset(strBuf, 0, (0xff+1)*sizeof(char));
  200. std::snprintf(strBuf, 0xff, hexadecimal ? "0x%lx" : "%lu", value);
  201. _init();
  202. _dup(strBuf);
  203. }
  204. /*
  205. * Single-precision floating point number.
  206. */
  207. explicit d_string(const float value)
  208. {
  209. char strBuf[0xff+1];
  210. std::memset(strBuf, 0, (0xff+1)*sizeof(char));
  211. std::snprintf(strBuf, 0xff, "%f", value);
  212. _init();
  213. _dup(strBuf);
  214. }
  215. /*
  216. * Double-precision floating point number.
  217. */
  218. explicit d_string(const double value)
  219. {
  220. char strBuf[0xff+1];
  221. std::memset(strBuf, 0, (0xff+1)*sizeof(char));
  222. std::snprintf(strBuf, 0xff, "%g", value);
  223. _init();
  224. _dup(strBuf);
  225. }
  226. // -------------------------------------------------------------------
  227. // non-explicit constructor
  228. /*
  229. * Create string from another string.
  230. */
  231. d_string(const d_string& str)
  232. {
  233. _init();
  234. _dup(str.fBuffer);
  235. }
  236. // -------------------------------------------------------------------
  237. // destructor
  238. /*
  239. * Destructor.
  240. */
  241. ~d_string()
  242. {
  243. assert(fBuffer != nullptr);
  244. delete[] fBuffer;
  245. fBuffer = nullptr;
  246. }
  247. // -------------------------------------------------------------------
  248. // public methods
  249. /*
  250. * Get length of the string.
  251. */
  252. size_t length() const noexcept
  253. {
  254. return fBufferLen;
  255. }
  256. /*
  257. * Check if the string is empty.
  258. */
  259. bool isEmpty() const noexcept
  260. {
  261. return (fBufferLen == 0);
  262. }
  263. /*
  264. * Check if the string is not empty.
  265. */
  266. bool isNotEmpty() const noexcept
  267. {
  268. return (fBufferLen != 0);
  269. }
  270. /*
  271. * Check if the string contains another string, optionally ignoring case.
  272. */
  273. bool contains(const char* const strBuf, const bool ignoreCase = false) const
  274. {
  275. if (strBuf == nullptr)
  276. return false;
  277. if (ignoreCase)
  278. {
  279. #ifdef __USE_GNU
  280. return (strcasestr(fBuffer, strBuf) != nullptr);
  281. #else
  282. d_string tmp1(fBuffer), tmp2(strBuf);
  283. tmp1.toLower();
  284. tmp2.toLower();
  285. return (std::strstr((const char*)tmp1, (const char*)tmp2) != nullptr);
  286. #endif
  287. }
  288. return (std::strstr(fBuffer, strBuf) != nullptr);
  289. }
  290. /*
  291. * Overloaded function.
  292. */
  293. bool contains(const d_string& str, const bool ignoreCase = false) const
  294. {
  295. return contains(str.fBuffer, ignoreCase);
  296. }
  297. /*
  298. * Check if character at 'pos' is a digit.
  299. */
  300. bool isDigit(const size_t pos) const noexcept
  301. {
  302. if (pos >= fBufferLen)
  303. return false;
  304. return (fBuffer[pos] >= '0' && fBuffer[pos] <= '9');
  305. }
  306. /*
  307. * Check if the string starts with the character 'c'.
  308. */
  309. bool startsWith(const char c) const
  310. {
  311. if (c == '\0')
  312. return false;
  313. return (fBufferLen > 0 && fBuffer[0] == c);
  314. }
  315. /*
  316. * Check if the string starts with the string 'prefix'.
  317. */
  318. bool startsWith(const char* const prefix) const
  319. {
  320. if (prefix == nullptr)
  321. return false;
  322. const size_t prefixLen(std::strlen(prefix));
  323. if (fBufferLen < prefixLen)
  324. return false;
  325. return (std::strncmp(fBuffer + (fBufferLen-prefixLen), prefix, prefixLen) == 0);
  326. }
  327. /*
  328. * Check if the string ends with the character 'c'.
  329. */
  330. bool endsWith(const char c) const
  331. {
  332. if (c == '\0')
  333. return false;
  334. return (fBufferLen > 0 && fBuffer[fBufferLen] == c);
  335. }
  336. /*
  337. * Check if the string ends with the string 'suffix'.
  338. */
  339. bool endsWith(const char* const suffix) const
  340. {
  341. if (suffix == nullptr)
  342. return false;
  343. const size_t suffixLen(std::strlen(suffix));
  344. if (fBufferLen < suffixLen)
  345. return false;
  346. return (std::strncmp(fBuffer + (fBufferLen-suffixLen), suffix, suffixLen) == 0);
  347. }
  348. /*
  349. * Clear the string.
  350. */
  351. void clear() noexcept
  352. {
  353. truncate(0);
  354. }
  355. /*
  356. * Replace all occurrences of character 'before' with character 'after'.
  357. */
  358. void replace(const char before, const char after) noexcept
  359. {
  360. if (before == '\0' || after == '\0')
  361. return;
  362. for (size_t i=0; i < fBufferLen; ++i)
  363. {
  364. if (fBuffer[i] == before)
  365. fBuffer[i] = after;
  366. else if (fBuffer[i] == '\0')
  367. break;
  368. }
  369. }
  370. /*
  371. * Truncate the string to size 'n'.
  372. */
  373. void truncate(const size_t n) noexcept
  374. {
  375. if (n >= fBufferLen)
  376. return;
  377. for (size_t i=n; i < fBufferLen; ++i)
  378. fBuffer[i] = '\0';
  379. fBufferLen = n;
  380. }
  381. /*
  382. * Convert all non-basic characters to '_'.
  383. */
  384. void toBasic() noexcept
  385. {
  386. for (size_t i=0; i < fBufferLen; ++i)
  387. {
  388. if (fBuffer[i] >= '0' && fBuffer[i] <= '9')
  389. continue;
  390. if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z')
  391. continue;
  392. if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z')
  393. continue;
  394. if (fBuffer[i] == '_')
  395. continue;
  396. fBuffer[i] = '_';
  397. }
  398. }
  399. /*
  400. * Convert to all ascii characters to lowercase.
  401. */
  402. void toLower() noexcept
  403. {
  404. static const char kCharDiff('a' - 'A');
  405. for (size_t i=0; i < fBufferLen; ++i)
  406. {
  407. if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z')
  408. fBuffer[i] = static_cast<char>(fBuffer[i] + kCharDiff);
  409. }
  410. }
  411. /*
  412. * Convert to all ascii characters to uppercase.
  413. */
  414. void toUpper() noexcept
  415. {
  416. static const char kCharDiff('a' - 'A');
  417. for (size_t i=0; i < fBufferLen; ++i)
  418. {
  419. if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z')
  420. fBuffer[i] = static_cast<char>(fBuffer[i] - kCharDiff);
  421. }
  422. }
  423. // -------------------------------------------------------------------
  424. // public operators
  425. operator const char*() const noexcept
  426. {
  427. return fBuffer;
  428. }
  429. char& operator[](const size_t pos) const noexcept
  430. {
  431. return fBuffer[pos];
  432. }
  433. bool operator==(const char* const strBuf) const
  434. {
  435. return (strBuf != nullptr && std::strcmp(fBuffer, strBuf) == 0);
  436. }
  437. bool operator==(const d_string& str) const
  438. {
  439. return operator==(str.fBuffer);
  440. }
  441. bool operator!=(const char* const strBuf) const
  442. {
  443. return !operator==(strBuf);
  444. }
  445. bool operator!=(const d_string& str) const
  446. {
  447. return !operator==(str.fBuffer);
  448. }
  449. d_string& operator=(const char* const strBuf)
  450. {
  451. _dup(strBuf);
  452. return *this;
  453. }
  454. d_string& operator=(const d_string& str)
  455. {
  456. return operator=(str.fBuffer);
  457. }
  458. d_string& operator+=(const char* const strBuf)
  459. {
  460. if (strBuf == nullptr)
  461. return *this;
  462. const size_t newBufSize = fBufferLen + std::strlen(strBuf) + 1;
  463. char newBuf[newBufSize];
  464. std::strcpy(newBuf, fBuffer);
  465. std::strcat(newBuf, strBuf);
  466. _dup(newBuf, newBufSize-1);
  467. return *this;
  468. }
  469. d_string& operator+=(const d_string& str)
  470. {
  471. return operator+=(str.fBuffer);
  472. }
  473. d_string operator+(const char* const strBuf)
  474. {
  475. const size_t newBufSize = fBufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1;
  476. char newBuf[newBufSize];
  477. std::strcpy(newBuf, fBuffer);
  478. if (strBuf != nullptr)
  479. std::strcat(newBuf, strBuf);
  480. return d_string(newBuf);
  481. }
  482. d_string operator+(const d_string& str)
  483. {
  484. return operator+(str.fBuffer);
  485. }
  486. // -------------------------------------------------------------------
  487. private:
  488. char* fBuffer; // the actual string buffer
  489. size_t fBufferLen; // string length
  490. bool fFirstInit; // true when first initiated
  491. /*
  492. * Shared init function.
  493. * Called on all constructors.
  494. */
  495. void _init() noexcept
  496. {
  497. fBuffer = nullptr;
  498. fBufferLen = 0;
  499. fFirstInit = true;
  500. }
  501. /*
  502. * Helper function.
  503. * Called whenever the string needs to be allocated.
  504. *
  505. * Notes:
  506. * - Allocates string only if first initiated, or if 'strBuf' is not null and new string contents are different
  507. * - If 'strBuf' is null 'size' must be 0
  508. */
  509. void _dup(const char* const strBuf, const size_t size = 0)
  510. {
  511. if (strBuf != nullptr)
  512. {
  513. // don't recreate string if contents match
  514. if (fFirstInit || std::strcmp(fBuffer, strBuf) != 0)
  515. {
  516. if (! fFirstInit)
  517. {
  518. assert(fBuffer != nullptr);
  519. delete[] fBuffer;
  520. }
  521. fBufferLen = (size > 0) ? size : std::strlen(strBuf);
  522. fBuffer = new char[fBufferLen+1];
  523. std::strcpy(fBuffer, strBuf);
  524. fBuffer[fBufferLen] = '\0';
  525. fFirstInit = false;
  526. }
  527. }
  528. else
  529. {
  530. assert(size == 0);
  531. // don't recreate null string
  532. if (fFirstInit || fBufferLen != 0)
  533. {
  534. if (! fFirstInit)
  535. {
  536. assert(fBuffer != nullptr);
  537. delete[] fBuffer;
  538. }
  539. fBufferLen = 0;
  540. fBuffer = new char[1];
  541. fBuffer[0] = '\0';
  542. fFirstInit = false;
  543. }
  544. }
  545. }
  546. };
  547. // -----------------------------------------------------------------------
  548. static inline
  549. d_string operator+(const d_string& strBefore, const char* const strBufAfter)
  550. {
  551. const char* const strBufBefore = (const char*)strBefore;
  552. const size_t newBufSize = strBefore.length() + ((strBufAfter != nullptr) ? std::strlen(strBufAfter) : 0) + 1;
  553. char newBuf[newBufSize];
  554. std::strcpy(newBuf, strBufBefore);
  555. std::strcat(newBuf, strBufAfter);
  556. return d_string(newBuf);
  557. }
  558. static inline
  559. d_string operator+(const char* const strBufBefore, const d_string& strAfter)
  560. {
  561. const char* const strBufAfter = (const char*)strAfter;
  562. const size_t newBufSize = ((strBufBefore != nullptr) ? std::strlen(strBufBefore) : 0) + strAfter.length() + 1;
  563. char newBuf[newBufSize];
  564. std::strcpy(newBuf, strBufBefore);
  565. std::strcat(newBuf, strBufAfter);
  566. return d_string(newBuf);
  567. }
  568. // -----------------------------------------------------------------------
  569. #endif // DISTRHO_UTILS_HPP_INCLUDED