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    }