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.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;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user