// File: /workspace/github_cpp_makefile_star2_O2/PrzemekWirkus[P]functional-workshop/src/examples.cpp
// Function: main
int main(int argc, char *argv[]) {
    // ######### Example 1 - sorting with binary predicate #########
    {
        cout << "Example 1:" << endl;

        int Table[] = {55, -7, 3, -9, 2, -9198, -937, 1, 473};
        const int TableSize = sizeof(Table) / sizeof(int);

        // Print C-style table:
        // for_each(Table, Table + TableSize, [] (int i) { cout << i << " "; }); cout << endl;
        TABLE_PRINT();

        // ### Variation 1.1, std::less predicate
        std::less<int> normalCompare;
        bool b = normalCompare(4, 6); // 4 < 6
        bubble_sort(Table, TableSize, normalCompare);     // Sort big -> small
        TABLE_PRINT();
        // or
        bubble_sort(Table, TableSize, std::less<int>());  // Like above
        TABLE_PRINT();

        // ### Variation 1.2, reverse sorting order
        bubble_sort(Table, TableSize, std::greater<int>()); // Sort small -> big, reverse order
        TABLE_PRINT();
        // or
        bubble_sort(Table, TableSize, std::not2(std::less<int>())); // Sort small -> big, reverse order
        TABLE_PRINT();

        // ### variation 1.3, sort as if values in array are absolute
        bubble_sort(Table, TableSize, absoluteLess());
        TABLE_PRINT();
        // or in reverse order
        bubble_sort(Table, TableSize, std::not2(absoluteLess()));
        TABLE_PRINT();
    }

    // ######### Example 2 #########
    {
        cout << "Example 2:" << endl;

        vector<int> vec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
        VECTOR_PRINT();

        // ### variation 2.1
        // finds the first number in the int vector v which is less than 3
        vector<int>::reverse_iterator f = vec.rend();
        f = find_if(vec.rbegin(), vec.rend(), bind2nd(less<int>(), 3)); // bind 2nd!
        F_PRINT();

        // ### variation 2.2
        // finds the first number in the int vector v which is not less than 5
        f = std::find_if(vec.rbegin(), vec.rend(), std::bind1st(std::less<int>(), 5)); // bind 1nd!
        F_PRINT();

        // ### variation 2.3
        // finds the first number in the int vector v which is greater than 7
        f = std::find_if(vec.rbegin(), vec.rend(), std::bind2nd(std::greater<int>(), 7)); // bind 2nd!
        F_PRINT();

        // ### variation 2.4
        // finds the first number in the int vector v which is equal to 4
        f = std::find_if(vec.rbegin(), vec.rend(), std::bind1st(std::equal_to<int>(), 4)); // bind 1nd!
        F_PRINT();
    }

    // ######### Example 3 #########
    {
        // ### variation 3.1

    	vector<string> Gals = {
            string("Annabella"),
            string("Scheherazade"),
            string("Xaviera")};
        vector<string> Guys = {
            string("Bogey"),
            string("Amadeus"),
            string("Wladimir")};
        vector<string> Couples(3);

        // ### variation 3.2 transform with unary predicate
        // target == source
        std::transform(Guys.begin(),
                       Guys.end(),
                       Guys.begin(),
                        [] (string &s) {
                            for_each(begin(s), end(s),
                                [] (string::value_type &c) {
                                    if (c >= 'a' && c <= 'z') {
                                        c -= 'a' - 'A';
                                    }
                                }
                            );
                            return s;
                        });

        // Print
        for_each(Guys.begin(), Guys.end(), [] (const string &s) { cout << s << " "; }); cout << endl;

        // ### variation 3.3, transform and grab in lambda global variable as reference
        string connector = " and ";

        std::transform(Gals.begin(),
                       Gals.end(),
                       Guys.begin(),
                       Couples.begin(),
                       [&connector] (const std::string& a, const std::string& b) {
                            return a + connector + b;
                       });

        // Print
        for_each(Couples.begin(), Couples.end(), [] (const string &s) { cout << s << endl; });

    }

    return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x138, %rsp            # imm = 0x138
movq 0x3c36(%rip), %rbx      # 0x4fd8
leaq 0x1c89(%rip), %rsi      # 0x3032
movq %rbx, %rdi
callq 0x10e0
movq %rax, %rdi
callq 0x1080
movaps 0x1d10(%rip), %xmm0     # 0x30d0
movaps %xmm0, 0x40(%rsp)
movaps 0x1cf4(%rip), %xmm0     # 0x30c0
movaps %xmm0, 0x30(%rsp)
movl $0x1d9, 0x50(%rsp)      # imm = 0x1D9
xorl %r15d, %r15d
leaq 0x1c3e(%rip), %r14      # 0x3021
cmpq $0x24, %r15
je 0x1407
movl 0x30(%rsp,%r15), %esi
movq %rbx, %rdi
callq 0x1170
movq %rax, %rdi
movq %r14, %rsi
callq 0x10e0
addq $0x4, %r15
jmp 0x13e3
movq 0x3bca(%rip), %rbx      # 0x4fd8
movq %rbx, %rdi
callq 0x1080
leaq 0x30(%rsp), %rdi
pushq $0x9
popq %rsi
leaq 0xc0(%rsp), %rdx
callq 0x1bb3
xorl %r15d, %r15d
leaq 0x1bec(%rip), %r14      # 0x3021
cmpq $0x24, %r15
je 0x1459
movl 0x30(%rsp,%r15), %esi
movq %rbx, %rdi
callq 0x1170
movq %rax, %rdi
movq %r14, %rsi
callq 0x10e0
addq $0x4, %r15
jmp 0x1435
movq 0x3b78(%rip), %rbx      # 0x4fd8
movq %rbx, %rdi
callq 0x1080
leaq 0x30(%rsp), %rdi
pushq $0x9
popq %rsi
leaq 0x10(%rsp), %rdx
callq 0x1bb3
xorl %r15d, %r15d
leaq 0x1b9d(%rip), %r14      # 0x3021
cmpq $0x24, %r15
je 0x14a8
movl 0x30(%rsp,%r15), %esi
movq %rbx, %rdi
callq 0x1170
movq %rax, %rdi
movq %r14, %rsi
callq 0x10e0
addq $0x4, %r15
jmp 0x1484
movq 0x3b29(%rip), %rbx      # 0x4fd8
movq %rbx, %rdi
callq 0x1080
leaq 0x30(%rsp), %rdi
pushq $0x9
popq %rsi
leaq 0x10(%rsp), %rdx
callq 0x1bf2
xorl %r15d, %r15d
leaq 0x1b4e(%rip), %r14      # 0x3021
cmpq $0x24, %r15
je 0x14f7
movl 0x30(%rsp,%r15), %esi
movq %rbx, %rdi
callq 0x1170
movq %rax, %rdi
movq %r14, %rsi
callq 0x10e0
addq $0x4, %r15
jmp 0x14d3
movq 0x3ada(%rip), %rbx      # 0x4fd8
movq %rbx, %rdi
callq 0x1080
leaq 0x30(%rsp), %rdi
pushq $0x9
popq %rsi
leaq 0x10(%rsp), %rdx
callq 0x1c31
xorl %r15d, %r15d
leaq 0x1aff(%rip), %r14      # 0x3021
cmpq $0x24, %r15
je 0x1546
movl 0x30(%rsp,%r15), %esi
movq %rbx, %rdi
callq 0x1170
movq %rax, %rdi
movq %r14, %rsi
callq 0x10e0
addq $0x4, %r15
jmp 0x1522
movq 0x3a8b(%rip), %rbx      # 0x4fd8
movq %rbx, %rdi
callq 0x1080
leaq 0x30(%rsp), %rdi
pushq $0x9
popq %rsi
leaq 0x10(%rsp), %rdx
callq 0x1c70
xorl %r15d, %r15d
leaq 0x1ab0(%rip), %r14      # 0x3021
cmpq $0x24, %r15
je 0x1595
movl 0x30(%rsp,%r15), %esi
movq %rbx, %rdi
callq 0x1170
movq %rax, %rdi
movq %r14, %rsi
callq 0x10e0
addq $0x4, %r15
jmp 0x1571
movq 0x3a3c(%rip), %rbx      # 0x4fd8
movq %rbx, %rdi
callq 0x1080
leaq 0x30(%rsp), %rdi
pushq $0x9
popq %rsi
leaq 0x10(%rsp), %rdx
callq 0x1ccb
xorl %r15d, %r15d
leaq 0x1a61(%rip), %r14      # 0x3021
cmpq $0x24, %r15
je 0x15e4
movl 0x30(%rsp,%r15), %esi
movq %rbx, %rdi
callq 0x1170
movq %rax, %rdi
movq %r14, %rsi
callq 0x10e0
addq $0x4, %r15
jmp 0x15c0
movq 0x39ed(%rip), %rbx      # 0x4fd8
movq %rbx, %rdi
callq 0x1080
leaq 0x1a43(%rip), %rsi      # 0x303d
movq %rbx, %rdi
callq 0x10e0
movq %rax, %rdi
callq 0x1080
leaq 0x1ad3(%rip), %rsi      # 0x30e4
pushq $0x13
popq %rdx
leaq 0x30(%rsp), %rax
movq %rdx, %rcx
movq %rax, %rdi
rep  movsl (%rsi), %es:(%rdi)
leaq 0x10(%rsp), %rdi
leaq 0xc0(%rsp), %rcx
movq %rax, %rsi
callq 0x1d26
movq 0x10(%rsp), %r15
movq 0x18(%rsp), %r12
movq 0x3991(%rip), %rbx      # 0x4fd8
leaq 0x19d3(%rip), %r14      # 0x3021
cmpq %r12, %r15
je 0x166f
movl (%r15), %esi
movq %rbx, %rdi
callq 0x1170
movq %rax, %rdi
movq %r14, %rsi
callq 0x10e0
addq $0x4, %r15
jmp 0x164e
movq 0x3962(%rip), %rdi      # 0x4fd8
callq 0x1080
movq 0x10(%rsp), %rax
movq 0x18(%rsp), %rcx
leaq 0x130(%rsp), %rsi
movq %rcx, (%rsi)
leaq 0x128(%rsp), %rdx
movq %rax, (%rdx)
leaq 0x30(%rsp), %rdi
movabsq $0x300000000, %rcx      # imm = 0x300000000
callq 0x1d5c
movq 0x30(%rsp), %rax
movl -0x4(%rax), %esi
movq 0x391a(%rip), %rdi      # 0x4fd8
callq 0x1170
movq %rax, %rdi
callq 0x1080
movq 0x10(%rsp), %rax
movq 0x18(%rsp), %rcx
leaq 0x120(%rsp), %rsi
movq %rcx, (%rsi)
leaq 0x118(%rsp), %rdx
movq %rax, (%rdx)
leaq 0x30(%rsp), %rdi
movabsq $0x500000000, %rcx      # imm = 0x500000000
callq 0x1d86
movq 0x30(%rsp), %rax
movl -0x4(%rax), %esi
movq 0x38ca(%rip), %rdi      # 0x4fd8
callq 0x1170
movq %rax, %rdi
callq 0x1080
movq 0x10(%rsp), %rax
movq 0x18(%rsp), %rcx
leaq 0x110(%rsp), %rsi
movq %rcx, (%rsi)
leaq 0x108(%rsp), %rdx
movq %rax, (%rdx)
leaq 0x30(%rsp), %rdi
movabsq $0x700000000, %rcx      # imm = 0x700000000
callq 0x1db0
movq 0x30(%rsp), %rax
movl -0x4(%rax), %esi
movq 0x387a(%rip), %rdi      # 0x4fd8
callq 0x1170
movq %rax, %rdi
callq 0x1080
movq 0x10(%rsp), %rax
movq 0x18(%rsp), %rcx
leaq 0x100(%rsp), %rsi
movq %rcx, (%rsi)
leaq 0xf8(%rsp), %rdx
movq %rax, (%rdx)
leaq 0x30(%rsp), %rdi
movabsq $0x400000000, %rcx      # imm = 0x400000000
callq 0x1dda
movq 0x30(%rsp), %rax
movl -0x4(%rax), %esi
movq 0x382a(%rip), %rdi      # 0x4fd8
callq 0x1170
movq %rax, %rdi
callq 0x1080
leaq 0x10(%rsp), %rdi
callq 0x1f18
leaq 0x187c(%rip), %rsi      # 0x3048
leaq 0x30(%rsp), %r14
leaq 0x10(%rsp), %rdx
movq %r14, %rdi
callq 0x1050
leaq 0x50(%rsp), %r15
leaq 0x1868(%rip), %rsi      # 0x3052
leaq 0xc0(%rsp), %rdx
movq %r15, %rdi
callq 0x1050
leaq 0x70(%rsp), %r15
leaq 0x1859(%rip), %rsi      # 0x305f
leaq 0x90(%rsp), %rdx
movq %r15, %rdi
callq 0x1050
leaq 0xe0(%rsp), %rdi
leaq 0x30(%rsp), %rsi
pushq $0x3
popq %rdx
leaq 0xa8(%rsp), %rcx
callq 0x1e04
pushq $0x40
popq %rbx
leaq (%rsp,%rbx), %rdi
addq $0x30, %rdi
callq 0x1070
addq $-0x20, %rbx
cmpq $-0x20, %rbx
jne 0x1836
leaq 0x1813(%rip), %rsi      # 0x3067
leaq 0x30(%rsp), %r14
leaq 0x10(%rsp), %rdx
movq %r14, %rdi
callq 0x1050
leaq 0x50(%rsp), %r15
leaq 0x17fb(%rip), %rsi      # 0x306d
leaq 0xc0(%rsp), %rdx
movq %r15, %rdi
callq 0x1050
leaq 0x70(%rsp), %r15
leaq 0x17e7(%rip), %rsi      # 0x3075
leaq 0xa8(%rsp), %rdx
movq %r15, %rdi
callq 0x1050
leaq 0x90(%rsp), %rdi
leaq 0x30(%rsp), %rsi
pushq $0x3
popq %rdx
leaq 0xf(%rsp), %rcx
callq 0x1e04
pushq $0x40
popq %rbx
leaq (%rsp,%rbx), %rdi
addq $0x30, %rdi
callq 0x1070
addq $-0x20, %rbx
cmpq $-0x20, %rbx
jne 0x18bb
leaq 0xa8(%rsp), %rdi
pushq $0x3
popq %rsi
leaq 0x30(%rsp), %rdx
callq 0x1e3e
movq 0x90(%rsp), %rbx
movq 0x98(%rsp), %r15
leaq 0x30(%rsp), %r14
cmpq %r15, %rbx
je 0x194d
movq (%rbx), %rax
movq 0x8(%rbx), %rcx
xorl %edx, %edx
cmpq %rdx, %rcx
je 0x1929
movb (%rax,%rdx), %sil
leal -0x61(%rsi), %edi
cmpb $0x19, %dil
ja 0x1924
addb $-0x20, %sil
movb %sil, (%rax,%rdx)
incq %rdx
jmp 0x190a
movq %r14, %rdi
movq %rbx, %rsi
callq 0x1120
movq %rbx, %rdi
movq %r14, %rsi
callq 0x1100
movq %r14, %rdi
callq 0x1070
addq $0x20, %rbx
jmp 0x18fc
movq 0x90(%rsp), %rbx
movq 0x98(%rsp), %r12
movq 0x3674(%rip), %r14      # 0x4fd8
leaq 0x16b6(%rip), %r15      # 0x3021
cmpq %r12, %rbx
je 0x198c
movq %r14, %rdi
movq %rbx, %rsi
callq 0x10c0
movq %rax, %rdi
movq %r15, %rsi
callq 0x10e0
addq $0x20, %rbx
jmp 0x196b
movq 0x3645(%rip), %rdi      # 0x4fd8
callq 0x1080
leaq 0x16df(%rip), %rsi      # 0x307e
leaq 0xc0(%rsp), %rdi
leaq 0x30(%rsp), %rdx
callq 0x1050
movq 0xe0(%rsp), %rbx
movq 0xe8(%rsp), %r13
movq 0x90(%rsp), %r14
movq 0xa8(%rsp), %r15
leaq 0x30(%rsp), %r12
leaq 0x10(%rsp), %rbp
cmpq %r13, %rbx
je 0x1a2a
movq %r12, %rdi
movq %rbx, %rsi
leaq 0xc0(%rsp), %rdx
callq 0x253d
movq %rbp, %rdi
movq %r12, %rsi
movq %r14, %rdx
callq 0x251e
movq %r12, %rdi
callq 0x1070
movq %r15, %rdi
movq %rbp, %rsi
callq 0x1100
movq %rbp, %rdi
callq 0x1070
addq $0x20, %rbx
addq $0x20, %r14
addq $0x20, %r15
jmp 0x19db
movq 0xa8(%rsp), %rbx
movq 0xb0(%rsp), %r15
movq 0x3597(%rip), %r14      # 0x4fd8
cmpq %r15, %rbx
je 0x1a5f
movq %r14, %rdi
movq %rbx, %rsi
callq 0x10c0
movq %rax, %rdi
callq 0x1080
addq $0x20, %rbx
jmp 0x1a41
leaq 0xc0(%rsp), %rdi
callq 0x1070
leaq 0xa8(%rsp), %rdi
callq 0x1e90
leaq 0x90(%rsp), %rdi
callq 0x1e90
leaq 0xe0(%rsp), %rdi
callq 0x1e90
xorl %eax, %eax
addq $0x138, %rsp            # imm = 0x138
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x1b72
jmp 0x1b72
movq %rax, %rbx
jmp 0x1b82
movq %rax, %rbx
pushq $0x40
popq %r14
leaq (%rsp,%r14), %rdi
addq $0x30, %rdi
callq 0x1070
addq $-0x20, %r14
cmpq $-0x20, %r14
jne 0x1ac0
jmp 0x1b8f
jmp 0x1ade
movq %rax, %rbx
addq $-0x20, %r15
movq %r15, %rdi
callq 0x1070
cmpq %r14, %r15
jne 0x1ae1
jmp 0x1b8f
movq %rax, %rbx
jmp 0x1b8f
movq %rax, %rbx
pushq $0x40
popq %r14
leaq (%rsp,%r14), %rdi
addq $0x30, %rdi
callq 0x1070
addq $-0x20, %r14
cmpq $-0x20, %r14
jne 0x1b06
jmp 0x1bab
jmp 0x1b24
movq %rax, %rbx
addq $-0x20, %r15
movq %r15, %rdi
callq 0x1070
cmpq %r14, %r15
jne 0x1b27
jmp 0x1bab
jmp 0x1b46
jmp 0x1b9e
jmp 0x1b9e
jmp 0x1b9e
jmp 0x1b9e
jmp 0x1b9e
movq %rax, %rbx
jmp 0x1bab
jmp 0x1b9e
jmp 0x1b60
movq %rax, %rbx
leaq 0x30(%rsp), %rdi
callq 0x1070
jmp 0x1b63
jmp 0x1b72
movq %rax, %rbx
leaq 0xc0(%rsp), %rdi
callq 0x1070
jmp 0x1b75
movq %rax, %rbx
leaq 0xa8(%rsp), %rdi
callq 0x1e90
leaq 0x90(%rsp), %rdi
callq 0x1e90
leaq 0xe0(%rsp), %rdi
callq 0x1e90
jmp 0x1bab
movq %rax, %rbx
leaq 0x10(%rsp), %rdi
callq 0x1f18
movq %rbx, %rdi
callq 0x1180