// File: wichtounet[P]cpp_utils_test/include/cpp_utils/parallel.hpp
// Function: void cpp::parallel_foreach_i<cpp::thread_pool<true>, __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int>>>, DOCTEST_ANON_FUNC_12()::$_0>(cpp::thread_pool<true>&, __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int>>>, __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int>>>, DOCTEST_ANON_FUNC_12()::$_0)
void parallel_foreach_i(TP& thread_pool, Iterator first, Iterator last, Functor fun) {
    if constexpr (std::is_same_v<typename std::iterator_traits<Iterator>::iterator_category, std::random_access_iterator_tag>) {
        const auto n    = std::distance(first, last);
        const auto part = n / thread_pool.size();

        if (part < 2) {
            for (std::size_t i = 0; first != last; ++first, ++i) {
                thread_pool.do_task(fun, *first, i);
            }
        } else {
            auto batch_functor = [fun](Iterator first, Iterator last, std::size_t i_start) {
                std::size_t i = i_start;
                for (Iterator it = first; it != last; ++it, ++i) {
                    fun(*it, i);
                }
            };

            // Distribute evenly the batches

            for (std::size_t t = 0; t < thread_pool.size(); ++t) {
                thread_pool.do_task(batch_functor, first + t * part, first + (t + 1) * part, t * part);
            }

            // Compute the remainders
            if (auto rem = n % thread_pool.size(); rem > 0) {
                std::size_t i = n - rem;
                for (Iterator it = last - rem; it < last; ++it, ++i) {
                    fun(*it, i);
                }
            }
        }
    } else {
        for (std::size_t i = 0; first != last; ++first, ++i) {
            thread_pool.do_task(fun, *first, i);
        }
    }

    thread_pool.wait();
}

// Assembly:
subq $0xc8, %rsp
movq %rsi, 0xc0(%rsp)
movq %rdx, 0xb8(%rsp)
movq %rcx, 0xb0(%rsp)
movq %rdi, 0xa8(%rsp)
movq 0xc0(%rsp), %rax
movq %rax, 0x98(%rsp)
movq 0xb8(%rsp), %rax
movq %rax, 0x90(%rsp)
movq 0x98(%rsp), %rdi
movq 0x90(%rsp), %rsi
callq 0x30000
movq %rax, 0xa0(%rsp)
movq 0xa0(%rsp), %rax
movq %rax, 0x28(%rsp)
movq 0xa8(%rsp), %rdi
callq 0x50e20
movq %rax, %rcx
movq 0x28(%rsp), %rax
xorl %edx, %edx
divq %rcx
movq %rax, 0x88(%rsp)
cmpq $0x2, 0x88(%rsp)
jae 0x48c53
movq $0x0, 0x80(%rsp)
leaq 0xc0(%rsp), %rdi
leaq 0xb8(%rsp), %rsi
callq 0x1edd0
xorb $-0x1, %al
testb $0x1, %al
jne 0x48beb
jmp 0x48c4e
movq 0xa8(%rsp), %rax
movq %rax, 0x20(%rsp)
movq 0xb0(%rsp), %rax
movq %rax, 0x78(%rsp)
leaq 0xc0(%rsp), %rdi
callq 0x1ee50
movq 0x20(%rsp), %rdi
movl (%rax), %edx
movq 0x80(%rsp), %rcx
movq 0x78(%rsp), %rsi
callq 0x48e10
leaq 0xc0(%rsp), %rdi
callq 0x1f180
movq 0x80(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x80(%rsp)
jmp 0x48bce
jmp 0x48df7
movq 0xb0(%rsp), %rax
movq %rax, 0x70(%rsp)
movq $0x0, 0x68(%rsp)
movq 0x68(%rsp), %rax
movq %rax, 0x18(%rsp)
movq 0xa8(%rsp), %rdi
callq 0x50e20
movq %rax, %rcx
movq 0x18(%rsp), %rax
cmpq %rcx, %rax
jae 0x48d26
movq 0xa8(%rsp), %rax
movq %rax, 0x10(%rsp)
movq 0x70(%rsp), %rax
movq %rax, 0x60(%rsp)
movq 0x68(%rsp), %rsi
imulq 0x88(%rsp), %rsi
leaq 0xc0(%rsp), %rdi
callq 0x50e30
movq %rax, 0x58(%rsp)
movq 0x68(%rsp), %rsi
addq $0x1, %rsi
imulq 0x88(%rsp), %rsi
leaq 0xc0(%rsp), %rdi
callq 0x50e30
movq 0x10(%rsp), %rdi
movq %rax, 0x50(%rsp)
movq 0x68(%rsp), %r8
imulq 0x88(%rsp), %r8
movq 0x60(%rsp), %rsi
movq 0x58(%rsp), %rdx
movq 0x50(%rsp), %rcx
callq 0x48ea0
movq 0x68(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x68(%rsp)
jmp 0x48c69
movq 0xa0(%rsp), %rax
movq %rax, 0x8(%rsp)
movq 0xa8(%rsp), %rdi
callq 0x50e20
movq %rax, %rcx
movq 0x8(%rsp), %rax
xorl %edx, %edx
divq %rcx
movq %rdx, 0x48(%rsp)
cmpq $0x0, 0x48(%rsp)
jbe 0x48df5
movq 0xa0(%rsp), %rax
subq 0x48(%rsp), %rax
movq %rax, 0x40(%rsp)
movq 0x48(%rsp), %rsi
leaq 0xb8(%rsp), %rdi
callq 0x50e70
movq %rax, 0x38(%rsp)
leaq 0x38(%rsp), %rdi
leaq 0xb8(%rsp), %rsi
callq 0x50ee0
movb %al, 0x37(%rsp)
leaq 0x36(%rsp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x50f30
movzbl 0x37(%rsp), %edi
callq 0x50ec0
testb $0x1, %al
jne 0x48dbb
jmp 0x48df3
leaq 0x38(%rsp), %rdi
callq 0x1ee50
movl (%rax), %esi
movq 0x40(%rsp), %rdx
leaq 0xb0(%rsp), %rdi
callq 0x48f40
leaq 0x38(%rsp), %rdi
callq 0x1f180
movq 0x40(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x40(%rsp)
jmp 0x48d87
jmp 0x48df5
jmp 0x48df7
movq 0xa8(%rsp), %rdi
callq 0x50f40
addq $0xc8, %rsp
retq
nopl (%rax)