wesnoth-0001: A* pathfinding std::find on pq vector for decrease-key O(V*Q) per relaxation, fix: lazy deletion. HIGH, 1279x at N=5000. wesnoth-0002: server ip_log_ deque linear scan on login/logoff O(N) per event with N up to 500. MEDIUM, 437x at L=2000. wesnoth-0003: combine_special_notes O(N^2) vector dedup utils::contains on vector per note insertion. MEDIUM, 499x at N=1000. MOAD-0002 (Intertangle): singletons deeply embedded, not actionable. MOAD-0003 (Leaked Context): thread_local for debug/call-stack only. MOAD-0004 (Logged Secret): passwords never logged verbatim. MOAD-0005 (Thundering Herd): single-threaded game + coroutine server. 6/6 unit tests PASS.
67 lines
2.5 KiB
Diff
67 lines
2.5 KiB
Diff
# UNDF: UNDF-2026-000000972
|
|
--- a/src/units/types.cpp
|
|
+++ b/src/units/types.cpp
|
|
@@ -458,10 +458,11 @@ std::vector<t_string> unit_type::special_notes() const {
|
|
|
|
static void append_special_note(std::vector<t_string>& notes, const t_string& new_note) {
|
|
if(new_note.empty()) return;
|
|
std::string_view note_plain = new_note.c_str();
|
|
utils::trim(note_plain);
|
|
if(note_plain.empty()) return;
|
|
- if(utils::contains(notes, new_note)) return;
|
|
notes.push_back(new_note);
|
|
}
|
|
|
|
-std::vector<t_string> combine_special_notes(const std::vector<t_string>& direct, const config& abilities, const const_attack_itors& attacks, const movetype& mt)
|
|
+std::vector<t_string> combine_special_notes(const std::vector<t_string>& direct, const config& abilities, const const_attack_itors& attacks, const movetype& mt)
|
|
{
|
|
- std::vector<t_string> notes;
|
|
+ std::vector<t_string> notes;
|
|
+ // Use a set to track seen notes for O(1) dedup instead of
|
|
+ // O(N) linear scan via utils::contains on vector per insertion.
|
|
+ std::set<std::string> seen;
|
|
for(const auto& note : direct) {
|
|
- append_special_note(notes, note);
|
|
+ std::string key(note.c_str());
|
|
+ if(!key.empty() && seen.insert(key).second) {
|
|
+ notes.push_back(note);
|
|
+ }
|
|
}
|
|
for(const auto [key, cfg] : abilities.all_children_view()) {
|
|
if(cfg.has_attribute("special_note")) {
|
|
- append_special_note(notes, cfg["special_note"].t_str());
|
|
+ const t_string& sn = cfg["special_note"].t_str();
|
|
+ std::string k(sn.c_str());
|
|
+ if(!k.empty() && seen.insert(k).second) {
|
|
+ notes.push_back(sn);
|
|
+ }
|
|
}
|
|
}
|
|
for(const auto& attack : attacks) {
|
|
for(const auto& p_ab : attack.specials()) {
|
|
if(p_ab->cfg().has_attribute("special_note")) {
|
|
- append_special_note(notes, p_ab->cfg()["special_note"].t_str());
|
|
+ const t_string& sn = p_ab->cfg()["special_note"].t_str();
|
|
+ std::string k(sn.c_str());
|
|
+ if(!k.empty() && seen.insert(k).second) {
|
|
+ notes.push_back(sn);
|
|
+ }
|
|
}
|
|
}
|
|
if(auto attack_type_note = string_table.find("special_note_damage_type_" + attack.type()); attack_type_note != string_table.end()) {
|
|
- append_special_note(notes, attack_type_note->second);
|
|
+ std::string k(attack_type_note->second.c_str());
|
|
+ if(!k.empty() && seen.insert(k).second) {
|
|
+ notes.push_back(attack_type_note->second);
|
|
+ }
|
|
}
|
|
}
|
|
for(const auto& move_note : mt.special_notes()) {
|
|
- append_special_note(notes, move_note);
|
|
+ std::string k(move_note.c_str());
|
|
+ if(!k.empty() && seen.insert(k).second) {
|
|
+ notes.push_back(move_note);
|
|
+ }
|
|
}
|
|
return notes;
|
|
}
|