86 lines
3 KiB
Java
86 lines
3 KiB
Java
package unit;
|
|
|
|
import java.util.*;
|
|
|
|
/**
|
|
* CWE-407 unit test: cmake-0003
|
|
* AddRuntimeDLL — O(n²) std::find before emplace_back vs O(n) set insertion.
|
|
*
|
|
* Simulates CMake's AddRuntimeDLL():
|
|
* slow: scan vector for membership before push → O(n) per call, O(n²) total
|
|
* fast: use HashSet for membership check → O(1) per call, O(n) total
|
|
*/
|
|
public class RuntimeDllAlgorithm {
|
|
|
|
// Slow: mirrors std::find(begin, end, tgt) == end before emplace_back
|
|
static long slowAddRuntimeDlls(List<Integer> dllIds) {
|
|
long ops = 0;
|
|
List<Integer> runtimeDlls = new ArrayList<>();
|
|
for (int id : dllIds) {
|
|
boolean found = false;
|
|
for (int existing : runtimeDlls) { // O(n) scan
|
|
ops++;
|
|
if (existing == id) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) runtimeDlls.add(id);
|
|
}
|
|
return ops;
|
|
}
|
|
|
|
// Fast: unordered_set insertion returns bool (inserted = new)
|
|
static long fastAddRuntimeDlls(List<Integer> dllIds) {
|
|
long ops = 0;
|
|
Set<Integer> runtimeDllsSet = new HashSet<>();
|
|
List<Integer> runtimeDlls = new ArrayList<>();
|
|
for (int id : dllIds) {
|
|
ops++;
|
|
if (runtimeDllsSet.add(id)) {
|
|
runtimeDlls.add(id);
|
|
}
|
|
}
|
|
return ops;
|
|
}
|
|
|
|
public static void main(String[] args) {
|
|
int[] sizes = {100, 500, 1000};
|
|
int passed = 0, total = 0;
|
|
|
|
for (int N : sizes) {
|
|
// D unique DLLs, each referenced twice (common: transitive deps)
|
|
List<Integer> dllIds = new ArrayList<>(N * 2);
|
|
for (int i = 0; i < N; i++) dllIds.add(i);
|
|
for (int i = 0; i < N; i++) dllIds.add(i); // duplicates
|
|
|
|
long slowOps = slowAddRuntimeDlls(dllIds);
|
|
long fastOps = fastAddRuntimeDlls(dllIds);
|
|
double ratio = (double) slowOps / fastOps;
|
|
|
|
total++;
|
|
System.out.printf("D=%4d slow=%8d fast=%6d ratio=%.1fx%n",
|
|
N, slowOps, fastOps, ratio);
|
|
// At D=1000: slow accumulates O(N²/2)=500k ops, fast=2N=2000
|
|
assert ratio > 10.0 : "Expected ratio > 10, got " + ratio;
|
|
passed++;
|
|
}
|
|
|
|
// Correctness: same unique set produced
|
|
List<Integer> input = Arrays.asList(1, 2, 1, 3, 2, 4);
|
|
List<Integer> slowResult = new ArrayList<>();
|
|
Set<Integer> seen = new HashSet<>();
|
|
for (int id : input) {
|
|
boolean found = false;
|
|
for (int x : slowResult) if (x == id) { found = true; break; }
|
|
if (!found) slowResult.add(id);
|
|
}
|
|
Set<Integer> fastResult = new HashSet<>();
|
|
for (int id : input) fastResult.add(id);
|
|
assert new HashSet<>(slowResult).equals(fastResult) :
|
|
"Correctness check failed: " + slowResult + " vs " + fastResult;
|
|
passed++; total++;
|
|
|
|
System.out.printf("%d/%d PASS%n", passed, total);
|
|
}
|
|
}
|