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.

125 lines
3.1KB

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