Insert, delete or replace the specified element 'ele' of length 'len' at * the specified position 'p', with 'p' being a listpack element pointer * obtained with lpFirst(), lpLast(), lpNext(), lpPrev() or lpSeek(). * * The element is inserted before, after, or replaces the element pointed * by 'p' depending on the 'where' argument, that can be LP_BEFORE, LP_AFTER * or LP_REPLACE. * * If 'el
| 653 | * element, on the right of the deleted one, or to NULL if the deleted element |
| 654 | * was the last one. */ |
| 655 | unsigned char *lpInsert(unsigned char *lp, unsigned char *ele, uint32_t size, unsigned char *p, int where, unsigned char **newp) { |
| 656 | unsigned char intenc[LP_MAX_INT_ENCODING_LEN]; |
| 657 | unsigned char backlen[LP_MAX_BACKLEN_SIZE]; |
| 658 | |
| 659 | uint64_t enclen; /* The length of the encoded element. */ |
| 660 | |
| 661 | /* An element pointer set to NULL means deletion, which is conceptually |
| 662 | * replacing the element with a zero-length element. So whatever we |
| 663 | * get passed as 'where', set it to LP_REPLACE. */ |
| 664 | if (ele == NULL) where = LP_REPLACE; |
| 665 | |
| 666 | /* If we need to insert after the current element, we just jump to the |
| 667 | * next element (that could be the EOF one) and handle the case of |
| 668 | * inserting before. So the function will actually deal with just two |
| 669 | * cases: LP_BEFORE and LP_REPLACE. */ |
| 670 | if (where == LP_AFTER) { |
| 671 | p = lpSkip(p); |
| 672 | where = LP_BEFORE; |
| 673 | ASSERT_INTEGRITY(lp, p); |
| 674 | } |
| 675 | |
| 676 | /* Store the offset of the element 'p', so that we can obtain its |
| 677 | * address again after a reallocation. */ |
| 678 | unsigned long poff = p-lp; |
| 679 | |
| 680 | /* Calling lpEncodeGetType() results into the encoded version of the |
| 681 | * element to be stored into 'intenc' in case it is representable as |
| 682 | * an integer: in that case, the function returns LP_ENCODING_INT. |
| 683 | * Otherwise if LP_ENCODING_STR is returned, we'll have to call |
| 684 | * lpEncodeString() to actually write the encoded string on place later. |
| 685 | * |
| 686 | * Whatever the returned encoding is, 'enclen' is populated with the |
| 687 | * length of the encoded element. */ |
| 688 | int enctype; |
| 689 | if (ele) { |
| 690 | enctype = lpEncodeGetType(ele,size,intenc,&enclen); |
| 691 | } else { |
| 692 | enctype = -1; |
| 693 | enclen = 0; |
| 694 | } |
| 695 | |
| 696 | /* We need to also encode the backward-parsable length of the element |
| 697 | * and append it to the end: this allows to traverse the listpack from |
| 698 | * the end to the start. */ |
| 699 | unsigned long backlen_size = ele ? lpEncodeBacklen(backlen,enclen) : 0; |
| 700 | uint64_t old_listpack_bytes = lpGetTotalBytes(lp); |
| 701 | uint32_t replaced_len = 0; |
| 702 | if (where == LP_REPLACE) { |
| 703 | replaced_len = lpCurrentEncodedSizeUnsafe(p); |
| 704 | replaced_len += lpEncodeBacklen(NULL,replaced_len); |
| 705 | ASSERT_INTEGRITY_LEN(lp, p, replaced_len); |
| 706 | } |
| 707 | |
| 708 | uint64_t new_listpack_bytes = old_listpack_bytes + enclen + backlen_size |
| 709 | - replaced_len; |
| 710 | if (new_listpack_bytes > UINT32_MAX) return NULL; |
| 711 | |
| 712 | /* We now need to reallocate in order to make space or shrink the |
no test coverage detected