return repeats.begin()->second.reach;
}
-static
-u32 find_next_top(const map<u32, PureRepeat> &repeats) {
- u32 top = verify_u32(repeats.size());
- assert(!contains(repeats, top));
- return top;
-}
-
u32 CastleProto::add(const PureRepeat &pr) {
assert(repeats.size() < max_occupancy);
assert(pr.reach == reach());
assert(pr.reports.size() == 1);
- u32 top = find_next_top(repeats);
+ u32 top = next_top++;
DEBUG_PRINTF("selected unused top %u\n", top);
+ assert(!contains(repeats, top));
repeats.emplace(top, pr);
for (const auto &report : pr.reports) {
report_map[report].insert(top);
return top;
}
+void CastleProto::erase(u32 top) {
+ DEBUG_PRINTF("erase top %u\n", top);
+ assert(contains(repeats, top));
+ repeats.erase(top);
+ for (auto &m : report_map) {
+ m.second.erase(top);
+ }
+}
+
u32 CastleProto::merge(const PureRepeat &pr) {
assert(repeats.size() <= max_occupancy);
assert(pr.reach == reach());
for (const auto &m : proto.repeats) {
const u32 top = m.first;
const PureRepeat &pr = m.second;
- u32 new_top = find_next_top(out);
+ u32 new_top = out.size();
out.emplace(new_top, pr);
top_map[top] = new_top;
}
explicit CastleProto(const PureRepeat &pr);
const CharReach &reach() const;
+ /** \brief Add a new repeat. */
u32 add(const PureRepeat &pr);
+ /** \brief Remove a repeat. */
+ void erase(u32 top);
+
/**
* \brief Merge in the given repeat, returning the top used.
*
/** \brief Mapping from report to associated tops. */
ue2::unordered_map<ReportID, flat_set<u32>> report_map;
+
+ /**
+ * \brief Next top id to use. Repeats may be removed without top remapping,
+ * so we track this explicitly instead of using repeats.size().
+ */
+ u32 next_top = 1;
};
std::set<ReportID> all_reports(const CastleProto &proto);
* Castle. */
static
void pruneCastle(CastleProto &castle, ReportID report) {
- for (map<u32, PureRepeat>::iterator it = castle.repeats.begin();
- it != castle.repeats.end(); /* incr inside */) {
- if (contains(it->second.reports, report)) {
- ++it;
- } else {
- castle.repeats.erase(it++);
+ unordered_set<u32> dead; // tops to remove.
+ for (const auto &m : castle.repeats) {
+ if (!contains(m.second.reports, report)) {
+ dead.insert(m.first);
}
}
+
+ for (const auto &top : dead) {
+ castle.erase(top);
+ }
+
assert(!castle.repeats.empty());
}
for (u32 top : assoc_keys(castle.repeats)) {
if (!contains(used_tops, top)) {
DEBUG_PRINTF("removing unused top %u\n", top);
- castle.repeats.erase(top);
+ castle.erase(top);
}
}
}