diff options
Diffstat (limited to 'src/keeper.cpp')
-rw-r--r-- | src/keeper.cpp | 75 |
1 files changed, 58 insertions, 17 deletions
diff --git a/src/keeper.cpp b/src/keeper.cpp index ae09b37..cfeebbb 100644 --- a/src/keeper.cpp +++ b/src/keeper.cpp | |||
@@ -66,6 +66,10 @@ class KeyUD | |||
66 | static constexpr int kContentsTableIndex{ 1 }; | 66 | static constexpr int kContentsTableIndex{ 1 }; |
67 | 67 | ||
68 | public: | 68 | public: |
69 | static constexpr std::string_view kUnder{ "under" }; | ||
70 | static constexpr std::string_view kExact{ "exact" }; | ||
71 | static constexpr std::string_view kOver{ "over" }; | ||
72 | |||
69 | int first{ 1 }; | 73 | int first{ 1 }; |
70 | int count{ 0 }; | 74 | int count{ 0 }; |
71 | LindaLimit limit{ -1 }; | 75 | LindaLimit limit{ -1 }; |
@@ -83,6 +87,8 @@ class KeyUD | |||
83 | [[nodiscard]] int pop(KeeperState K_, int minCount_, int maxCount_); // keepercall_receive[_batched] | 87 | [[nodiscard]] int pop(KeeperState K_, int minCount_, int maxCount_); // keepercall_receive[_batched] |
84 | void prepareAccess(KeeperState K_, int idx_) const; | 88 | void prepareAccess(KeeperState K_, int idx_) const; |
85 | [[nodiscard]] bool push(KeeperState K_, int count_, bool enforceLimit_); // keepercall_send and keepercall_set | 89 | [[nodiscard]] bool push(KeeperState K_, int count_, bool enforceLimit_); // keepercall_send and keepercall_set |
90 | void pushFillStatus(KeeperState K_) const; | ||
91 | static void PushFillStatus(KeeperState K_, KeyUD const* key_); | ||
86 | [[nodiscard]] bool reset(KeeperState K_); | 92 | [[nodiscard]] bool reset(KeeperState K_); |
87 | }; | 93 | }; |
88 | 94 | ||
@@ -232,6 +238,35 @@ bool KeyUD::push(KeeperState const K_, int const count_, bool const enforceLimit | |||
232 | 238 | ||
233 | // ################################################################################################# | 239 | // ################################################################################################# |
234 | 240 | ||
241 | void KeyUD::pushFillStatus(KeeperState const K_) const | ||
242 | { | ||
243 | if (limit < 0) { | ||
244 | luaG_pushstring(K_, kUnder); | ||
245 | return; | ||
246 | } | ||
247 | int const _delta{limit - count}; | ||
248 | if (_delta < 0) { | ||
249 | luaG_pushstring(K_, kOver); | ||
250 | } else if (_delta > 0) { | ||
251 | luaG_pushstring(K_, kUnder); | ||
252 | } else { | ||
253 | luaG_pushstring(K_, kExact); | ||
254 | } | ||
255 | } | ||
256 | |||
257 | // ################################################################################################# | ||
258 | |||
259 | void KeyUD::PushFillStatus(KeeperState const K_, KeyUD const* const key_) | ||
260 | { | ||
261 | if (key_) { | ||
262 | key_->pushFillStatus(K_); // _K: ... <fill status> | ||
263 | } else { | ||
264 | luaG_pushstring(K_, KeyUD::kUnder); // _K: ... "under" | ||
265 | } | ||
266 | } | ||
267 | |||
268 | // ################################################################################################# | ||
269 | |||
235 | // expects 'this' on top of the stack | 270 | // expects 'this' on top of the stack |
236 | bool KeyUD::reset(KeeperState const K_) | 271 | bool KeyUD::reset(KeeperState const K_) |
237 | { | 272 | { |
@@ -394,10 +429,11 @@ int keepercall_get(lua_State* const L_) | |||
394 | // ################################################################################################# | 429 | // ################################################################################################# |
395 | 430 | ||
396 | // in: linda key [n|nil] | 431 | // in: linda key [n|nil] |
397 | // out: true or nil | 432 | // out: boolean, <fill status: string> |
398 | int keepercall_limit(lua_State* const L_) | 433 | int keepercall_limit(lua_State* const L_) |
399 | { | 434 | { |
400 | KeeperState const _K{ L_ }; | 435 | KeeperState const _K{ L_ }; |
436 | STACK_CHECK_START_ABS(_K, lua_gettop(_K)); | ||
401 | // no limit to set, means we read and return the current limit instead | 437 | // no limit to set, means we read and return the current limit instead |
402 | bool const _reading{ lua_gettop(_K) == 2 }; | 438 | bool const _reading{ lua_gettop(_K) == 2 }; |
403 | LindaLimit const _limit{ static_cast<LindaLimit::type>(luaL_optinteger(_K, 3, -1)) }; // -1 if we read nil because the argument is absent | 439 | LindaLimit const _limit{ static_cast<LindaLimit::type>(luaL_optinteger(_K, 3, -1)) }; // -1 if we read nil because the argument is absent |
@@ -408,10 +444,12 @@ int keepercall_limit(lua_State* const L_) | |||
408 | lua_rawget(_K, -3); // _K: KeysDB key KeyUD|nil | 444 | lua_rawget(_K, -3); // _K: KeysDB key KeyUD|nil |
409 | KeyUD* _key{ KeyUD::GetPtr(_K, -1) }; | 445 | KeyUD* _key{ KeyUD::GetPtr(_K, -1) }; |
410 | if (_reading) { | 446 | if (_reading) { |
447 | // remove any clutter on the stack | ||
448 | lua_settop(_K, 0); // _K: | ||
411 | if (_key && _key->limit >= 0) { | 449 | if (_key && _key->limit >= 0) { |
412 | lua_pushinteger(_K, _key->limit); // _K: KeysDB key KeyUD limit | 450 | lua_pushinteger(_K, _key->limit); // _K: limit |
413 | } else { // if the key doesn't exist, it is unlimited by default | 451 | } else { // if the key doesn't exist, it is unlimited by default |
414 | luaG_pushstring(_K, "unlimited"); // _K: KeysDB key KeyUD "unlimited" | 452 | luaG_pushstring(_K, "unlimited"); // _K: "unlimited" |
415 | } | 453 | } |
416 | // return a single value: the limit of the key | 454 | // return a single value: the limit of the key |
417 | } else { | 455 | } else { |
@@ -426,7 +464,9 @@ int keepercall_limit(lua_State* const L_) | |||
426 | // this is the case if we detect the key was full but it is no longer the case | 464 | // this is the case if we detect the key was full but it is no longer the case |
427 | lua_pushboolean(_K, _key->changeLimit(_limit) ? 1 : 0); // _K: bool | 465 | lua_pushboolean(_K, _key->changeLimit(_limit) ? 1 : 0); // _K: bool |
428 | } | 466 | } |
429 | return 1; | 467 | KeyUD::PushFillStatus(_K, _key); // _K: limit|bool <fill status> |
468 | STACK_CHECK(_K, 2); | ||
469 | return 2; | ||
430 | } | 470 | } |
431 | 471 | ||
432 | // ################################################################################################# | 472 | // ################################################################################################# |
@@ -538,12 +578,12 @@ int keepercall_set(lua_State* const L_) | |||
538 | // retrieve KeysDB associated with the linda | 578 | // retrieve KeysDB associated with the linda |
539 | PushKeysDB(_K, 1); // _K: linda key val... KeysDB | 579 | PushKeysDB(_K, 1); // _K: linda key val... KeysDB |
540 | lua_replace(_K, 1); // _K: KeysDB key val... | 580 | lua_replace(_K, 1); // _K: KeysDB key val... |
581 | lua_pushvalue(_K, 2); // _K: KeysDB key val... key | ||
582 | lua_rawget(_K, 1); // _K: KeysDB key val KeyUD|nil | ||
583 | KeyUD* _key{ KeyUD::GetPtr(_K, -1) }; | ||
541 | 584 | ||
542 | if (lua_gettop(_K) == 2) { // no value to set // _K: KeysDB key | 585 | if (lua_gettop(_K) == 3) { // no value to set // _K: KeysDB key KeyUD|nil |
543 | lua_pushvalue(_K, -1); // _K: KeysDB key key | ||
544 | lua_rawget(_K, 1); // _K: KeysDB key KeyUD|nil | ||
545 | // empty the KeyUD for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! | 586 | // empty the KeyUD for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! |
546 | KeyUD* const _key{ KeyUD::GetPtr(_K, -1) }; | ||
547 | if (_key != nullptr) { // might be nullptr if we set a nonexistent key to nil // _K: KeysDB key KeyUD | 587 | if (_key != nullptr) { // might be nullptr if we set a nonexistent key to nil // _K: KeysDB key KeyUD |
548 | if (_key->limit < 0) { // KeyUD limit value is the default (unlimited): we can totally remove it | 588 | if (_key->limit < 0) { // KeyUD limit value is the default (unlimited): we can totally remove it |
549 | lua_pop(_K, 1); // _K: KeysDB key | 589 | lua_pop(_K, 1); // _K: KeysDB key |
@@ -555,18 +595,17 @@ int keepercall_set(lua_State* const L_) | |||
555 | _should_wake_writers = _key->reset(_K); | 595 | _should_wake_writers = _key->reset(_K); |
556 | } | 596 | } |
557 | } | 597 | } |
598 | lua_settop(_K, 0); // we are done, remove everything // _K: | ||
558 | } else { // set/replace contents stored at the specified key? | 599 | } else { // set/replace contents stored at the specified key? |
559 | int const _count{ lua_gettop(_K) - 2 }; // number of items we want to store | 600 | int const _count{ lua_gettop(_K) - 3 }; // number of items we want to store // _K: KeysDB key val... KeyUD|nil |
560 | lua_pushvalue(_K, 2); // _K: KeysDB key val... key | 601 | if (_key == nullptr) { // can be nullptr if we store a value at a new key // _K: KeysDB key val... nil |
561 | lua_rawget(_K, 1); // _K: KeysDB key val... KeyUD|nil | 602 | assert(lua_isnil(_K, -1)); |
562 | KeyUD* _key{ KeyUD::GetPtr(_K, -1) }; | ||
563 | if (_key == nullptr) { // can be nullptr if we store a value at a new key // KeysDB key val... nil | ||
564 | // no need to wake writers in that case, because a writer can't wait on an inexistent key | ||
565 | lua_pop(_K, 1); // _K: KeysDB key val... | 603 | lua_pop(_K, 1); // _K: KeysDB key val... |
566 | _key = KeyUD::Create(KeeperState{ _K }); // _K: KeysDB key val... KeyUD | 604 | _key = KeyUD::Create(KeeperState{ _K }); // _K: KeysDB key val... KeyUD |
567 | lua_pushvalue(_K, 2); // _K: KeysDB key val... KeyUD key | 605 | lua_pushvalue(_K, 2); // _K: KeysDB key val... KeyUD key |
568 | lua_pushvalue(_K, -2); // _K: KeysDB key val... KeyUD key KeyUD | 606 | lua_pushvalue(_K, -2); // _K: KeysDB key val... KeyUD key KeyUD |
569 | lua_rawset(_K, 1); // _K: KeysDB key val... KeyUD | 607 | lua_rawset(_K, 1); // _K: KeysDB key val... KeyUD |
608 | // no need to wake writers, because a writer can't wait on an inexistent key | ||
570 | } else { // _K: KeysDB key val... KeyUD | 609 | } else { // _K: KeysDB key val... KeyUD |
571 | // the KeyUD exists, we just want to update its contents | 610 | // the KeyUD exists, we just want to update its contents |
572 | // we create room if the KeyUD was full but we didn't refill it to the brim with new data | 611 | // we create room if the KeyUD was full but we didn't refill it to the brim with new data |
@@ -575,10 +614,12 @@ int keepercall_set(lua_State* const L_) | |||
575 | // replace the key with the KeyUD in the stack | 614 | // replace the key with the KeyUD in the stack |
576 | lua_replace(_K, -2 - _count); // _K: KeysDB KeyUD val... | 615 | lua_replace(_K, -2 - _count); // _K: KeysDB KeyUD val... |
577 | [[maybe_unused]] bool const _pushed{ _key->push(_K, _count, false) }; // _K: KeysDB | 616 | [[maybe_unused]] bool const _pushed{ _key->push(_K, _count, false) }; // _K: KeysDB |
617 | lua_pop(_K, 1); // _K: | ||
578 | } | 618 | } |
579 | // stack isn't the same here depending on what we did before, but that's not a problem | 619 | assert(lua_gettop(_K) == 0); |
580 | lua_pushboolean(_K, _should_wake_writers ? 1 : 0); // _K: ... bool | 620 | lua_pushboolean(_K, _should_wake_writers ? 1 : 0); // _K: bool |
581 | return 1; | 621 | KeyUD::PushFillStatus(_K, _key); // _K: bool <fill status> |
622 | return 2; | ||
582 | } | 623 | } |
583 | 624 | ||
584 | // ################################################################################################# | 625 | // ################################################################################################# |