java-topology/defects/javac/DependencySorter.java
russell@unturf.com 0a580b313d undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
2026-03-26 17:11:57 -04:00

52 lines
2.3 KiB
Java

package net.minecraft.util;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
/** BEFORE — defective: isCyclic has no visited set — exponential on diamond graphs */
public class DependencySorter<K, V extends DependencySorter.Entry<K>> {
private final Map<K, V> contents = new HashMap<>();
public DependencySorter<K, V> addEntry(K id, V value) {
this.contents.put(id, value);
return this;
}
private void visitDependenciesAndElement(Multimap<K, K> dependencies, Set<K> alreadyVisited, K id, BiConsumer<K, V> output) {
if (!alreadyVisited.add(id)) return;
dependencies.get(id).forEach(dep -> visitDependenciesAndElement(dependencies, alreadyVisited, dep, output));
V current = this.contents.get(id);
if (current != null) output.accept(id, current);
}
// DEFECT: no visited set — O(E^D) on diamond graphs
private static <K> boolean isCyclic(Multimap<K, K> directDependencies, K from, K to) {
Collection<K> dependencies = directDependencies.get(to);
if (dependencies.contains(from)) return true;
return dependencies.stream().anyMatch(dep -> isCyclic(directDependencies, from, dep));
}
private static <K> void addDependencyIfNotCyclic(Multimap<K, K> directDependencies, K from, K to) {
if (!isCyclic(directDependencies, from, to)) directDependencies.put(from, to);
}
public void orderByDependencies(BiConsumer<K, V> output) {
HashMultimap<K, K> directDependencies = HashMultimap.create();
this.contents.forEach((id, value) -> value.visitRequiredDependencies(dep -> addDependencyIfNotCyclic(directDependencies, id, dep)));
this.contents.forEach((id, value) -> value.visitOptionalDependencies(dep -> addDependencyIfNotCyclic(directDependencies, id, dep)));
Set<K> alreadyVisited = new HashSet<>();
this.contents.keySet().forEach(id -> visitDependenciesAndElement(directDependencies, alreadyVisited, id, output));
}
public interface Entry<K> {
void visitRequiredDependencies(Consumer<K> consumer);
void visitOptionalDependencies(Consumer<K> consumer);
}
}