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