// File: /workspace/github_cpp_makefile_star2_O1/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
sarq $0x2, %rcx
xorl %r8d, %r8d
cmpq %rax, %rdi
je 0x3858
movq %rdi, -0x38(%rbp)
movq %rdx, -0x40(%rbp)
addl %edx, %edx
movl %edx, -0x2c(%rbp)
xorl %r14d, %r14d
xorl %r15d, %r15d
xorl %r11d, %r11d
movq %rsi, %rdx
cmpl $0x0, (%rax,%r8,4)
je 0x3762
movl %r11d, %r12d
jmp 0x3842
movb $0x1, %r12b
testl %r8d, %r8d
jne 0x3839
movq (%rdx), %rbx
movq (%rbx), %r10
movq 0x8(%rbx), %r9
movb $0x1, %r12b
movb $0x1, %r13b
subq %r10, %r9
je 0x37a7
sarq $0x3, %r9
xorl %edi, %edi
xorl %r13d, %r13d
cmpl $0x1, 0x4(%r10,%rdi,8)
adcl $0x0, %r13d
incq %rdi
movl %edi, %esi
cmpq %rsi, %r9
ja 0x378c
testl %r13d, %r13d
sete %r13b
testb %r13b, %r13b
je 0x3834
xorl %r14d, %r14d
cmpq $0x2, %rcx
jb 0x3818
xorl %r14d, %r14d
movl $0x1, %r12d
movl $0x1, %edi
movl (%rax,%rdi,4), %esi
testl %esi, %esi
je 0x380a
cmpl $0x1, %esi
jne 0x380d
leaq (%rdi,%rdi,2), %rsi
movq (%rbx,%rsi,8), %r9
movq 0x8(%rbx,%rsi,8), %r10
subq %r9, %r10
je 0x380d
sarq $0x3, %r10
movl $0x1, %edi
xorl %esi, %esi
cmpl $0x0, 0x4(%r9,%rsi,8)
jne 0x37ff
cmpl $0x0, (%r9,%rsi,8)
jne 0x380a
movl %edi, %esi
incl %edi
cmpq %rsi, %r10
ja 0x37f0
jmp 0x380d
incl %r14d
incl %r12d
movq %r12, %rdi
cmpq %r12, %rcx
ja 0x37c7
cmpl -0x2c(%rbp), %r14d
movzbl %r11b, %r12d
movl $0x1, %esi
cmovgel %esi, %r12d
movzbl %r15b, %r15d
cmovll %esi, %r15d
movb $0x1, %r14b
testb %r13b, %r13b
je 0x384e
movl %r12d, %r11d
testb $0x1, %r12b
jne 0x384e
incl %r8d
cmpq %r8, %rcx
ja 0x3753
movq -0x40(%rbp), %rdx
movq -0x38(%rbp), %rdi
jmp 0x3861
xorl %r12d, %r12d
xorl %r15d, %r15d
xorl %r14d, %r14d
cmpq %rax, %rdi
je 0x3885
xorl %edi, %edi
xorl %esi, %esi
xorl %r8d, %r8d
cmpl $0x1, (%rax,%rdi,4)
sete %r8b
addl %r8d, %esi
incq %rdi
movl %edi, %r8d
cmpq %r8, %rcx
ja 0x386a
jmp 0x3887
xorl %esi, %esi
movl %edx, %eax
addl %edx, %eax
leal 0x1(,%rdx,2), %ecx
cmpl %eax, %esi
setg %al
movl %r15d, %edx
andb $0x1, %dl
movzbl %dl, %edx
addl %esi, %edx
cmpl %ecx, %edx
sete %r13b
orb %al, %r13b
movq 0x5726(%rip), %rbx      # 0x8fd8
leaq 0x2878(%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 0x2839(%rip), %rsi      # 0x613f
movl $0x9, %edx
movq %rbx, %rdi
callq 0x2170
movzbl %r15b, %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 0x27f6(%rip), %rsi      # 0x6149
movl $0x9, %edx
movq %rbx, %rdi
callq 0x2170
movzbl %r12b, %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 0x27b0(%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