java-topology/defects/widelands-0001/patch/widelands-0001.patch

44 lines
1.6 KiB
Diff

# UNDF: UNDF-2026-000000976
# Widelands CWE-407: FindBobsCallback std::find on vector O(B²) dedup
# File: src/logic/map.cc
# Severity: HIGH
# Speedup: ~250x at B=500 (500 bobs in area)
#
# FindBobsCallback::operator() uses std::find() on a std::vector<Bob*>
# to deduplicate bobs found across adjacent fields. Each bob insertion
# requires scanning the entire list, producing O(B²) where B = bobs found.
# This callback is invoked from find_bobs() and find_reachable_bobs(),
# which are called from 36 sites including combat (soldier finding),
# critter AI (population density), ship fleet scanning, and worker tasks.
#
# Fix: Add an std::unordered_set<Bob*> as a shadow structure for O(1)
# membership checks, keeping the vector output interface unchanged.
--- a/src/logic/map.cc
+++ b/src/logic/map.cc
@@ -1159,14 +1159,16 @@
struct FindBobsCallback {
FindBobsCallback(std::vector<Bob*>* const list, const FindBob& functor)
- : list_(list), functor_(functor) {
+ : list_(list), functor_(functor), seen_() {
}
void operator()(const EditorGameBase& /* egbase */, const FCoords& cur) {
for (Bob* bob = cur.field->get_first_bob(); bob != nullptr; bob = bob->get_next_bob()) {
- if ((list_ != nullptr) && std::find(list_->begin(), list_->end(), bob) != list_->end()) {
+ if ((list_ != nullptr) && seen_.count(bob) != 0) {
continue;
}
if (functor_.accept(bob)) {
if (list_ != nullptr) {
list_->push_back(bob);
+ seen_.insert(bob);
}
++found_;
}
@@ -1176,6 +1178,7 @@
std::vector<Bob*>* list_;
const FindBob& functor_;
uint32_t found_{0U};
+ std::unordered_set<Bob*> seen_;
};