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 kotlin.Function1; 020 import kotlin.KotlinPackage; 021 import org.jetbrains.annotations.NotNull; 022 import org.jetbrains.kotlin.descriptors.ClassDescriptor; 023 import org.jetbrains.kotlin.descriptors.ClassOrPackageFragmentDescriptor; 024 import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; 025 import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor; 026 import org.jetbrains.kotlin.name.FqName; 027 import org.jetbrains.kotlin.name.Name; 028 029 import java.util.List; 030 031 import static org.jetbrains.kotlin.serialization.ProtoBuf.QualifiedNameTable.QualifiedName; 032 033 public class StringTable { 034 private static final class FqNameProto { 035 public final QualifiedName.Builder fqName; 036 037 public FqNameProto(@NotNull QualifiedName.Builder fqName) { 038 this.fqName = fqName; 039 } 040 041 @Override 042 public int hashCode() { 043 int result = 13; 044 result = 31 * result + fqName.getParentQualifiedName(); 045 result = 31 * result + fqName.getShortName(); 046 result = 31 * result + fqName.getKind().hashCode(); 047 return result; 048 } 049 050 @Override 051 public boolean equals(Object obj) { 052 if (obj == null || getClass() != obj.getClass()) return false; 053 054 QualifiedName.Builder other = ((FqNameProto) obj).fqName; 055 return fqName.getParentQualifiedName() == other.getParentQualifiedName() 056 && fqName.getShortName() == other.getShortName() 057 && fqName.getKind() == other.getKind(); 058 } 059 } 060 061 private final Interner<String> strings = new Interner<String>(); 062 private final Interner<FqNameProto> qualifiedNames = new Interner<FqNameProto>(); 063 private final SerializerExtension extension; 064 065 public StringTable(@NotNull SerializerExtension extension) { 066 this.extension = extension; 067 } 068 069 @NotNull 070 public List<String> getStrings() { 071 return strings.getAllInternedObjects(); 072 } 073 074 @NotNull 075 public List<QualifiedName.Builder> getFqNames() { 076 return KotlinPackage.map(qualifiedNames.getAllInternedObjects(), new Function1<FqNameProto, QualifiedName.Builder>() { 077 @Override 078 public QualifiedName.Builder invoke(FqNameProto proto) { 079 return proto.fqName; 080 } 081 }); 082 } 083 084 public int getSimpleNameIndex(@NotNull Name name) { 085 return getStringIndex(name.asString()); 086 } 087 088 public int getStringIndex(@NotNull String string) { 089 return strings.intern(string); 090 } 091 092 public int getFqNameIndex(@NotNull ClassOrPackageFragmentDescriptor descriptor) { 093 QualifiedName.Builder builder = QualifiedName.newBuilder(); 094 if (descriptor instanceof ClassDescriptor) { 095 builder.setKind(QualifiedName.Kind.CLASS); 096 } 097 098 DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); 099 int shortName; 100 if (containingDeclaration instanceof PackageFragmentDescriptor) { 101 shortName = getSimpleNameIndex(descriptor.getName()); 102 PackageFragmentDescriptor fragment = (PackageFragmentDescriptor) containingDeclaration; 103 if (!fragment.getFqName().isRoot()) { 104 builder.setParentQualifiedName(getFqNameIndex(fragment.getFqName())); 105 } 106 } 107 else if (containingDeclaration instanceof ClassDescriptor) { 108 shortName = getSimpleNameIndex(descriptor.getName()); 109 ClassDescriptor outerClass = (ClassDescriptor) containingDeclaration; 110 builder.setParentQualifiedName(getFqNameIndex(outerClass)); 111 } 112 else { 113 if (descriptor instanceof ClassDescriptor) { 114 builder.setKind(QualifiedName.Kind.LOCAL); 115 shortName = getStringIndex(extension.getLocalClassName((ClassDescriptor) descriptor)); 116 } 117 else { 118 throw new IllegalStateException("Package container should be a package: " + descriptor); 119 } 120 } 121 122 builder.setShortName(shortName); 123 124 return qualifiedNames.intern(new FqNameProto(builder)); 125 } 126 127 public int getFqNameIndex(@NotNull FqName fqName) { 128 int result = -1; 129 for (Name segment : fqName.pathSegments()) { 130 QualifiedName.Builder builder = QualifiedName.newBuilder(); 131 builder.setShortName(getSimpleNameIndex(segment)); 132 if (result != -1) { 133 builder.setParentQualifiedName(result); 134 } 135 result = qualifiedNames.intern(new FqNameProto(builder)); 136 } 137 return result; 138 } 139 }