// File: /workspace/github_cpp_makefile_star2_O1/Baobaobear[P]sort/./wikisort.hpp
// Function: void Wiki::MergeInPlace<baobao::TestClass*, std::less<baobao::TestClass>>(baobao::TestClass*, baobao::TestClass*, baobao::TestClass*, baobao::TestClass*, std::less<baobao::TestClass>)
void MergeInPlace(RandomAccessIterator first1, RandomAccessIterator last1,
                      RandomAccessIterator first2, RandomAccessIterator last2,
                      Comparison compare) {
        if (last1 - first1 == 0 || last2 - first2 == 0) return;

        /*
         this just repeatedly binary searches into B and rotates A into position.
         the paper suggests using the 'rotation-based Hwang and Lin algorithm' here,
         but I decided to stick with this because it had better situational performance

         (Hwang and Lin is designed for merging subarrays of very different sizes,
         but WikiSort almost always uses subarrays that are roughly the same size)

         normally this is incredibly suboptimal, but this function is only called
         when none of the A or B blocks in any subarray contained 2sqrtA unique values,
         which places a hard limit on the number of times this will ACTUALLY need
         to binary search and rotate.

         according to my analysis the worst case is sqrtA rotations performed on sqrtA items
         once the constant factors are removed, which ends up being O(n)

         again, this is NOT a general-purpose solution - it only works well in this case!
         kind of like how the O(n^2) insertion sort is used in some places
         */

        while (true) {
            // find the first place in B where the first item in A needs to be inserted
            RandomAccessIterator mid = std::lower_bound(first2, last2, *first1, compare);

            // rotate A into place
            std::size_t amount = mid - last1;
            std::rotate(first1, last1, mid);
            if (last2 == mid) break;

            // calculate the new A and B ranges
            first2 = mid;
            first1 += amount;
            last1 = first2;
            first1 = std::upper_bound(first1, last1, *first1, compare);
            if (std::distance(first1, last1) == 0) break;
        }
    }

// Assembly:
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
movq %rcx, %rbx
cmpq %rdi, %rsi
sete %al
cmpq %rdx, %rcx
sete %cl
orb %al, %cl
jne 0x11c06
movq %rdx, %r13
movq %rsi, %r12
movq %rdi, %r14
movq %rbx, %rdx
subq %r13, %rdx
sarq $0x5, %rdx
movq %r13, %r15
testq %rdx, %rdx
jle 0x11b98
movl (%r14), %eax
movq %r13, %r15
movq %rdx, %rcx
shrq %rcx
movq %rcx, %rsi
shlq $0x5, %rsi
cmpl %eax, (%r15,%rsi)
jge 0x11b90
notq %rcx
addq %rdx, %rcx
addq %rsi, %r15
addq $0x20, %r15
movq %rcx, %rdx
testq %rcx, %rcx
jg 0x11b73
movq %r14, %rdi
movq %r12, %rsi
movq %r15, %rdx
callq 0x5b3a
cmpq %rbx, %r15
je 0x11bfc
movq %r15, %rax
subq %r12, %rax
addq %rax, %r14
movq %r15, %rdx
subq %r14, %rdx
sarq $0x5, %rdx
testq %rdx, %rdx
jle 0x11bee
movl (%r14), %eax
movq %rdx, %rcx
shrq %rcx
movq %rcx, %rsi
shlq $0x5, %rsi
cmpl (%r14,%rsi), %eax
jl 0x11be6
notq %rcx
addq %rdx, %rcx
addq %rsi, %r14
addq $0x20, %r14
movq %rcx, %rdx
testq %rcx, %rcx
jg 0x11bc9
cmpq %r14, %r15
setne %al
movq %r15, %r12
movq %r15, %r13
jmp 0x11bfe
xorl %eax, %eax
testb %al, %al
jne 0x11b58
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
retq