// File: /workspace/github_cpp_makefile_star2_O1/aalto-speech[P]ftk/src/MSFG.cc
// Function: MultiStringFactorGraph::add(FactorGraph const&, bool)
void
MultiStringFactorGraph::add(const FactorGraph &text,
                            bool lookahead)
{
    map<fg_node_idx_t, msfg_node_idx_t> visited_nodes;
    multimap<fg_node_idx_t, pair<msfg_node_idx_t, FactorGraph::Arc*> > arcs_to_process;
    // multimap key is target index in fg, value pair source index in msfg, arc in fg
    // ordering arcs by target index ensures topological order for text nodes in msfg

    const FactorGraph::Node &fg_node = text.nodes[0];
    for (auto fg_arcit = fg_node.outgoing.cbegin(); fg_arcit != fg_node.outgoing.cend(); ++fg_arcit)
        arcs_to_process.insert(make_pair((**fg_arcit).target_node, make_pair(0, *fg_arcit)));

    while (arcs_to_process.size() > 0) {

        auto arc_to_process = arcs_to_process.begin();
        FactorGraph::Arc *arc = (*arc_to_process).second.second;
        fg_node_idx_t fg_target_node = arc->target_node;
        msfg_node_idx_t msfg_source_node = (*arc_to_process).second.first;
        arcs_to_process.erase(arc_to_process);

        string target_node_factor = text.get_factor(fg_target_node);
        msfg_node_idx_t msfg_target_node = 0;

        // Check if have connected to this fg node already from some other node
        // Just find or add arc and continue
        if (visited_nodes.find(fg_target_node) != visited_nodes.end()) {
            msfg_target_node = visited_nodes[fg_target_node];
            find_or_create_arc(msfg_source_node, msfg_target_node);
            continue;
        }

        // Check if node exists in msfg, just not visited yet
        if (lookahead) {
            auto flait = factor_lookahead.find(msfg_source_node);
            if (flait != factor_lookahead.end()) {
                auto flait2 = flait->second.find(target_node_factor);
                if (flait2 != flait->second.end())
                    msfg_target_node = flait2->second;
            }
        }
        else {
            MultiStringFactorGraph::Node &msfg_node = nodes[msfg_source_node];
            for (auto msfg_arcit = msfg_node.outgoing.begin(); msfg_arcit != msfg_node.outgoing.end(); ++msfg_arcit)
                if (nodes[(**msfg_arcit).target_node].factor == target_node_factor) {
                    msfg_target_node = (**msfg_arcit).target_node;
                    break;
                }
        }

        if (msfg_target_node != 0) {
            visited_nodes[fg_target_node] = msfg_target_node;
            const FactorGraph::Node &fg_node = text.nodes[fg_target_node];
            for (auto fg_arcit = fg_node.outgoing.cbegin(); fg_arcit != fg_node.outgoing.cend(); ++fg_arcit)
                arcs_to_process.insert(make_pair((**fg_arcit).target_node, make_pair(msfg_target_node, *fg_arcit)));
            continue;
        }

        // Create new node and arc
        nodes.push_back(Node(target_node_factor));
        msfg_target_node = nodes.size()-1;
        visited_nodes[fg_target_node] = msfg_target_node;
        if (lookahead) factor_lookahead[msfg_source_node][target_node_factor] = msfg_target_node;
        const FactorGraph::Node &fg_node = text.nodes[fg_target_node];
        for (auto fg_arcit = fg_node.outgoing.cbegin(); fg_arcit != fg_node.outgoing.cend(); ++fg_arcit)
            arcs_to_process.insert(make_pair((**fg_arcit).target_node, make_pair(msfg_target_node, *fg_arcit)));
        create_arc(msfg_source_node, msfg_target_node);
    }


    string_end_nodes[text.text] = visited_nodes[text.nodes.size()-1];
    reverse_string_end_nodes[visited_nodes[text.nodes.size()-1]] = text.text;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x148, %rsp            # imm = 0x148
movl %edx, -0x3c(%rbp)
movq %rsi, %r13
movq %rdi, -0x38(%rbp)
leaq -0xe0(%rbp), %rcx
xorl %eax, %eax
movl %eax, (%rcx)
movq %rax, 0x8(%rcx)
movq %rcx, 0x10(%rcx)
movq %rcx, 0x18(%rcx)
movq %rax, 0x20(%rcx)
leaq -0xb0(%rbp), %rcx
movl %eax, (%rcx)
movq %rax, 0x8(%rcx)
movq %rcx, 0x10(%rcx)
movq %rcx, 0x18(%rcx)
movq %rax, 0x20(%rcx)
movq 0x40(%rsi), %r14
movq 0x20(%r14), %r12
cmpq 0x28(%r14), %r12
je 0x11941
leaq -0xb8(%rbp), %rbx
leaq -0x168(%rbp), %r15
movq (%r12), %rax
movzwl 0x2(%rax), %ecx
movw %cx, -0x168(%rbp)
movl $0x0, -0x160(%rbp)
movq %rax, -0x158(%rbp)
movq %rbx, %rdi
movq %r15, %rsi
callq 0x1476c
addq $0x8, %r12
cmpq 0x28(%r14), %r12
jne 0x1190c
cmpq $0x0, -0x90(%rbp)
je 0x11c8c
movq -0x38(%rbp), %rax
leaq 0xd0(%rax), %r15
leaq 0x20(%rax), %rcx
movq %rcx, -0x78(%rbp)
addq $0xc8, %rax
movq %rax, -0x70(%rbp)
movq %r13, -0x48(%rbp)
movq %r15, -0x80(%rbp)
movq -0xa0(%rbp), %rsi
movq 0x30(%rsi), %rax
movzwl 0x2(%rax), %eax
movw %ax, -0x2a(%rbp)
movl 0x28(%rsi), %eax
movl %eax, -0x30(%rbp)
leaq -0xb8(%rbp), %rdi
callq 0x14850
movzwl -0x2a(%rbp), %edx
leaq -0x68(%rbp), %rdi
movq %r13, %rsi
callq 0x10378
leaq -0xe0(%rbp), %rdi
movq -0xd8(%rbp), %rcx
movq %rdi, %rax
testq %rcx, %rcx
je 0x119de
movzwl -0x2a(%rbp), %edx
movq %rdi, %rax
xorl %esi, %esi
cmpw %dx, 0x20(%rcx)
setb %sil
cmovaeq %rcx, %rax
movq 0x10(%rcx,%rsi,8), %rcx
testq %rcx, %rcx
jne 0x119c6
movq %rdi, %rcx
cmpq %rdi, %rax
je 0x119f5
movzwl -0x2a(%rbp), %ecx
cmpw 0x20(%rax), %cx
cmovbq %rdi, %rax
movq %rax, %rcx
cmpq %rdi, %rcx
je 0x11a41
leaq -0xe8(%rbp), %rdi
leaq -0x2a(%rbp), %rsi
callq 0x136b4
movl (%rax), %edx
movl -0x30(%rbp), %esi
movq -0x38(%rbp), %rdi
callq 0x11d94
movq -0x68(%rbp), %rdi
leaq -0x58(%rbp), %rax
cmpq %rax, %rdi
je 0x11a2a
callq 0x4350
cmpq $0x0, -0x90(%rbp)
movq -0x80(%rbp), %r15
jne 0x11974
jmp 0x11c8c
cmpb $0x0, -0x3c(%rbp)
je 0x11ab4
movq -0x38(%rbp), %rax
movq 0xd8(%rax), %rcx
movq %r15, %rax
testq %rcx, %rcx
je 0x11a77
movl -0x30(%rbp), %edx
movq %r15, %rax
xorl %esi, %esi
cmpl %edx, 0x20(%rcx)
setb %sil
cmovaeq %rcx, %rax
movq 0x10(%rcx,%rsi,8), %rcx
testq %rcx, %rcx
jne 0x11a60
movq %r15, %rbx
cmpq %r15, %rax
je 0x11a8c
movl -0x30(%rbp), %ecx
cmpl 0x20(%rax), %ecx
cmovbq %r15, %rax
movq %rax, %rbx
xorl %r14d, %r14d
cmpq %r15, %rbx
je 0x11b2b
leaq 0x28(%rbx), %rdi
leaq -0x68(%rbp), %rsi
callq 0x14ab0
addq $0x30, %rbx
cmpq %rbx, %rax
je 0x11b2b
movl 0x40(%rax), %r14d
jmp 0x11b2b
movl -0x30(%rbp), %eax
movq -0x38(%rbp), %rcx
movq 0x20(%rcx), %r15
shlq $0x7, %rax
leaq (%r15,%rax), %r13
addq $0x58, %r13
movq 0x10(%r13), %r12
cmpq %r13, %r12
je 0x11b28
movq -0x68(%rbp), %rax
movq %rax, -0x88(%rbp)
movq -0x60(%rbp), %rbx
movq 0x20(%r12), %rax
movl 0x4(%rax), %r14d
movq %r14, %rax
shlq $0x7, %rax
movq 0x8(%r15,%rax), %rdx
cmpq %rbx, %rdx
jne 0x11b18
testq %rdx, %rdx
je 0x11b2b
addq %r15, %rax
movq (%rax), %rdi
movq -0x88(%rbp), %rsi
callq 0x43a0
testl %eax, %eax
je 0x11b2b
movq %r12, %rdi
callq 0x4410
movq %rax, %r12
cmpq %r13, %rax
jne 0x11ae3
xorl %r14d, %r14d
testl %r14d, %r14d
je 0x11ba9
leaq -0xe8(%rbp), %rdi
leaq -0x2a(%rbp), %rsi
callq 0x136b4
movq -0x48(%rbp), %r13
movl %r14d, (%rax)
movzwl -0x2a(%rbp), %ecx
movq 0x40(%r13), %rax
imulq $0x38, %rcx, %rcx
movq 0x20(%rax,%rcx), %rbx
cmpq 0x28(%rax,%rcx), %rbx
je 0x11a18
leaq (%rax,%rcx), %r15
addq $0x20, %r15
movq (%rbx), %rax
movzwl 0x2(%rax), %ecx
movw %cx, -0x168(%rbp)
movl %r14d, -0x160(%rbp)
movq %rax, -0x158(%rbp)
leaq -0xb8(%rbp), %rdi
leaq -0x168(%rbp), %rsi
callq 0x14b4e
addq $0x8, %rbx
cmpq 0x8(%r15), %rbx
jne 0x11b6b
jmp 0x11a18
leaq -0x168(%rbp), %rbx
movq %rbx, %rdi
leaq -0x68(%rbp), %rsi
callq 0x13720
movq -0x48(%rbp), %r13
movq -0x78(%rbp), %rdi
movq %rbx, %rsi
callq 0x1425c
movq %rbx, %rdi
callq 0x137a8
movq -0x38(%rbp), %rax
movq 0x28(%rax), %r12
subq 0x20(%rax), %r12
leaq -0xe8(%rbp), %rdi
leaq -0x2a(%rbp), %rsi
callq 0x136b4
shrq $0x7, %r12
decl %r12d
movl %r12d, (%rax)
cmpb $0x0, -0x3c(%rbp)
je 0x11c1c
movq -0x70(%rbp), %rdi
leaq -0x30(%rbp), %rsi
callq 0x13800
movq %rax, %rdi
leaq -0x68(%rbp), %rsi
callq 0x13868
movl %r12d, (%rax)
movzwl -0x2a(%rbp), %ecx
movq 0x40(%r13), %rax
imulq $0x38, %rcx, %rcx
movq 0x20(%rax,%rcx), %rbx
cmpq 0x28(%rax,%rcx), %rbx
leaq -0x168(%rbp), %r15
je 0x11c78
leaq (%rax,%rcx), %r14
addq $0x20, %r14
movq (%rbx), %rax
movzwl 0x2(%rax), %ecx
movw %cx, -0x168(%rbp)
movl %r12d, -0x160(%rbp)
movq %rax, -0x158(%rbp)
leaq -0xb8(%rbp), %rdi
movq %r15, %rsi
callq 0x14b4e
addq $0x8, %rbx
cmpq 0x8(%r14), %rbx
jne 0x11c43
movl -0x30(%rbp), %esi
movq -0x38(%rbp), %rdi
movl %r12d, %edx
callq 0x11dfc
jmp 0x11a18
movl 0x48(%r13), %eax
subl 0x40(%r13), %eax
shrl $0x3, %eax
imull $0x6db7, %eax, %eax     # imm = 0x6DB7
decl %eax
leaq -0x168(%rbp), %rsi
movw %ax, (%rsi)
leaq -0xe8(%rbp), %rdi
callq 0x138e8
movl (%rax), %ebx
movq -0x38(%rbp), %rax
leaq 0x38(%rax), %rdi
movq %r13, %rsi
callq 0x13868
movl %ebx, (%rax)
movl 0x48(%r13), %eax
subl 0x40(%r13), %eax
shrl $0x3, %eax
imull $0x6db7, %eax, %eax     # imm = 0x6DB7
decl %eax
leaq -0x168(%rbp), %rsi
movw %ax, (%rsi)
leaq -0xe8(%rbp), %rdi
callq 0x138e8
movq -0x38(%rbp), %rdi
addq $0x68, %rdi
movq %rax, %rsi
callq 0x13954
movq %rax, %rdi
movq %r13, %rsi
callq 0x41c0
leaq -0xb8(%rbp), %rdi
callq 0x13f32
leaq -0xe8(%rbp), %rdi
callq 0x13f8a
addq $0x148, %rsp            # imm = 0x148
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x11d56
jmp 0x11d5f
jmp 0x11d5f
movq %rax, %rbx
leaq -0x168(%rbp), %rdi
callq 0x137a8
jmp 0x11d62
jmp 0x11d5f
jmp 0x11d56
jmp 0x11d56
jmp 0x11d56
movq %rax, %rbx
jmp 0x11d74
jmp 0x11d5f
jmp 0x11d5f
movq %rax, %rbx
movq -0x68(%rbp), %rdi
leaq -0x58(%rbp), %rax
cmpq %rax, %rdi
je 0x11d74
callq 0x4350
leaq -0xb8(%rbp), %rdi
callq 0x13f32
leaq -0xe8(%rbp), %rdi
callq 0x13f8a
movq %rbx, %rdi
callq 0x4650