aboutsummaryrefslogtreecommitdiff
path: root/src/keeper.cpp
diff options
context:
space:
mode:
authorBenoit Germain <benoit.germain@ubisoft.com>2024-12-03 10:26:47 +0100
committerBenoit Germain <benoit.germain@ubisoft.com>2024-12-03 10:26:47 +0100
commit307fd830eb168005a3ba3d557343284814757eff (patch)
treeeb14512492d58e33585bc5df3f3d9b23d7308934 /src/keeper.cpp
parentca7657e24549acb8a2dd45fa81c309b5bf9f61ee (diff)
downloadlanes-307fd830eb168005a3ba3d557343284814757eff.tar.gz
lanes-307fd830eb168005a3ba3d557343284814757eff.tar.bz2
lanes-307fd830eb168005a3ba3d557343284814757eff.zip
New method linda:restrict()
Diffstat (limited to 'src/keeper.cpp')
-rw-r--r--src/keeper.cpp145
1 files changed, 133 insertions, 12 deletions
diff --git a/src/keeper.cpp b/src/keeper.cpp
index 8a99a36..e7b02e6 100644
--- a/src/keeper.cpp
+++ b/src/keeper.cpp
@@ -73,6 +73,7 @@ class KeyUD
73 int first{ 1 }; 73 int first{ 1 };
74 int count{ 0 }; 74 int count{ 0 };
75 LindaLimit limit{ -1 }; 75 LindaLimit limit{ -1 };
76 LindaRestrict restrict { LindaRestrict::None };
76 77
77 // 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
78 [[nodiscard]] 79 [[nodiscard]]
@@ -84,6 +85,8 @@ class KeyUD
84 [[nodiscard]] 85 [[nodiscard]]
85 bool changeLimit(LindaLimit limit_); 86 bool changeLimit(LindaLimit limit_);
86 [[nodiscard]] 87 [[nodiscard]]
88 LindaRestrict changeRestrict(LindaRestrict restrict_);
89 [[nodiscard]]
87 static KeyUD* Create(KeeperState K_); 90 static KeyUD* Create(KeeperState K_);
88 [[nodiscard]] 91 [[nodiscard]]
89 static KeyUD* GetPtr(KeeperState K_, StackIndex idx_); 92 static KeyUD* GetPtr(KeeperState K_, StackIndex idx_);
@@ -114,6 +117,14 @@ bool KeyUD::changeLimit(LindaLimit const limit_)
114 117
115// ################################################################################################# 118// #################################################################################################
116 119
120[[nodiscard]]
121LindaRestrict KeyUD::changeRestrict(LindaRestrict const restrict_)
122{
123 return std::exchange(restrict, restrict_);
124}
125
126// #################################################################################################
127
117// in: nothing 128// in: nothing
118// out: { first = 1, count = 0, limit = -1} 129// out: { first = 1, count = 0, limit = -1}
119KeyUD* KeyUD::Create(KeeperState const K_) 130KeyUD* KeyUD::Create(KeeperState const K_)
@@ -280,7 +291,7 @@ bool KeyUD::reset(KeeperState const K_)
280 LUA_ASSERT(K_, KeyUD::GetPtr(K_, kIdxTop) == this); 291 LUA_ASSERT(K_, KeyUD::GetPtr(K_, kIdxTop) == this);
281 STACK_CHECK_START_REL(K_, 0); 292 STACK_CHECK_START_REL(K_, 0);
282 bool const _wasFull{ (limit > 0) && (count >= limit) }; 293 bool const _wasFull{ (limit > 0) && (count >= limit) };
283 // empty the KeyUD: replace uservalue with a virgin table, reset counters, but leave limit unchanged! 294 // empty the KeyUD: replace uservalue with a virgin table, reset counters, but leave limit and restrict unchanged!
284 // if we have an actual limit, use it to preconfigure the table 295 // if we have an actual limit, use it to preconfigure the table
285 lua_createtable(K_, (limit <= 0) ? 0 : limit.value(), 0); // K_: KeysDB key val... KeyUD {} 296 lua_createtable(K_, (limit <= 0) ? 0 : limit.value(), 0); // K_: KeysDB key val... KeyUD {}
286 lua_setiuservalue(K_, StackIndex{ -2 }, kContentsTableIndex); // K_: KeysDB key val... KeyUD 297 lua_setiuservalue(K_, StackIndex{ -2 }, kContentsTableIndex); // K_: KeysDB key val... KeyUD
@@ -408,7 +419,7 @@ int keepercall_destruct(lua_State* const L_)
408// ################################################################################################# 419// #################################################################################################
409 420
410// in: linda_ud key [count] 421// in: linda_ud key [count]
411// out: bool + at most <count> values 422// out: N <N values>|kRestrictedChannel
412int keepercall_get(lua_State* const L_) 423int keepercall_get(lua_State* const L_)
413{ 424{
414 KeeperState const _K{ L_ }; 425 KeeperState const _K{ L_ };
@@ -423,7 +434,13 @@ int keepercall_get(lua_State* const L_)
423 lua_remove(_K, 1); // _K: KeyUD 434 lua_remove(_K, 1); // _K: KeyUD
424 KeyUD const* const _key{ KeyUD::GetPtr(_K, kIdxTop) }; 435 KeyUD const* const _key{ KeyUD::GetPtr(_K, kIdxTop) };
425 if (_key != nullptr) { 436 if (_key != nullptr) {
426 _key->peek(_K, _count); // _K: N val... 437 if (_key->restrict == LindaRestrict::SendReceive) { // can we use set/get?
438 lua_settop(_K, 0); // _K:
439 kRestrictedChannel.pushKey(_K); // _K: kRestrictedChannel
440 return 1;
441 } else {
442 _key->peek(_K, _count); // _K: N val...
443 }
427 } else { 444 } else {
428 // no fifo was ever registered for this key, or it is empty 445 // no fifo was ever registered for this key, or it is empty
429 lua_pop(_K, 1); // _K: 446 lua_pop(_K, 1); // _K:
@@ -492,6 +509,17 @@ int keepercall_receive(lua_State* const L_)
492 lua_rawget(_K, 1); // _K: KeysDB keys... KeyUD 509 lua_rawget(_K, 1); // _K: KeysDB keys... KeyUD
493 KeyUD* const _key{ KeyUD::GetPtr(_K, kIdxTop) }; 510 KeyUD* const _key{ KeyUD::GetPtr(_K, kIdxTop) };
494 if (_key != nullptr) { // it's fine to attempt a read on a key that wasn't yet written to 511 if (_key != nullptr) { // it's fine to attempt a read on a key that wasn't yet written to
512 if (_key->restrict == LindaRestrict::SetGet) { // can we use send/receive?
513 kRestrictedChannel.pushKey(_K); // _K: KeysDB keys... key[i] kRestrictedChannel
514 lua_replace(_K, 1); // _K: kRestrictedChannel keys... key[i]
515 lua_settop(_K, _keyIdx); // _K: kRestrictedChannel keys... key[i]
516 if (_keyIdx != 2) {
517 lua_replace(_K, 2); // _K: kRestrictedChannel key[i] keys...
518 lua_settop(_K, 2); // _K: kRestrictedChannel key[i]
519 }
520 lua_insert(_K, 1); // _K: key kRestrictedChannel
521 return 2;
522 }
495 int const _popped{ _key->pop(_K, 1, 1) }; // _K: KeysDB keys... val 523 int const _popped{ _key->pop(_K, 1, 1) }; // _K: KeysDB keys... val
496 if (_popped > 0) { 524 if (_popped > 0) {
497 lua_replace(_K, 1); // _K: val keys... 525 lua_replace(_K, 1); // _K: val keys...
@@ -527,19 +555,89 @@ int keepercall_receive_batched(lua_State* const L_)
527 lua_rawget(_K, 2); // _K: key KeysDB KeyUD 555 lua_rawget(_K, 2); // _K: key KeysDB KeyUD
528 lua_remove(_K, 2); // _K: key KeyUD 556 lua_remove(_K, 2); // _K: key KeyUD
529 KeyUD* const _key{ KeyUD::GetPtr(_K, kIdxTop) }; 557 KeyUD* const _key{ KeyUD::GetPtr(_K, kIdxTop) };
530 if (_key == nullptr || _key->pop(_K, _min_count, _max_count) == 0) { // _K: [key val...]|crap 558 if (!_key) {
531 // Lua will adjust the stack for us when we return 559 return 0; // Lua will adjust the stack for us when we return
532 return 0; 560 }
561 if (_key->restrict == LindaRestrict::SetGet) { // can we use send/receive?
562 lua_settop(_K, 1); // _K: key
563 kRestrictedChannel.pushKey(_K); // _K: key kRestrictedChannel
564 return 2;
565 }
566 if (_key->pop(_K, _min_count, _max_count) == 0) { // _K: [key val...]|crap
567 return 0; // Lua will adjust the stack for us when we return
568 }
569 // return whatever remains on the stack at that point: the key and the values we pulled from the fifo
570 return lua_gettop(_K);
571}
572
573// #################################################################################################
574
575// in: linda key [mode]
576// out: mode
577int keepercall_restrict(lua_State* const L_)
578{
579 KeeperState const _K{ L_ };
580 STACK_CHECK_START_ABS(_K, lua_gettop(_K));
581 // no restriction to set, means we read and return the current restriction instead
582 bool const _reading{ lua_gettop(_K) == 2 };
583 auto _decodeRestrict = [_K, _reading]() {
584 if (_reading) {
585 return LindaRestrict::None;
586 }
587 std::string_view const _val{ luaG_tostring(_K, StackIndex{ 3 }) };
588 if (_val == "set/get") {
589 return LindaRestrict::SetGet;
590 }
591 if (_val == "send/receive") {
592 return LindaRestrict::SendReceive;
593 }
594 return LindaRestrict::None;
595 };
596 auto _encodeRestrict = [](LindaRestrict const val_) {
597 switch (val_) {
598 default:
599 case LindaRestrict::None:
600 return std::string_view{ "none" };
601 case LindaRestrict::SetGet:
602 return std::string_view{ "set/get" };
603 case LindaRestrict::SendReceive:
604 return std::string_view{ "send/receive" };
605 }
606 };
607 LindaRestrict const _rstrct{ _decodeRestrict() }; // if we read nil because the argument is absent
608 lua_settop(_K, 2); // _K: linda key
609 PushKeysDB(_K, StackIndex{ 1 }); // _K: linda key KeysDB
610 lua_replace(_K, 1); // _K: KeysDB key
611 lua_pushvalue(_K, -1); // _K: KeysDB key key
612 lua_rawget(_K, -3); // _K: KeysDB key KeyUD|nil
613 KeyUD* _key{ KeyUD::GetPtr(_K, kIdxTop) };
614 if (_reading) {
615 // remove any clutter on the stack
616 lua_settop(_K, 0); // _K:
617 auto const _prevRstrct{ _key ? _key->restrict : LindaRestrict::None };
618 // return a single value: the restrict mode of the key
619 luaG_pushstring(_K, _encodeRestrict(_prevRstrct)); // _K: _previous
533 } else { 620 } else {
534 // return whatever remains on the stack at that point: the key and the values we pulled from the fifo 621 if (_key == nullptr) { // _K: KeysDB key nil
535 return lua_gettop(_K); 622 lua_pop(_K, 1); // _K: KeysDB key
623 _key = KeyUD::Create(_K); // _K: KeysDB key KeyUD
624 lua_rawset(_K, -3); // _K: KeysDB
625 }
626 // remove any clutter on the stack
627 lua_settop(_K, 0); // _K:
628 // return true if we decide that blocked threads waiting to write on that key should be awakened
629 // this is the case if we detect the key was full but it is no longer the case
630 LindaRestrict const _previous{ _key->changeRestrict(_rstrct) };
631 luaG_pushstring(_K, _encodeRestrict(_previous)); // _K: _previous
536 } 632 }
633 STACK_CHECK(_K, 1);
634 return 1;
537} 635}
538 636
539// ################################################################################################# 637// #################################################################################################
540 638
541// in: linda, key, ... 639// in: linda, key, ...
542// out: true|false 640// out: true|false|kRestrictedChannel
543int keepercall_send(lua_State* const L_) 641int keepercall_send(lua_State* const L_)
544{ 642{
545 KeeperState const _K{ L_ }; 643 KeeperState const _K{ L_ };
@@ -561,7 +659,11 @@ int keepercall_send(lua_State* const L_)
561 lua_pop(_K, 1); // _K: linda KeyUD val... 659 lua_pop(_K, 1); // _K: linda KeyUD val...
562 STACK_CHECK(_K, 0); 660 STACK_CHECK(_K, 0);
563 KeyUD* const _key{ KeyUD::GetPtr(_K, StackIndex{ 2 }) }; 661 KeyUD* const _key{ KeyUD::GetPtr(_K, StackIndex{ 2 }) };
564 if (_key && _key->push(_K, _n, true)) { // not enough room? 662 if (_key->restrict == LindaRestrict::SetGet) { // can we use send/receive?
663 lua_settop(_K, 0); // _K:
664 kRestrictedChannel.pushKey(_K); // _K: kRestrictedChannel
665 }
666 else if (_key->push(_K, _n, true)) { // not enough room?
565 lua_settop(_K, 0); // _K: 667 lua_settop(_K, 0); // _K:
566 lua_pushboolean(_K, 1); // _K: true 668 lua_pushboolean(_K, 1); // _K: true
567 } else { 669 } else {
@@ -575,7 +677,7 @@ int keepercall_send(lua_State* const L_)
575// ################################################################################################# 677// #################################################################################################
576 678
577// in: linda key [val...] 679// in: linda key [val...]
578// out: true if the linda was full but it's no longer the case, else false 680// out: true if the linda was full but it's no longer the case, else false, or kRestrictedChannel if the key is restricted
579int keepercall_set(lua_State* const L_) 681int keepercall_set(lua_State* const L_)
580{ 682{
581 KeeperState const _K{ L_ }; 683 KeeperState const _K{ L_ };
@@ -588,11 +690,16 @@ int keepercall_set(lua_State* const L_)
588 lua_pushvalue(_K, 2); // _K: KeysDB key val... key 690 lua_pushvalue(_K, 2); // _K: KeysDB key val... key
589 lua_rawget(_K, 1); // _K: KeysDB key val KeyUD|nil 691 lua_rawget(_K, 1); // _K: KeysDB key val KeyUD|nil
590 KeyUD* _key{ KeyUD::GetPtr(_K, kIdxTop) }; 692 KeyUD* _key{ KeyUD::GetPtr(_K, kIdxTop) };
693 if (_key && _key->restrict == LindaRestrict::SendReceive) { // can we use send/receive?
694 lua_settop(_K, 0); // _K:
695 kRestrictedChannel.pushKey(_K); // _K: kRestrictedChannel
696 return 1;
697 }
591 698
592 if (lua_gettop(_K) == 3) { // no value to set // _K: KeysDB key KeyUD|nil 699 if (lua_gettop(_K) == 3) { // no value to set // _K: KeysDB key KeyUD|nil
593 // empty the KeyUD for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! 700 // empty the KeyUD for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged!
594 if (_key != nullptr) { // might be nullptr if we set a nonexistent key to nil // _K: KeysDB key KeyUD 701 if (_key != nullptr) { // might be nullptr if we set a nonexistent key to nil // _K: KeysDB key KeyUD
595 if (_key->limit < 0) { // KeyUD limit value is the default (unlimited): we can totally remove it 702 if (_key->limit < 0 && _key->restrict == LindaRestrict::None) { // KeyUD limit value and restrict mode are the default (unlimited/none): we can totally remove it
596 lua_pop(_K, 1); // _K: KeysDB key 703 lua_pop(_K, 1); // _K: KeysDB key
597 lua_pushnil(_K); // _K: KeysDB key nil 704 lua_pushnil(_K); // _K: KeysDB key nil
598 lua_rawset(_K, -3); // _K: KeysDB 705 lua_rawset(_K, -3); // _K: KeysDB
@@ -777,6 +884,20 @@ int Keeper::PushLindaStorage(Linda& linda_, DestState const L_)
777 } 884 }
778 STACK_CHECK(L_, 5); 885 STACK_CHECK(L_, 5);
779 lua_setfield(L_, -3, "limit"); // _K: KeysDB key L_: out key keyout fifo 886 lua_setfield(L_, -3, "limit"); // _K: KeysDB key L_: out key keyout fifo
887 // keyout.restrict
888 switch (_key->restrict) {
889 case LindaRestrict::None:
890 luaG_pushstring(L_, "none"); // _K: KeysDB key L_: out key keyout fifo restrict
891 break;
892 case LindaRestrict::SetGet:
893 luaG_pushstring(L_, "set/get"); // _K: KeysDB key L_: out key keyout fifo restrict
894 break;
895 case LindaRestrict::SendReceive:
896 luaG_pushstring(L_, "send/receive"); // _K: KeysDB key L_: out key keyout fifo restrict
897 break;
898 }
899 STACK_CHECK(L_, 5);
900 lua_setfield(L_, -3, "restrict"); // _K: KeysDB key L_: out key keyout fifo
780 // keyout.fifo 901 // keyout.fifo
781 lua_setfield(L_, -2, "fifo"); // _K: KeysDB key L_: out key keyout 902 lua_setfield(L_, -2, "fifo"); // _K: KeysDB key L_: out key keyout
782 // out[key] = keyout 903 // out[key] = keyout