89 lines
3.1 KiB
Java
89 lines
3.1 KiB
Java
package unit;
|
|
|
|
import java.util.*;
|
|
|
|
/**
|
|
* CWE-407 unit test: cmake-0002
|
|
* GetDirectoriesWithBacktraces — O(n*m) std::find inside loop vs O(n+m) map lookup.
|
|
*
|
|
* Simulates CMake's GetDirectoriesWithBacktraces():
|
|
* slow: for each orderedDir, scan targetLinkDirs linearly → O(n*m)
|
|
* fast: build HashMap from targetLinkDirs, then lookup → O(n+m)
|
|
*/
|
|
public class GetDirectoriesAlgorithm {
|
|
|
|
// Slow: O(n*m) — mirrors std::find inside for loop
|
|
static long slowGetDirectories(List<String> orderedDirs, List<String> targetLinkDirs) {
|
|
long ops = 0;
|
|
List<String> result = new ArrayList<>();
|
|
for (String dir : orderedDirs) {
|
|
boolean found = false;
|
|
for (String t : targetLinkDirs) { // O(m) scan per element
|
|
ops++;
|
|
if (t.equals(dir)) {
|
|
result.add(t + "#BT");
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) result.add(dir);
|
|
}
|
|
return ops;
|
|
}
|
|
|
|
// Fast: O(n+m) — build map then lookup
|
|
static long fastGetDirectories(List<String> orderedDirs, List<String> targetLinkDirs) {
|
|
long ops = 0;
|
|
Map<String, String> dirIndex = new HashMap<>(targetLinkDirs.size() * 2);
|
|
for (String t : targetLinkDirs) {
|
|
ops++;
|
|
dirIndex.put(t, t + "#BT");
|
|
}
|
|
List<String> result = new ArrayList<>();
|
|
for (String dir : orderedDirs) {
|
|
ops++;
|
|
String bt = dirIndex.get(dir);
|
|
result.add(bt != null ? bt : dir);
|
|
}
|
|
return ops;
|
|
}
|
|
|
|
public static void main(String[] args) {
|
|
int[] sizes = {100, 500, 1000};
|
|
int passed = 0, total = 0;
|
|
|
|
for (int N : sizes) {
|
|
// Build N ordered dirs, half of which are in targetLinkDirs
|
|
List<String> orderedDirs = new ArrayList<>(N);
|
|
List<String> targetLinkDirs = new ArrayList<>(N);
|
|
for (int i = 0; i < N; i++) {
|
|
orderedDirs.add("/usr/lib/dir" + i);
|
|
}
|
|
for (int i = 0; i < N; i += 2) {
|
|
targetLinkDirs.add("/usr/lib/dir" + i); // every other dir has BT
|
|
}
|
|
|
|
long slowOps = slowGetDirectories(orderedDirs, targetLinkDirs);
|
|
long fastOps = fastGetDirectories(orderedDirs, targetLinkDirs);
|
|
double ratio = (double) slowOps / fastOps;
|
|
|
|
total++;
|
|
System.out.printf("N=%4d slow=%8d fast=%6d ratio=%.1fx%n",
|
|
N, slowOps, fastOps, ratio);
|
|
// At N=1000: slow ~ N*M/2 = 250000, fast ~ 3N/2 = 1500 → >100x
|
|
assert ratio > 5.0 : "Expected slow/fast ratio > 5, got " + ratio;
|
|
passed++;
|
|
}
|
|
|
|
// Correctness: both produce same result
|
|
List<String> dirs = Arrays.asList("/a", "/b", "/c");
|
|
List<String> targets = Arrays.asList("/b");
|
|
// Just verify no crash and ops make sense
|
|
long s = slowGetDirectories(dirs, targets);
|
|
long f = fastGetDirectories(dirs, targets);
|
|
assert s > 0 && f > 0;
|
|
passed++; total++;
|
|
|
|
System.out.printf("%d/%d PASS%n", passed, total);
|
|
}
|
|
}
|