// File: jansucan[P]diff-dd/src/create.cpp
// Function: diffsTryMerge(Diff&, Diff&, unsigned long, unsigned long)
MergeState
diffsTryMerge(Diff &diff_a, Diff &diff_b, size_t max_merge_gap, size_t max_size)
{
    if (diff_a.isEmpty()) {
        // Do not merge to an empty diff
        return MergeState::Finished;
    }

    if (diff_b.isEmpty()) {
        // Nothing to merge from an empty diff
        return MergeState::Finished;
    }

    assert(diff_a.getEnd() <= diff_b.getStart());
    const size_t gap{diff_b.getStart() - diff_a.getEnd()};
    if (gap > max_merge_gap) {
        // B is too far away
        return MergeState::Finished;
    }

    if ((diff_a.getSize() + gap) >= max_size) {
        // No space in A
        return MergeState::Finished;
    }

    // Can be merged

    // Adjust the diff start and end offsets

    // There is always at least 1 byte free in A here
    const size_t free{max_size - (diff_a.getSize() + gap)};
    const size_t to_merge{std::min(free, diff_b.getSize())};
    // There is always at least 1 byte to merge from B here

    // Enlarge A
    diff_a.m_end += gap + to_merge;
    // Shrink B
    diff_b.m_start += to_merge;

    // Add B's page to A if needed

    // Non-empty A must have only the first, or both pages
    assert(diff_a.hasPage(0));
    // Non-empty B must have only the first page
    assert(diff_b.hasPage(0) && !diff_b.hasPage(1));

    // If A has both pages, B's page must only be the same as A's second
    // page. No setting of pages in A is needed in this case
    assert(!diff_a.hasPage(1) || (diff_b.m_pages[0] == diff_a.m_pages[1]));
    if (!diff_a.hasPage(1)) {
        // If A has only the first page, B's page must only be the same as the
        // A's first page or following it
        const bool b_follows{
            (diff_b.m_pages[0].getData() != diff_a.m_pages[0].getData()) &&
            (diff_b.m_pages[0].getStart() == diff_a.m_pages[0].getEnd())};
        assert((diff_b.m_pages[0] == diff_a.m_pages[0]) || b_follows);
        if (b_follows) {
            diff_a.m_pages[1] = diff_b.m_pages[0];
        }
    }

    return (diff_a.getSize() >= max_size) ? MergeState::Finished
                                          : MergeState::Incomplete;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xf0, %rsp
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq %rdx, -0x20(%rbp)
movq %rcx, -0x28(%rbp)
movq -0x10(%rbp), %rdi
callq 0x7550
testb $0x1, %al
jne 0x688a
jmp 0x6896
movl $0x0, -0x4(%rbp)
jmp 0x6ccc
movq -0x18(%rbp), %rdi
callq 0x7550
testb $0x1, %al
jne 0x68a5
jmp 0x68b1
movl $0x0, -0x4(%rbp)
jmp 0x6ccc
movq -0x10(%rbp), %rdi
callq 0x7580
movq %rax, -0x88(%rbp)
movq -0x18(%rbp), %rdi
callq 0x75a0
movq %rax, %rcx
movq -0x88(%rbp), %rax
cmpq %rcx, %rax
ja 0x68db
jmp 0x68fa
leaq 0x7a4a(%rip), %rdi      # 0xe32c
leaq 0x7a68(%rip), %rsi      # 0xe351
movl $0xb3, %edx
leaq 0x7a67(%rip), %rcx      # 0xe35c
callq 0x31c0
movq -0x18(%rbp), %rdi
callq 0x75a0
movq %rax, -0x90(%rbp)
movq -0x10(%rbp), %rdi
callq 0x7580
movq %rax, %rcx
movq -0x90(%rbp), %rax
subq %rcx, %rax
movq %rax, -0x30(%rbp)
movq -0x30(%rbp), %rax
cmpq -0x20(%rbp), %rax
jbe 0x693a
movl $0x0, -0x4(%rbp)
jmp 0x6ccc
movq -0x10(%rbp), %rdi
callq 0x75c0
addq -0x30(%rbp), %rax
cmpq -0x28(%rbp), %rax
jb 0x6959
movl $0x0, -0x4(%rbp)
jmp 0x6ccc
movq -0x28(%rbp), %rax
movq %rax, -0x98(%rbp)
movq -0x10(%rbp), %rdi
callq 0x75c0
movq %rax, %rcx
movq -0x98(%rbp), %rax
addq -0x30(%rbp), %rcx
subq %rcx, %rax
movq %rax, -0x38(%rbp)
movq -0x18(%rbp), %rdi
callq 0x75c0
movq %rax, -0x48(%rbp)
leaq -0x38(%rbp), %rdi
leaq -0x48(%rbp), %rsi
callq 0x4a50
movq (%rax), %rax
movq %rax, -0x40(%rbp)
movq -0x30(%rbp), %rcx
addq -0x40(%rbp), %rcx
movq -0x10(%rbp), %rax
addq 0x48(%rax), %rcx
movq %rcx, 0x48(%rax)
movq -0x40(%rbp), %rcx
movq -0x18(%rbp), %rax
addq 0x40(%rax), %rcx
movq %rcx, 0x40(%rax)
movq -0x10(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x75e0
testb $0x1, %al
jne 0x69da
jmp 0x69dc
jmp 0x69fb
leaq 0x79b2(%rip), %rdi      # 0xe395
leaq 0x7967(%rip), %rsi      # 0xe351
movl $0xd0, %edx
leaq 0x7966(%rip), %rcx      # 0xe35c
callq 0x31c0
movq -0x18(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x75e0
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, -0x99(%rbp)
jne 0x6a19
jmp 0x6a2f
movq -0x18(%rbp), %rdi
movl $0x1, %esi
callq 0x75e0
xorb $-0x1, %al
movb %al, -0x99(%rbp)
movb -0x99(%rbp), %al
testb $0x1, %al
jne 0x6a3b
jmp 0x6a3d
jmp 0x6a5c
leaq 0x7963(%rip), %rdi      # 0xe3a7
leaq 0x7906(%rip), %rsi      # 0xe351
movl $0xd2, %edx
leaq 0x7905(%rip), %rcx      # 0xe35c
callq 0x31c0
movq -0x10(%rbp), %rdi
movl $0x1, %esi
callq 0x75e0
movb %al, %cl
movb $0x1, %al
testb $0x1, %cl
movb %al, -0x9a(%rbp)
jne 0x6a7b
jmp 0x6ab2
movq -0x18(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x7670
movq %rax, -0xa8(%rbp)
movq -0x10(%rbp), %rdi
movl $0x1, %esi
callq 0x7670
movq -0xa8(%rbp), %rdi
movq %rax, %rsi
callq 0x67f0
movb %al, -0x9a(%rbp)
movb -0x9a(%rbp), %al
testb $0x1, %al
jne 0x6abe
jmp 0x6ac0
jmp 0x6adf
leaq 0x7908(%rip), %rdi      # 0xe3cf
leaq 0x7883(%rip), %rsi      # 0xe351
movl $0xd6, %edx
leaq 0x7882(%rip), %rcx      # 0xe35c
callq 0x31c0
movq -0x10(%rbp), %rdi
movl $0x1, %esi
callq 0x75e0
testb $0x1, %al
jne 0x6cac
movq -0x18(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
movq %rsi, -0xb0(%rbp)
callq 0x7670
movq %rax, %rsi
leaq -0x60(%rbp), %rdi
callq 0x76e0
movq -0xb0(%rbp), %rsi
movq -0x10(%rbp), %rdi
callq 0x7670
movq %rax, %rsi
leaq -0x70(%rbp), %rdi
callq 0x76e0
jmp 0x6b33
leaq -0x60(%rbp), %rdi
leaq -0x70(%rbp), %rsi
callq 0x76a0
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, -0xb1(%rbp)
jne 0x6b51
jmp 0x6ba7
movq -0x18(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x7670
movq %rax, %rdi
callq 0x7710
movq %rax, -0xc0(%rbp)
jmp 0x6b6f
movq -0x10(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x7670
movq %rax, %rdi
callq 0x7730
movq %rax, -0xc8(%rbp)
jmp 0x6b8d
movq -0xc0(%rbp), %rax
movq -0xc8(%rbp), %rcx
cmpq %rcx, %rax
sete %al
movb %al, -0xb1(%rbp)
movb -0xb1(%rbp), %al
movb %al, -0xd9(%rbp)
leaq -0x70(%rbp), %rdi
callq 0x47d0
leaq -0x60(%rbp), %rdi
callq 0x47d0
movb -0xd9(%rbp), %al
andb $0x1, %al
movb %al, -0x49(%rbp)
movq -0x18(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x7670
movq %rax, -0xd8(%rbp)
movq -0x10(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x7670
movq -0xd8(%rbp), %rdi
movq %rax, %rsi
callq 0x67f0
movb %al, %cl
movb $0x1, %al
testb $0x1, %cl
movb %al, -0xc9(%rbp)
jne 0x6c18
movb -0x49(%rbp), %al
movb %al, -0xc9(%rbp)
movb -0xc9(%rbp), %al
testb $0x1, %al
jne 0x6c24
jmp 0x6c26
jmp 0x6c73
leaq 0x77e1(%rip), %rdi      # 0xe40e
leaq 0x771d(%rip), %rsi      # 0xe351
movl $0xdd, %edx
leaq 0x771c(%rip), %rcx      # 0xe35c
callq 0x31c0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x78(%rbp)
movl %eax, -0x7c(%rbp)
jmp 0x6c68
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x78(%rbp)
movl %eax, -0x7c(%rbp)
leaq -0x70(%rbp), %rdi
callq 0x47d0
leaq -0x60(%rbp), %rdi
callq 0x47d0
jmp 0x6cd8
testb $0x1, -0x49(%rbp)
je 0x6caa
movq -0x18(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x7670
movq %rax, -0xe8(%rbp)
movq -0x10(%rbp), %rdi
movl $0x1, %esi
callq 0x7670
movq -0xe8(%rbp), %rsi
movq %rax, %rdi
callq 0x7750
jmp 0x6cac
movq -0x10(%rbp), %rdi
callq 0x75c0
movq %rax, %rdx
movq -0x28(%rbp), %rsi
movl $0x1, %eax
xorl %ecx, %ecx
cmpq %rsi, %rdx
cmovael %ecx, %eax
movl %eax, -0x4(%rbp)
movl -0x4(%rbp), %eax
addq $0xf0, %rsp
popq %rbp
retq
movq -0x78(%rbp), %rdi
callq 0x3490
nopw %cs:(%rax,%rax)