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.

275 lines
6.7KB

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