data_accessor_t::edges_range data_accessor_t::get_incident_edges(vertex_id_t vertex_id, 
                                                                 edge_type_t edges_type) const
{
  details::raw_vertex_t * raw_v = raw_vertex_by_id(vertex_id);

  if (raw_v == NULL)
  {
    return edges_range(details::edges_iterator(), details::edges_iterator());
  }
  
  raw_edge_id_t eid_begin;
  raw_edge_id_t eid_end;
  if (edges_type == EDGE_REVERSED)
  {
    eid_begin = raw_v->transposed_edges_begin_id;
    eid_end = raw_v->transposed_edges_end_id;    
  }
  else // edges_type == EDGE_NORMAL or wrong edges_type
  {
    eid_begin = raw_v->edges_begin_id;
    eid_end = raw_v->edges_end_id;
  }
  
  return edges_range(details::edges_iterator(this, vertex_id, eid_begin),
                     details::edges_iterator(this, vertex_id, eid_end));
}
Esempio n. 2
0
/** Remove vacuous edges in graphs where the min_offset or min_length
 * constraints dictate that they can never produce a match. */
static
void pruneVacuousEdges(NGWrapper &g) {
    if (!g.min_length && !g.min_offset) {
        return;
    }

    vector<NFAEdge> dead;

    for (const auto &e : edges_range(g)) {
        const NFAVertex u = source(e, g);
        const NFAVertex v = target(e, g);

        // Special case: Crudely remove vacuous edges from start in graphs with a
        // min_offset.
        if (g.min_offset && u == g.start && is_any_accept(v, g)) {
            DEBUG_PRINTF("vacuous edge in graph with min_offset!\n");
            dead.push_back(e);
            continue;
        }

        // If a min_length is set, vacuous edges can be removed.
        if (g.min_length && is_any_start(u, g) && is_any_accept(v, g)) {
            DEBUG_PRINTF("vacuous edge in graph with min_length!\n");
            dead.push_back(e);
            continue;
        }
    }

    if (dead.empty()) {
        return;
    }

    remove_edges(dead, g);
    pruneUseless(g);
}
Esempio n. 3
0
static
void dump_graph(const GoughGraph &g, const string &base, const Grey &grey) {
    stringstream ss;
    ss << grey.dumpPath << "gough_" << base << ".dot";

    FILE *f = fopen(ss.str().c_str(), "w");

    fprintf(f, "digraph NFA {\n");
    fprintf(f, "rankdir=LR;\n");
    fprintf(f, "size=\"11.5,8\"\n");
    fprintf(f, "node [ shape = circle ];\n");
    fprintf(f, "START [style=invis];\n");

    for (auto v : vertices_range(g)) {
        fprintf(f, "%s [ width = 1, fixedsize = true, fontsize = 12, ",
                dump_name(g[v]).c_str());
        if (!g[v].reports.empty() || !g[v].reports_eod.empty()) {
            fprintf(f, "shape = doublecircle ");
        }

        fprintf(f, "label = \"%u\"];\n", g[v].state_id);
    }
    for (const auto &e : edges_range(g)) {
        GoughVertex s = source(e, g);
        GoughVertex t = target(e, g);

        fprintf(f, "%s -> %s\n",
                dump_name(g[s]).c_str(), dump_name(g[t]).c_str());
    }
    fprintf(f, "}\n");

    fclose(f);
}
Esempio n. 4
0
static
void gather_vars(const GoughGraph &g, vector<const GoughSSAVar *> *vars,
                 map<const GoughSSAVar *, string> *names,
                 map<const GoughSSAVar *, string> *src_label,
                 set<const GoughSSAVar *> *reporters) {
    for (auto v : vertices_range(g)) {
        for (const auto &r : g[v].reports) {
            reporters->insert(r.second);
        }
        for (const auto &r : g[v].reports_eod) {
            reporters->insert(r.second);
        }

        for (u32 i = 0; i < g[v].vars.size(); i++) {
            const GoughSSAVar *vp = g[v].vars[i].get();
            stringstream ss;
            ss << dump_name(g[v]) << "_" << i;
            vars->push_back(vp);
            names->insert(make_pair(vp, ss.str()));
            src_label->insert(make_pair(vp, dump_name(g[v])));
        }
    }

    for (const auto &e : edges_range(g)) {
        for (u32 i = 0; i < g[e].vars.size(); i++) {
            const GoughSSAVar *vp = g[e].vars[i].get();
            stringstream ss;
            ss << dump_name(g, e) << "_" << i;
            vars->push_back(vp);
            names->insert(make_pair(vp, ss.str()));
            src_label->insert(make_pair(vp, dump_name(g, e)));
        }
    }
}
static
void all_vars(const GoughGraph &g, vector<GoughSSAVar *> *out) {
    for (auto v : vertices_range(g)) {
        push_back_all_raw(out, g[v].vars);
    }
    for (const auto &e : edges_range(g)) {
        push_back_all_raw(out, g[e].vars);
    }
}
/* crude, deterministic assignment of symbolic register slots.
 * returns number of slots given out
 */
