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