// File: /workspace/github_cpp_makefile_star2_O3/dechimal[P]TaggedUnion/test_product.cpp
// Function: main
int main() {
    {
        // basic
        auto v1 = product<int, int const>{1, 2};
        auto const v2 = v1;
        static_assert(std::is_same<decltype(v1.get(_0)), int &>{}, "failed to basic 1");
        static_assert(std::is_same<decltype(v1.get(_1)), int const &>{}, "failed to basic 2");
        static_assert(std::is_same<decltype(v2.get(_0)), int const &>{}, "failed to basic 3");
        static_assert(std::is_same<decltype(v2.get(_1)), int const &>{}, "failed to basic 4");
        assert(v1.get(_0) == 1);
        assert(v1.get(_1) == 2);
    }
    {
        // with recursion
        struct u {};
        using state = sum<u, int>;
        using stream = product<int, std::function<_()>>;
        auto f = fix([] (auto f, auto st) -> std::function<stream()> {
            return [f, st] {
                return st.when([&] (tag<0>, u) {
                    return stream{0, f(state(_1, 0))};
                }, [&] (tag<1>, int i) {
                    return stream{i + 1, f(state(_1, i + 1))};
                });
            };
        });
        auto s = f(state(_0))();
        assert(s.get(_0) == 0);
        s = s.get(_1)();
        assert(s.get(_0) == 1);
    }
}

// Assembly:
pushq %r14
pushq %rbx
subq $0x68, %rsp
xorl %eax, %eax
movl %eax, 0x8(%rsp)
leaq 0x10(%rsp), %r14
movl %eax, (%r14)
leaq 0x18(%rsp), %rdi
movq %r14, %rsi
callq 0x1386
movl 0x10(%rsp), %eax
movq %rsp, %rdi
movq %r14, (%rdi)
andl $0x7fffffff, %eax       # imm = 0x7FFFFFFF
leaq 0x2bdc(%rip), %rbx      # 0x3db0
callq *(%rbx,%rax,8)
cmpq $0x0, 0x28(%rsp)
je 0x1299
leaq 0x40(%rsp), %rdi
leaq 0x18(%rsp), %rsi
callq *0x18(%rsi)
movq 0x28(%rsp), %rax
testq %rax, %rax
je 0x1209
leaq 0x18(%rsp), %rdi
movq %rdi, %rsi
movl $0x3, %edx
callq *%rax
leaq 0x8(%rsp), %rax
movl (%rax), %ecx
movq %rsp, %rdi
movq %rax, (%rdi)
andl $0x7fffffff, %ecx       # imm = 0x7FFFFFFF
callq *(%rbx,%rcx,8)
cmpl $0x0, 0x60(%rsp)
jne 0x129e
cmpq $0x0, 0x50(%rsp)
je 0x12bd
leaq 0x18(%rsp), %rdi
leaq 0x40(%rsp), %rsi
callq *0x18(%rsi)
leaq 0x18(%rsp), %rbx
movl 0x20(%rbx), %eax
leaq 0x40(%rsp), %rdi
movl %eax, 0x20(%rdi)
movq %rbx, %rsi
callq 0x17b6
movq 0x10(%rbx), %rax
testq %rax, %rax
je 0x126f
leaq 0x18(%rsp), %rdi
movq %rdi, %rsi
movl $0x3, %edx
callq *%rax
cmpl $0x1, 0x60(%rsp)
jne 0x12c2
movq 0x50(%rsp), %rax
testq %rax, %rax
je 0x128f
leaq 0x40(%rsp), %rdi
movq %rdi, %rsi
movl $0x3, %edx
callq *%rax
xorl %eax, %eax
addq $0x68, %rsp
popq %rbx
popq %r14
retq
callq 0x1040
leaq 0xe4e(%rip), %rdi       # 0x20f3
leaq 0xe2b(%rip), %rsi       # 0x20d7
leaq 0xe35(%rip), %rcx       # 0x20e8
movl $0x30, %edx
callq 0x1060
callq 0x1040
leaq 0xe39(%rip), %rdi       # 0x2102
leaq 0xe07(%rip), %rsi       # 0x20d7
leaq 0xe11(%rip), %rcx       # 0x20e8
movl $0x32, %edx
callq 0x1060
jmp 0x137d
jmp 0x137d
jmp 0x137d
jmp 0x137d
jmp 0x137d
movq %rax, %rbx
movl 0x10(%rsp), %eax
movq %rsp, %rdi
movq %r14, (%rdi)
andl $0x7fffffff, %eax       # imm = 0x7FFFFFFF
leaq 0x2a9d(%rip), %rcx      # 0x3db0
callq *(%rcx,%rax,8)
jmp 0x1356
jmp 0x137d
movq %rax, %rbx
movq 0x50(%rsp), %rax
testq %rax, %rax
je 0x1373
leaq 0x40(%rsp), %rdi
movq %rdi, %rsi
movl $0x3, %edx
callq *%rax
jmp 0x1373
jmp 0x137d
movq %rax, %rbx
movq 0x28(%rsp), %rax
testq %rax, %rax
je 0x1356
leaq 0x18(%rsp), %rdi
movq %rdi, %rsi
movl $0x3, %edx
callq *%rax
leaq 0x8(%rsp), %rax
movl (%rax), %ecx
movq %rsp, %rdi
movq %rax, (%rdi)
andl $0x7fffffff, %ecx       # imm = 0x7FFFFFFF
leaq 0x2a40(%rip), %rax      # 0x3db0
callq *(%rax,%rcx,8)
movq %rbx, %rdi
callq 0x1090
jmp 0x137d
movq %rax, %rdi
callq 0x17ab
nop