diff options
author | Benoit Germain <benoit.germain@ubisoft.com> | 2024-12-03 10:26:47 +0100 |
---|---|---|
committer | Benoit Germain <benoit.germain@ubisoft.com> | 2024-12-03 10:26:47 +0100 |
commit | 307fd830eb168005a3ba3d557343284814757eff (patch) | |
tree | eb14512492d58e33585bc5df3f3d9b23d7308934 /src/keeper.cpp | |
parent | ca7657e24549acb8a2dd45fa81c309b5bf9f61ee (diff) | |
download | lanes-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.cpp | 145 |
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]] | ||
121 | LindaRestrict 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} |
119 | KeyUD* KeyUD::Create(KeeperState const K_) | 130 | KeyUD* 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 |
412 | int keepercall_get(lua_State* const L_) | 423 | int 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 | ||
577 | int 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 |
543 | int keepercall_send(lua_State* const L_) | 641 | int 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 |
579 | int keepercall_set(lua_State* const L_) | 681 | int 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 |