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