// File: /workspace/github_c_makefile_star2_O1/nilyang[P]redis-tdd-annotation/src/ziplist.c
// Function: _ziplistDelete
static unsigned char *__ziplistDelete(unsigned char *zl, unsigned char *p, unsigned int num) {
    unsigned int i, totlen, deleted = 0;
    size_t offset;
    int nextdiff = 0;
    zlentry first, tail;

    // 计算被删除节点总共占用的内存字节数
    // 以及被删除节点的总个数
    // T = O(N)
    first = zipEntry(p);
    for (i = 0; p[0] != ZIP_END && i < num; i++) {
        p += zipRawEntryLength(p);
        deleted++;
    }

    // totlen 是所有被删除节点总共占用的内存字节数
    totlen = p-first.p;
    if (totlen > 0) {
        if (p[0] != ZIP_END) {

            // 执行这里，表示被删除节点之后仍然有节点存在

            /* Storing `prevrawlen` in this entry may increase or decrease the
             * number of bytes required compare to the current `prevrawlen`.
             * There always is room to store this, because it was previously
             * stored by an entry that is now being deleted. */
            // 因为位于被删除范围之后的第一个节点的 header 部分的大小
            // 可能容纳不了新的前置节点，所以需要计算新旧前置节点之间的字节数差
            // T = O(1)
            nextdiff = zipPrevLenByteDiff(p,first.prevrawlen);
            // 如果有需要的话，将指针 p 后退 nextdiff 字节，为新 header 空出空间
            p -= nextdiff;
            // 将 first 的前置节点的长度编码至 p 中
            // T = O(1)
            zipPrevEncodeLength(p,first.prevrawlen);

            /* Update offset for tail */
            // 更新到达表尾的偏移量
            // T = O(1)
            ZIPLIST_TAIL_OFFSET(zl) =
                intrev32ifbe(intrev32ifbe(ZIPLIST_TAIL_OFFSET(zl))-totlen);

            /* When the tail contains more than one entry, we need to take
             * "nextdiff" in account as well. Otherwise, a change in the
             * size of prevlen doesn't have an effect on the *tail* offset. */
            // 如果被删除节点之后，有多于一个节点
            // 那么程序需要将 nextdiff 记录的字节数也计算到表尾偏移量中
            // 这样才能让表尾偏移量正确对齐表尾节点
            // T = O(1)
            tail = zipEntry(p);
            if (p[tail.headersize+tail.len] != ZIP_END) {
                ZIPLIST_TAIL_OFFSET(zl) =
                   intrev32ifbe(intrev32ifbe(ZIPLIST_TAIL_OFFSET(zl))+nextdiff);
            }

            /* Move tail to the front of the ziplist */
            // 从表尾向表头移动数据，覆盖被删除节点的数据
            // T = O(N)
            memmove(first.p,p,
                intrev32ifbe(ZIPLIST_BYTES(zl))-(p-zl)-1);
        } else {

            // 执行这里，表示被删除节点之后已经没有其他节点了

            /* The entire tail was deleted. No need to move memory. */
            // T = O(1)
            ZIPLIST_TAIL_OFFSET(zl) =
                intrev32ifbe((first.p-zl)-first.prevrawlen);
        }

        /* Resize and update length */
        // 缩小并更新 ziplist 的长度
        offset = first.p-zl;
        zl = ziplistResize(zl, intrev32ifbe(ZIPLIST_BYTES(zl))-totlen+nextdiff);
        ZIPLIST_INCR_LENGTH(zl,-deleted);
        p = zl+offset;

        /* When nextdiff != 0, the raw length of the next entry has changed, so
         * we need to cascade the update throughout the ziplist */
        // 如果 p 所指向的节点的大小已经变更，那么进行级联更新
        // 检查 p 之后的所有节点是否符合 ziplist 的编码要求
        // T = O(N^2)
        if (nextdiff != 0)
            zl = __ziplistCascadeUpdate(zl,p);
    }

    return zl;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x38, %rsp
movl %edx, %ebp
movq %rsi, %r15
movq %rdi, %rbx
leaq 0x18(%rsp), %r14
movq %r14, %rdi
callq 0x2c0a0
movl 0x4(%r14), %edi
movq 0x18(%r14), %r14
movb (%r15), %al
cmpb $-0x1, %al
setne %cl
sete %dl
testl %ebp, %ebp
sete %sil
xorl %r13d, %r13d
orb %dl, %sil
jne 0x2c507
movq %rdi, 0x10(%rsp)
movq %r15, %r12
movq %r15, %rdi
callq 0x2c1c5
movl %eax, %eax
addq %rax, %r15
incl %r13d
movb (%r12,%rax), %al
cmpb $-0x1, %al
setne %cl
je 0x2c502
cmpl %ebp, %r13d
jb 0x2c4df
movq 0x10(%rsp), %rdi
movl %r15d, %ebp
subl %r14d, %ebp
je 0x2c60b
testb %cl, %cl
movq %r14, 0x8(%rsp)
je 0x2c54b
xorl %ecx, %ecx
cmpb $-0x2, %al
setne %cl
negl %ecx
orl $-0x5, %ecx
xorl %eax, %eax
cmpl $0xfe, %edi
setae %al
leal (%rcx,%rax,4), %edx
notl %edx
movslq %edx, %rdx
addq %rdx, %r15
cmpl $0xfd, %edi
ja 0x2c55a
movb %dil, (%r15)
jmp 0x2c562
addl %ebx, %edi
movl %r14d, %eax
subl %edi, %eax
movl %eax, 0x4(%rbx)
xorl %r14d, %r14d
jmp 0x2c5ac
movb $-0x2, (%r15)
movl %edi, 0x1(%r15)
leal (%rcx,%rax,4), %r14d
incl %r14d
subl %ebp, 0x4(%rbx)
leaq 0x18(%rsp), %r12
movq %r12, %rdi
movq %r15, %rsi
callq 0x2c0a0
movl 0x10(%r12), %eax
addl 0xc(%r12), %eax
cmpb $-0x1, (%r15,%rax)
je 0x2c591
addl %r14d, 0x4(%rbx)
movl (%rbx), %edx
movq %r15, %rax
notq %rax
addq %rbx, %rdx
addq %rax, %rdx
movq 0x8(%rsp), %rdi
movq %r15, %rsi
callq 0x1f780
movl (%rbx), %r12d
subl %ebp, %r12d
leal (%r12,%r14), %r15d
movq %rbx, %rdi
movq %r15, %rsi
callq 0x297b5
movl %r15d, (%rax)
leal (%r12,%r14), %ecx
decl %ecx
movb $-0x1, (%rax,%rcx)
movzwl 0x8(%rax), %ecx
cmpw $-0x1, %cx
je 0x2c5df
subl %r13d, %ecx
movw %cx, 0x8(%rax)
testl %r14d, %r14d
je 0x2c608
movq 0x8(%rsp), %rcx
subq %rbx, %rcx
movq %rax, %rsi
addq %rcx, %rsi
movq %rax, %rdi
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x2cb63
movq %rax, %rbx
movq %rbx, %rax
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq