diff options
Diffstat (limited to '')
-rw-r--r-- | src/macros_and_utils.h | 220 |
1 files changed, 153 insertions, 67 deletions
diff --git a/src/macros_and_utils.h b/src/macros_and_utils.h index e184476..e8d5ab5 100644 --- a/src/macros_and_utils.h +++ b/src/macros_and_utils.h | |||
@@ -1,107 +1,193 @@ | |||
1 | /* | 1 | #pragma once |
2 | * MACROS_AND_UTILS.H | ||
3 | */ | ||
4 | #ifndef MACROS_AND_UTILS_H | ||
5 | #define MACROS_AND_UTILS_H | ||
6 | 2 | ||
3 | #ifdef __cplusplus | ||
4 | extern "C" { | ||
5 | #endif // __cplusplus | ||
7 | #include "lua.h" | 6 | #include "lua.h" |
8 | #include "lualib.h" | 7 | #include "lualib.h" |
9 | #include "lauxlib.h" | 8 | #include "lauxlib.h" |
9 | #ifdef __cplusplus | ||
10 | } | ||
11 | #endif // __cplusplus | ||
12 | |||
13 | #include <cassert> | ||
14 | #include <chrono> | ||
15 | #include <tuple> | ||
16 | #include <type_traits> | ||
10 | 17 | ||
11 | // M$ compiler doesn't support 'inline' keyword in C files... | 18 | using namespace std::chrono_literals; |
12 | #if defined( _MSC_VER) | ||
13 | #define inline __inline | ||
14 | #endif | ||
15 | 19 | ||
16 | #define USE_DEBUG_SPEW() 0 | 20 | #define USE_DEBUG_SPEW() 0 |
17 | #if USE_DEBUG_SPEW() | 21 | #if USE_DEBUG_SPEW() |
18 | extern char const* debugspew_indent; | 22 | extern char const* debugspew_indent; |
19 | #define INDENT_BEGIN "%.*s " | 23 | #define INDENT_BEGIN "%.*s " |
20 | #define INDENT_END , (U ? U->debugspew_indent_depth : 0), debugspew_indent | 24 | #define INDENT_END , (U ? U->debugspew_indent_depth.load(std::memory_order_relaxed) : 0), debugspew_indent |
21 | #define DEBUGSPEW_CODE(_code) _code | 25 | #define DEBUGSPEW_CODE(_code) _code |
22 | #define DEBUGSPEW_PARAM_COMMA( param_) param_, | 26 | #define DEBUGSPEW_OR_NOT(a_, b_) a_ |
27 | #define DEBUGSPEW_PARAM_COMMA(param_) param_, | ||
23 | #define DEBUGSPEW_COMMA_PARAM( param_) , param_ | 28 | #define DEBUGSPEW_COMMA_PARAM( param_) , param_ |
24 | #else // USE_DEBUG_SPEW() | 29 | #else // USE_DEBUG_SPEW() |
25 | #define DEBUGSPEW_CODE(_code) | 30 | #define DEBUGSPEW_CODE(_code) |
26 | #define DEBUGSPEW_PARAM_COMMA( param_) | 31 | #define DEBUGSPEW_OR_NOT(a_, b_) b_ |
32 | #define DEBUGSPEW_PARAM_COMMA(param_) | ||
27 | #define DEBUGSPEW_COMMA_PARAM( param_) | 33 | #define DEBUGSPEW_COMMA_PARAM( param_) |
28 | #endif // USE_DEBUG_SPEW() | 34 | #endif // USE_DEBUG_SPEW() |
29 | 35 | ||
30 | #ifdef NDEBUG | 36 | #ifdef NDEBUG |
31 | 37 | ||
32 | #define _ASSERT_L(lua,c) //nothing | 38 | #define _ASSERT_L(lua,c) //nothing |
33 | #define STACK_CHECK(L,o) //nothing | ||
34 | #define STACK_CHECK_ABS(L,o) //nothing | ||
35 | #define STACK_MID(L,c) //nothing | ||
36 | #define STACK_END(L,c) //nothing | ||
37 | #define STACK_DUMP(L) //nothing | 39 | #define STACK_DUMP(L) //nothing |
38 | 40 | ||
41 | #define STACK_CHECK_START_REL(L, offset_) | ||
42 | #define STACK_CHECK_START_ABS(L, offset_) | ||
43 | #define STACK_CHECK_RESET_REL(L, offset_) | ||
44 | #define STACK_CHECK_RESET_ABS(L, offset_) | ||
45 | #define STACK_CHECK(L, offset_) | ||
46 | |||
39 | #else // NDEBUG | 47 | #else // NDEBUG |
40 | 48 | ||
41 | #define _ASSERT_L( L, cond_) if( (cond_) == 0) { (void) luaL_error( L, "ASSERT failed: %s:%d '%s'", __FILE__, __LINE__, #cond_);} | 49 | #define _ASSERT_L(L, cond_) if( (cond_) == 0) { (void) luaL_error(L, "ASSERT failed: %s:%d '%s'", __FILE__, __LINE__, #cond_);} |
42 | 50 | #define STACK_DUMP(L) luaG_dump(L) | |
43 | #define STACK_CHECK( L, offset_) \ | 51 | |
44 | { \ | 52 | class StackChecker |
45 | int const L##_delta = offset_; \ | 53 | { |
46 | if( (L##_delta < 0) || (lua_gettop( L) < L##_delta)) \ | 54 | private: |
47 | { \ | 55 | lua_State* const m_L; |
48 | assert( FALSE); \ | 56 | int m_oldtop; |
49 | (void) luaL_error( L, "STACK INIT ASSERT failed (%d not %d): %s:%d", lua_gettop( L), L##_delta, __FILE__, __LINE__); \ | 57 | |
50 | } \ | 58 | public: |
51 | int const L##_oldtop = lua_gettop( L) - L##_delta | 59 | struct Relative |
52 | 60 | { | |
53 | #define STACK_CHECK_ABS( L, offset_) \ | 61 | int const m_offset; |
54 | { \ | 62 | |
55 | int const L##_pos = offset_; \ | 63 | operator int() const { return m_offset; } |
56 | if( lua_gettop( L) < L##_pos) \ | 64 | }; |
57 | { \ | 65 | |
58 | assert( FALSE); \ | 66 | struct Absolute |
59 | (void) luaL_error( L, "STACK INIT ASSERT failed (%d not %d): %s:%d", lua_gettop( L), L##_pos, __FILE__, __LINE__); \ | 67 | { |
60 | } \ | 68 | int const m_offset; |
61 | int const L##_oldtop = 0 | 69 | |
62 | 70 | operator int() const { return m_offset; } | |
63 | #define STACK_MID( L, change) \ | 71 | }; |
64 | do if( change != LUA_MULTRET) \ | 72 | |
65 | { \ | 73 | StackChecker(lua_State* const L_, Relative offset_, char const* file_, size_t const line_) |
66 | int stack_check_a = lua_gettop( L) - L##_oldtop; \ | 74 | : m_L{ L_ } |
67 | int stack_check_b = (change); \ | 75 | , m_oldtop{ lua_gettop(L_) - offset_ } |
68 | if( stack_check_a != stack_check_b) \ | 76 | { |
69 | { \ | 77 | if ((offset_ < 0) || (m_oldtop < 0)) |
70 | assert( FALSE); \ | 78 | { |
71 | luaL_error( L, "STACK ASSERT failed (%d not %d): %s:%d", stack_check_a, stack_check_b, __FILE__, __LINE__); \ | 79 | assert(false); |
72 | } \ | 80 | luaL_error(m_L, "STACK INIT ASSERT failed (%d not %d): %s:%d", lua_gettop(m_L), offset_, file_, line_); // doesn't return |
73 | } while( 0) | 81 | } |
74 | 82 | } | |
75 | #define STACK_END( L, change) \ | 83 | |
76 | STACK_MID( L, change); \ | 84 | StackChecker(lua_State* const L_, Absolute pos_, char const* file_, size_t const line_) |
85 | : m_L{ L_ } | ||
86 | , m_oldtop{ 0 } | ||
87 | { | ||
88 | if (lua_gettop(m_L) != pos_) | ||
89 | { | ||
90 | assert(false); | ||
91 | luaL_error(m_L, "STACK INIT ASSERT failed (%d not %d): %s:%d", lua_gettop(m_L), pos_, file_, line_); // doesn't return | ||
92 | } | ||
77 | } | 93 | } |
78 | 94 | ||
79 | #define STACK_DUMP( L) luaG_dump( L) | 95 | StackChecker& operator=(StackChecker const& rhs_) |
96 | { | ||
97 | assert(m_L == rhs_.m_L); | ||
98 | m_oldtop = rhs_.m_oldtop; | ||
99 | return *this; | ||
100 | } | ||
101 | |||
102 | // verify if the distance between the current top and the initial one is what we expect | ||
103 | void check(int expected_, char const* file_, size_t const line_) | ||
104 | { | ||
105 | if (expected_ != LUA_MULTRET) | ||
106 | { | ||
107 | int const actual{ lua_gettop(m_L) - m_oldtop }; | ||
108 | if (actual != expected_) | ||
109 | { | ||
110 | assert(false); | ||
111 | luaL_error(m_L, "STACK ASSERT failed (%d not %d): %s:%d", actual, expected_, file_, line_); // doesn't return | ||
112 | } | ||
113 | } | ||
114 | } | ||
115 | }; | ||
116 | |||
117 | #define STACK_CHECK_START_REL(L, offset_) StackChecker stackChecker_##L(L, StackChecker::Relative{ offset_ }, __FILE__, __LINE__) | ||
118 | #define STACK_CHECK_START_ABS(L, offset_) StackChecker stackChecker_##L(L, StackChecker::Absolute{ offset_ }, __FILE__, __LINE__) | ||
119 | #define STACK_CHECK_RESET_REL(L, offset_) stackChecker_##L = StackChecker{L, StackChecker::Relative{ offset_ }, __FILE__, __LINE__} | ||
120 | #define STACK_CHECK_RESET_ABS(L, offset_) stackChecker_##L = StackChecker{L, StackChecker::Absolute{ offset_ }, __FILE__, __LINE__} | ||
121 | #define STACK_CHECK(L, offset_) stackChecker_##L.check(offset_, __FILE__, __LINE__) | ||
80 | 122 | ||
81 | #endif // NDEBUG | 123 | #endif // NDEBUG |
82 | 124 | ||
83 | #define ASSERT_L(c) _ASSERT_L(L,c) | 125 | #define ASSERT_L(c) _ASSERT_L(L,c) |
84 | 126 | ||
85 | inline void STACK_GROW(lua_State * L, int n_) | 127 | inline void STACK_GROW(lua_State* L, int n_) |
86 | { | 128 | { |
87 | if (!lua_checkstack(L, n_)) | 129 | if (!lua_checkstack(L, n_)) |
88 | luaL_error(L, "Cannot grow stack!"); | 130 | { |
131 | luaL_error(L, "Cannot grow stack!"); // doesn't return | ||
132 | } | ||
89 | } | 133 | } |
90 | 134 | ||
91 | // non-string keyed registry access | 135 | #define LUAG_FUNC(func_name) [[nodiscard]] int LG_##func_name(lua_State* L) |
92 | #define REGISTRY_SET( L, key_, value_) \ | 136 | |
93 | { \ | 137 | // ################################################################################################# |
94 | push_unique_key( L, key_); \ | 138 | |
95 | value_; \ | 139 | // a small helper to extract a full userdata pointer from the stack in a safe way |
96 | lua_rawset( L, LUA_REGISTRYINDEX); \ | 140 | template<typename T> |
141 | [[nodiscard]] T* lua_tofulluserdata(lua_State* L, int index_) | ||
142 | { | ||
143 | ASSERT_L(lua_isnil(L, index_) || lua_type(L, index_) == LUA_TUSERDATA); | ||
144 | return static_cast<T*>(lua_touserdata(L, index_)); | ||
97 | } | 145 | } |
98 | 146 | ||
99 | #define REGISTRY_GET( L, key_) \ | 147 | template<typename T> |
100 | { \ | 148 | [[nodiscard]] auto lua_tolightuserdata(lua_State* L, int index_) |
101 | push_unique_key( L, key_); \ | 149 | { |
102 | lua_rawget( L, LUA_REGISTRYINDEX); \ | 150 | ASSERT_L(lua_isnil(L, index_) || lua_islightuserdata(L, index_)); |
151 | if constexpr (std::is_pointer_v<T>) | ||
152 | { | ||
153 | return static_cast<T>(lua_touserdata(L, index_)); | ||
154 | } | ||
155 | else | ||
156 | { | ||
157 | return static_cast<T*>(lua_touserdata(L, index_)); | ||
158 | } | ||
159 | } | ||
160 | |||
161 | template <typename T> | ||
162 | [[nodiscard]] T* lua_newuserdatauv(lua_State* L, int nuvalue_) | ||
163 | { | ||
164 | return static_cast<T*>(lua_newuserdatauv(L, sizeof(T), nuvalue_)); | ||
165 | } | ||
166 | |||
167 | // ################################################################################################# | ||
168 | |||
169 | // use this instead of Lua's lua_error if possible | ||
170 | [[noreturn]] static inline void raise_lua_error(lua_State* L) | ||
171 | { | ||
172 | std::ignore = lua_error(L); // doesn't return | ||
173 | assert(false); // we should never get here, but i'm paranoid | ||
103 | } | 174 | } |
104 | 175 | ||
105 | #define LUAG_FUNC( func_name) int LG_##func_name( lua_State* L) | 176 | using lua_Duration = std::chrono::template duration<lua_Number>; |
177 | |||
178 | // ################################################################################################# | ||
179 | |||
180 | // A unique type generator | ||
181 | template <typename T, auto = []{}> | ||
182 | struct Unique | ||
183 | { | ||
184 | T m_val; | ||
185 | constexpr Unique() = default; | ||
186 | constexpr operator T() const { return m_val; } | ||
187 | constexpr explicit Unique(T b_) : m_val{ b_ } {} | ||
188 | }; | ||
189 | |||
190 | // ################################################################################################# | ||
106 | 191 | ||
107 | #endif // MACROS_AND_UTILS_H | 192 | using Source = Unique<lua_State*>; |
193 | using Dest = Unique<lua_State*>; \ No newline at end of file | ||