aboutsummaryrefslogtreecommitdiff
path: root/src/keeper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/keeper.cpp')
-rw-r--r--src/keeper.cpp149
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]]
107bool KeyUD::changeLimit(LindaLimit const limit_) 108bool 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]]
130KeyUD* KeyUD::Create(KeeperState const K_) 132KeyUD* 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]]
144KeyUD* KeyUD::GetPtr(KeeperState const K_, StackIndex const idx_) 147KeyUD* 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]]
184int KeyUD::pop(KeeperState const K_, int const minCount_, int const maxCount_) 188int 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)
223void KeyUD::prepareAccess(KeeperState const K_, StackIndex const idx_) const 237void 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]]
236bool KeyUD::push(KeeperState const K_, int const count_, bool const enforceLimit_) 251bool 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
259void KeyUD::pushFillStatus(KeeperState const K_) const 274void 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]]
289bool KeyUD::reset(KeeperState const K_) 307bool 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]]
340int keepercall_collectgarbage(lua_State* const L_) 359int 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]]
349int keepercall_count(lua_State* const L_) 369int 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]]
412int keepercall_destruct(lua_State* const L_) 433int 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]]
430int keepercall_get(lua_State* const L_) 452int 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]]
464int keepercall_limit(lua_State* const L_) 487int 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]]
507int keepercall_receive(lua_State* const L_) 531int 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]]
551int keepercall_receive_batched(lua_State* const L_) 576int 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]]
584int keepercall_restrict(lua_State* const L_) 610int 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]]
648int keepercall_send(lua_State* const L_) 675int 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]]
687int keepercall_set(lua_State* const L_) 715int 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]]
756KeeperCallResult keeper_call(KeeperState const K_, keeper_api_t const func_, lua_State* const L_, Linda* const linda_, StackIndex const starting_index_) 785KeeperCallResult 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
814void* 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
823void 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]]
841int Keeper::PushLindaStorage(Linda& linda_, DestState const L_) 855int 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]]
971void Keepers::close() 985bool 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}