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.

227 lines
5.2KB

  1. #pragma once
  2. // Include most of the C stdlib for convenience
  3. #include <cstdlib>
  4. #include <cstdio>
  5. #include <cstdint>
  6. #include <cstdarg>
  7. #include <climits>
  8. #include <cmath>
  9. #include <cstring>
  10. #include <cassert>
  11. // Include some of the C++ stdlib for convenience
  12. #include <string>
  13. #include <stdexcept>
  14. #include <logger.hpp>
  15. namespace rack {
  16. /** Attribute for deprecated functions and symbols.
  17. E.g.
  18. DEPRECATED void foo();
  19. */
  20. #if defined(__GNUC__) || defined(__clang__)
  21. #define DEPRECATED __attribute__ ((deprecated))
  22. #elif defined(_MSC_VER)
  23. #define DEPRECATED __declspec(deprecated)
  24. #endif
  25. /** Attribute for private functions and symbols not intended to be used by plugins.
  26. By default this does nothing, but when #including rack.hpp, it prints a compile-time warning.
  27. */
  28. #define PRIVATE
  29. /** Concatenates two literals or two macros
  30. Example:
  31. #define COUNT 42
  32. CONCAT(myVariable, COUNT)
  33. expands to
  34. myVariable42
  35. */
  36. #define CONCAT_LITERAL(x, y) x ## y
  37. #define CONCAT(x, y) CONCAT_LITERAL(x, y)
  38. /** Surrounds raw text with quotes
  39. Example:
  40. #define NAME "world"
  41. printf("Hello " TOSTRING(NAME))
  42. expands to
  43. printf("Hello " "world")
  44. and of course the C++ lexer/parser then concatenates the string literals.
  45. */
  46. #define TOSTRING_LITERAL(x) #x
  47. #define TOSTRING(x) TOSTRING_LITERAL(x)
  48. /** Produces the length of a static array in number of elements */
  49. #define LENGTHOF(arr) (sizeof(arr) / sizeof((arr)[0]))
  50. /** Reserve space for `count` enums starting with `name`.
  51. Example:
  52. enum Foo {
  53. ENUMS(BAR, 14),
  54. BAZ
  55. };
  56. `BAR + 0` to `BAR + 13` is reserved. `BAZ` has a value of 14.
  57. */
  58. #define ENUMS(name, count) name, name ## _LAST = name + (count) - 1
  59. /** References binary files compiled into the program.
  60. For example, to include a file "Test.dat" directly into your program binary, add
  61. BINARIES += Test.dat
  62. to your Makefile and declare
  63. BINARY(Test_dat);
  64. at the root of a .c or .cpp source file. Note that special characters are replaced with "_". Then use
  65. BINARY_START(Test_dat)
  66. BINARY_END(Test_dat)
  67. to reference the data beginning and end as a void* array, and
  68. BINARY_SIZE(Test_dat)
  69. to get its size in bytes.
  70. */
  71. #if defined ARCH_MAC
  72. // Use output from `xxd -i`
  73. #define BINARY(sym) extern unsigned char sym[]; extern unsigned int sym##_len
  74. #define BINARY_START(sym) ((const void*) sym)
  75. #define BINARY_END(sym) ((const void*) sym + sym##_len)
  76. #define BINARY_SIZE(sym) (sym##_len)
  77. #else
  78. #define BINARY(sym) extern char _binary_##sym##_start, _binary_##sym##_end, _binary_##sym##_size
  79. #define BINARY_START(sym) ((const void*) &_binary_##sym##_start)
  80. #define BINARY_END(sym) ((const void*) &_binary_##sym##_end)
  81. // 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.
  82. #define BINARY_SIZE(sym) ((size_t) (&_binary_##sym##_end - &_binary_##sym##_start))
  83. #endif
  84. /** C#-style property constructor
  85. Example:
  86. Foo *foo = construct<Foo>(&Foo::greeting, "Hello world", &Foo::legs, 2);
  87. */
  88. template <typename T>
  89. T* construct() {
  90. return new T;
  91. }
  92. template <typename T, typename F, typename V, typename... Args>
  93. T* construct(F f, V v, Args... args) {
  94. T* o = construct<T>(args...);
  95. o->*f = v;
  96. return o;
  97. }
  98. /** Defers code until the scope is destructed
  99. From http://www.gingerbill.org/article/defer-in-cpp.html
  100. Example:
  101. file = fopen(...);
  102. DEFER({
  103. fclose(file);
  104. });
  105. */
  106. template <typename F>
  107. struct DeferWrapper {
  108. F f;
  109. DeferWrapper(F f) : f(f) {}
  110. ~DeferWrapper() {
  111. f();
  112. }
  113. };
  114. template <typename F>
  115. DeferWrapper<F> deferWrapper(F f) {
  116. return DeferWrapper<F>(f);
  117. }
  118. #define DEFER(code) auto CONCAT(_defer_, __COUNTER__) = rack::deferWrapper([&]() code)
  119. /** An exception explicitly thrown by Rack or a Rack plugin.
  120. Can be subclassed to throw/catch specific custom exceptions.
  121. */
  122. struct Exception : std::exception {
  123. std::string msg;
  124. Exception(const std::string& msg) : msg(msg) {}
  125. const char* what() const noexcept override {
  126. return msg.c_str();
  127. }
  128. };
  129. /** Given a std::map, returns the value of the given key, or returns `def` if the key doesn't exist.
  130. Does *not* add the default value to the map.
  131. Posted to https://stackoverflow.com/a/63683271/272642.
  132. Example:
  133. std::map<std::string, int> m;
  134. int v = get(m, "a", 3);
  135. // v is 3 because the key "a" does not exist
  136. int w = get(m, "a");
  137. // w is 0 because no default value is given, so it assumes the default int.
  138. */
  139. template <typename C>
  140. typename C::mapped_type get(const C& m, const typename C::key_type& key, const typename C::mapped_type& def = typename C::mapped_type()) {
  141. typename C::const_iterator it = m.find(key);
  142. if (it == m.end())
  143. return def;
  144. return it->second;
  145. }
  146. // config
  147. extern const std::string APP_NAME;
  148. extern const std::string APP_VERSION;
  149. extern const std::string APP_ARCH;
  150. extern const std::string ABI_VERSION;
  151. extern const std::string API_URL;
  152. extern const std::string API_VERSION;
  153. } // namespace rack
  154. #if defined ARCH_WIN
  155. // wchar_t on Windows should be 2 bytes
  156. static_assert(sizeof(wchar_t) == 2);
  157. // Windows C standard functions are ASCII-8 instead of UTF-8, so redirect these functions to wrappers which convert to UTF-8
  158. #define fopen fopen_u8
  159. extern "C" {
  160. FILE* fopen_u8(const char* filename, const char* mode);
  161. }
  162. namespace std {
  163. using ::fopen_u8;
  164. }
  165. #endif