001 /* 002 * Copyright 2010-2015 JetBrains s.r.o. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package org.jetbrains.kotlin.serialization; 018 019 import org.jetbrains.annotations.NotNull; 020 import org.jetbrains.kotlin.descriptors.ClassDescriptor; 021 import org.jetbrains.kotlin.descriptors.ClassOrPackageFragmentDescriptor; 022 import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; 023 import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor; 024 import org.jetbrains.kotlin.name.FqName; 025 import org.jetbrains.kotlin.name.Name; 026 027 import static org.jetbrains.kotlin.serialization.ProtoBuf.QualifiedNameTable.QualifiedName; 028 029 public class StringTable { 030 private static final class FqNameProto { 031 public final QualifiedName.Builder fqName; 032 033 public FqNameProto(@NotNull QualifiedName.Builder fqName) { 034 this.fqName = fqName; 035 } 036 037 @Override 038 public int hashCode() { 039 int result = 13; 040 result = 31 * result + fqName.getParentQualifiedName(); 041 result = 31 * result + fqName.getShortName(); 042 result = 31 * result + fqName.getKind().hashCode(); 043 return result; 044 } 045 046 @Override 047 public boolean equals(Object obj) { 048 if (obj == null || getClass() != obj.getClass()) return false; 049 050 QualifiedName.Builder other = ((FqNameProto) obj).fqName; 051 return fqName.getParentQualifiedName() == other.getParentQualifiedName() 052 && fqName.getShortName() == other.getShortName() 053 && fqName.getKind() == other.getKind(); 054 } 055 } 056 057 private final Interner<String> strings = new Interner<String>(); 058 private final Interner<FqNameProto> qualifiedNames = new Interner<FqNameProto>(); 059 private final SerializerExtension extension; 060 061 public StringTable(@NotNull SerializerExtension extension) { 062 this.extension = extension; 063 } 064 065 public int getSimpleNameIndex(@NotNull Name name) { 066 return getStringIndex(name.asString()); 067 } 068 069 public int getStringIndex(@NotNull String string) { 070 return strings.intern(string); 071 } 072 073 public int getFqNameIndex(@NotNull ClassOrPackageFragmentDescriptor descriptor) { 074 QualifiedName.Builder builder = QualifiedName.newBuilder(); 075 if (descriptor instanceof ClassDescriptor) { 076 builder.setKind(QualifiedName.Kind.CLASS); 077 } 078 079 DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); 080 int shortName; 081 if (containingDeclaration instanceof PackageFragmentDescriptor) { 082 shortName = getSimpleNameIndex(descriptor.getName()); 083 PackageFragmentDescriptor fragment = (PackageFragmentDescriptor) containingDeclaration; 084 if (!fragment.getFqName().isRoot()) { 085 builder.setParentQualifiedName(getFqNameIndex(fragment.getFqName())); 086 } 087 } 088 else if (containingDeclaration instanceof ClassDescriptor) { 089 shortName = getSimpleNameIndex(descriptor.getName()); 090 ClassDescriptor outerClass = (ClassDescriptor) containingDeclaration; 091 builder.setParentQualifiedName(getFqNameIndex(outerClass)); 092 } 093 else { 094 if (descriptor instanceof ClassDescriptor) { 095 builder.setKind(QualifiedName.Kind.LOCAL); 096 shortName = getStringIndex(extension.getLocalClassName((ClassDescriptor) descriptor)); 097 } 098 else { 099 throw new IllegalStateException("Package container should be a package: " + descriptor); 100 } 101 } 102 103 builder.setShortName(shortName); 104 105 return qualifiedNames.intern(new FqNameProto(builder)); 106 } 107 108 public int getFqNameIndex(@NotNull FqName fqName) { 109 int result = -1; 110 for (Name segment : fqName.pathSegments()) { 111 QualifiedName.Builder builder = QualifiedName.newBuilder(); 112 builder.setShortName(getSimpleNameIndex(segment)); 113 if (result != -1) { 114 builder.setParentQualifiedName(result); 115 } 116 result = qualifiedNames.intern(new FqNameProto(builder)); 117 } 118 return result; 119 } 120 121 @NotNull 122 public ProtoBuf.StringTable serializeSimpleNames() { 123 ProtoBuf.StringTable.Builder builder = ProtoBuf.StringTable.newBuilder(); 124 for (String simpleName : strings.getAllInternedObjects()) { 125 builder.addString(simpleName); 126 } 127 return builder.build(); 128 } 129 130 @NotNull 131 public ProtoBuf.QualifiedNameTable serializeQualifiedNames() { 132 ProtoBuf.QualifiedNameTable.Builder builder = ProtoBuf.QualifiedNameTable.newBuilder(); 133 for (FqNameProto fqName : qualifiedNames.getAllInternedObjects()) { 134 builder.addQualifiedName(fqName.fqName); 135 } 136 return builder.build(); 137 } 138 }