// Unit test for 0ad-0003: CCmpTemplateManager::FindUsedTemplates dedup // Verifies that unordered_set-based dedup matches vector-based behavior // and demonstrates O(T^2) -> O(T) improvement. #include #include #include #include #include #include #include #include #include using entity_id_t = uint32_t; // --- BEFORE: vector + std::find --- std::vector FindUsedTemplatesBefore(const std::map& latestTemplates) { std::vector usedTemplates; for (const auto& p : latestTemplates) if (std::find(usedTemplates.begin(), usedTemplates.end(), p.second) == usedTemplates.end()) usedTemplates.push_back(p.second); return usedTemplates; } // --- AFTER: unordered_set --- std::vector FindUsedTemplatesAfter(const std::map& latestTemplates) { std::unordered_set seen; for (const auto& p : latestTemplates) seen.insert(p.second); return std::vector(seen.begin(), seen.end()); } void test_correctness() { std::map templates; // 500 entities using 50 unique templates (typical RTS: many units, few template types) for (entity_id_t i = 0; i < 500; ++i) templates[i] = "template_" + std::to_string(i % 50); auto before = FindUsedTemplatesBefore(templates); auto after = FindUsedTemplatesAfter(templates); // Same size assert(before.size() == after.size()); assert(before.size() == 50); // Same contents (order may differ) std::unordered_set beforeSet(before.begin(), before.end()); std::unordered_set afterSet(after.begin(), after.end()); assert(beforeSet == afterSet); printf("PASS correctness: %zu unique templates from %zu entities\n", after.size(), templates.size()); } void test_performance() { const int ENTITIES = 2000; const int UNIQUE_TEMPLATES = 100; std::map templates; for (int i = 0; i < ENTITIES; ++i) templates[i] = "units/athen/infantry_spearman_" + std::to_string(i % UNIQUE_TEMPLATES); // BEFORE auto t0 = std::chrono::high_resolution_clock::now(); auto before = FindUsedTemplatesBefore(templates); auto t1 = std::chrono::high_resolution_clock::now(); // AFTER auto t2 = std::chrono::high_resolution_clock::now(); auto after = FindUsedTemplatesAfter(templates); auto t3 = std::chrono::high_resolution_clock::now(); assert(before.size() == after.size()); double before_us = std::chrono::duration(t1 - t0).count(); double after_us = std::chrono::duration(t3 - t2).count(); double ratio = before_us / after_us; printf("PASS performance: before=%.0fus after=%.0fus ratio=%.1fx (E=%d, T=%d)\n", before_us, after_us, ratio, ENTITIES, UNIQUE_TEMPLATES); assert(ratio > 1.5 && "Expected at least 1.5x speedup"); } int main() { test_correctness(); test_performance(); printf("ALL TESTS PASSED\n"); return 0; }