// File: /workspace/github_cpp_makefile_star2_O2/iZhangHui[P]CppPrimer/CH19_SpecializedToolsAndTechniques/examples/calc.cc
// Function: main
int main()
{
	function<int(int, int)> f1 = add;      // function pointer
	function<int(int, int)> f2 = divide(); // callable class type
	function<int(int, int)> f3 = [](int i, int j) // lambda
	                             { return i * j; };
	cout << f1(4,2) << endl; // prints 6
	cout << f2(4,2) << endl; // prints 2
	cout << f3(4,2) << endl; // prints 8

	// table of callable objects corresponding to each binary operator
	// all the callables must take two ints and return an int
	// an element can be a function pointer, function object, or lambda
	map<string, function<int(int, int)>> binops = {
		{"+", add},                  // function pointer
		{"-", std::minus<int>()},    // library function object
		{"/",  divide()},            // user-defined function object
		{"*", [](int i, int j) { return i * j; }}, // unnamed lambda
		{"%", mod} };                // named lambda object

	cout << binops["+"](10, 5) << endl; // calls add(10, 5)
	cout << binops["-"](10, 5) << endl; // uses the call operator of the minus<int> object
	cout << binops["/"](10, 5) << endl; // uses the call operator of the divide object
	cout << binops["*"](10, 5) << endl; // calls the lambda function object
	cout << binops["%"](10, 5) << endl; // calls the lambda function object

	// memp can point to either shift operation in ShiftOps
	// memp points to the Lshift member
	function<int (ShiftOps*, int, int)> memp = &ShiftOps::Lshift;  

	ShiftOps shift(cout);      // declare an object to which to bind the member pointer
	binops.insert({"<<", bind(memp, &shift, _1, _2)}); 
	cout << binops["<<"](10, 5) << endl; // calls member function
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %rbx
subq $0x228, %rsp            # imm = 0x228
leaq -0x240(%rbp), %rdi
andq $0x0, 0x8(%rdi)
leaq -0x2c(%rip), %rax       # 0x22ec
movq %rax, (%rdi)
leaq 0xbba(%rip), %rax       # 0x2edc
movq %rax, 0x18(%rdi)
leaq 0xbbd(%rip), %rax       # 0x2eea
movq %rax, 0x10(%rdi)
xorps %xmm0, %xmm0
movaps %xmm0, -0xc0(%rbp)
leaq 0xbd0(%rip), %rax       # 0x2f12
movq %rax, -0xa8(%rbp)
leaq 0xbd0(%rip), %rax       # 0x2f20
movq %rax, -0xb0(%rbp)
movaps %xmm0, -0xa0(%rbp)
leaq 0x599(%rip), %rax       # 0x28fe
movq %rax, -0x88(%rbp)
leaq 0x597(%rip), %rax       # 0x290a
movq %rax, -0x90(%rbp)
pushq $0x4
popq %rsi
pushq $0x2
popq %rdx
callq 0x2928
movq 0x4c4c(%rip), %rdi      # 0x6fd8
movl %eax, %esi
callq 0x2190
movq %rax, %rdi
callq 0x20b0
leaq -0xc0(%rbp), %rdi
pushq $0x4
popq %rsi
pushq $0x2
popq %rdx
callq 0x2928
movq 0x4c24(%rip), %rdi      # 0x6fd8
movl %eax, %esi
callq 0x2190
movq %rax, %rdi
callq 0x20b0
leaq -0xa0(%rbp), %rdi
pushq $0x4
popq %rsi
pushq $0x2
popq %rdx
callq 0x2928
movq 0x4bfc(%rip), %rdi      # 0x6fd8
movl %eax, %esi
callq 0x2190
movq %rax, %rdi
callq 0x20b0
leaq 0x1c3e(%rip), %rsi      # 0x4030
leaq -0x10d(%rip), %rdx      # 0x22ec
leaq -0x220(%rbp), %r14
movq %r14, %rdi
callq 0x2954
leaq -0x1e0(%rbp), %r15
leaq 0x1c1c(%rip), %rsi      # 0x4032
leaq -0xe0(%rbp), %rdx
movq %r15, %rdi
callq 0x2996
leaq -0x1a0(%rbp), %r15
leaq 0x1c01(%rip), %rsi      # 0x4034
leaq -0x50(%rbp), %rbx
movq %r15, %rdi
movq %rbx, %rdx
callq 0x29cc
leaq -0x160(%rbp), %r15
leaq 0x1be6(%rip), %rsi      # 0x4036
leaq -0x48(%rbp), %rdx
movq %r15, %rdi
callq 0x2080
xorps %xmm0, %xmm0
leaq -0x120(%rbp), %r15
movups %xmm0, -0x20(%r15)
leaq 0x434(%rip), %rax       # 0x28a6
movq %rax, -0x8(%r15)
leaq 0x435(%rip), %rax       # 0x28b2
movq %rax, -0x10(%r15)
leaq 0x1bb0(%rip), %rsi      # 0x4038
leaq -0x48(%rbp), %rdx
movq %r15, %rdi
callq 0x2080
leaq -0x220(%rbp), %rsi
xorps %xmm0, %xmm0
movups %xmm0, 0x120(%rsi)
leaq 0x424(%rip), %rax       # 0x28d0
movq %rax, 0x138(%rsi)
leaq 0x426(%rip), %rax       # 0x28e0
movq %rax, 0x130(%rsi)
leaq -0x80(%rbp), %rdi
pushq $0x5
popq %rdx
leaq -0x48(%rbp), %rcx
leaq -0x19(%rbp), %r8
callq 0x2a02
movl $0x100, %r14d           # imm = 0x100
leaq (%r14,%rbp), %rdi
addq $-0x220, %rdi           # imm = 0xFDE0
callq 0x2a4a
addq $-0x40, %r14
cmpq $-0x40, %r14
jne 0x24db
leaq 0x1b34(%rip), %rsi      # 0x4030
leaq -0x220(%rbp), %rdi
leaq -0x48(%rbp), %rdx
callq 0x2080
leaq -0x80(%rbp), %rdi
leaq -0x220(%rbp), %rsi
callq 0x2a6a
pushq $0xa
popq %rsi
pushq $0x5
popq %rdx
movq %rax, %rdi
callq 0x2928
movq 0x4aa7(%rip), %rdi      # 0x6fd8
movl %eax, %esi
callq 0x2190
movq %rax, %rdi
callq 0x20b0
leaq -0x220(%rbp), %rdi
callq 0x20a0
leaq 0x1adf(%rip), %rsi      # 0x4032
leaq -0x220(%rbp), %rdi
leaq -0x48(%rbp), %rdx
callq 0x2080
leaq -0x80(%rbp), %rdi
leaq -0x220(%rbp), %rsi
callq 0x2a6a
pushq $0xa
popq %rsi
pushq $0x5
popq %rdx
movq %rax, %rdi
callq 0x2928
movq 0x4a50(%rip), %rdi      # 0x6fd8
movl %eax, %esi
callq 0x2190
movq %rax, %rdi
callq 0x20b0
leaq -0x220(%rbp), %rdi
callq 0x20a0
leaq 0x1a8a(%rip), %rsi      # 0x4034
leaq -0x220(%rbp), %rdi
leaq -0x48(%rbp), %rdx
callq 0x2080
leaq -0x80(%rbp), %rdi
leaq -0x220(%rbp), %rsi
callq 0x2a6a
pushq $0xa
popq %rsi
pushq $0x5
popq %rdx
movq %rax, %rdi
callq 0x2928
movq 0x49f9(%rip), %rdi      # 0x6fd8
movl %eax, %esi
callq 0x2190
movq %rax, %rdi
callq 0x20b0
leaq -0x220(%rbp), %rdi
callq 0x20a0
leaq 0x1a35(%rip), %rsi      # 0x4036
leaq -0x220(%rbp), %rdi
leaq -0x48(%rbp), %rdx
callq 0x2080
leaq -0x80(%rbp), %rdi
leaq -0x220(%rbp), %rsi
callq 0x2a6a
pushq $0xa
popq %rsi
pushq $0x5
popq %rdx
movq %rax, %rdi
callq 0x2928
movq 0x49a2(%rip), %rdi      # 0x6fd8
movl %eax, %esi
callq 0x2190
movq %rax, %rdi
callq 0x20b0
leaq -0x220(%rbp), %rdi
callq 0x20a0
leaq 0x19e0(%rip), %rsi      # 0x4038
leaq -0x220(%rbp), %rdi
leaq -0x48(%rbp), %rdx
callq 0x2080
leaq -0x80(%rbp), %rdi
leaq -0x220(%rbp), %rsi
callq 0x2a6a
pushq $0xa
popq %rsi
pushq $0x5
popq %rdx
movq %rax, %rdi
callq 0x2928
movq 0x494b(%rip), %r14      # 0x6fd8
movq %r14, %rdi
movl %eax, %esi
callq 0x2190
movq %rax, %rdi
callq 0x20b0
leaq -0x220(%rbp), %rdi
callq 0x20a0
leaq 0x422(%rip), %rax       # 0x2ad4
leaq -0xe0(%rbp), %rsi
movq %rax, (%rsi)
andq $0x0, 0x8(%rsi)
leaq 0xea6(%rip), %rax       # 0x356e
movq %rax, 0x18(%rsi)
leaq 0xea5(%rip), %rax       # 0x3578
movq %rax, 0x10(%rsi)
movq %r14, -0x50(%rbp)
leaq -0x48(%rbp), %rdi
callq 0x2e12
leaq -0x48(%rbp), %rdx
movq %rbx, 0x20(%rdx)
leaq 0x1947(%rip), %rsi      # 0x403a
leaq -0x220(%rbp), %rdi
callq 0x2b20
leaq -0x80(%rbp), %rdi
leaq -0x220(%rbp), %rsi
callq 0x35f4
leaq -0x220(%rbp), %rdi
callq 0x2a4a
leaq -0x48(%rbp), %rdi
callq 0x2b62
leaq 0x190f(%rip), %rsi      # 0x403a
leaq -0x220(%rbp), %rdi
leaq -0x48(%rbp), %rdx
callq 0x2080
leaq -0x80(%rbp), %rdi
leaq -0x220(%rbp), %rsi
callq 0x2a6a
pushq $0xa
popq %rsi
pushq $0x5
popq %rdx
movq %rax, %rdi
callq 0x2928
movq 0x4878(%rip), %rdi      # 0x6fd8
movl %eax, %esi
callq 0x2190
movq %rax, %rdi
callq 0x20b0
leaq -0x220(%rbp), %rdi
callq 0x20a0
leaq -0xe0(%rbp), %rdi
callq 0x2b62
leaq -0x80(%rbp), %rdi
callq 0x2e60
leaq -0xa0(%rbp), %rdi
callq 0x2b62
leaq -0xc0(%rbp), %rdi
callq 0x2b62
leaq -0x240(%rbp), %rdi
callq 0x2b62
xorl %eax, %eax
addq $0x228, %rsp            # imm = 0x228
popq %rbx
popq %r14
popq %r15
popq %rbp
retq
jmp 0x27e5
movq %rax, %rbx
leaq -0x220(%rbp), %rdi
callq 0x2a4a
jmp 0x27da
movq %rax, %rbx
leaq -0x48(%rbp), %rdi
callq 0x2b62
jmp 0x2847
movq %rax, %rbx
jmp 0x2847
jmp 0x27f2
jmp 0x27f2
jmp 0x27f2
jmp 0x27f2
movq %rax, %rbx
jmp 0x286c
movq %rax, %rbx
movl $0x100, %r14d           # imm = 0x100
leaq (%r14,%rbp), %rdi
addq $-0x220, %rdi           # imm = 0xFDE0
callq 0x2a4a
addq $-0x40, %r14
cmpq $-0x40, %r14
jne 0x2800
jmp 0x287a
jmp 0x2822
jmp 0x2822
jmp 0x2877
movq %rax, %rbx
addq $-0x40, %r15
movq %r15, %rdi
callq 0x2a4a
cmpq %r14, %r15
jne 0x2825
jmp 0x287a
movq %rax, %rbx
leaq -0x220(%rbp), %rdi
callq 0x20a0
leaq -0xe0(%rbp), %rdi
callq 0x2b62
jmp 0x286c
jmp 0x285d
jmp 0x285d
jmp 0x285d
jmp 0x285d
movq %rax, %rbx
leaq -0x220(%rbp), %rdi
callq 0x20a0
leaq -0x80(%rbp), %rdi
callq 0x2e60
jmp 0x287a
movq %rax, %rbx
leaq -0xa0(%rbp), %rdi
callq 0x2b62
leaq -0xc0(%rbp), %rdi
callq 0x2b62
leaq -0x240(%rbp), %rdi
callq 0x2b62
movq %rbx, %rdi
callq 0x21a0