From ae53d9918eb7015cbef51037158eea5227343b15 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 24 Mar 2014 11:29:20 +0100 Subject: [PATCH] introduce VirtualFile.getNameSequence() to avoid too many String instantiations --- .../compiler/server/BuildManager.java | 2 +- .../src/com/intellij/spi/SPIFileType.java | 11 ++- .../com/intellij/openapi/vfs/VirtualFile.java | 5 + .../history/integration/IdeaGateway.java | 3 +- .../openapi/vfs/newvfs/NewVirtualFile.java | 3 + .../vfs/newvfs/impl/FileNameCache.java | 95 +++++-------------- .../vfs/newvfs/impl/VirtualDirectoryImpl.java | 8 +- .../newvfs/impl/VirtualFileSystemEntry.java | 17 +++- .../vfs/newvfs/persistent/FSRecords.java | 4 +- .../newvfs/persistent/PersistentFSImpl.java | 12 +-- .../util/text/ByteArrayCharSequence.java | 48 ++++++++++ .../groovy/dsl/GroovyDslFileIndex.java | 10 +- 12 files changed, 116 insertions(+), 102 deletions(-) create mode 100644 platform/util/src/com/intellij/util/text/ByteArrayCharSequence.java diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java index 01dfb345a8ec..50227a71b35f 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java @@ -1266,7 +1266,7 @@ public class BuildManager implements ApplicationComponent{ @Override public String getValue() { if (myPath.length == 1) { - final String name = FileNameCache.getVFileName(myPath[0]); + final String name = FileNameCache.getVFileName(myPath[0]).toString(); // handle case of windows drive letter return name.length() == 2 && name.endsWith(":")? name + "/" : name; } diff --git a/java/java-impl/src/com/intellij/spi/SPIFileType.java b/java/java-impl/src/com/intellij/spi/SPIFileType.java index 507540460353..ad254be57360 100644 --- a/java/java-impl/src/com/intellij/spi/SPIFileType.java +++ b/java/java-impl/src/com/intellij/spi/SPIFileType.java @@ -18,13 +18,14 @@ package com.intellij.spi; import com.intellij.icons.AllIcons; import com.intellij.lang.spi.SPILanguage; import com.intellij.openapi.extensions.Extensions; -import com.intellij.openapi.fileTypes.*; +import com.intellij.openapi.fileTypes.FileTypeRegistry; +import com.intellij.openapi.fileTypes.FileTypes; +import com.intellij.openapi.fileTypes.LanguageFileType; import com.intellij.openapi.fileTypes.ex.FileTypeIdentifiableByVirtualFile; +import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Condition; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.openapi.vfs.VirtualFile; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -43,9 +44,9 @@ public class SPIFileType extends LanguageFileType implements FileTypeIdentifiabl @Override public boolean isMyFileType(VirtualFile file) { VirtualFile parent = file.getParent(); - if (parent != null && "services".equals(parent.getName())) { + if (parent != null && Comparing.equal("services", parent.getNameSequence())) { final VirtualFile gParent = parent.getParent(); - if (gParent != null && "META-INF".equals(gParent.getName())) { + if (gParent != null && Comparing.equal("META-INF", gParent.getNameSequence())) { final String fileName = file.getName(); for (Object condition : Extensions.getExtensions("com.intellij.vetoSPICondition")) { if (((Condition)condition).value(fileName)) return false; diff --git a/platform/core-api/src/com/intellij/openapi/vfs/VirtualFile.java b/platform/core-api/src/com/intellij/openapi/vfs/VirtualFile.java index e1c23aa071d8..5ac232d80274 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/VirtualFile.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/VirtualFile.java @@ -742,4 +742,9 @@ public abstract class VirtualFile extends UserDataHolderBase implements Modifica public void setDetectedLineSeparator(@Nullable String separator) { putUserData(DETECTED_LINE_SEPARATOR_KEY, separator); } + + @NotNull + public CharSequence getNameSequence() { + return getName(); + } } diff --git a/platform/lvcs-impl/src/com/intellij/history/integration/IdeaGateway.java b/platform/lvcs-impl/src/com/intellij/history/integration/IdeaGateway.java index 523c96802b9b..1a916917d038 100644 --- a/platform/lvcs-impl/src/com/intellij/history/integration/IdeaGateway.java +++ b/platform/lvcs-impl/src/com/intellij/history/integration/IdeaGateway.java @@ -63,8 +63,7 @@ public class IdeaGateway { public boolean isVersioned(@NotNull VirtualFile f, boolean shouldBeInContent) { if (!f.isInLocalFileSystem()) return false; - String fileName = f.getName(); - if (!f.isDirectory() && fileName.endsWith(".class")) return false; + if (!f.isDirectory() && StringUtil.endsWith(f.getNameSequence(), ".class")) return false; Project[] openProjects = ProjectManager.getInstance().getOpenProjects(); boolean isInContent = false; diff --git a/platform/platform-api/src/com/intellij/openapi/vfs/newvfs/NewVirtualFile.java b/platform/platform-api/src/com/intellij/openapi/vfs/newvfs/NewVirtualFile.java index b3b20bf2c95d..73dfa7090318 100644 --- a/platform/platform-api/src/com/intellij/openapi/vfs/newvfs/NewVirtualFile.java +++ b/platform/platform-api/src/com/intellij/openapi/vfs/newvfs/NewVirtualFile.java @@ -67,6 +67,9 @@ public abstract class NewVirtualFile extends VirtualFile implements VirtualFileW public abstract void setTimeStamp(final long time) throws IOException; + + @NotNull + public abstract CharSequence getNameSequence(); @Override public abstract int getId(); diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/FileNameCache.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/FileNameCache.java index a16886740be6..99eca70ed7db 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/FileNameCache.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/FileNameCache.java @@ -16,13 +16,12 @@ package com.intellij.openapi.vfs.newvfs.impl; import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.newvfs.persistent.FSRecords; -import com.intellij.util.containers.IntObjectLinkedMap; import com.intellij.util.IntSLRUCache; +import com.intellij.util.containers.IntObjectLinkedMap; import com.intellij.util.io.IOUtil; import com.intellij.util.io.PersistentStringEnumerator; -import com.intellij.util.text.StringFactory; +import com.intellij.util.text.ByteArrayCharSequence; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -31,12 +30,12 @@ import org.jetbrains.annotations.Nullable; */ public class FileNameCache { private static final PersistentStringEnumerator ourNames = FSRecords.getNames(); - @SuppressWarnings("unchecked") private static final IntSLRUCache>[] ourNameCache = new IntSLRUCache[16]; + @SuppressWarnings("unchecked") private static final IntSLRUCache>[] ourNameCache = new IntSLRUCache[16]; static { final int protectedSize = 40000 / ourNameCache.length; final int probationalSize = 20000 / ourNameCache.length; for(int i = 0; i < ourNameCache.length; ++i) { - ourNameCache[i] = new IntSLRUCache>(protectedSize, probationalSize); + ourNameCache[i] = new IntSLRUCache>(protectedSize, probationalSize); } } @@ -47,15 +46,16 @@ public class FileNameCache { } @NotNull - private static IntObjectLinkedMap.MapEntry cacheData(String name, int id, int stripe) { + private static IntObjectLinkedMap.MapEntry cacheData(String name, int id, int stripe) { if (name == null) { ourNames.markCorrupted(); throw new RuntimeException("VFS name enumerator corrupted"); } - Object rawName = convertToBytesIfAsciiString(name); - IntObjectLinkedMap.MapEntry entry = new IntObjectLinkedMap.MapEntry(id, rawName); - IntSLRUCache> cache = ourNameCache[stripe]; + CharSequence rawName = convertToBytesIfAsciiString(name); + IntObjectLinkedMap.MapEntry entry = new IntObjectLinkedMap.MapEntry(id, rawName); + IntSLRUCache> cache = ourNameCache[stripe]; + //noinspection SynchronizationOnLocalVariableOrMethodParameter synchronized (cache) { return cache.cacheEntry(entry); } @@ -74,7 +74,7 @@ public class FileNameCache { } @NotNull - private static Object convertToBytesIfAsciiString(@NotNull String name) { + private static CharSequence convertToBytesIfAsciiString(@NotNull String name) { int length = name.length(); if (length == 0) return ""; @@ -86,15 +86,16 @@ public class FileNameCache { for (int i = 0; i < length; i++) { bytes[i] = (byte)name.charAt(i); } - return bytes; + return new ByteArrayCharSequence(bytes); } @NotNull - private static IntObjectLinkedMap.MapEntry getEntry(int id) { + private static IntObjectLinkedMap.MapEntry getEntry(int id) { final int stripe = calcStripeIdFromNameId(id); - IntSLRUCache> cache = ourNameCache[stripe]; + IntSLRUCache> cache = ourNameCache[stripe]; + //noinspection SynchronizationOnLocalVariableOrMethodParameter synchronized (cache) { - IntObjectLinkedMap.MapEntry entry = cache.getCachedEntry(id); + IntObjectLinkedMap.MapEntry entry = cache.getCachedEntry(id); if (entry != null) { return entry; } @@ -104,57 +105,20 @@ public class FileNameCache { } @NotNull - public static String getVFileName(int nameId) { - IntObjectLinkedMap.MapEntry entry = getEntry(nameId); - Object name = entry.value; - if (name instanceof String) { - //noinspection StringEquality - return (String)name; - } - - byte[] bytes = (byte[])name; - int length = bytes.length; - char[] chars = new char[length]; - for (int i = 0; i < length; i++) { - chars[i] = (char)bytes[i]; - } - return StringFactory.createShared(chars); + public static CharSequence getVFileName(int nameId) { + return getEntry(nameId).value; } - static int compareNameTo(int nameId, @NotNull String name, boolean ignoreCase) { - IntObjectLinkedMap.MapEntry entry = getEntry(nameId); - Object rawName = entry.value; - if (rawName instanceof String) { - String thisName = (String)rawName; - return VirtualFileSystemEntry.compareNames(thisName, name, ignoreCase); - } - - byte[] bytes = (byte[])rawName; - int bytesLength = bytes.length; - - int d = bytesLength - name.length(); - if (d != 0) return d; - - return compareBytes(bytes, name, bytesLength, ignoreCase); - } - - private static int compareBytes(@NotNull byte[] name1, @NotNull String name2, int len, boolean ignoreCase) { - for (int i = 0; i < len; i++) { - char c1 = (char)name1[i]; - char c2 = name2.charAt(i); - int d = StringUtil.compare(c1, c2, ignoreCase); - if (d != 0) return d; - } - return 0; + static int compareNameTo(int nameId, @NotNull CharSequence name, boolean ignoreCase) { + return VirtualFileSystemEntry.compareNames(getEntry(nameId).value, name, ignoreCase); } @NotNull static char[] appendPathOnFileSystem(int nameId, @Nullable VirtualFileSystemEntry parent, int accumulatedPathLength, @NotNull int[] positionRef) { - IntObjectLinkedMap.MapEntry entry = getEntry(nameId); - Object o = entry.value; - int nameLength = o instanceof String ? ((String)o).length() : ((byte[])o).length; - boolean appendSlash = SystemInfo.isWindows && parent == null && nameLength == 2 && - (o instanceof String ? ((String)o).charAt(1) : (char)((byte[])o)[1]) == ':'; + IntObjectLinkedMap.MapEntry entry = getEntry(nameId); + CharSequence o = entry.value; + int nameLength = o.length(); + boolean appendSlash = SystemInfo.isWindows && parent == null && nameLength == 2 && o.charAt(1) == ':'; char[] chars; if (parent != null) { @@ -169,18 +133,7 @@ public class FileNameCache { chars = new char[rootPathLength]; } - if (o instanceof String) { - positionRef[0] = VirtualFileSystemEntry.copyString(chars, positionRef[0], (String)o); - } - else { - byte[] bytes = (byte[])o; - int pos = positionRef[0]; - //noinspection ForLoopReplaceableByForEach - for (int i = 0, len = bytes.length; i < len; i++) { - chars[pos++] = (char)bytes[i]; - } - positionRef[0] = pos; - } + positionRef[0] = VirtualFileSystemEntry.copyString(chars, positionRef[0], o); if (appendSlash) { chars[positionRef[0]++] = '/'; diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java index 611d01470b87..ae23f72a2e8c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java @@ -151,7 +151,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { @NotNull @Override - public String getName() { + public CharSequence getNameSequence() { return myName; } @@ -161,7 +161,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { } @Override - public int compareNameTo(@NotNull String name, boolean ignoreCase) { + public int compareNameTo(@NotNull CharSequence name, boolean ignoreCase) { return compareNames(myName, name, ignoreCase); } @@ -548,8 +548,8 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { Arrays.sort(childrenIds, new java.util.Comparator() { @Override public int compare(FSRecords.NameId o1, FSRecords.NameId o2) { - String name1 = o1.name; - String name2 = o2.name; + CharSequence name1 = o1.name; + CharSequence name2 = o2.name; int cmp = compareNames(name1, name2, ignoreCase); if (cmp == 0 && name1 != name2) { LOG.error(ourPersistence + " returned duplicate file names("+name1+","+name2+")" + diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualFileSystemEntry.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualFileSystemEntry.java index e0772bc3e4fc..48bfc01c0fa2 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualFileSystemEntry.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualFileSystemEntry.java @@ -32,6 +32,7 @@ import com.intellij.openapi.vfs.newvfs.NewVirtualFile; import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS; import com.intellij.psi.SingleRootFileViewProvider; import com.intellij.util.LocalTimeCounter; +import com.intellij.util.text.CharArrayUtil; import com.intellij.util.text.StringFactory; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -103,18 +104,24 @@ public abstract class VirtualFileSystemEntry extends NewVirtualFile { @Override @NotNull public String getName() { + return getNameSequence().toString(); + } + + @NotNull + @Override + public CharSequence getNameSequence() { return FileNameCache.getVFileName(myNameId); } - public int compareNameTo(@NotNull String name, boolean ignoreCase) { + public int compareNameTo(@NotNull CharSequence name, boolean ignoreCase) { return FileNameCache.compareNameTo(myNameId, name, ignoreCase); } - protected static int compareNames(@NotNull String name1, @NotNull String name2, boolean ignoreCase) { + protected static int compareNames(@NotNull CharSequence name1, @NotNull CharSequence name2, boolean ignoreCase) { return compareNames(name1, name2, ignoreCase, 0); } - static int compareNames(@NotNull String name1, @NotNull String name2, boolean ignoreCase, int offset2) { + static int compareNames(@NotNull CharSequence name1, @NotNull CharSequence name2, boolean ignoreCase, int offset2) { int d = name1.length() - name2.length() + offset2; if (d != 0) return d; for (int i=0; i() { @Override public String fun(FSRecords.NameId id) { - return id.name; + return id.name.toString(); } }); } @@ -172,7 +172,7 @@ public class PersistentFSImpl extends PersistentFS implements ApplicationCompone Set toAdd = ContainerUtil.newHashSet(delegateNames); for (FSRecords.NameId nameId : current) { - toAdd.remove(nameId.name); + toAdd.remove(nameId.name.toString()); } final TIntArrayList childrenIds = new TIntArrayList(current.length + toAdd.size()); @@ -1276,10 +1276,10 @@ public class PersistentFSImpl extends PersistentFS implements ApplicationCompone @NotNull @Override - public abstract String getName(); + public abstract CharSequence getNameSequence(); @Override - public int compareNameTo(@NotNull String name, boolean ignoreCase) { + public int compareNameTo(@NotNull CharSequence name, boolean ignoreCase) { return VirtualFileSystemEntry.compareNames(getName(), name, ignoreCase); } @@ -1309,7 +1309,7 @@ public class PersistentFSImpl extends PersistentFS implements ApplicationCompone @NotNull @Override - public String getName() { + public CharSequence getNameSequence() { return myParentLocalFile.getName(); } @@ -1332,7 +1332,7 @@ public class PersistentFSImpl extends PersistentFS implements ApplicationCompone @NotNull @Override - public String getName() { + public CharSequence getNameSequence() { return myName; } diff --git a/platform/util/src/com/intellij/util/text/ByteArrayCharSequence.java b/platform/util/src/com/intellij/util/text/ByteArrayCharSequence.java new file mode 100644 index 000000000000..2292249b7e91 --- /dev/null +++ b/platform/util/src/com/intellij/util/text/ByteArrayCharSequence.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2014 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 com.intellij.util.text; + +import org.jetbrains.annotations.NotNull; + +public class ByteArrayCharSequence implements CharSequence { + private final byte[] myChars; + + public ByteArrayCharSequence(@NotNull byte... chars) { + myChars = chars; + } + + @Override + public final int length() { + return myChars.length; + } + + @Override + public final char charAt(int index) { + return (char)myChars[index]; + } + + @Override + public CharSequence subSequence(int start, int end) { + return start == 0 && end == length() ? this : new CharSequenceSubSequence(this, start, end); + } + + @Override + @NotNull + public String toString() { + return StringFactory.createShared(CharArrayUtil.fromSequence(this, 0, length())); + } + +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java index fdb4b7f08768..5fe2b8480236 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslFileIndex.java @@ -32,10 +32,8 @@ import com.intellij.openapi.util.ModificationTracker; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Trinity; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileAdapter; -import com.intellij.openapi.vfs.VirtualFileEvent; -import com.intellij.openapi.vfs.VirtualFileManager; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.*; import com.intellij.openapi.vfs.newvfs.FileAttribute; import com.intellij.psi.*; import com.intellij.psi.impl.PsiModificationTrackerImpl; @@ -516,8 +514,8 @@ public class GroovyDslFileIndex extends ScalarIndexExtension { } @Override - public boolean acceptInput(@NotNull final VirtualFile file) { - return "gdsl".equals(file.getExtension()); + public boolean acceptInput(final VirtualFile file) { + return StringUtil.endsWith(file.getNameSequence(), ".gdsl"); } }