static
u32 initial_slots(const GoughGraph &g) {
    u32 next_slot = 0;
    for (auto v : vertices_range(g)) {
        set_initial_slots(g[v].vars, &next_slot);
    }
    for (const auto &e : edges_range(g)) {
        set_initial_slots(g[e].vars, &next_slot);
    }

    return next_slot;
}
Esempio n. 7
0
static
void dump_var_mapping(const GoughGraph &g, const string &base,
                      const Grey &grey) {
    stringstream ss;
    ss << grey.dumpPath << "gough_" << base << "_vars.txt";
    FILE *f = fopen(ss.str().c_str(), "w");
    for (auto v : vertices_range(g)) {
        set<const GoughSSAVar *> used = uses(g[v]);
        if (g[v].vars.empty() && used.empty()) {
            continue;
        }
        fprintf(f, "%s\n", dump_name(g[v]).c_str());
        for (u32 i = 0; i < g[v].vars.size(); i++) {
            const GoughSSAVar *vp = g[v].vars[i].get();
            fprintf(f, "\t%u: slot %u\n", i, vp->slot);
        }
        if (!used.empty()) {
            fprintf(f, "\tuses:");
            vector<u32> used_id;
            for (const GoughSSAVar *var : used) {
                used_id.push_back(var->slot);
            }
            for (const u32 &id : used_id) {
                fprintf(f, " %u", id);
            }
            fprintf(f, "\n");
        }
    }
    for (const auto &e : edges_range(g)) {
        set<const GoughSSAVar *> used = uses(g[e]);
        if (g[e].vars.empty() && used.empty()) {
            continue;
        }
        fprintf(f, "%s\n", dump_name(g, e).c_str());
        for (u32 i = 0; i < g[e].vars.size(); i++) {
            const GoughSSAVar *vp = g[e].vars[i].get();
            fprintf(f, "\t%u: slot %u\n", i, vp->slot);
        }
        if (!used.empty()) {
            fprintf(f, "\tuses:");
            vector<u32> used_id;
            for (const GoughSSAVar *var : used) {
                used_id.push_back(var->slot);
            }
            for (const u32 &id : used_id) {
                fprintf(f, " %u", id);
            }
            fprintf(f, "\n");
        }
    }
    fclose(f);
}
Esempio n. 8
0
static
void pruneExtUnreachable(NGWrapper &g) {
    vector<NFAVertexBidiDepth> depths;
    calcDepths(g, depths);

    vector<NFAEdge> dead;

    for (const auto &e : edges_range(g)) {
        if (isEdgePrunable(g, depths, e)) {
            DEBUG_PRINTF("pruning\n");
            dead.push_back(e);
        }
    }

    if (dead.empty()) {
        return;
    }

    remove_edges(dead, g);
    pruneUseless(g);
}
static
void update_local_slots(GoughGraph &g, set<GoughSSAVar *> &locals,
                        u32 local_base) {
    DEBUG_PRINTF("%zu local variables\n", locals.size());
    /* local variables only occur on edges (joins are never local) */

    u32 allocated_count = 0;
    for (const auto &e : edges_range(g)) {
        u32 next_slot = local_base;
        for (auto &var : g[e].vars) {
            if (contains(locals, var.get())) {
                DEBUG_PRINTF("updating slot %u using local %u\n", var->slot,
                             next_slot);
                var->slot = next_slot++;
                allocated_count++;
            }
        }
    }

    assert(allocated_count == locals.size());
}
Esempio n. 10
0
/** \brief Convert temporary assert vertices (from construction method) to
 * edge-based flags.
 *
 * Remove the horrors that are the temporary assert vertices which arise from
 * our construction method. Allows the rest of our code base to live in
 * blissful ignorance of their existence. */
