// File: reddragon[P]packed-memory-array/impl1.cpp
// Function: PackedMemoryArray<int>::expand_PMA(int)
void PackedMemoryArray<E>::expand_PMA(E e) {
    // Create a new store
    std::vector<E> new_store;
    new_store.resize(store.size() * 2);
    std::vector<bool> new_exists;
    new_exists.resize((int)ceil(s+1));
    
    int count = 0, i;
    // Insert all elements less than e
    for(i = 0; i < (int)store.size(); i++) 
        if(ELEM_EXISTS_AT(i)) {
            if(store[i] > e)
                break;
            new_exists[count] = 1;
            new_store[count++] = store[i];
        }
    
    // Insert the element we wanted
    new_exists[count] = 1;
    new_store[count++] = e;
    
    // Insert rest of the elements
    for(; i < (int)store.size(); i++) 
        if(ELEM_EXISTS_AT(i)) {
            new_exists[count] = 1;
            new_store[count++] = store[i];
        }

    // Replace the existing store and bitmask
    store = new_store;
    exists = new_exists;
 
    // Increment the number of elements in the PMA
    s++;
    
    // std::cout << "Old smallest window size: " << segment_size << std::endl;
    // Recalculate l and segment_size
    int log2n = __builtin_popcount(store.size()-1);
    if(log2n & (log2n-1)) {
        // log2n is not a power of 2, round it up to the nearest power of 2.
        segment_size = 1<<((int)floor(log2(log2n<<1)));
    }
    else {
        // log2n is a power of 2, so, all is fine.
        segment_size = 1<<log2n;
    }
    l = log2n - log2(segment_size);
    // std::cout << "New smallest window size: " << segment_size << std::endl;

    // Now rebalance the entire PMA 
    rebalance(0, l);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x150, %rsp            # imm = 0x150
movq %rdi, -0x8(%rbp)
movl %esi, -0xc(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0xd0(%rbp)
leaq -0x28(%rbp), %rdi
movq %rdi, -0xc8(%rbp)
callq 0x16f0
movq -0xd0(%rbp), %rdi
callq 0x1950
movq -0xc8(%rbp), %rdi
movq %rax, %rsi
addq %rsi, %rsi
callq 0x1730
jmp 0x4d5d
leaq -0x60(%rbp), %rdi
movq %rdi, -0xd8(%rbp)
callq 0x1710
movq -0xd0(%rbp), %rax
movl 0x58(%rax), %eax
incl %eax
cvtsi2sd %rax, %xmm0
callq 0x1030
movq -0xd8(%rbp), %rdi
cvttsd2si %xmm0, %eax
movslq %eax, %rsi
xorl %edx, %edx
callq 0x17c0
jmp 0x4d9a
movl $0x0, -0x64(%rbp)
movl $0x0, -0x68(%rbp)
movq -0xd0(%rbp), %rdi
movl -0x68(%rbp), %eax
movl %eax, -0xdc(%rbp)
callq 0x1950
movq %rax, %rcx
movl -0xdc(%rbp), %eax
cmpl %ecx, %eax
jge 0x4eef
movq -0xd0(%rbp), %rdi
addq $0x18, %rdi
movslq -0x68(%rbp), %rsi
callq 0x4750
movq %rdx, -0xf0(%rbp)
movq %rax, -0xe8(%rbp)
jmp 0x4df2
movq -0xf0(%rbp), %rax
movq -0xe8(%rbp), %rcx
movq %rcx, -0x78(%rbp)
movq %rax, -0x70(%rbp)
leaq -0x78(%rbp), %rdi
callq 0x38e0
testb $0x1, %al
jne 0x4e1a
jmp 0x4edf
movq -0xd0(%rbp), %rdi
movslq -0x68(%rbp), %rsi
callq 0x4730
movl (%rax), %eax
cmpl -0xc(%rbp), %eax
jle 0x4e61
jmp 0x4eef
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
jmp 0x51ab
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
leaq -0x60(%rbp), %rdi
callq 0x1970
jmp 0x51ab
movslq -0x64(%rbp), %rsi
leaq -0x60(%rbp), %rdi
callq 0x4750
movq %rdx, -0x100(%rbp)
movq %rax, -0xf8(%rbp)
jmp 0x4e7e
movq -0x100(%rbp), %rax
movq -0xf8(%rbp), %rcx
movq %rcx, -0x88(%rbp)
movq %rax, -0x80(%rbp)
leaq -0x88(%rbp), %rdi
movl $0x1, %esi
callq 0x3910
movq -0xd0(%rbp), %rdi
movslq -0x68(%rbp), %rsi
callq 0x4730
movl (%rax), %eax
movl %eax, -0x104(%rbp)
movl -0x64(%rbp), %eax
movl %eax, %ecx
addl $0x1, %ecx
movl %ecx, -0x64(%rbp)
movslq %eax, %rsi
leaq -0x28(%rbp), %rdi
callq 0x4730
movl -0x104(%rbp), %ecx
movl %ecx, (%rax)
jmp 0x4ee1
movl -0x68(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x68(%rbp)
jmp 0x4da8
movslq -0x64(%rbp), %rsi
leaq -0x60(%rbp), %rdi
callq 0x4750
movq %rdx, -0x118(%rbp)
movq %rax, -0x110(%rbp)
jmp 0x4f0c
movq -0x118(%rbp), %rax
movq -0x110(%rbp), %rcx
movq %rcx, -0x98(%rbp)
movq %rax, -0x90(%rbp)
leaq -0x98(%rbp), %rdi
movl $0x1, %esi
callq 0x3910
movl -0xc(%rbp), %eax
movl %eax, -0x11c(%rbp)
movl -0x64(%rbp), %eax
movl %eax, %ecx
addl $0x1, %ecx
movl %ecx, -0x64(%rbp)
movslq %eax, %rsi
leaq -0x28(%rbp), %rdi
callq 0x4730
movl -0x11c(%rbp), %ecx
movl %ecx, (%rax)
movq -0xd0(%rbp), %rdi
movl -0x68(%rbp), %eax
movl %eax, -0x120(%rbp)
callq 0x1950
movq %rax, %rcx
movl -0x120(%rbp), %eax
cmpl %ecx, %eax
jge 0x506d
movq -0xd0(%rbp), %rdi
addq $0x18, %rdi
movslq -0x68(%rbp), %rsi
callq 0x4750
movq %rdx, -0x130(%rbp)
movq %rax, -0x128(%rbp)
jmp 0x4fab
movq -0x130(%rbp), %rax
movq -0x128(%rbp), %rcx
movq %rcx, -0xa8(%rbp)
movq %rax, -0xa0(%rbp)
leaq -0xa8(%rbp), %rdi
callq 0x38e0
testb $0x1, %al
jne 0x4fdc
jmp 0x505d
movslq -0x64(%rbp), %rsi
leaq -0x60(%rbp), %rdi
callq 0x4750
movq %rdx, -0x140(%rbp)
movq %rax, -0x138(%rbp)
jmp 0x4ff9
movq -0x140(%rbp), %rax
movq -0x138(%rbp), %rcx
movq %rcx, -0xb8(%rbp)
movq %rax, -0xb0(%rbp)
leaq -0xb8(%rbp), %rdi
movl $0x1, %esi
callq 0x3910
movq -0xd0(%rbp), %rdi
movslq -0x68(%rbp), %rsi
callq 0x4730
movl (%rax), %eax
movl %eax, -0x144(%rbp)
movl -0x64(%rbp), %eax
movl %eax, %ecx
addl $0x1, %ecx
movl %ecx, -0x64(%rbp)
movslq %eax, %rsi
leaq -0x28(%rbp), %rdi
callq 0x4730
movl -0x144(%rbp), %ecx
movl %ecx, (%rax)
jmp 0x505f
movl -0x68(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x68(%rbp)
jmp 0x4f61
movq -0xd0(%rbp), %rdi
leaq -0x28(%rbp), %rsi
callq 0x55e0
jmp 0x507f
movq -0xd0(%rbp), %rdi
addq $0x18, %rdi
leaq -0x60(%rbp), %rsi
callq 0x5830
jmp 0x5095
movq -0xd0(%rbp), %rdi
movl 0x58(%rdi), %eax
addl $0x1, %eax
movl %eax, 0x58(%rdi)
callq 0x1950
subq $0x1, %rax
movl %eax, %ecx
movl %ecx, %eax
shrl %eax
andl $0x55555555, %eax       # imm = 0x55555555
subl %eax, %ecx
movl %ecx, %eax
andl $0x33333333, %eax       # imm = 0x33333333
shrl $0x2, %ecx
andl $0x33333333, %ecx       # imm = 0x33333333
addl %ecx, %eax
movl %eax, %ecx
shrl $0x4, %ecx
addl %ecx, %eax
andl $0xf0f0f0f, %eax        # imm = 0xF0F0F0F
imull $0x1010101, %eax, %eax  # imm = 0x1010101
shrl $0x18, %eax
movl %eax, -0xbc(%rbp)
movl -0xbc(%rbp), %eax
movl -0xbc(%rbp), %ecx
subl $0x1, %ecx
andl %ecx, %eax
cmpl $0x0, %eax
je 0x512d
movl -0xbc(%rbp), %eax
shll %eax
cvtsi2sd %eax, %xmm0
callq 0x1180
callq 0x1160
movq -0xd0(%rbp), %rax
cvttsd2si %xmm0, %ecx
movl $0x1, %edx
shll %cl, %edx
movl %edx, %ecx
movl %ecx, 0x5c(%rax)
jmp 0x5146
movq -0xd0(%rbp), %rax
movl -0xbc(%rbp), %ecx
movl $0x1, %edx
shll %cl, %edx
movl %edx, %ecx
movl %ecx, 0x5c(%rax)
movq -0xd0(%rbp), %rax
cvtsi2sdl -0xbc(%rbp), %xmm0
movsd %xmm0, -0x150(%rbp)
cvtsi2sdl 0x5c(%rax), %xmm0
callq 0x1180
movq -0xd0(%rbp), %rdi
movaps %xmm0, %xmm1
movsd -0x150(%rbp), %xmm0
subsd %xmm1, %xmm0
cvttsd2si %xmm0, %eax
movl %eax, 0x54(%rdi)
movl 0x54(%rdi), %edx
xorl %esi, %esi
callq 0x5990
jmp 0x5190
leaq -0x60(%rbp), %rdi
callq 0x1970
leaq -0x28(%rbp), %rdi
callq 0x1990
addq $0x150, %rsp            # imm = 0x150
popq %rbp
retq
leaq -0x28(%rbp), %rdi
callq 0x1990
movq -0x30(%rbp), %rdi
callq 0x1170
nopl (%rax)