com.vladsch.flexmark.util.dependency.DependencyResolver Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of flexmark-util-dependency Show documentation
Show all versions of flexmark-util-dependency Show documentation
flexmark-java dependency utility classes
The newest version!
package com.vladsch.flexmark.util.dependency;
import com.vladsch.flexmark.util.collection.iteration.ReversibleIndexedIterator;
import com.vladsch.flexmark.util.misc.Ref;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class DependencyResolver {
public static @NotNull List resolveFlatDependencies(
@NotNull List dependentsList,
@Nullable Function, DependentItemMap> itemSorter,
@Nullable Function super D, Class>> classExtractor) {
List> list = resolveDependencies(dependentsList, itemSorter, classExtractor);
if (list.isEmpty()) {
return Collections.emptyList();
} else if (list.size() == 1) {
return list.get(0);
} else {
int totalSize = 0;
for (List subList : list) {
totalSize += subList.size();
}
List flatList = new ArrayList<>(totalSize);
for (List subList : list) {
flatList.addAll(subList);
}
return flatList;
}
}
public static @NotNull List> resolveDependencies(
@NotNull List dependentsList,
@Nullable Function, DependentItemMap> itemSorter,
@Nullable Function super D, Class>> classExtractor) {
if (dependentsList.size() == 0) {
return Collections.emptyList();
} else if (dependentsList.size() == 1) {
return Collections.singletonList(dependentsList);
} else {
// resolve dependencies and processing lists
int dependentCount = dependentsList.size();
DependentItemMap dependentItemMap = new DependentItemMap<>(dependentCount);
if (classExtractor == null) classExtractor = D::getClass;
for (D dependent : dependentsList) {
Class> dependentClass = classExtractor.apply(dependent);
if (dependentItemMap.containsKey(dependentClass)) {
throw new IllegalStateException(
"Dependent class "
+ dependentClass
+ " is duplicated. Only one instance can be present in the list");
}
DependentItem item =
new DependentItem<>(
dependentItemMap.size(),
dependent,
classExtractor.apply(dependent),
dependent.affectsGlobalScope());
dependentItemMap.put(dependentClass, item);
}
for (Map.Entry, DependentItem> entry : dependentItemMap) {
DependentItem item = entry.getValue();
Set> afterDependencies = item.dependent.getAfterDependents();
if (afterDependencies != null && afterDependencies.size() > 0) {
for (Class> dependentClass : afterDependencies) {
if (dependentClass == LastDependent.class) {
// must come after all others
for (DependentItem dependentItem : dependentItemMap.valueIterable()) {
if (dependentItem != null && dependentItem != item) {
item.addDependency(dependentItem);
dependentItem.addDependent(item);
}
}
} else {
DependentItem dependentItem = dependentItemMap.get(dependentClass);
if (dependentItem != null) {
item.addDependency(dependentItem);
dependentItem.addDependent(item);
}
}
}
}
Set> beforeDependents = item.dependent.getBeforeDependents();
if (beforeDependents != null && beforeDependents.size() > 0) {
for (Class> dependentClass : beforeDependents) {
if (dependentClass == FirstDependent.class) {
// must come before all others
for (DependentItem dependentItem : dependentItemMap.valueIterable()) {
if (dependentItem != null && dependentItem != item) {
dependentItem.addDependency(item);
item.addDependent(dependentItem);
}
}
} else {
DependentItem dependentItem = dependentItemMap.get(dependentClass);
if (dependentItem != null) {
dependentItem.addDependency(item);
item.addDependent(dependentItem);
}
}
}
}
}
if (itemSorter != null) {
dependentItemMap = itemSorter.apply(dependentItemMap);
}
dependentCount = dependentItemMap.size();
BitSet newReady = new BitSet(dependentCount);
Ref newReadyRef = new Ref<>(newReady);
ReversibleIndexedIterator> iterator = dependentItemMap.valueIterator();
while (iterator.hasNext()) {
DependentItem item = iterator.next();
if (!item.hasDependencies()) {
newReadyRef.value.set(item.index);
}
}
BitSet dependents = new BitSet(dependentCount);
dependents.set(0, dependentItemMap.size());
List> dependencyStages = new ArrayList<>();
while (newReady.nextSetBit(0) != -1) {
// process these independents in unspecified order since they do not have dependencies
List stageDependents = new ArrayList<>();
BitSet nextDependents = new BitSet();
// collect block processors ready for processing, any non-globals go into independents
while (true) {
int i = newReady.nextSetBit(0);
if (i < 0) {
break;
}
newReady.clear(i);
DependentItem item = dependentItemMap.getValue(i);
stageDependents.add(item.dependent);
dependents.clear(i);
// removeIndex it from dependent's dependencies
if (item.hasDependents()) {
while (true) {
int j = item.dependents.nextSetBit(0);
if (j < 0) {
break;
}
item.dependents.clear(j);
DependentItem dependentItem = dependentItemMap.getValue(j);
if (!dependentItem.removeDependency(item)) {
if (item.isGlobalScope) {
nextDependents.set(j);
} else {
newReady.set(j);
}
}
}
} else if (item.isGlobalScope) {
// globals go in their own stage
nextDependents.or(newReady);
break;
}
}
// can process these in parallel since it will only contain non-globals or globals not
// dependent on other globals
newReady = nextDependents;
dependencyStages.add(stageDependents);
}
if (dependents.nextSetBit(0) != -1) {
throw new IllegalStateException("have dependents with dependency cycles" + dependents);
}
return dependencyStages;
}
}
}