aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cancel.cpp16
-rw-r--r--src/cancel.h4
-rw-r--r--src/compat.h11
-rw-r--r--src/intercopycontext.cpp87
-rw-r--r--src/lanes.cpp9
-rw-r--r--src/lindafactory.cpp9
-rw-r--r--src/tools.cpp31
-rw-r--r--src/universe.cpp6
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
165CancelOp which_cancel_op(char const* opString_) 165CancelOp 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
19class Lane; // forward 21class 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
49static constexpr UniqueKey kCancelError{ 0x0630345FEF912746ull, "lanes.cancel_error" }; // 'raise_cancel_error' sentinel 51static 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
251LuaType luaG_getmodule(lua_State* L_, char const* name_); 252LuaType luaG_getmodule(lua_State* L_, char const* name_);
253
254// #################################################################################################
255
256// a replacement of lua_tolstring
257inline 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
104DeepPrelude* LindaFactory::newDeepObjectInternal(lua_State* L_) const 104DeepPrelude* 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
368int universe_gc(lua_State* L_) 368int 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 }