wave8c: 452/202 — envoy/cilium, graph-dbs, elixir/nim, k8s/maven + PDF
This commit is contained in:
parent
c4330be5b0
commit
3c0b3edc79
49 changed files with 3820 additions and 8 deletions
135
defects/elixir/unit/ElixirMixTopoSortAlgorithm.java
Normal file
135
defects/elixir/unit/ElixirMixTopoSortAlgorithm.java
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
package unit;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* ElixirMixTopoSortAlgorithm — CWE-407 test for elixir-0001
|
||||
*
|
||||
* Models Mix.Dep.Converger.topological_sort/1:
|
||||
* slow: Enum.map(apps, fn app -> Enum.find(deps, ...) end) — O(N²)
|
||||
* fast: Map.new(deps, ...) then Enum.map(apps, dep_index[app]) — O(N)
|
||||
*
|
||||
* Test: for N deps, slow path does N*N list scans; fast path does N map lookups.
|
||||
*/
|
||||
public class ElixirMixTopoSortAlgorithm {
|
||||
|
||||
// Simulate a Mix.Dep struct — just an app name (atom) and an index
|
||||
static class MixDep {
|
||||
final String app;
|
||||
MixDep(String app) { this.app = app; }
|
||||
}
|
||||
|
||||
// --- SLOW: O(N²) ---
|
||||
// Enum.map(apps, fn app -> Enum.find(deps, fn dep -> dep.app == app end) end)
|
||||
static class SlowTopoSort {
|
||||
long comparisons = 0;
|
||||
|
||||
List<MixDep> sort(List<String> apps, List<MixDep> deps) {
|
||||
List<MixDep> result = new ArrayList<>(apps.size());
|
||||
for (String app : apps) {
|
||||
// Enum.find — linear scan
|
||||
MixDep found = null;
|
||||
for (MixDep dep : deps) {
|
||||
comparisons++;
|
||||
if (dep.app.equals(app)) {
|
||||
found = dep;
|
||||
break;
|
||||
}
|
||||
}
|
||||
result.add(found);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// --- FAST: O(N) ---
|
||||
// dep_index = Map.new(deps, fn dep -> {dep.app, dep} end)
|
||||
// Enum.map(apps, fn app -> dep_index[app] end)
|
||||
static class FastTopoSort {
|
||||
long lookups = 0;
|
||||
|
||||
List<MixDep> sort(List<String> apps, List<MixDep> deps) {
|
||||
// Build index: O(N)
|
||||
Map<String, MixDep> index = new HashMap<>(deps.size() * 2);
|
||||
for (MixDep dep : deps) {
|
||||
index.put(dep.app, dep);
|
||||
}
|
||||
// Map lookup: O(1) each
|
||||
List<MixDep> result = new ArrayList<>(apps.size());
|
||||
for (String app : apps) {
|
||||
lookups++;
|
||||
result.add(index.get(app));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
static List<MixDep> makeDeps(int n) {
|
||||
List<MixDep> deps = new ArrayList<>(n);
|
||||
for (int i = 0; i < n; i++) deps.add(new MixDep("dep_" + i));
|
||||
return deps;
|
||||
}
|
||||
|
||||
static List<String> makeApps(List<MixDep> deps) {
|
||||
// Simulate topsort returning atoms in some order
|
||||
List<String> apps = new ArrayList<>(deps.size());
|
||||
for (MixDep d : deps) apps.add(d.app);
|
||||
Collections.shuffle(apps, new Random(42));
|
||||
return apps;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
int[] sizes = {50, 100, 200, 400};
|
||||
System.out.println("ElixirMixTopoSortAlgorithm — elixir-0001");
|
||||
System.out.println(" Pattern: Enum.map + Enum.find(deps) — O(N²) vs Map index — O(N)");
|
||||
System.out.println();
|
||||
|
||||
int passed = 0;
|
||||
int total = 0;
|
||||
|
||||
for (int n : sizes) {
|
||||
List<MixDep> deps = makeDeps(n);
|
||||
List<String> apps = makeApps(deps);
|
||||
|
||||
SlowTopoSort slow = new SlowTopoSort();
|
||||
FastTopoSort fast = new FastTopoSort();
|
||||
|
||||
List<MixDep> slowResult = slow.sort(apps, deps);
|
||||
List<MixDep> fastResult = fast.sort(apps, deps);
|
||||
|
||||
// Verify both produce same order
|
||||
boolean same = true;
|
||||
for (int i = 0; i < apps.size(); i++) {
|
||||
if (!slowResult.get(i).app.equals(fastResult.get(i).app)) {
|
||||
same = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// slow should do ~N*N comparisons (worst case); fast should do exactly N lookups
|
||||
long slowCmp = slow.comparisons;
|
||||
long fastLkp = fast.lookups;
|
||||
|
||||
// For random order, average Enum.find scan is N/2 per element → ~N²/2 total
|
||||
// Fast is always N lookups
|
||||
boolean slowIsQuadratic = slowCmp >= (long) n * n / 4;
|
||||
boolean fastIsLinear = fastLkp == n;
|
||||
|
||||
total += 3;
|
||||
if (same) { System.out.println("PASS N=" + n + ": results match"); passed++; }
|
||||
else { System.out.println("FAIL N=" + n + ": result mismatch"); }
|
||||
|
||||
if (slowIsQuadratic) { System.out.println("PASS N=" + n + ": slow O(N²) comparisons=" + slowCmp + " >= N²/4=" + (n * n / 4)); passed++; }
|
||||
else { System.out.println("FAIL N=" + n + ": slow not quadratic, comparisons=" + slowCmp); }
|
||||
|
||||
if (fastIsLinear) { System.out.println("PASS N=" + n + ": fast O(N) lookups=" + fastLkp + " == N=" + n); passed++; }
|
||||
else { System.out.println("FAIL N=" + n + ": fast not linear, lookups=" + fastLkp); }
|
||||
}
|
||||
|
||||
System.out.println();
|
||||
System.out.println(passed + "/" + total + " PASS");
|
||||
if (passed != total) {
|
||||
throw new AssertionError(passed + "/" + total + " tests passed");
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue