diff --git a/src/nfa/castlecompile.cpp b/src/nfa/castlecompile.cpp index 8d7f3913..cc5c599b 100644 --- a/src/nfa/castlecompile.cpp +++ b/src/nfa/castlecompile.cpp @@ -740,19 +740,13 @@ const CharReach &CastleProto::reach() const { return repeats.begin()->second.reach; } -static -u32 find_next_top(const map &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); @@ -760,6 +754,15 @@ u32 CastleProto::add(const PureRepeat &pr) { 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()); @@ -820,7 +823,7 @@ void remapCastleTops(CastleProto &proto, map &top_map) { 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; } diff --git a/src/nfa/castlecompile.h b/src/nfa/castlecompile.h index 8ca3581c..fc4bb991 100644 --- a/src/nfa/castlecompile.h +++ b/src/nfa/castlecompile.h @@ -68,8 +68,12 @@ struct CastleProto { 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. * @@ -84,6 +88,12 @@ struct CastleProto { /** \brief Mapping from report to associated tops. */ ue2::unordered_map> 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 all_reports(const CastleProto &proto); diff --git a/src/rose/rose_build_role_aliasing.cpp b/src/rose/rose_build_role_aliasing.cpp index 62db5b2e..88deaa25 100644 --- a/src/rose/rose_build_role_aliasing.cpp +++ b/src/rose/rose_build_role_aliasing.cpp @@ -751,14 +751,17 @@ void pruneReportIfUnused(const RoseBuildImpl &tbi, shared_ptr h, * Castle. */ static void pruneCastle(CastleProto &castle, ReportID report) { - for (map::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 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()); } @@ -798,7 +801,7 @@ void pruneUnusedTops(CastleProto &castle, const RoseGraph &g, 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); } } }