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.

202 lines
4.4KB

  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. /** Deprecation notice for functions
  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. /** Concatenates two literals or two macros
  26. Example:
  27. #define COUNT 42
  28. CONCAT(myVariable, COUNT)
  29. expands to
  30. myVariable42
  31. */
  32. #define CONCAT_LITERAL(x, y) x ## y
  33. #define CONCAT(x, y) CONCAT_LITERAL(x, y)
  34. /** Surrounds raw text with quotes
  35. Example:
  36. #define NAME "world"
  37. printf("Hello " TOSTRING(NAME))
  38. expands to
  39. printf("Hello " "world")
  40. and of course the C++ lexer/parser then concatenates the string literals.
  41. */
  42. #define TOSTRING_LITERAL(x) #x
  43. #define TOSTRING(x) TOSTRING_LITERAL(x)
  44. /** Produces the length of a static array in number of elements */
  45. #define LENGTHOF(arr) (sizeof(arr) / sizeof((arr)[0]))
  46. /** Reserve space for `count` enums starting with `name`.
  47. Example:
  48. enum Foo {
  49. ENUMS(BAR, 14),
  50. BAZ
  51. };
  52. `BAR + 0` to `BAR + 13` is reserved. `BAZ` has a value of 14.
  53. */
  54. #define ENUMS(name, count) name, name ## _LAST = name + (count) - 1
  55. /** References binary files compiled into the program.
  56. For example, to include a file "Test.dat" directly into your program binary, add
  57. BINARIES += Test.dat
  58. to your Makefile and declare
  59. BINARY(Test_dat);
  60. at the root of a .c or .cpp source file. Note that special characters are replaced with "_". Then use
  61. BINARY_START(Test_dat)
  62. BINARY_END(Test_dat)
  63. to reference the data beginning and end as a void* array, and
  64. BINARY_SIZE(Test_dat)
  65. to get its size in bytes.
  66. */
  67. #if defined ARCH_MAC
  68. // Use output from `xxd -i`
  69. #define BINARY(sym) extern unsigned char sym[]; extern unsigned int sym##_len
  70. #define BINARY_START(sym) ((const void*) sym)
  71. #define BINARY_END(sym) ((const void*) sym + sym##_len)
  72. #define BINARY_SIZE(sym) (sym##_len)
  73. #else
  74. #define BINARY(sym) extern char _binary_##sym##_start, _binary_##sym##_end, _binary_##sym##_size
  75. #define BINARY_START(sym) ((const void*) &_binary_##sym##_start)
  76. #define BINARY_END(sym) ((const void*) &_binary_##sym##_end)
  77. // 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.
  78. #define BINARY_SIZE(sym) ((size_t) (&_binary_##sym##_end - &_binary_##sym##_start))
  79. #endif
  80. /** C#-style property constructor
  81. Example:
  82. Foo *foo = construct<Foo>(&Foo::greeting, "Hello world", &Foo::legs, 2);
  83. */
  84. template <typename T>
  85. T* construct() {
  86. return new T;
  87. }
  88. template <typename T, typename F, typename V, typename... Args>
  89. T* construct(F f, V v, Args... args) {
  90. T* o = construct<T>(args...);
  91. o->*f = v;
  92. return o;
  93. }
  94. /** Defers code until the scope is destructed
  95. From http://www.gingerbill.org/article/defer-in-cpp.html
  96. Example:
  97. file = fopen(...);
  98. DEFER({
  99. fclose(file);
  100. });
  101. */
  102. template <typename F>
  103. struct DeferWrapper {
  104. F f;
  105. DeferWrapper(F f) : f(f) {}
  106. ~DeferWrapper() {
  107. f();
  108. }
  109. };
  110. template <typename F>
  111. DeferWrapper<F> deferWrapper(F f) {
  112. return DeferWrapper<F>(f);
  113. }
  114. #define DEFER(code) auto CONCAT(_defer_, __COUNTER__) = rack::deferWrapper([&]() code)
  115. /** An exception explicitly thrown by Rack. */
  116. struct Exception : std::runtime_error {
  117. Exception(const std::string& msg) : std::runtime_error(msg) {}
  118. };
  119. // config
  120. extern const std::string APP_NAME;
  121. extern const std::string APP_VERSION;
  122. extern const std::string APP_ARCH;
  123. extern const std::string ABI_VERSION;
  124. extern const std::string API_URL;
  125. extern const std::string API_VERSION;
  126. } // namespace rack
  127. #if defined ARCH_WIN
  128. // wchar_t on Windows should be 2 bytes
  129. static_assert(sizeof(char16_t) == sizeof(wchar_t));
  130. // Windows C standard functions are ASCII-8 instead of UTF-8, so redirect these functions to wrappers which convert to UTF-8
  131. #define fopen fopen_utf8
  132. #define remove remove_utf8
  133. #define rename rename_utf8
  134. extern "C" {
  135. FILE* fopen_utf8(const char* filename, const char* mode);
  136. int remove_utf8(const char* path);
  137. int rename_utf8(const char* oldname, const char* newname);
  138. }
  139. namespace std {
  140. using ::fopen_utf8;
  141. using ::remove_utf8;
  142. using ::rename_utf8;
  143. }
  144. #endif