001 package org.jetbrains.jet.descriptors.serialization;
002
003 import com.google.protobuf.Internal;
004 import org.jetbrains.annotations.NotNull;
005 import org.jetbrains.jet.lang.descriptors.*;
006
007 public class Flags {
008 private Flags() {}
009
010 // Common
011
012 public static final FlagField<Boolean> HAS_ANNOTATIONS = FlagField.booleanFirst();
013
014 public static final FlagField<ProtoBuf.Visibility> VISIBILITY = FlagField.after(HAS_ANNOTATIONS, ProtoBuf.Visibility.values());
015
016 public static final FlagField<ProtoBuf.Modality> MODALITY = FlagField.after(VISIBILITY, ProtoBuf.Modality.values());
017
018 // Class
019
020 public static final FlagField<ProtoBuf.Class.Kind> CLASS_KIND = FlagField.after(MODALITY, ProtoBuf.Class.Kind.values());
021
022 public static final FlagField<Boolean> INNER = FlagField.booleanAfter(CLASS_KIND);
023
024 // Callables
025
026 public static final FlagField<ProtoBuf.Callable.CallableKind> CALLABLE_KIND = FlagField.after(MODALITY,
027 ProtoBuf.Callable.CallableKind.values());
028
029 public static final FlagField<ProtoBuf.Callable.MemberKind> MEMBER_KIND = FlagField.after(CALLABLE_KIND,
030 ProtoBuf.Callable.MemberKind.values());
031 public static final FlagField<Boolean> HAS_GETTER = FlagField.booleanAfter(MEMBER_KIND);
032 public static final FlagField<Boolean> HAS_SETTER = FlagField.booleanAfter(HAS_GETTER);
033
034 // Parameters
035
036 public static final FlagField<Boolean> DECLARES_DEFAULT_VALUE = FlagField.booleanAfter(HAS_ANNOTATIONS);
037
038 // Accessors
039
040 // It's important that this flag is negated: "is NOT default" instead of "is default"
041 public static final FlagField<Boolean> IS_NOT_DEFAULT = FlagField.booleanAfter(MODALITY);
042
043 // ---
044
045 private static <E> int bitWidth(@NotNull E[] enumEntries) {
046 int length = enumEntries.length - 1;
047 if (length == 0) return 1;
048 for (int i = 31; i >= 0; i--) {
049 if ((length & (1 << i)) != 0) return i + 1;
050 }
051 throw new IllegalStateException("Empty enum: " + enumEntries.getClass());
052 }
053
054 public static int getClassFlags(
055 boolean hasAnnotations,
056 Visibility visibility,
057 Modality modality,
058 ClassKind kind,
059 boolean inner
060 ) {
061 return HAS_ANNOTATIONS.toFlags(hasAnnotations)
062 | MODALITY.toFlags(modality(modality))
063 | VISIBILITY.toFlags(visibility(visibility))
064 | CLASS_KIND.toFlags(classKind(kind))
065 | INNER.toFlags(inner)
066 ;
067 }
068
069 private static ProtoBuf.Class.Kind classKind(ClassKind kind) {
070 switch (kind) {
071 case CLASS:
072 return ProtoBuf.Class.Kind.CLASS;
073 case TRAIT:
074 return ProtoBuf.Class.Kind.TRAIT;
075 case ENUM_CLASS:
076 return ProtoBuf.Class.Kind.ENUM_CLASS;
077 case ENUM_ENTRY:
078 return ProtoBuf.Class.Kind.ENUM_ENTRY;
079 case ANNOTATION_CLASS:
080 return ProtoBuf.Class.Kind.ANNOTATION_CLASS;
081 case OBJECT:
082 return ProtoBuf.Class.Kind.OBJECT;
083 case CLASS_OBJECT:
084 return ProtoBuf.Class.Kind.CLASS_OBJECT;
085 }
086 throw new IllegalArgumentException("Unknown class kind: " + kind);
087 }
088
089 public static int getCallableFlags(
090 boolean hasAnnotations,
091 @NotNull Visibility visibility,
092 @NotNull Modality modality,
093 @NotNull CallableMemberDescriptor.Kind memberKind,
094 @NotNull ProtoBuf.Callable.CallableKind callableKind,
095 boolean hasGetter,
096 boolean hasSetter
097 ) {
098 return HAS_ANNOTATIONS.toFlags(hasAnnotations)
099 | MODALITY.toFlags(modality(modality))
100 | VISIBILITY.toFlags(visibility(visibility))
101 | MEMBER_KIND.toFlags(memberKind(memberKind))
102 | CALLABLE_KIND.toFlags(callableKind)
103 | HAS_GETTER.toFlags(hasGetter)
104 | HAS_SETTER.toFlags(hasSetter)
105 ;
106 }
107
108 public static int getAccessorFlags(
109 boolean hasAnnotations,
110 @NotNull Visibility visibility,
111 @NotNull Modality modality,
112 boolean isNotDefault
113 ) {
114 return HAS_ANNOTATIONS.toFlags(hasAnnotations)
115 | MODALITY.toFlags(modality(modality))
116 | VISIBILITY.toFlags(visibility(visibility))
117 | IS_NOT_DEFAULT.toFlags(isNotDefault)
118 ;
119 }
120
121 @NotNull
122 private static ProtoBuf.Visibility visibility(@NotNull Visibility visibility) {
123 if (visibility == Visibilities.INTERNAL) {
124 return ProtoBuf.Visibility.INTERNAL;
125 }
126 else if (visibility == Visibilities.PUBLIC) {
127 return ProtoBuf.Visibility.PUBLIC;
128 }
129 else if (visibility == Visibilities.PRIVATE) {
130 return ProtoBuf.Visibility.PRIVATE;
131 }
132 else if (visibility == Visibilities.PROTECTED) {
133 return ProtoBuf.Visibility.PROTECTED;
134 }
135 return ProtoBuf.Visibility.EXTRA;
136 }
137
138 @NotNull
139 private static ProtoBuf.Modality modality(@NotNull Modality modality) {
140 switch (modality) {
141 case FINAL:
142 return ProtoBuf.Modality.FINAL;
143 case OPEN:
144 return ProtoBuf.Modality.OPEN;
145 case ABSTRACT:
146 return ProtoBuf.Modality.ABSTRACT;
147 }
148 throw new IllegalArgumentException("Unknown modality: " + modality);
149 }
150
151 @NotNull
152 private static ProtoBuf.Callable.MemberKind memberKind(@NotNull CallableMemberDescriptor.Kind kind) {
153 switch (kind) {
154 case DECLARATION:
155 return ProtoBuf.Callable.MemberKind.DECLARATION;
156 case FAKE_OVERRIDE:
157 return ProtoBuf.Callable.MemberKind.FAKE_OVERRIDE;
158 case DELEGATION:
159 return ProtoBuf.Callable.MemberKind.DELEGATION;
160 case SYNTHESIZED:
161 return ProtoBuf.Callable.MemberKind.SYNTHESIZED;
162 }
163 throw new IllegalArgumentException("Unknown member kind: " + kind);
164 }
165
166 public static int getValueParameterFlags(boolean hasAnnotations, boolean declaresDefaultValue) {
167 return HAS_ANNOTATIONS.toFlags(hasAnnotations)
168 | DECLARES_DEFAULT_VALUE.toFlags(declaresDefaultValue)
169 ;
170 }
171
172 // Infrastructure
173
174 public static abstract class FlagField<E> {
175 public static <E extends Internal.EnumLite> FlagField<E> after(FlagField<?> previousField, E[] values) {
176 int offset = previousField.offset + previousField.bitWidth;
177 return new EnumLiteFlagField<E>(offset, values);
178 }
179
180 public static <E extends Internal.EnumLite> FlagField<E> first(E[] values) {
181 return new EnumLiteFlagField<E>(0, values);
182 }
183
184 public static FlagField<Boolean> booleanFirst() {
185 return new BooleanFlagField(0);
186 }
187
188 public static FlagField<Boolean> booleanAfter(FlagField<?> previousField) {
189 int offset = previousField.offset + previousField.bitWidth;
190 return new BooleanFlagField(offset);
191 }
192
193 private final int offset;
194 private final int bitWidth;
195 private final E[] values;
196
197 private FlagField(int offset, E[] values) {
198 this.offset = offset;
199 this.bitWidth = bitWidth(values);
200 this.values = values;
201 }
202
203 public E get(int flags) {
204 int maskUnshifted = (1 << bitWidth) - 1;
205 int mask = maskUnshifted << offset;
206 int value = (flags & mask) >> offset;
207 return values[value];
208 }
209
210 public int toFlags(E value) {
211 return getIntValue(value) << offset;
212 }
213
214 protected abstract int getIntValue(E value);
215
216 }
217
218 private static class BooleanFlagField extends FlagField<Boolean> {
219 private static final Boolean[] BOOLEAN = { false, true };
220
221 public BooleanFlagField(int offset) {
222 super(offset, BOOLEAN);
223 }
224
225 @Override
226 protected int getIntValue(Boolean value) {
227 return value ? 1 : 0;
228 }
229 }
230
231 private static class EnumLiteFlagField<E extends Internal.EnumLite> extends FlagField<E> {
232 public EnumLiteFlagField(int offset, E[] values) {
233 super(offset, values);
234 }
235
236 @Override
237 protected int getIntValue(E value) {
238 return value.getNumber();
239 }
240 }
241
242 }