1 /* 2 * [The "BSD license"] 3 * Copyright (c) 2010 Terence Parr 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 package org.antlr.misc; 29 30 import org.antlr.analysis.Label; 31 import org.antlr.tool.Grammar; 32 33 import java.util.Collection; 34 import java.util.Iterator; 35 import java.util.List; 36 import java.util.Map; 37 38 /**A BitSet to replace java.util.BitSet. 39 * 40 * Primary differences are that most set operators return new sets 41 * as opposed to oring and anding "in place". Further, a number of 42 * operations were added. I cannot contain a BitSet because there 43 * is no way to access the internal bits (which I need for speed) 44 * and, because it is final, I cannot subclass to add functionality. 45 * Consider defining set degree. Without access to the bits, I must 46 * call a method n times to test the ith bit...ack! 47 * 48 * Also seems like or() from util is wrong when size of incoming set is bigger 49 * than this.bits.length. 50 * 51 * @author Terence Parr 52 */ 53 public class BitSet implements IntSet, Cloneable { 54 protected final static int BITS = 64; // number of bits / long 55 protected final static int LOG_BITS = 6; // 2^6 == 64 56 57 /* We will often need to do a mod operator (i mod nbits). Its 58 * turns out that, for powers of two, this mod operation is 59 * same as (i & (nbits-1)). Since mod is slow, we use a 60 * precomputed mod mask to do the mod instead. 61 */ 62 protected final static int MOD_MASK = BITS - 1; 63 64 /** The actual data bits */ 65 protected long bits[]; 66 67 /** Construct a bitset of size one word (64 bits) */ BitSet()68 public BitSet() { 69 this(BITS); 70 } 71 72 /** Construction from a static array of longs */ BitSet(long[] bits_)73 public BitSet(long[] bits_) { 74 bits = bits_; 75 } 76 77 /** Construct a bitset given the size 78 * @param nbits The size of the bitset in bits 79 */ BitSet(int nbits)80 public BitSet(int nbits) { 81 bits = new long[((nbits - 1) >> LOG_BITS) + 1]; 82 } 83 84 /** or this element into this set (grow as necessary to accommodate) */ add(int el)85 public void add(int el) { 86 //System.out.println("add("+el+")"); 87 int n = wordNumber(el); 88 //System.out.println("word number is "+n); 89 //System.out.println("bits.length "+bits.length); 90 if (n >= bits.length) { 91 growToInclude(el); 92 } 93 bits[n] |= bitMask(el); 94 } 95 addAll(IntSet set)96 public void addAll(IntSet set) { 97 if ( set instanceof BitSet ) { 98 this.orInPlace((BitSet)set); 99 } 100 else if ( set instanceof IntervalSet ) { 101 IntervalSet other = (IntervalSet)set; 102 // walk set and add each interval 103 for (Iterator iter = other.intervals.iterator(); iter.hasNext();) { 104 Interval I = (Interval) iter.next(); 105 this.orInPlace(BitSet.range(I.a,I.b)); 106 } 107 } 108 else { 109 throw new IllegalArgumentException("can't add "+ 110 set.getClass().getName()+ 111 " to BitSet"); 112 } 113 } 114 addAll(int[] elements)115 public void addAll(int[] elements) { 116 if ( elements==null ) { 117 return; 118 } 119 for (int i = 0; i < elements.length; i++) { 120 int e = elements[i]; 121 add(e); 122 } 123 } 124 addAll(Iterable elements)125 public void addAll(Iterable elements) { 126 if ( elements==null ) { 127 return; 128 } 129 Iterator it = elements.iterator(); 130 while (it.hasNext()) { 131 Object o = (Object) it.next(); 132 if ( !(o instanceof Integer) ) { 133 throw new IllegalArgumentException(); 134 } 135 Integer eI = (Integer)o; 136 add(eI.intValue()); 137 } 138 /* 139 int n = elements.size(); 140 for (int i = 0; i < n; i++) { 141 Object o = elements.get(i); 142 if ( !(o instanceof Integer) ) { 143 throw new IllegalArgumentException(); 144 } 145 Integer eI = (Integer)o; 146 add(eI.intValue()); 147 } 148 */ 149 } 150 and(IntSet a)151 public IntSet and(IntSet a) { 152 BitSet s = (BitSet)this.clone(); 153 s.andInPlace((BitSet)a); 154 return s; 155 } 156 andInPlace(BitSet a)157 public void andInPlace(BitSet a) { 158 int min = Math.min(bits.length, a.bits.length); 159 for (int i = min - 1; i >= 0; i--) { 160 bits[i] &= a.bits[i]; 161 } 162 // clear all bits in this not present in a (if this bigger than a). 163 for (int i = min; i < bits.length; i++) { 164 bits[i] = 0; 165 } 166 } 167 bitMask(int bitNumber)168 private final static long bitMask(int bitNumber) { 169 int bitPosition = bitNumber & MOD_MASK; // bitNumber mod BITS 170 return 1L << bitPosition; 171 } 172 clear()173 public void clear() { 174 for (int i = bits.length - 1; i >= 0; i--) { 175 bits[i] = 0; 176 } 177 } 178 clear(int el)179 public void clear(int el) { 180 int n = wordNumber(el); 181 if (n >= bits.length) { // grow as necessary to accommodate 182 growToInclude(el); 183 } 184 bits[n] &= ~bitMask(el); 185 } 186 clone()187 public Object clone() { 188 BitSet s; 189 try { 190 s = (BitSet)super.clone(); 191 s.bits = new long[bits.length]; 192 System.arraycopy(bits, 0, s.bits, 0, bits.length); 193 } 194 catch (CloneNotSupportedException e) { 195 throw new InternalError(); 196 } 197 return s; 198 } 199 size()200 public int size() { 201 int deg = 0; 202 for (int i = bits.length - 1; i >= 0; i--) { 203 long word = bits[i]; 204 if (word != 0L) { 205 for (int bit = BITS - 1; bit >= 0; bit--) { 206 if ((word & (1L << bit)) != 0) { 207 deg++; 208 } 209 } 210 } 211 } 212 return deg; 213 } 214 equals(Object other)215 public boolean equals(Object other) { 216 if ( other == null || !(other instanceof BitSet) ) { 217 return false; 218 } 219 220 BitSet otherSet = (BitSet)other; 221 222 int n = Math.min(this.bits.length, otherSet.bits.length); 223 224 // for any bits in common, compare 225 for (int i=0; i<n; i++) { 226 if (this.bits[i] != otherSet.bits[i]) { 227 return false; 228 } 229 } 230 231 // make sure any extra bits are off 232 233 if (this.bits.length > n) { 234 for (int i = n+1; i<this.bits.length; i++) { 235 if (this.bits[i] != 0) { 236 return false; 237 } 238 } 239 } 240 else if (otherSet.bits.length > n) { 241 for (int i = n+1; i<otherSet.bits.length; i++) { 242 if (otherSet.bits[i] != 0) { 243 return false; 244 } 245 } 246 } 247 248 return true; 249 } 250 251 /** 252 * Grows the set to a larger number of bits. 253 * @param bit element that must fit in set 254 */ growToInclude(int bit)255 public void growToInclude(int bit) { 256 int newSize = Math.max(bits.length << 1, numWordsToHold(bit)); 257 long newbits[] = new long[newSize]; 258 System.arraycopy(bits, 0, newbits, 0, bits.length); 259 bits = newbits; 260 } 261 member(int el)262 public boolean member(int el) { 263 int n = wordNumber(el); 264 if (n >= bits.length) return false; 265 return (bits[n] & bitMask(el)) != 0; 266 } 267 268 /** Get the first element you find and return it. Return Label.INVALID 269 * otherwise. 270 */ getSingleElement()271 public int getSingleElement() { 272 for (int i = 0; i < (bits.length << LOG_BITS); i++) { 273 if (member(i)) { 274 return i; 275 } 276 } 277 return Label.INVALID; 278 } 279 isNil()280 public boolean isNil() { 281 for (int i = bits.length - 1; i >= 0; i--) { 282 if (bits[i] != 0) return false; 283 } 284 return true; 285 } 286 complement()287 public IntSet complement() { 288 BitSet s = (BitSet)this.clone(); 289 s.notInPlace(); 290 return s; 291 } 292 complement(IntSet set)293 public IntSet complement(IntSet set) { 294 if ( set==null ) { 295 return this.complement(); 296 } 297 return set.subtract(this); 298 } 299 notInPlace()300 public void notInPlace() { 301 for (int i = bits.length - 1; i >= 0; i--) { 302 bits[i] = ~bits[i]; 303 } 304 } 305 306 /** complement bits in the range 0..maxBit. */ notInPlace(int maxBit)307 public void notInPlace(int maxBit) { 308 notInPlace(0, maxBit); 309 } 310 311 /** complement bits in the range minBit..maxBit.*/ notInPlace(int minBit, int maxBit)312 public void notInPlace(int minBit, int maxBit) { 313 // make sure that we have room for maxBit 314 growToInclude(maxBit); 315 for (int i = minBit; i <= maxBit; i++) { 316 int n = wordNumber(i); 317 bits[n] ^= bitMask(i); 318 } 319 } 320 numWordsToHold(int el)321 private final int numWordsToHold(int el) { 322 return (el >> LOG_BITS) + 1; 323 } 324 of(int el)325 public static BitSet of(int el) { 326 BitSet s = new BitSet(el + 1); 327 s.add(el); 328 return s; 329 } 330 of(Collection elements)331 public static BitSet of(Collection elements) { 332 BitSet s = new BitSet(); 333 Iterator iter = elements.iterator(); 334 while (iter.hasNext()) { 335 Integer el = (Integer) iter.next(); 336 s.add(el.intValue()); 337 } 338 return s; 339 } 340 of(IntSet set)341 public static BitSet of(IntSet set) { 342 if ( set==null ) { 343 return null; 344 } 345 346 if ( set instanceof BitSet ) { 347 return (BitSet)set; 348 } 349 if ( set instanceof IntervalSet ) { 350 BitSet s = new BitSet(); 351 s.addAll(set); 352 return s; 353 } 354 throw new IllegalArgumentException("can't create BitSet from "+set.getClass().getName()); 355 } 356 of(Map elements)357 public static BitSet of(Map elements) { 358 return BitSet.of(elements.keySet()); 359 } 360 range(int a, int b)361 public static BitSet range(int a, int b) { 362 BitSet s = new BitSet(b + 1); 363 for (int i = a; i <= b; i++) { 364 int n = wordNumber(i); 365 s.bits[n] |= bitMask(i); 366 } 367 return s; 368 } 369 370 /** return this | a in a new set */ or(IntSet a)371 public IntSet or(IntSet a) { 372 if ( a==null ) { 373 return this; 374 } 375 BitSet s = (BitSet)this.clone(); 376 s.orInPlace((BitSet)a); 377 return s; 378 } 379 orInPlace(BitSet a)380 public void orInPlace(BitSet a) { 381 if ( a==null ) { 382 return; 383 } 384 // If this is smaller than a, grow this first 385 if (a.bits.length > bits.length) { 386 setSize(a.bits.length); 387 } 388 int min = Math.min(bits.length, a.bits.length); 389 for (int i = min - 1; i >= 0; i--) { 390 bits[i] |= a.bits[i]; 391 } 392 } 393 394 // remove this element from this set remove(int el)395 public void remove(int el) { 396 int n = wordNumber(el); 397 if (n >= bits.length) { 398 growToInclude(el); 399 } 400 bits[n] &= ~bitMask(el); 401 } 402 403 /** 404 * Sets the size of a set. 405 * @param nwords how many words the new set should be 406 */ setSize(int nwords)407 private void setSize(int nwords) { 408 long newbits[] = new long[nwords]; 409 int n = Math.min(nwords, bits.length); 410 System.arraycopy(bits, 0, newbits, 0, n); 411 bits = newbits; 412 } 413 numBits()414 public int numBits() { 415 return bits.length << LOG_BITS; // num words * bits per word 416 } 417 418 /** return how much space is being used by the bits array not 419 * how many actually have member bits on. 420 */ lengthInLongWords()421 public int lengthInLongWords() { 422 return bits.length; 423 } 424 425 /**Is this contained within a? */ subset(BitSet a)426 public boolean subset(BitSet a) { 427 if (a == null) return false; 428 return this.and(a).equals(this); 429 } 430 431 /**Subtract the elements of 'a' from 'this' in-place. 432 * Basically, just turn off all bits of 'this' that are in 'a'. 433 */ subtractInPlace(BitSet a)434 public void subtractInPlace(BitSet a) { 435 if (a == null) return; 436 // for all words of 'a', turn off corresponding bits of 'this' 437 for (int i = 0; i < bits.length && i < a.bits.length; i++) { 438 bits[i] &= ~a.bits[i]; 439 } 440 } 441 subtract(IntSet a)442 public IntSet subtract(IntSet a) { 443 if (a == null || !(a instanceof BitSet)) return null; 444 445 BitSet s = (BitSet)this.clone(); 446 s.subtractInPlace((BitSet)a); 447 return s; 448 } 449 toList()450 public List toList() { 451 throw new NoSuchMethodError("BitSet.toList() unimplemented"); 452 } 453 toArray()454 public int[] toArray() { 455 int[] elems = new int[size()]; 456 int en = 0; 457 for (int i = 0; i < (bits.length << LOG_BITS); i++) { 458 if (member(i)) { 459 elems[en++] = i; 460 } 461 } 462 return elems; 463 } 464 toPackedArray()465 public long[] toPackedArray() { 466 return bits; 467 } 468 toString()469 public String toString() { 470 return toString(null); 471 } 472 473 /** Transform a bit set into a string by formatting each element as an integer 474 * separator The string to put in between elements 475 * @return A commma-separated list of values 476 */ toString(Grammar g)477 public String toString(Grammar g) { 478 StringBuffer buf = new StringBuffer(); 479 String separator = ","; 480 boolean havePrintedAnElement = false; 481 buf.append('{'); 482 483 for (int i = 0; i < (bits.length << LOG_BITS); i++) { 484 if (member(i)) { 485 if (i > 0 && havePrintedAnElement ) { 486 buf.append(separator); 487 } 488 if ( g!=null ) { 489 buf.append(g.getTokenDisplayName(i)); 490 } 491 else { 492 buf.append(i); 493 } 494 havePrintedAnElement = true; 495 } 496 } 497 buf.append('}'); 498 return buf.toString(); 499 } 500 501 /**Create a string representation where instead of integer elements, the 502 * ith element of vocabulary is displayed instead. Vocabulary is a Vector 503 * of Strings. 504 * separator The string to put in between elements 505 * @return A commma-separated list of character constants. 506 */ toString(String separator, List vocabulary)507 public String toString(String separator, List vocabulary) { 508 if (vocabulary == null) { 509 return toString(null); 510 } 511 String str = ""; 512 for (int i = 0; i < (bits.length << LOG_BITS); i++) { 513 if (member(i)) { 514 if (str.length() > 0) { 515 str += separator; 516 } 517 if (i >= vocabulary.size()) { 518 str += "'" + (char)i + "'"; 519 } 520 else if (vocabulary.get(i) == null) { 521 str += "'" + (char)i + "'"; 522 } 523 else { 524 str += (String)vocabulary.get(i); 525 } 526 } 527 } 528 return str; 529 } 530 531 /** 532 * Dump a comma-separated list of the words making up the bit set. 533 * Split each 64 bit number into two more manageable 32 bit numbers. 534 * This generates a comma-separated list of C++-like unsigned long constants. 535 */ toStringOfHalfWords()536 public String toStringOfHalfWords() { 537 StringBuffer s = new StringBuffer(); 538 for (int i = 0; i < bits.length; i++) { 539 if (i != 0) s.append(", "); 540 long tmp = bits[i]; 541 tmp &= 0xFFFFFFFFL; 542 s.append(tmp); 543 s.append("UL"); 544 s.append(", "); 545 tmp = bits[i] >>> 32; 546 tmp &= 0xFFFFFFFFL; 547 s.append(tmp); 548 s.append("UL"); 549 } 550 return s.toString(); 551 } 552 553 /** 554 * Dump a comma-separated list of the words making up the bit set. 555 * This generates a comma-separated list of Java-like long int constants. 556 */ toStringOfWords()557 public String toStringOfWords() { 558 StringBuffer s = new StringBuffer(); 559 for (int i = 0; i < bits.length; i++) { 560 if (i != 0) s.append(", "); 561 s.append(bits[i]); 562 s.append("L"); 563 } 564 return s.toString(); 565 } 566 toStringWithRanges()567 public String toStringWithRanges() { 568 return toString(); 569 } 570 wordNumber(int bit)571 private final static int wordNumber(int bit) { 572 return bit >> LOG_BITS; // bit / BITS 573 } 574 } 575