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.

140 lines
3.4KB

  1. #pragma once
  2. #include "logger.hpp"
  3. // Include most of the C stdlib for convenience
  4. #include <cstdlib>
  5. #include <cstdio>
  6. #include <cstdint>
  7. #include <cstdarg>
  8. #include <climits>
  9. #include <cmath>
  10. #include <cstring>
  11. #include <cassert>
  12. // Include some of the C++ stdlib for convenience
  13. #include <string>
  14. namespace rack {
  15. /** Deprecation notice for functions
  16. E.g.
  17. DEPRECATED void foo();
  18. */
  19. #if defined(__GNUC__) || defined(__clang__)
  20. #define DEPRECATED __attribute__ ((deprecated))
  21. #elif defined(_MSC_VER)
  22. #define DEPRECATED __declspec(deprecated)
  23. #endif
  24. /** Concatenates two literals or two macros
  25. Example:
  26. #define COUNT 42
  27. CONCAT(myVariable, COUNT)
  28. expands to
  29. myVariable42
  30. */
  31. #define CONCAT_LITERAL(x, y) x ## y
  32. #define CONCAT(x, y) CONCAT_LITERAL(x, y)
  33. /** Surrounds raw text with quotes
  34. Example:
  35. #define NAME "world"
  36. printf("Hello " TOSTRING(NAME))
  37. expands to
  38. printf("Hello " "world")
  39. and of course the C++ lexer/parser then concatenates the string literals.
  40. */
  41. #define TOSTRING_LITERAL(x) #x
  42. #define TOSTRING(x) TOSTRING_LITERAL(x)
  43. /** Produces the length of a static array in number of elements */
  44. #define LENGTHOF(arr) (sizeof(arr) / sizeof((arr)[0]))
  45. /** Reserve space for `count` enums starting with `name`.
  46. Example:
  47. enum Foo {
  48. ENUMS(BAR, 14),
  49. BAZ
  50. };
  51. BAR + 0 to BAR + 13 is reserved. BAZ has a value of 14.
  52. */
  53. #define ENUMS(name, count) name, name ## _LAST = name + (count) - 1
  54. /** References binary files compiled into the program.
  55. For example, to include a file "Test.dat" directly into your program binary, add
  56. BINARIES += Test.dat
  57. to your Makefile and declare
  58. BINARY(Test_dat);
  59. at the root of a .c or .cpp source file. Note that special characters are replaced with "_". Then use
  60. BINARY_START(Test_dat)
  61. BINARY_END(Test_dat)
  62. to reference the data beginning and end as a void* array, and
  63. BINARY_SIZE(Test_dat)
  64. to get its size in bytes.
  65. */
  66. #if defined ARCH_MAC
  67. // Use output from `xxd -i`
  68. #define BINARY(sym) extern unsigned char sym[]; extern unsigned int sym##_len
  69. #define BINARY_START(sym) ((const void*) sym)
  70. #define BINARY_END(sym) ((const void*) sym + sym##_len)
  71. #define BINARY_SIZE(sym) (sym##_len)
  72. #else
  73. #define BINARY(sym) extern char _binary_##sym##_start, _binary_##sym##_end, _binary_##sym##_size
  74. #define BINARY_START(sym) ((const void*) &_binary_##sym##_start)
  75. #define BINARY_END(sym) ((const void*) &_binary_##sym##_end)
  76. // 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.
  77. #define BINARY_SIZE(sym) ((size_t) (&_binary_##sym##_end - &_binary_##sym##_start))
  78. #endif
  79. /** C#-style property constructor
  80. Example:
  81. Foo *foo = construct<Foo>(&Foo::greeting, "Hello world", &Foo::legs, 2);
  82. */
  83. template<typename T>
  84. T *construct() {
  85. return new T;
  86. }
  87. template<typename T, typename F, typename V, typename... Args>
  88. T *construct(F f, V v, Args... args) {
  89. T *o = construct<T>(args...);
  90. o->*f = v;
  91. return o;
  92. }
  93. /** Defers code until the scope is destructed
  94. From http://www.gingerbill.org/article/defer-in-cpp.html
  95. Example:
  96. file = fopen(...);
  97. DEFER({
  98. fclose(file);
  99. });
  100. */
  101. template<typename F>
  102. struct DeferWrapper {
  103. F f;
  104. DeferWrapper(F f) : f(f) {}
  105. ~DeferWrapper() { f(); }
  106. };
  107. template<typename F>
  108. DeferWrapper<F> deferWrapper(F f) {
  109. return DeferWrapper<F>(f);
  110. }
  111. #define DEFER(code) auto CONCAT(_defer_, __COUNTER__) = rack::deferWrapper([&]() code)
  112. } // namespace rack