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.

277 lines
6.6KB

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