rose_build: reduce size/scope of context objects

This commit is contained in:
Alex Coyte 2017-03-30 14:34:33 +11:00 committed by Matthew Barr
parent a2b2940f85
commit 37cb93e60f
14 changed files with 520 additions and 458 deletions

View File

@ -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);
} }

View File

@ -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;

View File

@ -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

View File

@ -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);
} }

View File

@ -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,18 +2219,21 @@ 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) {
return; return;
} }
@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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,92 +680,91 @@ 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 */ continue; /* wrong table */
} }
if (e.second.table != table) { if (lit.delay) {
continue; /* wrong table */ continue; /* delay id's are virtual-ish */
} }
assert(id < build.literal_info.size()); assert(id < build.literal_info.size());
const rose_literal_info &info = build.literal_info[id]; const auto &info = build.literal_info.at(id);
/* 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(), /* Note: requires_benefits are handled in the literal entries */
lit.length()); const ue2_literal &s = lit.s;
// When building the delay rebuild table, we only want to include DEBUG_PRINTF("lit='%s' (len %zu)\n", escapeString(s).c_str(),
// literals that have delayed variants. s.length());
if (delay_rebuild && info.delayed_ids.empty()) {
DEBUG_PRINTF("not needed for delay rebuild\n");
continue;
}
if (max_offset != ROSE_BOUND_INF) { // When building the delay rebuild table, we only want to include
u64a min_report = literalMinReportOffset(build, e.second, info); // literals that have delayed variants.
if (min_report > max_offset) { if (delay_rebuild && info.delayed_ids.empty()) {
DEBUG_PRINTF("min report offset=%llu exceeds max_offset=%u\n", DEBUG_PRINTF("not needed for delay rebuild\n");
min_report, max_offset);
continue; continue;
} }
if (max_offset != ROSE_BOUND_INF) {
u64a min_report = literalMinReportOffset(build, lit, info);
if (min_report > max_offset) {
DEBUG_PRINTF("min report offset=%llu exceeds "
"max_offset=%u\n", min_report, max_offset);
continue;
}
}
const vector<u8> &msk = lit.msk;
const vector<u8> &cmp = lit.cmp;
bool noruns = isNoRunsLiteral(build, id, info, max_len);
size_t lit_hist_len = 0;
if (build.cc.streaming) {
lit_hist_len = max(msk.size(), min(s.length(), max_len));
lit_hist_len = lit_hist_len ? lit_hist_len - 1 : 0;
}
DEBUG_PRINTF("lit requires %zu bytes of history\n", lit_hist_len);
assert(lit_hist_len <= build.cc.grey.maxHistoryAvailable);
auto lit_final = s; // copy
if (lit_final.length() > ROSE_SHORT_LITERAL_LEN_MAX) {
DEBUG_PRINTF("truncating to tail of length %zu\n",
size_t{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.
assert(msk.size() <= ROSE_SHORT_LITERAL_LEN_MAX);
assert(!noruns);
}
const auto &s_final = lit_final.get_string();
bool nocase = lit_final.any_nocase();
DEBUG_PRINTF("id=%u, s='%s', nocase=%d, noruns=%d, msk=%s, "
"cmp=%s\n", f.fragment_id,
escapeString(s_final).c_str(), (int)nocase, noruns,
dumpMask(msk).c_str(), dumpMask(cmp).c_str());
if (!maskIsConsistent(s_final, nocase, msk, cmp)) {
DEBUG_PRINTF("msk/cmp for literal can't match, skipping\n");
continue;
}
mp.accel_lits.emplace_back(s.get_string(), s.any_nocase(), msk, cmp,
info.group_mask);
mp.history_required = max(mp.history_required, lit_hist_len);
u32 prog_offset = delay_rebuild ? f.delay_program_offset
: f.lit_program_offset;
const auto &groups = f.groups;
mp.lits.emplace_back(move(s_final), nocase, noruns, prog_offset,
groups, msk, cmp);
} }
const vector<u8> &msk = e.second.msk;
const vector<u8> &cmp = e.second.cmp;
bool noruns = isNoRunsLiteral(build, id, info, max_len);
size_t lit_hist_len = 0;
if (build.cc.streaming) {
lit_hist_len = max(msk.size(), min(lit.length(), max_len));
lit_hist_len = lit_hist_len ? lit_hist_len - 1 : 0;
}
DEBUG_PRINTF("lit requires %zu bytes of history\n", lit_hist_len);
assert(lit_hist_len <= build.cc.grey.maxHistoryAvailable);
auto lit_final = lit; // copy
if (lit_final.length() > ROSE_SHORT_LITERAL_LEN_MAX) {
DEBUG_PRINTF("truncating to tail of length %zu\n",
size_t{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.
assert(msk.size() <= ROSE_SHORT_LITERAL_LEN_MAX);
assert(!noruns);
}
const auto &s = lit_final.get_string();
bool nocase = lit_final.any_nocase();
DEBUG_PRINTF("id=%u, s='%s', nocase=%d, noruns=%d, msk=%s, "
"cmp=%s\n",
info.fragment_id, escapeString(s).c_str(), (int)nocase,
noruns, dumpMask(msk).c_str(), dumpMask(cmp).c_str());
if (!maskIsConsistent(s, nocase, msk, cmp)) {
DEBUG_PRINTF("msk/cmp for literal can't match, skipping\n");
continue;
}
mp.accel_lits.emplace_back(lit.get_string(), lit.any_nocase(), msk, cmp,
info.group_mask);
mp.history_required = max(mp.history_required, lit_hist_len);
assert(info.fragment_id < build.fragments.size());
const auto &frag = build.fragments.at(info.fragment_id);
u32 prog_offset =
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,
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()) {

View File

@ -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);

View File

@ -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);
} }

View File

@ -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>

View File

@ -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;

View File

@ -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);