LTRIM */
| 527 | |
| 528 | /* LTRIM <key> <start> <stop> */ |
| 529 | void ltrimCommand(client *c) { |
| 530 | robj *o; |
| 531 | long start, end, llen, ltrim, rtrim; |
| 532 | |
| 533 | if ((getLongFromObjectOrReply(c, c->argv[2], &start, NULL) != C_OK) || |
| 534 | (getLongFromObjectOrReply(c, c->argv[3], &end, NULL) != C_OK)) return; |
| 535 | |
| 536 | if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.ok)) == nullptr || |
| 537 | checkType(c,o,OBJ_LIST)) return; |
| 538 | llen = listTypeLength(o); |
| 539 | |
| 540 | /* convert negative indexes */ |
| 541 | if (start < 0) start = llen+start; |
| 542 | if (end < 0) end = llen+end; |
| 543 | if (start < 0) start = 0; |
| 544 | |
| 545 | /* Invariant: start >= 0, so this test will be true when end < 0. |
| 546 | * The range is empty when start > end or start >= length. */ |
| 547 | if (start > end || start >= llen) { |
| 548 | /* Out of range start or start > end result in empty list */ |
| 549 | ltrim = llen; |
| 550 | rtrim = 0; |
| 551 | } else { |
| 552 | if (end >= llen) end = llen-1; |
| 553 | ltrim = start; |
| 554 | rtrim = llen-end-1; |
| 555 | } |
| 556 | |
| 557 | /* Remove list elements to perform the trim */ |
| 558 | if (o->encoding == OBJ_ENCODING_QUICKLIST) { |
| 559 | quicklistDelRange((quicklist*)ptrFromObj(o),0,ltrim); |
| 560 | quicklistDelRange((quicklist*)ptrFromObj(o),-rtrim,rtrim); |
| 561 | } else { |
| 562 | serverPanic("Unknown list encoding"); |
| 563 | } |
| 564 | |
| 565 | notifyKeyspaceEvent(NOTIFY_LIST,"ltrim",c->argv[1],c->db->id); |
| 566 | if (listTypeLength(o) == 0) { |
| 567 | dbDelete(c->db,c->argv[1]); |
| 568 | notifyKeyspaceEvent(NOTIFY_GENERIC,"del",c->argv[1],c->db->id); |
| 569 | } |
| 570 | signalModifiedKey(c,c->db,c->argv[1]); |
| 571 | g_pserver->dirty += (ltrim + rtrim); |
| 572 | addReply(c,shared.ok); |
| 573 | } |
| 574 | |
| 575 | /* LPOS key element [RANK rank] [COUNT num-matches] [MAXLEN len] |
| 576 | * |
nothing calls this directly
no test coverage detected