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