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.

608 lines
14KB

  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. explicit d_string()
  126. {
  127. _init();
  128. _dup(nullptr);
  129. }
  130. explicit d_string(char* const strBuf)
  131. {
  132. _init();
  133. _dup(strBuf);
  134. }
  135. explicit d_string(const char* const strBuf)
  136. {
  137. _init();
  138. _dup(strBuf);
  139. }
  140. explicit d_string(const int value)
  141. {
  142. char strBuf[0xff+1];
  143. std::memset(strBuf, 0, (0xff+1)*sizeof(char));
  144. std::snprintf(strBuf, 0xff, "%d", value);
  145. _init();
  146. _dup(strBuf);
  147. }
  148. explicit d_string(const unsigned int value, const bool hexadecimal = false)
  149. {
  150. char strBuf[0xff+1];
  151. std::memset(strBuf, 0, (0xff+1)*sizeof(char));
  152. std::snprintf(strBuf, 0xff, hexadecimal ? "0x%x" : "%u", value);
  153. _init();
  154. _dup(strBuf);
  155. }
  156. explicit d_string(const long int value)
  157. {
  158. char strBuf[0xff+1];
  159. std::memset(strBuf, 0, (0xff+1)*sizeof(char));
  160. std::snprintf(strBuf, 0xff, "%ld", value);
  161. _init();
  162. _dup(strBuf);
  163. }
  164. explicit d_string(const unsigned long int value, const bool hexadecimal = false)
  165. {
  166. char strBuf[0xff+1];
  167. std::memset(strBuf, 0, (0xff+1)*sizeof(char));
  168. std::snprintf(strBuf, 0xff, hexadecimal ? "0x%lx" : "%lu", value);
  169. _init();
  170. _dup(strBuf);
  171. }
  172. explicit d_string(const float value)
  173. {
  174. char strBuf[0xff+1];
  175. std::memset(strBuf, 0, (0xff+1)*sizeof(char));
  176. std::snprintf(strBuf, 0xff, "%f", value);
  177. _init();
  178. _dup(strBuf);
  179. }
  180. explicit d_string(const double value)
  181. {
  182. char strBuf[0xff+1];
  183. std::memset(strBuf, 0, (0xff+1)*sizeof(char));
  184. std::snprintf(strBuf, 0xff, "%g", value);
  185. _init();
  186. _dup(strBuf);
  187. }
  188. // -------------------------------------------------------------------
  189. // non-explicit constructor
  190. d_string(const d_string& str)
  191. {
  192. _init();
  193. _dup(str.fBuffer);
  194. }
  195. // -------------------------------------------------------------------
  196. // destructor
  197. ~d_string()
  198. {
  199. assert(fBuffer != nullptr);
  200. delete[] fBuffer;
  201. fBuffer = nullptr;
  202. }
  203. // -------------------------------------------------------------------
  204. // public methods
  205. size_t length() const noexcept
  206. {
  207. return fBufferLen;
  208. }
  209. bool isEmpty() const noexcept
  210. {
  211. return (fBufferLen == 0);
  212. }
  213. bool isNotEmpty() const noexcept
  214. {
  215. return (fBufferLen != 0);
  216. }
  217. #ifdef __USE_GNU
  218. bool contains(const char* const strBuf, const bool ignoreCase = false) const
  219. {
  220. if (strBuf == nullptr)
  221. return false;
  222. if (ignoreCase)
  223. return (strcasestr(fBuffer, strBuf) != nullptr);
  224. else
  225. return (std::strstr(fBuffer, strBuf) != nullptr);
  226. }
  227. bool contains(const d_string& str, const bool ignoreCase = false) const
  228. {
  229. return contains(str.fBuffer, ignoreCase);
  230. }
  231. #else
  232. bool contains(const char* const strBuf) const
  233. {
  234. if (strBuf == nullptr)
  235. return false;
  236. return (std::strstr(fBuffer, strBuf) != nullptr);
  237. }
  238. bool contains(const d_string& str) const
  239. {
  240. return contains(str.fBuffer);
  241. }
  242. #endif
  243. bool isDigit(const size_t pos) const noexcept
  244. {
  245. if (pos >= fBufferLen)
  246. return false;
  247. return (fBuffer[pos] >= '0' && fBuffer[pos] <= '9');
  248. }
  249. bool startsWith(const char* const prefix) const
  250. {
  251. if (prefix == nullptr)
  252. return false;
  253. const size_t prefixLen(std::strlen(prefix));
  254. if (fBufferLen < prefixLen)
  255. return false;
  256. return (std::strncmp(fBuffer + (fBufferLen-prefixLen), prefix, prefixLen) == 0);
  257. }
  258. bool endsWith(const char* const suffix) const
  259. {
  260. if (suffix == nullptr)
  261. return false;
  262. const size_t suffixLen(std::strlen(suffix));
  263. if (fBufferLen < suffixLen)
  264. return false;
  265. return (std::strncmp(fBuffer + (fBufferLen-suffixLen), suffix, suffixLen) == 0);
  266. }
  267. void clear() noexcept
  268. {
  269. truncate(0);
  270. }
  271. size_t find(const char c) const noexcept
  272. {
  273. for (size_t i=0; i < fBufferLen; ++i)
  274. {
  275. if (fBuffer[i] == c)
  276. return i;
  277. }
  278. return 0;
  279. }
  280. size_t rfind(const char c) const noexcept
  281. {
  282. for (size_t i=fBufferLen; i > 0; --i)
  283. {
  284. if (fBuffer[i-1] == c)
  285. return i-1;
  286. }
  287. return 0;
  288. }
  289. size_t rfind(const char* const strBuf) const
  290. {
  291. if (strBuf == nullptr || strBuf[0] == '\0')
  292. return fBufferLen;
  293. size_t ret = fBufferLen+1;
  294. const char* tmpBuf = fBuffer;
  295. for (size_t i=0; i < fBufferLen; ++i)
  296. {
  297. if (std::strstr(tmpBuf, strBuf) == nullptr)
  298. break;
  299. --ret;
  300. ++tmpBuf;
  301. }
  302. return (ret > fBufferLen) ? fBufferLen : fBufferLen-ret;
  303. }
  304. void replace(const char before, const char after) noexcept
  305. {
  306. if (after == '\0')
  307. return;
  308. for (size_t i=0; i < fBufferLen; ++i)
  309. {
  310. if (fBuffer[i] == before)
  311. fBuffer[i] = after;
  312. else if (fBuffer[i] == '\0')
  313. break;
  314. }
  315. }
  316. void truncate(const size_t n) noexcept
  317. {
  318. if (n >= fBufferLen)
  319. return;
  320. for (size_t i=n; i < fBufferLen; ++i)
  321. fBuffer[i] = '\0';
  322. fBufferLen = n;
  323. }
  324. void toBasic() noexcept
  325. {
  326. for (size_t i=0; i < fBufferLen; ++i)
  327. {
  328. if (fBuffer[i] >= '0' && fBuffer[i] <= '9')
  329. continue;
  330. if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z')
  331. continue;
  332. if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z')
  333. continue;
  334. if (fBuffer[i] == '_')
  335. continue;
  336. fBuffer[i] = '_';
  337. }
  338. }
  339. void toLower() noexcept
  340. {
  341. static const char kCharDiff('a' - 'A');
  342. for (size_t i=0; i < fBufferLen; ++i)
  343. {
  344. if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z')
  345. fBuffer[i] += kCharDiff;
  346. }
  347. }
  348. void toUpper() noexcept
  349. {
  350. static const char kCharDiff('a' - 'A');
  351. for (size_t i=0; i < fBufferLen; ++i)
  352. {
  353. if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z')
  354. fBuffer[i] -= kCharDiff;
  355. }
  356. }
  357. // -------------------------------------------------------------------
  358. // public operators
  359. operator const char*() const noexcept
  360. {
  361. return fBuffer;
  362. }
  363. char& operator[](const size_t pos) const noexcept
  364. {
  365. return fBuffer[pos];
  366. }
  367. bool operator==(const char* const strBuf) const
  368. {
  369. return (strBuf != nullptr && std::strcmp(fBuffer, strBuf) == 0);
  370. }
  371. bool operator==(const d_string& str) const
  372. {
  373. return operator==(str.fBuffer);
  374. }
  375. bool operator!=(const char* const strBuf) const
  376. {
  377. return !operator==(strBuf);
  378. }
  379. bool operator!=(const d_string& str) const
  380. {
  381. return !operator==(str.fBuffer);
  382. }
  383. d_string& operator=(const char* const strBuf)
  384. {
  385. _dup(strBuf);
  386. return *this;
  387. }
  388. d_string& operator=(const d_string& str)
  389. {
  390. return operator=(str.fBuffer);
  391. }
  392. d_string& operator+=(const char* const strBuf)
  393. {
  394. const size_t newBufSize = fBufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1;
  395. char newBuf[newBufSize];
  396. std::strcpy(newBuf, fBuffer);
  397. std::strcat(newBuf, strBuf);
  398. _dup(newBuf, newBufSize-1);
  399. return *this;
  400. }
  401. d_string& operator+=(const d_string& str)
  402. {
  403. return operator+=(str.fBuffer);
  404. }
  405. d_string operator+(const char* const strBuf)
  406. {
  407. const size_t newBufSize = fBufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1;
  408. char newBuf[newBufSize];
  409. std::strcpy(newBuf, fBuffer);
  410. std::strcat(newBuf, strBuf);
  411. return d_string(newBuf);
  412. }
  413. d_string operator+(const d_string& str)
  414. {
  415. return operator+(str.fBuffer);
  416. }
  417. // -------------------------------------------------------------------
  418. private:
  419. char* fBuffer;
  420. size_t fBufferLen;
  421. bool fFirstInit;
  422. void _init() noexcept
  423. {
  424. fBuffer = nullptr;
  425. fBufferLen = 0;
  426. fFirstInit = true;
  427. }
  428. // allocate string strBuf if not null
  429. // size > 0 only if strBuf is valid
  430. void _dup(const char* const strBuf, const size_t size = 0)
  431. {
  432. if (strBuf != nullptr)
  433. {
  434. // don't recreate string if contents match
  435. if (fFirstInit || std::strcmp(fBuffer, strBuf) != 0)
  436. {
  437. if (! fFirstInit)
  438. {
  439. assert(fBuffer != nullptr);
  440. delete[] fBuffer;
  441. }
  442. fBufferLen = (size > 0) ? size : std::strlen(strBuf);
  443. fBuffer = new char[fBufferLen+1];
  444. std::strcpy(fBuffer, strBuf);
  445. fBuffer[fBufferLen] = '\0';
  446. fFirstInit = false;
  447. }
  448. }
  449. else
  450. {
  451. assert(size == 0);
  452. // don't recreate null string
  453. if (fFirstInit || fBufferLen != 0)
  454. {
  455. if (! fFirstInit)
  456. {
  457. assert(fBuffer != nullptr);
  458. delete[] fBuffer;
  459. }
  460. fBufferLen = 0;
  461. fBuffer = new char[1];
  462. fBuffer[0] = '\0';
  463. fFirstInit = false;
  464. }
  465. }
  466. }
  467. };
  468. // -----------------------------------------------------------------------
  469. static inline
  470. d_string operator+(const d_string& strBefore, const char* const strBufAfter)
  471. {
  472. const char* const strBufBefore = (const char*)strBefore;
  473. const size_t newBufSize = strBefore.length() + ((strBufAfter != nullptr) ? std::strlen(strBufAfter) : 0) + 1;
  474. char newBuf[newBufSize];
  475. std::strcpy(newBuf, strBufBefore);
  476. std::strcat(newBuf, strBufAfter);
  477. return d_string(newBuf);
  478. }
  479. static inline
  480. d_string operator+(const char* const strBufBefore, const d_string& strAfter)
  481. {
  482. const char* const strBufAfter = (const char*)strAfter;
  483. const size_t newBufSize = ((strBufBefore != nullptr) ? std::strlen(strBufBefore) : 0) + strAfter.length() + 1;
  484. char newBuf[newBufSize];
  485. std::strcpy(newBuf, strBufBefore);
  486. std::strcat(newBuf, strBufAfter);
  487. return d_string(newBuf);
  488. }
  489. // -----------------------------------------------------------------------
  490. #endif // DISTRHO_UTILS_HPP_INCLUDED