// Unit test for widelands-0003: cleanup_playerimmovables_area burnlist O(N^2) // Simulates the pattern from src/logic/editor_game_base.cc // Demonstrates O(N^2) with std::find vs O(N) with unordered_set #include #include #include #include #include #include #include using PlayerImmovable = void; // BEFORE: O(N^2) void build_burnlist_before(const std::vector& immovables, std::vector& burnlist) { for (PlayerImmovable* imm : immovables) { if (std::find(burnlist.begin(), burnlist.end(), imm) == burnlist.end()) { burnlist.push_back(imm); } } } // AFTER: O(N) void build_burnlist_after(const std::vector& immovables, std::vector& burnlist) { std::unordered_set burnset; for (PlayerImmovable* imm : immovables) { if (burnset.insert(imm).second) { burnlist.push_back(imm); } } } int main() { const int N = 2000; // Create pool of unique immovables std::vector pool; for (int i = 0; i < N; ++i) { pool.push_back(reinterpret_cast(static_cast(i + 1))); } // Create input with ~2x duplicates (simulating overlapping field scans) std::vector immovables; for (int i = 0; i < N; ++i) { immovables.push_back(pool[i]); } for (int i = 0; i < N; ++i) { immovables.push_back(pool[i]); } // --- BEFORE --- std::vector burnlist_before; auto t0 = std::chrono::high_resolution_clock::now(); build_burnlist_before(immovables, burnlist_before); auto t1 = std::chrono::high_resolution_clock::now(); double ms_before = std::chrono::duration(t1 - t0).count(); // --- AFTER --- std::vector burnlist_after; auto t2 = std::chrono::high_resolution_clock::now(); build_burnlist_after(immovables, burnlist_after); auto t3 = std::chrono::high_resolution_clock::now(); double ms_after = std::chrono::duration(t3 - t2).count(); // Correctness assert(burnlist_before.size() == burnlist_after.size()); assert(burnlist_before.size() == static_cast(N)); std::sort(burnlist_before.begin(), burnlist_before.end()); std::sort(burnlist_after.begin(), burnlist_after.end()); assert(burnlist_before == burnlist_after); double ratio = ms_before / ms_after; printf("cleanup_playerimmovables_area burnlist dedup (N=%d, %d entries):\n", N, (int)immovables.size()); printf(" BEFORE (std::find): %.3f ms\n", ms_before); printf(" AFTER (unordered_set): %.3f ms\n", ms_after); printf(" Ratio: %.1fx\n", ratio); assert(ratio > 2.0); printf("PASS\n"); return 0; }