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                boolean isDefaultObject
078        ) {
079            return HAS_ANNOTATIONS.toFlags(hasAnnotations)
080                   | MODALITY.toFlags(modality(modality))
081                   | VISIBILITY.toFlags(visibility(visibility))
082                   | CLASS_KIND.toFlags(classKind(kind, isDefaultObject))
083                   | INNER.toFlags(inner)
084                   ;
085        }
086    
087        private static ProtoBuf.Class.Kind classKind(ClassKind kind, boolean isDefaultObject) {
088            if (isDefaultObject) return ProtoBuf.Class.Kind.CLASS_OBJECT;
089    
090            switch (kind) {
091                case CLASS:
092                    return ProtoBuf.Class.Kind.CLASS;
093                case TRAIT:
094                    return ProtoBuf.Class.Kind.TRAIT;
095                case ENUM_CLASS:
096                    return ProtoBuf.Class.Kind.ENUM_CLASS;
097                case ENUM_ENTRY:
098                    return ProtoBuf.Class.Kind.ENUM_ENTRY;
099                case ANNOTATION_CLASS:
100                    return ProtoBuf.Class.Kind.ANNOTATION_CLASS;
101                case OBJECT:
102                    return ProtoBuf.Class.Kind.OBJECT;
103            }
104            throw new IllegalArgumentException("Unknown class kind: " + kind);
105        }
106    
107        public static int getCallableFlags(
108                boolean hasAnnotations,
109                @NotNull Visibility visibility,
110                @NotNull Modality modality,
111                @NotNull CallableMemberDescriptor.Kind memberKind,
112                @NotNull ProtoBuf.Callable.CallableKind callableKind,
113                boolean hasGetter,
114                boolean hasSetter,
115                boolean hasConstant
116        ) {
117            return HAS_ANNOTATIONS.toFlags(hasAnnotations)
118                   | MODALITY.toFlags(modality(modality))
119                   | VISIBILITY.toFlags(visibility(visibility))
120                   | MEMBER_KIND.toFlags(memberKind(memberKind))
121                   | CALLABLE_KIND.toFlags(callableKind)
122                   | HAS_GETTER.toFlags(hasGetter)
123                   | HAS_SETTER.toFlags(hasSetter)
124                   | HAS_CONSTANT.toFlags(hasConstant)
125                   ;
126        }
127    
128        public static int getAccessorFlags(
129                boolean hasAnnotations,
130                @NotNull Visibility visibility,
131                @NotNull Modality modality,
132                boolean isNotDefault
133        ) {
134            return HAS_ANNOTATIONS.toFlags(hasAnnotations)
135                   | MODALITY.toFlags(modality(modality))
136                   | VISIBILITY.toFlags(visibility(visibility))
137                   | IS_NOT_DEFAULT.toFlags(isNotDefault)
138                   ;
139        }
140    
141        @NotNull
142        private static ProtoBuf.Visibility visibility(@NotNull Visibility visibility) {
143            if (visibility == Visibilities.INTERNAL) {
144                return ProtoBuf.Visibility.INTERNAL;
145            }
146            else if (visibility == Visibilities.PUBLIC) {
147                return ProtoBuf.Visibility.PUBLIC;
148            }
149            else if (visibility == Visibilities.PRIVATE) {
150                return ProtoBuf.Visibility.PRIVATE;
151            }
152            else if (visibility == Visibilities.PRIVATE_TO_THIS) {
153                return ProtoBuf.Visibility.PRIVATE_TO_THIS;
154            }
155            else if (visibility == Visibilities.PROTECTED) {
156                return ProtoBuf.Visibility.PROTECTED;
157            }
158            else if (visibility == Visibilities.LOCAL) {
159                return ProtoBuf.Visibility.LOCAL;
160            }
161            throw new IllegalArgumentException("Unknown visibility: " + visibility);
162        }
163    
164        @NotNull
165        private static ProtoBuf.Modality modality(@NotNull Modality modality) {
166            switch (modality) {
167                case FINAL:
168                    return ProtoBuf.Modality.FINAL;
169                case OPEN:
170                    return ProtoBuf.Modality.OPEN;
171                case ABSTRACT:
172                    return ProtoBuf.Modality.ABSTRACT;
173            }
174            throw new IllegalArgumentException("Unknown modality: " + modality);
175        }
176    
177        @NotNull
178        private static ProtoBuf.Callable.MemberKind memberKind(@NotNull CallableMemberDescriptor.Kind kind) {
179            switch (kind) {
180                case DECLARATION:
181                    return ProtoBuf.Callable.MemberKind.DECLARATION;
182                case FAKE_OVERRIDE:
183                    return ProtoBuf.Callable.MemberKind.FAKE_OVERRIDE;
184                case DELEGATION:
185                    return ProtoBuf.Callable.MemberKind.DELEGATION;
186                case SYNTHESIZED:
187                    return ProtoBuf.Callable.MemberKind.SYNTHESIZED;
188            }
189            throw new IllegalArgumentException("Unknown member kind: " + kind);
190        }
191    
192        public static int getValueParameterFlags(boolean hasAnnotations, boolean declaresDefaultValue) {
193            return HAS_ANNOTATIONS.toFlags(hasAnnotations)
194                   | DECLARES_DEFAULT_VALUE.toFlags(declaresDefaultValue)
195                   ;
196        }
197    
198        // Infrastructure
199    
200        public static abstract class FlagField<E> {
201            public static <E extends Internal.EnumLite> FlagField<E> after(FlagField<?> previousField, E[] values) {
202                int offset = previousField.offset + previousField.bitWidth;
203                return new EnumLiteFlagField<E>(offset, values);
204            }
205    
206            public static <E extends Internal.EnumLite> FlagField<E> first(E[] values) {
207                return new EnumLiteFlagField<E>(0, values);
208            }
209    
210            public static FlagField<Boolean> booleanFirst() {
211                return new BooleanFlagField(0);
212            }
213    
214            public static FlagField<Boolean> booleanAfter(FlagField<?> previousField) {
215                int offset = previousField.offset + previousField.bitWidth;
216                return new BooleanFlagField(offset);
217            }
218    
219            private final int offset;
220            private final int bitWidth;
221            private final E[] values;
222    
223            private FlagField(int offset, E[] values) {
224                this.offset = offset;
225                this.bitWidth = bitWidth(values);
226                this.values = values;
227            }
228    
229            public E get(int flags) {
230                int maskUnshifted = (1 << bitWidth) - 1;
231                int mask = maskUnshifted << offset;
232                int value = (flags & mask) >> offset;
233                for (E e : values) {
234                    if (getIntValue(e) == value) {
235                        return e;
236                    }
237                }
238                throw new IllegalStateException("Flag not found: " + value);
239            }
240    
241            public int toFlags(E value) {
242                return getIntValue(value) << offset;
243            }
244    
245            protected abstract int getIntValue(E value);
246    
247        }
248    
249        private static class BooleanFlagField extends FlagField<Boolean> {
250            private static final Boolean[] BOOLEAN = { false, true };
251    
252            public BooleanFlagField(int offset) {
253                super(offset, BOOLEAN);
254            }
255    
256            @Override
257            protected int getIntValue(Boolean value) {
258                return value ? 1 : 0;
259            }
260        }
261    
262        private static class EnumLiteFlagField<E extends Internal.EnumLite> extends FlagField<E> {
263            public EnumLiteFlagField(int offset, E[] values) {
264                super(offset, values);
265            }
266    
267            @Override
268            protected int getIntValue(E value) {
269                return value.getNumber();
270            }
271        }
272    
273    }