001 /*
002 * Copyright 2010-2014 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.jet.descriptors.serialization;
018
019 import com.google.protobuf.Internal;
020 import org.jetbrains.annotations.NotNull;
021 import org.jetbrains.jet.lang.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.PROTECTED) {
152 return ProtoBuf.Visibility.PROTECTED;
153 }
154 return ProtoBuf.Visibility.EXTRA;
155 }
156
157 @NotNull
158 private static ProtoBuf.Modality modality(@NotNull Modality modality) {
159 switch (modality) {
160 case FINAL:
161 return ProtoBuf.Modality.FINAL;
162 case OPEN:
163 return ProtoBuf.Modality.OPEN;
164 case ABSTRACT:
165 return ProtoBuf.Modality.ABSTRACT;
166 }
167 throw new IllegalArgumentException("Unknown modality: " + modality);
168 }
169
170 @NotNull
171 private static ProtoBuf.Callable.MemberKind memberKind(@NotNull CallableMemberDescriptor.Kind kind) {
172 switch (kind) {
173 case DECLARATION:
174 return ProtoBuf.Callable.MemberKind.DECLARATION;
175 case FAKE_OVERRIDE:
176 return ProtoBuf.Callable.MemberKind.FAKE_OVERRIDE;
177 case DELEGATION:
178 return ProtoBuf.Callable.MemberKind.DELEGATION;
179 case SYNTHESIZED:
180 return ProtoBuf.Callable.MemberKind.SYNTHESIZED;
181 }
182 throw new IllegalArgumentException("Unknown member kind: " + kind);
183 }
184
185 public static int getValueParameterFlags(boolean hasAnnotations, boolean declaresDefaultValue) {
186 return HAS_ANNOTATIONS.toFlags(hasAnnotations)
187 | DECLARES_DEFAULT_VALUE.toFlags(declaresDefaultValue)
188 ;
189 }
190
191 // Infrastructure
192
193 public static abstract class FlagField<E> {
194 public static <E extends Internal.EnumLite> FlagField<E> after(FlagField<?> previousField, E[] values) {
195 int offset = previousField.offset + previousField.bitWidth;
196 return new EnumLiteFlagField<E>(offset, values);
197 }
198
199 public static <E extends Internal.EnumLite> FlagField<E> first(E[] values) {
200 return new EnumLiteFlagField<E>(0, values);
201 }
202
203 public static FlagField<Boolean> booleanFirst() {
204 return new BooleanFlagField(0);
205 }
206
207 public static FlagField<Boolean> booleanAfter(FlagField<?> previousField) {
208 int offset = previousField.offset + previousField.bitWidth;
209 return new BooleanFlagField(offset);
210 }
211
212 private final int offset;
213 private final int bitWidth;
214 private final E[] values;
215
216 private FlagField(int offset, E[] values) {
217 this.offset = offset;
218 this.bitWidth = bitWidth(values);
219 this.values = values;
220 }
221
222 public E get(int flags) {
223 int maskUnshifted = (1 << bitWidth) - 1;
224 int mask = maskUnshifted << offset;
225 int value = (flags & mask) >> offset;
226 return values[value];
227 }
228
229 public int toFlags(E value) {
230 return getIntValue(value) << offset;
231 }
232
233 protected abstract int getIntValue(E value);
234
235 }
236
237 private static class BooleanFlagField extends FlagField<Boolean> {
238 private static final Boolean[] BOOLEAN = { false, true };
239
240 public BooleanFlagField(int offset) {
241 super(offset, BOOLEAN);
242 }
243
244 @Override
245 protected int getIntValue(Boolean value) {
246 return value ? 1 : 0;
247 }
248 }
249
250 private static class EnumLiteFlagField<E extends Internal.EnumLite> extends FlagField<E> {
251 public EnumLiteFlagField(int offset, E[] values) {
252 super(offset, values);
253 }
254
255 @Override
256 protected int getIntValue(E value) {
257 return value.getNumber();
258 }
259 }
260
261 }