// File: /workspace/github_cpp_makefile_star2_O3/NeoResearch[P]dbft3-spork-detect/main.cpp
// Function: getCommitCountFromCancels(std::vector<int, std::allocator<int>>, std::vector<std::vector<std::pair<int, int>, std::allocator<std::pair<int, int>>>, std::allocator<std::vector<std::pair<int, int>, std::allocator<std::pair<int, int>>>>>, int)
int getCommitCountFromCancels(vector<int> cancels, vector<vector<pair<int, int>>> selections, int f)
{
    // compute commit counts
    // commit zero (X_0) may be issued when any zero is present
    // commit one (X_1) may be issued when 2*f+1 ones is present

    bool hasCommitOne = false;
    bool hasCommitZero = false; // a little bit more complex

    bool hasBadZero = false;     // bad zero condition, may help commit one too... BadZero + 2 ones (N=4).. when 1 is faulty
    bool hasTrustedZero = false; // trusted zero should be the same as BadZero above...

    // look for zero commits
    for (unsigned i = 0; i < cancels.size(); i++)
    {
        // if not cancel zero, proceed...
        if (cancels[i] != 0)
            continue;

        // found POSSIBLE X_0

        // must verify primary edge case
        if (i == 0) // may be tricky (mandatory for replica 0 to issue cancel 0)
        {
            // if primary 0 has another independent confirmation, then it's good
            int confirmations = 0;
            // selections contains only prepare responses (not request!)
            for (unsigned k = 0; k < selections[0].size(); k++)
                if ((selections[0][k].second == 0)) //&& (selections[0][k].first != 0)) // a zero from someone else
                    confirmations++;                // including itself
            if (confirmations >= 1)                 // more than itself
            {
                hasCommitZero = true;
                break; // guaranteed
            }
            else
            {
                // only itself...
                hasTrustedZero = true;
                // one may received this "Cancel 0" with two other Cancel 1 (for 2f+1 = 3)
                // must find in ALL other possible Cancel 1, if it could provide evidence that ONE NON-FAULTY zero exists.
                // let's go.
                int countConfirmed = 0; // must have at least 2f OTHERS including a VALID zero (a non-faulty zero)
                for (unsigned j = 1; j < cancels.size(); j++)
                {
                    if (cancels[j] == 0) // OK, if you are lucky to receive this one...
                        countConfirmed++;
                    else
                    {
                        // not so lucky this time...
                        if (cancels[j] == 1) // any good option must include extra f+1
                        {
                            for (unsigned k = 0; k < selections[j].size(); k++)
                                if ((selections[j][k].second == 0) && (selections[j][k].first != 0))
                                {
                                    countConfirmed++;
                                    break;
                                }
                        }
                    }
                } // for j=1 to N-1

                // one needs this zero + 2f good ones (TODO: confirm for 7 nodes... maybe this is N-2... for 4 its same as 2f+1.. who knows)
                if (countConfirmed >= 2 * f)
                    hasCommitZero = true;
                else
                    hasBadZero = true; // bad zero may help commit one, perhaps!
            }
        }                         // end replica 0 for cancel 0
        else                      // this is trivial, not primary, thus certain value.
            hasCommitZero = true; // this one is certainly good

        // if found zero already, breaks search
        if (hasCommitZero)
            break;
    } // end looking for zeros

    // look for one commits
    int ones = 0;
    for (unsigned i = 0; i < cancels.size(); i++)
        if (cancels[i] == 1)
            ones++;
    if (ones >= 2 * f + 1) // found a possible X_1
        hasCommitOne = true;

    // special case: two one's and one BadZero (N=4) and a failed node...
    if (ones + hasBadZero == 2 * f + 1) // since ones are never in primary when BadZero is, this is good.
        hasCommitOne = true;

    cout << "trustedzero: " << hasTrustedZero << endl;
    cout << "badzero: " << hasBadZero << endl;
    cout << "commit0: " << hasCommitZero << endl;
    cout << "commit1: " << hasCommitOne << endl;

    return hasCommitZero + hasCommitOne;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x18, %rsp
movq (%rdi), %rax
movq 0x8(%rdi), %rdi
movq %rdi, %rcx
subq %rax, %rcx
je 0x3867
movq %rdi, -0x38(%rbp)
sarq $0x2, %rcx
movq %rdx, -0x30(%rbp)
leal (%rdx,%rdx), %r8d
xorl %r9d, %r9d
xorl %r14d, %r14d
xorl %r12d, %r12d
xorl %r15d, %r15d
cmpl $0x0, (%rax,%r9,4)
jne 0x3859
testl %r9d, %r9d
jne 0x3874
movq (%rsi), %r11
movq (%r11), %rdi
movq 0x8(%r11), %rbx
subq %rdi, %rbx
je 0x37cf
sarq $0x3, %rbx
xorl %r10d, %r10d
xorl %r13d, %r13d
cmpl $0x1, 0x4(%rdi,%r10,8)
adcl $0x0, %r13d
incq %r10
movl %r10d, %edx
cmpq %rdx, %rbx
ja 0x37b1
testl %r13d, %r13d
jne 0x3874
xorl %ebx, %ebx
cmpq $0x2, %rcx
jb 0x3838
xorl %ebx, %ebx
movl $0x1, %r14d
movl $0x1, %edi
movl (%rax,%rdi,4), %edx
testl %edx, %edx
je 0x382b
cmpl $0x1, %edx
jne 0x382d
leaq (%rdi,%rdi,2), %rdx
movq (%r11,%rdx,8), %r13
movq 0x8(%r11,%rdx,8), %rdi
subq %r13, %rdi
je 0x382d
sarq $0x3, %rdi
movl $0x1, %r10d
xorl %edx, %edx
cmpl $0x0, 0x4(%r13,%rdx,8)
jne 0x381e
cmpl $0x0, (%r13,%rdx,8)
jne 0x382b
movl %r10d, %edx
incl %r10d
cmpq %rdx, %rdi
ja 0x380e
jmp 0x382d
incl %ebx
incl %r14d
movq %r14, %rdi
cmpq %r14, %rcx
ja 0x37e4
cmpl %r8d, %ebx
movzbl %r15b, %r15d
movl $0x1, %edx
cmovgel %edx, %r15d
movzbl %r12b, %r12d
cmovll %edx, %r12d
movb $0x1, %r14b
testb $0x1, %r15b
jne 0x3877
incl %r9d
cmpq %r9, %rcx
ja 0x3784
jmp 0x3877
xorl %r14d, %r14d
xorl %r12d, %r12d
xorl %r15d, %r15d
xorl %esi, %esi
jmp 0x38a6
movb $0x1, %r15b
cmpq %rax, -0x38(%rbp)
je 0x38a0
xorl %r8d, %r8d
xorl %esi, %esi
movq -0x30(%rbp), %rdx
xorl %edi, %edi
cmpl $0x1, (%rax,%r8,4)
sete %dil
addl %edi, %esi
incq %r8
movl %r8d, %edi
cmpq %rdi, %rcx
ja 0x3886
jmp 0x38a6
xorl %esi, %esi
movq -0x30(%rbp), %rdx
movl %edx, %eax
addl %edx, %eax
leal 0x1(,%rdx,2), %ecx
cmpl %eax, %esi
setg %al
movl %r12d, %edx
andb $0x1, %dl
movzbl %dl, %edx
addl %esi, %edx
cmpl %ecx, %edx
sete %r13b
orb %al, %r13b
movq 0x5707(%rip), %rbx      # 0x8fd8
leaq 0x2859(%rip), %rsi      # 0x6131
movl $0xd, %edx
movq %rbx, %rdi
callq 0x2170
movzbl %r14b, %esi
andl $0x1, %esi
movq %rbx, %rdi
callq 0x2200
movq %rax, %r14
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r14, %rdi
movl $0xa, %esi
callq 0x2120
movsbl %al, %esi
movq %r14, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20e0
leaq 0x281a(%rip), %rsi      # 0x613f
movl $0x9, %edx
movq %rbx, %rdi
callq 0x2170
movzbl %r12b, %esi
andl $0x1, %esi
movq %rbx, %rdi
callq 0x2200
movq %rax, %r14
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r14, %rdi
movl $0xa, %esi
callq 0x2120
movsbl %al, %esi
movq %r14, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20e0
leaq 0x27d7(%rip), %rsi      # 0x6149
movl $0x9, %edx
movq %rbx, %rdi
callq 0x2170
movzbl %r15b, %r15d
movl %r15d, %esi
andl $0x1, %esi
movq %rbx, %rdi
callq 0x2200
movq %rax, %r14
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r14, %rdi
movl $0xa, %esi
callq 0x2120
movsbl %al, %esi
movq %r14, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20e0
leaq 0x2791(%rip), %rsi      # 0x6153
movl $0x9, %edx
movq %rbx, %rdi
callq 0x2170
movzbl %r13b, %r14d
movq %rbx, %rdi
movl %r14d, %esi
callq 0x2200
movq %rax, %rbx
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x2120
movsbl %al, %esi
movq %rbx, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20e0
andb $0x1, %r15b
movzbl %r15b, %eax
addl %r14d, %eax
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq