All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.vladsch.flexmark.util.dependency.DependencyResolver Maven / Gradle / Ivy

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> 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> 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;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy