// Unit test for widelands-0002: find_reachable_immovables_unique O(N^2) dedup // Simulates the pattern from src/logic/map.cc // Demonstrates O(N^2) with std::find vs O(N) with unordered_set #include #include #include #include #include #include #include using BaseImmovable = void; struct ImmovableFound { BaseImmovable* object; }; // BEFORE: O(N^2) void dedup_before(const std::vector& duplist, std::vector& list) { for (const ImmovableFound& imm_found : duplist) { BaseImmovable* obj = imm_found.object; if (std::find(list.begin(), list.end(), obj) == list.end()) { list.push_back(obj); } } } // AFTER: O(N) void dedup_after(const std::vector& duplist, std::vector& list) { std::unordered_set seen; for (const ImmovableFound& imm_found : duplist) { BaseImmovable* obj = imm_found.object; if (seen.insert(obj).second) { list.push_back(obj); } } } 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 duplist with ~2x duplicates std::vector duplist; for (int i = 0; i < N; ++i) { duplist.push_back({pool[i]}); } for (int i = 0; i < N; ++i) { duplist.push_back({pool[i]}); } // --- BEFORE --- std::vector list_before; auto t0 = std::chrono::high_resolution_clock::now(); dedup_before(duplist, list_before); auto t1 = std::chrono::high_resolution_clock::now(); double ms_before = std::chrono::duration(t1 - t0).count(); // --- AFTER --- std::vector list_after; auto t2 = std::chrono::high_resolution_clock::now(); dedup_after(duplist, list_after); auto t3 = std::chrono::high_resolution_clock::now(); double ms_after = std::chrono::duration(t3 - t2).count(); // Correctness assert(list_before.size() == list_after.size()); assert(list_before.size() == static_cast(N)); std::sort(list_before.begin(), list_before.end()); std::sort(list_after.begin(), list_after.end()); assert(list_before == list_after); double ratio = ms_before / ms_after; printf("find_reachable_immovables_unique dedup (N=%d, %d entries):\n", N, (int)duplist.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; }