108 lines
3.9 KiB
Java
108 lines
3.9 KiB
Java
package unit;
|
|
|
|
import java.util.*;
|
|
|
|
/**
|
|
* CWE-407 unit test: meson-0001
|
|
* BuildTarget.add_deps extra_files dedup — O(n²) list "not in" scan vs O(n) set guard.
|
|
*
|
|
* Simulates mesonbuild/build.py:1572:
|
|
* self.extra_files.extend(f for f in dep.extra_files if f not in self.extra_files)
|
|
*
|
|
* slow: "f not in self.extra_files" is O(len(extra_files)) per element → O(D*F*E)
|
|
* fast: shadow set → O(D*F) amortised
|
|
*/
|
|
public class ExtraFilesAlgorithm {
|
|
|
|
// Slow: mirrors Python "if f not in self.extra_files" — list scan per element
|
|
static long slowAddDepsExtraFiles(List<List<String>> depsExtraFiles) {
|
|
long ops = 0;
|
|
List<String> extraFiles = new ArrayList<>();
|
|
for (List<String> depFiles : depsExtraFiles) {
|
|
for (String f : depFiles) {
|
|
boolean alreadyIn = false;
|
|
for (String existing : extraFiles) { // O(E) scan
|
|
ops++;
|
|
if (existing.equals(f)) { alreadyIn = true; break; }
|
|
}
|
|
if (!alreadyIn) extraFiles.add(f);
|
|
}
|
|
}
|
|
return ops;
|
|
}
|
|
|
|
// Fast: shadow set for O(1) membership
|
|
static long fastAddDepsExtraFiles(List<List<String>> depsExtraFiles) {
|
|
long ops = 0;
|
|
List<String> extraFiles = new ArrayList<>();
|
|
Set<String> extraFilesSet = new HashSet<>();
|
|
for (List<String> depFiles : depsExtraFiles) {
|
|
for (String f : depFiles) {
|
|
ops++;
|
|
if (extraFilesSet.add(f)) {
|
|
extraFiles.add(f);
|
|
}
|
|
}
|
|
}
|
|
return ops;
|
|
}
|
|
|
|
// Generate D deps each contributing F extra files, with X% overlap
|
|
static List<List<String>> makeDepFiles(int D, int F, int uniqueFiles) {
|
|
List<List<String>> result = new ArrayList<>(D);
|
|
Random rng = new Random(42);
|
|
for (int d = 0; d < D; d++) {
|
|
List<String> files = new ArrayList<>(F);
|
|
for (int f = 0; f < F; f++) {
|
|
// Pick randomly from uniqueFiles pool — high overlap expected
|
|
files.add("header_" + rng.nextInt(uniqueFiles) + ".h");
|
|
}
|
|
result.add(files);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static void main(String[] args) {
|
|
// D=deps, F=files-per-dep, unique=unique-file-pool
|
|
int[][] configs = {
|
|
{20, 20, 30}, // small: 20 deps, 20 files each, 30 unique → high overlap
|
|
{50, 50, 80},
|
|
{100, 100, 150},
|
|
{200, 200, 300},
|
|
};
|
|
int passed = 0, total = 0;
|
|
|
|
for (int[] cfg : configs) {
|
|
int D = cfg[0], F = cfg[1], U = cfg[2];
|
|
List<List<String>> depFiles = makeDepFiles(D, F, U);
|
|
|
|
long slowOps = slowAddDepsExtraFiles(depFiles);
|
|
long fastOps = fastAddDepsExtraFiles(depFiles);
|
|
double ratio = (double) slowOps / fastOps;
|
|
|
|
total++;
|
|
System.out.printf("D=%3d F=%3d unique=%3d slow=%8d fast=%6d ratio=%.1fx%n",
|
|
D, F, U, slowOps, fastOps, ratio);
|
|
assert ratio > 3.0 : "Expected ratio > 3 for D=" + D + ", got " + ratio;
|
|
passed++;
|
|
}
|
|
|
|
// Correctness: same unique set produced (order may differ so compare as sets)
|
|
List<List<String>> input = Arrays.asList(
|
|
Arrays.asList("a.h", "b.h", "c.h"),
|
|
Arrays.asList("b.h", "d.h"),
|
|
Arrays.asList("a.h", "e.h")
|
|
);
|
|
List<String> slowOut = new ArrayList<>();
|
|
for (List<String> dep : input)
|
|
for (String f : dep)
|
|
if (!slowOut.contains(f)) slowOut.add(f);
|
|
Set<String> fastOut = new LinkedHashSet<>();
|
|
for (List<String> dep : input) fastOut.addAll(dep);
|
|
assert new HashSet<>(slowOut).equals(new HashSet<>(fastOut)) :
|
|
"Correctness: " + slowOut + " vs " + fastOut;
|
|
passed++; total++;
|
|
|
|
System.out.printf("%d/%d PASS%n", passed, total);
|
|
}
|
|
}
|