N^3 logN algorithm

This commit is contained in:
Alexey Kudravtsev
2012-10-05 14:15:52 +04:00
parent d1e5ac7653
commit 942805ab65
2 changed files with 72 additions and 54 deletions
@@ -15,6 +15,9 @@
*/
package com.intellij.openapi.vcs.update;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.*;
@@ -22,22 +25,18 @@ import java.util.*;
* author: lesya
*/
public class GroupByPackages {
private final Map<File, Collection<File>> myParentToChildrenMap
= new HashMap<File, Collection<File>>();
private final Map<File, Collection<File>> myParentToChildrenMap = new HashMap<File, Collection<File>>();
private final Collection<File> myRoots = new HashSet<File>();
public GroupByPackages(Collection<File> fiels) {
for (Iterator each = fiels.iterator(); each.hasNext();) {
process((File)each.next());
public GroupByPackages(@NotNull Collection<File> files) {
for (File file : files) {
process(file);
}
splitRoots();
}
private void splitRoots() {
for (Iterator each = new ArrayList(myRoots).iterator(); each.hasNext();) {
File oldRoot = (File)each.next();
for (File oldRoot : new ArrayList<File>(myRoots)) {
File newRoot = splitRoot(oldRoot);
if (!oldRoot.equals(newRoot)) replaceRoot(oldRoot, newRoot);
}
@@ -48,39 +47,38 @@ public class GroupByPackages {
myRoots.add(newRoot);
}
private File splitRoot(File oldRoot) {
Collection<File> children = getChildren(oldRoot);
if (children == null) return oldRoot;
if (children.size() == 1)
return splitRoot(children.iterator().next());
else {
return oldRoot;
private File splitRoot(@NotNull File oldRoot) {
List<File> children = getChildren(oldRoot);
if (children.size() == 1) {
return splitRoot(children.get(0));
}
return oldRoot;
}
private void process(File file) {
private void process(@NotNull final File file) {
File f;
File parent = file.getParentFile();
if (parent == null) {
myRoots.add(file);
return;
for (f = file; parent != null; f = parent, parent = parent.getParentFile()) {
Collection<File> files = myParentToChildrenMap.get(parent);
if (files == null) {
myParentToChildrenMap.put(parent, files = new HashSet<File>());
}
files.add(f);
}
if (!myParentToChildrenMap.containsKey(parent)) myParentToChildrenMap.put(parent, new HashSet<File>());
myParentToChildrenMap.get(parent).add(file);
process(parent);
myRoots.add(f);
}
@NotNull
public List<File> getRoots() {
return new ArrayList<File>(myRoots);
}
@NotNull
public List<File> getChildren(File file) {
Collection<File> collection = myParentToChildrenMap.get(file);
if (collection == null)
return new ArrayList<File>();
else
return new ArrayList<File>(collection);
if (collection == null) {
return ContainerUtil.emptyList();
}
return new ArrayList<File>(collection);
}
}
@@ -40,8 +40,11 @@ public class GroupTreeNode extends AbstractTreeNode implements Disposable {
private final SimpleTextAttributes myInvalidAttributes;
private final Project myProject;
public GroupTreeNode(String name, boolean supportsDeletion, SimpleTextAttributes invalidAttributes,
Project project, final Map<String, String> errorsMap) {
public GroupTreeNode(@NotNull String name,
boolean supportsDeletion,
@NotNull SimpleTextAttributes invalidAttributes,
@NotNull Project project,
@NotNull Map<String, String> errorsMap) {
myName = name;
mySupportsDeletion = supportsDeletion;
myInvalidAttributes = invalidAttributes;
@@ -49,15 +52,20 @@ public class GroupTreeNode extends AbstractTreeNode implements Disposable {
myErrorsMap = errorsMap;
}
@NotNull
@Override
public String getName() {
return myName;
}
@Override
public Icon getIcon(boolean expanded) {
@NonNls String iconName = expanded ? "folderOpen" : "folder";
return IconLoader.getIcon("/nodes/" + iconName + ".png");
}
@NotNull
@Override
public Collection<VirtualFile> getVirtualFiles() {
ArrayList<VirtualFile> result = new ArrayList<VirtualFile>();
for (int i = 0; i < getChildCount(); i++) {
@@ -66,6 +74,8 @@ public class GroupTreeNode extends AbstractTreeNode implements Disposable {
return result;
}
@NotNull
@Override
public Collection<File> getFiles() {
ArrayList<File> result = new ArrayList<File>();
for (int i = 0; i < getChildCount(); i++) {
@@ -74,6 +84,7 @@ public class GroupTreeNode extends AbstractTreeNode implements Disposable {
return result;
}
@Override
protected int getItemsCount() {
int result = 0;
Enumeration children = children();
@@ -84,14 +95,18 @@ public class GroupTreeNode extends AbstractTreeNode implements Disposable {
return result;
}
@Override
protected boolean showStatistics() {
return true;
}
@NotNull
@Override
public SimpleTextAttributes getAttributes() {
return SimpleTextAttributes.SIMPLE_CELL_ATTRIBUTES;
}
@Override
public boolean getSupportsDeletion() {
return mySupportsDeletion;
}
@@ -104,18 +119,19 @@ public class GroupTreeNode extends AbstractTreeNode implements Disposable {
if (containsGroups()) {
rebuildGroups(groupByPackages);
}
else
else {
rebuildFiles(groupByPackages);
}
}
private void rebuildGroups(boolean groupByPackages) {
for (int i = 0; i < getChildCount(); i++)
for (int i = 0; i < getChildCount(); i++) {
((GroupTreeNode)getChildAt(i)).rebuild(groupByPackages);
}
}
private void rebuildFiles(boolean groupByPackages) {
for (int i = getChildCount()-1; i >= 0; i--) {
for (int i = getChildCount() - 1; i >= 0; i--) {
final TreeNode node = getChildAt(i);
if (node instanceof Disposable) {
Disposer.dispose((Disposable)node);
@@ -132,12 +148,13 @@ public class GroupTreeNode extends AbstractTreeNode implements Disposable {
setTreeModel(myTreeModel);
if (myTreeModel != null)
if (myTreeModel != null) {
myTreeModel.nodeStructureChanged(this);
}
}
private void buildPackages() {
ArrayList<File> files = new ArrayList<File>();
Collection<File> files = new LinkedHashSet<File>();
for (final String myFilePath : myFilePaths) {
files.add(new File(myFilePath));
}
@@ -145,21 +162,22 @@ public class GroupTreeNode extends AbstractTreeNode implements Disposable {
List<File> roots = groupByPackages.getRoots();
addFiles(this, roots, files, groupByPackages, null);
}
private void addFiles(AbstractTreeNode parentNode, List<File> roots,
final ArrayList<File> files, GroupByPackages groupByPackages, String parentPath) {
if (roots == null) return;
Collections.sort(roots, new Comparator<File>(){
public int compare(File file, File file1) {
if (files.contains(file) == files.contains(file1))
return file.getAbsolutePath().compareToIgnoreCase(file1.getAbsolutePath());
else if (files.contains(file))
return 1;
else
return -1;
private void addFiles(@NotNull AbstractTreeNode parentNode,
@NotNull List<File> roots,
@NotNull final Collection<File> files,
@NotNull GroupByPackages groupByPackages,
String parentPath) {
Collections.sort(roots, new Comparator<File>() {
@Override
public int compare(File file1, File file2) {
boolean containsFile1 = files.contains(file1);
boolean containsFile2 = files.contains(file2);
if (containsFile1 == containsFile2) {
return file1.getAbsolutePath().compareToIgnoreCase(file2.getAbsolutePath());
}
return containsFile1 ? 1 : -1;
}
});
@@ -167,14 +185,15 @@ public class GroupTreeNode extends AbstractTreeNode implements Disposable {
FileOrDirectoryTreeNode child = files.contains(root)
? new FileTreeNode(root.getAbsolutePath(), myInvalidAttributes, myProject, parentPath)
: new DirectoryTreeNode(root.getAbsolutePath(), myProject, parentPath);
Disposer.register(((Disposable) parentNode), child);
Disposer.register((Disposable)parentNode, child);
parentNode.add(child);
addFiles(child, groupByPackages.getChildren(root), files, groupByPackages, child.getFilePath());
}
}
private void buildFiles() {
Collections.sort(myFilePaths, new Comparator<String>(){
Collections.sort(myFilePaths, new Comparator<String>() {
@Override
public int compare(String path1, String path2) {
return path1.compareToIgnoreCase(path2);
}
@@ -191,10 +210,11 @@ public class GroupTreeNode extends AbstractTreeNode implements Disposable {
}
}
private boolean containsGroups(){
private boolean containsGroups() {
return myFilePaths.isEmpty();
}
@Override
public void dispose() {
}
}