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