1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.tools.metalava.model.api.surface 18 19 /** An API variant of [type] for [surface] */ 20 class ApiVariant( 21 /** The [ApiSurface] of which this is a variant. */ 22 val surface: ApiSurface, 23 24 /** The type of this variant. */ 25 val type: ApiVariantType, 26 27 /** 28 * The list of all [ApiVariant]s belonging to the owning [ApiSurfaces]. 29 * 30 * This must add itself to it. 31 */ 32 allVariants: MutableList<ApiVariant>, 33 ) { 34 /** 35 * Bit mask for this, used within [ApiVariantSet]. 36 * 37 * This must be unique across all [ApiVariant]s within `allVariants` so it computes the bit 38 * based on the current size of `allVariants` and then adds itself to the list ensuring that the 39 * next [ApiVariant] will use a different bit. 40 */ <lambda>null41 internal val bitMask: Int = 1 shl allVariants.size.also { allVariants.add(this) } 42 toStringnull43 override fun toString(): String { 44 return "${surface.name}(${type.name})" 45 } 46 } 47 48 /** 49 * The base set of [ApiVariant]s. 50 * 51 * Provides common query only functionality for [ApiVariantSet] and [MutableApiVariantSet]. 52 */ 53 sealed class BaseApiVariantSet(internal val apiSurfaces: ApiSurfaces) { 54 internal abstract val bits: Int 55 isEmptynull56 fun isEmpty() = bits == 0 57 58 fun isNotEmpty() = bits != 0 59 60 operator fun contains(variant: ApiVariant) = (bits and variant.bitMask) != 0 61 62 /** True if this set contains any of the variants from [surface]. */ 63 fun containsAny(surface: ApiSurface) = containsAny(surface.variantSet) 64 65 /** True if this set contains any of the variants from [variantSet]. */ 66 fun containsAny(variantSet: ApiVariantSet): Boolean { 67 require(apiSurfaces === variantSet.apiSurfaces) { 68 "Mismatch between ApiSurfaces, this set is for $apiSurfaces, other set is for ${variantSet.apiSurfaces}" 69 } 70 return (bits and variantSet.bits) != 0 71 } 72 73 /** 74 * Get a [MutableApiVariantSet] from this. 75 * 76 * This will return the object on which it is called if that is already mutable, otherwise it 77 * will create a separate mutable copy of this. 78 */ toMutablenull79 abstract fun toMutable(): MutableApiVariantSet 80 81 /** 82 * Get an immutable [ApiVariantSet] from this. 83 * 84 * This will return the object on which it is called if that is already immutable, otherwise it 85 * will create a separate immutable copy of this. 86 */ 87 abstract fun toImmutable(): ApiVariantSet 88 89 override fun equals(other: Any?): Boolean { 90 if (this === other) return true 91 if (other !is BaseApiVariantSet) return false 92 93 if (apiSurfaces != other.apiSurfaces) return false 94 if (bits != other.bits) return false 95 96 return true 97 } 98 hashCodenull99 override fun hashCode(): Int { 100 var result = apiSurfaces.hashCode() 101 result = 31 * result + bits 102 return result 103 } 104 toStringnull105 override fun toString(): String { 106 return buildString { 107 append("ApiVariantSet[") 108 var separator = "" 109 for (apiSurface in apiSurfaces.all) { 110 // If this set does not contain any variants from the ApiSurface then ignore it. 111 if (!this@BaseApiVariantSet.containsAny(apiSurface)) continue 112 append(separator) 113 separator = "," 114 append(apiSurface.name) 115 append("(") 116 for (variant in apiSurface.variants) { 117 if (variant in this@BaseApiVariantSet) append(variant.type.shortCode) 118 } 119 append(")") 120 } 121 append("]") 122 } 123 } 124 } 125 126 /** An immutable set of [ApiVariant]s. */ 127 class ApiVariantSet(apiSurfaces: ApiSurfaces, override val bits: Int) : 128 BaseApiVariantSet(apiSurfaces) { 129 toMutablenull130 override fun toMutable() = MutableApiVariantSet(apiSurfaces, bits) 131 132 override fun toImmutable() = this 133 134 companion object { 135 internal fun emptySet(apiSurfaces: ApiSurfaces) = ApiVariantSet(apiSurfaces, 0) 136 137 /** 138 * Build an [ApiVariantSet]. 139 * 140 * Creates a [MutableApiVariantSet], calls [lambda] to modify it and then calls 141 * [MutableApiVariantSet.toImmutable] to return an immutable [ApiVariantSet]. 142 * 143 * @param apiSurfaces the [ApiSurfaces] whose [ApiVariant]s it will contain. 144 * @param lambda the lambda that will be passed a [MutableApiVariantSet] to modify. 145 */ 146 fun build(apiSurfaces: ApiSurfaces, lambda: MutableApiVariantSet.() -> Unit) = 147 MutableApiVariantSet(apiSurfaces).apply(lambda).toImmutable() 148 } 149 } 150 151 /** A mutable set of [ApiVariant]s. */ 152 class MutableApiVariantSet 153 internal constructor(apiSurfaces: ApiSurfaces, override var bits: Int = 0) : 154 BaseApiVariantSet(apiSurfaces) { 155 toMutablenull156 override fun toMutable() = this 157 158 override fun toImmutable() = 159 if (bits == 0) apiSurfaces.emptyVariantSet else ApiVariantSet(apiSurfaces, bits) 160 161 /** 162 * Add [variant] to this set. 163 * 164 * This has no effect if it is already a member. 165 */ 166 fun add(variant: ApiVariant) { 167 bits = bits or variant.bitMask 168 } 169 170 /** 171 * Remove [variant] from this set. 172 * 173 * This has no effect if it was not a member. 174 */ removenull175 fun remove(variant: ApiVariant) { 176 bits = bits and variant.bitMask.inv() 177 } 178 179 /** Clear the set. */ clearnull180 fun clear() { 181 bits = 0 182 } 183 184 companion object { 185 186 /** Create a [MutableApiVariantSet] for [apiSurfaces]. */ setOfnull187 fun setOf(apiSurfaces: ApiSurfaces): MutableApiVariantSet { 188 // Make sure all the variant bits can fit into an Int. 189 if (apiSurfaces.variants.count() > 30) 190 error("Too many API variants to store in the set") 191 return MutableApiVariantSet(apiSurfaces, 0) 192 } 193 } 194 } 195