Serializing/Deserializing simple and qualified names
This commit is contained in:
committed by
Alexander Udalov
parent
099b3ffc9f
commit
a0895e9046
+28
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2013 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.jet.descriptors.serialization;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||||
|
|
||||||
|
public interface ClassResolver {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
ClassDescriptor findClass(@NotNull FqName fqName);
|
||||||
|
}
|
||||||
+67
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2013 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.jet.descriptors.serialization;
|
||||||
|
|
||||||
|
import gnu.trove.TObjectHashingStrategy;
|
||||||
|
import gnu.trove.TObjectIntHashMap;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public final class Interner<T> {
|
||||||
|
private final Interner<T> parent;
|
||||||
|
private final int firstIndex;
|
||||||
|
private final TObjectIntHashMap<T> interned;
|
||||||
|
private final List<T> all = new ArrayList<T>();
|
||||||
|
|
||||||
|
public Interner(Interner<T> parent, @NotNull TObjectHashingStrategy<T> hashing) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.firstIndex = parent == null ? 0 : parent.all.size();
|
||||||
|
this.interned = new TObjectIntHashMap<T>(hashing);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Interner(@NotNull TObjectHashingStrategy<T> hashing) {
|
||||||
|
this(null, hashing);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Interner(@Nullable Interner<T> parent) {
|
||||||
|
//noinspection unchecked
|
||||||
|
this(parent, TObjectHashingStrategy.CANONICAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Interner() {
|
||||||
|
//noinspection unchecked
|
||||||
|
this((Interner) null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int intern(@NotNull T obj) {
|
||||||
|
assert parent == null || parent.all.size() == firstIndex : "Parent changed in parallel with child: indexes will be wrong";
|
||||||
|
if (interned.contains(obj)) {
|
||||||
|
return interned.get(obj);
|
||||||
|
}
|
||||||
|
int index = firstIndex + interned.size();
|
||||||
|
interned.put(obj, index);
|
||||||
|
all.add(obj);
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<T> getAllInternedObjects() {
|
||||||
|
return all;
|
||||||
|
}
|
||||||
|
}
|
||||||
+94
@@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2013 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.jet.descriptors.serialization;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||||
|
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||||
|
|
||||||
|
public class NameResolver {
|
||||||
|
private final ProtoBuf.SimpleNameTable simpleNames;
|
||||||
|
private final ProtoBuf.QualifiedNameTable qualifiedNames;
|
||||||
|
private final ClassDescriptor[] classDescriptors;
|
||||||
|
private final ClassResolver classResolver;
|
||||||
|
|
||||||
|
public NameResolver(
|
||||||
|
@NotNull ProtoBuf.SimpleNameTable simpleNames,
|
||||||
|
@NotNull ProtoBuf.QualifiedNameTable qualifiedNames,
|
||||||
|
@NotNull ClassResolver classResolver
|
||||||
|
) {
|
||||||
|
this.simpleNames = simpleNames;
|
||||||
|
this.qualifiedNames = qualifiedNames;
|
||||||
|
this.classDescriptors = new ClassDescriptor[qualifiedNames.getQualifiedNamesCount()];
|
||||||
|
this.classResolver = classResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public Name getName(int index) {
|
||||||
|
String name = simpleNames.getNames(index);
|
||||||
|
return Name.identifier(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public ClassDescriptor getClassDescriptor(int fqNameIndex) {
|
||||||
|
if (classDescriptors[fqNameIndex] != null) {
|
||||||
|
return classDescriptors[fqNameIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtoBuf.QualifiedNameTable.QualifiedName fqNameProto = qualifiedNames.getQualifiedNames(fqNameIndex);
|
||||||
|
assert fqNameProto.getKind() == ProtoBuf.QualifiedNameTable.QualifiedName.Kind.CLASS : "Not a class fqName: " + getFqName(fqNameIndex);
|
||||||
|
|
||||||
|
if (fqNameProto.hasParentQualifiedName()) {
|
||||||
|
int parentFqNameIndex = fqNameProto.getParentQualifiedName();
|
||||||
|
ProtoBuf.QualifiedNameTable.QualifiedName parentFqNameProto = qualifiedNames.getQualifiedNames(parentFqNameIndex);
|
||||||
|
switch (fqNameProto.getKind()) {
|
||||||
|
case CLASS:
|
||||||
|
return classResolver.findClass(getFqName(fqNameIndex));
|
||||||
|
case PACKAGE:
|
||||||
|
Name name = getName(fqNameProto.getShortName());
|
||||||
|
ClassDescriptor outerClass = getClassDescriptor(parentFqNameIndex);
|
||||||
|
if (outerClass == null) return null;
|
||||||
|
|
||||||
|
return (ClassDescriptor) outerClass.getUnsubstitutedInnerClassesScope().getClassifier(name);
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("Unknown kind: " + fqNameProto);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
FqName fqName = FqName.topLevel(getName(fqNameProto.getShortName()));
|
||||||
|
return classResolver.findClass(fqName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public FqName getFqName(int index) {
|
||||||
|
ProtoBuf.QualifiedNameTable.QualifiedName fqNameProto = qualifiedNames.getQualifiedNames(index);
|
||||||
|
StringBuilder sb = renderFqName(new StringBuilder(), fqNameProto);
|
||||||
|
return new FqName(sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private StringBuilder renderFqName(StringBuilder sb, ProtoBuf.QualifiedNameTable.QualifiedName fqNameProto) {
|
||||||
|
if (fqNameProto.hasParentQualifiedName()) {
|
||||||
|
ProtoBuf.QualifiedNameTable.QualifiedName parentProto = qualifiedNames.getQualifiedNames(fqNameProto.getParentQualifiedName());
|
||||||
|
renderFqName(sb, parentProto);
|
||||||
|
sb.append(".");
|
||||||
|
}
|
||||||
|
sb.append(simpleNames.getNames(fqNameProto.getShortName()));
|
||||||
|
return sb;
|
||||||
|
}
|
||||||
|
}
|
||||||
+47
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2013 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.jet.descriptors.serialization;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
public class NameSerializationUtil {
|
||||||
|
@NotNull
|
||||||
|
public static NameResolver deserializeNameResolver(@NotNull InputStream in, @NotNull ClassResolver classResolver)
|
||||||
|
throws IOException {
|
||||||
|
ProtoBuf.SimpleNameTable simpleNames = ProtoBuf.SimpleNameTable.parseDelimitedFrom(in);
|
||||||
|
ProtoBuf.QualifiedNameTable qualifiedNames = ProtoBuf.QualifiedNameTable.parseDelimitedFrom(in);
|
||||||
|
return new NameResolver(simpleNames, qualifiedNames, classResolver);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void serializeNameTable(@NotNull OutputStream out, @NotNull NameTable nameTable) throws IOException {
|
||||||
|
ProtoBuf.SimpleNameTable.Builder simpleNames = ProtoBuf.SimpleNameTable.newBuilder();
|
||||||
|
for (String simpleName : nameTable.getSimpleNames()) {
|
||||||
|
simpleNames.addNames(simpleName);
|
||||||
|
}
|
||||||
|
simpleNames.build().writeDelimitedTo(out);
|
||||||
|
|
||||||
|
ProtoBuf.QualifiedNameTable.Builder qualifiedNames = ProtoBuf.QualifiedNameTable.newBuilder();
|
||||||
|
for (ProtoBuf.QualifiedNameTable.QualifiedName.Builder qName : nameTable.getFqNames()) {
|
||||||
|
qualifiedNames.addQualifiedNames(qName);
|
||||||
|
}
|
||||||
|
qualifiedNames.build().writeDelimitedTo(out);
|
||||||
|
}
|
||||||
|
}
|
||||||
+110
@@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2013 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.jet.descriptors.serialization;
|
||||||
|
|
||||||
|
import gnu.trove.TObjectHashingStrategy;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.impl.NamespaceDescriptorParent;
|
||||||
|
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||||
|
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.jetbrains.jet.descriptors.serialization.ProtoBuf.QualifiedNameTable.QualifiedName;
|
||||||
|
|
||||||
|
public class NameTable {
|
||||||
|
public static final TObjectHashingStrategy<QualifiedName.Builder> QUALIFIED_NAME_BUILDER_HASHING =
|
||||||
|
new TObjectHashingStrategy<ProtoBuf.QualifiedNameTable.QualifiedName.Builder>() {
|
||||||
|
@Override
|
||||||
|
public int computeHashCode(QualifiedName.Builder object) {
|
||||||
|
int result = 13;
|
||||||
|
result = 31 * result + object.getParentQualifiedName();
|
||||||
|
result = 31 * result + object.getShortName();
|
||||||
|
result = 31 * result + object.getKind().hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(
|
||||||
|
QualifiedName.Builder o1, QualifiedName.Builder o2
|
||||||
|
) {
|
||||||
|
return o1.getParentQualifiedName() == o2.getParentQualifiedName()
|
||||||
|
&& o1.getShortName() == o2.getShortName()
|
||||||
|
&& o1.getKind() == o2.getKind();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final Interner<String> simpleNames = new Interner<String>();
|
||||||
|
private final Interner<QualifiedName.Builder> qualifiedNames = new Interner<QualifiedName.Builder>(QUALIFIED_NAME_BUILDER_HASHING);
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public List<String> getSimpleNames() {
|
||||||
|
return simpleNames.getAllInternedObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public List<QualifiedName.Builder> getFqNames() {
|
||||||
|
return qualifiedNames.getAllInternedObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSimpleNameIndex(@NotNull Name name) {
|
||||||
|
return simpleNames.intern(name.asString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFqNameIndex(@NotNull ClassDescriptor classDescriptor) {
|
||||||
|
QualifiedName.Builder builder = QualifiedName.newBuilder();
|
||||||
|
builder.setKind(QualifiedName.Kind.CLASS);
|
||||||
|
builder.setShortName(getSimpleNameIndex(classDescriptor.getName()));
|
||||||
|
|
||||||
|
DeclarationDescriptor containingDeclaration = classDescriptor.getContainingDeclaration();
|
||||||
|
if (containingDeclaration instanceof NamespaceDescriptor) {
|
||||||
|
NamespaceDescriptor namespaceDescriptor = (NamespaceDescriptor) containingDeclaration;
|
||||||
|
builder.setParentQualifiedName(getFqNameIndex(namespaceDescriptor));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ClassDescriptor outerClass = (ClassDescriptor) containingDeclaration;
|
||||||
|
builder.setParentQualifiedName(getFqNameIndex(outerClass));
|
||||||
|
}
|
||||||
|
|
||||||
|
return qualifiedNames.intern(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFqNameIndex(@NotNull NamespaceDescriptor namespaceDescriptor) {
|
||||||
|
QualifiedName.Builder builder = QualifiedName.newBuilder();
|
||||||
|
//default: builder.setKind(QualifiedNameTable.QualifiedName.Kind.PACKAGE);
|
||||||
|
builder.setShortName(getSimpleNameIndex(namespaceDescriptor.getName()));
|
||||||
|
|
||||||
|
NamespaceDescriptorParent containingDeclaration = namespaceDescriptor.getContainingDeclaration();
|
||||||
|
if (containingDeclaration instanceof NamespaceDescriptor) {
|
||||||
|
NamespaceDescriptor parentNamespace = (NamespaceDescriptor) containingDeclaration;
|
||||||
|
if (!DescriptorUtils.isRootNamespace(parentNamespace)) {
|
||||||
|
builder.setParentQualifiedName(getFqNameIndex(parentNamespace));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
builder.clearParentQualifiedName();
|
||||||
|
}
|
||||||
|
|
||||||
|
return qualifiedNames.intern(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user