mirror of
https://github.com/VectorCamp/vectorscan.git
synced 2025-06-28 16:41:01 +03:00
insertion_ordered_{map,set}: add new containers
These are associative map/set structures that are iterable in insertion order.
This commit is contained in:
parent
72973ccb47
commit
3ff70d5568
@ -1007,6 +1007,7 @@ SET (hs_compile_SRCS
|
|||||||
src/util/graph_small_color_map.h
|
src/util/graph_small_color_map.h
|
||||||
src/util/hash.h
|
src/util/hash.h
|
||||||
src/util/hash_dynamic_bitset.h
|
src/util/hash_dynamic_bitset.h
|
||||||
|
src/util/insertion_ordered.h
|
||||||
src/util/math.h
|
src/util/math.h
|
||||||
src/util/multibit_build.cpp
|
src/util/multibit_build.cpp
|
||||||
src/util/multibit_build.h
|
src/util/multibit_build.h
|
||||||
|
@ -60,6 +60,7 @@
|
|||||||
#include "util/flat_containers.h"
|
#include "util/flat_containers.h"
|
||||||
#include "util/graph.h"
|
#include "util/graph.h"
|
||||||
#include "util/graph_range.h"
|
#include "util/graph_range.h"
|
||||||
|
#include "util/insertion_ordered.h"
|
||||||
#include "util/make_unique.h"
|
#include "util/make_unique.h"
|
||||||
#include "util/order_check.h"
|
#include "util/order_check.h"
|
||||||
#include "util/target_info.h"
|
#include "util/target_info.h"
|
||||||
@ -1076,24 +1077,21 @@ bool splitRoseEdge(const NGHolder &base_graph, RoseInGraph &vg,
|
|||||||
insert(&splitter_reports, base_graph[v].reports);
|
insert(&splitter_reports, base_graph[v].reports);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* find the targets of each source vertex; note the use of vectors to
|
/* find the targets of each source vertex; insertion_ordered_map used to
|
||||||
* preserve deterministic ordering */
|
* preserve deterministic ordering */
|
||||||
vector<RoseInVertex> sources;
|
insertion_ordered_map<RoseInVertex, vector<RoseInVertex>> images;
|
||||||
map<RoseInVertex, vector<RoseInVertex>> images;
|
|
||||||
for (const RoseInEdge &e : ee) {
|
for (const RoseInEdge &e : ee) {
|
||||||
RoseInVertex src = source(e, vg);
|
RoseInVertex src = source(e, vg);
|
||||||
RoseInVertex dest = target(e, vg);
|
RoseInVertex dest = target(e, vg);
|
||||||
if (!contains(images, src)) {
|
|
||||||
sources.push_back(src);
|
|
||||||
}
|
|
||||||
images[src].push_back(dest);
|
images[src].push_back(dest);
|
||||||
remove_edge(e, vg);
|
remove_edge(e, vg);
|
||||||
}
|
}
|
||||||
|
|
||||||
map<vector<RoseInVertex>, vector<RoseInVertex>> verts_by_image;
|
map<vector<RoseInVertex>, vector<RoseInVertex>> verts_by_image;
|
||||||
|
|
||||||
for (const auto &u : sources) {
|
for (const auto &m : images) {
|
||||||
const auto &image = images[u];
|
const auto &u = m.first;
|
||||||
|
const auto &image = m.second;
|
||||||
|
|
||||||
if (contains(verts_by_image, image)) {
|
if (contains(verts_by_image, image)) {
|
||||||
for (RoseInVertex v : verts_by_image[image]) {
|
for (RoseInVertex v : verts_by_image[image]) {
|
||||||
@ -1743,8 +1741,7 @@ void removeRedundantLiteralsFromInfix(const NGHolder &h, RoseInGraph &ig,
|
|||||||
static
|
static
|
||||||
void removeRedundantLiteralsFromInfixes(RoseInGraph &g,
|
void removeRedundantLiteralsFromInfixes(RoseInGraph &g,
|
||||||
const CompileContext &cc) {
|
const CompileContext &cc) {
|
||||||
vector<NGHolder *> seen_order;
|
insertion_ordered_map<NGHolder *, vector<RoseInEdge>> infixes;
|
||||||
map<NGHolder *, vector<RoseInEdge>> infixes;
|
|
||||||
|
|
||||||
for (const RoseInEdge &e : edges_range(g)) {
|
for (const RoseInEdge &e : edges_range(g)) {
|
||||||
RoseInVertex s = source(e, g);
|
RoseInVertex s = source(e, g);
|
||||||
@ -1766,14 +1763,13 @@ void removeRedundantLiteralsFromInfixes(RoseInGraph &g,
|
|||||||
}
|
}
|
||||||
|
|
||||||
NGHolder *h = g[e].graph.get();
|
NGHolder *h = g[e].graph.get();
|
||||||
if (!contains(infixes, h)) {
|
|
||||||
seen_order.push_back(h);
|
|
||||||
}
|
|
||||||
infixes[h].push_back(e);
|
infixes[h].push_back(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (NGHolder *h : seen_order) {
|
for (const auto &m : infixes) {
|
||||||
removeRedundantLiteralsFromInfix(*h, g, infixes[h], cc);
|
NGHolder *h = m.first;
|
||||||
|
const auto &edges = m.second;
|
||||||
|
removeRedundantLiteralsFromInfix(*h, g, edges, cc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2088,13 +2084,13 @@ void findBetterPrefixes(RoseInGraph &vg, const CompileContext &cc) {
|
|||||||
STAGE_DEBUG_PRINTF("FIND BETTER PREFIXES\n");
|
STAGE_DEBUG_PRINTF("FIND BETTER PREFIXES\n");
|
||||||
RoseInVertex start = getStart(vg);
|
RoseInVertex start = getStart(vg);
|
||||||
|
|
||||||
|
insertion_ordered_map<NGHolder *, vector<RoseInEdge>> prefixes;
|
||||||
bool changed;
|
bool changed;
|
||||||
u32 gen = 0;
|
u32 gen = 0;
|
||||||
do {
|
do {
|
||||||
DEBUG_PRINTF("gen %u\n", gen);
|
DEBUG_PRINTF("gen %u\n", gen);
|
||||||
changed = false;
|
changed = false;
|
||||||
vector<NGHolder *> seen_order;
|
prefixes.clear();
|
||||||
map<NGHolder *, vector<RoseInEdge> > prefixes;
|
|
||||||
|
|
||||||
/* find prefixes */
|
/* find prefixes */
|
||||||
for (const RoseInEdge &e : out_edges_range(start, vg)) {
|
for (const RoseInEdge &e : out_edges_range(start, vg)) {
|
||||||
@ -2102,9 +2098,6 @@ void findBetterPrefixes(RoseInGraph &vg, const CompileContext &cc) {
|
|||||||
assert(vg[target(e, vg)].type == RIV_LITERAL);
|
assert(vg[target(e, vg)].type == RIV_LITERAL);
|
||||||
if (vg[e].graph) {
|
if (vg[e].graph) {
|
||||||
NGHolder *h = vg[e].graph.get();
|
NGHolder *h = vg[e].graph.get();
|
||||||
if (!contains(prefixes, h)) {
|
|
||||||
seen_order.push_back(h);
|
|
||||||
}
|
|
||||||
prefixes[h].push_back(e);
|
prefixes[h].push_back(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2114,14 +2107,16 @@ void findBetterPrefixes(RoseInGraph &vg, const CompileContext &cc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* look for bad prefixes and try to split */
|
/* look for bad prefixes and try to split */
|
||||||
for (NGHolder *h : seen_order) {
|
for (const auto &m : prefixes) {
|
||||||
|
NGHolder *h = m.first;
|
||||||
|
const auto &edges = m.second;
|
||||||
depth max_width = findMaxWidth(*h);
|
depth max_width = findMaxWidth(*h);
|
||||||
if (willBeTransient(max_width, cc)
|
if (willBeTransient(max_width, cc)
|
||||||
|| willBeAnchoredTable(max_width, cc.grey)) {
|
|| willBeAnchoredTable(max_width, cc.grey)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
changed = improvePrefix(*h, vg, prefixes[h], cc);
|
changed = improvePrefix(*h, vg, edges, cc);
|
||||||
}
|
}
|
||||||
} while (changed && gen++ < MAX_FIND_BETTER_PREFIX_GEN);
|
} while (changed && gen++ < MAX_FIND_BETTER_PREFIX_GEN);
|
||||||
}
|
}
|
||||||
@ -2149,24 +2144,25 @@ void extractStrongLiterals(RoseInGraph &vg, const CompileContext &cc) {
|
|||||||
if (!cc.grey.violetExtractStrongLiterals) {
|
if (!cc.grey.violetExtractStrongLiterals) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
STAGE_DEBUG_PRINTF("EXTRACT STRONG LITERALS\n");
|
|
||||||
set<NGHolder *> stuck;
|
|
||||||
|
|
||||||
|
STAGE_DEBUG_PRINTF("EXTRACT STRONG LITERALS\n");
|
||||||
|
|
||||||
|
unordered_set<NGHolder *> stuck;
|
||||||
|
insertion_ordered_map<NGHolder *, vector<RoseInEdge>> edges_by_graph;
|
||||||
bool changed;
|
bool changed;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
changed = false;
|
changed = false;
|
||||||
|
|
||||||
vector<NGHolder *> seen_order;
|
edges_by_graph.clear();
|
||||||
map<NGHolder *, vector<RoseInEdge> > edges_by_graph;
|
|
||||||
for (const RoseInEdge &ve : edges_range(vg)) {
|
for (const RoseInEdge &ve : edges_range(vg)) {
|
||||||
if (vg[source(ve, vg)].type != RIV_LITERAL) {
|
if (vg[source(ve, vg)].type != RIV_LITERAL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vg[ve].graph) {
|
if (vg[ve].graph) {
|
||||||
if (!contains(edges_by_graph, vg[ve].graph.get())) {
|
NGHolder *h = vg[ve].graph.get();
|
||||||
seen_order.push_back(vg[ve].graph.get());
|
edges_by_graph[h].push_back(ve);
|
||||||
}
|
|
||||||
edges_by_graph[vg[ve].graph.get()].push_back(ve);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2175,12 +2171,14 @@ void extractStrongLiterals(RoseInGraph &vg, const CompileContext &cc) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (NGHolder *g : seen_order) {
|
for (const auto &m : edges_by_graph) {
|
||||||
|
NGHolder *g = m.first;
|
||||||
|
const auto &edges = m.second;
|
||||||
if (contains(stuck, g)) {
|
if (contains(stuck, g)) {
|
||||||
DEBUG_PRINTF("already known to be bad\n");
|
DEBUG_PRINTF("already known to be bad\n");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
bool rv = extractStrongLiteral(*g, vg, edges_by_graph[g], cc);
|
bool rv = extractStrongLiteral(*g, vg, edges, cc);
|
||||||
if (rv) {
|
if (rv) {
|
||||||
changed = true;
|
changed = true;
|
||||||
} else {
|
} else {
|
||||||
@ -2228,8 +2226,7 @@ void improveWeakInfixes(RoseInGraph &vg, const CompileContext &cc) {
|
|||||||
|
|
||||||
RoseInVertex start = getStart(vg);
|
RoseInVertex start = getStart(vg);
|
||||||
|
|
||||||
set<NGHolder *> weak;
|
unordered_set<NGHolder *> weak;
|
||||||
vector<NGHolder *> ordered_weak;
|
|
||||||
|
|
||||||
for (RoseInVertex vv : adjacent_vertices_range(start, vg)) {
|
for (RoseInVertex vv : adjacent_vertices_range(start, vg)) {
|
||||||
/* outfixes shouldn't have made it this far */
|
/* outfixes shouldn't have made it this far */
|
||||||
@ -2245,22 +2242,22 @@ void improveWeakInfixes(RoseInGraph &vg, const CompileContext &cc) {
|
|||||||
|
|
||||||
NGHolder *h = vg[e].graph.get();
|
NGHolder *h = vg[e].graph.get();
|
||||||
DEBUG_PRINTF("'%s' guards %p\n", dumpString(vg[vv].s).c_str(), h);
|
DEBUG_PRINTF("'%s' guards %p\n", dumpString(vg[vv].s).c_str(), h);
|
||||||
if (!contains(weak, h)) {
|
weak.insert(h);
|
||||||
weak.insert(h);
|
|
||||||
ordered_weak.push_back(h);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
map<NGHolder *, vector<RoseInEdge> > weak_edges;
|
insertion_ordered_map<NGHolder *, vector<RoseInEdge>> weak_edges;
|
||||||
for (const RoseInEdge &ve : edges_range(vg)) {
|
for (const RoseInEdge &ve : edges_range(vg)) {
|
||||||
if (contains(weak, vg[ve].graph.get())) {
|
NGHolder *h = vg[ve].graph.get();
|
||||||
weak_edges[vg[ve].graph.get()].push_back(ve);
|
if (contains(weak, h)) {
|
||||||
|
weak_edges[h].push_back(ve);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (NGHolder *h : ordered_weak) {
|
for (const auto &m : weak_edges) {
|
||||||
improveInfix(*h, vg, weak_edges[h], cc);
|
NGHolder *h = m.first;
|
||||||
|
const auto &edges = m.second;
|
||||||
|
improveInfix(*h, vg, edges, cc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2416,8 +2413,8 @@ void avoidSuffixes(RoseInGraph &vg, const CompileContext &cc) {
|
|||||||
STAGE_DEBUG_PRINTF("AVOID SUFFIXES\n");
|
STAGE_DEBUG_PRINTF("AVOID SUFFIXES\n");
|
||||||
|
|
||||||
RoseInVertex accept = getPrimaryAccept(vg);
|
RoseInVertex accept = getPrimaryAccept(vg);
|
||||||
map<const NGHolder *, vector<RoseInEdge> > suffixes;
|
|
||||||
vector<const NGHolder *> ordered_suffixes;
|
insertion_ordered_map<const NGHolder *, vector<RoseInEdge>> suffixes;
|
||||||
|
|
||||||
/* find suffixes */
|
/* find suffixes */
|
||||||
for (const RoseInEdge &e : in_edges_range(accept, vg)) {
|
for (const RoseInEdge &e : in_edges_range(accept, vg)) {
|
||||||
@ -2426,15 +2423,14 @@ void avoidSuffixes(RoseInGraph &vg, const CompileContext &cc) {
|
|||||||
assert(vg[e].graph); /* non suffix paths should be wired to other
|
assert(vg[e].graph); /* non suffix paths should be wired to other
|
||||||
accepts */
|
accepts */
|
||||||
const NGHolder *h = vg[e].graph.get();
|
const NGHolder *h = vg[e].graph.get();
|
||||||
if (!contains(suffixes, h)) {
|
|
||||||
ordered_suffixes.push_back(h);
|
|
||||||
}
|
|
||||||
suffixes[h].push_back(e);
|
suffixes[h].push_back(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* look at suffixes and try to split */
|
/* look at suffixes and try to split */
|
||||||
for (const NGHolder *h : ordered_suffixes) {
|
for (const auto &m : suffixes) {
|
||||||
replaceSuffixWithInfix(*h, vg, suffixes[h], cc);
|
const NGHolder *h = m.first;
|
||||||
|
const auto &edges = m.second;
|
||||||
|
replaceSuffixWithInfix(*h, vg, edges, cc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2518,20 +2514,18 @@ void lookForDoubleCut(RoseInGraph &vg, const CompileContext &cc) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
map<const NGHolder *, vector<RoseInEdge> > right_edges;
|
insertion_ordered_map<const NGHolder *, vector<RoseInEdge>> right_edges;
|
||||||
vector<const NGHolder *> ordered_graphs;
|
|
||||||
for (const RoseInEdge &ve : edges_range(vg)) {
|
for (const RoseInEdge &ve : edges_range(vg)) {
|
||||||
if (vg[ve].graph && vg[source(ve, vg)].type == RIV_LITERAL) {
|
if (vg[ve].graph && vg[source(ve, vg)].type == RIV_LITERAL) {
|
||||||
const NGHolder *h = vg[ve].graph.get();
|
const NGHolder *h = vg[ve].graph.get();
|
||||||
if (!contains(right_edges, h)) {
|
|
||||||
ordered_graphs.push_back(h);
|
|
||||||
}
|
|
||||||
right_edges[h].push_back(ve);
|
right_edges[h].push_back(ve);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const NGHolder *h : ordered_graphs) {
|
for (const auto &m : right_edges) {
|
||||||
lookForDoubleCut(*h, right_edges[h], vg, cc.grey);
|
const NGHolder *h = m.first;
|
||||||
|
const auto &edges = m.second;
|
||||||
|
lookForDoubleCut(*h, edges, vg, cc.grey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2656,24 +2650,22 @@ void decomposeLiteralChains(RoseInGraph &vg, const CompileContext &cc) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
insertion_ordered_map<const NGHolder *, vector<RoseInEdge>> right_edges;
|
||||||
bool changed;
|
bool changed;
|
||||||
do {
|
do {
|
||||||
changed = false;
|
changed = false;
|
||||||
|
|
||||||
map<const NGHolder *, vector<RoseInEdge> > right_edges;
|
right_edges.clear();
|
||||||
vector<const NGHolder *> ordered_graphs;
|
|
||||||
for (const RoseInEdge &ve : edges_range(vg)) {
|
for (const RoseInEdge &ve : edges_range(vg)) {
|
||||||
if (vg[ve].graph && vg[source(ve, vg)].type == RIV_LITERAL) {
|
if (vg[ve].graph && vg[source(ve, vg)].type == RIV_LITERAL) {
|
||||||
const NGHolder *h = vg[ve].graph.get();
|
const NGHolder *h = vg[ve].graph.get();
|
||||||
if (!contains(right_edges, h)) {
|
|
||||||
ordered_graphs.push_back(h);
|
|
||||||
}
|
|
||||||
right_edges[h].push_back(ve);
|
right_edges[h].push_back(ve);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const NGHolder *h : ordered_graphs) {
|
for (const auto &m : right_edges) {
|
||||||
const vector<RoseInEdge> &ee = right_edges[h];
|
const NGHolder *h = m.first;
|
||||||
|
const vector<RoseInEdge> &ee = m.second;
|
||||||
bool rv = lookForDoubleCut(*h, ee, vg, cc.grey);
|
bool rv = lookForDoubleCut(*h, ee, vg, cc.grey);
|
||||||
if (!rv && h->kind != NFA_SUFFIX) {
|
if (!rv && h->kind != NFA_SUFFIX) {
|
||||||
rv = lookForTrailingLiteralDotStar(*h, ee, vg, cc.grey);
|
rv = lookForTrailingLiteralDotStar(*h, ee, vg, cc.grey);
|
||||||
@ -2701,39 +2693,34 @@ static
|
|||||||
void lookForCleanEarlySplits(RoseInGraph &vg, const CompileContext &cc) {
|
void lookForCleanEarlySplits(RoseInGraph &vg, const CompileContext &cc) {
|
||||||
u32 gen = 0;
|
u32 gen = 0;
|
||||||
|
|
||||||
vector<RoseInVertex> prev = {getStart(vg)};
|
insertion_ordered_set<RoseInVertex> prev({getStart(vg)});
|
||||||
|
insertion_ordered_set<RoseInVertex> curr;
|
||||||
|
|
||||||
while (gen < MAX_DESIRED_CLEAN_SPLIT_DEPTH) {
|
while (gen < MAX_DESIRED_CLEAN_SPLIT_DEPTH) {
|
||||||
/* collect vertices in edge order for determinism */
|
curr.clear();
|
||||||
vector<RoseInVertex> curr;
|
|
||||||
set<RoseInVertex> curr_seen;
|
|
||||||
for (RoseInVertex u : prev) {
|
for (RoseInVertex u : prev) {
|
||||||
for (auto v : adjacent_vertices_range(u, vg)) {
|
for (auto v : adjacent_vertices_range(u, vg)) {
|
||||||
if (curr_seen.insert(v).second) {
|
curr.insert(v);
|
||||||
curr.push_back(v);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
map<const NGHolder *, vector<RoseInEdge>> rightfixes;
|
insertion_ordered_map<const NGHolder *, vector<RoseInEdge>> rightfixes;
|
||||||
vector<NGHolder *> ordered_graphs;
|
|
||||||
for (RoseInVertex v : curr) {
|
for (RoseInVertex v : curr) {
|
||||||
for (const RoseInEdge &e : out_edges_range(v, vg)) {
|
for (const RoseInEdge &e : out_edges_range(v, vg)) {
|
||||||
if (vg[e].graph) {
|
if (vg[e].graph) {
|
||||||
NGHolder *h = vg[e].graph.get();
|
NGHolder *h = vg[e].graph.get();
|
||||||
if (!contains(rightfixes, h)) {
|
|
||||||
ordered_graphs.push_back(h);
|
|
||||||
}
|
|
||||||
rightfixes[h].push_back(e);
|
rightfixes[h].push_back(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const NGHolder *h : ordered_graphs) {
|
for (const auto &m : rightfixes) {
|
||||||
lookForCleanSplit(*h, rightfixes[h], vg, cc);
|
const NGHolder *h = m.first;
|
||||||
|
const auto &edges = m.second;
|
||||||
|
lookForCleanSplit(*h, edges, vg, cc);
|
||||||
}
|
}
|
||||||
|
|
||||||
prev = curr;
|
prev = std::move(curr);
|
||||||
gen++;
|
gen++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2907,18 +2894,16 @@ bool ensureImplementable(RoseBuild &rose, RoseInGraph &vg, bool allow_changes,
|
|||||||
do {
|
do {
|
||||||
changed = false;
|
changed = false;
|
||||||
DEBUG_PRINTF("added %u\n", added_count);
|
DEBUG_PRINTF("added %u\n", added_count);
|
||||||
map<const NGHolder *, vector<RoseInEdge> > edges_by_graph;
|
insertion_ordered_map<shared_ptr<NGHolder>,
|
||||||
vector<shared_ptr<NGHolder>> graphs;
|
vector<RoseInEdge>> edges_by_graph;
|
||||||
for (const RoseInEdge &ve : edges_range(vg)) {
|
for (const RoseInEdge &ve : edges_range(vg)) {
|
||||||
if (vg[ve].graph && !vg[ve].dfa) {
|
if (vg[ve].graph && !vg[ve].dfa) {
|
||||||
auto &h = vg[ve].graph;
|
auto &h = vg[ve].graph;
|
||||||
if (!contains(edges_by_graph, h.get())) {
|
edges_by_graph[h].push_back(ve);
|
||||||
graphs.push_back(h);
|
|
||||||
}
|
|
||||||
edges_by_graph[h.get()].push_back(ve);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (auto &h : graphs) {
|
for (auto &m : edges_by_graph) {
|
||||||
|
auto &h = m.first;
|
||||||
if (contains(good, h)) {
|
if (contains(good, h)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -2928,9 +2913,10 @@ bool ensureImplementable(RoseBuild &rose, RoseInGraph &vg, bool allow_changes,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tryForEarlyDfa(*h, cc)
|
const auto &edges = m.second;
|
||||||
&& doEarlyDfa(rose, vg, *h, edges_by_graph[h.get()],
|
|
||||||
final_chance, rm, cc)) {
|
if (tryForEarlyDfa(*h, cc) &&
|
||||||
|
doEarlyDfa(rose, vg, *h, edges, final_chance, rm, cc)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2939,7 +2925,7 @@ bool ensureImplementable(RoseBuild &rose, RoseInGraph &vg, bool allow_changes,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (splitForImplementability(vg, *h, edges_by_graph[h.get()], cc)) {
|
if (splitForImplementability(vg, *h, edges, cc)) {
|
||||||
added_count++;
|
added_count++;
|
||||||
if (added_count > MAX_IMPLEMENTABLE_SPLITS) {
|
if (added_count > MAX_IMPLEMENTABLE_SPLITS) {
|
||||||
DEBUG_PRINTF("added_count hit limit\n");
|
DEBUG_PRINTF("added_count hit limit\n");
|
||||||
|
@ -55,6 +55,7 @@
|
|||||||
#include "util/container.h"
|
#include "util/container.h"
|
||||||
#include "util/dump_charclass.h"
|
#include "util/dump_charclass.h"
|
||||||
#include "util/graph_range.h"
|
#include "util/graph_range.h"
|
||||||
|
#include "util/insertion_ordered.h"
|
||||||
#include "util/make_unique.h"
|
#include "util/make_unique.h"
|
||||||
#include "util/noncopyable.h"
|
#include "util/noncopyable.h"
|
||||||
#include "util/order_check.h"
|
#include "util/order_check.h"
|
||||||
@ -1525,8 +1526,7 @@ bool RoseBuildImpl::addRose(const RoseInGraph &ig, bool prefilter) {
|
|||||||
renumber_vertices(in);
|
renumber_vertices(in);
|
||||||
assert(validateKinds(in));
|
assert(validateKinds(in));
|
||||||
|
|
||||||
map<NGHolder *, vector<RoseInEdge> > graphs;
|
insertion_ordered_map<NGHolder *, vector<RoseInEdge>> graphs;
|
||||||
vector<NGHolder *> ordered_graphs; // Stored in first-encounter order.
|
|
||||||
|
|
||||||
for (const auto &e : edges_range(in)) {
|
for (const auto &e : edges_range(in)) {
|
||||||
if (!in[e].graph) {
|
if (!in[e].graph) {
|
||||||
@ -1544,21 +1544,17 @@ bool RoseBuildImpl::addRose(const RoseInGraph &ig, bool prefilter) {
|
|||||||
NGHolder *h = in[e].graph.get();
|
NGHolder *h = in[e].graph.get();
|
||||||
|
|
||||||
assert(isCorrectlyTopped(*h));
|
assert(isCorrectlyTopped(*h));
|
||||||
if (!contains(graphs, h)) {
|
|
||||||
ordered_graphs.push_back(h);
|
|
||||||
}
|
|
||||||
graphs[h].push_back(e);
|
graphs[h].push_back(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(ordered_graphs.size() == graphs.size());
|
|
||||||
|
|
||||||
vector<RoseInEdge> graph_edges;
|
vector<RoseInEdge> graph_edges;
|
||||||
|
|
||||||
for (auto h : ordered_graphs) {
|
for (const auto &m : graphs) {
|
||||||
|
NGHolder *h = m.first;
|
||||||
if (!canImplementGraph(*h, prefilter, rm, cc)) {
|
if (!canImplementGraph(*h, prefilter, rm, cc)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
insert(&graph_edges, graph_edges.end(), graphs[h]);
|
insert(&graph_edges, graph_edges.end(), m.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we are now past the point of no return. We can start making irreversible
|
/* we are now past the point of no return. We can start making irreversible
|
||||||
|
@ -86,6 +86,7 @@
|
|||||||
#include "util/container.h"
|
#include "util/container.h"
|
||||||
#include "util/fatbit_build.h"
|
#include "util/fatbit_build.h"
|
||||||
#include "util/graph_range.h"
|
#include "util/graph_range.h"
|
||||||
|
#include "util/insertion_ordered.h"
|
||||||
#include "util/make_unique.h"
|
#include "util/make_unique.h"
|
||||||
#include "util/multibit_build.h"
|
#include "util/multibit_build.h"
|
||||||
#include "util/noncopyable.h"
|
#include "util/noncopyable.h"
|
||||||
@ -1474,11 +1475,11 @@ bool buildLeftfixes(RoseBuildImpl &tbi, build_context &bc,
|
|||||||
RoseGraph &g = tbi.g;
|
RoseGraph &g = tbi.g;
|
||||||
const CompileContext &cc = tbi.cc;
|
const CompileContext &cc = tbi.cc;
|
||||||
|
|
||||||
map<left_id, set<PredTopPair> > infixTriggers;
|
map<left_id, set<PredTopPair>> infixTriggers;
|
||||||
vector<left_id> order;
|
|
||||||
unordered_map<left_id, vector<RoseVertex>> succs;
|
|
||||||
findInfixTriggers(tbi, &infixTriggers);
|
findInfixTriggers(tbi, &infixTriggers);
|
||||||
|
|
||||||
|
insertion_ordered_map<left_id, vector<RoseVertex>> succs;
|
||||||
|
|
||||||
if (cc.grey.allowTamarama && cc.streaming && !do_prefix) {
|
if (cc.grey.allowTamarama && cc.streaming && !do_prefix) {
|
||||||
findExclusiveInfixes(tbi, bc, qif, infixTriggers, no_retrigger_queues);
|
findExclusiveInfixes(tbi, bc, qif, infixTriggers, no_retrigger_queues);
|
||||||
}
|
}
|
||||||
@ -1517,10 +1518,6 @@ bool buildLeftfixes(RoseBuildImpl &tbi, build_context &bc,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!contains(succs, leftfix)) {
|
|
||||||
order.push_back(leftfix);
|
|
||||||
}
|
|
||||||
|
|
||||||
succs[leftfix].push_back(v);
|
succs[leftfix].push_back(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1529,8 +1526,9 @@ bool buildLeftfixes(RoseBuildImpl &tbi, build_context &bc,
|
|||||||
|
|
||||||
map<left_id, eager_info> eager;
|
map<left_id, eager_info> eager;
|
||||||
|
|
||||||
for (const left_id &leftfix : order) {
|
for (const auto &m : succs) {
|
||||||
const auto &left_succs = succs[leftfix];
|
const left_id &leftfix = m.first;
|
||||||
|
const auto &left_succs = m.second;
|
||||||
|
|
||||||
rose_group squash_mask = tbi.rose_squash_masks.at(leftfix);
|
rose_group squash_mask = tbi.rose_squash_masks.at(leftfix);
|
||||||
eager_info ei;
|
eager_info ei;
|
||||||
@ -1549,9 +1547,11 @@ bool buildLeftfixes(RoseBuildImpl &tbi, build_context &bc,
|
|||||||
eager.clear();
|
eager.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const left_id &leftfix : order) {
|
for (const auto &m : succs) {
|
||||||
|
const left_id &leftfix = m.first;
|
||||||
|
const auto &left_succs = m.second;
|
||||||
buildLeftfix(tbi, bc, do_prefix, qif.get_queue(), infixTriggers,
|
buildLeftfix(tbi, bc, do_prefix, qif.get_queue(), infixTriggers,
|
||||||
no_retrigger_queues, eager_queues, eager, succs[leftfix],
|
no_retrigger_queues, eager_queues, eager, left_succs,
|
||||||
leftfix);
|
leftfix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
368
src/util/insertion_ordered.h
Normal file
368
src/util/insertion_ordered.h
Normal file
@ -0,0 +1,368 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, Intel Corporation
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Intel Corporation nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef UTIL_INSERTION_ORDERED_H
|
||||||
|
#define UTIL_INSERTION_ORDERED_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief Insertion-ordered associative containers (set, map).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "util/operators.h"
|
||||||
|
#include "util/unordered.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <iterator>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <boost/iterator/iterator_facade.hpp>
|
||||||
|
|
||||||
|
namespace ue2 {
|
||||||
|
|
||||||
|
namespace insertion_ordered_detail {
|
||||||
|
|
||||||
|
// Iterator facade that wraps an underlying iterator, so that we get our
|
||||||
|
// own iterator types.
|
||||||
|
template<class WrappedIter, class Value>
|
||||||
|
class iter_wrapper
|
||||||
|
: public boost::iterator_facade<iter_wrapper<WrappedIter, Value>, Value,
|
||||||
|
boost::random_access_traversal_tag> {
|
||||||
|
public:
|
||||||
|
iter_wrapper() = default;
|
||||||
|
explicit iter_wrapper(WrappedIter it_in) : it(std::move(it_in)) {}
|
||||||
|
|
||||||
|
// Templated copy-constructor to allow for interoperable iterator and
|
||||||
|
// const_iterator.
|
||||||
|
template<class, class> friend class iter_wrapper;
|
||||||
|
|
||||||
|
template<class OtherIter, class OtherValue>
|
||||||
|
iter_wrapper(iter_wrapper<OtherIter, OtherValue> other,
|
||||||
|
typename std::enable_if<std::is_convertible<
|
||||||
|
OtherIter, WrappedIter>::value>::type * = nullptr)
|
||||||
|
: it(std::move(other.it)) {}
|
||||||
|
|
||||||
|
WrappedIter get() const { return it; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class boost::iterator_core_access;
|
||||||
|
|
||||||
|
WrappedIter it;
|
||||||
|
|
||||||
|
void increment() { ++it; }
|
||||||
|
void decrement() { --it; }
|
||||||
|
void advance(size_t n) { it += n; }
|
||||||
|
typename std::iterator_traits<WrappedIter>::difference_type
|
||||||
|
distance_to(const iter_wrapper &other) const {
|
||||||
|
return other.it - it;
|
||||||
|
}
|
||||||
|
bool equal(const iter_wrapper &other) const { return it == other.it; }
|
||||||
|
Value &dereference() const { return *it; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Key, class Element>
|
||||||
|
class element_store {
|
||||||
|
std::vector<Element> data;
|
||||||
|
ue2_unordered_map<Key, size_t> map;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool empty() const {
|
||||||
|
return data.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const {
|
||||||
|
assert(data.size() == map.size());
|
||||||
|
return data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
data.clear();
|
||||||
|
map.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void reserve(size_t n) {
|
||||||
|
data.reserve(n);
|
||||||
|
map.reserve(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iteration.
|
||||||
|
|
||||||
|
using const_iterator =
|
||||||
|
iter_wrapper<typename std::vector<Element>::const_iterator,
|
||||||
|
const Element>;
|
||||||
|
using iterator =
|
||||||
|
iter_wrapper<typename std::vector<Element>::iterator, Element>;
|
||||||
|
|
||||||
|
const_iterator begin() const {
|
||||||
|
return const_iterator(data.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator end() const {
|
||||||
|
return const_iterator(data.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator begin() {
|
||||||
|
return iterator(data.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator end() {
|
||||||
|
return iterator(data.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search.
|
||||||
|
|
||||||
|
const_iterator find(const Key &key) const {
|
||||||
|
auto map_it = map.find(key);
|
||||||
|
if (map_it == map.end()) {
|
||||||
|
return end();
|
||||||
|
}
|
||||||
|
auto idx = map_it->second;
|
||||||
|
assert(idx < data.size());
|
||||||
|
return begin() + idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator find(const Key &key) {
|
||||||
|
auto map_it = map.find(key);
|
||||||
|
if (map_it == map.end()) {
|
||||||
|
return end();
|
||||||
|
}
|
||||||
|
auto idx = map_it->second;
|
||||||
|
assert(idx < data.size());
|
||||||
|
return begin() + idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert.
|
||||||
|
|
||||||
|
std::pair<iterator, bool> insert(const Key &key, const Element &element) {
|
||||||
|
const auto idx = data.size();
|
||||||
|
if (map.emplace(key, idx).second) {
|
||||||
|
data.push_back(element);
|
||||||
|
return {begin() + idx, true};
|
||||||
|
}
|
||||||
|
return {end(), false};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const element_store &a) const {
|
||||||
|
return data == a.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const element_store &a) const {
|
||||||
|
return data < a.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(element_store &a) {
|
||||||
|
using std::swap;
|
||||||
|
swap(data, a.data);
|
||||||
|
swap(map, a.map);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace insertion_ordered_detail
|
||||||
|
|
||||||
|
template<class Key, class Value>
|
||||||
|
class insertion_ordered_map
|
||||||
|
: public totally_ordered<insertion_ordered_map<Key, Value>> {
|
||||||
|
public:
|
||||||
|
using key_type = Key;
|
||||||
|
using mapped_type = Value;
|
||||||
|
using value_type = std::pair<const Key, Value>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
using store_type = insertion_ordered_detail::element_store<Key, value_type>;
|
||||||
|
store_type store;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using const_iterator = typename store_type::const_iterator;
|
||||||
|
using iterator = typename store_type::iterator;
|
||||||
|
|
||||||
|
insertion_ordered_map() = default;
|
||||||
|
|
||||||
|
template<class Iter>
|
||||||
|
insertion_ordered_map(Iter it, Iter it_end) {
|
||||||
|
insert(it, it_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit insertion_ordered_map(std::initializer_list<value_type> init) {
|
||||||
|
insert(init.begin(), init.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator begin() const { return store.begin(); }
|
||||||
|
const_iterator end() const { return store.end(); }
|
||||||
|
iterator begin() { return store.begin(); }
|
||||||
|
iterator end() { return store.end(); }
|
||||||
|
|
||||||
|
const_iterator find(const Key &key) const {
|
||||||
|
return store.find(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator find(const Key &key) {
|
||||||
|
return store.find(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<iterator, bool> insert(const std::pair<const Key, Value> &p) {
|
||||||
|
return store.insert(p.first, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Iter>
|
||||||
|
void insert(Iter it, Iter it_end) {
|
||||||
|
for (; it != it_end; ++it) {
|
||||||
|
insert(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Value &operator[](const Key &key) {
|
||||||
|
auto it = find(key);
|
||||||
|
if (it == end()) {
|
||||||
|
it = insert({key, Value{}}).first;
|
||||||
|
}
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Value &at(const Key &key) const {
|
||||||
|
return find(key)->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value &at(const Key &key) {
|
||||||
|
return find(key)->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const {
|
||||||
|
return store.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const {
|
||||||
|
return store.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
store.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void reserve(size_t n) {
|
||||||
|
store.reserve(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const insertion_ordered_map &a) const {
|
||||||
|
return store == a.store;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const insertion_ordered_map &a) const {
|
||||||
|
return store < a.store;
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(insertion_ordered_map &a) {
|
||||||
|
store.swap(a.store);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend void swap(insertion_ordered_map &a, insertion_ordered_map &b) {
|
||||||
|
a.swap(b);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Key>
|
||||||
|
class insertion_ordered_set
|
||||||
|
: public totally_ordered<insertion_ordered_set<Key>> {
|
||||||
|
public:
|
||||||
|
using key_type = Key;
|
||||||
|
using value_type = Key;
|
||||||
|
|
||||||
|
private:
|
||||||
|
using store_type = insertion_ordered_detail::element_store<Key, value_type>;
|
||||||
|
store_type store;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using const_iterator = typename store_type::const_iterator;
|
||||||
|
using iterator = typename store_type::iterator;
|
||||||
|
|
||||||
|
insertion_ordered_set() = default;
|
||||||
|
|
||||||
|
template<class Iter>
|
||||||
|
insertion_ordered_set(Iter it, Iter it_end) {
|
||||||
|
insert(it, it_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit insertion_ordered_set(std::initializer_list<value_type> init) {
|
||||||
|
insert(init.begin(), init.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator begin() const { return store.begin(); }
|
||||||
|
const_iterator end() const { return store.end(); }
|
||||||
|
|
||||||
|
const_iterator find(const Key &key) const {
|
||||||
|
return store.find(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<iterator, bool> insert(const Key &key) {
|
||||||
|
return store.insert(key, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Iter>
|
||||||
|
void insert(Iter it, Iter it_end) {
|
||||||
|
for (; it != it_end; ++it) {
|
||||||
|
insert(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const {
|
||||||
|
return store.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const {
|
||||||
|
return store.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
store.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void reserve(size_t n) {
|
||||||
|
store.reserve(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const insertion_ordered_set &a) const {
|
||||||
|
return store == a.store;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const insertion_ordered_set &a) const {
|
||||||
|
return store < a.store;
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(insertion_ordered_set &a) {
|
||||||
|
store.swap(a.store);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend void swap(insertion_ordered_set &a, insertion_ordered_set &b) {
|
||||||
|
a.swap(b);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ue2
|
||||||
|
|
||||||
|
#endif // UTIL_INSERTION_ORDERED_H
|
@ -78,6 +78,7 @@ set(unit_internal_SOURCES
|
|||||||
internal/flat_set.cpp
|
internal/flat_set.cpp
|
||||||
internal/flat_map.cpp
|
internal/flat_map.cpp
|
||||||
internal/graph.cpp
|
internal/graph.cpp
|
||||||
|
internal/insertion_ordered.cpp
|
||||||
internal/lbr.cpp
|
internal/lbr.cpp
|
||||||
internal/limex_nfa.cpp
|
internal/limex_nfa.cpp
|
||||||
internal/masked_move.cpp
|
internal/masked_move.cpp
|
||||||
|
209
unit/internal/insertion_ordered.cpp
Normal file
209
unit/internal/insertion_ordered.cpp
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, Intel Corporation
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Intel Corporation nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "ue2common.h"
|
||||||
|
#include "util/insertion_ordered.h"
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace ue2;
|
||||||
|
|
||||||
|
template <class K, class V>
|
||||||
|
std::ostream &operator<<(std::ostream &os,
|
||||||
|
const insertion_ordered_map<K, V> &m) {
|
||||||
|
os << "{";
|
||||||
|
for (auto it = begin(m); it != end(m); ++it) {
|
||||||
|
os << "{" << it->first << ", " << it->second << "}";
|
||||||
|
if (it != end(m)) {
|
||||||
|
os << ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
os << "}";
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(insertion_ordered_map, empty) {
|
||||||
|
insertion_ordered_map<u32, u32> m;
|
||||||
|
EXPECT_TRUE(m.empty());
|
||||||
|
EXPECT_TRUE(m.begin() == m.end());
|
||||||
|
EXPECT_EQ(0, m.size());
|
||||||
|
|
||||||
|
m.insert({10, 10});
|
||||||
|
EXPECT_FALSE(m.empty());
|
||||||
|
EXPECT_EQ(1, m.size());
|
||||||
|
|
||||||
|
m.clear();
|
||||||
|
EXPECT_TRUE(m.empty());
|
||||||
|
EXPECT_TRUE(m.begin() == m.end());
|
||||||
|
EXPECT_EQ(0, m.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(insertion_ordered_map, insert) {
|
||||||
|
const vector<pair<u32, u32>> v = {{7, 1}, {1, 2}, {3, 4},
|
||||||
|
{10, 5}, {99, 6}, {12, 7}};
|
||||||
|
insertion_ordered_map<u32, u32> m;
|
||||||
|
for (const auto &e : v) {
|
||||||
|
m.insert(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_FALSE(m.empty());
|
||||||
|
EXPECT_EQ(v.size(), m.size());
|
||||||
|
vector<pair<u32, u32>> v2(m.begin(), m.end());
|
||||||
|
EXPECT_EQ(v, v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(insertion_ordered_map, insert_iter) {
|
||||||
|
const vector<pair<u32, u32>> v = {{7, 1}, {1, 2}, {3, 4},
|
||||||
|
{10, 5}, {99, 6}, {12, 7}};
|
||||||
|
insertion_ordered_map<u32, u32> m;
|
||||||
|
m.insert(v.begin(), v.end());
|
||||||
|
|
||||||
|
EXPECT_FALSE(m.empty());
|
||||||
|
EXPECT_EQ(v.size(), m.size());
|
||||||
|
vector<pair<u32, u32>> v2(m.begin(), m.end());
|
||||||
|
EXPECT_EQ(v, v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(insertion_ordered_map, find_const) {
|
||||||
|
const vector<pair<u32, u32>> v = {{7, 1}, {1, 2}, {3, 4},
|
||||||
|
{10, 5}, {99, 6}, {12, 7}};
|
||||||
|
const insertion_ordered_map<u32, u32> m(v.begin(), v.end());
|
||||||
|
|
||||||
|
for (const auto &e : v) {
|
||||||
|
auto it = m.find(e.first);
|
||||||
|
ASSERT_NE(m.end(), it);
|
||||||
|
EXPECT_EQ(e.first, it->first);
|
||||||
|
EXPECT_EQ(e.second, it->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(insertion_ordered_map, find_mutable) {
|
||||||
|
const vector<pair<u32, u32>> v = {{7, 1}, {1, 2}, {3, 4},
|
||||||
|
{10, 5}, {99, 6}, {12, 7}};
|
||||||
|
insertion_ordered_map<u32, u32> m(v.begin(), v.end());
|
||||||
|
|
||||||
|
for (const auto &e : v) {
|
||||||
|
auto it = m.find(e.first);
|
||||||
|
ASSERT_NE(m.end(), it);
|
||||||
|
EXPECT_EQ(e.first, it->first);
|
||||||
|
EXPECT_EQ(e.second, it->second);
|
||||||
|
auto &mut = it->second;
|
||||||
|
++mut;
|
||||||
|
EXPECT_EQ(e.second + 1, m.at(e.first));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(insertion_ordered_map, operator_brackets) {
|
||||||
|
insertion_ordered_map<u32, u32> m;
|
||||||
|
|
||||||
|
u32 val = 1000;
|
||||||
|
for (u32 i = 10; i > 0; i--) {
|
||||||
|
m[i] = val++;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_EQ(10, m.size());
|
||||||
|
|
||||||
|
val = 1000;
|
||||||
|
auto it = m.begin();
|
||||||
|
for (u32 i = 10; i > 0; i--) {
|
||||||
|
ASSERT_NE(m.end(), it);
|
||||||
|
EXPECT_EQ(i, it->first);
|
||||||
|
EXPECT_EQ(val, it->second);
|
||||||
|
++val;
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_EQ(m.end(), it);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K>
|
||||||
|
std::ostream &operator<<(std::ostream &os, const insertion_ordered_set<K> &s) {
|
||||||
|
os << "{";
|
||||||
|
for (auto it = begin(s); it != end(s); ++it) {
|
||||||
|
os << *it;
|
||||||
|
if (it != end(s)) {
|
||||||
|
os << ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
os << "}";
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(insertion_ordered_set, empty) {
|
||||||
|
insertion_ordered_set<u32> m;
|
||||||
|
EXPECT_TRUE(m.empty());
|
||||||
|
EXPECT_TRUE(m.begin() == m.end());
|
||||||
|
EXPECT_EQ(0, m.size());
|
||||||
|
|
||||||
|
m.insert(10);
|
||||||
|
EXPECT_FALSE(m.empty());
|
||||||
|
EXPECT_EQ(1, m.size());
|
||||||
|
|
||||||
|
m.clear();
|
||||||
|
EXPECT_TRUE(m.empty());
|
||||||
|
EXPECT_TRUE(m.begin() == m.end());
|
||||||
|
EXPECT_EQ(0, m.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(insertion_ordered_set, insert) {
|
||||||
|
const vector<u32> v = {7, 1, 3, 10, 99, 12};
|
||||||
|
insertion_ordered_set<u32> s;
|
||||||
|
for (const auto &e : v) {
|
||||||
|
s.insert(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_FALSE(s.empty());
|
||||||
|
EXPECT_EQ(v.size(), s.size());
|
||||||
|
vector<u32> v2(s.begin(), s.end());
|
||||||
|
EXPECT_EQ(v, v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(insertion_ordered_set, insert_iter) {
|
||||||
|
const vector<u32> v = {7, 1, 3, 10, 99, 12};
|
||||||
|
insertion_ordered_set<u32> s;
|
||||||
|
s.insert(v.begin(), v.end());
|
||||||
|
|
||||||
|
EXPECT_FALSE(s.empty());
|
||||||
|
EXPECT_EQ(v.size(), s.size());
|
||||||
|
vector<u32> v2(s.begin(), s.end());
|
||||||
|
EXPECT_EQ(v, v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(insertion_ordered_set, find_const) {
|
||||||
|
const vector<u32> v = {7, 1, 3, 10, 99, 12};
|
||||||
|
const insertion_ordered_set<u32> s(v.begin(), v.end());
|
||||||
|
|
||||||
|
for (const auto &e : v) {
|
||||||
|
auto it = s.find(e);
|
||||||
|
ASSERT_NE(s.end(), it);
|
||||||
|
EXPECT_EQ(e, *it);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user