// File: /workspace/github_cpp_makefile_star2_O2/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
pushq %rax
movq (%rdi), %rax
movq 0x8(%rdi), %rcx
subq %rax, %rcx
sarq $0x2, %rcx
addl %edx, %edx
xorl %r14d, %r14d
pushq $0x1
popq %rdi
xorl %r15d, %r15d
xorl %r12d, %r12d
xorl %r8d, %r8d
movl %r8d, %r8d
cmpq %r8, %rcx
jbe 0x21c9
cmpl $0x0, (%rax,%r8,4)
jne 0x21be
testq %r8, %r8
jne 0x21c6
movq (%rsi), %r9
movq (%r9), %r10
movq 0x8(%r9), %r11
subq %r10, %r11
sarq $0x3, %r11
xorl %ebx, %ebx
xorl %r13d, %r13d
movl %r13d, %r13d
cmpq %r13, %r11
jbe 0x2148
cmpl $0x1, 0x4(%r10,%r13,8)
adcl $0x0, %ebx
incl %r13d
jmp 0x2132
testl %ebx, %ebx
jne 0x21c6
xorl %r10d, %r10d
movl %edi, %r11d
movl %r11d, %r11d
cmpq %r11, %rcx
jbe 0x21a2
movl (%rax,%r11,4), %ebx
testl %ebx, %ebx
je 0x219a
cmpl $0x1, %ebx
jne 0x219d
imulq $0x18, %r11, %r12
movq (%r9,%r12), %rbx
movq 0x8(%r9,%r12), %r12
subq %rbx, %r12
sarq $0x3, %r12
xorl %r13d, %r13d
movl %r13d, %r13d
cmpq %r13, %r12
jbe 0x219d
cmpl $0x0, 0x4(%rbx,%r13,8)
jne 0x2195
cmpl $0x0, (%rbx,%r13,8)
jne 0x219a
incl %r13d
jmp 0x217e
incl %r10d
incl %r11d
jmp 0x2152
cmpl %edx, %r10d
movzbl %r14b, %r14d
cmovgel %edi, %r14d
movzbl %r15b, %r15d
cmovll %edi, %r15d
movb $0x1, %r12b
testb $0x1, %r14b
jne 0x21c9
incl %r8d
jmp 0x20fc
movb $0x1, %r14b
xorl %esi, %esi
xorl %edi, %edi
movl %edi, %edi
cmpq %rdi, %rcx
jbe 0x21e6
xorl %r8d, %r8d
cmpl $0x1, (%rax,%rdi,4)
sete %r8b
addl %r8d, %esi
incl %edi
jmp 0x21cd
movl %edx, %eax
orl $0x1, %eax
cmpl %edx, %esi
setg %cl
movl %r15d, %edx
andb $0x1, %dl
movzbl %dl, %edx
addl %esi, %edx
cmpl %eax, %edx
sete %r13b
orb %cl, %r13b
movq 0x4dcd(%rip), %rbx      # 0x6fd8
leaq 0x1f1f(%rip), %rsi      # 0x4131
movq %rbx, %rdi
callq 0x1100
movzbl %r12b, %esi
andl $0x1, %esi
movq %rax, %rdi
callq 0x11c0
movq %rax, %rdi
callq 0x1090
leaq 0x1f07(%rip), %rsi      # 0x413f
movq %rbx, %rdi
callq 0x1100
movzbl %r15b, %esi
andl $0x1, %esi
movq %rax, %rdi
callq 0x11c0
movq %rax, %rdi
callq 0x1090
leaq 0x1eeb(%rip), %rsi      # 0x4149
movq %rbx, %rdi
callq 0x1100
movzbl %r14b, %r14d
movl %r14d, %esi
andl $0x1, %esi
movq %rax, %rdi
callq 0x11c0
movq %rax, %rdi
callq 0x1090
leaq 0x1ecc(%rip), %rsi      # 0x4153
movq %rbx, %rdi
callq 0x1100
movzbl %r13b, %ebx
movq %rax, %rdi
movl %ebx, %esi
callq 0x11c0
movq %rax, %rdi
callq 0x1090
andb $0x1, %r14b
movzbl %r14b, %eax
addl %ebx, %eax
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq