// File: /workspace/github_cpp_makefile_star2_O3/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 %r12
pushq %rbx
pushq %rax
movq %rcx, %rbx
cmpq %rdi, %rsi
sete %al
cmpq %rdx, %rcx
sete %cl
orb %al, %cl
jne 0x11ab7
movq %rdx, %r14
movq %rsi, %r12
movq %rdi, %r15
movq %rbx, %rdx
subq %r14, %rdx
sarq $0x5, %rdx
testq %rdx, %rdx
jle 0x11a55
movl (%r15), %eax
movq %rdx, %rcx
shrq %rcx
movq %rcx, %rsi
shlq $0x5, %rsi
cmpl %eax, (%r14,%rsi)
jge 0x11a4d
notq %rcx
addq %rdx, %rcx
addq %rsi, %r14
addq $0x20, %r14
movq %rcx, %rdx
testq %rcx, %rcx
jg 0x11a30
movq %r15, %rdi
movq %r12, %rsi
movq %r14, %rdx
callq 0x5a6e
cmpq %rbx, %r14
je 0x11ab7
movq %r14, %rax
subq %r12, %rax
addq %rax, %r15
movq %r14, %rdx
subq %r15, %rdx
sarq $0x5, %rdx
testq %rdx, %rdx
jle 0x11aab
movl (%r15), %eax
movq %rdx, %rcx
shrq %rcx
movq %rcx, %rsi
shlq $0x5, %rsi
cmpl (%r15,%rsi), %eax
jl 0x11aa3
notq %rcx
addq %rdx, %rcx
addq %rsi, %r15
addq $0x20, %r15
movq %rcx, %rdx
testq %rcx, %rcx
jg 0x11a86
movq %r14, %r12
cmpq %r15, %r14
jne 0x11a1b
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r14
popq %r15
retq