introduce VirtualFile.getNameSequence() to avoid too many String instantiations

This commit is contained in:
peter
2014-03-24 11:29:20 +01:00
parent 297a0b4b79
commit ae53d9918e
12 changed files with 116 additions and 102 deletions
@@ -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;
}
@@ -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<String>)condition).value(fileName)) return false;
@@ -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();
}
}
@@ -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;
@@ -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();
@@ -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<IntObjectLinkedMap.MapEntry<Object>>[] ourNameCache = new IntSLRUCache[16];
@SuppressWarnings("unchecked") private static final IntSLRUCache<IntObjectLinkedMap.MapEntry<CharSequence>>[] 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<IntObjectLinkedMap.MapEntry<Object>>(protectedSize, probationalSize);
ourNameCache[i] = new IntSLRUCache<IntObjectLinkedMap.MapEntry<CharSequence>>(protectedSize, probationalSize);
}
}
@@ -47,15 +46,16 @@ public class FileNameCache {
}
@NotNull
private static IntObjectLinkedMap.MapEntry<Object> cacheData(String name, int id, int stripe) {
private static IntObjectLinkedMap.MapEntry<CharSequence> 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<Object> entry = new IntObjectLinkedMap.MapEntry<Object>(id, rawName);
IntSLRUCache<IntObjectLinkedMap.MapEntry<Object>> cache = ourNameCache[stripe];
CharSequence rawName = convertToBytesIfAsciiString(name);
IntObjectLinkedMap.MapEntry<CharSequence> entry = new IntObjectLinkedMap.MapEntry<CharSequence>(id, rawName);
IntSLRUCache<IntObjectLinkedMap.MapEntry<CharSequence>> 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<Object> getEntry(int id) {
private static IntObjectLinkedMap.MapEntry<CharSequence> getEntry(int id) {
final int stripe = calcStripeIdFromNameId(id);
IntSLRUCache<IntObjectLinkedMap.MapEntry<Object>> cache = ourNameCache[stripe];
IntSLRUCache<IntObjectLinkedMap.MapEntry<CharSequence>> cache = ourNameCache[stripe];
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (cache) {
IntObjectLinkedMap.MapEntry<Object> entry = cache.getCachedEntry(id);
IntObjectLinkedMap.MapEntry<CharSequence> 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<Object> 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<Object> 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<Object> 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<CharSequence> 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]++] = '/';
@@ -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<FSRecords.NameId>() {
@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+")" +
@@ -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<name1.length(); i++) {
@@ -197,9 +204,9 @@ public abstract class VirtualFileSystemEntry extends NewVirtualFile {
return FileNameCache.appendPathOnFileSystem(myNameId, myParent, accumulatedPathLength, positionRef);
}
protected static int copyString(@NotNull char[] chars, int pos, @NotNull String s) {
protected static int copyString(@NotNull char[] chars, int pos, @NotNull CharSequence s) {
int length = s.length();
s.getChars(0, length, chars, pos);
CharArrayUtil.getChars(s, chars, 0, pos, length);
return pos + length;
}
@@ -879,10 +879,10 @@ public class FSRecords implements Forceable {
public static class NameId {
public static final NameId[] EMPTY_ARRAY = new NameId[0];
public final int id;
public final String name;
public final CharSequence name;
public final int nameId;
public NameId(int id, int nameId, @NotNull String name) {
public NameId(int id, int nameId, @NotNull CharSequence name) {
this.id = id;
this.nameId = nameId;
this.name = name;
@@ -141,7 +141,7 @@ public class PersistentFSImpl extends PersistentFS implements ApplicationCompone
return ContainerUtil.map2Array(nameIds, String.class, new Function<FSRecords.NameId, String>() {
@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<String> 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;
}
@@ -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()));
}
}
@@ -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<String> {
}
@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");
}
}