// File: /workspace/github_cpp_makefile_star2_O3/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 %r13
pushq %r12
pushq %rbx
subq $0x238, %rsp            # imm = 0x238
movq $0x0, -0x110(%rbp)
leaq -0x2f(%rip), %r13       # 0x22ec
movq %r13, -0x118(%rbp)
leaq 0xf4f(%rip), %r14       # 0x3278
movq %r14, -0x100(%rbp)
leaq 0xf4f(%rip), %r12       # 0x3286
movq %r12, -0x108(%rbp)
xorps %xmm0, %xmm0
movaps %xmm0, -0xf0(%rbp)
leaq 0xf5f(%rip), %rax       # 0x32ae
movq %rax, -0xd8(%rbp)
leaq 0xf5f(%rip), %rax       # 0x32bc
movq %rax, -0xe0(%rbp)
movaps %xmm0, -0xd0(%rbp)
leaq 0x96e(%rip), %rax       # 0x2ce0
movq %rax, -0xb8(%rbp)
leaq 0x96c(%rip), %rax       # 0x2cec
movq %rax, -0xc0(%rbp)
movq 0x4c4a(%rip), %rdi      # 0x6fd8
movl $0x6, %esi
callq 0x2180
movq %rax, %rbx
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x2100
movsbl %al, %esi
movq %rbx, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20b0
movl $0x4, -0x258(%rbp)
movl $0x2, -0xa8(%rbp)
cmpq $0x0, -0xe0(%rbp)
je 0x2b0b
leaq -0xf0(%rbp), %rdi
leaq -0x258(%rbp), %rsi
leaq -0xa8(%rbp), %rdx
callq *0x18(%rdi)
movq 0x4bd5(%rip), %rdi      # 0x6fd8
movl %eax, %esi
callq 0x2180
movq %rax, %rbx
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x2100
movsbl %al, %esi
movq %rbx, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20b0
movl $0x4, -0x258(%rbp)
movl $0x2, -0xa8(%rbp)
cmpq $0x0, -0xc0(%rbp)
je 0x2b0b
leaq -0xd0(%rbp), %rdi
leaq -0x258(%rbp), %rsi
leaq -0xa8(%rbp), %rdx
callq *0x18(%rdi)
movq 0x4b63(%rip), %rdi      # 0x6fd8
movl %eax, %esi
callq 0x2180
movq %rax, %rbx
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x2100
movsbl %al, %esi
movq %rbx, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20b0
leaq -0x248(%rbp), %r15
movq %r15, -0x10(%r15)
movw $0x2b, (%r15)
movl $0x1, %eax
movq %rax, -0x8(%r15)
movq $0x0, 0x18(%r15)
movq %r13, 0x10(%r15)
movq %r14, 0x28(%r15)
movq %r12, 0x20(%r15)
leaq -0x208(%rbp), %rcx
movq %rcx, -0x10(%rcx)
movw $0x2d, (%rcx)
movq %rax, -0x8(%rcx)
xorps %xmm0, %xmm0
movups %xmm0, 0x10(%rcx)
leaq 0xa3a(%rip), %rdx       # 0x2f30
movq %rdx, 0x28(%rcx)
leaq 0xa39(%rip), %rdx       # 0x2f3a
movq %rdx, 0x20(%rcx)
leaq -0x1c8(%rbp), %rcx
movq %rcx, -0x10(%rcx)
movw $0x2f, (%rcx)
movq %rax, -0x8(%rcx)
movups %xmm0, 0x10(%rcx)
leaq 0xd8a(%rip), %rdx       # 0x32ae
movq %rdx, 0x28(%rcx)
leaq 0xd8d(%rip), %rdx       # 0x32bc
movq %rdx, 0x20(%rcx)
leaq -0x188(%rbp), %rcx
movq %rcx, -0x10(%rcx)
movw $0x2a, (%rcx)
movq %rax, -0x8(%rcx)
movups %xmm0, 0x10(%rcx)
leaq 0x736(%rip), %rdx       # 0x2c88
movq %rdx, 0x28(%rcx)
leaq 0x737(%rip), %rdx       # 0x2c94
movq %rdx, 0x20(%rcx)
leaq -0x148(%rbp), %rbx
movq %rbx, -0x10(%rbx)
movw $0x25, (%rbx)
movq %rax, -0x8(%rbx)
movups %xmm0, 0x10(%rbx)
leaq 0x732(%rip), %rax       # 0x2cb2
movq %rax, 0x28(%rbx)
leaq 0x737(%rip), %rax       # 0x2cc2
movq %rax, 0x20(%rbx)
leaq -0xa8(%rbp), %rdi
leaq -0x258(%rbp), %rsi
leaq -0x78(%rbp), %rcx
leaq -0x48(%rbp), %r8
movl $0x5, %edx
callq 0x2d0a
xorl %r14d, %r14d
movq -0x128(%rbp,%r14), %rax
testq %rax, %rax
je 0x25d4
leaq (%r14,%rbp), %rdi
addq $-0x138, %rdi           # imm = 0xFEC8
movq %rdi, %rsi
movl $0x3, %edx
callq *%rax
movq -0x158(%rbp,%r14), %rdi
leaq (%rbx,%r14), %rax
cmpq %rdi, %rax
je 0x25f5
movq -0x148(%rbp,%r14), %rsi
incq %rsi
callq 0x2120
addq $-0x40, %r14
cmpq $-0x140, %r14           # imm = 0xFEC0
jne 0x25b2
leaq -0x258(%rbp), %rsi
movq %r15, (%rsi)
movw $0x2b, 0x10(%rsi)
movq $0x1, 0x8(%rsi)
leaq -0xa8(%rbp), %rdi
callq 0x2dd8
movl $0xa, -0x78(%rbp)
movl $0x5, -0x48(%rbp)
cmpq $0x0, 0x10(%rax)
je 0x2b10
leaq -0x78(%rbp), %rsi
leaq -0x48(%rbp), %rdx
movq %rax, %rdi
callq *0x18(%rax)
movq 0x4984(%rip), %rdi      # 0x6fd8
movl %eax, %esi
callq 0x2180
movq %rax, %rbx
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x2100
movsbl %al, %esi
movq %rbx, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20b0
movq -0x258(%rbp), %rdi
cmpq %r15, %rdi
je 0x26a0
movq -0x248(%rbp), %rsi
incq %rsi
callq 0x2120
leaq -0x258(%rbp), %rsi
movq %r15, (%rsi)
movw $0x2d, 0x10(%rsi)
movq $0x1, 0x8(%rsi)
leaq -0xa8(%rbp), %rdi
callq 0x2dd8
movl $0xa, -0x78(%rbp)
movl $0x5, -0x48(%rbp)
cmpq $0x0, 0x10(%rax)
je 0x2b15
leaq -0x78(%rbp), %rsi
leaq -0x48(%rbp), %rdx
movq %rax, %rdi
callq *0x18(%rax)
movq 0x48e6(%rip), %rdi      # 0x6fd8
movl %eax, %esi
callq 0x2180
movq %rax, %rbx
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x2100
movsbl %al, %esi
movq %rbx, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20b0
movq -0x258(%rbp), %rdi
cmpq %r15, %rdi
je 0x273e
movq -0x248(%rbp), %rsi
incq %rsi
callq 0x2120
leaq -0x258(%rbp), %rsi
movq %r15, (%rsi)
movw $0x2f, 0x10(%rsi)
movq $0x1, 0x8(%rsi)
leaq -0xa8(%rbp), %rdi
callq 0x2dd8
movl $0xa, -0x78(%rbp)
movl $0x5, -0x48(%rbp)
cmpq $0x0, 0x10(%rax)
je 0x2b1a
leaq -0x78(%rbp), %rsi
leaq -0x48(%rbp), %rdx
movq %rax, %rdi
callq *0x18(%rax)
movq 0x4848(%rip), %rdi      # 0x6fd8
movl %eax, %esi
callq 0x2180
movq %rax, %rbx
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x2100
movsbl %al, %esi
movq %rbx, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20b0
movq -0x258(%rbp), %rdi
cmpq %r15, %rdi
je 0x27dc
movq -0x248(%rbp), %rsi
incq %rsi
callq 0x2120
leaq -0x258(%rbp), %rsi
movq %r15, (%rsi)
movw $0x2a, 0x10(%rsi)
movq $0x1, 0x8(%rsi)
leaq -0xa8(%rbp), %rdi
callq 0x2dd8
movl $0xa, -0x78(%rbp)
movl $0x5, -0x48(%rbp)
cmpq $0x0, 0x10(%rax)
je 0x2b1f
leaq -0x78(%rbp), %rsi
leaq -0x48(%rbp), %rdx
movq %rax, %rdi
callq *0x18(%rax)
movq 0x47aa(%rip), %rdi      # 0x6fd8
movl %eax, %esi
callq 0x2180
movq %rax, %rbx
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x2100
movsbl %al, %esi
movq %rbx, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20b0
movq -0x258(%rbp), %rdi
cmpq %r15, %rdi
je 0x287a
movq -0x248(%rbp), %rsi
incq %rsi
callq 0x2120
leaq -0x258(%rbp), %rsi
movq %r15, (%rsi)
movw $0x25, 0x10(%rsi)
movq $0x1, 0x8(%rsi)
leaq -0xa8(%rbp), %rdi
callq 0x2dd8
movl $0xa, -0x78(%rbp)
movl $0x5, -0x48(%rbp)
cmpq $0x0, 0x10(%rax)
je 0x2b24
leaq -0x78(%rbp), %rsi
leaq -0x48(%rbp), %rdx
movq %rax, %rdi
callq *0x18(%rax)
movq 0x470c(%rip), %rbx      # 0x6fd8
movq %rbx, %rdi
movl %eax, %esi
callq 0x2180
movq %rax, %r14
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r14, %rdi
movl $0xa, %esi
callq 0x2100
movsbl %al, %esi
movq %r14, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20b0
movq -0x258(%rbp), %rdi
cmpq %r15, %rdi
je 0x291b
movq -0x248(%rbp), %rsi
incq %rsi
callq 0x2120
leaq 0x536(%rip), %rax       # 0x2e58
leaq -0x48(%rbp), %rsi
movq %rax, (%rsi)
movq $0x0, 0x8(%rsi)
leaq 0x1034(%rip), %rax      # 0x396c
movq %rax, 0x18(%rsi)
leaq 0x1051(%rip), %rax      # 0x3994
movq %rax, 0x10(%rsi)
movq %rbx, -0xf8(%rbp)
leaq -0x78(%rbp), %rdi
callq 0x315c
leaq -0xf8(%rbp), %rax
leaq -0x78(%rbp), %rdx
movq %rax, 0x20(%rdx)
leaq 0x16a7(%rip), %rsi      # 0x4014
leaq -0x258(%rbp), %rdi
callq 0x2ebc
leaq -0xa8(%rbp), %rdi
leaq -0x258(%rbp), %rsi
callq 0x39c2
movq -0x228(%rbp), %rax
testq %rax, %rax
je 0x29a9
leaq -0x238(%rbp), %rdi
movq %rdi, %rsi
movl $0x3, %edx
callq *%rax
movq -0x258(%rbp), %rdi
cmpq %r15, %rdi
je 0x29c4
movq -0x248(%rbp), %rsi
incq %rsi
callq 0x2120
movq -0x68(%rbp), %rax
testq %rax, %rax
je 0x29db
leaq -0x78(%rbp), %rdi
movq %rdi, %rsi
movl $0x3, %edx
callq *%rax
leaq -0x258(%rbp), %rsi
movq %r15, (%rsi)
movw $0x3c3c, 0x10(%rsi)     # imm = 0x3C3C
movq $0x2, 0x8(%rsi)
movb $0x0, 0x12(%rsi)
leaq -0xa8(%rbp), %rdi
callq 0x2dd8
movl $0xa, -0x78(%rbp)
movl $0x5, -0x4c(%rbp)
cmpq $0x0, 0x10(%rax)
je 0x2b29
leaq -0x78(%rbp), %rsi
leaq -0x4c(%rbp), %rdx
movq %rax, %rdi
callq *0x18(%rax)
movq 0x45a7(%rip), %rdi      # 0x6fd8
movl %eax, %esi
callq 0x2180
movq %rax, %rbx
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x2100
movsbl %al, %esi
movq %rbx, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20b0
movq -0x258(%rbp), %rdi
cmpq %r15, %rdi
je 0x2a7d
movq -0x248(%rbp), %rsi
incq %rsi
callq 0x2120
movq -0x38(%rbp), %rax
testq %rax, %rax
je 0x2a94
leaq -0x48(%rbp), %rdi
movq %rdi, %rsi
movl $0x3, %edx
callq *%rax
leaq -0xa8(%rbp), %rdi
callq 0x31c2
movq -0xc0(%rbp), %rax
testq %rax, %rax
je 0x2abd
leaq -0xd0(%rbp), %rdi
movq %rdi, %rsi
movl $0x3, %edx
callq *%rax
movq -0xe0(%rbp), %rax
testq %rax, %rax
je 0x2ada
leaq -0xf0(%rbp), %rdi
movq %rdi, %rsi
movl $0x3, %edx
callq *%rax
movq -0x108(%rbp), %rax
testq %rax, %rax
je 0x2af7
leaq -0x118(%rbp), %rdi
movq %rdi, %rsi
movl $0x3, %edx
callq *%rax
xorl %eax, %eax
addq $0x238, %rsp            # imm = 0x238
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
callq 0x2070
callq 0x2070
callq 0x2070
callq 0x2070
callq 0x2070
callq 0x2070
callq 0x2070
jmp 0x2c80
jmp 0x2c80
jmp 0x2c80
jmp 0x2c80
jmp 0x2c80
jmp 0x2c80
movq %rax, %rbx
leaq -0x258(%rbp), %rdi
callq 0x2d8c
jmp 0x2b60
movq %rax, %rbx
movq -0x68(%rbp), %rax
testq %rax, %rax
je 0x2bc6
leaq -0x78(%rbp), %rdi
movq %rdi, %rsi
movl $0x3, %edx
callq *%rax
jmp 0x2bc6
jmp 0x2c80
movq %rax, %rbx
jmp 0x2bc6
movq %rax, %rbx
movl $0x100, %r14d           # imm = 0x100
leaq (%r14,%rbp), %rdi
addq $-0x258, %rdi           # imm = 0xFDA8
callq 0x2d8c
addq $-0x40, %r14
cmpq $-0x40, %r14
jne 0x2b8c
jmp 0x2c1b
movq %rax, %rbx
movq -0x258(%rbp), %rdi
cmpq %r15, %rdi
je 0x2bc6
movq -0x248(%rbp), %rsi
incq %rsi
callq 0x2120
movq -0x38(%rbp), %rax
testq %rax, %rax
je 0x2c0a
leaq -0x48(%rbp), %rdi
movq %rdi, %rsi
movl $0x3, %edx
callq *%rax
jmp 0x2c0a
jmp 0x2c80
jmp 0x2bec
jmp 0x2bec
jmp 0x2bec
jmp 0x2bec
movq %rax, %rbx
movq -0x258(%rbp), %rdi
cmpq %r15, %rdi
je 0x2c0a
movq -0x248(%rbp), %rsi
incq %rsi
callq 0x2120
leaq -0xa8(%rbp), %rdi
callq 0x31c2
jmp 0x2c1b
movq %rax, %rbx
movq -0xc0(%rbp), %rax
testq %rax, %rax
je 0x2c38
leaq -0xd0(%rbp), %rdi
movq %rdi, %rsi
movl $0x3, %edx
callq *%rax
movq -0xe0(%rbp), %rax
testq %rax, %rax
je 0x2c55
leaq -0xf0(%rbp), %rdi
movq %rdi, %rsi
movl $0x3, %edx
callq *%rax
movq -0x108(%rbp), %rax
testq %rax, %rax
je 0x2c72
leaq -0x118(%rbp), %rdi
movq %rdi, %rsi
movl $0x3, %edx
callq *%rax
movq %rbx, %rdi
callq 0x2190
jmp 0x2c80
jmp 0x2c80
jmp 0x2c80
movq %rax, %rdi
callq 0x2f22