Extracted PartiallyOrderedSet from ClassSorter.
This commit is contained in:
+2
-2
@@ -28,7 +28,7 @@ import org.jetbrains.k2js.translate.context.TranslationContext;
|
|||||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||||
import org.jetbrains.k2js.translate.general.Translation;
|
import org.jetbrains.k2js.translate.general.Translation;
|
||||||
import org.jetbrains.k2js.translate.utils.BindingUtils;
|
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.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -128,7 +128,7 @@ public final class ClassDeclarationTranslator extends AbstractTranslator {
|
|||||||
for (ClassDescriptor classDescriptor : descriptors) {
|
for (ClassDescriptor classDescriptor : descriptors) {
|
||||||
classes.add(BindingUtils.getClassForDescriptor(bindingContext(), classDescriptor));
|
classes.add(BindingUtils.getClassForDescriptor(bindingContext(), classDescriptor));
|
||||||
}
|
}
|
||||||
return ClassSorter.sortUsingInheritanceOrder(classes, bindingContext());
|
return ClassSortingUtils.sortUsingInheritanceOrder(classes, bindingContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user