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 com.google.protobuf.Internal; 020 import org.jetbrains.annotations.NotNull; 021 import org.jetbrains.kotlin.descriptors.*; 022 023 public class Flags { 024 private Flags() {} 025 026 // Common 027 028 public static final FlagField<Boolean> HAS_ANNOTATIONS = FlagField.booleanFirst(); 029 030 public static final FlagField<ProtoBuf.Visibility> VISIBILITY = FlagField.after(HAS_ANNOTATIONS, ProtoBuf.Visibility.values()); 031 032 public static final FlagField<ProtoBuf.Modality> MODALITY = FlagField.after(VISIBILITY, ProtoBuf.Modality.values()); 033 034 // Class 035 036 public static final FlagField<ProtoBuf.Class.Kind> CLASS_KIND = FlagField.after(MODALITY, ProtoBuf.Class.Kind.values()); 037 038 public static final FlagField<Boolean> INNER = FlagField.booleanAfter(CLASS_KIND); 039 040 // Callables 041 042 public static final FlagField<ProtoBuf.Callable.CallableKind> CALLABLE_KIND = FlagField.after(MODALITY, 043 ProtoBuf.Callable.CallableKind.values()); 044 045 public static final FlagField<ProtoBuf.Callable.MemberKind> MEMBER_KIND = FlagField.after(CALLABLE_KIND, 046 ProtoBuf.Callable.MemberKind.values()); 047 public static final FlagField<Boolean> HAS_GETTER = FlagField.booleanAfter(MEMBER_KIND); 048 public static final FlagField<Boolean> HAS_SETTER = FlagField.booleanAfter(HAS_GETTER); 049 public static final FlagField<Boolean> HAS_CONSTANT = FlagField.booleanAfter(HAS_SETTER); 050 051 // Parameters 052 053 public static final FlagField<Boolean> DECLARES_DEFAULT_VALUE = FlagField.booleanAfter(HAS_ANNOTATIONS); 054 055 // Accessors 056 057 // It's important that this flag is negated: "is NOT default" instead of "is default" 058 public static final FlagField<Boolean> IS_NOT_DEFAULT = FlagField.booleanAfter(MODALITY); 059 060 // --- 061 062 private static <E> int bitWidth(@NotNull E[] enumEntries) { 063 int length = enumEntries.length - 1; 064 if (length == 0) return 1; 065 for (int i = 31; i >= 0; i--) { 066 if ((length & (1 << i)) != 0) return i + 1; 067 } 068 throw new IllegalStateException("Empty enum: " + enumEntries.getClass()); 069 } 070 071 public static int getClassFlags( 072 boolean hasAnnotations, 073 Visibility visibility, 074 Modality modality, 075 ClassKind kind, 076 boolean inner 077 ) { 078 return HAS_ANNOTATIONS.toFlags(hasAnnotations) 079 | MODALITY.toFlags(modality(modality)) 080 | VISIBILITY.toFlags(visibility(visibility)) 081 | CLASS_KIND.toFlags(classKind(kind)) 082 | INNER.toFlags(inner) 083 ; 084 } 085 086 private static ProtoBuf.Class.Kind classKind(ClassKind kind) { 087 switch (kind) { 088 case CLASS: 089 return ProtoBuf.Class.Kind.CLASS; 090 case TRAIT: 091 return ProtoBuf.Class.Kind.TRAIT; 092 case ENUM_CLASS: 093 return ProtoBuf.Class.Kind.ENUM_CLASS; 094 case ENUM_ENTRY: 095 return ProtoBuf.Class.Kind.ENUM_ENTRY; 096 case ANNOTATION_CLASS: 097 return ProtoBuf.Class.Kind.ANNOTATION_CLASS; 098 case OBJECT: 099 return ProtoBuf.Class.Kind.OBJECT; 100 case CLASS_OBJECT: 101 return ProtoBuf.Class.Kind.CLASS_OBJECT; 102 } 103 throw new IllegalArgumentException("Unknown class kind: " + kind); 104 } 105 106 public static int getCallableFlags( 107 boolean hasAnnotations, 108 @NotNull Visibility visibility, 109 @NotNull Modality modality, 110 @NotNull CallableMemberDescriptor.Kind memberKind, 111 @NotNull ProtoBuf.Callable.CallableKind callableKind, 112 boolean hasGetter, 113 boolean hasSetter, 114 boolean hasConstant 115 ) { 116 return HAS_ANNOTATIONS.toFlags(hasAnnotations) 117 | MODALITY.toFlags(modality(modality)) 118 | VISIBILITY.toFlags(visibility(visibility)) 119 | MEMBER_KIND.toFlags(memberKind(memberKind)) 120 | CALLABLE_KIND.toFlags(callableKind) 121 | HAS_GETTER.toFlags(hasGetter) 122 | HAS_SETTER.toFlags(hasSetter) 123 | HAS_CONSTANT.toFlags(hasConstant) 124 ; 125 } 126 127 public static int getAccessorFlags( 128 boolean hasAnnotations, 129 @NotNull Visibility visibility, 130 @NotNull Modality modality, 131 boolean isNotDefault 132 ) { 133 return HAS_ANNOTATIONS.toFlags(hasAnnotations) 134 | MODALITY.toFlags(modality(modality)) 135 | VISIBILITY.toFlags(visibility(visibility)) 136 | IS_NOT_DEFAULT.toFlags(isNotDefault) 137 ; 138 } 139 140 @NotNull 141 private static ProtoBuf.Visibility visibility(@NotNull Visibility visibility) { 142 if (visibility == Visibilities.INTERNAL) { 143 return ProtoBuf.Visibility.INTERNAL; 144 } 145 else if (visibility == Visibilities.PUBLIC) { 146 return ProtoBuf.Visibility.PUBLIC; 147 } 148 else if (visibility == Visibilities.PRIVATE) { 149 return ProtoBuf.Visibility.PRIVATE; 150 } 151 else if (visibility == Visibilities.PRIVATE_TO_THIS) { 152 return ProtoBuf.Visibility.PRIVATE_TO_THIS; 153 } 154 else if (visibility == Visibilities.PROTECTED) { 155 return ProtoBuf.Visibility.PROTECTED; 156 } 157 return ProtoBuf.Visibility.EXTRA; 158 } 159 160 @NotNull 161 private static ProtoBuf.Modality modality(@NotNull Modality modality) { 162 switch (modality) { 163 case FINAL: 164 return ProtoBuf.Modality.FINAL; 165 case OPEN: 166 return ProtoBuf.Modality.OPEN; 167 case ABSTRACT: 168 return ProtoBuf.Modality.ABSTRACT; 169 } 170 throw new IllegalArgumentException("Unknown modality: " + modality); 171 } 172 173 @NotNull 174 private static ProtoBuf.Callable.MemberKind memberKind(@NotNull CallableMemberDescriptor.Kind kind) { 175 switch (kind) { 176 case DECLARATION: 177 return ProtoBuf.Callable.MemberKind.DECLARATION; 178 case FAKE_OVERRIDE: 179 return ProtoBuf.Callable.MemberKind.FAKE_OVERRIDE; 180 case DELEGATION: 181 return ProtoBuf.Callable.MemberKind.DELEGATION; 182 case SYNTHESIZED: 183 return ProtoBuf.Callable.MemberKind.SYNTHESIZED; 184 } 185 throw new IllegalArgumentException("Unknown member kind: " + kind); 186 } 187 188 public static int getValueParameterFlags(boolean hasAnnotations, boolean declaresDefaultValue) { 189 return HAS_ANNOTATIONS.toFlags(hasAnnotations) 190 | DECLARES_DEFAULT_VALUE.toFlags(declaresDefaultValue) 191 ; 192 } 193 194 // Infrastructure 195 196 public static abstract class FlagField<E> { 197 public static <E extends Internal.EnumLite> FlagField<E> after(FlagField<?> previousField, E[] values) { 198 int offset = previousField.offset + previousField.bitWidth; 199 return new EnumLiteFlagField<E>(offset, values); 200 } 201 202 public static <E extends Internal.EnumLite> FlagField<E> first(E[] values) { 203 return new EnumLiteFlagField<E>(0, values); 204 } 205 206 public static FlagField<Boolean> booleanFirst() { 207 return new BooleanFlagField(0); 208 } 209 210 public static FlagField<Boolean> booleanAfter(FlagField<?> previousField) { 211 int offset = previousField.offset + previousField.bitWidth; 212 return new BooleanFlagField(offset); 213 } 214 215 private final int offset; 216 private final int bitWidth; 217 private final E[] values; 218 219 private FlagField(int offset, E[] values) { 220 this.offset = offset; 221 this.bitWidth = bitWidth(values); 222 this.values = values; 223 } 224 225 public E get(int flags) { 226 int maskUnshifted = (1 << bitWidth) - 1; 227 int mask = maskUnshifted << offset; 228 int value = (flags & mask) >> offset; 229 return values[value]; 230 } 231 232 public int toFlags(E value) { 233 return getIntValue(value) << offset; 234 } 235 236 protected abstract int getIntValue(E value); 237 238 } 239 240 private static class BooleanFlagField extends FlagField<Boolean> { 241 private static final Boolean[] BOOLEAN = { false, true }; 242 243 public BooleanFlagField(int offset) { 244 super(offset, BOOLEAN); 245 } 246 247 @Override 248 protected int getIntValue(Boolean value) { 249 return value ? 1 : 0; 250 } 251 } 252 253 private static class EnumLiteFlagField<E extends Internal.EnumLite> extends FlagField<E> { 254 public EnumLiteFlagField(int offset, E[] values) { 255 super(offset, values); 256 } 257 258 @Override 259 protected int getIntValue(E value) { 260 return value.getNumber(); 261 } 262 } 263 264 }