From 7a1645efc35db7c1f346335cc079bc756cacd8e3 Mon Sep 17 00:00:00 2001 From: Pavel Talanov Date: Wed, 14 Dec 2011 14:09:32 +0400 Subject: [PATCH] Changes to class sorter implementation. --- .../ClassDeclarationTranslator.java | 2 +- .../k2js/translate/utils/ClassSorter.java | 113 ++++++++++ .../org/jetbrains/k2js/utils/ClassSorter.java | 83 ------- .../org/jetbrains/k2js/utils/DiGraphNode.java | 171 -------------- .../k2js/utils/PartiallyOrderedSet.java | 210 ------------------ 5 files changed, 114 insertions(+), 465 deletions(-) create mode 100644 translator/src/org/jetbrains/k2js/translate/utils/ClassSorter.java delete mode 100644 translator/src/org/jetbrains/k2js/utils/ClassSorter.java delete mode 100644 translator/src/org/jetbrains/k2js/utils/DiGraphNode.java delete mode 100644 translator/src/org/jetbrains/k2js/utils/PartiallyOrderedSet.java diff --git a/translator/src/org/jetbrains/k2js/translate/declaration/ClassDeclarationTranslator.java b/translator/src/org/jetbrains/k2js/translate/declaration/ClassDeclarationTranslator.java index 282648d18a1..23b29c55c97 100644 --- a/translator/src/org/jetbrains/k2js/translate/declaration/ClassDeclarationTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/declaration/ClassDeclarationTranslator.java @@ -13,7 +13,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.utils.ClassSorter; +import org.jetbrains.k2js.translate.utils.ClassSorter; import java.util.ArrayList; import java.util.HashMap; diff --git a/translator/src/org/jetbrains/k2js/translate/utils/ClassSorter.java b/translator/src/org/jetbrains/k2js/translate/utils/ClassSorter.java new file mode 100644 index 00000000000..38152b2f9b7 --- /dev/null +++ b/translator/src/org/jetbrains/k2js/translate/utils/ClassSorter.java @@ -0,0 +1,113 @@ +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.BindingUtils.getSuperclassDescriptors; + +/** + * @author Talanov Pavel + */ +public final class ClassSorter { + + @NotNull + private final List descriptorList; + @NotNull + private final List classesWithNoAncestors; + @NotNull + private final Map classWasInheritedCount = new HashMap(); + @NotNull + private final BindingContext bindingContext; + + @NotNull + static public List sortUsingInheritanceOrder(@NotNull List original, + @NotNull BindingContext bindingContext) { + ClassSorter sorter = new ClassSorter(original, bindingContext); + return sorter.sortUsingInheritanceOrder(); + } + + private ClassSorter(@NotNull List original, @NotNull BindingContext bindingContext) { + this.bindingContext = bindingContext; + this.descriptorList = getDescriptorList(original); + this.classesWithNoAncestors = new ArrayList(descriptorList); + setInitialCount(); + } + + @NotNull + private List sortUsingInheritanceOrder() { + List sortedClasses = new ArrayList(); + 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 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); + classesWithNoAncestors.remove(classesWithNoAncestors.size() - 1); + return result; + } + + + @NotNull + private List getDescriptorList(@NotNull List classesToSort) { + List descriptorList = new ArrayList(); + for (JetClass jetClass : classesToSort) { + descriptorList.add(BindingUtils.getClassDescriptor(bindingContext, jetClass)); + } + return descriptorList; + } + + private void setInitialCount() { + for (ClassDescriptor descriptor : descriptorList) { + List superclasses = getSuperclassDescriptors(descriptor); + classWasInheritedCount.put(descriptor, superclasses.size()); + if (!superclasses.isEmpty()) { + classesWithNoAncestors.remove(descriptor); + } + } + } + +} diff --git a/translator/src/org/jetbrains/k2js/utils/ClassSorter.java b/translator/src/org/jetbrains/k2js/utils/ClassSorter.java deleted file mode 100644 index 2b47930292c..00000000000 --- a/translator/src/org/jetbrains/k2js/utils/ClassSorter.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.jetbrains.k2js.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 org.jetbrains.k2js.translate.utils.BindingUtils; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author Talanov Pavel - */ -public final class ClassSorter { - - @NotNull - private final List classesToSort; - @NotNull - private final List descriptorList; - @NotNull - private final BindingContext bindingContext; - @NotNull - private final PartiallyOrderedSet partiallyOrderedSet = new PartiallyOrderedSet(); - - @NotNull - static public List sortUsingInheritanceOrder(@NotNull List original, - @NotNull BindingContext bindingContext) { - ClassSorter sorter = new ClassSorter(original, bindingContext); - return sorter.sortUsingInheritanceOrder(); - } - - private ClassSorter(@NotNull List original, @NotNull BindingContext bindingContext) { - this.classesToSort = original; - this.bindingContext = bindingContext; - this.descriptorList = getDescriptorList(); - } - - @NotNull - private List sortUsingInheritanceOrder() { - putDescriptorsInPartiallyOrderedSet(); - setInheritanceOrder(); - return getSortedClasses(); - } - - @NotNull - private List getSortedClasses() { - List sortedClasses = new ArrayList(); - for (Object object : partiallyOrderedSet) { - assert object instanceof ClassDescriptor; - sortedClasses.add(BindingUtils.getClassForDescriptor(bindingContext, (ClassDescriptor) object)); - } - return sortedClasses; - } - - private void putDescriptorsInPartiallyOrderedSet() { - partiallyOrderedSet.addAll(descriptorList); - } - - private void setInheritanceOrder() { - for (ClassDescriptor descriptor : getDescriptorList()) { - traverseAncestorsAndSetOrder(descriptor); - } - } - - @NotNull - private List getDescriptorList() { - List descriptorList = new ArrayList(); - for (JetClass jetClass : classesToSort) { - descriptorList.add(BindingUtils.getClassDescriptor(bindingContext, jetClass)); - } - return descriptorList; - } - - private void traverseAncestorsAndSetOrder(@NotNull ClassDescriptor descriptor) { - List superclasses = BindingUtils.getSuperclassDescriptors(descriptor); - for (ClassDescriptor superclass : superclasses) { - partiallyOrderedSet.setOrdering(superclass, descriptor); - traverseAncestorsAndSetOrder(superclass); - } - } - -} diff --git a/translator/src/org/jetbrains/k2js/utils/DiGraphNode.java b/translator/src/org/jetbrains/k2js/utils/DiGraphNode.java deleted file mode 100644 index b599a6cac0e..00000000000 --- a/translator/src/org/jetbrains/k2js/utils/DiGraphNode.java +++ /dev/null @@ -1,171 +0,0 @@ -package org.jetbrains.k2js.utils; - -//TODO: find other implementation or steal it! -/* - * Copyright 2000 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Sun designates this - * particular file as subject to the "Classpath" exception as provided - * by Sun in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - */ - -import java.io.Serializable; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -/** - * A node in a directed graph. In addition to an arbitrary - * Object containing user data associated with the node, - * each node maintains a Sets of nodes which are pointed - * to by the current node (available from getOutNodes). - * The in-degree of the node (that is, number of nodes that point to - * the current node) may be queried. - */ -class DiGraphNode implements Cloneable, Serializable { - - /** - * The data associated with this node. - */ - protected Object data; - - /** - * A Set of neighboring nodes pointed to by this - * node. - */ - protected Set outNodes = new HashSet(); - - /** - * The in-degree of the node. - */ - protected int inDegree = 0; - - /** - * A Set of neighboring nodes that point to this - * node. - */ - private Set inNodes = new HashSet(); - - public DiGraphNode(Object data) { - this.data = data; - } - - /** - * Returns the Object referenced by this node. - */ - public Object getData() { - return data; - } - - /** - * Returns an Iterator containing the nodes pointed - * to by this node. - */ - public Iterator getOutNodes() { - return outNodes.iterator(); - } - - /** - * Adds a directed edge to the graph. The outNodes list of this - * node is updated and the in-degree of the other node is incremented. - * - * @param node a DiGraphNode. - * @return true if the node was not previously the - * target of an edge. - */ - public boolean addEdge(DiGraphNode node) { - if (outNodes.contains(node)) { - return false; - } - - outNodes.add(node); - node.inNodes.add(this); - node.incrementInDegree(); - return true; - } - - /** - * Returns true if an edge exists between this node - * and the given node. - * - * @param node a DiGraphNode. - * @return true if the node is the target of an edge. - */ - public boolean hasEdge(DiGraphNode node) { - return outNodes.contains(node); - } - - /** - * Removes a directed edge from the graph. The outNodes list of this - * node is updated and the in-degree of the other node is decremented. - * - * @return true if the node was previously the target - * of an edge. - */ - public boolean removeEdge(DiGraphNode node) { - if (!outNodes.contains(node)) { - return false; - } - - outNodes.remove(node); - node.inNodes.remove(this); - node.decrementInDegree(); - return true; - } - - /** - * Removes this node from the graph, updating neighboring nodes - * appropriately. - */ - public void dispose() { - Object[] inNodesArray = inNodes.toArray(); - for (int i = 0; i < inNodesArray.length; i++) { - DiGraphNode node = (DiGraphNode) inNodesArray[i]; - node.removeEdge(this); - } - - Object[] outNodesArray = outNodes.toArray(); - for (int i = 0; i < outNodesArray.length; i++) { - DiGraphNode node = (DiGraphNode) outNodesArray[i]; - removeEdge(node); - } - } - - /** - * Returns the in-degree of this node. - */ - public int getInDegree() { - return inDegree; - } - - /** - * Increments the in-degree of this node. - */ - private void incrementInDegree() { - ++inDegree; - } - - /** - * Decrements the in-degree of this node. - */ - private void decrementInDegree() { - --inDegree; - } -} \ No newline at end of file diff --git a/translator/src/org/jetbrains/k2js/utils/PartiallyOrderedSet.java b/translator/src/org/jetbrains/k2js/utils/PartiallyOrderedSet.java deleted file mode 100644 index d18b7b2cb34..00000000000 --- a/translator/src/org/jetbrains/k2js/utils/PartiallyOrderedSet.java +++ /dev/null @@ -1,210 +0,0 @@ -package org.jetbrains.k2js.utils; - -//TODO: find another implementation or steal it! -/* - * Copyright 2000 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Sun designates this - * particular file as subject to the "Classpath" exception as provided - * by Sun in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - */ - -import java.util.*; - -/** - * A set of Objects with pairwise orderings between them. - * The iterator method provides the elements in - * topologically sorted order. Elements participating in a cycle - * are not returned. - *

