1 /* 2 * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.tools.javac.util; 27 28 import java.util.Arrays; 29 30 /** A class for extensible, mutable bit sets. 31 * 32 * <p><b>This is NOT part of any supported API. 33 * If you write code that depends on this, you do so at your own risk. 34 * This code and its internal interfaces are subject to change or 35 * deletion without notice.</b> 36 */ 37 public class Bits { 38 39 // ____________ reset _________ 40 // / UNKNOWN \ <-------- / UNINIT \ 41 // \____________/ | \_________/ 42 // | | | 43 // |assign | | any 44 // | ___________ | 45 // ------> / NORMAL \ <---- 46 // \___________/ | 47 // | | 48 // | | 49 // ----------- 50 // any 51 protected enum BitsState { 52 /* A Bits instance is in UNKNOWN state if it has been explicitly reset. 53 * It is possible to get to this state from any other by calling the 54 * reset method. An instance in the UNKNOWN state can pass to the 55 * NORMAL state after being assigned another Bits instance. 56 * 57 * Bits instances are final fields in Flow so the UNKNOWN state models 58 * the null assignment. 59 */ 60 UNKNOWN, 61 /* A Bits instance is in UNINIT when it is created with the default 62 * constructor but it isn't explicitly reset. The main objective of this 63 * internal state is to save some memory. 64 */ 65 UNINIT, 66 /* The normal state is reached after creating a Bits instance from an 67 * existing one or after applying any operation to an instance on UNINIT 68 * or NORMAL state. From this state a bits instance can pass to the 69 * UNKNOWN state by calling the reset method. 70 */ 71 NORMAL; 72 73 static BitsState getState(int[] someBits, boolean reset) { 74 if (reset) { 75 return UNKNOWN; 76 } else { 77 if (someBits != unassignedBits) { 78 return NORMAL; 79 } else { 80 return UNINIT; 81 } 82 } 83 } 84 85 } 86 87 private static final int wordlen = 32; 88 private static final int wordshift = 5; 89 private static final int wordmask = wordlen - 1; 90 91 /* every int in the bits array is used to represent 32 bits, so the bits array will have 92 * length == 1 until we need to represent the 33rd bit and so on. 93 */ 94 private int[] bits = null; 95 // This field will store last version of bits after every change. 96 private static final int[] unassignedBits = new int[0]; 97 98 protected BitsState currentState; 99 100 /** Construct an initially empty set. 101 */ 102 public Bits() { 103 this(false); 104 } 105 106 public Bits(Bits someBits) { 107 this(someBits.dup().bits, BitsState.getState(someBits.bits, false)); 108 } 109 110 public Bits(boolean reset) { 111 this(unassignedBits, BitsState.getState(unassignedBits, reset)); 112 } 113 114 /** Construct a set consisting initially of given bit vector. 115 */ 116 protected Bits(int[] bits, BitsState initState) { 117 this.bits = bits; 118 this.currentState = initState; 119 switch (initState) { 120 case UNKNOWN: 121 this.bits = null; 122 break; 123 case NORMAL: 124 Assert.check(bits != unassignedBits); 125 break; 126 } 127 } 128 129 protected void sizeTo(int len) { 130 if (bits.length < len) { 131 bits = Arrays.copyOf(bits, len); 132 } 133 } 134 135 /** This set = {}. 136 */ 137 public void clear() { 138 Assert.check(currentState != BitsState.UNKNOWN); 139 for (int i = 0; i < bits.length; i++) { 140 bits[i] = 0; 141 } 142 currentState = BitsState.NORMAL; 143 } 144 145 public void reset() { 146 internalReset(); 147 } 148 149 protected void internalReset() { 150 bits = null; 151 currentState = BitsState.UNKNOWN; 152 } 153 154 public boolean isReset() { 155 return currentState == BitsState.UNKNOWN; 156 } 157 158 public Bits assign(Bits someBits) { 159 bits = someBits.dup().bits; 160 currentState = BitsState.NORMAL; 161 return this; 162 } 163 164 /** Return a copy of this set. 165 */ 166 public Bits dup() { 167 Assert.check(currentState != BitsState.UNKNOWN); 168 Bits tmp = new Bits(); 169 tmp.bits = dupBits(); 170 currentState = BitsState.NORMAL; 171 return tmp; 172 } 173 174 protected int[] dupBits() { 175 int [] result; 176 if (currentState != BitsState.NORMAL) { 177 result = bits; 178 } else { 179 result = new int[bits.length]; 180 System.arraycopy(bits, 0, result, 0, bits.length); 181 } 182 return result; 183 } 184 185 /** Include x in this set. 186 */ 187 public void incl(int x) { 188 Assert.check(currentState != BitsState.UNKNOWN); 189 Assert.check(x >= 0); 190 sizeTo((x >>> wordshift) + 1); 191 bits[x >>> wordshift] = bits[x >>> wordshift] | 192 (1 << (x & wordmask)); 193 currentState = BitsState.NORMAL; 194 } 195 196 197 /** Include [start..limit) in this set. 198 */ 199 public void inclRange(int start, int limit) { 200 Assert.check(currentState != BitsState.UNKNOWN); 201 sizeTo((limit >>> wordshift) + 1); 202 for (int x = start; x < limit; x++) { 203 bits[x >>> wordshift] = bits[x >>> wordshift] | 204 (1 << (x & wordmask)); 205 } 206 currentState = BitsState.NORMAL; 207 } 208 209 /** Exclude [start...end] from this set. 210 */ 211 public void excludeFrom(int start) { 212 Assert.check(currentState != BitsState.UNKNOWN); 213 Bits temp = new Bits(); 214 temp.sizeTo(bits.length); 215 temp.inclRange(0, start); 216 internalAndSet(temp); 217 currentState = BitsState.NORMAL; 218 } 219 220 /** Exclude x from this set. 221 */ 222 public void excl(int x) { 223 Assert.check(currentState != BitsState.UNKNOWN); 224 Assert.check(x >= 0); 225 sizeTo((x >>> wordshift) + 1); 226 bits[x >>> wordshift] = bits[x >>> wordshift] & 227 ~(1 << (x & wordmask)); 228 currentState = BitsState.NORMAL; 229 } 230 231 /** Is x an element of this set? 232 */ 233 public boolean isMember(int x) { 234 Assert.check(currentState != BitsState.UNKNOWN); 235 return 236 0 <= x && x < (bits.length << wordshift) && 237 (bits[x >>> wordshift] & (1 << (x & wordmask))) != 0; 238 } 239 240 /** {@literal this set = this set & xs}. 241 */ 242 public Bits andSet(Bits xs) { 243 Assert.check(currentState != BitsState.UNKNOWN); 244 internalAndSet(xs); 245 currentState = BitsState.NORMAL; 246 return this; 247 } 248 249 protected void internalAndSet(Bits xs) { 250 Assert.check(currentState != BitsState.UNKNOWN); 251 sizeTo(xs.bits.length); 252 for (int i = 0; i < xs.bits.length; i++) { 253 bits[i] = bits[i] & xs.bits[i]; 254 } 255 } 256 257 /** this set = this set | xs. 258 */ 259 public Bits orSet(Bits xs) { 260 Assert.check(currentState != BitsState.UNKNOWN); 261 sizeTo(xs.bits.length); 262 for (int i = 0; i < xs.bits.length; i++) { 263 bits[i] = bits[i] | xs.bits[i]; 264 } 265 currentState = BitsState.NORMAL; 266 return this; 267 } 268 269 /** this set = this set \ xs. 270 */ 271 public Bits diffSet(Bits xs) { 272 Assert.check(currentState != BitsState.UNKNOWN); 273 for (int i = 0; i < bits.length; i++) { 274 if (i < xs.bits.length) { 275 bits[i] = bits[i] & ~xs.bits[i]; 276 } 277 } 278 currentState = BitsState.NORMAL; 279 return this; 280 } 281 282 /** this set = this set ^ xs. 283 */ 284 public Bits xorSet(Bits xs) { 285 Assert.check(currentState != BitsState.UNKNOWN); 286 sizeTo(xs.bits.length); 287 for (int i = 0; i < xs.bits.length; i++) { 288 bits[i] = bits[i] ^ xs.bits[i]; 289 } 290 currentState = BitsState.NORMAL; 291 return this; 292 } 293 294 /** Count trailing zero bits in an int. Algorithm from "Hacker's 295 * Delight" by Henry S. Warren Jr. (figure 5-13) 296 */ 297 private static int trailingZeroBits(int x) { 298 Assert.check(wordlen == 32); 299 if (x == 0) { 300 return 32; 301 } 302 int n = 1; 303 if ((x & 0xffff) == 0) { n += 16; x >>>= 16; } 304 if ((x & 0x00ff) == 0) { n += 8; x >>>= 8; } 305 if ((x & 0x000f) == 0) { n += 4; x >>>= 4; } 306 if ((x & 0x0003) == 0) { n += 2; x >>>= 2; } 307 return n - (x&1); 308 } 309 310 /** Return the index of the least bit position ≥ x that is set. 311 * If none are set, returns -1. This provides a nice way to iterate 312 * over the members of a bit set: 313 * <pre>{@code 314 * for (int i = bits.nextBit(0); i>=0; i = bits.nextBit(i+1)) ... 315 * }</pre> 316 */ 317 public int nextBit(int x) { 318 Assert.check(currentState != BitsState.UNKNOWN); 319 int windex = x >>> wordshift; 320 if (windex >= bits.length) { 321 return -1; 322 } 323 int word = bits[windex] & ~((1 << (x & wordmask))-1); 324 while (true) { 325 if (word != 0) { 326 return (windex << wordshift) + trailingZeroBits(word); 327 } 328 windex++; 329 if (windex >= bits.length) { 330 return -1; 331 } 332 word = bits[windex]; 333 } 334 } 335 336 /** a string representation of this set. 337 */ 338 @Override 339 public String toString() { 340 if (bits != null && bits.length > 0) { 341 char[] digits = new char[bits.length * wordlen]; 342 for (int i = 0; i < bits.length * wordlen; i++) { 343 digits[i] = isMember(i) ? '1' : '0'; 344 } 345 return new String(digits); 346 } else { 347 return "[]"; 348 } 349 } 350 351 }