void removeAssertVertices(ReportManager &rm, NGWrapper &g) {
    size_t num = 0;

    DEBUG_PRINTF("before: graph has %zu vertices\n", num_vertices(g));

    // Sweep over the graph and ascertain that we do actually have vertices
    // with assertion flags set. Otherwise, we're done.
    if (!hasAssertVertices(g)) {
        DEBUG_PRINTF("no assert vertices, done\n");
        return;
    }

    u32 assert_edge_count = 0;

    // Build a cache of (u, v) vertex pairs to edge descriptors.
    edge_cache_t edge_cache;
    for (const auto &e : edges_range(g)) {
        edge_cache[make_pair(source(e, g), target(e, g))] = e;
    }

    for (auto v : vertices_range(g)) {
        if (g[v].assert_flags & WORDBOUNDARY_FLAGS) {
            replaceAssertVertex(g, v, edge_cache, assert_edge_count);
            num++;
        }
    }

    checkForMultilineStart(rm, g);

    if (num) {
        DEBUG_PRINTF("resolved %zu assert vertices\n", num);
        pruneUseless(g);
        pruneEmptyVertices(g);
        g.renumberVertices();
        g.renumberEdges();
    }

    DEBUG_PRINTF("after: graph has %zu vertices\n", num_vertices(g));
    assert(!hasAssertVertices(g));
}
Esempio n. 11
0
static
NFAVertex findSingleCyclic(const NGHolder &g) {
    NFAVertex v = NGHolder::null_vertex();
    for (const auto &e : edges_range(g)) {
        if (source(e, g) == target(e, g)) {
            if (source(e, g) == g.startDs) {
                continue;
            }
            if (v != NGHolder::null_vertex()) {
                // More than one cyclic vertex.
                return NGHolder::null_vertex();
            }
            v = source(e, g);
        }
    }

    if (v != NGHolder::null_vertex()) {
        DEBUG_PRINTF("cyclic is %u\n", g[v].index);
        assert(!is_special(v, g));
    }
    return v;
}
Esempio n. 12
0
static never_inline
void fill_aux(const GoughGraph &g, GoughGraphAux *aux) {
    for (auto v : vertices_range(g)) {
        for (const auto &var : g[v].vars) {
            aux->containing_v[var.get()] = v;
            DEBUG_PRINTF("%u is on vertex %u\n", var->slot, g[v].state_id);
        }

        for (GoughSSAVar *var : g[v].reports | map_values) {
            aux->reporters[var].insert(v);
        }

        for (GoughSSAVar *var : g[v].reports_eod | map_values) {
            aux->reporters[var].insert(v);
        }
    }
    for (const auto &e : edges_range(g)) {
        for (const auto &var : g[e].vars) {
            aux->containing_e[var.get()] = e;
            DEBUG_PRINTF("%u is on edge %u->%u\n", var->slot,
                         g[source(e, g)].state_id, g[target(e, g)].state_id);
        }
    }
}
Esempio n. 13
0
static never_inline
void mergeNfa(NGHolder &dest, vector<NFAVertex> &destStateMap,
              ue2::unordered_map<NFAVertex, u32> &dest_state_ids,
              NGHolder &vic, vector<NFAVertex> &vicStateMap,
              size_t common_len) {
    map<NFAVertex, NFAVertex> vmap; // vic -> dest

    vmap[vic.start]     = dest.start;
    vmap[vic.startDs]   = dest.startDs;
    vmap[vic.accept]    = dest.accept;
    vmap[vic.acceptEod] = dest.acceptEod;
    vmap[nullptr] = nullptr;

    u32 stateNum = countStates(dest, dest_state_ids);

    // For vertices in the common len, add to vmap and merge in the reports, if
    // any.
    for (u32 i = 0; i < common_len; i++) {
        NFAVertex v_old = vicStateMap[i], v = destStateMap[i];
        vmap[v_old] = v;

        const auto &reports = vic[v_old].reports;
        dest[v].reports.insert(reports.begin(), reports.end());
    }

    // Add in vertices beyond the common len, giving them state numbers
    // starting at stateNum.
    for (u32 i = common_len; i < vicStateMap.size(); i++) {
        NFAVertex v_old = vicStateMap[i];

        if (is_special(v_old, vic)) {
            // Dest already has start vertices, just merge the reports.
            u32 idx = vic[v_old].index;
            NFAVertex v = dest.getSpecialVertex(idx);
            const auto &reports = vic[v_old].reports;
            dest[v].reports.insert(reports.begin(), reports.end());
            continue;
        }

        NFAVertex v = add_vertex(vic[v_old], dest);
        dest_state_ids[v] = stateNum++;
        vmap[v_old] = v;
    }

    /* add edges */
    DEBUG_PRINTF("common_len=%zu\n", common_len);
    for (const auto &e : edges_range(vic)) {
        NFAVertex u_old = source(e, vic), v_old = target(e, vic);
        NFAVertex u = vmap[u_old], v = vmap[v_old];
        bool uspecial = is_special(u, dest);
        bool vspecial = is_special(v, dest);

        // Skip stylised edges that are already present.
        if (uspecial && vspecial && edge(u, v, dest).second) {
            continue;
        }

        // We're in the common region if v's state ID is low enough, unless v
        // is a special (an accept), in which case we use u's state ID.
        assert(contains(dest_state_ids, v));
        bool in_common_region = dest_state_ids.at(v) < common_len;
        if (vspecial && dest_state_ids.at(u) < common_len) {
            in_common_region = true;
        }

        DEBUG_PRINTF("adding idx=%u (state %u) -> idx=%u (state %u)%s\n",
                     dest[u].index, dest_state_ids.at(u),
                     dest[v].index, dest_state_ids.at(v),
                     in_common_region ? " [common]" : "");

        if (in_common_region) {
            if (!is_special(v, dest)) {
                DEBUG_PRINTF("skipping common edge\n");
                assert(edge(u, v, dest).second);
                // Should never merge edges with different top values.
                assert(vic[e].top == dest[edge(u, v, dest).first].top);
                continue;
            } else {
                assert(is_any_accept(v, dest));
                // If the edge exists in both graphs, skip it.
                if (edge(u, v, dest).second) {
                    DEBUG_PRINTF("skipping common edge to accept\n");
                    continue;
                }
            }
        }

        assert(!edge(u, v, dest).second);
        add_edge(u, v, vic[e], dest);
    }

    dest.renumberEdges();
    dest.renumberVertices();
}
Esempio n. 14
0
static
u32 findMaxInfixMatches(const NGHolder &h, const set<ue2_literal> &lits) {
    DEBUG_PRINTF("h=%p, %zu literals\n", &h, lits.size());
    //dumpGraph("infix.dot", h.g);

    if (!onlyOneTop(h)) {
        DEBUG_PRINTF("more than one top!n");
        return NO_MATCH_LIMIT;
    }

    // Indices of vertices that could terminate any of the literals in 'lits'.
    set<u32> terms;

    for (const auto &s : lits) {
        DEBUG_PRINTF("lit s='%s'\n", escapeString(s).c_str());
        if (s.empty()) {
            // Likely an anchored case, be conservative here.
            return NO_MATCH_LIMIT;
        }

        for (auto v : vertices_range(h)) {
            if (is_special(v, h)) {
                continue;
            }

            if (couldEndLiteral(s, v, h)) {
                u32 idx = h[v].index;
                DEBUG_PRINTF("vertex %u could terminate lit\n", idx);
                terms.insert(idx);
            }
        }
    }

    if (terms.empty()) {
        DEBUG_PRINTF("literals cannot match inside infix\n");
        return 0;
    }

    NGHolder g;
    cloneHolder(g, h);
    vector<NFAVertex> dead;

    // The set of all edges in the graph is used for existence checks in contractVertex.
    ue2::unordered_set<pair<NFAVertex, NFAVertex>> all_edges;
    for (const auto &e : edges_range(g)) {
        all_edges.emplace(source(e, g), target(e, g));
    }

    for (auto v : vertices_range(g)) {
        if (is_special(v, g)) {
            continue;
        }
        if (contains(terms, g[v].index)) {
            continue;
        }

        contractVertex(g, v, all_edges);
        dead.push_back(v);
    }

    remove_vertices(dead, g);
    //dumpGraph("relaxed.dot", g.g);

    depth maxWidth = findMaxWidth(g);
    DEBUG_PRINTF("maxWidth=%s\n", maxWidth.str().c_str());
    assert(maxWidth.is_reachable());

    if (maxWidth.is_infinite()) {
        // Cycle detected, so we can likely squeeze an unlimited number of
        // matches into this graph.
        return NO_MATCH_LIMIT;
    }

    assert(terms.size() >= maxWidth);
    return maxWidth;
}