// File: ridiculousfish[P]docopt_fish/docopt_fish.cpp
// Function: docopt_fish::uniqueize_options(std::vector<docopt_fish::option_t, std::allocator<docopt_fish::option_t>>*, bool, std::vector<docopt_fish::error_t, std::allocator<docopt_fish::error_t>>*)
static void uniqueize_options(option_list_t *options, bool error_on_duplicates,
                              error_list_t *errors) {
    // Maintain an outer cursor. For each option, loop over the remainder,
    // deleting those that share
    // a name
    // Grab the best description as we go
    // We "delete" from the middle of the vector by moving the last element into
    // the slot, and then
    // decrementing the length
    size_t options_count = options->size();  // note this changes as we go
    for (size_t outer = 0; outer < options_count; outer++) {
        const option_t representative = options->at(outer);

        // Find all options that share a name with this representative
        // Determine which one is best
        for (size_t match_cursor = outer + 1; match_cursor < options_count; match_cursor++) {
            option_t *candidate = &options->at(match_cursor);
            if (!representative.has_same_name(*candidate)) {
                continue;
            }

            // Ok, we know that candidate has the same name as the best match
            // Generate an error if we're supposed to
            // TODO: verify agreement in the parameters, etc.
            // Then we copy the description over if it's better, then "erase" the
            // candidate
            // That will cause us to skip over it later
            if (error_on_duplicates) {
                // Generate an error, and then continue on
                append_token_error(errors, candidate->best_name(),
                                    error_option_duplicated_in_options_section,
                                    "Option specified more than once");
            }

            // "Delete" candidate by overwriting it with the last value, and
            // decrementing the count
            *candidate = std::move(options->back());
            options->pop_back();
            options_count -= 1;
            match_cursor -= 1;  // have to re-evaluate this value
        }
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xc0, %rsp
movb %sil, %al
movq %rdi, -0x8(%rbp)
andb $0x1, %al
movb %al, -0x9(%rbp)
movq %rdx, -0x18(%rbp)
movq -0x8(%rbp), %rdi
callq 0xcab0
movq %rax, -0x20(%rbp)
movq $0x0, -0x28(%rbp)
movq -0x28(%rbp), %rax
cmpq -0x20(%rbp), %rax
jae 0xb895
movq -0x8(%rbp), %rdi
movq -0x28(%rbp), %rsi
callq 0xcbe0
movq %rax, %rsi
leaq -0xa8(%rbp), %rdi
movl $0x80, %edx
callq 0x8270
movq -0x28(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xb0(%rbp)
movq -0xb0(%rbp), %rax
cmpq -0x20(%rbp), %rax
jae 0xb882
movq -0x8(%rbp), %rdi
movq -0xb0(%rbp), %rsi
callq 0xcbe0
movq %rax, -0xb8(%rbp)
movq -0xb8(%rbp), %rsi
leaq -0xa8(%rbp), %rdi
callq 0x1f300
testb $0x1, %al
jne 0xb7ef
jmp 0xb86b
testb $0x1, -0x9(%rbp)
je 0xb827
movq -0x18(%rbp), %rax
movq %rax, -0xc0(%rbp)
movq -0xb8(%rbp), %rdi
callq 0x1f390
movq -0xc0(%rbp), %rdi
movq %rax, %rsi
movl $0xd, %edx
leaq 0x4059e(%rip), %rcx     # 0x4bdc0
callq 0x8e80
movq -0x8(%rbp), %rdi
callq 0xcc20
movq %rax, %rsi
movq -0xb8(%rbp), %rdi
movl $0x7c, %edx
callq 0x8270
movq -0x8(%rbp), %rdi
callq 0x1f410
movq -0x20(%rbp), %rax
subq $0x1, %rax
movq %rax, -0x20(%rbp)
movq -0xb0(%rbp), %rax
subq $0x1, %rax
movq %rax, -0xb0(%rbp)
movq -0xb0(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xb0(%rbp)
jmp 0xb7ae
jmp 0xb884
movq -0x28(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x28(%rbp)
jmp 0xb770
addq $0xc0, %rsp
popq %rbp
retq
nop