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.

256 lines
6.8KB

  1. #pragma once
  2. // Include most of the C++ standard library for convenience
  3. #include <cstdlib>
  4. #include <cstdio>
  5. #include <cstdint>
  6. #include <cstring>
  7. #include <cassert>
  8. #include <climits>
  9. #include <string>
  10. #include <vector>
  11. #include <condition_variable>
  12. #include <mutex>
  13. ////////////////////
  14. // Handy macros
  15. ////////////////////
  16. /** Concatenates two literals or two macros
  17. Example:
  18. #define COUNT 42
  19. CONCAT(myVariable, COUNT)
  20. expands to
  21. myVariable42
  22. */
  23. #define CONCAT_LITERAL(x, y) x ## y
  24. #define CONCAT(x, y) CONCAT_LITERAL(x, y)
  25. /** Surrounds raw text with quotes
  26. Example:
  27. #define NAME "world"
  28. printf("Hello " TOSTRING(NAME))
  29. expands to
  30. printf("Hello " "world")
  31. and of course the C++ lexer/parser then concatenates the string literals.
  32. */
  33. #define TOSTRING_LITERAL(x) #x
  34. #define TOSTRING(x) TOSTRING_LITERAL(x)
  35. /** Produces the length of a static array in number of elements */
  36. #define LENGTHOF(arr) (sizeof(arr) / sizeof((arr)[0]))
  37. /** Reserve space for `count` enums starting with `name`.
  38. Example:
  39. enum Foo {
  40. ENUMS(BAR, 14),
  41. BAZ
  42. };
  43. BAR + 0 to BAR + 13 is reserved. BAZ has a value of 14.
  44. */
  45. #define ENUMS(name, count) name, name ## _LAST = name + (count) - 1
  46. /** Deprecation notice for GCC */
  47. #define DEPRECATED __attribute__ ((deprecated))
  48. /** References binary files compiled into the program.
  49. For example, to include a file "Test.dat" directly into your program binary, add
  50. BINARIES += Test.dat
  51. to your Makefile and declare
  52. BINARY(Test_dat);
  53. at the root of a .c or .cpp source file. Note that special characters are replaced with "_". Then use
  54. BINARY_START(Test_dat)
  55. BINARY_END(Test_dat)
  56. to reference the data beginning and end as a void* array, and
  57. BINARY_SIZE(Test_dat)
  58. to get its size in bytes.
  59. */
  60. #ifdef ARCH_MAC
  61. // Use output from `xxd -i`
  62. #define BINARY(sym) extern unsigned char sym[]; extern unsigned int sym##_len
  63. #define BINARY_START(sym) ((const void*) sym)
  64. #define BINARY_END(sym) ((const void*) sym + sym##_len)
  65. #define BINARY_SIZE(sym) (sym##_len)
  66. #else
  67. #define BINARY(sym) extern char _binary_##sym##_start, _binary_##sym##_end, _binary_##sym##_size
  68. #define BINARY_START(sym) ((const void*) &_binary_##sym##_start)
  69. #define BINARY_END(sym) ((const void*) &_binary_##sym##_end)
  70. // The symbol "_binary_##sym##_size" doesn't seem to be valid after a plugin is dynamically loaded, so simply take the difference between the two addresses.
  71. #define BINARY_SIZE(sym) ((size_t) (&_binary_##sym##_end - &_binary_##sym##_start))
  72. #endif
  73. #include "math.hpp"
  74. namespace rack {
  75. ////////////////////
  76. // Template hacks
  77. ////////////////////
  78. /** C#-style property constructor
  79. Example:
  80. Foo *foo = construct<Foo>(&Foo::greeting, "Hello world");
  81. */
  82. template<typename T>
  83. T *construct() {
  84. return new T();
  85. }
  86. template<typename T, typename F, typename V, typename... Args>
  87. T *construct(F f, V v, Args... args) {
  88. T *o = construct<T>(args...);
  89. o->*f = v;
  90. return o;
  91. }
  92. /** Defers code until the scope is destructed
  93. From http://www.gingerbill.org/article/defer-in-cpp.html
  94. Example:
  95. file = fopen(...);
  96. defer({
  97. fclose(file);
  98. });
  99. */
  100. template<typename F>
  101. struct DeferWrapper {
  102. F f;
  103. DeferWrapper(F f) : f(f) {}
  104. ~DeferWrapper() { f(); }
  105. };
  106. template<typename F>
  107. DeferWrapper<F> deferWrapper(F f) {
  108. return DeferWrapper<F>(f);
  109. }
  110. #define defer(code) auto CONCAT(_defer_, __COUNTER__) = deferWrapper([&]() code)
  111. ////////////////////
  112. // Random number generator
  113. // random.cpp
  114. ////////////////////
  115. /** Seeds the RNG with the current time */
  116. void randomInit();
  117. /** Returns a uniform random uint32_t from 0 to UINT32_MAX */
  118. uint32_t randomu32();
  119. uint64_t randomu64();
  120. /** Returns a uniform random float in the interval [0.0, 1.0) */
  121. float randomUniform();
  122. /** Returns a normal random number with mean 0 and standard deviation 1 */
  123. float randomNormal();
  124. DEPRECATED inline float randomf() {return randomUniform();}
  125. ////////////////////
  126. // String utilities
  127. // string.cpp
  128. ////////////////////
  129. /** Converts a printf format string and optional arguments into a std::string */
  130. std::string stringf(const char *format, ...);
  131. std::string stringLowercase(std::string s);
  132. std::string stringUppercase(std::string s);
  133. /** Truncates and adds "..." to a string, not exceeding `len` characters */
  134. std::string stringEllipsize(std::string s, size_t len);
  135. bool stringStartsWith(std::string str, std::string prefix);
  136. bool stringEndsWith(std::string str, std::string suffix);
  137. /** Extracts portions of a path */
  138. std::string stringDirectory(std::string path);
  139. std::string stringFilename(std::string path);
  140. std::string stringExtension(std::string path);
  141. struct StringCaseInsensitiveCompare {
  142. bool operator()(const std::string &a, const std::string &b) const {
  143. return stringLowercase(a) < stringLowercase(b);
  144. }
  145. };
  146. ////////////////////
  147. // Operating-system specific utilities
  148. // system.cpp
  149. ////////////////////
  150. std::vector<std::string> systemListEntries(std::string path);
  151. bool systemIsFile(std::string path);
  152. bool systemIsDirectory(std::string path);
  153. void systemCopy(std::string srcPath, std::string destPath);
  154. void systemCreateDirectory(std::string path);
  155. /** Opens a URL, also happens to work with PDFs and folders.
  156. Shell injection is possible, so make sure the URL is trusted or hard coded.
  157. May block, so open in a new thread.
  158. */
  159. void systemOpenBrowser(std::string url);
  160. ////////////////////
  161. // Debug logger
  162. // logger.cpp
  163. ////////////////////
  164. enum LoggerLevel {
  165. DEBUG_LEVEL = 0,
  166. INFO_LEVEL,
  167. WARN_LEVEL,
  168. FATAL_LEVEL
  169. };
  170. void loggerInit(bool devMode);
  171. void loggerDestroy();
  172. /** Do not use this function directly. Use the macros below. */
  173. void loggerLog(LoggerLevel level, const char *file, int line, const char *format, ...);
  174. /** Example usage:
  175. debug("error: %d", errno);
  176. will print something like
  177. [0.123 debug myfile.cpp:45] error: 67
  178. */
  179. #define debug(format, ...) loggerLog(DEBUG_LEVEL, __FILE__, __LINE__, format, ##__VA_ARGS__)
  180. #define info(format, ...) loggerLog(INFO_LEVEL, __FILE__, __LINE__, format, ##__VA_ARGS__)
  181. #define warn(format, ...) loggerLog(WARN_LEVEL, __FILE__, __LINE__, format, ##__VA_ARGS__)
  182. #define fatal(format, ...) loggerLog(FATAL_LEVEL, __FILE__, __LINE__, format, ##__VA_ARGS__)
  183. ////////////////////
  184. // Thread functions
  185. ////////////////////
  186. /** Threads which obtain a VIPLock will cause wait() to block for other less important threads.
  187. This does not provide the VIPs with an exclusive lock. That should be left up to another mutex shared between the less important thread.
  188. */
  189. struct VIPMutex {
  190. int count = 0;
  191. std::condition_variable cv;
  192. std::mutex countMutex;
  193. /** Blocks until there are no remaining VIPLocks */
  194. void wait() {
  195. std::unique_lock<std::mutex> lock(countMutex);
  196. while (count > 0)
  197. cv.wait(lock);
  198. }
  199. };
  200. struct VIPLock {
  201. VIPMutex &m;
  202. VIPLock(VIPMutex &m) : m(m) {
  203. std::unique_lock<std::mutex> lock(m.countMutex);
  204. m.count++;
  205. }
  206. ~VIPLock() {
  207. std::unique_lock<std::mutex> lock(m.countMutex);
  208. m.count--;
  209. lock.unlock();
  210. m.cv.notify_all();
  211. }
  212. };
  213. } // namespace rack