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 }