// File: /workspace/github_cpp_makefile_star2_O1/manpat[P]iterator_trait/main.cpp
// Function: main
int main() {
	int arr[] { 1, 2, 3, 4, 5 };

	// Construct an iterator
	int sum = 0;
	for (const auto v : iter(arr)) {
		sum += v;
	}

	std::printf("sum:  %d\n", sum);

	// Map values
	int sum2 = 0;
	for (const auto v : iter(arr).map([](int v) { return v * 2; })) {
		sum2 += v;
	}

	std::printf("sum2: %d\n", sum2);

	// Sum squares with map-fold
	int sum3 = iter(arr)
		.map([](int v) { return v * v; })
		.fold(0, [](int a, int) { return a + 1; });

	std::printf("sum3: %d\n", sum3);

	// Construct a string from an std::array + char doubling and uppercasing
	// NOTE: implicit cast from int return of std::toupper to char in fold
	auto str = iter(std::array<char, 3>{'a', 'b', 'c'})
		.map([](char v) { return std::toupper(v); })
		.fold(std::string{}, [](auto& a, char c) { a += c; return a += c; });

	std::printf("str:  %s\n", str.c_str());

	// Enumerate const char[]
	for (const auto kv : iter("ABCD").enumerate()) {
		if (kv.second)
			std::printf("%d '%c' ", (int)kv.first, kv.second);
	}

	std::putchar('\n');

	// Filter every second letter in string
	std::string str_to_filter {"Hello I'm a string"};
	auto filter_it = iter(str_to_filter).enumerate()
		.filter([](const auto& kv) { return !(kv.first & 1); })
		.map([](const auto& kv) { return kv.second; });

	std::printf("'%s' -> '", str_to_filter.data());
	for (auto c : filter_it) {
		std::putchar(c);
	}
	std::puts("'");

	// Zip two strings together
	const char* zip_string_a = "HloImasrn";
	const char* zip_string_b = "el '  tig";

	auto iter_a = iter(zip_string_a, zip_string_a + std::strlen(zip_string_a));
	auto iter_b = iter(zip_string_b, zip_string_b + std::strlen(zip_string_b));
	auto zip_string = iter_a.zip(iter_b)
		.fold(std::string{}, [](auto& s, auto ab) {
			s += ab.first;
			return s += ab.second;
		});

	std::printf("%s\n", zip_string.data());

	// Chain two strings together
	auto chain_string = iter("Hello").chain(iter(" world"))
		.filter([](char c) { return c != 0; }) // Skip the null terminator
		.fold(std::string{}, [](auto& s, auto c) { return s += c; });

	std::printf("%s\n", chain_string.data());
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x128, %rsp            # imm = 0x128
movl $0x4, %eax
movl $0x1, %ecx
movb $0x1, %r8b
xorl %edx, %edx
leaq 0xea1(%rip), %r9        # 0x20b4
leaq 0xe96(%rip), %rbx       # 0x20b0
xorl %esi, %esi
movb $0x1, %dil
testb $0x1, %dil
je 0x193a
testb $0x1, %r8b
je 0x193a
cmpq $0x14, %rax
jne 0x123e
xorl %r8d, %r8d
jmp 0x1248
movl (%r9), %r10d
addq $0x4, %rax
movb $0x1, %r8b
addl %ecx, %esi
movzbl %dil, %edi
leaq (%rbx,%rax), %r9
testb %r8b, %r8b
cmovel %edx, %edi
cmovnel %r10d, %ecx
jne 0x121f
leaq 0xd9f(%rip), %rdi       # 0x2004
xorl %ebp, %ebp
xorl %eax, %eax
callq 0x1030
movl $0x4, %eax
movl $0x2, %ecx
movb $0x1, %dil
leaq 0xe32(%rip), %r8        # 0x20b4
xorl %esi, %esi
movb $0x1, %dl
testb $0x1, %dl
je 0x193a
testb $0x1, %dil
je 0x193a
xorl %r9d, %r9d
cmpq $0x14, %rax
jne 0x12a6
xorl %edi, %edi
jmp 0x12b3
movl (%r8), %r9d
addq $0x4, %rax
addl %r9d, %r9d
movb $0x1, %dil
addl %ecx, %esi
movzbl %dl, %edx
leaq (%rbx,%rax), %r8
testb %dil, %dil
cmovel %ebp, %edx
cmovnel %r9d, %ecx
jne 0x1286
leaq 0xd3f(%rip), %rdi       # 0x200e
xorl %r13d, %r13d
xorl %eax, %eax
callq 0x1030
leaq 0xd38(%rip), %rdi       # 0x2018
movl $0x5, %esi
xorl %eax, %eax
callq 0x1030
movw $0x6261, 0x30(%rsp)     # imm = 0x6261
movb $0x63, 0x32(%rsp)
leaq 0x60(%rsp), %rax
movq %rax, -0x10(%rax)
movq $0x0, -0x8(%rax)
movb $0x0, (%rax)
leaq 0x50(%rsp), %rbx
leaq 0x70(%rsp), %r14
movq %r13, %r12
movl $0x0, %edi
cmpq $0x3, %r13
je 0x132e
movsbl 0x30(%rsp,%r13), %edi
leaq 0x1(%r13), %r12
cmpq $0x3, %r13
je 0x133b
callq 0x10e0
movl %eax, %ebp
cmpq $0x3, %r13
je 0x13b7
movsbl %bpl, %r15d
movq %rbx, %rdi
movl %r15d, %esi
callq 0x1070
movq %rbx, %rdi
movl %r15d, %esi
callq 0x1070
leaq 0x80(%rsp), %rax
movq %rax, 0x70(%rsp)
movq 0x50(%rsp), %rsi
movq 0x58(%rsp), %rdx
addq %rsi, %rdx
movq %r14, %rdi
callq 0x1aa8
movq %rbx, %rdi
movq %r14, %rsi
callq 0x1090
movq 0x70(%rsp), %rdi
leaq 0x80(%rsp), %rax
cmpq %rax, %rdi
je 0x13aa
movq 0x80(%rsp), %rsi
incq %rsi
callq 0x1080
cmpq $0x3, %r13
movq %r12, %r13
jne 0x1319
leaq 0xf8(%rsp), %rcx
movq %rcx, -0x10(%rcx)
movq 0x50(%rsp), %rax
leaq 0x60(%rsp), %rdx
cmpq %rdx, %rax
je 0x13e9
movq %rax, 0xe8(%rsp)
movq 0x60(%rsp), %rax
movq %rax, 0xf8(%rsp)
jmp 0x13ef
movups (%rdx), %xmm0
movups %xmm0, (%rcx)
movq 0x58(%rsp), %rax
movq %rax, 0xf0(%rsp)
movq %rdx, 0x50(%rsp)
xorl %r14d, %r14d
movq %r14, 0x58(%rsp)
movb $0x0, 0x60(%rsp)
movq 0xe8(%rsp), %rsi
leaq 0xc05(%rip), %rdi       # 0x2022
xorl %eax, %eax
callq 0x1030
leaq 0xc06(%rip), %rax       # 0x2031
leaq 0x70(%rsp), %rbx
movq %rax, 0x8(%rbx)
movb $0x1, %al
movb %al, 0x18(%rbx)
leaq 0xbed(%rip), %rcx       # 0x202d
movq %rcx, (%rbx)
movq $0x1, 0x10(%rbx)
movb %al, 0x30(%rbx)
movq %r14, 0x20(%rbx)
movb $0x41, 0x28(%rbx)
leaq 0xbd4(%rip), %r14       # 0x2031
cmpb $0x0, 0x88(%rsp)
je 0x14a2
je 0x193a
cmpb $0x0, 0xa0(%rsp)
je 0x193a
movsbl 0x98(%rsp), %edx
testl %edx, %edx
je 0x1498
movl 0x90(%rsp), %esi
movq %r14, %rdi
xorl %eax, %eax
callq 0x1030
movq %rbx, %rdi
callq 0x1a40
jmp 0x145d
movl $0xa, %edi
callq 0x10a0
leaq 0x40(%rsp), %rax
movq %rax, -0x10(%rax)
leaq 0xb7e(%rip), %rsi       # 0x203a
leaq 0xb89(%rip), %rdx       # 0x204c
leaq 0x30(%rsp), %rdi
callq 0x1b38
movq 0x30(%rsp), %rbx
movq 0x38(%rsp), %r15
leaq 0xb6f(%rip), %rdi       # 0x204d
movq %rbx, %rsi
xorl %eax, %eax
callq 0x1030
testq %r15, %r15
je 0x14f6
movb (%rbx), %bpl
leaq 0x1(%rbx), %r14
jmp 0x14f9
movq %rbx, %r14
addq %r15, %rbx
testq %r15, %r15
je 0x15df
setne %r15b
movzbl %r15b, %r12d
movl %r15d, %r13d
movl %r15d, %ecx
testb $0x1, %r13b
je 0x193a
testb $0x1, %cl
je 0x193a
movsbl %bpl, %edi
callq 0x10a0
movq %r12, %rcx
movl $0x3, %r11d
cmpq %rbx, %r14
setne %dil
andb %r15b, %dil
cmpb $0x1, %dil
jne 0x1550
movb (%r14), %r8b
incq %r14
jmp 0x1550
testb %dil, %dil
je 0x1564
leaq 0x1(%rcx), %r12
movq %rcx, %rdx
movq %r12, %rcx
movl %r8d, %esi
jmp 0x1567
movl %esi, %r8d
movl %edx, %r10d
andl $0x1, %r10d
movl %r10d, %r9d
xorl $0x1, %r9d
testq %r10, %r10
movzbl %al, %eax
movzbl %r8b, %r8d
cmovnel %eax, %r8d
testb %dil, %dil
cmovel %eax, %r8d
movl %r8d, %eax
cmovel %r11d, %r9d
testl %r9d, %r9d
je 0x1538
cmpl $0x1, %r9d
jne 0x15a0
movb $0x1, %cl
jmp 0x15a6
xorl %ecx, %ecx
movb 0xb(%rsp), %al
movb %al, 0xb(%rsp)
movzbl %al, %eax
testb $0x1, %r15b
movzbl %r15b, %edx
movl %edx, %r15d
movl $0x0, %esi
cmovnel %esi, %r15d
movzbl %bpl, %ebp
testb %cl, %cl
cmovnel %eax, %ebp
movzbl %r13b, %r13d
cmovel %esi, %r13d
cmovnel %edx, %r15d
testb %r13b, %r13b
jne 0x1513
leaq 0xa6f(%rip), %rdi       # 0x2055
callq 0x10b0
leaq 0xa65(%rip), %rax       # 0x2057
leaq 0x108(%rsp), %rbx
movq %rax, (%rbx)
leaq 0xa5c(%rip), %rax       # 0x2060
movq %rax, 0x8(%rbx)
leaq 0xa52(%rip), %rax       # 0x2061
movq %rax, 0x10(%rbx)
leaq 0xa50(%rip), %rax       # 0x206a
movq %rax, 0x18(%rbx)
leaq 0xb8(%rsp), %r12
movq %r12, -0x10(%r12)
movq $0x0, -0x8(%r12)
movb $0x0, (%r12)
leaq 0x70(%rsp), %r14
leaq 0xa8(%rsp), %r15
leaq 0x80(%rsp), %r13
movq %r14, %rdi
movq %rbx, %rsi
callq 0x1bc8
movb 0x72(%rsp), %al
testb %al, %al
je 0x1666
movzwl 0x70(%rsp), %ebp
cmpb $0x1, %al
jne 0x16cd
movsbl %bpl, %esi
movq %r15, %rdi
callq 0x1070
movl %ebp, %eax
shrl $0x8, %eax
movsbl %al, %esi
movq %r15, %rdi
callq 0x1070
movq %r13, 0x70(%rsp)
movq 0xa8(%rsp), %rsi
movq 0xb0(%rsp), %rdx
addq %rsi, %rdx
movq %r14, %rdi
callq 0x1aa8
movq %r15, %rdi
movq %r14, %rsi
callq 0x1090
movq 0x70(%rsp), %rdi
cmpq %r13, %rdi
je 0x164e
movq 0x80(%rsp), %rsi
incq %rsi
callq 0x1080
jmp 0x164e
leaq 0xd8(%rsp), %rcx
movq %rcx, -0x10(%rcx)
movq 0xa8(%rsp), %rax
cmpq %r12, %rax
je 0x1700
movq %rax, 0xc8(%rsp)
movq 0xb8(%rsp), %rax
movq %rax, 0xd8(%rsp)
jmp 0x1708
movups (%r12), %xmm0
movups %xmm0, (%rcx)
movq 0xb0(%rsp), %rax
movq %rax, 0xd0(%rsp)
movq %r12, 0xa8(%rsp)
xorl %ebp, %ebp
movq %rbp, 0xb0(%rsp)
movb %bpl, 0xb8(%rsp)
movq 0xc8(%rsp), %rdi
callq 0x10b0
leaq 0x20(%rsp), %rax
movq %rax, -0x10(%rax)
movq %rbp, -0x8(%rax)
movb %bpl, (%rax)
xorl %r14d, %r14d
xorl %edi, %edi
movq %r14, %rdx
cmpq $0x6, %r14
je 0x176c
leaq 0x907(%rip), %rcx       # 0x206b
movb (%rdx,%rcx), %sil
leaq 0x1(%rdx), %r14
movb $0x1, %cl
cmpq $0x6, %rdx
jne 0x178e
cmpq $0x7, %rbp
setne %cl
je 0x1791
leaq 0x8ed(%rip), %rdx       # 0x2071
movb (%rbp,%rdx), %r13b
incq %rbp
jmp 0x1791
movl %esi, %r13d
movzbl %r13b, %esi
movzbl %al, %eax
movl $0x3, %edx
testb %cl, %cl
cmovnel %esi, %eax
je 0x17b8
testb %al, %al
je 0x17b6
movl $0x1, %edx
movb $0x1, %dil
movb %al, 0xb(%rsp)
jmp 0x17b8
xorl %edx, %edx
testl %edx, %edx
je 0x1754
cmpl $0x3, %edx
jne 0x17c3
xorl %edi, %edi
movzbl 0xb(%rsp), %eax
movzbl %bl, %ebx
movl %edi, 0xc(%rsp)
testb $0x1, %dil
cmovnel %eax, %ebx
je 0x183e
movsbl %bl, %esi
leaq 0x10(%rsp), %rdi
callq 0x1070
leaq 0x80(%rsp), %r15
leaq 0x70(%rsp), %r12
movq %r15, 0x70(%rsp)
movq 0x10(%rsp), %rsi
movq 0x18(%rsp), %rdx
addq %rsi, %rdx
movq %r12, %rdi
callq 0x1aa8
leaq 0x10(%rsp), %rdi
movq %r12, %rsi
callq 0x1090
movq 0x70(%rsp), %rdi
cmpq %r15, %rdi
je 0x1833
movq 0x80(%rsp), %rsi
incq %rsi
callq 0x1080
testb $0x1, 0xc(%rsp)
jne 0x1752
leaq 0x118(%rsp), %rbx
movq %rbx, -0x10(%rbx)
movq 0x10(%rsp), %rax
leaq 0x20(%rsp), %rcx
cmpq %rcx, %rax
je 0x1870
movq %rax, 0x108(%rsp)
movq 0x20(%rsp), %rax
movq %rax, 0x118(%rsp)
jmp 0x1876
movups (%rcx), %xmm0
movups %xmm0, (%rbx)
leaq 0xd8(%rsp), %r14
movq 0x18(%rsp), %rax
movq %rax, 0x110(%rsp)
movq %rcx, 0x10(%rsp)
movq $0x0, 0x18(%rsp)
movb $0x0, 0x20(%rsp)
movq 0x108(%rsp), %rdi
callq 0x10b0
movq 0x108(%rsp), %rdi
cmpq %rbx, %rdi
je 0x18c8
movq 0x118(%rsp), %rsi
incq %rsi
callq 0x1080
movq 0xc8(%rsp), %rdi
cmpq %r14, %rdi
je 0x18e5
movq 0xd8(%rsp), %rsi
incq %rsi
callq 0x1080
movq 0x30(%rsp), %rdi
leaq 0x40(%rsp), %rax
cmpq %rax, %rdi
je 0x1901
movq 0x40(%rsp), %rsi
incq %rsi
callq 0x1080
movq 0xe8(%rsp), %rdi
leaq 0xf8(%rsp), %rax
cmpq %rax, %rdi
je 0x1926
movq 0xf8(%rsp), %rsi
incq %rsi
callq 0x1080
xorl %eax, %eax
addq $0x128, %rsp            # imm = 0x128
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
callq 0x1040
jmp 0x1941
movq %rax, %rbx
jmp 0x19dc
movq %rax, %rbx
movq 0x10(%rsp), %rdi
leaq 0x20(%rsp), %rax
cmpq %rax, %rdi
je 0x1968
movq 0x20(%rsp), %rsi
incq %rsi
callq 0x1080
movq 0xc8(%rsp), %rdi
leaq 0xd8(%rsp), %rax
cmpq %rax, %rdi
je 0x19c0
movq 0xd8(%rsp), %rsi
jmp 0x19b8
movq %rax, %rbx
movq 0x50(%rsp), %rdi
leaq 0x60(%rsp), %rax
cmpq %rax, %rdi
je 0x1a01
movq 0x60(%rsp), %rsi
jmp 0x19f9
movq %rax, %rbx
movq 0xa8(%rsp), %rdi
cmpq %r12, %rdi
je 0x19c0
movq 0xb8(%rsp), %rsi
incq %rsi
callq 0x1080
leaq 0x40(%rsp), %rax
movq 0x30(%rsp), %rdi
cmpq %rax, %rdi
je 0x19dc
movq 0x40(%rsp), %rsi
incq %rsi
callq 0x1080
leaq 0xf8(%rsp), %rax
movq 0xe8(%rsp), %rdi
cmpq %rax, %rdi
je 0x1a01
movq 0xf8(%rsp), %rsi
incq %rsi
callq 0x1080
movq %rbx, %rdi
callq 0x10c0