Serializing/Deserializing simple and qualified names

This commit is contained in:
Andrey Breslav
2013-05-14 12:50:05 +04:00
committed by Alexander Udalov
parent 099b3ffc9f
commit a0895e9046
5 changed files with 346 additions and 0 deletions
@@ -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);
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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);
}
}
@@ -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);
}
}