Extracted PartiallyOrderedSet from ClassSorter.

This commit is contained in:
Pavel V. Talanov
2012-03-15 20:24:49 +04:00
parent 090fd1b7f6
commit 452bbdce4d
4 changed files with 211 additions and 143 deletions
@@ -28,7 +28,7 @@ import org.jetbrains.k2js.translate.context.TranslationContext;
import org.jetbrains.k2js.translate.general.AbstractTranslator;
import org.jetbrains.k2js.translate.general.Translation;
import org.jetbrains.k2js.translate.utils.BindingUtils;
import org.jetbrains.k2js.translate.utils.ClassSorter;
import org.jetbrains.k2js.translate.utils.ClassSortingUtils;
import java.util.ArrayList;
import java.util.HashMap;
@@ -128,7 +128,7 @@ public final class ClassDeclarationTranslator extends AbstractTranslator {
for (ClassDescriptor classDescriptor : descriptors) {
classes.add(BindingUtils.getClassForDescriptor(bindingContext(), classDescriptor));
}
return ClassSorter.sortUsingInheritanceOrder(classes, bindingContext());
return ClassSortingUtils.sortUsingInheritanceOrder(classes, bindingContext());
}
@NotNull
@@ -1,141 +0,0 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.k2js.translate.utils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.psi.JetClass;
import org.jetbrains.jet.lang.resolve.BindingContext;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getSuperclassDescriptors;
//TODO: can optimise using less dumb implementation
//TODO: pass list of descriptors here, not the list of jet classes
/**
* @author Pavel Talanov
*/
public final class ClassSorter {
@NotNull
private final List<ClassDescriptor> descriptorList;
@NotNull
private final List<ClassDescriptor> classesWithNoAncestors;
@NotNull
private final Map<ClassDescriptor, Integer> classWasInheritedCount = new HashMap<ClassDescriptor, Integer>();
@NotNull
private final BindingContext bindingContext;
@NotNull
public static List<JetClass> sortUsingInheritanceOrder(@NotNull List<JetClass> original,
@NotNull BindingContext bindingContext) {
ClassSorter sorter = new ClassSorter(original, bindingContext);
return sorter.sortUsingInheritanceOrder();
}
private ClassSorter(@NotNull List<JetClass> original, @NotNull BindingContext bindingContext) {
this.bindingContext = bindingContext;
this.descriptorList = getDescriptorList(original);
this.classesWithNoAncestors = new ArrayList<ClassDescriptor>(descriptorList);
setInitialCount();
}
@NotNull
private List<JetClass> sortUsingInheritanceOrder() {
List<JetClass> sortedClasses = new ArrayList<JetClass>();
while (!classesWithNoAncestors.isEmpty()) {
ClassDescriptor classDescriptor = getNextClass();
sortedClasses.add(BindingUtils.getClassForDescriptor(bindingContext, classDescriptor));
}
assert sortedClasses.size() == descriptorList.size();
return sortedClasses;
}
@NotNull
private ClassDescriptor getNextClass() {
ClassDescriptor result = popFromList();
decreaseCountForDerivedClasses(result);
classWasInheritedCount.remove(result);
return result;
}
private void decreaseCountForDerivedClasses(@NotNull ClassDescriptor result) {
for (ClassDescriptor derived : descriptorList) {
if (isDerivedClass(result, derived)) {
decreaseCountForDerivedClass(derived);
}
}
}
private void decreaseCountForDerivedClass(@NotNull ClassDescriptor derived) {
Integer timesInherited = classWasInheritedCount.get(derived);
assert timesInherited != null;
assert timesInherited > 0;
int newCount = timesInherited - 1;
classWasInheritedCount.put(derived, newCount);
if (newCount == 0) {
classesWithNoAncestors.add(derived);
}
}
private static boolean isDerivedClass(@NotNull ClassDescriptor ancestor, @NotNull ClassDescriptor derived) {
return (getSuperclassDescriptors(derived).contains(ancestor));
}
@NotNull
private ClassDescriptor popFromList() {
assert !classesWithNoAncestors.isEmpty();
ClassDescriptor result = classesWithNoAncestors.get(classesWithNoAncestors.size() - 1);
ClassDescriptor removed = classesWithNoAncestors.remove(classesWithNoAncestors.size() - 1);
assert removed != null;
return result;
}
@NotNull
private List<ClassDescriptor> getDescriptorList(@NotNull List<JetClass> classesToSort) {
List<ClassDescriptor> descriptorList = new ArrayList<ClassDescriptor>();
for (JetClass jetClass : classesToSort) {
descriptorList.add(BindingUtils.getClassDescriptor(bindingContext, jetClass));
}
return descriptorList;
}
private void setInitialCount() {
for (ClassDescriptor descriptor : descriptorList) {
List<ClassDescriptor> superclasses = getSuperclassDescriptors(descriptor);
int count = 0;
for (ClassDescriptor superclassDescriptor : superclasses) {
if (descriptorList.contains(superclassDescriptor)) {
count++;
}
}
classWasInheritedCount.put(descriptor, superclasses.size());
if (count > 0) {
boolean success = classesWithNoAncestors.remove(descriptor);
assert success;
}
}
}
}
@@ -0,0 +1,88 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.k2js.translate.utils;
import com.google.common.collect.Lists;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.psi.JetClass;
import org.jetbrains.jet.lang.resolve.BindingContext;
import java.util.ArrayList;
import java.util.List;
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getSuperclassDescriptors;
//TODO: can optimise using less dumb implementation
//TODO: pass list of descriptors here, not the list of jet classes
/**
* @author Pavel Talanov
*/
public final class ClassSortingUtils {
private ClassSortingUtils() {
}
@NotNull
public static List<JetClass> sortUsingInheritanceOrder(@NotNull List<JetClass> elements,
@NotNull BindingContext bindingContext) {
List<ClassDescriptor> descriptors = descriptorsFromClasses(elements, bindingContext);
PartiallyOrderedSet<ClassDescriptor> partiallyOrderedSet
= new PartiallyOrderedSet<ClassDescriptor>(descriptors, inheritanceOrder());
List<JetClass> sortedClasses = descriptorsToClasses(partiallyOrderedSet.partiallySortedElements(), bindingContext);
assert elements.size() == sortedClasses.size();
return sortedClasses;
}
@NotNull
private static PartiallyOrderedSet.Order<ClassDescriptor> inheritanceOrder() {
return new PartiallyOrderedSet.Order<ClassDescriptor>() {
@Override
public boolean firstDependsOnSecond(@NotNull ClassDescriptor first, @NotNull ClassDescriptor second) {
return isDerivedClass(first, second);
}
};
}
private static boolean isDerivedClass(@NotNull ClassDescriptor ancestor, @NotNull ClassDescriptor derived) {
return (getSuperclassDescriptors(derived).contains(ancestor));
}
@NotNull
private static List<JetClass> descriptorsToClasses(@NotNull List<ClassDescriptor> descriptors,
@NotNull BindingContext bindingContext) {
List<JetClass> sortedClasses = Lists.newArrayList();
for (ClassDescriptor descriptor : descriptors) {
sortedClasses.add(BindingUtils.getClassForDescriptor(bindingContext, descriptor));
}
return sortedClasses;
}
@NotNull
private static List<ClassDescriptor> descriptorsFromClasses(@NotNull List<JetClass> classesToSort,
@NotNull BindingContext bindingContext) {
List<ClassDescriptor> descriptorList = new ArrayList<ClassDescriptor>();
for (JetClass jetClass : classesToSort) {
descriptorList.add(BindingUtils.getClassDescriptor(bindingContext, jetClass));
}
return descriptorList;
}
}
@@ -0,0 +1,121 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.k2js.translate.utils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* @author Pavel Talanov
* <p/>
* This is very inefficient but simple implementation of partially orderered set.
* Feel free to replace with library implementation.
*/
public final class PartiallyOrderedSet<Element> {
private class Arc {
@NotNull
public final Element from;
@NotNull
public final Element to;
private Arc(@NotNull Element from, @NotNull Element to) {
this.from = from;
this.to = to;
}
}
public interface Order<Element> {
boolean firstDependsOnSecond(@NotNull Element first, @NotNull Element Second);
}
@NotNull
private final List<Arc> arcs = Lists.newArrayList();
@NotNull
private final Map<Element, Integer> incomingArcs = Maps.newHashMap();
@NotNull
private final List<Element> elementsWithZeroIncoming = Lists.newArrayList();
public PartiallyOrderedSet(@NotNull Collection<Element> elements, @NotNull Order<Element> order) {
elementsWithZeroIncoming.addAll(elements);
for (@NotNull Element first : elements) {
for (@NotNull Element second : elements) {
if (order.firstDependsOnSecond(first, second)) {
arcs.add(new Arc(first, second));
increaseIncomingCount(second);
}
}
}
}
private void increaseIncomingCount(@NotNull Element element) {
if (!incomingArcs.containsKey(element)) {
incomingArcs.put(element, 1);
elementsWithZeroIncoming.remove(element);
}
else {
Integer count = incomingArcs.get(element);
incomingArcs.put(element, count + 1);
}
}
private void decreaseIncomingCount(@NotNull Element element) {
assert incomingArcs.containsKey(element);
Integer count = incomingArcs.get(element);
if (count == 1) {
incomingArcs.remove(element);
elementsWithZeroIncoming.add(element);
}
else {
incomingArcs.put(element, count - 1);
}
}
@NotNull
public List<Element> partiallySortedElements() {
List<Element> result = Lists.newArrayList();
while (!elementsWithZeroIncoming.isEmpty()) {
result.add(getNextElement());
}
return result;
}
@NotNull
private Element getNextElement() {
Element elementWithZeroIncoming = getElementWithZeroIncoming();
for (Arc arc : arcs) {
if (arc.from == elementWithZeroIncoming) {
decreaseIncomingCount(arc.to);
}
}
return elementWithZeroIncoming;
}
@NotNull
private Element getElementWithZeroIncoming() {
int indexOfLast = elementsWithZeroIncoming.size() - 1;
Element element = elementsWithZeroIncoming.get(indexOfLast);
elementsWithZeroIncoming.remove(indexOfLast);
return element;
}
}