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 gnu.trove.TObjectHashingStrategy; 020 import org.jetbrains.annotations.NotNull; 021 import org.jetbrains.kotlin.descriptors.ClassDescriptor; 022 import org.jetbrains.kotlin.descriptors.ClassOrPackageFragmentDescriptor; 023 import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; 024 import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor; 025 import org.jetbrains.kotlin.name.FqName; 026 import org.jetbrains.kotlin.name.Name; 027 028 import java.util.List; 029 030 import static org.jetbrains.kotlin.serialization.ProtoBuf.QualifiedNameTable.QualifiedName; 031 032 public class StringTable { 033 public static final TObjectHashingStrategy<QualifiedName.Builder> QUALIFIED_NAME_BUILDER_HASHING = 034 new TObjectHashingStrategy<ProtoBuf.QualifiedNameTable.QualifiedName.Builder>() { 035 @Override 036 public int computeHashCode(QualifiedName.Builder object) { 037 int result = 13; 038 result = 31 * result + object.getParentQualifiedName(); 039 result = 31 * result + object.getShortName(); 040 result = 31 * result + object.getKind().hashCode(); 041 return result; 042 } 043 044 @Override 045 public boolean equals(QualifiedName.Builder o1, QualifiedName.Builder o2) { 046 return o1.getParentQualifiedName() == o2.getParentQualifiedName() 047 && o1.getShortName() == o2.getShortName() 048 && o1.getKind() == o2.getKind(); 049 } 050 }; 051 052 private final Interner<String> strings = new Interner<String>(); 053 private final Interner<QualifiedName.Builder> qualifiedNames = new Interner<QualifiedName.Builder>(QUALIFIED_NAME_BUILDER_HASHING); 054 055 @NotNull 056 public List<String> getStrings() { 057 return strings.getAllInternedObjects(); 058 } 059 060 @NotNull 061 public List<QualifiedName.Builder> getFqNames() { 062 return qualifiedNames.getAllInternedObjects(); 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 builder.setShortName(getSimpleNameIndex(descriptor.getName())); 079 080 DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); 081 if (containingDeclaration instanceof PackageFragmentDescriptor) { 082 PackageFragmentDescriptor fragment = (PackageFragmentDescriptor) containingDeclaration; 083 if (!fragment.getFqName().isRoot()) { 084 builder.setParentQualifiedName(getFqNameIndex(fragment.getFqName())); 085 } 086 } 087 else if (containingDeclaration instanceof ClassDescriptor) { 088 ClassDescriptor outerClass = (ClassDescriptor) containingDeclaration; 089 builder.setParentQualifiedName(getFqNameIndex(outerClass)); 090 } 091 else { 092 throw new IllegalStateException("FQ names are only stored for top-level or inner classes: " + descriptor); 093 } 094 095 return qualifiedNames.intern(builder); 096 } 097 098 public int getFqNameIndex(@NotNull FqName fqName) { 099 int result = -1; 100 for (Name segment : fqName.pathSegments()) { 101 QualifiedName.Builder builder = QualifiedName.newBuilder(); 102 builder.setShortName(getSimpleNameIndex(segment)); 103 if (result != -1) { 104 builder.setParentQualifiedName(result); 105 } 106 result = qualifiedNames.intern(builder); 107 } 108 return result; 109 } 110 }