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> depsExtraFiles) { long ops = 0; List extraFiles = new ArrayList<>(); for (List 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> depsExtraFiles) { long ops = 0; List extraFiles = new ArrayList<>(); Set extraFilesSet = new HashSet<>(); for (List 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> makeDepFiles(int D, int F, int uniqueFiles) { List> result = new ArrayList<>(D); Random rng = new Random(42); for (int d = 0; d < D; d++) { List 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> 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> input = Arrays.asList( Arrays.asList("a.h", "b.h", "c.h"), Arrays.asList("b.h", "d.h"), Arrays.asList("a.h", "e.h") ); List slowOut = new ArrayList<>(); for (List dep : input) for (String f : dep) if (!slowOut.contains(f)) slowOut.add(f); Set fastOut = new LinkedHashSet<>(); for (List 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); } }