java-topology/defects/cataclysm-0001/test/cataclysm-0001-test.cpp
russell@unturf.com 8ea8ad434f undf: assign 935-937; cataclysm-dda 3 CWE-407 defects
cataclysm-0001: overmap_ui search dedup vector O(P*M), 79x
cataclysm-0002: dependency_tree dedup vector O(N^2), 2x
cataclysm-0003: surroundings_menu item/terfurn dedup O(N^2), 9x
2026-03-31 10:08:23 -04:00

80 lines
2.8 KiB
C++

// Unit test for cataclysm-0001: overmap_ui search dedup
// Verifies that unordered_set dedup matches vector+std::find dedup
// and measures O(1) vs O(N) lookup performance.
#include <algorithm>
#include <cassert>
#include <chrono>
#include <cstdio>
#include <unordered_set>
#include <vector>
// Simulate point_abs_om as a simple pair
struct point_abs_om {
int x, y;
bool operator==( const point_abs_om &o ) const { return x == o.x && y == o.y; }
};
struct point_abs_om_hash {
size_t operator()( const point_abs_om &p ) const {
return std::hash<int>()( p.x ) ^ ( std::hash<int>()( p.y ) << 16 );
}
};
int main() {
// Generate overmap coordinates as if scanning radius 900
// In practice, distinct overmaps = (2*900/180+1)^2 ~ 100
const int num_overmaps = 100;
const int num_lookups = 50000; // simulating many points mapping to same overmaps
std::vector<point_abs_om> points;
for( int i = 0; i < num_lookups; i++ ) {
points.push_back( { i % num_overmaps, i / num_overmaps } );
}
// BEFORE: vector + std::find
{
std::vector<point_abs_om> checked;
int found_count = 0;
auto t0 = std::chrono::high_resolution_clock::now();
for( const auto &p : points ) {
if( std::find( checked.begin(), checked.end(), p ) == checked.end() ) {
checked.push_back( p );
} else {
found_count++;
}
}
auto t1 = std::chrono::high_resolution_clock::now();
double ms_before = std::chrono::duration<double, std::milli>( t1 - t0 ).count();
printf( "BEFORE (vector+find): %.3f ms, %d unique, %d dupes\n",
ms_before, (int)checked.size(), found_count );
// AFTER: unordered_set
std::unordered_set<point_abs_om, point_abs_om_hash> checked_set;
int found_count2 = 0;
auto t2 = std::chrono::high_resolution_clock::now();
for( const auto &p : points ) {
if( checked_set.find( p ) == checked_set.end() ) {
checked_set.insert( p );
} else {
found_count2++;
}
}
auto t3 = std::chrono::high_resolution_clock::now();
double ms_after = std::chrono::duration<double, std::milli>( t3 - t2 ).count();
printf( "AFTER (unordered_set): %.3f ms, %zu unique, %d dupes\n",
ms_after, checked_set.size(), found_count2 );
// Verify correctness
assert( checked.size() == checked_set.size() );
assert( found_count == found_count2 );
double ratio = ms_before / ms_after;
printf( "Speedup ratio: %.1fx\n", ratio );
assert( ratio > 1.5 ); // Must be measurably faster
printf( "PASS: cataclysm-0001 overmap search dedup\n" );
}
return 0;
}