mirror of
https://github.com/VectorCamp/vectorscan.git
synced 2025-06-28 16:41:01 +03:00
rose_build: reduce size/scope of context objects
This commit is contained in:
parent
a2b2940f85
commit
37cb93e60f
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2015-2016, Intel Corporation
|
* Copyright (c) 2015-2017, Intel Corporation
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
@ -560,7 +560,7 @@ buildCastle(const CastleProto &proto,
|
|||||||
DEBUG_PRINTF("%zu subcastles may go stale\n", may_stale.size());
|
DEBUG_PRINTF("%zu subcastles may go stale\n", may_stale.size());
|
||||||
vector<mmbit_sparse_iter> stale_iter;
|
vector<mmbit_sparse_iter> stale_iter;
|
||||||
if (!may_stale.empty()) {
|
if (!may_stale.empty()) {
|
||||||
mmbBuildSparseIterator(stale_iter, may_stale, numRepeats);
|
stale_iter = mmbBuildSparseIterator(may_stale, numRepeats);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
#include "grey.h"
|
#include "grey.h"
|
||||||
#include "rose_build_impl.h"
|
#include "rose_build_impl.h"
|
||||||
|
#include "rose_build_matchers.h"
|
||||||
#include "rose_internal.h"
|
#include "rose_internal.h"
|
||||||
#include "ue2common.h"
|
#include "ue2common.h"
|
||||||
#include "nfa/dfa_min.h"
|
#include "nfa/dfa_min.h"
|
||||||
@ -71,6 +72,8 @@ namespace ue2 {
|
|||||||
|
|
||||||
#define INIT_STATE (DEAD_STATE + 1)
|
#define INIT_STATE (DEAD_STATE + 1)
|
||||||
|
|
||||||
|
#define NO_FRAG_ID (~0U)
|
||||||
|
|
||||||
// Adds a vertex with the given reach.
|
// Adds a vertex with the given reach.
|
||||||
static
|
static
|
||||||
NFAVertex add_vertex(NGHolder &h, const CharReach &cr) {
|
NFAVertex add_vertex(NGHolder &h, const CharReach &cr) {
|
||||||
@ -173,7 +176,7 @@ void mergeAnchoredDfas(vector<unique_ptr<raw_dfa>> &dfas,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void remapAnchoredReports(raw_dfa &rdfa, const RoseBuildImpl &build) {
|
void remapAnchoredReports(raw_dfa &rdfa, const vector<u32> &frag_map) {
|
||||||
for (dstate &ds : rdfa.states) {
|
for (dstate &ds : rdfa.states) {
|
||||||
assert(ds.reports_eod.empty()); // Not used in anchored matcher.
|
assert(ds.reports_eod.empty()); // Not used in anchored matcher.
|
||||||
if (ds.reports.empty()) {
|
if (ds.reports.empty()) {
|
||||||
@ -182,8 +185,8 @@ void remapAnchoredReports(raw_dfa &rdfa, const RoseBuildImpl &build) {
|
|||||||
|
|
||||||
flat_set<ReportID> new_reports;
|
flat_set<ReportID> new_reports;
|
||||||
for (auto id : ds.reports) {
|
for (auto id : ds.reports) {
|
||||||
assert(id < build.literal_info.size());
|
assert(id < frag_map.size());
|
||||||
new_reports.insert(build.literal_info.at(id).fragment_id);
|
new_reports.insert(frag_map[id]);
|
||||||
}
|
}
|
||||||
ds.reports = std::move(new_reports);
|
ds.reports = std::move(new_reports);
|
||||||
}
|
}
|
||||||
@ -194,21 +197,37 @@ void remapAnchoredReports(raw_dfa &rdfa, const RoseBuildImpl &build) {
|
|||||||
* ids) with the fragment id for each literal.
|
* ids) with the fragment id for each literal.
|
||||||
*/
|
*/
|
||||||
static
|
static
|
||||||
void remapAnchoredReports(RoseBuildImpl &build) {
|
void remapAnchoredReports(RoseBuildImpl &build, const vector<u32> &frag_map) {
|
||||||
for (auto &m : build.anchored_nfas) {
|
for (auto &m : build.anchored_nfas) {
|
||||||
for (auto &rdfa : m.second) {
|
for (auto &rdfa : m.second) {
|
||||||
assert(rdfa);
|
assert(rdfa);
|
||||||
remapAnchoredReports(*rdfa, build);
|
remapAnchoredReports(*rdfa, frag_map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns mapping from literal ids to fragment ids.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
vector<u32> reverseFragMap(const RoseBuildImpl &build,
|
||||||
|
const vector<LitFragment> &fragments) {
|
||||||
|
vector<u32> rev(build.literal_info.size(), NO_FRAG_ID);
|
||||||
|
for (const auto &f : fragments) {
|
||||||
|
for (u32 lit_id : f.lit_ids) {
|
||||||
|
assert(lit_id < rev.size());
|
||||||
|
rev[lit_id] = f.fragment_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rev;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Replace the reports (which are literal final_ids) in the given
|
* \brief Replace the reports (which are literal final_ids) in the given
|
||||||
* raw_dfa with program offsets.
|
* raw_dfa with program offsets.
|
||||||
*/
|
*/
|
||||||
static
|
static
|
||||||
void remapIdsToPrograms(const RoseBuildImpl &build, raw_dfa &rdfa) {
|
void remapIdsToPrograms(const vector<LitFragment> &fragments, raw_dfa &rdfa) {
|
||||||
for (dstate &ds : rdfa.states) {
|
for (dstate &ds : rdfa.states) {
|
||||||
assert(ds.reports_eod.empty()); // Not used in anchored matcher.
|
assert(ds.reports_eod.empty()); // Not used in anchored matcher.
|
||||||
if (ds.reports.empty()) {
|
if (ds.reports.empty()) {
|
||||||
@ -217,7 +236,7 @@ void remapIdsToPrograms(const RoseBuildImpl &build, raw_dfa &rdfa) {
|
|||||||
|
|
||||||
flat_set<ReportID> new_reports;
|
flat_set<ReportID> new_reports;
|
||||||
for (auto fragment_id : ds.reports) {
|
for (auto fragment_id : ds.reports) {
|
||||||
auto &frag = build.fragments.at(fragment_id);
|
const auto &frag = fragments.at(fragment_id);
|
||||||
new_reports.insert(frag.lit_program_offset);
|
new_reports.insert(frag.lit_program_offset);
|
||||||
}
|
}
|
||||||
ds.reports = std::move(new_reports);
|
ds.reports = std::move(new_reports);
|
||||||
@ -731,7 +750,7 @@ int addToAnchoredMatcher(RoseBuildImpl &build, const NGHolder &anchored,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void buildSimpleDfas(const RoseBuildImpl &build,
|
void buildSimpleDfas(const RoseBuildImpl &build, const vector<u32> &frag_map,
|
||||||
vector<unique_ptr<raw_dfa>> *anchored_dfas) {
|
vector<unique_ptr<raw_dfa>> *anchored_dfas) {
|
||||||
/* we should have determinised all of these before so there should be no
|
/* we should have determinised all of these before so there should be no
|
||||||
* chance of failure. */
|
* chance of failure. */
|
||||||
@ -739,7 +758,8 @@ void buildSimpleDfas(const RoseBuildImpl &build,
|
|||||||
for (const auto &simple : build.anchored_simple) {
|
for (const auto &simple : build.anchored_simple) {
|
||||||
exit_ids.clear();
|
exit_ids.clear();
|
||||||
for (auto lit_id : simple.second) {
|
for (auto lit_id : simple.second) {
|
||||||
exit_ids.insert(build.literal_info[lit_id].fragment_id);
|
assert(lit_id < frag_map.size());
|
||||||
|
exit_ids.insert(frag_map[lit_id]);
|
||||||
}
|
}
|
||||||
auto h = populate_holder(simple.first, exit_ids);
|
auto h = populate_holder(simple.first, exit_ids);
|
||||||
Automaton_Holder autom(*h);
|
Automaton_Holder autom(*h);
|
||||||
@ -760,7 +780,8 @@ void buildSimpleDfas(const RoseBuildImpl &build,
|
|||||||
* from RoseBuildImpl.
|
* from RoseBuildImpl.
|
||||||
*/
|
*/
|
||||||
static
|
static
|
||||||
vector<unique_ptr<raw_dfa>> getAnchoredDfas(RoseBuildImpl &build) {
|
vector<unique_ptr<raw_dfa>> getAnchoredDfas(RoseBuildImpl &build,
|
||||||
|
const vector<u32> &frag_map) {
|
||||||
vector<unique_ptr<raw_dfa>> dfas;
|
vector<unique_ptr<raw_dfa>> dfas;
|
||||||
|
|
||||||
// DFAs that already exist as raw_dfas.
|
// DFAs that already exist as raw_dfas.
|
||||||
@ -773,7 +794,7 @@ vector<unique_ptr<raw_dfa>> getAnchoredDfas(RoseBuildImpl &build) {
|
|||||||
|
|
||||||
// DFAs we currently have as simple literals.
|
// DFAs we currently have as simple literals.
|
||||||
if (!build.anchored_simple.empty()) {
|
if (!build.anchored_simple.empty()) {
|
||||||
buildSimpleDfas(build, &dfas);
|
buildSimpleDfas(build, frag_map, &dfas);
|
||||||
build.anchored_simple.clear();
|
build.anchored_simple.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -825,7 +846,8 @@ size_t buildNfas(vector<raw_dfa> &anchored_dfas,
|
|||||||
return total_size;
|
return total_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<raw_dfa> buildAnchoredDfas(RoseBuildImpl &build) {
|
vector<raw_dfa> buildAnchoredDfas(RoseBuildImpl &build,
|
||||||
|
const vector<LitFragment> &fragments) {
|
||||||
vector<raw_dfa> dfas;
|
vector<raw_dfa> dfas;
|
||||||
|
|
||||||
if (build.anchored_nfas.empty() && build.anchored_simple.empty()) {
|
if (build.anchored_nfas.empty() && build.anchored_simple.empty()) {
|
||||||
@ -833,9 +855,10 @@ vector<raw_dfa> buildAnchoredDfas(RoseBuildImpl &build) {
|
|||||||
return dfas;
|
return dfas;
|
||||||
}
|
}
|
||||||
|
|
||||||
remapAnchoredReports(build);
|
const auto frag_map = reverseFragMap(build, fragments);
|
||||||
|
remapAnchoredReports(build, frag_map);
|
||||||
|
|
||||||
auto anch_dfas = getAnchoredDfas(build);
|
auto anch_dfas = getAnchoredDfas(build, frag_map);
|
||||||
mergeAnchoredDfas(anch_dfas, build);
|
mergeAnchoredDfas(anch_dfas, build);
|
||||||
|
|
||||||
dfas.reserve(anch_dfas.size());
|
dfas.reserve(anch_dfas.size());
|
||||||
@ -847,8 +870,8 @@ vector<raw_dfa> buildAnchoredDfas(RoseBuildImpl &build) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
aligned_unique_ptr<anchored_matcher_info>
|
aligned_unique_ptr<anchored_matcher_info>
|
||||||
buildAnchoredMatcher(RoseBuildImpl &build, vector<raw_dfa> &dfas,
|
buildAnchoredMatcher(RoseBuildImpl &build, const vector<LitFragment> &fragments,
|
||||||
size_t *asize) {
|
vector<raw_dfa> &dfas, size_t *asize) {
|
||||||
const CompileContext &cc = build.cc;
|
const CompileContext &cc = build.cc;
|
||||||
|
|
||||||
if (dfas.empty()) {
|
if (dfas.empty()) {
|
||||||
@ -858,7 +881,7 @@ buildAnchoredMatcher(RoseBuildImpl &build, vector<raw_dfa> &dfas,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (auto &rdfa : dfas) {
|
for (auto &rdfa : dfas) {
|
||||||
remapIdsToPrograms(build, rdfa);
|
remapIdsToPrograms(fragments, rdfa);
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<aligned_unique_ptr<NFA>> nfas;
|
vector<aligned_unique_ptr<NFA>> nfas;
|
||||||
|
@ -44,11 +44,13 @@ namespace ue2 {
|
|||||||
|
|
||||||
class RoseBuildImpl;
|
class RoseBuildImpl;
|
||||||
struct raw_dfa;
|
struct raw_dfa;
|
||||||
|
struct LitFragment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Construct a set of anchored DFAs from our anchored literals/engines.
|
* \brief Construct a set of anchored DFAs from our anchored literals/engines.
|
||||||
*/
|
*/
|
||||||
std::vector<raw_dfa> buildAnchoredDfas(RoseBuildImpl &build);
|
std::vector<raw_dfa> buildAnchoredDfas(RoseBuildImpl &build,
|
||||||
|
const std::vector<LitFragment> &fragments);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Construct an anchored_matcher_info runtime structure from the given
|
* \brief Construct an anchored_matcher_info runtime structure from the given
|
||||||
@ -58,8 +60,9 @@ std::vector<raw_dfa> buildAnchoredDfas(RoseBuildImpl &build);
|
|||||||
* given in litPrograms.
|
* given in litPrograms.
|
||||||
*/
|
*/
|
||||||
aligned_unique_ptr<anchored_matcher_info>
|
aligned_unique_ptr<anchored_matcher_info>
|
||||||
buildAnchoredMatcher(RoseBuildImpl &build, std::vector<raw_dfa> &dfas,
|
buildAnchoredMatcher(RoseBuildImpl &build,
|
||||||
size_t *asize);
|
const std::vector<LitFragment> &fragments,
|
||||||
|
std::vector<raw_dfa> &dfas, size_t *asize);
|
||||||
|
|
||||||
u32 anchoredStateSize(const anchored_matcher_info &atable);
|
u32 anchoredStateSize(const anchored_matcher_info &atable);
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1669,7 +1669,7 @@ bool roleOffsetsAreValid(const RoseGraph &g) {
|
|||||||
#endif // NDEBUG
|
#endif // NDEBUG
|
||||||
|
|
||||||
aligned_unique_ptr<RoseEngine> RoseBuildImpl::buildRose(u32 minWidth) {
|
aligned_unique_ptr<RoseEngine> RoseBuildImpl::buildRose(u32 minWidth) {
|
||||||
dumpRoseGraph(*this, nullptr, "rose_early.dot");
|
dumpRoseGraph(*this, "rose_early.dot");
|
||||||
|
|
||||||
// Early check for Rose implementability.
|
// Early check for Rose implementability.
|
||||||
assert(canImplementGraphs(*this));
|
assert(canImplementGraphs(*this));
|
||||||
@ -1780,7 +1780,7 @@ aligned_unique_ptr<RoseEngine> RoseBuildImpl::buildRose(u32 minWidth) {
|
|||||||
assert(roleOffsetsAreValid(g));
|
assert(roleOffsetsAreValid(g));
|
||||||
assert(historiesAreValid(g));
|
assert(historiesAreValid(g));
|
||||||
|
|
||||||
dumpRoseGraph(*this, nullptr, "rose_pre_norm.dot");
|
dumpRoseGraph(*this, "rose_pre_norm.dot");
|
||||||
|
|
||||||
return buildFinalEngine(minWidth);
|
return buildFinalEngine(minWidth);
|
||||||
}
|
}
|
||||||
|
@ -112,8 +112,11 @@ string rose_off::str(void) const {
|
|||||||
|
|
||||||
class RoseGraphWriter {
|
class RoseGraphWriter {
|
||||||
public:
|
public:
|
||||||
RoseGraphWriter(const RoseBuildImpl &b_in, const RoseEngine *t_in) :
|
RoseGraphWriter(const RoseBuildImpl &b_in, const map<u32, u32> &frag_map_in,
|
||||||
build(b_in), t(t_in) {
|
const map<left_id, u32> &lqm_in,
|
||||||
|
const map<suffix_id, u32> &sqm_in, const RoseEngine *t_in)
|
||||||
|
: frag_map(frag_map_in), leftfix_queue_map(lqm_in),
|
||||||
|
suffix_queue_map(sqm_in), build(b_in), t(t_in) {
|
||||||
for (const auto &m : build.ghost) {
|
for (const auto &m : build.ghost) {
|
||||||
ghost.insert(m.second);
|
ghost.insert(m.second);
|
||||||
}
|
}
|
||||||
@ -160,8 +163,8 @@ public:
|
|||||||
if (g[v].suffix) {
|
if (g[v].suffix) {
|
||||||
suffix_id suff(g[v].suffix);
|
suffix_id suff(g[v].suffix);
|
||||||
os << "\\n" << render_kind(suff) << " (top " << g[v].suffix.top;
|
os << "\\n" << render_kind(suff) << " (top " << g[v].suffix.top;
|
||||||
auto it = build.suffix_queue_map.find(suff);
|
auto it = suffix_queue_map.find(suff);
|
||||||
if (it != end(build.suffix_queue_map)) {
|
if (it != end(suffix_queue_map)) {
|
||||||
os << ", queue " << it->second;
|
os << ", queue " << it->second;
|
||||||
}
|
}
|
||||||
os << ")";
|
os << ")";
|
||||||
@ -174,8 +177,8 @@ public:
|
|||||||
if (g[v].left) {
|
if (g[v].left) {
|
||||||
left_id left(g[v].left);
|
left_id left(g[v].left);
|
||||||
os << "\\n" << render_kind(left) << " (queue ";
|
os << "\\n" << render_kind(left) << " (queue ";
|
||||||
auto it = build.leftfix_queue_map.find(left);
|
auto it = leftfix_queue_map.find(left);
|
||||||
if (it != end(build.leftfix_queue_map)) {
|
if (it != end(leftfix_queue_map)) {
|
||||||
os << it->second;
|
os << it->second;
|
||||||
} else {
|
} else {
|
||||||
os << "??";
|
os << "??";
|
||||||
@ -248,8 +251,8 @@ private:
|
|||||||
// Render the literal associated with a vertex.
|
// Render the literal associated with a vertex.
|
||||||
void writeLiteral(ostream &os, u32 id) const {
|
void writeLiteral(ostream &os, u32 id) const {
|
||||||
os << "lit=" << id;
|
os << "lit=" << id;
|
||||||
if (id < build.literal_info.size()) {
|
if (contains(frag_map, id)) {
|
||||||
os << "/" << build.literal_info[id].fragment_id << " ";
|
os << "/" << frag_map.at(id) << " ";
|
||||||
} else {
|
} else {
|
||||||
os << "/nofrag ";
|
os << "/nofrag ";
|
||||||
}
|
}
|
||||||
@ -269,13 +272,32 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
set<RoseVertex> ghost;
|
set<RoseVertex> ghost;
|
||||||
|
const map<u32, u32> &frag_map;
|
||||||
|
const map<left_id, u32> &leftfix_queue_map;
|
||||||
|
const map<suffix_id, u32> &suffix_queue_map;
|
||||||
const RoseBuildImpl &build;
|
const RoseBuildImpl &build;
|
||||||
const RoseEngine *t;
|
const RoseEngine *t;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
static
|
||||||
|
map<u32, u32> makeFragMap(const vector<LitFragment> &fragments) {
|
||||||
|
map<u32, u32> fm;
|
||||||
|
for (const auto &f : fragments) {
|
||||||
|
for (u32 id : f.lit_ids) {
|
||||||
|
fm[id] = f.fragment_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fm;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
void dumpRoseGraph(const RoseBuildImpl &build, const RoseEngine *t,
|
void dumpRoseGraph(const RoseBuildImpl &build, const RoseEngine *t,
|
||||||
|
const vector<LitFragment> &fragments,
|
||||||
|
const map<left_id, u32> &leftfix_queue_map,
|
||||||
|
const map<suffix_id, u32> &suffix_queue_map,
|
||||||
const char *filename) {
|
const char *filename) {
|
||||||
const Grey &grey = build.cc.grey;
|
const Grey &grey = build.cc.grey;
|
||||||
|
|
||||||
@ -293,10 +315,16 @@ void dumpRoseGraph(const RoseBuildImpl &build, const RoseEngine *t,
|
|||||||
DEBUG_PRINTF("dumping graph to %s\n", ss.str().c_str());
|
DEBUG_PRINTF("dumping graph to %s\n", ss.str().c_str());
|
||||||
ofstream os(ss.str());
|
ofstream os(ss.str());
|
||||||
|
|
||||||
RoseGraphWriter writer(build, t);
|
auto frag_map = makeFragMap(fragments);
|
||||||
|
RoseGraphWriter writer(build, frag_map, leftfix_queue_map, suffix_queue_map,
|
||||||
|
t);
|
||||||
writeGraphviz(os, build.g, writer, get(boost::vertex_index, build.g));
|
writeGraphviz(os, build.g, writer, get(boost::vertex_index, build.g));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dumpRoseGraph(const RoseBuildImpl &build, const char *filename) {
|
||||||
|
dumpRoseGraph(build, nullptr, {}, {}, {}, filename);
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
struct CompareVertexRole {
|
struct CompareVertexRole {
|
||||||
explicit CompareVertexRole(const RoseGraph &g_in) : g(g_in) {}
|
explicit CompareVertexRole(const RoseGraph &g_in) : g(g_in) {}
|
||||||
@ -321,11 +349,14 @@ void lit_graph_info(const RoseBuildImpl &build, const rose_literal_info &li,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void dumpRoseLiterals(const RoseBuildImpl &build, const char *filename) {
|
void dumpRoseLiterals(const RoseBuildImpl &build,
|
||||||
|
const vector<LitFragment> &fragments,
|
||||||
|
const Grey &grey) {
|
||||||
const RoseGraph &g = build.g;
|
const RoseGraph &g = build.g;
|
||||||
|
map<u32, u32> frag_map = makeFragMap(fragments);
|
||||||
|
|
||||||
DEBUG_PRINTF("dumping literals\n");
|
DEBUG_PRINTF("dumping literals\n");
|
||||||
ofstream os(filename);
|
ofstream os(grey.dumpPath + "rose_literals.txt");
|
||||||
|
|
||||||
os << "ROSE LITERALS: a total of " << build.literals.right.size()
|
os << "ROSE LITERALS: a total of " << build.literals.right.size()
|
||||||
<< " literals and " << num_vertices(g) << " roles." << endl << endl;
|
<< " literals and " << num_vertices(g) << " roles." << endl << endl;
|
||||||
@ -353,8 +384,11 @@ void dumpRoseLiterals(const RoseBuildImpl &build, const char *filename) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
os << " ID " << id << "/" << lit_info.fragment_id << ": \""
|
os << " ID " << id;
|
||||||
<< escapeString(s.get_string()) << "\""
|
if (contains(frag_map, id)) {
|
||||||
|
os << "/" << frag_map.at(id);
|
||||||
|
}
|
||||||
|
os << ": \"" << escapeString(s.get_string()) << "\""
|
||||||
<< " (len " << s.length() << ",";
|
<< " (len " << s.length() << ",";
|
||||||
if (s.any_nocase()) {
|
if (s.any_nocase()) {
|
||||||
os << " nocase,";
|
os << " nocase,";
|
||||||
@ -833,7 +867,7 @@ void dumpMultipathShufti(ofstream &os, u32 len, const u8 *lo, const u8 *hi,
|
|||||||
#define PROGRAM_CASE(name) \
|
#define PROGRAM_CASE(name) \
|
||||||
case ROSE_INSTR_##name: { \
|
case ROSE_INSTR_##name: { \
|
||||||
os << " " << std::setw(4) << std::setfill('0') << (pc - pc_base) \
|
os << " " << std::setw(4) << std::setfill('0') << (pc - pc_base) \
|
||||||
<< ": " #name " (" << (int)ROSE_INSTR_##name << ")" << endl; \
|
<< ": " #name "\n"; \
|
||||||
const auto *ri = (const struct ROSE_STRUCT_##name *)pc;
|
const auto *ri = (const struct ROSE_STRUCT_##name *)pc;
|
||||||
|
|
||||||
#define PROGRAM_NEXT_INSTRUCTION \
|
#define PROGRAM_NEXT_INSTRUCTION \
|
||||||
@ -1444,13 +1478,13 @@ void dumpProgram(ofstream &os, const RoseEngine *t, const char *pc) {
|
|||||||
#undef PROGRAM_NEXT_INSTRUCTION
|
#undef PROGRAM_NEXT_INSTRUCTION
|
||||||
|
|
||||||
static
|
static
|
||||||
void dumpRoseLitPrograms(const RoseBuildImpl &build, const RoseEngine *t,
|
void dumpRoseLitPrograms(const vector<LitFragment> &fragments,
|
||||||
const string &filename) {
|
const RoseEngine *t, const string &filename) {
|
||||||
ofstream os(filename);
|
ofstream os(filename);
|
||||||
|
|
||||||
// Collect all programs referenced by a literal fragment.
|
// Collect all programs referenced by a literal fragment.
|
||||||
vector<u32> programs;
|
vector<u32> programs;
|
||||||
for (const auto &frag : build.fragments) {
|
for (const auto &frag : fragments) {
|
||||||
if (frag.lit_program_offset) {
|
if (frag.lit_program_offset) {
|
||||||
programs.push_back(frag.lit_program_offset);
|
programs.push_back(frag.lit_program_offset);
|
||||||
}
|
}
|
||||||
@ -2185,16 +2219,19 @@ void roseDumpComponents(const RoseEngine *t, bool dump_raw,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void roseDumpPrograms(const RoseBuildImpl &build, const RoseEngine *t,
|
void roseDumpPrograms(const vector<LitFragment> &fragments, const RoseEngine *t,
|
||||||
const string &base) {
|
const string &base) {
|
||||||
dumpRoseLitPrograms(build, t, base + "/rose_lit_programs.txt");
|
dumpRoseLitPrograms(fragments, t, base + "/rose_lit_programs.txt");
|
||||||
dumpRoseEodPrograms(t, base + "/rose_eod_programs.txt");
|
dumpRoseEodPrograms(t, base + "/rose_eod_programs.txt");
|
||||||
dumpRoseReportPrograms(t, base + "/rose_report_programs.txt");
|
dumpRoseReportPrograms(t, base + "/rose_report_programs.txt");
|
||||||
dumpRoseAnchoredPrograms(t, base + "/rose_anchored_programs.txt");
|
dumpRoseAnchoredPrograms(t, base + "/rose_anchored_programs.txt");
|
||||||
dumpRoseDelayPrograms(t, base + "/rose_delay_programs.txt");
|
dumpRoseDelayPrograms(t, base + "/rose_delay_programs.txt");
|
||||||
}
|
}
|
||||||
|
|
||||||
void dumpRose(const RoseBuildImpl &build, const RoseEngine *t) {
|
void dumpRose(const RoseBuildImpl &build, const vector<LitFragment> &fragments,
|
||||||
|
const map<left_id, u32> &leftfix_queue_map,
|
||||||
|
const map<suffix_id, u32> &suffix_queue_map,
|
||||||
|
const RoseEngine *t) {
|
||||||
const Grey &grey = build.cc.grey;
|
const Grey &grey = build.cc.grey;
|
||||||
|
|
||||||
if (!grey.dumpFlags) {
|
if (!grey.dumpFlags) {
|
||||||
@ -2218,16 +2255,14 @@ void dumpRose(const RoseBuildImpl &build, const RoseEngine *t) {
|
|||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
roseDumpComponents(t, false, grey.dumpPath);
|
roseDumpComponents(t, false, grey.dumpPath);
|
||||||
roseDumpPrograms(build, t, grey.dumpPath);
|
roseDumpPrograms(fragments, t, grey.dumpPath);
|
||||||
|
|
||||||
// Graph.
|
// Graph.
|
||||||
dumpRoseGraph(build, t, "rose.dot");
|
dumpRoseGraph(build, t, fragments, leftfix_queue_map, suffix_queue_map,
|
||||||
|
"rose.dot");
|
||||||
|
|
||||||
// Literals.
|
// Literals
|
||||||
ss.str("");
|
dumpRoseLiterals(build, fragments, grey);
|
||||||
ss.clear();
|
|
||||||
ss << grey.dumpPath << "rose_literals.txt";
|
|
||||||
dumpRoseLiterals(build, ss.str().c_str());
|
|
||||||
|
|
||||||
f = fopen((grey.dumpPath + "/rose_struct.txt").c_str(), "w");
|
f = fopen((grey.dumpPath + "/rose_struct.txt").c_str(), "w");
|
||||||
roseDumpStructRaw(t, f);
|
roseDumpStructRaw(t, f);
|
||||||
|
@ -29,6 +29,9 @@
|
|||||||
#ifndef ROSE_BUILD_DUMP_H
|
#ifndef ROSE_BUILD_DUMP_H
|
||||||
#define ROSE_BUILD_DUMP_H
|
#define ROSE_BUILD_DUMP_H
|
||||||
|
|
||||||
|
#include "ue2common.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -39,30 +42,40 @@ namespace ue2 {
|
|||||||
class RoseBuildImpl;
|
class RoseBuildImpl;
|
||||||
struct Grey;
|
struct Grey;
|
||||||
struct hwlmLiteral;
|
struct hwlmLiteral;
|
||||||
|
struct LitFragment;
|
||||||
|
struct left_id;
|
||||||
|
struct suffix_id;
|
||||||
|
|
||||||
#ifdef DUMP_SUPPORT
|
#ifdef DUMP_SUPPORT
|
||||||
// Dump the Rose graph in graphviz representation.
|
// Dump the Rose graph in graphviz representation.
|
||||||
void dumpRoseGraph(const RoseBuildImpl &build, const RoseEngine *t,
|
void dumpRoseGraph(const RoseBuildImpl &build, const char *filename);
|
||||||
const char *filename);
|
|
||||||
|
|
||||||
void dumpRose(const RoseBuildImpl &build, const RoseEngine *t);
|
void dumpRose(const RoseBuildImpl &build,
|
||||||
|
const std::vector<LitFragment> &fragments,
|
||||||
|
const std::map<left_id, u32> &leftfix_queue_map,
|
||||||
|
const std::map<suffix_id, u32> &suffix_queue_map,
|
||||||
|
const RoseEngine *t);
|
||||||
|
|
||||||
void dumpMatcherLiterals(const std::vector<hwlmLiteral> &lits,
|
void dumpMatcherLiterals(const std::vector<hwlmLiteral> &lits,
|
||||||
const std::string &name, const Grey &grey);
|
const std::string &name, const Grey &grey);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static UNUSED
|
static UNUSED
|
||||||
void dumpRoseGraph(const RoseBuildImpl &, const RoseEngine *, const char *) {
|
void dumpRoseGraph(const RoseBuildImpl &, const char *) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static UNUSED
|
static UNUSED
|
||||||
void dumpRose(const RoseBuildImpl &, const RoseEngine *) {
|
void dumpRose(const RoseBuildImpl &, const std::vector<LitFragment> &,
|
||||||
|
const std::map<left_id, u32> &, const std::map<suffix_id, u32> &,
|
||||||
|
const RoseEngine *) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static UNUSED
|
static UNUSED
|
||||||
void dumpMatcherLiterals(const std::vector<hwlmLiteral> &, const std::string &,
|
void dumpMatcherLiterals(const std::vector<hwlmLiteral> &, const std::string &,
|
||||||
const Grey &) {
|
const Grey &) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace ue2
|
} // namespace ue2
|
||||||
|
@ -264,7 +264,6 @@ struct rose_literal_info {
|
|||||||
ue2::flat_set<RoseVertex> vertices;
|
ue2::flat_set<RoseVertex> vertices;
|
||||||
rose_group group_mask = 0;
|
rose_group group_mask = 0;
|
||||||
u32 undelayed_id = MO_INVALID_IDX;
|
u32 undelayed_id = MO_INVALID_IDX;
|
||||||
u32 fragment_id = MO_INVALID_IDX; //!< ID corresponding to literal prog.
|
|
||||||
bool squash_group = false;
|
bool squash_group = false;
|
||||||
bool requires_benefits = false;
|
bool requires_benefits = false;
|
||||||
};
|
};
|
||||||
@ -437,15 +436,6 @@ private:
|
|||||||
|
|
||||||
std::set<ReportID> all_reports(const OutfixInfo &outfix);
|
std::set<ReportID> all_reports(const OutfixInfo &outfix);
|
||||||
|
|
||||||
struct LitFragment {
|
|
||||||
LitFragment(u32 fragment_id_in, rose_group groups_in)
|
|
||||||
: fragment_id(fragment_id_in), groups(groups_in) {}
|
|
||||||
u32 fragment_id;
|
|
||||||
rose_group groups;
|
|
||||||
u32 lit_program_offset = ROSE_INVALID_PROG_OFFSET;
|
|
||||||
u32 delay_program_offset = ROSE_INVALID_PROG_OFFSET;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Concrete impl class
|
// Concrete impl class
|
||||||
class RoseBuildImpl : public RoseBuild {
|
class RoseBuildImpl : public RoseBuild {
|
||||||
public:
|
public:
|
||||||
@ -576,19 +566,11 @@ public:
|
|||||||
|
|
||||||
u32 ematcher_region_size; /**< number of bytes the eod table runs over */
|
u32 ematcher_region_size; /**< number of bytes the eod table runs over */
|
||||||
|
|
||||||
/** \brief Mapping from leftfix to queue ID (used in dump code). */
|
|
||||||
unordered_map<left_id, u32> leftfix_queue_map;
|
|
||||||
|
|
||||||
/** \brief Mapping from suffix to queue ID (used in dump code). */
|
|
||||||
unordered_map<suffix_id, u32> suffix_queue_map;
|
|
||||||
|
|
||||||
/** \brief Mapping from anchored literal ID to the original literal suffix
|
/** \brief Mapping from anchored literal ID to the original literal suffix
|
||||||
* present when the literal was added to the literal matcher. Used for
|
* present when the literal was added to the literal matcher. Used for
|
||||||
* overlap calculation in history assignment. */
|
* overlap calculation in history assignment. */
|
||||||
std::map<u32, rose_literal_id> anchoredLitSuffix;
|
std::map<u32, rose_literal_id> anchoredLitSuffix;
|
||||||
|
|
||||||
std::vector<LitFragment> fragments;
|
|
||||||
|
|
||||||
unordered_set<left_id> transient;
|
unordered_set<left_id> transient;
|
||||||
unordered_map<left_id, rose_group> rose_squash_masks;
|
unordered_map<left_id, rose_group> rose_squash_masks;
|
||||||
|
|
||||||
|
@ -350,9 +350,6 @@ void findMoreLiteralMasks(RoseBuildImpl &build) {
|
|||||||
const u32 id = e.first;
|
const u32 id = e.first;
|
||||||
const auto &lit = e.second;
|
const auto &lit = e.second;
|
||||||
|
|
||||||
// This pass takes place before fragment IDs are assigned to literals.
|
|
||||||
assert(build.literal_info.at(id).fragment_id == MO_INVALID_IDX);
|
|
||||||
|
|
||||||
if (lit.delay || build.isDelayed(id)) {
|
if (lit.delay || build.isDelayed(id)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -673,6 +670,7 @@ struct MatcherProto {
|
|||||||
*/
|
*/
|
||||||
static
|
static
|
||||||
MatcherProto makeMatcherProto(const RoseBuildImpl &build,
|
MatcherProto makeMatcherProto(const RoseBuildImpl &build,
|
||||||
|
const vector<LitFragment> &fragments,
|
||||||
rose_literal_table table, bool delay_rebuild,
|
rose_literal_table table, bool delay_rebuild,
|
||||||
size_t max_len, u32 max_offset = ROSE_BOUND_INF) {
|
size_t max_len, u32 max_offset = ROSE_BOUND_INF) {
|
||||||
MatcherProto mp;
|
MatcherProto mp;
|
||||||
@ -682,27 +680,26 @@ MatcherProto makeMatcherProto(const RoseBuildImpl &build,
|
|||||||
assert(build.cc.streaming);
|
assert(build.cc.streaming);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &e : build.literals.right) {
|
for (const auto &f : fragments) {
|
||||||
const u32 id = e.first;
|
for (u32 id : f.lit_ids) {
|
||||||
if (build.literal_info.at(id).fragment_id == MO_INVALID_IDX) {
|
const rose_literal_id &lit = build.literals.right.at(id);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.second.delay) {
|
if (lit.table != table) {
|
||||||
continue; /* delay id's are virtual-ish */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.second.table != table) {
|
|
||||||
continue; /* wrong table */
|
continue; /* wrong table */
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(id < build.literal_info.size());
|
if (lit.delay) {
|
||||||
const rose_literal_info &info = build.literal_info[id];
|
continue; /* delay id's are virtual-ish */
|
||||||
/* Note: requires_benefits are handled in the literal entries */
|
}
|
||||||
const ue2_literal &lit = e.second.s;
|
|
||||||
|
|
||||||
DEBUG_PRINTF("lit='%s' (len %zu)\n", escapeString(lit).c_str(),
|
assert(id < build.literal_info.size());
|
||||||
lit.length());
|
const auto &info = build.literal_info.at(id);
|
||||||
|
|
||||||
|
/* Note: requires_benefits are handled in the literal entries */
|
||||||
|
const ue2_literal &s = lit.s;
|
||||||
|
|
||||||
|
DEBUG_PRINTF("lit='%s' (len %zu)\n", escapeString(s).c_str(),
|
||||||
|
s.length());
|
||||||
|
|
||||||
// When building the delay rebuild table, we only want to include
|
// When building the delay rebuild table, we only want to include
|
||||||
// literals that have delayed variants.
|
// literals that have delayed variants.
|
||||||
@ -712,62 +709,62 @@ MatcherProto makeMatcherProto(const RoseBuildImpl &build,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (max_offset != ROSE_BOUND_INF) {
|
if (max_offset != ROSE_BOUND_INF) {
|
||||||
u64a min_report = literalMinReportOffset(build, e.second, info);
|
u64a min_report = literalMinReportOffset(build, lit, info);
|
||||||
if (min_report > max_offset) {
|
if (min_report > max_offset) {
|
||||||
DEBUG_PRINTF("min report offset=%llu exceeds max_offset=%u\n",
|
DEBUG_PRINTF("min report offset=%llu exceeds "
|
||||||
min_report, max_offset);
|
"max_offset=%u\n", min_report, max_offset);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const vector<u8> &msk = e.second.msk;
|
const vector<u8> &msk = lit.msk;
|
||||||
const vector<u8> &cmp = e.second.cmp;
|
const vector<u8> &cmp = lit.cmp;
|
||||||
bool noruns = isNoRunsLiteral(build, id, info, max_len);
|
bool noruns = isNoRunsLiteral(build, id, info, max_len);
|
||||||
|
|
||||||
size_t lit_hist_len = 0;
|
size_t lit_hist_len = 0;
|
||||||
if (build.cc.streaming) {
|
if (build.cc.streaming) {
|
||||||
lit_hist_len = max(msk.size(), min(lit.length(), max_len));
|
lit_hist_len = max(msk.size(), min(s.length(), max_len));
|
||||||
lit_hist_len = lit_hist_len ? lit_hist_len - 1 : 0;
|
lit_hist_len = lit_hist_len ? lit_hist_len - 1 : 0;
|
||||||
}
|
}
|
||||||
DEBUG_PRINTF("lit requires %zu bytes of history\n", lit_hist_len);
|
DEBUG_PRINTF("lit requires %zu bytes of history\n", lit_hist_len);
|
||||||
assert(lit_hist_len <= build.cc.grey.maxHistoryAvailable);
|
assert(lit_hist_len <= build.cc.grey.maxHistoryAvailable);
|
||||||
|
|
||||||
auto lit_final = lit; // copy
|
auto lit_final = s; // copy
|
||||||
|
|
||||||
if (lit_final.length() > ROSE_SHORT_LITERAL_LEN_MAX) {
|
if (lit_final.length() > ROSE_SHORT_LITERAL_LEN_MAX) {
|
||||||
DEBUG_PRINTF("truncating to tail of length %zu\n",
|
DEBUG_PRINTF("truncating to tail of length %zu\n",
|
||||||
size_t{ROSE_SHORT_LITERAL_LEN_MAX});
|
size_t{ROSE_SHORT_LITERAL_LEN_MAX});
|
||||||
lit_final.erase(0, lit_final.length() - ROSE_SHORT_LITERAL_LEN_MAX);
|
lit_final.erase(0, lit_final.length()
|
||||||
|
- ROSE_SHORT_LITERAL_LEN_MAX);
|
||||||
// We shouldn't have set a threshold below 8 chars.
|
// We shouldn't have set a threshold below 8 chars.
|
||||||
assert(msk.size() <= ROSE_SHORT_LITERAL_LEN_MAX);
|
assert(msk.size() <= ROSE_SHORT_LITERAL_LEN_MAX);
|
||||||
assert(!noruns);
|
assert(!noruns);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &s = lit_final.get_string();
|
const auto &s_final = lit_final.get_string();
|
||||||
bool nocase = lit_final.any_nocase();
|
bool nocase = lit_final.any_nocase();
|
||||||
|
|
||||||
DEBUG_PRINTF("id=%u, s='%s', nocase=%d, noruns=%d, msk=%s, "
|
DEBUG_PRINTF("id=%u, s='%s', nocase=%d, noruns=%d, msk=%s, "
|
||||||
"cmp=%s\n",
|
"cmp=%s\n", f.fragment_id,
|
||||||
info.fragment_id, escapeString(s).c_str(), (int)nocase,
|
escapeString(s_final).c_str(), (int)nocase, noruns,
|
||||||
noruns, dumpMask(msk).c_str(), dumpMask(cmp).c_str());
|
dumpMask(msk).c_str(), dumpMask(cmp).c_str());
|
||||||
|
|
||||||
if (!maskIsConsistent(s, nocase, msk, cmp)) {
|
if (!maskIsConsistent(s_final, nocase, msk, cmp)) {
|
||||||
DEBUG_PRINTF("msk/cmp for literal can't match, skipping\n");
|
DEBUG_PRINTF("msk/cmp for literal can't match, skipping\n");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
mp.accel_lits.emplace_back(lit.get_string(), lit.any_nocase(), msk, cmp,
|
mp.accel_lits.emplace_back(s.get_string(), s.any_nocase(), msk, cmp,
|
||||||
info.group_mask);
|
info.group_mask);
|
||||||
mp.history_required = max(mp.history_required, lit_hist_len);
|
mp.history_required = max(mp.history_required, lit_hist_len);
|
||||||
|
|
||||||
assert(info.fragment_id < build.fragments.size());
|
u32 prog_offset = delay_rebuild ? f.delay_program_offset
|
||||||
const auto &frag = build.fragments.at(info.fragment_id);
|
: f.lit_program_offset;
|
||||||
u32 prog_offset =
|
const auto &groups = f.groups;
|
||||||
delay_rebuild ? frag.delay_program_offset : frag.lit_program_offset;
|
|
||||||
const auto &groups = frag.groups;
|
|
||||||
|
|
||||||
mp.lits.emplace_back(move(s), nocase, noruns, prog_offset, groups, msk,
|
mp.lits.emplace_back(move(s_final), nocase, noruns, prog_offset,
|
||||||
cmp);
|
groups, msk, cmp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sort_and_unique(mp.lits);
|
sort_and_unique(mp.lits);
|
||||||
@ -809,14 +806,15 @@ void buildAccel(const RoseBuildImpl &build, const MatcherProto &mp,
|
|||||||
}
|
}
|
||||||
|
|
||||||
aligned_unique_ptr<HWLM>
|
aligned_unique_ptr<HWLM>
|
||||||
buildFloatingMatcher(const RoseBuildImpl &build, size_t longLitLengthThreshold,
|
buildFloatingMatcher(const RoseBuildImpl &build,
|
||||||
rose_group *fgroups, size_t *fsize,
|
const vector<LitFragment> &fragments,
|
||||||
size_t *historyRequired) {
|
size_t longLitLengthThreshold, rose_group *fgroups,
|
||||||
|
size_t *fsize, size_t *historyRequired) {
|
||||||
*fsize = 0;
|
*fsize = 0;
|
||||||
*fgroups = 0;
|
*fgroups = 0;
|
||||||
|
|
||||||
auto mp =
|
auto mp = makeMatcherProto(build, fragments, ROSE_FLOATING, false,
|
||||||
makeMatcherProto(build, ROSE_FLOATING, false, longLitLengthThreshold);
|
longLitLengthThreshold);
|
||||||
if (mp.lits.empty()) {
|
if (mp.lits.empty()) {
|
||||||
DEBUG_PRINTF("empty floating matcher\n");
|
DEBUG_PRINTF("empty floating matcher\n");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -847,6 +845,7 @@ buildFloatingMatcher(const RoseBuildImpl &build, size_t longLitLengthThreshold,
|
|||||||
}
|
}
|
||||||
|
|
||||||
aligned_unique_ptr<HWLM> buildDelayRebuildMatcher(const RoseBuildImpl &build,
|
aligned_unique_ptr<HWLM> buildDelayRebuildMatcher(const RoseBuildImpl &build,
|
||||||
|
const vector<LitFragment> &fragments,
|
||||||
size_t longLitLengthThreshold,
|
size_t longLitLengthThreshold,
|
||||||
size_t *drsize) {
|
size_t *drsize) {
|
||||||
*drsize = 0;
|
*drsize = 0;
|
||||||
@ -856,8 +855,8 @@ aligned_unique_ptr<HWLM> buildDelayRebuildMatcher(const RoseBuildImpl &build,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto mp =
|
auto mp = makeMatcherProto(build, fragments, ROSE_FLOATING, true,
|
||||||
makeMatcherProto(build, ROSE_FLOATING, true, longLitLengthThreshold);
|
longLitLengthThreshold);
|
||||||
if (mp.lits.empty()) {
|
if (mp.lits.empty()) {
|
||||||
DEBUG_PRINTF("empty delay rebuild matcher\n");
|
DEBUG_PRINTF("empty delay rebuild matcher\n");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -877,8 +876,9 @@ aligned_unique_ptr<HWLM> buildDelayRebuildMatcher(const RoseBuildImpl &build,
|
|||||||
return hwlm;
|
return hwlm;
|
||||||
}
|
}
|
||||||
|
|
||||||
aligned_unique_ptr<HWLM> buildSmallBlockMatcher(const RoseBuildImpl &build,
|
aligned_unique_ptr<HWLM>
|
||||||
size_t *sbsize) {
|
buildSmallBlockMatcher(const RoseBuildImpl &build,
|
||||||
|
const vector<LitFragment> &fragments, size_t *sbsize) {
|
||||||
*sbsize = 0;
|
*sbsize = 0;
|
||||||
|
|
||||||
if (build.cc.streaming) {
|
if (build.cc.streaming) {
|
||||||
@ -893,7 +893,7 @@ aligned_unique_ptr<HWLM> buildSmallBlockMatcher(const RoseBuildImpl &build,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto mp = makeMatcherProto(build, ROSE_FLOATING, false,
|
auto mp = makeMatcherProto(build, fragments, ROSE_FLOATING, false,
|
||||||
ROSE_SMALL_BLOCK_LEN, ROSE_SMALL_BLOCK_LEN);
|
ROSE_SMALL_BLOCK_LEN, ROSE_SMALL_BLOCK_LEN);
|
||||||
if (mp.lits.empty()) {
|
if (mp.lits.empty()) {
|
||||||
DEBUG_PRINTF("no floating table\n");
|
DEBUG_PRINTF("no floating table\n");
|
||||||
@ -903,9 +903,10 @@ aligned_unique_ptr<HWLM> buildSmallBlockMatcher(const RoseBuildImpl &build,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto mp_anchored =
|
auto mp_anchored = makeMatcherProto(build, fragments,
|
||||||
makeMatcherProto(build, ROSE_ANCHORED_SMALL_BLOCK, false,
|
ROSE_ANCHORED_SMALL_BLOCK, false,
|
||||||
ROSE_SMALL_BLOCK_LEN, ROSE_SMALL_BLOCK_LEN);
|
ROSE_SMALL_BLOCK_LEN,
|
||||||
|
ROSE_SMALL_BLOCK_LEN);
|
||||||
if (mp_anchored.lits.empty()) {
|
if (mp_anchored.lits.empty()) {
|
||||||
DEBUG_PRINTF("no small-block anchored literals\n");
|
DEBUG_PRINTF("no small-block anchored literals\n");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -937,11 +938,12 @@ aligned_unique_ptr<HWLM> buildSmallBlockMatcher(const RoseBuildImpl &build,
|
|||||||
return hwlm;
|
return hwlm;
|
||||||
}
|
}
|
||||||
|
|
||||||
aligned_unique_ptr<HWLM> buildEodAnchoredMatcher(const RoseBuildImpl &build,
|
aligned_unique_ptr<HWLM>
|
||||||
size_t *esize) {
|
buildEodAnchoredMatcher(const RoseBuildImpl &build,
|
||||||
|
const vector<LitFragment> &fragments, size_t *esize) {
|
||||||
*esize = 0;
|
*esize = 0;
|
||||||
|
|
||||||
auto mp = makeMatcherProto(build, ROSE_EOD_ANCHORED, false,
|
auto mp = makeMatcherProto(build, fragments, ROSE_EOD_ANCHORED, false,
|
||||||
build.ematcher_region_size);
|
build.ematcher_region_size);
|
||||||
|
|
||||||
if (mp.lits.empty()) {
|
if (mp.lits.empty()) {
|
||||||
|
@ -36,25 +36,45 @@
|
|||||||
|
|
||||||
#include "rose_build_impl.h"
|
#include "rose_build_impl.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
struct Grey;
|
struct Grey;
|
||||||
struct HWLM;
|
struct HWLM;
|
||||||
|
|
||||||
namespace ue2 {
|
namespace ue2 {
|
||||||
|
|
||||||
|
struct LitFragment {
|
||||||
|
LitFragment(u32 fragment_id_in, rose_group groups_in, u32 lit_id)
|
||||||
|
: fragment_id(fragment_id_in), groups(groups_in), lit_ids({lit_id}) {}
|
||||||
|
LitFragment(u32 fragment_id_in, rose_group groups_in,
|
||||||
|
std::vector<u32> lit_ids_in)
|
||||||
|
: fragment_id(fragment_id_in), groups(groups_in),
|
||||||
|
lit_ids(std::move(lit_ids_in)) {}
|
||||||
|
u32 fragment_id;
|
||||||
|
rose_group groups;
|
||||||
|
std::vector<u32> lit_ids;
|
||||||
|
u32 lit_program_offset = ROSE_INVALID_PROG_OFFSET;
|
||||||
|
u32 delay_program_offset = ROSE_INVALID_PROG_OFFSET;
|
||||||
|
};
|
||||||
|
|
||||||
aligned_unique_ptr<HWLM> buildFloatingMatcher(const RoseBuildImpl &build,
|
aligned_unique_ptr<HWLM> buildFloatingMatcher(const RoseBuildImpl &build,
|
||||||
|
const std::vector<LitFragment> &fragments,
|
||||||
size_t longLitLengthThreshold,
|
size_t longLitLengthThreshold,
|
||||||
rose_group *fgroups,
|
rose_group *fgroups,
|
||||||
size_t *fsize,
|
size_t *fsize,
|
||||||
size_t *historyRequired);
|
size_t *historyRequired);
|
||||||
|
|
||||||
aligned_unique_ptr<HWLM> buildDelayRebuildMatcher(const RoseBuildImpl &build,
|
aligned_unique_ptr<HWLM> buildDelayRebuildMatcher(const RoseBuildImpl &build,
|
||||||
|
const std::vector<LitFragment> &fragments,
|
||||||
size_t longLitLengthThreshold,
|
size_t longLitLengthThreshold,
|
||||||
size_t *drsize);
|
size_t *drsize);
|
||||||
|
|
||||||
aligned_unique_ptr<HWLM> buildSmallBlockMatcher(const RoseBuildImpl &build,
|
aligned_unique_ptr<HWLM> buildSmallBlockMatcher(const RoseBuildImpl &build,
|
||||||
|
const std::vector<LitFragment> &fragments,
|
||||||
size_t *sbsize);
|
size_t *sbsize);
|
||||||
|
|
||||||
aligned_unique_ptr<HWLM> buildEodAnchoredMatcher(const RoseBuildImpl &build,
|
aligned_unique_ptr<HWLM> buildEodAnchoredMatcher(const RoseBuildImpl &build,
|
||||||
|
const std::vector<LitFragment> &fragments,
|
||||||
size_t *esize);
|
size_t *esize);
|
||||||
|
|
||||||
void findMoreLiteralMasks(RoseBuildImpl &build);
|
void findMoreLiteralMasks(RoseBuildImpl &build);
|
||||||
|
@ -450,8 +450,7 @@ void RoseInstrSparseIterBegin::write(void *dest, RoseEngineBlob &blob,
|
|||||||
jump_offsets.push_back(offset_map.at(jump.second));
|
jump_offsets.push_back(offset_map.at(jump.second));
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<mmbit_sparse_iter> iter;
|
auto iter = mmbBuildSparseIterator(keys, num_keys);
|
||||||
mmbBuildSparseIterator(iter, keys, num_keys);
|
|
||||||
assert(!iter.empty());
|
assert(!iter.empty());
|
||||||
inst->iter_offset = blob.add_iterator(iter);
|
inst->iter_offset = blob.add_iterator(iter);
|
||||||
inst->jump_table = blob.add(jump_offsets.begin(), jump_offsets.end());
|
inst->jump_table = blob.add(jump_offsets.begin(), jump_offsets.end());
|
||||||
@ -485,8 +484,7 @@ void RoseInstrSparseIterAny::write(void *dest, RoseEngineBlob &blob,
|
|||||||
inst->fail_jump = calc_jump(offset_map, this, target);
|
inst->fail_jump = calc_jump(offset_map, this, target);
|
||||||
|
|
||||||
// Write the multibit sparse iterator.
|
// Write the multibit sparse iterator.
|
||||||
vector<mmbit_sparse_iter> iter;
|
auto iter = mmbBuildSparseIterator(keys, num_keys);
|
||||||
mmbBuildSparseIterator(iter, keys, num_keys);
|
|
||||||
assert(!iter.empty());
|
assert(!iter.empty());
|
||||||
inst->iter_offset = blob.add_iterator(iter);
|
inst->iter_offset = blob.add_iterator(iter);
|
||||||
}
|
}
|
||||||
|
@ -155,9 +155,9 @@ void bfs(vector<mmbit_sparse_iter> &out, const TreeNode &tree) {
|
|||||||
|
|
||||||
/** \brief Construct a sparse iterator over the values in \a bits for a
|
/** \brief Construct a sparse iterator over the values in \a bits for a
|
||||||
* multibit of size \a total_bits. */
|
* multibit of size \a total_bits. */
|
||||||
void mmbBuildSparseIterator(vector<mmbit_sparse_iter> &out,
|
vector<mmbit_sparse_iter> mmbBuildSparseIterator(const vector<u32> &bits,
|
||||||
const vector<u32> &bits, u32 total_bits) {
|
u32 total_bits) {
|
||||||
assert(out.empty());
|
vector<mmbit_sparse_iter> out;
|
||||||
assert(!bits.empty());
|
assert(!bits.empty());
|
||||||
assert(total_bits > 0);
|
assert(total_bits > 0);
|
||||||
assert(total_bits <= MMB_MAX_BITS);
|
assert(total_bits <= MMB_MAX_BITS);
|
||||||
@ -186,6 +186,7 @@ void mmbBuildSparseIterator(vector<mmbit_sparse_iter> &out,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
DEBUG_PRINTF("iter has %zu records\n", out.size());
|
DEBUG_PRINTF("iter has %zu records\n", out.size());
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2015-2016, Intel Corporation
|
* Copyright (c) 2015-2017, Intel Corporation
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
@ -61,8 +61,8 @@ u32 mmbit_size(u32 total_bits);
|
|||||||
|
|
||||||
/** \brief Construct a sparse iterator over the values in \a bits for a
|
/** \brief Construct a sparse iterator over the values in \a bits for a
|
||||||
* multibit of size \a total_bits. */
|
* multibit of size \a total_bits. */
|
||||||
void mmbBuildSparseIterator(std::vector<mmbit_sparse_iter> &out,
|
std::vector<mmbit_sparse_iter>
|
||||||
const std::vector<u32> &bits, u32 total_bits);
|
mmbBuildSparseIterator(const std::vector<u32> &bits, u32 total_bits);
|
||||||
|
|
||||||
struct scatter_plan_raw;
|
struct scatter_plan_raw;
|
||||||
|
|
||||||
|
@ -782,7 +782,6 @@ TEST_P(MultiBitTest, InitRangePlanChunked) {
|
|||||||
|
|
||||||
TEST(MultiBit, SparseIteratorBegin1) {
|
TEST(MultiBit, SparseIteratorBegin1) {
|
||||||
const u32 test_size = 100;
|
const u32 test_size = 100;
|
||||||
vector<mmbit_sparse_iter> it;
|
|
||||||
vector<u32> bits;
|
vector<u32> bits;
|
||||||
|
|
||||||
bits.push_back(1);
|
bits.push_back(1);
|
||||||
@ -791,7 +790,7 @@ TEST(MultiBit, SparseIteratorBegin1) {
|
|||||||
bits.push_back(35);
|
bits.push_back(35);
|
||||||
bits.push_back(68);
|
bits.push_back(68);
|
||||||
|
|
||||||
mmbBuildSparseIterator(it, bits, test_size);
|
auto it = mmbBuildSparseIterator(bits, test_size);
|
||||||
//ASSERT_EQ(4U, it.size());
|
//ASSERT_EQ(4U, it.size());
|
||||||
|
|
||||||
// Trivial initial test: all bits in 'bits' are on, all others are off
|
// Trivial initial test: all bits in 'bits' are on, all others are off
|
||||||
@ -820,7 +819,6 @@ TEST(MultiBit, SparseIteratorBegin1) {
|
|||||||
|
|
||||||
TEST(MultiBit, SparseIteratorBegin2) {
|
TEST(MultiBit, SparseIteratorBegin2) {
|
||||||
const u32 test_size = 40000;
|
const u32 test_size = 40000;
|
||||||
vector<mmbit_sparse_iter> it;
|
|
||||||
vector<u32> bits;
|
vector<u32> bits;
|
||||||
|
|
||||||
bits.push_back(1);
|
bits.push_back(1);
|
||||||
@ -830,7 +828,7 @@ TEST(MultiBit, SparseIteratorBegin2) {
|
|||||||
bits.push_back(8920);
|
bits.push_back(8920);
|
||||||
bits.push_back(37000);
|
bits.push_back(37000);
|
||||||
|
|
||||||
mmbBuildSparseIterator(it, bits, test_size);
|
auto it = mmbBuildSparseIterator(bits, test_size);
|
||||||
//ASSERT_EQ(12U, it.size());
|
//ASSERT_EQ(12U, it.size());
|
||||||
|
|
||||||
// Trivial initial test: all bits in 'bits' are on, all others are off
|
// Trivial initial test: all bits in 'bits' are on, all others are off
|
||||||
@ -859,7 +857,6 @@ TEST(MultiBit, SparseIteratorBegin2) {
|
|||||||
|
|
||||||
TEST(MultiBit, SparseIteratorNext1) {
|
TEST(MultiBit, SparseIteratorNext1) {
|
||||||
const u32 test_size = 100;
|
const u32 test_size = 100;
|
||||||
vector<mmbit_sparse_iter> it;
|
|
||||||
vector<u32> bits;
|
vector<u32> bits;
|
||||||
|
|
||||||
bits.push_back(1);
|
bits.push_back(1);
|
||||||
@ -868,7 +865,7 @@ TEST(MultiBit, SparseIteratorNext1) {
|
|||||||
bits.push_back(35);
|
bits.push_back(35);
|
||||||
bits.push_back(68);
|
bits.push_back(68);
|
||||||
|
|
||||||
mmbBuildSparseIterator(it, bits, test_size);
|
auto it = mmbBuildSparseIterator(bits, test_size);
|
||||||
|
|
||||||
// Trivial initial test: all bits in 'bits' are on, all others are off
|
// Trivial initial test: all bits in 'bits' are on, all others are off
|
||||||
mmbit_holder ba(test_size);
|
mmbit_holder ba(test_size);
|
||||||
@ -924,7 +921,6 @@ TEST(MultiBit, SparseIteratorNext1) {
|
|||||||
|
|
||||||
TEST(MultiBit, SparseIteratorNext2) {
|
TEST(MultiBit, SparseIteratorNext2) {
|
||||||
const u32 test_size = 40000;
|
const u32 test_size = 40000;
|
||||||
vector<mmbit_sparse_iter> it;
|
|
||||||
vector<u32> bits;
|
vector<u32> bits;
|
||||||
|
|
||||||
bits.push_back(1);
|
bits.push_back(1);
|
||||||
@ -939,7 +935,7 @@ TEST(MultiBit, SparseIteratorNext2) {
|
|||||||
bits.push_back(37000);
|
bits.push_back(37000);
|
||||||
bits.push_back(39999);
|
bits.push_back(39999);
|
||||||
|
|
||||||
mmbBuildSparseIterator(it, bits, test_size);
|
auto it = mmbBuildSparseIterator(bits, test_size);
|
||||||
|
|
||||||
// Trivial initial test: all bits in 'bits' are on, all others are off
|
// Trivial initial test: all bits in 'bits' are on, all others are off
|
||||||
mmbit_holder ba(test_size);
|
mmbit_holder ba(test_size);
|
||||||
@ -995,7 +991,6 @@ TEST(MultiBit, SparseIteratorNext2) {
|
|||||||
|
|
||||||
TEST(MultiBit, SparseIteratorNextSmall) {
|
TEST(MultiBit, SparseIteratorNextSmall) {
|
||||||
const u32 test_size = 15;
|
const u32 test_size = 15;
|
||||||
vector<mmbit_sparse_iter> it;
|
|
||||||
vector<u32> bits;
|
vector<u32> bits;
|
||||||
|
|
||||||
bits.push_back(1);
|
bits.push_back(1);
|
||||||
@ -1005,7 +1000,7 @@ TEST(MultiBit, SparseIteratorNextSmall) {
|
|||||||
bits.push_back(12);
|
bits.push_back(12);
|
||||||
bits.push_back(14);
|
bits.push_back(14);
|
||||||
|
|
||||||
mmbBuildSparseIterator(it, bits, test_size);
|
auto it = mmbBuildSparseIterator(bits, test_size);
|
||||||
|
|
||||||
// Trivial initial test: all bits in 'bits' are on, all others are off
|
// Trivial initial test: all bits in 'bits' are on, all others are off
|
||||||
mmbit_holder ba(test_size);
|
mmbit_holder ba(test_size);
|
||||||
@ -1064,13 +1059,12 @@ TEST_P(MultiBitTest, SparseIteratorBeginAll) {
|
|||||||
ASSERT_TRUE(ba != nullptr);
|
ASSERT_TRUE(ba != nullptr);
|
||||||
|
|
||||||
// Put all our bits into the sparse iterator.
|
// Put all our bits into the sparse iterator.
|
||||||
vector<mmbit_sparse_iter> it;
|
|
||||||
vector<u32> bits;
|
vector<u32> bits;
|
||||||
bits.reserve(test_size / stride);
|
bits.reserve(test_size / stride);
|
||||||
for (u64a i = 0; i < test_size; i += stride) {
|
for (u64a i = 0; i < test_size; i += stride) {
|
||||||
bits.push_back(i);
|
bits.push_back(i);
|
||||||
}
|
}
|
||||||
mmbBuildSparseIterator(it, bits, test_size);
|
auto it = mmbBuildSparseIterator(bits, test_size);
|
||||||
|
|
||||||
// Switch all bits on in state.
|
// Switch all bits on in state.
|
||||||
mmbit_clear(ba, test_size);
|
mmbit_clear(ba, test_size);
|
||||||
@ -1104,12 +1098,11 @@ TEST_P(MultiBitTest, SparseIteratorBeginThirds) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Put all our bits into the sparse iterator
|
// Put all our bits into the sparse iterator
|
||||||
vector<mmbit_sparse_iter> it;
|
|
||||||
vector<u32> bits(test_size);
|
vector<u32> bits(test_size);
|
||||||
for (u32 i = 0; i != test_size; i++) {
|
for (u32 i = 0; i != test_size; i++) {
|
||||||
bits[i] = i;
|
bits[i] = i;
|
||||||
}
|
}
|
||||||
mmbBuildSparseIterator(it, bits, test_size);
|
auto it = mmbBuildSparseIterator(bits, test_size);
|
||||||
|
|
||||||
// Switch every third bits on in state
|
// Switch every third bits on in state
|
||||||
mmbit_clear(ba, test_size);
|
mmbit_clear(ba, test_size);
|
||||||
@ -1139,13 +1132,12 @@ TEST_P(MultiBitTest, SparseIteratorNextAll) {
|
|||||||
ASSERT_TRUE(ba != nullptr);
|
ASSERT_TRUE(ba != nullptr);
|
||||||
|
|
||||||
// Put all our bits into the sparse iterator.
|
// Put all our bits into the sparse iterator.
|
||||||
vector<mmbit_sparse_iter> it;
|
|
||||||
vector<u32> bits;
|
vector<u32> bits;
|
||||||
bits.reserve(test_size / stride);
|
bits.reserve(test_size / stride);
|
||||||
for (u64a i = 0; i < test_size; i += stride) {
|
for (u64a i = 0; i < test_size; i += stride) {
|
||||||
bits.push_back(i);
|
bits.push_back(i);
|
||||||
}
|
}
|
||||||
mmbBuildSparseIterator(it, bits, test_size);
|
auto it = mmbBuildSparseIterator(bits, test_size);
|
||||||
|
|
||||||
// Switch all bits on in state
|
// Switch all bits on in state
|
||||||
mmbit_clear(ba, test_size);
|
mmbit_clear(ba, test_size);
|
||||||
@ -1182,14 +1174,13 @@ TEST_P(MultiBitTest, SparseIteratorNextExactStrided) {
|
|||||||
// Put all our bits into the sparse iterator and switch them on in the
|
// Put all our bits into the sparse iterator and switch them on in the
|
||||||
// state.
|
// state.
|
||||||
mmbit_clear(ba, test_size);
|
mmbit_clear(ba, test_size);
|
||||||
vector<mmbit_sparse_iter> it;
|
|
||||||
vector<u32> bits;
|
vector<u32> bits;
|
||||||
bits.reserve(test_size / stride);
|
bits.reserve(test_size / stride);
|
||||||
for (u64a i = 0; i < test_size; i += stride) {
|
for (u64a i = 0; i < test_size; i += stride) {
|
||||||
bits.push_back(i);
|
bits.push_back(i);
|
||||||
mmbit_set(ba, test_size, i);
|
mmbit_set(ba, test_size, i);
|
||||||
}
|
}
|
||||||
mmbBuildSparseIterator(it, bits, test_size);
|
auto it = mmbBuildSparseIterator(bits, test_size);
|
||||||
|
|
||||||
// Iterate over all bits.
|
// Iterate over all bits.
|
||||||
vector<mmbit_sparse_state> state(mmbit_sparse_iter_state_size(test_size));
|
vector<mmbit_sparse_state> state(mmbit_sparse_iter_state_size(test_size));
|
||||||
@ -1214,13 +1205,12 @@ TEST_P(MultiBitTest, SparseIteratorNextNone) {
|
|||||||
ASSERT_TRUE(ba != nullptr);
|
ASSERT_TRUE(ba != nullptr);
|
||||||
|
|
||||||
// Put all our bits into the sparse iterator.
|
// Put all our bits into the sparse iterator.
|
||||||
vector<mmbit_sparse_iter> it;
|
|
||||||
vector<u32> bits;
|
vector<u32> bits;
|
||||||
bits.reserve(test_size / stride);
|
bits.reserve(test_size / stride);
|
||||||
for (u64a i = 0; i < test_size; i += stride) {
|
for (u64a i = 0; i < test_size; i += stride) {
|
||||||
bits.push_back(i);
|
bits.push_back(i);
|
||||||
}
|
}
|
||||||
mmbBuildSparseIterator(it, bits, test_size);
|
auto it = mmbBuildSparseIterator(bits, test_size);
|
||||||
|
|
||||||
// Switch only the first bit on
|
// Switch only the first bit on
|
||||||
mmbit_clear(ba, test_size);
|
mmbit_clear(ba, test_size);
|
||||||
@ -1243,13 +1233,12 @@ TEST_P(MultiBitTest, SparseIteratorUnsetAll) {
|
|||||||
ASSERT_TRUE(ba != nullptr);
|
ASSERT_TRUE(ba != nullptr);
|
||||||
|
|
||||||
// Put all our bits into the sparse iterator
|
// Put all our bits into the sparse iterator
|
||||||
vector<mmbit_sparse_iter> it;
|
|
||||||
vector<u32> bits;
|
vector<u32> bits;
|
||||||
bits.reserve(test_size / stride);
|
bits.reserve(test_size / stride);
|
||||||
for (u64a i = 0; i < test_size; i += stride) {
|
for (u64a i = 0; i < test_size; i += stride) {
|
||||||
bits.push_back(i);
|
bits.push_back(i);
|
||||||
}
|
}
|
||||||
mmbBuildSparseIterator(it, bits, test_size);
|
auto it = mmbBuildSparseIterator(bits, test_size);
|
||||||
|
|
||||||
// Switch all bits on
|
// Switch all bits on
|
||||||
mmbit_clear(ba, test_size);
|
mmbit_clear(ba, test_size);
|
||||||
@ -1283,9 +1272,8 @@ TEST_P(MultiBitTest, SparseIteratorUnsetHalves) {
|
|||||||
odd.push_back(i);
|
odd.push_back(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<mmbit_sparse_iter> it_even, it_odd;
|
auto it_even = mmbBuildSparseIterator(even, test_size);
|
||||||
mmbBuildSparseIterator(it_even, even, test_size);
|
auto it_odd = mmbBuildSparseIterator(odd, test_size);
|
||||||
mmbBuildSparseIterator(it_odd, odd, test_size);
|
|
||||||
|
|
||||||
// Switch all bits on
|
// Switch all bits on
|
||||||
mmbit_clear(ba, test_size);
|
mmbit_clear(ba, test_size);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user