|
- #pragma once
- // Include most of the C stdlib for convenience
- #include <cstddef>
- #include <cstdlib>
- #include <cstdio>
- #include <cstdint>
- #include <cinttypes>
- #include <cstdarg>
- #include <climits>
- #include <cmath>
- #include <cstring>
- #include <cassert>
-
- // Include some of the C++ stdlib for convenience
- #include <string>
- #include <stdexcept>
-
-
- /** Attribute for deprecated functions and symbols.
- E.g.
-
- DEPRECATED void foo();
- */
- #define DEPRECATED __attribute__((deprecated))
-
- /** Attribute for private functions not intended to be called by plugins.
- When #including rack.hpp, attempting to call PRIVATE functions will result in a compile-time error.
- */
- #ifndef PRIVATE
- #define PRIVATE
- #endif
-
-
- /** Concatenates two literals or two macros
- Example:
-
- #define COUNT 42
- CONCAT(myVariable, COUNT)
-
- expands to
-
- myVariable42
- */
- #define CONCAT_LITERAL(x, y) x ## y
- #define CONCAT(x, y) CONCAT_LITERAL(x, y)
-
-
- /** Surrounds raw text with quotes
- Example:
-
- #define NAME "world"
- printf("Hello " TOSTRING(NAME))
-
- expands to
-
- printf("Hello " "world")
-
- and of course the C++ lexer/parser then concatenates the string literals.
- */
- #define TOSTRING_LITERAL(x) #x
- #define TOSTRING(x) TOSTRING_LITERAL(x)
-
-
- /** Produces the length of a static array in number of elements */
- #define LENGTHOF(arr) (sizeof(arr) / sizeof((arr)[0]))
-
-
- /** Reserve space for `count` enums starting with `name`.
- Example:
-
- enum Foo {
- ENUMS(BAR, 14),
- BAZ
- };
-
- `BAR + 0` to `BAR + 13` is reserved. `BAZ` has a value of 14.
- */
- #define ENUMS(name, count) name, name ## _LAST = name + (count) - 1
-
-
- /** References binary files compiled into the program.
- For example, to include a file "Test.dat" directly into your program binary, add
-
- BINARIES += Test.dat
-
- to your Makefile and declare
-
- BINARY(Test_dat);
-
- at the root of a .c or .cpp source file. Note that special characters are replaced with "_". Then use
-
- BINARY_START(Test_dat)
- BINARY_END(Test_dat)
-
- to reference the data beginning and end as a void* array, and
-
- BINARY_SIZE(Test_dat)
-
- to get its size in bytes.
- */
- #if defined ARCH_MAC
- // Use output from `xxd -i`
- #define BINARY(sym) extern unsigned char sym[]; extern unsigned int sym##_len
- #define BINARY_START(sym) ((const void*) sym)
- #define BINARY_END(sym) ((const void*) sym + sym##_len)
- #define BINARY_SIZE(sym) (sym##_len)
- #else
- #define BINARY(sym) extern char _binary_##sym##_start, _binary_##sym##_end, _binary_##sym##_size
- #define BINARY_START(sym) ((const void*) &_binary_##sym##_start)
- #define BINARY_END(sym) ((const void*) &_binary_##sym##_end)
- // 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.
- #define BINARY_SIZE(sym) ((size_t) (&_binary_##sym##_end - &_binary_##sym##_start))
- #endif
-
-
- /** Helpful user-defined literals for specifying exact integer and float types.
- Usage examples:
- 42_i8
- -4242_u16
- 0x4a2b_i32
- 0b11010111000000_u64
- 42_f32
- 4.2e-4_f64
- */
- inline int8_t operator"" _i8(unsigned long long x) {return x;}
- inline int16_t operator"" _i16(unsigned long long x) {return x;}
- inline int32_t operator"" _i32(unsigned long long x) {return x;}
- inline int64_t operator"" _i64(unsigned long long x) {return x;}
- inline uint8_t operator"" _u8(unsigned long long x) {return x;}
- inline uint16_t operator"" _u16(unsigned long long x) {return x;}
- inline uint32_t operator"" _u32(unsigned long long x) {return x;}
- inline uint64_t operator"" _u64(unsigned long long x) {return x;}
- inline float operator"" _f32(long double x) {return x;}
- inline float operator"" _f32(unsigned long long x) {return x;}
- inline double operator"" _f64(long double x) {return x;}
- inline double operator"" _f64(unsigned long long x) {return x;}
-
-
- #if defined ARCH_WIN
- // wchar_t on Windows should be 2 bytes
- static_assert(sizeof(wchar_t) == 2);
-
- // Windows C standard functions are ASCII-8 instead of UTF-8, so redirect these functions to wrappers which convert to UTF-8
- #define fopen fopen_u8
-
- extern "C" {
- FILE* fopen_u8(const char* filename, const char* mode);
- }
-
- namespace std {
- using ::fopen_u8;
- }
- #endif
-
-
- /** Root namespace for the Rack API */
- namespace rack {
-
-
- /** Casts a primitive, preserving its bits instead of converting. */
- template <typename To, typename From>
- To bitCast(From from) {
- static_assert(sizeof(From) == sizeof(To), "Types must be the same size");
- To to;
- // This is optimized out
- std::memcpy(&to, &from, sizeof(From));
- return to;
- }
-
-
- /** C#-style property constructor
- Example:
-
- Foo *foo = construct<Foo>(&Foo::greeting, "Hello world", &Foo::legs, 2);
- */
- template <typename T>
- T* construct() {
- return new T;
- }
-
- template <typename T, typename F, typename V, typename... Args>
- T* construct(F f, V v, Args... args) {
- T* o = construct<T>(args...);
- o->*f = v;
- return o;
- }
-
-
- /** Defers running code until the scope is destructed
-
- From http://www.gingerbill.org/article/defer-in-cpp.html.
- Example:
-
- file = fopen(...);
- DEFER({
- fclose(file);
- });
- */
- template <typename F>
- struct DeferWrapper {
- F f;
- DeferWrapper(F f) : f(f) {}
- ~DeferWrapper() {
- f();
- }
- };
-
- template <typename F>
- DeferWrapper<F> deferWrapper(F f) {
- return DeferWrapper<F>(f);
- }
-
- #define DEFER(code) auto CONCAT(_defer_, __COUNTER__) = rack::deferWrapper([&]() code)
-
-
- /** An exception explicitly thrown by Rack or a Rack plugin.
- Can be subclassed to throw/catch specific custom exceptions.
- */
- struct Exception : std::exception {
- std::string msg;
-
- // Attribute index 1 refers to `Exception*` argument so use 2.
- __attribute__((format(printf, 2, 3)))
- Exception(const char* format, ...);
- Exception(const std::string& msg) : msg(msg) {}
- const char* what() const noexcept override {
- return msg.c_str();
- }
- };
-
-
- /** Given a std::map, returns the value of the given key, or returns `def` if the key doesn't exist.
- Does *not* add the default value to the map.
-
- Posted to https://stackoverflow.com/a/63683271/272642.
- Example:
-
- std::map<std::string, int> m;
- int v = get(m, "a", 3);
- // v is 3 because the key "a" does not exist
-
- int w = get(m, "a");
- // w is 0 because no default value is given, so it assumes the default int.
- */
- template <typename C>
- typename C::mapped_type get(const C& m, const typename C::key_type& key, const typename C::mapped_type& def = typename C::mapped_type()) {
- typename C::const_iterator it = m.find(key);
- if (it == m.end())
- return def;
- return it->second;
- }
-
-
- // config
-
- extern const std::string APP_NAME;
- extern const std::string APP_EDITION;
- extern const std::string APP_EDITION_NAME;
- extern const std::string APP_VERSION_MAJOR;
- extern const std::string APP_VERSION;
- extern const std::string APP_OS;
- extern const std::string APP_ARCH;
- extern const std::string API_URL;
-
-
- } // namespace rack
-
-
- // Logger depends on common.hpp, but it is handy to include it along with common.hpp.
- #include <logger.hpp>
|