diff options
| author | Benoit Germain <benoit.germain@ubisoft.com> | 2024-05-20 15:57:03 +0200 |
|---|---|---|
| committer | Benoit Germain <benoit.germain@ubisoft.com> | 2024-05-20 15:57:03 +0200 |
| commit | ac8caa415b36c875578c2ad0490965b80be2f37e (patch) | |
| tree | 96bf4411f57452a74f0e566994a2ca103aef797a | |
| parent | 9a0781e52fd0f9eac8ac75c18d7f58936fb6c981 (diff) | |
| download | lanes-ac8caa415b36c875578c2ad0490965b80be2f37e.tar.gz lanes-ac8caa415b36c875578c2ad0490965b80be2f37e.tar.bz2 lanes-ac8caa415b36c875578c2ad0490965b80be2f37e.zip | |
More string_view
| -rw-r--r-- | src/cancel.cpp | 16 | ||||
| -rw-r--r-- | src/cancel.h | 4 | ||||
| -rw-r--r-- | src/compat.h | 11 | ||||
| -rw-r--r-- | src/intercopycontext.cpp | 87 | ||||
| -rw-r--r-- | src/lanes.cpp | 9 | ||||
| -rw-r--r-- | src/lindafactory.cpp | 9 | ||||
| -rw-r--r-- | src/tools.cpp | 31 | ||||
| -rw-r--r-- | src/universe.cpp | 6 |
8 files changed, 88 insertions, 85 deletions
diff --git a/src/cancel.cpp b/src/cancel.cpp index ff7af1e..f093905 100644 --- a/src/cancel.cpp +++ b/src/cancel.cpp | |||
| @@ -162,20 +162,20 @@ CancelResult thread_cancel(Lane* lane_, CancelOp op_, int hookCount_, std::chron | |||
| 162 | // ################################################################################################# | 162 | // ################################################################################################# |
| 163 | // ################################################################################################# | 163 | // ################################################################################################# |
| 164 | 164 | ||
| 165 | CancelOp which_cancel_op(char const* opString_) | 165 | CancelOp which_cancel_op(std::string_view const& opString_) |
| 166 | { | 166 | { |
| 167 | CancelOp _op{ CancelOp::Invalid }; | 167 | CancelOp _op{ CancelOp::Invalid }; |
| 168 | if (strcmp(opString_, "hard") == 0) { | 168 | if (opString_ == "hard") { |
| 169 | _op = CancelOp::Hard; | 169 | _op = CancelOp::Hard; |
| 170 | } else if (strcmp(opString_, "soft") == 0) { | 170 | } else if (opString_ == "soft") { |
| 171 | _op = CancelOp::Soft; | 171 | _op = CancelOp::Soft; |
| 172 | } else if (strcmp(opString_, "call") == 0) { | 172 | } else if (opString_== "call") { |
| 173 | _op = CancelOp::MaskCall; | 173 | _op = CancelOp::MaskCall; |
| 174 | } else if (strcmp(opString_, "ret") == 0) { | 174 | } else if (opString_ == "ret") { |
| 175 | _op = CancelOp::MaskRet; | 175 | _op = CancelOp::MaskRet; |
| 176 | } else if (strcmp(opString_, "line") == 0) { | 176 | } else if (opString_ == "line") { |
| 177 | _op = CancelOp::MaskLine; | 177 | _op = CancelOp::MaskLine; |
| 178 | } else if (strcmp(opString_, "count") == 0) { | 178 | } else if (opString_ == "count") { |
| 179 | _op = CancelOp::MaskCount; | 179 | _op = CancelOp::MaskCount; |
| 180 | } | 180 | } |
| 181 | return _op; | 181 | return _op; |
| @@ -186,7 +186,7 @@ CancelOp which_cancel_op(char const* opString_) | |||
| 186 | [[nodiscard]] static CancelOp which_cancel_op(lua_State* L_, int idx_) | 186 | [[nodiscard]] static CancelOp which_cancel_op(lua_State* L_, int idx_) |
| 187 | { | 187 | { |
| 188 | if (lua_type(L_, idx_) == LUA_TSTRING) { | 188 | if (lua_type(L_, idx_) == LUA_TSTRING) { |
| 189 | char const* const _str{ lua_tostring(L_, idx_) }; | 189 | std::string_view const _str{ lua_tostringview(L_, idx_) }; |
| 190 | CancelOp _op{ which_cancel_op(_str) }; | 190 | CancelOp _op{ which_cancel_op(_str) }; |
| 191 | lua_remove(L_, idx_); // argument is processed, remove it | 191 | lua_remove(L_, idx_); // argument is processed, remove it |
| 192 | if (_op == CancelOp::Invalid) { | 192 | if (_op == CancelOp::Invalid) { |
diff --git a/src/cancel.h b/src/cancel.h index 1918df3..bac8b05 100644 --- a/src/cancel.h +++ b/src/cancel.h | |||
| @@ -14,6 +14,8 @@ extern "C" | |||
| 14 | #include "macros_and_utils.h" | 14 | #include "macros_and_utils.h" |
| 15 | #include "uniquekey.h" | 15 | #include "uniquekey.h" |
| 16 | 16 | ||
| 17 | #include <string_view> | ||
| 18 | |||
| 17 | // ################################################################################################# | 19 | // ################################################################################################# |
| 18 | 20 | ||
| 19 | class Lane; // forward | 21 | class Lane; // forward |
| @@ -48,7 +50,7 @@ enum class CancelOp | |||
| 48 | // xxh64 of string "kCancelError" generated at https://www.pelock.com/products/hash-calculator | 50 | // xxh64 of string "kCancelError" generated at https://www.pelock.com/products/hash-calculator |
| 49 | static constexpr UniqueKey kCancelError{ 0x0630345FEF912746ull, "lanes.cancel_error" }; // 'raise_cancel_error' sentinel | 51 | static constexpr UniqueKey kCancelError{ 0x0630345FEF912746ull, "lanes.cancel_error" }; // 'raise_cancel_error' sentinel |
| 50 | 52 | ||
| 51 | [[nodiscard]] CancelOp which_cancel_op(char const* opString_); | 53 | [[nodiscard]] CancelOp which_cancel_op(std::string_view const& opString_); |
| 52 | [[nodiscard]] CancelResult thread_cancel(Lane* lane_, CancelOp op_, int hookCount_, std::chrono::time_point<std::chrono::steady_clock> until_, bool wakeLane_); | 54 | [[nodiscard]] CancelResult thread_cancel(Lane* lane_, CancelOp op_, int hookCount_, std::chrono::time_point<std::chrono::steady_clock> until_, bool wakeLane_); |
| 53 | 55 | ||
| 54 | [[noreturn]] static inline void raise_cancel_error(lua_State* L_) | 56 | [[noreturn]] static inline void raise_cancel_error(lua_State* L_) |
diff --git a/src/compat.h b/src/compat.h index 0e95cde..3fb4e2d 100644 --- a/src/compat.h +++ b/src/compat.h | |||
| @@ -25,6 +25,7 @@ extern "C" | |||
| 25 | #endif // LUA_JITLIBNAME | 25 | #endif // LUA_JITLIBNAME |
| 26 | 26 | ||
| 27 | #include <cassert> | 27 | #include <cassert> |
| 28 | #include <string_view> | ||
| 28 | 29 | ||
| 29 | // code is now preferring Lua 5.4 API | 30 | // code is now preferring Lua 5.4 API |
| 30 | 31 | ||
| @@ -249,3 +250,13 @@ inline constexpr LuaError ToLuaError(int rc_) | |||
| 249 | // ################################################################################################# | 250 | // ################################################################################################# |
| 250 | 251 | ||
| 251 | LuaType luaG_getmodule(lua_State* L_, char const* name_); | 252 | LuaType luaG_getmodule(lua_State* L_, char const* name_); |
| 253 | |||
| 254 | // ################################################################################################# | ||
| 255 | |||
| 256 | // a replacement of lua_tolstring | ||
| 257 | inline std::string_view lua_tostringview(lua_State* L_, int idx_) | ||
| 258 | { | ||
| 259 | size_t _len{ 0 }; | ||
| 260 | char const* _str{ lua_tolstring(L_, idx_, &_len) }; | ||
| 261 | return std::string_view{ _str, _len }; | ||
| 262 | } | ||
diff --git a/src/intercopycontext.cpp b/src/intercopycontext.cpp index 2f83400..1487afd 100644 --- a/src/intercopycontext.cpp +++ b/src/intercopycontext.cpp | |||
| @@ -96,38 +96,37 @@ THE SOFTWARE. | |||
| 96 | lua_pushvalue(L1, L1_i); // L1: ... v ... {} v | 96 | lua_pushvalue(L1, L1_i); // L1: ... v ... {} v |
| 97 | lua_rawget(L1, -2); // L1: ... v ... {} "f.q.n" | 97 | lua_rawget(L1, -2); // L1: ... v ... {} "f.q.n" |
| 98 | } | 98 | } |
| 99 | size_t _len{ 0 }; | 99 | std::string_view _fqn{ lua_tostringview(L1, -1) }; |
| 100 | char const* _fqn{ lua_tolstring(L1, -1, &_len) }; | ||
| 101 | DEBUGSPEW_CODE(Universe* const _U = universe_get(L1)); | 100 | DEBUGSPEW_CODE(Universe* const _U = universe_get(L1)); |
| 102 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "function [C] %s \n" INDENT_END(_U), _fqn)); | 101 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "function [C] %s \n" INDENT_END(_U), _fqn.data())); |
| 103 | // popping doesn't invalidate the pointer since this is an interned string gotten from the lookup database | 102 | // popping doesn't invalidate the pointer since this is an interned string gotten from the lookup database |
| 104 | lua_pop(L1, (mode == LookupMode::FromKeeper) ? 1 : 2); // L1: ... v ... | 103 | lua_pop(L1, (mode == LookupMode::FromKeeper) ? 1 : 2); // L1: ... v ... |
| 105 | STACK_CHECK(L1, 0); | 104 | STACK_CHECK(L1, 0); |
| 106 | if (nullptr == _fqn && !lua_istable(L1, L1_i)) { // raise an error if we try to send an unknown function (but not for tables) | 105 | if (_fqn.empty() && !lua_istable(L1, L1_i)) { // raise an error if we try to send an unknown function (but not for tables) |
| 107 | _len = 0; // just in case | 106 | _fqn = std::string_view{}; // just in case |
| 108 | // try to discover the name of the function we want to send | 107 | // try to discover the name of the function we want to send |
| 109 | lua_getglobal(L1, "decoda_name"); // L1: ... v ... decoda_name | 108 | lua_getglobal(L1, "decoda_name"); // L1: ... v ... decoda_name |
| 110 | char const* from{ lua_tostring(L1, -1) }; | 109 | char const* _from{ lua_tostring(L1, -1) }; |
| 111 | lua_pushcfunction(L1, luaG_nameof); // L1: ... v ... decoda_name luaG_nameof | 110 | lua_pushcfunction(L1, luaG_nameof); // L1: ... v ... decoda_name luaG_nameof |
| 112 | lua_pushvalue(L1, L1_i); // L1: ... v ... decoda_name luaG_nameof t | 111 | lua_pushvalue(L1, L1_i); // L1: ... v ... decoda_name luaG_nameof t |
| 113 | lua_call(L1, 1, 2); // L1: ... v ... decoda_name "type" "name"|nil | 112 | lua_call(L1, 1, 2); // L1: ... v ... decoda_name "type" "name"|nil |
| 114 | char const* typewhat{ (lua_type(L1, -2) == LUA_TSTRING) ? lua_tostring(L1, -2) : luaL_typename(L1, -2) }; | 113 | char const* _typewhat{ (lua_type(L1, -2) == LUA_TSTRING) ? lua_tostring(L1, -2) : luaL_typename(L1, -2) }; |
| 115 | // second return value can be nil if the table was not found | 114 | // second return value can be nil if the table was not found |
| 116 | // probable reason: the function was removed from the source Lua state before Lanes was required. | 115 | // probable reason: the function was removed from the source Lua state before Lanes was required. |
| 117 | char const *what, *gotchaA, *gotchaB; | 116 | char const *_what, *_gotchaA, *_gotchaB; |
| 118 | if (lua_isnil(L1, -1)) { | 117 | if (lua_isnil(L1, -1)) { |
| 119 | gotchaA = " referenced by"; | 118 | _gotchaA = " referenced by"; |
| 120 | gotchaB = "\n(did you remove it from the source Lua state before requiring Lanes?)"; | 119 | _gotchaB = "\n(did you remove it from the source Lua state before requiring Lanes?)"; |
| 121 | what = name; | 120 | _what = name; |
| 122 | } else { | 121 | } else { |
| 123 | gotchaA = ""; | 122 | _gotchaA = ""; |
| 124 | gotchaB = ""; | 123 | _gotchaB = ""; |
| 125 | what = (lua_type(L1, -1) == LUA_TSTRING) ? lua_tostring(L1, -1) : luaL_typename(L1, -1); | 124 | _what = (lua_type(L1, -1) == LUA_TSTRING) ? lua_tostring(L1, -1) : luaL_typename(L1, -1); |
| 126 | } | 125 | } |
| 127 | raise_luaL_error(L1, "%s%s '%s' not found in %s origin transfer database.%s", typewhat, gotchaA, what, from ? from : "main", gotchaB); | 126 | raise_luaL_error(L1, "%s%s '%s' not found in %s origin transfer database.%s", _typewhat, _gotchaA, _what, _from ? _from : "main", _gotchaB); |
| 128 | } | 127 | } |
| 129 | STACK_CHECK(L1, 0); | 128 | STACK_CHECK(L1, 0); |
| 130 | return std::string_view{ _fqn, _len }; | 129 | return _fqn; |
| 131 | } | 130 | } |
| 132 | 131 | ||
| 133 | // ################################################################################################# | 132 | // ################################################################################################# |
| @@ -208,7 +207,7 @@ void InterCopyContext::copy_func() const | |||
| 208 | 207 | ||
| 209 | // transfer the bytecode, then the upvalues, to create a similar closure | 208 | // transfer the bytecode, then the upvalues, to create a similar closure |
| 210 | { | 209 | { |
| 211 | char const* fname = nullptr; | 210 | char const* _fname{}; |
| 212 | #define LOG_FUNC_INFO 0 | 211 | #define LOG_FUNC_INFO 0 |
| 213 | #if LOG_FUNC_INFO | 212 | #if LOG_FUNC_INFO |
| 214 | // "To get information about a function you push it onto the | 213 | // "To get information about a function you push it onto the |
| @@ -219,14 +218,13 @@ void InterCopyContext::copy_func() const | |||
| 219 | lua_pushvalue(L1, L1_i); // L1: ... b f | 218 | lua_pushvalue(L1, L1_i); // L1: ... b f |
| 220 | // fills 'fname' 'namewhat' and 'linedefined', pops function | 219 | // fills 'fname' 'namewhat' and 'linedefined', pops function |
| 221 | lua_getinfo(L1, ">nS", &_ar); // L1: ... b | 220 | lua_getinfo(L1, ">nS", &_ar); // L1: ... b |
| 222 | fname = _ar.namewhat; | 221 | _fname = _ar.namewhat; |
| 223 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "FNAME: %s @ %d" INDENT_END(U), _ar.short_src, _ar.linedefined)); // just gives nullptr | 222 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "FNAME: %s @ %d" INDENT_END(U), _ar.short_src, _ar.linedefined)); // just gives nullptr |
| 224 | } | 223 | } |
| 225 | #endif // LOG_FUNC_INFO | 224 | #endif // LOG_FUNC_INFO |
| 226 | { | 225 | { |
| 227 | size_t _sz; | 226 | std::string_view const _bytecode{ lua_tostringview(L1, -1) }; // L1: ... b |
| 228 | char const* _s{ lua_tolstring(L1, -1, &_sz) }; // L1: ... b | 227 | LUA_ASSERT(L1, !_bytecode.empty()); |
| 229 | LUA_ASSERT(L1, _s && _sz); | ||
| 230 | STACK_GROW(L2, 2); | 228 | STACK_GROW(L2, 2); |
| 231 | // Note: Line numbers seem to be taken precisely from the | 229 | // Note: Line numbers seem to be taken precisely from the |
| 232 | // original function. 'fname' is not used since the chunk | 230 | // original function. 'fname' is not used since the chunk |
| @@ -234,12 +232,12 @@ void InterCopyContext::copy_func() const | |||
| 234 | // | 232 | // |
| 235 | // TBD: Can we get the function's original name through, as well? | 233 | // TBD: Can we get the function's original name through, as well? |
| 236 | // | 234 | // |
| 237 | if (luaL_loadbuffer(L2, _s, _sz, fname) != 0) { // L2: ... {cache} ... p function | 235 | if (luaL_loadbuffer(L2, _bytecode.data(), _bytecode.size(), _fname) != 0) { // L2: ... {cache} ... p function |
| 238 | // chunk is precompiled so only LUA_ERRMEM can happen | 236 | // chunk is precompiled so only LUA_ERRMEM can happen |
| 239 | // "Otherwise, it pushes an error message" | 237 | // "Otherwise, it pushes an error message" |
| 240 | // | 238 | // |
| 241 | STACK_GROW(L1, 1); | 239 | STACK_GROW(L1, 1); |
| 242 | raise_luaL_error(getErrL(), "%s: %s", fname, lua_tostring(L2, -1)); | 240 | raise_luaL_error(getErrL(), "%s: %s", _fname, lua_tostring(L2, -1)); |
| 243 | } | 241 | } |
| 244 | // remove the dumped string | 242 | // remove the dumped string |
| 245 | lua_pop(L1, 1); // ... | 243 | lua_pop(L1, 1); // ... |
| @@ -268,7 +266,7 @@ void InterCopyContext::copy_func() const | |||
| 268 | lua_pushglobaltable(L1); // L1: ... _G | 266 | lua_pushglobaltable(L1); // L1: ... _G |
| 269 | #endif // LUA_VERSION_NUM | 267 | #endif // LUA_VERSION_NUM |
| 270 | for (_n = 0; (_c.name = lua_getupvalue(L1, L1_i, 1 + _n)) != nullptr; ++_n) { // L1: ... _G up[n] | 268 | for (_n = 0; (_c.name = lua_getupvalue(L1, L1_i, 1 + _n)) != nullptr; ++_n) { // L1: ... _G up[n] |
| 271 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "UPNAME[%d]: %s -> " INDENT_END(U), n, _c.name)); | 269 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "UPNAME[%d]: %s -> " INDENT_END(U), _n, _c.name)); |
| 272 | #if LUA_VERSION_NUM >= 502 | 270 | #if LUA_VERSION_NUM >= 502 |
| 273 | if (lua_rawequal(L1, -1, -2)) { // is the upvalue equal to the global table? | 271 | if (lua_rawequal(L1, -1, -2)) { // is the upvalue equal to the global table? |
| 274 | DEBUGSPEW_CODE(fprintf(stderr, "pushing destination global scope\n")); | 272 | DEBUGSPEW_CODE(fprintf(stderr, "pushing destination global scope\n")); |
| @@ -350,7 +348,7 @@ void InterCopyContext::lookup_native_func() const | |||
| 350 | "%s%s: function '%s' not found in %s destination transfer database.", | 348 | "%s%s: function '%s' not found in %s destination transfer database.", |
| 351 | lua_isnil(L2, -1) ? "" : "INTERNAL ERROR IN ", | 349 | lua_isnil(L2, -1) ? "" : "INTERNAL ERROR IN ", |
| 352 | _from ? _from : "main", | 350 | _from ? _from : "main", |
| 353 | _fqn, | 351 | _fqn.data(), |
| 354 | _to ? _to : "main"); | 352 | _to ? _to : "main"); |
| 355 | return; | 353 | return; |
| 356 | } | 354 | } |
| @@ -499,47 +497,45 @@ void InterCopyContext::inter_copy_keyvaluepair() const | |||
| 499 | // maybe offer this possibility as a global configuration option, or a linda setting, or as a parameter of the call causing the transfer? | 497 | // maybe offer this possibility as a global configuration option, or a linda setting, or as a parameter of the call causing the transfer? |
| 500 | } | 498 | } |
| 501 | 499 | ||
| 502 | char* valPath{ nullptr }; | 500 | char* _valPath{ nullptr }; |
| 503 | if (U->verboseErrors) { | 501 | if (U->verboseErrors) { |
| 504 | // for debug purposes, let's try to build a useful name | 502 | // for debug purposes, let's try to build a useful name |
| 505 | if (lua_type(L1, _key_i) == LUA_TSTRING) { | 503 | if (lua_type(L1, _key_i) == LUA_TSTRING) { |
| 506 | char const* key{ lua_tostring(L1, _key_i) }; | 504 | std::string_view const _key{ lua_tostringview(L1, _key_i) }; |
| 507 | size_t const keyRawLen = lua_rawlen(L1, _key_i); | 505 | size_t const _bufLen{ strlen(name) + _key.size() + 2 }; // +2 for separator dot and terminating 0 |
| 508 | size_t const bufLen = strlen(name) + keyRawLen + 2; | 506 | _valPath = static_cast<char*>(alloca(_bufLen)); |
| 509 | valPath = (char*) alloca(bufLen); | 507 | sprintf(_valPath, "%s.%*s", name, static_cast<int>(_key.size()), _key.data()); |
| 510 | sprintf(valPath, "%s.%*s", name, (int) keyRawLen, key); | ||
| 511 | key = nullptr; | ||
| 512 | } | 508 | } |
| 513 | #if defined LUA_LNUM || LUA_VERSION_NUM >= 503 | 509 | #if defined LUA_LNUM || LUA_VERSION_NUM >= 503 |
| 514 | else if (lua_isinteger(L1, _key_i)) { | 510 | else if (lua_isinteger(L1, _key_i)) { |
| 515 | lua_Integer const key{ lua_tointeger(L1, _key_i) }; | 511 | lua_Integer const key{ lua_tointeger(L1, _key_i) }; |
| 516 | valPath = (char*) alloca(strlen(name) + 32 + 3); | 512 | _valPath = (char*) alloca(strlen(name) + 32 + 3); // +3 for [] and terminating 0 |
| 517 | sprintf(valPath, "%s[" LUA_INTEGER_FMT "]", name, key); | 513 | sprintf(_valPath, "%s[" LUA_INTEGER_FMT "]", name, key); |
| 518 | } | 514 | } |
| 519 | #endif // defined LUA_LNUM || LUA_VERSION_NUM >= 503 | 515 | #endif // defined LUA_LNUM || LUA_VERSION_NUM >= 503 |
| 520 | else if (lua_type(L1, _key_i) == LUA_TNUMBER) { | 516 | else if (lua_type(L1, _key_i) == LUA_TNUMBER) { |
| 521 | lua_Number const key{ lua_tonumber(L1, _key_i) }; | 517 | lua_Number const key{ lua_tonumber(L1, _key_i) }; |
| 522 | valPath = (char*) alloca(strlen(name) + 32 + 3); | 518 | _valPath = (char*) alloca(strlen(name) + 32 + 3); // +3 for [] and terminating 0 |
| 523 | sprintf(valPath, "%s[" LUA_NUMBER_FMT "]", name, key); | 519 | sprintf(_valPath, "%s[" LUA_NUMBER_FMT "]", name, key); |
| 524 | } else if (lua_type(L1, _key_i) == LUA_TLIGHTUSERDATA) { | 520 | } else if (lua_type(L1, _key_i) == LUA_TLIGHTUSERDATA) { |
| 525 | void* const key{ lua_touserdata(L1, _key_i) }; | 521 | void* const key{ lua_touserdata(L1, _key_i) }; |
| 526 | valPath = (char*) alloca(strlen(name) + 16 + 5); | 522 | _valPath = (char*) alloca(strlen(name) + 16 + 5); // +5 for [U:] and terminating 0 |
| 527 | sprintf(valPath, "%s[U:%p]", name, key); | 523 | sprintf(_valPath, "%s[U:%p]", name, key); |
| 528 | } else if (lua_type(L1, _key_i) == LUA_TBOOLEAN) { | 524 | } else if (lua_type(L1, _key_i) == LUA_TBOOLEAN) { |
| 529 | int const key{ lua_toboolean(L1, _key_i) }; | 525 | int const key{ lua_toboolean(L1, _key_i) }; |
| 530 | valPath = (char*) alloca(strlen(name) + 8); | 526 | _valPath = (char*) alloca(strlen(name) + 8); // +8 for [], 'false' and terminating 0 |
| 531 | sprintf(valPath, "%s[%s]", name, key ? "true" : "false"); | 527 | sprintf(_valPath, "%s[%s]", name, key ? "true" : "false"); |
| 532 | } | 528 | } |
| 533 | } | 529 | } |
| 534 | _c.L1_i = SourceIndex{ _val_i }; | 530 | _c.L1_i = SourceIndex{ _val_i }; |
| 535 | // Contents of metatables are copied with cache checking. important to detect loops. | 531 | // Contents of metatables are copied with cache checking. important to detect loops. |
| 536 | _c.vt = VT::NORMAL; | 532 | _c.vt = VT::NORMAL; |
| 537 | _c.name = valPath ? valPath : name; | 533 | _c.name = _valPath ? _valPath : name; |
| 538 | if (_c.inter_copy_one()) { | 534 | if (_c.inter_copy_one()) { |
| 539 | LUA_ASSERT(L1, lua_istable(L2, -3)); | 535 | LUA_ASSERT(L1, lua_istable(L2, -3)); |
| 540 | lua_rawset(L2, -3); // add to table (pops key & val) | 536 | lua_rawset(L2, -3); // add to table (pops key & val) |
| 541 | } else { | 537 | } else { |
| 542 | raise_luaL_error(getErrL(), "Unable to copy %s entry '%s' because of value is of type '%s'", (vt == VT::NORMAL) ? "table" : "metatable", valPath, luaL_typename(L1, _val_i)); | 538 | raise_luaL_error(getErrL(), "Unable to copy %s entry '%s' because of value is of type '%s'", (vt == VT::NORMAL) ? "table" : "metatable", _valPath, luaL_typename(L1, _val_i)); |
| 543 | } | 539 | } |
| 544 | } | 540 | } |
| 545 | 541 | ||
| @@ -931,10 +927,9 @@ void InterCopyContext::inter_copy_keyvaluepair() const | |||
| 931 | 927 | ||
| 932 | [[nodiscard]] bool InterCopyContext::inter_copy_string() const | 928 | [[nodiscard]] bool InterCopyContext::inter_copy_string() const |
| 933 | { | 929 | { |
| 934 | size_t _len{ 0 }; | 930 | std::string_view const _s{ lua_tostringview(L1, L1_i) }; |
| 935 | char const* const _s{ lua_tolstring(L1, L1_i, &_len) }; | 931 | DEBUGSPEW_CODE(fprintf(stderr, "'%s'\n", _s.data())); |
| 936 | DEBUGSPEW_CODE(fprintf(stderr, "'%s'\n", _s)); | 932 | lua_pushlstring(L2, _s.data(), _s.size()); |
| 937 | lua_pushlstring(L2, _s, _len); | ||
| 938 | return true; | 933 | return true; |
| 939 | } | 934 | } |
| 940 | 935 | ||
diff --git a/src/lanes.cpp b/src/lanes.cpp index a68c3aa..74e2507 100644 --- a/src/lanes.cpp +++ b/src/lanes.cpp | |||
| @@ -395,9 +395,8 @@ LUAG_FUNC(lane_new) | |||
| 395 | raise_luaL_error(L_, "required module list should be a list of strings"); | 395 | raise_luaL_error(L_, "required module list should be a list of strings"); |
| 396 | } else { | 396 | } else { |
| 397 | // require the module in the target state, and populate the lookup table there too | 397 | // require the module in the target state, and populate the lookup table there too |
| 398 | size_t _len{ 0 }; | 398 | std::string_view const _name{ lua_tostringview(L_, -1) }; |
| 399 | char const* _name{ lua_tolstring(L_, -1, &_len) }; | 399 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: require '%s'\n" INDENT_END(_U), _name.data())); |
| 400 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: require '%s'\n" INDENT_END(_U), name)); | ||
| 401 | 400 | ||
| 402 | // require the module in the target lane | 401 | // require the module in the target lane |
| 403 | lua_getglobal(_L2, "require"); // L_: [fixed] args... n "modname" L2: require()? | 402 | lua_getglobal(_L2, "require"); // L_: [fixed] args... n "modname" L2: require()? |
| @@ -405,7 +404,7 @@ LUAG_FUNC(lane_new) | |||
| 405 | lua_pop(_L2, 1); // L_: [fixed] args... n "modname" L2: | 404 | lua_pop(_L2, 1); // L_: [fixed] args... n "modname" L2: |
| 406 | raise_luaL_error(L_, "cannot pre-require modules without loading 'package' library first"); | 405 | raise_luaL_error(L_, "cannot pre-require modules without loading 'package' library first"); |
| 407 | } else { | 406 | } else { |
| 408 | lua_pushlstring(_L2, _name, _len); // L_: [fixed] args... n "modname" L2: require() name | 407 | lua_pushlstring(_L2, _name.data(), _name.size()); // L_: [fixed] args... n "modname" L2: require() name |
| 409 | LuaError const _rc{ lua_pcall(_L2, 1, 1, 0) }; // L_: [fixed] args... n "modname" L2: ret/errcode | 408 | LuaError const _rc{ lua_pcall(_L2, 1, 1, 0) }; // L_: [fixed] args... n "modname" L2: ret/errcode |
| 410 | if (_rc != LuaError::OK) { | 409 | if (_rc != LuaError::OK) { |
| 411 | // propagate error to main state if any | 410 | // propagate error to main state if any |
| @@ -415,7 +414,7 @@ LUAG_FUNC(lane_new) | |||
| 415 | } | 414 | } |
| 416 | // here the module was successfully required // L_: [fixed] args... n "modname" L2: ret | 415 | // here the module was successfully required // L_: [fixed] args... n "modname" L2: ret |
| 417 | // after requiring the module, register the functions it exported in our name<->function database | 416 | // after requiring the module, register the functions it exported in our name<->function database |
| 418 | populate_func_lookup_table(_L2, -1, _name); | 417 | populate_func_lookup_table(_L2, -1, _name.data()); |
| 419 | lua_pop(_L2, 1); // L_: [fixed] args... n "modname" L2: | 418 | lua_pop(_L2, 1); // L_: [fixed] args... n "modname" L2: |
| 420 | } | 419 | } |
| 421 | } | 420 | } |
diff --git a/src/lindafactory.cpp b/src/lindafactory.cpp index 9bc56d9..015baf4 100644 --- a/src/lindafactory.cpp +++ b/src/lindafactory.cpp | |||
| @@ -103,8 +103,7 @@ std::string_view LindaFactory::moduleName() const | |||
| 103 | 103 | ||
| 104 | DeepPrelude* LindaFactory::newDeepObjectInternal(lua_State* L_) const | 104 | DeepPrelude* LindaFactory::newDeepObjectInternal(lua_State* L_) const |
| 105 | { | 105 | { |
| 106 | size_t _name_len{ 0 }; | 106 | std::string_view _linda_name{}; |
| 107 | char const* _linda_name{ nullptr }; | ||
| 108 | LindaGroup _linda_group{ 0 }; | 107 | LindaGroup _linda_group{ 0 }; |
| 109 | // should have a string and/or a number of the stack as parameters (name and group) | 108 | // should have a string and/or a number of the stack as parameters (name and group) |
| 110 | switch (lua_gettop(L_)) { | 109 | switch (lua_gettop(L_)) { |
| @@ -113,14 +112,14 @@ DeepPrelude* LindaFactory::newDeepObjectInternal(lua_State* L_) const | |||
| 113 | 112 | ||
| 114 | case 1: // 1 parameter, either a name or a group | 113 | case 1: // 1 parameter, either a name or a group |
| 115 | if (lua_type(L_, -1) == LUA_TSTRING) { | 114 | if (lua_type(L_, -1) == LUA_TSTRING) { |
| 116 | _linda_name = lua_tolstring(L_, -1, &_name_len); | 115 | _linda_name = lua_tostringview(L_, -1); |
| 117 | } else { | 116 | } else { |
| 118 | _linda_group = LindaGroup{ static_cast<int>(lua_tointeger(L_, -1)) }; | 117 | _linda_group = LindaGroup{ static_cast<int>(lua_tointeger(L_, -1)) }; |
| 119 | } | 118 | } |
| 120 | break; | 119 | break; |
| 121 | 120 | ||
| 122 | case 2: // 2 parameters, a name and group, in that order | 121 | case 2: // 2 parameters, a name and group, in that order |
| 123 | _linda_name = lua_tolstring(L_, -2, &_name_len); | 122 | _linda_name = lua_tostringview(L_, -2); |
| 124 | _linda_group = LindaGroup{ static_cast<int>(lua_tointeger(L_, -1)) }; | 123 | _linda_group = LindaGroup{ static_cast<int>(lua_tointeger(L_, -1)) }; |
| 125 | break; | 124 | break; |
| 126 | } | 125 | } |
| @@ -128,6 +127,6 @@ DeepPrelude* LindaFactory::newDeepObjectInternal(lua_State* L_) const | |||
| 128 | // The deep data is allocated separately of Lua stack; we might no longer be around when last reference to it is being released. | 127 | // The deep data is allocated separately of Lua stack; we might no longer be around when last reference to it is being released. |
| 129 | // One can use any memory allocation scheme. Just don't use L's allocF because we don't know which state will get the honor of GCing the linda | 128 | // One can use any memory allocation scheme. Just don't use L's allocF because we don't know which state will get the honor of GCing the linda |
| 130 | Universe* const _U{ universe_get(L_) }; | 129 | Universe* const _U{ universe_get(L_) }; |
| 131 | Linda* const _linda{ new (_U) Linda{ _U, _linda_group, _linda_name, _name_len } }; | 130 | Linda* const _linda{ new (_U) Linda{ _U, _linda_group, _linda_name.data(), _linda_name.size() } }; |
| 132 | return _linda; | 131 | return _linda; |
| 133 | } | 132 | } |
diff --git a/src/tools.cpp b/src/tools.cpp index 8ddce75..ba0785b 100644 --- a/src/tools.cpp +++ b/src/tools.cpp | |||
| @@ -90,26 +90,26 @@ static constexpr int kWriterReturnCode{ 666 }; | |||
| 90 | // ################################################################################################# | 90 | // ################################################################################################# |
| 91 | 91 | ||
| 92 | // inspired from tconcat() in ltablib.c | 92 | // inspired from tconcat() in ltablib.c |
| 93 | [[nodiscard]] static char const* luaG_pushFQN(lua_State* L_, int t_, int last_, size_t* length_) | 93 | [[nodiscard]] static std::string_view luaG_pushFQN(lua_State* L_, int t_, int last_) |
| 94 | { | 94 | { |
| 95 | luaL_Buffer _b; | 95 | luaL_Buffer _b; |
| 96 | STACK_CHECK_START_REL(L_, 0); | 96 | STACK_CHECK_START_REL(L_, 0); |
| 97 | // Lua 5.4 pushes &b as light userdata on the stack. be aware of it... | 97 | // Lua 5.4 pushes &b as light userdata on the stack. be aware of it... |
| 98 | luaL_buffinit(L_, &_b); // L_: ... {} ... &b? | 98 | luaL_buffinit(L_, &_b); // L_: ... {} ... &b? |
| 99 | int i = 1; | 99 | int _i{ 1 }; |
| 100 | for (; i < last_; ++i) { | 100 | for (; _i < last_; ++_i) { |
| 101 | lua_rawgeti(L_, t_, i); | 101 | lua_rawgeti(L_, t_, _i); |
| 102 | luaL_addvalue(&_b); | 102 | luaL_addvalue(&_b); |
| 103 | luaL_addlstring(&_b, "/", 1); | 103 | luaL_addlstring(&_b, "/", 1); |
| 104 | } | 104 | } |
| 105 | if (i == last_) { // add last value (if interval was not empty) | 105 | if (_i == last_) { // add last value (if interval was not empty) |
| 106 | lua_rawgeti(L_, t_, i); | 106 | lua_rawgeti(L_, t_, _i); |
| 107 | luaL_addvalue(&_b); | 107 | luaL_addvalue(&_b); |
| 108 | } | 108 | } |
| 109 | // &b is popped at that point (-> replaced by the result) | 109 | // &b is popped at that point (-> replaced by the result) |
| 110 | luaL_pushresult(&_b); // L_: ... {} ... "<result>" | 110 | luaL_pushresult(&_b); // L_: ... {} ... "<result>" |
| 111 | STACK_CHECK(L_, 1); | 111 | STACK_CHECK(L_, 1); |
| 112 | return lua_tolstring(L_, -1, length_); | 112 | return lua_tostringview(L_, -1); |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | // ################################################################################################# | 115 | // ################################################################################################# |
| @@ -129,7 +129,6 @@ static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA(Universe* U_) lua_State* L | |||
| 129 | // slot 2 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot _i | 129 | // slot 2 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot _i |
| 130 | int const _fqn{ ctxBase_ + 1 }; | 130 | int const _fqn{ ctxBase_ + 1 }; |
| 131 | 131 | ||
| 132 | DEBUGSPEW_CODE(char const* _newName); | ||
| 133 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "update_lookup_entry()\n" INDENT_END(U_))); | 132 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "update_lookup_entry()\n" INDENT_END(U_))); |
| 134 | DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ U_ }); | 133 | DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ U_ }); |
| 135 | 134 | ||
| @@ -137,16 +136,14 @@ static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA(Universe* U_) lua_State* L | |||
| 137 | // first, raise an error if the function is already known | 136 | // first, raise an error if the function is already known |
| 138 | lua_pushvalue(L_, -1); // L_: ... {bfc} k o o | 137 | lua_pushvalue(L_, -1); // L_: ... {bfc} k o o |
| 139 | lua_rawget(L_, _dest); // L_: ... {bfc} k o name? | 138 | lua_rawget(L_, _dest); // L_: ... {bfc} k o name? |
| 140 | size_t _prevNameLength; | 139 | std::string_view const _prevName{ lua_tostringview(L_, -1) }; // nullptr if we got nil (first encounter of this object) |
| 141 | char const* const _prevName{ lua_tolstring(L_, -1, &_prevNameLength) }; // nullptr if we got nil (first encounter of this object) | ||
| 142 | // push name in fqn stack (note that concatenation will crash if name is a not string or a number) | 140 | // push name in fqn stack (note that concatenation will crash if name is a not string or a number) |
| 143 | lua_pushvalue(L_, -3); // L_: ... {bfc} k o name? k | 141 | lua_pushvalue(L_, -3); // L_: ... {bfc} k o name? k |
| 144 | LUA_ASSERT(L_, lua_type(L_, -1) == LUA_TNUMBER || lua_type(L_, -1) == LUA_TSTRING); | 142 | LUA_ASSERT(L_, lua_type(L_, -1) == LUA_TNUMBER || lua_type(L_, -1) == LUA_TSTRING); |
| 145 | ++depth_; | 143 | ++depth_; |
| 146 | lua_rawseti(L_, _fqn, depth_); // L_: ... {bfc} k o name? | 144 | lua_rawseti(L_, _fqn, depth_); // L_: ... {bfc} k o name? |
| 147 | // generate name | 145 | // generate name |
| 148 | size_t _newNameLength; | 146 | std::string_view const _newName{ luaG_pushFQN(L_, _fqn, depth_) }; // L_: ... {bfc} k o name? "f.q.n" |
| 149 | DEBUGSPEW_OR_NOT(_newName, std::ignore) = luaG_pushFQN(L_, _fqn, depth_, &_newNameLength); // L_: ... {bfc} k o name? "f.q.n" | ||
| 150 | // Lua 5.2 introduced a hash randomizer seed which causes table iteration to yield a different key order | 147 | // Lua 5.2 introduced a hash randomizer seed which causes table iteration to yield a different key order |
| 151 | // on different VMs even when the tables are populated the exact same way. | 148 | // on different VMs even when the tables are populated the exact same way. |
| 152 | // When Lua is built with compatibility options (such as LUA_COMPAT_ALL), | 149 | // When Lua is built with compatibility options (such as LUA_COMPAT_ALL), |
| @@ -156,13 +153,13 @@ static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA(Universe* U_) lua_State* L | |||
| 156 | // Also, nothing prevents any external module from exposing a given object under several names, so... | 153 | // Also, nothing prevents any external module from exposing a given object under several names, so... |
| 157 | // Therefore, when we encounter an object for which a name was previously registered, we need to select the names | 154 | // Therefore, when we encounter an object for which a name was previously registered, we need to select the names |
| 158 | // based on some sorting order so that we end up with the same name in all databases whatever order the table walk yielded | 155 | // based on some sorting order so that we end up with the same name in all databases whatever order the table walk yielded |
| 159 | if (_prevName != nullptr && (_prevNameLength < _newNameLength || lua_lessthan(L_, -2, -1))) { | 156 | if (!_prevName.empty() && (_prevName.size() < _newName.size() || lua_lessthan(L_, -2, -1))) { |
| 160 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "%s '%s' remained named '%s'\n" INDENT_END(U_), lua_typename(L_, lua_type(L_, -3)), _newName, _prevName)); | 157 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "%s '%s' remained named '%s'\n" INDENT_END(U_), lua_typename(L_, lua_type(L_, -3)), _newName.data(), _prevName.data())); |
| 161 | // the previous name is 'smaller' than the one we just generated: keep it! | 158 | // the previous name is 'smaller' than the one we just generated: keep it! |
| 162 | lua_pop(L_, 3); // L_: ... {bfc} k | 159 | lua_pop(L_, 3); // L_: ... {bfc} k |
| 163 | } else { | 160 | } else { |
| 164 | // the name we generated is either the first one, or a better fit for our purposes | 161 | // the name we generated is either the first one, or a better fit for our purposes |
| 165 | if (_prevName) { | 162 | if (!_prevName.empty()) { |
| 166 | // clear the previous name for the database to avoid clutter | 163 | // clear the previous name for the database to avoid clutter |
| 167 | lua_insert(L_, -2); // L_: ... {bfc} k o "f.q.n" prevName | 164 | lua_insert(L_, -2); // L_: ... {bfc} k o "f.q.n" prevName |
| 168 | // t[prevName] = nil | 165 | // t[prevName] = nil |
| @@ -171,7 +168,7 @@ static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA(Universe* U_) lua_State* L | |||
| 171 | } else { | 168 | } else { |
| 172 | lua_remove(L_, -2); // L_: ... {bfc} k o "f.q.n" | 169 | lua_remove(L_, -2); // L_: ... {bfc} k o "f.q.n" |
| 173 | } | 170 | } |
| 174 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "%s '%s'\n" INDENT_END(U_), lua_typename(L_, lua_type(L_, -2)), _newName)); | 171 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "%s '%s'\n" INDENT_END(U_), lua_typename(L_, lua_type(L_, -2)), _newName.data())); |
| 175 | // prepare the stack for database feed | 172 | // prepare the stack for database feed |
| 176 | lua_pushvalue(L_, -1); // L_: ... {bfc} k o "f.q.n" "f.q.n" | 173 | lua_pushvalue(L_, -1); // L_: ... {bfc} k o "f.q.n" "f.q.n" |
| 177 | lua_pushvalue(L_, -3); // L_: ... {bfc} k o "f.q.n" "f.q.n" o | 174 | lua_pushvalue(L_, -3); // L_: ... {bfc} k o "f.q.n" "f.q.n" o |
| @@ -390,7 +387,7 @@ void populate_func_lookup_table(lua_State* L_, int i_, char const* name_) | |||
| 390 | // update shortest name | 387 | // update shortest name |
| 391 | if (depth_ < shortest_) { | 388 | if (depth_ < shortest_) { |
| 392 | shortest_ = depth_; | 389 | shortest_ = depth_; |
| 393 | std::ignore = luaG_pushFQN(L_, kFQN, depth_, nullptr); // L_: o "r" {c} {fqn} ... {?} k v "fqn" | 390 | std::ignore = luaG_pushFQN(L_, kFQN, depth_); // L_: o "r" {c} {fqn} ... {?} k v "fqn" |
| 394 | lua_replace(L_, kResult); // L_: o "r" {c} {fqn} ... {?} k v | 391 | lua_replace(L_, kResult); // L_: o "r" {c} {fqn} ... {?} k v |
| 395 | } | 392 | } |
| 396 | // no need to search further at this level | 393 | // no need to search further at this level |
diff --git a/src/universe.cpp b/src/universe.cpp index 9ab1290..52aa368 100644 --- a/src/universe.cpp +++ b/src/universe.cpp | |||
| @@ -368,14 +368,14 @@ void Universe::terminateFreeRunningLanes(lua_State* L_, lua_Duration shutdownTim | |||
| 368 | int universe_gc(lua_State* L_) | 368 | int universe_gc(lua_State* L_) |
| 369 | { | 369 | { |
| 370 | lua_Duration const _shutdown_timeout{ lua_tonumber(L_, lua_upvalueindex(1)) }; | 370 | lua_Duration const _shutdown_timeout{ lua_tonumber(L_, lua_upvalueindex(1)) }; |
| 371 | [[maybe_unused]] char const* const _op_string{ lua_tostring(L_, lua_upvalueindex(2)) }; | 371 | std::string_view const _op_string{ lua_tostringview(L_, lua_upvalueindex(2)) }; |
| 372 | Universe* const _U{ lua_tofulluserdata<Universe>(L_, 1) }; | 372 | Universe* const _U{ lua_tofulluserdata<Universe>(L_, 1) }; |
| 373 | _U->terminateFreeRunningLanes(L_, _shutdown_timeout, which_cancel_op(_op_string)); | 373 | _U->terminateFreeRunningLanes(L_, _shutdown_timeout, which_cancel_op(_op_string)); |
| 374 | 374 | ||
| 375 | // no need to mutex-protect this as all threads in the universe are gone at that point | 375 | // no need to mutex-protect this as all threads in the universe are gone at that point |
| 376 | if (_U->timerLinda != nullptr) { // test in case some early internal error prevented Lanes from creating the deep timer | 376 | if (_U->timerLinda != nullptr) { // test in case some early internal error prevented Lanes from creating the deep timer |
| 377 | [[maybe_unused]] int const prev_ref_count{ _U->timerLinda->refcount.fetch_sub(1, std::memory_order_relaxed) }; | 377 | [[maybe_unused]] int const _prev_ref_count{ _U->timerLinda->refcount.fetch_sub(1, std::memory_order_relaxed) }; |
| 378 | LUA_ASSERT(L_, prev_ref_count == 1); // this should be the last reference | 378 | LUA_ASSERT(L_, _prev_ref_count == 1); // this should be the last reference |
| 379 | DeepFactory::DeleteDeepObject(L_, _U->timerLinda); | 379 | DeepFactory::DeleteDeepObject(L_, _U->timerLinda); |
| 380 | _U->timerLinda = nullptr; | 380 | _U->timerLinda = nullptr; |
| 381 | } | 381 | } |
