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 }