diff options
Diffstat (limited to 'src/keeper.cpp')
-rw-r--r-- | src/keeper.cpp | 149 |
1 files changed, 83 insertions, 66 deletions
diff --git a/src/keeper.cpp b/src/keeper.cpp index cad9207..4af0d86 100644 --- a/src/keeper.cpp +++ b/src/keeper.cpp | |||
@@ -77,7 +77,7 @@ class KeyUD final | |||
77 | 77 | ||
78 | // a fifo full userdata has one uservalue, the table that holds the actual fifo contents | 78 | // a fifo full userdata has one uservalue, the table that holds the actual fifo contents |
79 | [[nodiscard]] | 79 | [[nodiscard]] |
80 | static void* operator new([[maybe_unused]] size_t size_, KeeperState L_) noexcept { return luaG_newuserdatauv<KeyUD>(L_, UserValueCount{ 1 }); } | 80 | static void* operator new([[maybe_unused]] size_t size_, KeeperState L_) noexcept { return luaW_newuserdatauv<KeyUD>(L_, UserValueCount{ 1 }); } |
81 | // always embedded somewhere else or "in-place constructed" as a full userdata | 81 | // always embedded somewhere else or "in-place constructed" as a full userdata |
82 | // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception | 82 | // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception |
83 | static void operator delete([[maybe_unused]] void* p_, [[maybe_unused]] KeeperState L_) { LUA_ASSERT(L_, !"should never be called"); } | 83 | static void operator delete([[maybe_unused]] void* p_, [[maybe_unused]] KeeperState L_) { LUA_ASSERT(L_, !"should never be called"); } |
@@ -104,6 +104,7 @@ class KeyUD final | |||
104 | 104 | ||
105 | // ################################################################################################# | 105 | // ################################################################################################# |
106 | 106 | ||
107 | [[nodiscard]] | ||
107 | bool KeyUD::changeLimit(LindaLimit const limit_) | 108 | bool KeyUD::changeLimit(LindaLimit const limit_) |
108 | { | 109 | { |
109 | bool const _newSlackAvailable{ | 110 | bool const _newSlackAvailable{ |
@@ -127,6 +128,7 @@ LindaRestrict KeyUD::changeRestrict(LindaRestrict const restrict_) | |||
127 | 128 | ||
128 | // in: nothing | 129 | // in: nothing |
129 | // out: { first = 1, count = 0, limit = -1} | 130 | // out: { first = 1, count = 0, limit = -1} |
131 | [[nodiscard]] | ||
130 | KeyUD* KeyUD::Create(KeeperState const K_) | 132 | KeyUD* KeyUD::Create(KeeperState const K_) |
131 | { | 133 | { |
132 | STACK_GROW(K_, 2); | 134 | STACK_GROW(K_, 2); |
@@ -141,9 +143,10 @@ KeyUD* KeyUD::Create(KeeperState const K_) | |||
141 | 143 | ||
142 | // ################################################################################################# | 144 | // ################################################################################################# |
143 | 145 | ||
146 | [[nodiscard]] | ||
144 | KeyUD* KeyUD::GetPtr(KeeperState const K_, StackIndex const idx_) | 147 | KeyUD* KeyUD::GetPtr(KeeperState const K_, StackIndex const idx_) |
145 | { | 148 | { |
146 | return luaG_tofulluserdata<KeyUD>(K_, idx_); | 149 | return luaW_tofulluserdata<KeyUD>(K_, idx_); |
147 | } | 150 | } |
148 | 151 | ||
149 | // ################################################################################################# | 152 | // ################################################################################################# |
@@ -181,6 +184,7 @@ void KeyUD::peek(KeeperState const K_, int const count_) const | |||
181 | 184 | ||
182 | // in: fifo | 185 | // in: fifo |
183 | // out: remove the fifo table from the stack, push as many items as required on the stack (function assumes they exist in sufficient number) | 186 | // out: remove the fifo table from the stack, push as many items as required on the stack (function assumes they exist in sufficient number) |
187 | [[nodiscard]] | ||
184 | int KeyUD::pop(KeeperState const K_, int const minCount_, int const maxCount_) | 188 | int KeyUD::pop(KeeperState const K_, int const minCount_, int const maxCount_) |
185 | { | 189 | { |
186 | if (count < minCount_) { | 190 | if (count < minCount_) { |
@@ -191,23 +195,33 @@ int KeyUD::pop(KeeperState const K_, int const minCount_, int const maxCount_) | |||
191 | int const _popCount{ std::min(count, maxCount_) }; | 195 | int const _popCount{ std::min(count, maxCount_) }; |
192 | LUA_ASSERT(K_, KeyUD::GetPtr(K_, kIdxTop) == this); // K_: ... this | 196 | LUA_ASSERT(K_, KeyUD::GetPtr(K_, kIdxTop) == this); // K_: ... this |
193 | prepareAccess(K_, kIdxTop); // K_: ... fifo | 197 | prepareAccess(K_, kIdxTop); // K_: ... fifo |
198 | |||
199 | STACK_CHECK_START_REL(K_, 0); | ||
194 | StackIndex const _fifo_idx{ lua_gettop(K_) }; | 200 | StackIndex const _fifo_idx{ lua_gettop(K_) }; |
195 | // each iteration pushes a value on the stack! | 201 | // each iteration pushes a value on the stack! |
196 | STACK_GROW(K_, _popCount + 2); | 202 | STACK_GROW(K_, _popCount + 2); |
197 | // skip first item, we will push it last | 203 | |
198 | for (int const _i : std::ranges::iota_view{ 1, _popCount }) { | 204 | // remove an element from fifo sequence and push it on the stack |
205 | auto _extractFifoItem = [K = K_, first = first, fifo_idx = lua_gettop(K_)](int const _i) | ||
206 | { | ||
207 | STACK_CHECK_START_REL(K, 0); | ||
199 | int const _at{ first + _i }; | 208 | int const _at{ first + _i }; |
200 | // push item on the stack | 209 | // push item on the stack |
201 | lua_rawgeti(K_, _fifo_idx, _at); // K_: ... fifo val | 210 | lua_rawgeti(K, fifo_idx, _at); // K_: ... fifo val |
202 | // remove item from the fifo | 211 | // remove item from the fifo |
203 | lua_pushnil(K_); // K_: ... fifo val nil | 212 | lua_pushnil(K); // K_: ... fifo val nil |
204 | lua_rawseti(K_, _fifo_idx, _at); // K_: ... fifo val | 213 | lua_rawseti(K, fifo_idx, _at); // K_: ... fifo val |
214 | STACK_CHECK(K, 1); | ||
215 | }; | ||
216 | |||
217 | // skip first item, we will push it last to avoid shifting the whole stack when removing 'fifo' | ||
218 | for (int const _i : std::ranges::iota_view{ 1, _popCount }) { | ||
219 | _extractFifoItem(_i); // K_: ... fifo val1...valN | ||
205 | } | 220 | } |
206 | // now process first item | 221 | // now process first item |
207 | lua_rawgeti(K_, _fifo_idx, first); // K_: ... fifo vals val | 222 | _extractFifoItem(0); // K_: ... fifo val1...valN val0 |
208 | lua_pushnil(K_); // K_: ... fifo vals val nil | 223 | STACK_CHECK(K_, _popCount); |
209 | lua_rawseti(K_, _fifo_idx, first); // K_: ... fifo vals val | 224 | lua_replace(K_, _fifo_idx); // K_: ... val0...valN |
210 | lua_replace(K_, _fifo_idx); // K_: ... vals | ||
211 | 225 | ||
212 | // avoid ever-growing indexes by resetting each time we detect the fifo is empty | 226 | // avoid ever-growing indexes by resetting each time we detect the fifo is empty |
213 | int const _new_count{ count - _popCount }; | 227 | int const _new_count{ count - _popCount }; |
@@ -222,7 +236,7 @@ int KeyUD::pop(KeeperState const K_, int const minCount_, int const maxCount_) | |||
222 | // replaces it by its uservalue on the stack (the table holding the fifo values) | 236 | // replaces it by its uservalue on the stack (the table holding the fifo values) |
223 | void KeyUD::prepareAccess(KeeperState const K_, StackIndex const idx_) const | 237 | void KeyUD::prepareAccess(KeeperState const K_, StackIndex const idx_) const |
224 | { | 238 | { |
225 | StackIndex const _idx{ luaG_absindex(K_, idx_) }; | 239 | StackIndex const _idx{ luaW_absindex(K_, idx_) }; |
226 | LUA_ASSERT(K_, KeyUD::GetPtr(K_, idx_) == this); | 240 | LUA_ASSERT(K_, KeyUD::GetPtr(K_, idx_) == this); |
227 | // we can replace the key userdata in the stack without fear of it being GCed, there are other references around | 241 | // we can replace the key userdata in the stack without fear of it being GCed, there are other references around |
228 | lua_getiuservalue(K_, _idx, kContentsTableIndex); | 242 | lua_getiuservalue(K_, _idx, kContentsTableIndex); |
@@ -233,9 +247,10 @@ void KeyUD::prepareAccess(KeeperState const K_, StackIndex const idx_) const | |||
233 | 247 | ||
234 | // in: expect this val... on top of the stack | 248 | // in: expect this val... on top of the stack |
235 | // out: nothing, removes all pushed values from the stack | 249 | // out: nothing, removes all pushed values from the stack |
250 | [[nodiscard]] | ||
236 | bool KeyUD::push(KeeperState const K_, int const count_, bool const enforceLimit_) | 251 | bool KeyUD::push(KeeperState const K_, int const count_, bool const enforceLimit_) |
237 | { | 252 | { |
238 | StackIndex const _fifoIdx{ luaG_absindex(K_, StackIndex{ -1 - count_ }) }; | 253 | StackIndex const _fifoIdx{ luaW_absindex(K_, StackIndex{ -1 - count_ }) }; |
239 | LUA_ASSERT(K_, KeyUD::GetPtr(K_, _fifoIdx) == this); // K_: this val... | 254 | LUA_ASSERT(K_, KeyUD::GetPtr(K_, _fifoIdx) == this); // K_: this val... |
240 | if (enforceLimit_ && (limit >= 0) && (count + count_ > limit)) { // not enough room | 255 | if (enforceLimit_ && (limit >= 0) && (count + count_ > limit)) { // not enough room |
241 | return false; | 256 | return false; |
@@ -259,16 +274,16 @@ bool KeyUD::push(KeeperState const K_, int const count_, bool const enforceLimit | |||
259 | void KeyUD::pushFillStatus(KeeperState const K_) const | 274 | void KeyUD::pushFillStatus(KeeperState const K_) const |
260 | { | 275 | { |
261 | if (limit < 0) { | 276 | if (limit < 0) { |
262 | luaG_pushstring(K_, kUnder); | 277 | luaW_pushstring(K_, kUnder); |
263 | return; | 278 | return; |
264 | } | 279 | } |
265 | int const _delta{limit - count}; | 280 | int const _delta{ limit - count }; |
266 | if (_delta < 0) { | 281 | if (_delta < 0) { |
267 | luaG_pushstring(K_, kOver); | 282 | luaW_pushstring(K_, kOver); |
268 | } else if (_delta > 0) { | 283 | } else if (_delta > 0) { |
269 | luaG_pushstring(K_, kUnder); | 284 | luaW_pushstring(K_, kUnder); |
270 | } else { | 285 | } else { |
271 | luaG_pushstring(K_, kExact); | 286 | luaW_pushstring(K_, kExact); |
272 | } | 287 | } |
273 | } | 288 | } |
274 | 289 | ||
@@ -279,13 +294,16 @@ void KeyUD::PushFillStatus(KeeperState const K_, KeyUD const* const key_) | |||
279 | if (key_) { | 294 | if (key_) { |
280 | key_->pushFillStatus(K_); // _K: ... <fill status> | 295 | key_->pushFillStatus(K_); // _K: ... <fill status> |
281 | } else { | 296 | } else { |
282 | luaG_pushstring(K_, KeyUD::kUnder); // _K: ... "under" | 297 | luaW_pushstring(K_, KeyUD::kUnder); // _K: ... "under" |
283 | } | 298 | } |
284 | } | 299 | } |
285 | 300 | ||
286 | // ################################################################################################# | 301 | // ################################################################################################# |
287 | 302 | ||
288 | // expects 'this' on top of the stack | 303 | // in: expects 'this' on top of the stack |
304 | // out: nothing | ||
305 | // returns true if the channel was full | ||
306 | [[nodiscard]] | ||
289 | bool KeyUD::reset(KeeperState const K_) | 307 | bool KeyUD::reset(KeeperState const K_) |
290 | { | 308 | { |
291 | LUA_ASSERT(K_, KeyUD::GetPtr(K_, kIdxTop) == this); | 309 | LUA_ASSERT(K_, KeyUD::GetPtr(K_, kIdxTop) == this); |
@@ -312,10 +330,10 @@ static void PushKeysDB(KeeperState const K_, StackIndex const idx_) | |||
312 | { | 330 | { |
313 | STACK_GROW(K_, 5); | 331 | STACK_GROW(K_, 5); |
314 | STACK_CHECK_START_REL(K_, 0); | 332 | STACK_CHECK_START_REL(K_, 0); |
315 | StackIndex const _absidx{ luaG_absindex(K_, idx_) }; | 333 | StackIndex const _absidx{ luaW_absindex(K_, idx_) }; |
316 | kLindasRegKey.pushValue(K_); // K_: ... LindasDB | 334 | kLindasRegKey.pushValue(K_); // K_: ... LindasDB |
317 | lua_pushvalue(K_, _absidx); // K_: ... LindasDB linda | 335 | lua_pushvalue(K_, _absidx); // K_: ... LindasDB linda |
318 | if (luaG_rawget(K_, StackIndex{ -2 }) == LuaType::NIL) { // K_: ... LindasDB KeysDB | 336 | if (luaW_rawget(K_, StackIndex{ -2 }) == LuaType::NIL) { // K_: ... LindasDB KeysDB |
319 | lua_pop(K_, 1); // K_: ... LindasDB | 337 | lua_pop(K_, 1); // K_: ... LindasDB |
320 | // add a new KeysDB table for this linda | 338 | // add a new KeysDB table for this linda |
321 | lua_newtable(K_); // K_: ... LindasDB KeysDB | 339 | lua_newtable(K_); // K_: ... LindasDB KeysDB |
@@ -337,6 +355,7 @@ static void PushKeysDB(KeeperState const K_, StackIndex const idx_) | |||
337 | 355 | ||
338 | // in: linda | 356 | // in: linda |
339 | // out: nothing | 357 | // out: nothing |
358 | [[nodiscard]] | ||
340 | int keepercall_collectgarbage(lua_State* const L_) | 359 | int keepercall_collectgarbage(lua_State* const L_) |
341 | { | 360 | { |
342 | lua_gc(L_, LUA_GCCOLLECT, 0); | 361 | lua_gc(L_, LUA_GCCOLLECT, 0); |
@@ -346,6 +365,7 @@ int keepercall_collectgarbage(lua_State* const L_) | |||
346 | // ################################################################################################# | 365 | // ################################################################################################# |
347 | 366 | ||
348 | // in: linda [, key [, ...]] | 367 | // in: linda [, key [, ...]] |
368 | [[nodiscard]] | ||
349 | int keepercall_count(lua_State* const L_) | 369 | int keepercall_count(lua_State* const L_) |
350 | { | 370 | { |
351 | KeeperState const _K{ L_ }; | 371 | KeeperState const _K{ L_ }; |
@@ -370,7 +390,7 @@ int keepercall_count(lua_State* const L_) | |||
370 | case 2: // _K: linda key | 390 | case 2: // _K: linda key |
371 | PushKeysDB(_K, StackIndex{ 1 }); // _K: linda key KeysDB | 391 | PushKeysDB(_K, StackIndex{ 1 }); // _K: linda key KeysDB |
372 | lua_replace(_K, 1); // _K: KeysDB key | 392 | lua_replace(_K, 1); // _K: KeysDB key |
373 | if (luaG_rawget(_K, StackIndex{ -2 }) == LuaType::NIL) { // the key is unknown // _K: KeysDB KeyUD|nil | 393 | if (luaW_rawget(_K, StackIndex{ -2 }) == LuaType::NIL) { // the key is unknown // _K: KeysDB KeyUD|nil |
374 | lua_remove(_K, -2); // _K: nil | 394 | lua_remove(_K, -2); // _K: nil |
375 | } else { // the key is known // _K: KeysDB KeyUD | 395 | } else { // the key is known // _K: KeysDB KeyUD |
376 | KeyUD* const _key{ KeyUD::GetPtr(_K, kIdxTop) }; | 396 | KeyUD* const _key{ KeyUD::GetPtr(_K, kIdxTop) }; |
@@ -409,6 +429,7 @@ int keepercall_count(lua_State* const L_) | |||
409 | 429 | ||
410 | // in: linda | 430 | // in: linda |
411 | // not part of the linda public API, only used for cleanup at linda GC | 431 | // not part of the linda public API, only used for cleanup at linda GC |
432 | [[nodiscard]] | ||
412 | int keepercall_destruct(lua_State* const L_) | 433 | int keepercall_destruct(lua_State* const L_) |
413 | { | 434 | { |
414 | STACK_GROW(L_, 3); | 435 | STACK_GROW(L_, 3); |
@@ -427,6 +448,7 @@ int keepercall_destruct(lua_State* const L_) | |||
427 | 448 | ||
428 | // in: linda_ud key [count] | 449 | // in: linda_ud key [count] |
429 | // out: N <N values>|kRestrictedChannel | 450 | // out: N <N values>|kRestrictedChannel |
451 | [[nodiscard]] | ||
430 | int keepercall_get(lua_State* const L_) | 452 | int keepercall_get(lua_State* const L_) |
431 | { | 453 | { |
432 | KeeperState const _K{ L_ }; | 454 | KeeperState const _K{ L_ }; |
@@ -461,6 +483,7 @@ int keepercall_get(lua_State* const L_) | |||
461 | 483 | ||
462 | // in: linda key [n|nil] | 484 | // in: linda key [n|nil] |
463 | // out: boolean, <fill status: string> | 485 | // out: boolean, <fill status: string> |
486 | [[nodiscard]] | ||
464 | int keepercall_limit(lua_State* const L_) | 487 | int keepercall_limit(lua_State* const L_) |
465 | { | 488 | { |
466 | KeeperState const _K{ L_ }; | 489 | KeeperState const _K{ L_ }; |
@@ -480,7 +503,7 @@ int keepercall_limit(lua_State* const L_) | |||
480 | if (_key && _key->limit >= 0) { | 503 | if (_key && _key->limit >= 0) { |
481 | lua_pushinteger(_K, _key->limit); // _K: limit | 504 | lua_pushinteger(_K, _key->limit); // _K: limit |
482 | } else { // if the key doesn't exist, it is unlimited by default | 505 | } else { // if the key doesn't exist, it is unlimited by default |
483 | luaG_pushstring(_K, "unlimited"); // _K: "unlimited" | 506 | luaW_pushstring(_K, "unlimited"); // _K: "unlimited" |
484 | } | 507 | } |
485 | // return a single value: the limit of the key | 508 | // return a single value: the limit of the key |
486 | } else { | 509 | } else { |
@@ -504,6 +527,7 @@ int keepercall_limit(lua_State* const L_) | |||
504 | 527 | ||
505 | // in: linda, key [, key]? | 528 | // in: linda, key [, key]? |
506 | // out: (key, val) or nothing | 529 | // out: (key, val) or nothing |
530 | [[nodiscard]] | ||
507 | int keepercall_receive(lua_State* const L_) | 531 | int keepercall_receive(lua_State* const L_) |
508 | { | 532 | { |
509 | KeeperState const _K{ L_ }; | 533 | KeeperState const _K{ L_ }; |
@@ -548,6 +572,7 @@ int keepercall_receive(lua_State* const L_) | |||
548 | // ################################################################################################# | 572 | // ################################################################################################# |
549 | 573 | ||
550 | // in: linda key mincount [maxcount] | 574 | // in: linda key mincount [maxcount] |
575 | [[nodiscard]] | ||
551 | int keepercall_receive_batched(lua_State* const L_) | 576 | int keepercall_receive_batched(lua_State* const L_) |
552 | { | 577 | { |
553 | KeeperState const _K{ L_ }; | 578 | KeeperState const _K{ L_ }; |
@@ -581,6 +606,7 @@ int keepercall_receive_batched(lua_State* const L_) | |||
581 | 606 | ||
582 | // in: linda key [mode] | 607 | // in: linda key [mode] |
583 | // out: mode | 608 | // out: mode |
609 | [[nodiscard]] | ||
584 | int keepercall_restrict(lua_State* const L_) | 610 | int keepercall_restrict(lua_State* const L_) |
585 | { | 611 | { |
586 | KeeperState const _K{ L_ }; | 612 | KeeperState const _K{ L_ }; |
@@ -591,7 +617,7 @@ int keepercall_restrict(lua_State* const L_) | |||
591 | if (_reading) { | 617 | if (_reading) { |
592 | return LindaRestrict::None; | 618 | return LindaRestrict::None; |
593 | } | 619 | } |
594 | std::string_view const _val{ luaG_tostring(_K, StackIndex{ 3 }) }; | 620 | std::string_view const _val{ luaW_tostring(_K, StackIndex{ 3 }) }; |
595 | if (_val == "set/get") { | 621 | if (_val == "set/get") { |
596 | return LindaRestrict::SetGet; | 622 | return LindaRestrict::SetGet; |
597 | } | 623 | } |
@@ -623,7 +649,7 @@ int keepercall_restrict(lua_State* const L_) | |||
623 | lua_settop(_K, 0); // _K: | 649 | lua_settop(_K, 0); // _K: |
624 | auto const _prevRstrct{ _key ? _key->restrict : LindaRestrict::None }; | 650 | auto const _prevRstrct{ _key ? _key->restrict : LindaRestrict::None }; |
625 | // return a single value: the restrict mode of the key | 651 | // return a single value: the restrict mode of the key |
626 | luaG_pushstring(_K, _encodeRestrict(_prevRstrct)); // _K: _previous | 652 | luaW_pushstring(_K, _encodeRestrict(_prevRstrct)); // _K: _previous |
627 | } else { | 653 | } else { |
628 | if (_key == nullptr) { // _K: KeysDB key nil | 654 | if (_key == nullptr) { // _K: KeysDB key nil |
629 | lua_pop(_K, 1); // _K: KeysDB key | 655 | lua_pop(_K, 1); // _K: KeysDB key |
@@ -635,7 +661,7 @@ int keepercall_restrict(lua_State* const L_) | |||
635 | // return true if we decide that blocked threads waiting to write on that key should be awakened | 661 | // return true if we decide that blocked threads waiting to write on that key should be awakened |
636 | // this is the case if we detect the key was full but it is no longer the case | 662 | // this is the case if we detect the key was full but it is no longer the case |
637 | LindaRestrict const _previous{ _key->changeRestrict(_rstrct) }; | 663 | LindaRestrict const _previous{ _key->changeRestrict(_rstrct) }; |
638 | luaG_pushstring(_K, _encodeRestrict(_previous)); // _K: _previous | 664 | luaW_pushstring(_K, _encodeRestrict(_previous)); // _K: _previous |
639 | } | 665 | } |
640 | STACK_CHECK(_K, 1); | 666 | STACK_CHECK(_K, 1); |
641 | return 1; | 667 | return 1; |
@@ -645,6 +671,7 @@ int keepercall_restrict(lua_State* const L_) | |||
645 | 671 | ||
646 | // in: linda, key, ... | 672 | // in: linda, key, ... |
647 | // out: true|false|kRestrictedChannel | 673 | // out: true|false|kRestrictedChannel |
674 | [[nodiscard]] | ||
648 | int keepercall_send(lua_State* const L_) | 675 | int keepercall_send(lua_State* const L_) |
649 | { | 676 | { |
650 | KeeperState const _K{ L_ }; | 677 | KeeperState const _K{ L_ }; |
@@ -653,7 +680,7 @@ int keepercall_send(lua_State* const L_) | |||
653 | PushKeysDB(_K, StackIndex{ 1 }); // _K: linda key val... KeysDB | 680 | PushKeysDB(_K, StackIndex{ 1 }); // _K: linda key val... KeysDB |
654 | // get the fifo associated to this key in this linda, create it if it doesn't exist | 681 | // get the fifo associated to this key in this linda, create it if it doesn't exist |
655 | lua_pushvalue(_K, 2); // _K: linda key val... KeysDB key | 682 | lua_pushvalue(_K, 2); // _K: linda key val... KeysDB key |
656 | if (luaG_rawget(_K, StackIndex{ -2 }) == LuaType::NIL) { // _K: linda key val... KeysDB KeyUD|nil | 683 | if (luaW_rawget(_K, StackIndex{ -2 }) == LuaType::NIL) { // _K: linda key val... KeysDB KeyUD|nil |
657 | lua_pop(_K, 1); // _K: linda key val... KeysDB | 684 | lua_pop(_K, 1); // _K: linda key val... KeysDB |
658 | std::ignore = KeyUD::Create(KeeperState{ _K }); // _K: linda key val... KeysDB KeyUD | 685 | std::ignore = KeyUD::Create(KeeperState{ _K }); // _K: linda key val... KeysDB KeyUD |
659 | // KeysDB[key] = KeyUD | 686 | // KeysDB[key] = KeyUD |
@@ -684,6 +711,7 @@ int keepercall_send(lua_State* const L_) | |||
684 | 711 | ||
685 | // in: linda key [val...] | 712 | // in: linda key [val...] |
686 | // out: true if the linda was full but it's no longer the case, else false, or kRestrictedChannel if the key is restricted | 713 | // out: true if the linda was full but it's no longer the case, else false, or kRestrictedChannel if the key is restricted |
714 | [[nodiscard]] | ||
687 | int keepercall_set(lua_State* const L_) | 715 | int keepercall_set(lua_State* const L_) |
688 | { | 716 | { |
689 | KeeperState const _K{ L_ }; | 717 | KeeperState const _K{ L_ }; |
@@ -753,6 +781,7 @@ int keepercall_set(lua_State* const L_) | |||
753 | * | 781 | * |
754 | * Returns: number of return values (pushed to 'L'), unset in case of error | 782 | * Returns: number of return values (pushed to 'L'), unset in case of error |
755 | */ | 783 | */ |
784 | [[nodiscard]] | ||
756 | KeeperCallResult keeper_call(KeeperState const K_, keeper_api_t const func_, lua_State* const L_, Linda* const linda_, StackIndex const starting_index_) | 785 | KeeperCallResult keeper_call(KeeperState const K_, keeper_api_t const func_, lua_State* const L_, Linda* const linda_, StackIndex const starting_index_) |
757 | { | 786 | { |
758 | KeeperCallResult _result; | 787 | KeeperCallResult _result; |
@@ -811,22 +840,6 @@ KeeperCallResult keeper_call(KeeperState const K_, keeper_api_t const func_, lua | |||
811 | // ################################################################################################# | 840 | // ################################################################################################# |
812 | // ################################################################################################# | 841 | // ################################################################################################# |
813 | 842 | ||
814 | void* Keeper::operator new[](size_t size_, Universe* U_) noexcept | ||
815 | { | ||
816 | // size_ is the memory for the element count followed by the elements themselves | ||
817 | return U_->internalAllocator.alloc(size_); | ||
818 | } | ||
819 | |||
820 | // ################################################################################################# | ||
821 | |||
822 | // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception | ||
823 | void Keeper::operator delete[](void* p_, Universe* U_) | ||
824 | { | ||
825 | U_->internalAllocator.free(p_, *static_cast<size_t*>(p_) * sizeof(Keeper) + sizeof(size_t)); | ||
826 | } | ||
827 | |||
828 | // ################################################################################################# | ||
829 | |||
830 | // only used by linda:dump() and linda:__towatch() for debugging purposes | 843 | // only used by linda:dump() and linda:__towatch() for debugging purposes |
831 | // table is populated as follows: | 844 | // table is populated as follows: |
832 | // { | 845 | // { |
@@ -838,6 +851,7 @@ void Keeper::operator delete[](void* p_, Universe* U_) | |||
838 | // } | 851 | // } |
839 | // ... | 852 | // ... |
840 | // } | 853 | // } |
854 | [[nodiscard]] | ||
841 | int Keeper::PushLindaStorage(Linda& linda_, DestState const L_) | 855 | int Keeper::PushLindaStorage(Linda& linda_, DestState const L_) |
842 | { | 856 | { |
843 | Keeper* const _keeper{ linda_.whichKeeper() }; | 857 | Keeper* const _keeper{ linda_.whichKeeper() }; |
@@ -849,7 +863,7 @@ int Keeper::PushLindaStorage(Linda& linda_, DestState const L_) | |||
849 | STACK_CHECK_START_REL(_K, 0); | 863 | STACK_CHECK_START_REL(_K, 0); |
850 | kLindasRegKey.pushValue(_K); // _K: LindasDB L_: | 864 | kLindasRegKey.pushValue(_K); // _K: LindasDB L_: |
851 | lua_pushlightuserdata(_K, &linda_); // _K: LindasDB linda L_: | 865 | lua_pushlightuserdata(_K, &linda_); // _K: LindasDB linda L_: |
852 | LuaType const _type{ luaG_rawget(_K, StackIndex{ -2 }) }; // _K: LindasDB KeysDB L_: | 866 | LuaType const _type{ luaW_rawget(_K, StackIndex{ -2 }) }; // _K: LindasDB KeysDB L_: |
853 | lua_remove(_K, -2); // _K: KeysDB L_: | 867 | lua_remove(_K, -2); // _K: KeysDB L_: |
854 | if (_type != LuaType::TABLE) { // possible if we didn't send anything through that linda | 868 | if (_type != LuaType::TABLE) { // possible if we didn't send anything through that linda |
855 | lua_pop(_K, 1); // _K: L_: | 869 | lua_pop(_K, 1); // _K: L_: |
@@ -886,20 +900,20 @@ int Keeper::PushLindaStorage(Linda& linda_, DestState const L_) | |||
886 | if (_key->limit >= 0) { | 900 | if (_key->limit >= 0) { |
887 | lua_pushinteger(L_, _key->limit); // _K: KeysDB key L_: out key keyout fifo limit | 901 | lua_pushinteger(L_, _key->limit); // _K: KeysDB key L_: out key keyout fifo limit |
888 | } else { | 902 | } else { |
889 | luaG_pushstring(L_, "unlimited"); // _K: KeysDB key L_: out key keyout fifo limit | 903 | luaW_pushstring(L_, "unlimited"); // _K: KeysDB key L_: out key keyout fifo limit |
890 | } | 904 | } |
891 | STACK_CHECK(L_, 5); | 905 | STACK_CHECK(L_, 5); |
892 | lua_setfield(L_, -3, "limit"); // _K: KeysDB key L_: out key keyout fifo | 906 | lua_setfield(L_, -3, "limit"); // _K: KeysDB key L_: out key keyout fifo |
893 | // keyout.restrict | 907 | // keyout.restrict |
894 | switch (_key->restrict) { | 908 | switch (_key->restrict) { |
895 | case LindaRestrict::None: | 909 | case LindaRestrict::None: |
896 | luaG_pushstring(L_, "none"); // _K: KeysDB key L_: out key keyout fifo restrict | 910 | luaW_pushstring(L_, "none"); // _K: KeysDB key L_: out key keyout fifo restrict |
897 | break; | 911 | break; |
898 | case LindaRestrict::SetGet: | 912 | case LindaRestrict::SetGet: |
899 | luaG_pushstring(L_, "set/get"); // _K: KeysDB key L_: out key keyout fifo restrict | 913 | luaW_pushstring(L_, "set/get"); // _K: KeysDB key L_: out key keyout fifo restrict |
900 | break; | 914 | break; |
901 | case LindaRestrict::SendReceive: | 915 | case LindaRestrict::SendReceive: |
902 | luaG_pushstring(L_, "send/receive"); // _K: KeysDB key L_: out key keyout fifo restrict | 916 | luaW_pushstring(L_, "send/receive"); // _K: KeysDB key L_: out key keyout fifo restrict |
903 | break; | 917 | break; |
904 | } | 918 | } |
905 | STACK_CHECK(L_, 5); | 919 | STACK_CHECK(L_, 5); |
@@ -927,7 +941,7 @@ void Keepers::DeleteKV::operator()(Keeper* const k_) const | |||
927 | for (auto& _k : std::span<Keeper>(k_, count)) { | 941 | for (auto& _k : std::span<Keeper>(k_, count)) { |
928 | _k.~Keeper(); | 942 | _k.~Keeper(); |
929 | } | 943 | } |
930 | U->internalAllocator.free(k_, count * sizeof(Keeper)); | 944 | U.internalAllocator.free(k_, count * sizeof(Keeper)); |
931 | } | 945 | } |
932 | 946 | ||
933 | // ################################################################################################# | 947 | // ################################################################################################# |
@@ -959,24 +973,24 @@ void Keepers::collectGarbage() | |||
959 | // when keeper N+1 is closed, object is GCed, linda operation is called, which attempts to acquire keeper N, whose Lua state no longer exists | 973 | // when keeper N+1 is closed, object is GCed, linda operation is called, which attempts to acquire keeper N, whose Lua state no longer exists |
960 | // in that case, the linda operation should do nothing. which means that these operations must check for keeper acquisition success | 974 | // in that case, the linda operation should do nothing. which means that these operations must check for keeper acquisition success |
961 | // which is early-outed with a keepers->nbKeepers null-check | 975 | // which is early-outed with a keepers->nbKeepers null-check |
962 | for (size_t const _i : std::ranges::iota_view{ size_t{ 0 }, _kv.nbKeepers }) { | 976 | for (Keeper& _k : std::span<Keeper>{ _kv.keepers.get(), _kv.nbKeepers }) { |
963 | _gcOneKeeper(_kv.keepers[_i]); | 977 | _gcOneKeeper(_k); |
964 | } | 978 | } |
965 | } | 979 | } |
966 | } | 980 | } |
967 | 981 | ||
968 | // ################################################################################################# | 982 | // ################################################################################################# |
969 | 983 | ||
970 | 984 | [[nodiscard]] | |
971 | void Keepers::close() | 985 | bool Keepers::close() |
972 | { | 986 | { |
973 | if (isClosing.test_and_set(std::memory_order_release)) { | 987 | if (isClosing.test_and_set(std::memory_order_release)) { |
974 | assert(false); // should never close more than once in practice | 988 | return false; // should never close more than once in practice |
975 | return; | ||
976 | } | 989 | } |
977 | 990 | ||
991 | // We may have not initialized the keepers if an error was raised in Universe::Create because of bad settings | ||
978 | if (std::holds_alternative<std::monostate>(keeper_array)) { | 992 | if (std::holds_alternative<std::monostate>(keeper_array)) { |
979 | return; | 993 | return true; |
980 | } | 994 | } |
981 | 995 | ||
982 | auto _closeOneKeeper = [](Keeper& keeper_) { | 996 | auto _closeOneKeeper = [](Keeper& keeper_) { |
@@ -996,9 +1010,8 @@ void Keepers::close() | |||
996 | // when keeper N+1 is closed, object is GCed, linda operation is called, which attempts to acquire keeper N, whose Lua state no longer exists | 1010 | // when keeper N+1 is closed, object is GCed, linda operation is called, which attempts to acquire keeper N, whose Lua state no longer exists |
997 | // in that case, the linda operation should do nothing. which means that these operations must check for keeper acquisition success | 1011 | // in that case, the linda operation should do nothing. which means that these operations must check for keeper acquisition success |
998 | // which is early-outed with a keepers->nbKeepers null-check | 1012 | // which is early-outed with a keepers->nbKeepers null-check |
999 | size_t const _nbKeepers{ std::exchange(_kv.nbKeepers, size_t{ 0 }) }; | 1013 | for (Keeper& _k : std::span<Keeper>{ _kv.keepers.get(), std::exchange(_kv.nbKeepers, size_t{ 0 }) }) { |
1000 | for (size_t const _i : std::ranges::iota_view{ size_t{ 0 }, _nbKeepers }) { | 1014 | if (!_closeOneKeeper(_k)) { |
1001 | if (!_closeOneKeeper(_kv.keepers[_i])) { | ||
1002 | // detected partial init: destroy only the mutexes that got initialized properly | 1015 | // detected partial init: destroy only the mutexes that got initialized properly |
1003 | break; | 1016 | break; |
1004 | } | 1017 | } |
@@ -1006,6 +1019,7 @@ void Keepers::close() | |||
1006 | } | 1019 | } |
1007 | 1020 | ||
1008 | keeper_array.emplace<std::monostate>(); | 1021 | keeper_array.emplace<std::monostate>(); |
1022 | return true; | ||
1009 | } | 1023 | } |
1010 | 1024 | ||
1011 | // ################################################################################################# | 1025 | // ################################################################################################# |
@@ -1076,7 +1090,7 @@ void Keepers::initialize(Universe& U_, lua_State* L_, size_t const nbKeepers_, i | |||
1076 | keeper_.K = _K; | 1090 | keeper_.K = _K; |
1077 | 1091 | ||
1078 | // Give a name to the state | 1092 | // Give a name to the state |
1079 | luaG_pushstring(_K, "Keeper #%d", i_ + 1); // L_: settings _K: "Keeper #n" | 1093 | luaW_pushstring(_K, "Keeper #%d", i_ + 1); // L_: settings _K: "Keeper #n" |
1080 | if constexpr (HAVE_DECODA_SUPPORT()) { | 1094 | if constexpr (HAVE_DECODA_SUPPORT()) { |
1081 | lua_pushvalue(_K, -1); // _K: "Keeper #n" Keeper #n" | 1095 | lua_pushvalue(_K, -1); // _K: "Keeper #n" Keeper #n" |
1082 | lua_setglobal(_K, "decoda_name"); // L_: settings _K: "Keeper #n" | 1096 | lua_setglobal(_K, "decoda_name"); // L_: settings _K: "Keeper #n" |
@@ -1098,9 +1112,9 @@ void Keepers::initialize(Universe& U_, lua_State* L_, size_t const nbKeepers_, i | |||
1098 | STACK_CHECK(_K, 0); | 1112 | STACK_CHECK(_K, 0); |
1099 | 1113 | ||
1100 | // copy package.path and package.cpath from the source state | 1114 | // copy package.path and package.cpath from the source state |
1101 | if (luaG_getmodule(L, LUA_LOADLIBNAME) != LuaType::NIL) { // L_: settings package _K: | 1115 | if (luaW_getmodule(L, LUA_LOADLIBNAME) != LuaType::NIL) { // L_: settings package _K: |
1102 | // when copying with mode LookupMode::ToKeeper, error message is pushed at the top of the stack, not raised immediately | 1116 | // when copying with mode LookupMode::ToKeeper, error message is pushed at the top of the stack, not raised immediately |
1103 | InterCopyContext _c{ U, DestState{ _K.value() }, SourceState{ L }, {}, SourceIndex{ luaG_absindex(L, kIdxTop).value() }, {}, LookupMode::ToKeeper, {} }; | 1117 | InterCopyContext _c{ U, DestState{ _K.value() }, SourceState{ L }, {}, SourceIndex{ luaW_absindex(L, kIdxTop).value() }, {}, LookupMode::ToKeeper, {} }; |
1104 | if (_c.interCopyPackage() != InterCopyResult::Success) { // L_: settings ... error_msg _K: | 1118 | if (_c.interCopyPackage() != InterCopyResult::Success) { // L_: settings ... error_msg _K: |
1105 | // if something went wrong, the error message is at the top of the stack | 1119 | // if something went wrong, the error message is at the top of the stack |
1106 | lua_remove(L, -2); // L_: settings error_msg | 1120 | lua_remove(L, -2); // L_: settings error_msg |
@@ -1137,11 +1151,14 @@ void Keepers::initialize(Universe& U_, lua_State* L_, size_t const nbKeepers_, i | |||
1137 | 1151 | ||
1138 | default: | 1152 | default: |
1139 | KV& _kv = keeper_array.emplace<KV>( | 1153 | KV& _kv = keeper_array.emplace<KV>( |
1140 | std::unique_ptr<Keeper[], DeleteKV>{ new(&U_) Keeper[nbKeepers_], DeleteKV{ &U_, nbKeepers_ } }, | 1154 | std::unique_ptr<Keeper, DeleteKV>{ static_cast<Keeper*>(U_.internalAllocator.alloc(sizeof(Keeper) * nbKeepers_)), DeleteKV{ U_, nbKeepers_ } }, |
1141 | nbKeepers_ | 1155 | nbKeepers_ |
1142 | ); | 1156 | ); |
1143 | for (size_t const _i : std::ranges::iota_view{ size_t{ 0 }, nbKeepers_ }) { | 1157 | // fak. std::ranges::views::enumerate is c++23 (would help having item and index iterated over simultaneously) |
1144 | _initOneKeeper(_kv.keepers[_i], static_cast<int>(_i)); | 1158 | int _i{}; |
1159 | for (Keeper& _k : std::span<Keeper>{ _kv.keepers.get(), nbKeepers_ }) { | ||
1160 | new (&_k) Keeper{}; | ||
1161 | _initOneKeeper(_k, _i++); | ||
1145 | } | 1162 | } |
1146 | } | 1163 | } |
1147 | } | 1164 | } |