- * Unlike the SortedSet and SortedMap - * interfaces, which require their elements to implement the - * Comparable interface, this class receives ordering - * information via its setOrdering and - * unsetPreference methods. This difference is due to - * the fact that the relevant ordering between elements is unlikely to - * be inherent in the elements themselves; rather, it is set - * dynamically accoring to application policy. For example, in a - * service provider registry situation, an application might allow the - * user to set a preference order for service provider objects - * supplied by a trusted vendor over those supplied by another. - */ -class PartiallyOrderedSet extends AbstractSet { - - // The topological sort (roughly) follows the algorithm described in - // Horowitz and Sahni, _Fundamentals of Data Structures_ (1976), - // p. 315. - - // Maps Objects to DigraphNodes that contain them - private Map poNodes = new HashMap(); - - // The set of Objects - private Set nodes = poNodes.keySet(); - - /** - * Constructs a PartiallyOrderedSet. - */ - public PartiallyOrderedSet() { - } - - public int size() { - return nodes.size(); - } - - public boolean contains(Object o) { - return nodes.contains(o); - } - - /** - * Returns an iterator over the elements contained in this - * collection, with an ordering that respects the orderings set - * by the setOrdering method. - */ - public Iterator iterator() { - return new PartialOrderIterator(poNodes.values().iterator()); - } - - /** - * Adds an Object to this - * PartiallyOrderedSet. - */ - public boolean add(Object o) { - if (nodes.contains(o)) { - return false; - } - - DiGraphNode node = new DiGraphNode(o); - poNodes.put(o, node); - return true; - } - - /** - * Removes an Object from this - * PartiallyOrderedSet. - */ - public boolean remove(Object o) { - DiGraphNode node = (DiGraphNode) poNodes.get(o); - if (node == null) { - return false; - } - - poNodes.remove(o); - node.dispose(); - return true; - } - - public void clear() { - poNodes.clear(); - } - - /** - * Sets an ordering between two nodes. When an iterator is - * requested, the first node will appear earlier in the - * sequence than the second node. If a prior ordering existed - * between the nodes in the opposite order, it is removed. - * - * @return true if no prior ordering existed - * between the nodes, falseotherwise. - */ - public boolean setOrdering(Object first, Object second) { - DiGraphNode firstPONode = - (DiGraphNode) poNodes.get(first); - DiGraphNode secondPONode = - (DiGraphNode) poNodes.get(second); - - secondPONode.removeEdge(firstPONode); - return firstPONode.addEdge(secondPONode); - } - - /** - * Removes any ordering between two nodes. - * - * @return true if a prior prefence existed between the nodes. - */ - public boolean unsetOrdering(Object first, Object second) { - DiGraphNode firstPONode = - (DiGraphNode) poNodes.get(first); - DiGraphNode secondPONode = - (DiGraphNode) poNodes.get(second); - - return firstPONode.removeEdge(secondPONode) || - secondPONode.removeEdge(firstPONode); - } - - /** - * Returns true if an ordering exists between two - * nodes. - */ - public boolean hasOrdering(Object preferred, Object other) { - DiGraphNode preferredPONode = - (DiGraphNode) poNodes.get(preferred); - DiGraphNode otherPONode = - (DiGraphNode) poNodes.get(other); - - return preferredPONode.hasEdge(otherPONode); - } -} - -class PartialOrderIterator implements Iterator { - - LinkedList zeroList = new LinkedList(); - Map inDegrees = new HashMap(); // DiGraphNode -> Integer - - public PartialOrderIterator(Iterator iter) { - // Initialize scratch in-degree values, zero list - while (iter.hasNext()) { - DiGraphNode node = (DiGraphNode) iter.next(); - int inDegree = node.getInDegree(); - inDegrees.put(node, new Integer(inDegree)); - - // Add nodes with zero in-degree to the zero list - if (inDegree == 0) { - zeroList.add(node); - } - } - } - - public boolean hasNext() { - return !zeroList.isEmpty(); - } - - public Object next() { - DiGraphNode first = (DiGraphNode) zeroList.removeFirst(); - - // For each out node of the output node, decrement its in-degree - Iterator outNodes = first.getOutNodes(); - while (outNodes.hasNext()) { - DiGraphNode node = (DiGraphNode) outNodes.next(); - int inDegree = ((Integer) inDegrees.get(node)).intValue() - 1; - inDegrees.put(node, new Integer(inDegree)); - - // If the in-degree has fallen to 0, place the node on the list - if (inDegree == 0) { - zeroList.add(node); - } - } - - return first.getData(); - } - - public void remove() { - throw new UnsupportedOperationException(); - } -} \ No newline at end of file