static uint32_t stats(nfa_state_t *root)
{
    std::vector<DfsNfaStats> stack;
    uint32_t topord = 0;
    uint32_t ncores = 0;

    DfsNfaStats i0 = {root, 0};
    stack.push_back(i0);

    while (!stack.empty()) {
        // Don't store references to stack as it may grow and get reallocated.
        nfa_state_t *state = stack.back().state;
        const uint32_t next = stack.back().next++;
        const size_t stack_size = stack.size();

        if (next == 0) {
            // Recursive enter: increase state in-degree.
            ++state->indeg;

            if (state->indeg > 1) {
                // In-degree was non-null => we have been here before, stop DFS.
                stack.pop_back();
                continue;
            }
        }

        switch (state->type) {
            case nfa_state_t::ALT:
                if (next == 0) {
                    DfsNfaStats i = {state->alt.out1, 0};
                    stack.push_back(i);
                } else if (next == 1) {
                    DfsNfaStats i = {state->alt.out2, 0};
                    stack.push_back(i);
                }
                break;
            case nfa_state_t::TAG:
                if (next == 0) {
                    DfsNfaStats i = {state->tag.out, 0};
                    stack.push_back(i);
                }
                break;
            case nfa_state_t::RAN:
                if (next == 0) {
                    ++ncores;
                    DfsNfaStats i = {state->tag.out, 0};
                    stack.push_back(i);
                }
                break;
            case nfa_state_t::FIN:
                ++ncores;
                break;
        }

        if (stack.size() == stack_size) {
            // No new states have been pushed on stack: all children have been
            // visited and this is the recursive return. Set topological index.
            state->topord = topord++;
            stack.pop_back();
        }
    }

    return ncores;
}
static uint32_t stats(nfa_state_t *root)
{
    std::vector<DfsNfaStats> stack;
    uint32_t topord = 0;
    uint32_t ncores = 0;

    DfsNfaStats i0 = {root, 0};
    stack.push_back(i0);

    while (!stack.empty()) {
         
        nfa_state_t *state = stack.back().state;
        const uint32_t next = stack.back().next++;
        const size_t stack_size = stack.size();

        if (next == 0) {
             
            ++state->indeg;

            if (state->indeg > 1) {
                 
                stack.pop_back();
                continue;
            }
        }

        switch (state->type) {
            case nfa_state_t::ALT:
                if (next == 0) {
                    DfsNfaStats i = {state->alt.out1, 0};
                    stack.push_back(i);
                } else if (next == 1) {
                    DfsNfaStats i = {state->alt.out2, 0};
                    stack.push_back(i);
                }
                break;
            case nfa_state_t::TAG:
                if (next == 0) {
                    DfsNfaStats i = {state->tag.out, 0};
                    stack.push_back(i);
                }
                break;
            case nfa_state_t::RAN:
                if (next == 0) {
                    ++ncores;
                    DfsNfaStats i = {state->tag.out, 0};
                    stack.push_back(i);
                }
                break;
            case nfa_state_t::FIN:
                ++ncores;
                break;
        }

        if (stack.size() == stack_size) {
             
             
            state->topord = topord++;
            stack.pop_back();
        }
    }

    return ncores;
}