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) */ 85 @Override add(int el)86 public void add(int el) { 87 //System.out.println("add("+el+")"); 88 int n = wordNumber(el); 89 //System.out.println("word number is "+n); 90 //System.out.println("bits.length "+bits.length); 91 if (n >= bits.length) { 92 growToInclude(el); 93 } 94 bits[n] |= bitMask(el); 95 } 96 97 @Override addAll(IntSet set)98 public void addAll(IntSet set) { 99 if ( set instanceof BitSet ) { 100 this.orInPlace((BitSet)set); 101 } 102 else if ( set instanceof IntervalSet ) { 103 IntervalSet other = (IntervalSet)set; 104 // walk set and add each interval 105 for (Interval I : other.intervals) { 106 this.orInPlace(BitSet.range(I.a,I.b)); 107 } 108 } 109 else { 110 throw new IllegalArgumentException("can't add "+ 111 set.getClass().getName()+ 112 " to BitSet"); 113 } 114 } 115 addAll(int[] elements)116 public void addAll(int[] elements) { 117 if ( elements==null ) { 118 return; 119 } 120 for (int i = 0; i < elements.length; i++) { 121 int e = elements[i]; 122 add(e); 123 } 124 } 125 addAll(Iterable<Integer> elements)126 public void addAll(Iterable<Integer> elements) { 127 if ( elements==null ) { 128 return; 129 } 130 for (Integer element : elements) { 131 add(element); 132 } 133 /* 134 int n = elements.size(); 135 for (int i = 0; i < n; i++) { 136 Object o = elements.get(i); 137 if ( !(o instanceof Integer) ) { 138 throw new IllegalArgumentException(); 139 } 140 Integer eI = (Integer)o; 141 add(eI.intValue()); 142 } 143 */ 144 } 145 146 @Override and(IntSet a)147 public IntSet and(IntSet a) { 148 BitSet s = (BitSet)this.clone(); 149 s.andInPlace((BitSet)a); 150 return s; 151 } 152 andInPlace(BitSet a)153 public void andInPlace(BitSet a) { 154 int min = Math.min(bits.length, a.bits.length); 155 for (int i = min - 1; i >= 0; i--) { 156 bits[i] &= a.bits[i]; 157 } 158 // clear all bits in this not present in a (if this bigger than a). 159 for (int i = min; i < bits.length; i++) { 160 bits[i] = 0; 161 } 162 } 163 bitMask(int bitNumber)164 private static long bitMask(int bitNumber) { 165 int bitPosition = bitNumber & MOD_MASK; // bitNumber mod BITS 166 return 1L << bitPosition; 167 } 168 clear()169 public void clear() { 170 for (int i = bits.length - 1; i >= 0; i--) { 171 bits[i] = 0; 172 } 173 } 174 clear(int el)175 public void clear(int el) { 176 int n = wordNumber(el); 177 if (n >= bits.length) { // grow as necessary to accommodate 178 growToInclude(el); 179 } 180 bits[n] &= ~bitMask(el); 181 } 182 183 @Override clone()184 public Object clone() { 185 BitSet s; 186 try { 187 s = (BitSet)super.clone(); 188 s.bits = new long[bits.length]; 189 System.arraycopy(bits, 0, s.bits, 0, bits.length); 190 } 191 catch (CloneNotSupportedException e) { 192 throw new InternalError(); 193 } 194 return s; 195 } 196 197 @Override size()198 public int size() { 199 int deg = 0; 200 for (int i = bits.length - 1; i >= 0; i--) { 201 long word = bits[i]; 202 if (word != 0L) { 203 for (int bit = BITS - 1; bit >= 0; bit--) { 204 if ((word & (1L << bit)) != 0) { 205 deg++; 206 } 207 } 208 } 209 } 210 return deg; 211 } 212 213 @Override equals(Object other)214 public boolean equals(Object other) { 215 if ( other == null || !(other instanceof BitSet) ) { 216 return false; 217 } 218 219 BitSet otherSet = (BitSet)other; 220 221 int n = Math.min(this.bits.length, otherSet.bits.length); 222 223 // for any bits in common, compare 224 for (int i=0; i<n; i++) { 225 if (this.bits[i] != otherSet.bits[i]) { 226 return false; 227 } 228 } 229 230 // make sure any extra bits are off 231 232 if (this.bits.length > n) { 233 for (int i = n+1; i<this.bits.length; i++) { 234 if (this.bits[i] != 0) { 235 return false; 236 } 237 } 238 } 239 else if (otherSet.bits.length > n) { 240 for (int i = n+1; i<otherSet.bits.length; i++) { 241 if (otherSet.bits[i] != 0) { 242 return false; 243 } 244 } 245 } 246 247 return true; 248 } 249 250 /** 251 * Grows the set to a larger number of bits. 252 * @param bit element that must fit in set 253 */ growToInclude(int bit)254 public void growToInclude(int bit) { 255 int newSize = Math.max(bits.length << 1, numWordsToHold(bit)); 256 long newbits[] = new long[newSize]; 257 System.arraycopy(bits, 0, newbits, 0, bits.length); 258 bits = newbits; 259 } 260 261 @Override 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 */ 271 @Override getSingleElement()272 public int getSingleElement() { 273 for (int i = 0; i < (bits.length << LOG_BITS); i++) { 274 if (member(i)) { 275 return i; 276 } 277 } 278 return Label.INVALID; 279 } 280 281 @Override isNil()282 public boolean isNil() { 283 for (int i = bits.length - 1; i >= 0; i--) { 284 if (bits[i] != 0) return false; 285 } 286 return true; 287 } 288 complement()289 public IntSet complement() { 290 BitSet s = (BitSet)this.clone(); 291 s.notInPlace(); 292 return s; 293 } 294 295 @Override complement(IntSet set)296 public IntSet complement(IntSet set) { 297 if ( set==null ) { 298 return this.complement(); 299 } 300 return set.subtract(this); 301 } 302 notInPlace()303 public void notInPlace() { 304 for (int i = bits.length - 1; i >= 0; i--) { 305 bits[i] = ~bits[i]; 306 } 307 } 308 309 /** complement bits in the range 0..maxBit. */ notInPlace(int maxBit)310 public void notInPlace(int maxBit) { 311 notInPlace(0, maxBit); 312 } 313 314 /** complement bits in the range minBit..maxBit.*/ notInPlace(int minBit, int maxBit)315 public void notInPlace(int minBit, int maxBit) { 316 // make sure that we have room for maxBit 317 growToInclude(maxBit); 318 for (int i = minBit; i <= maxBit; i++) { 319 int n = wordNumber(i); 320 bits[n] ^= bitMask(i); 321 } 322 } 323 numWordsToHold(int el)324 private int numWordsToHold(int el) { 325 return (el >> LOG_BITS) + 1; 326 } 327 of(int el)328 public static BitSet of(int el) { 329 BitSet s = new BitSet(el + 1); 330 s.add(el); 331 return s; 332 } 333 of(Collection<? extends Integer> elements)334 public static BitSet of(Collection<? extends Integer> elements) { 335 BitSet s = new BitSet(); 336 for (Integer el : elements) { 337 s.add(el); 338 } 339 return s; 340 } 341 of(IntSet set)342 public static BitSet of(IntSet set) { 343 if ( set==null ) { 344 return null; 345 } 346 347 if ( set instanceof BitSet ) { 348 return (BitSet)set; 349 } 350 if ( set instanceof IntervalSet ) { 351 BitSet s = new BitSet(); 352 s.addAll(set); 353 return s; 354 } 355 throw new IllegalArgumentException("can't create BitSet from "+set.getClass().getName()); 356 } 357 of(Map<? extends Integer, ?> elements)358 public static BitSet of(Map<? extends Integer, ?> elements) { 359 return BitSet.of(elements.keySet()); 360 } 361 range(int a, int b)362 public static BitSet range(int a, int b) { 363 BitSet s = new BitSet(b + 1); 364 for (int i = a; i <= b; i++) { 365 int n = wordNumber(i); 366 s.bits[n] |= bitMask(i); 367 } 368 return s; 369 } 370 371 /** return this | a in a new set */ 372 @Override or(IntSet a)373 public IntSet or(IntSet a) { 374 if ( a==null ) { 375 return this; 376 } 377 BitSet s = (BitSet)this.clone(); 378 s.orInPlace((BitSet)a); 379 return s; 380 } 381 orInPlace(BitSet a)382 public void orInPlace(BitSet a) { 383 if ( a==null ) { 384 return; 385 } 386 // If this is smaller than a, grow this first 387 if (a.bits.length > bits.length) { 388 setSize(a.bits.length); 389 } 390 int min = Math.min(bits.length, a.bits.length); 391 for (int i = min - 1; i >= 0; i--) { 392 bits[i] |= a.bits[i]; 393 } 394 } 395 396 // remove this element from this set 397 @Override remove(int el)398 public void remove(int el) { 399 int n = wordNumber(el); 400 if (n >= bits.length) { 401 growToInclude(el); 402 } 403 bits[n] &= ~bitMask(el); 404 } 405 406 /** 407 * Sets the size of a set. 408 * @param nwords how many words the new set should be 409 */ setSize(int nwords)410 private void setSize(int nwords) { 411 long newbits[] = new long[nwords]; 412 int n = Math.min(nwords, bits.length); 413 System.arraycopy(bits, 0, newbits, 0, n); 414 bits = newbits; 415 } 416 numBits()417 public int numBits() { 418 return bits.length << LOG_BITS; // num words * bits per word 419 } 420 421 /** return how much space is being used by the bits array not 422 * how many actually have member bits on. 423 */ lengthInLongWords()424 public int lengthInLongWords() { 425 return bits.length; 426 } 427 428 /**Is this contained within a? */ subset(BitSet a)429 public boolean subset(BitSet a) { 430 if (a == null) return false; 431 return this.and(a).equals(this); 432 } 433 434 /**Subtract the elements of 'a' from 'this' in-place. 435 * Basically, just turn off all bits of 'this' that are in 'a'. 436 */ subtractInPlace(BitSet a)437 public void subtractInPlace(BitSet a) { 438 if (a == null) return; 439 // for all words of 'a', turn off corresponding bits of 'this' 440 for (int i = 0; i < bits.length && i < a.bits.length; i++) { 441 bits[i] &= ~a.bits[i]; 442 } 443 } 444 445 @Override subtract(IntSet a)446 public IntSet subtract(IntSet a) { 447 if (a == null || !(a instanceof BitSet)) return null; 448 449 BitSet s = (BitSet)this.clone(); 450 s.subtractInPlace((BitSet)a); 451 return s; 452 } 453 454 @Override toList()455 public List<Integer> toList() { 456 throw new NoSuchMethodError("BitSet.toList() unimplemented"); 457 } 458 toArray()459 public int[] toArray() { 460 int[] elems = new int[size()]; 461 int en = 0; 462 for (int i = 0; i < (bits.length << LOG_BITS); i++) { 463 if (member(i)) { 464 elems[en++] = i; 465 } 466 } 467 return elems; 468 } 469 toPackedArray()470 public long[] toPackedArray() { 471 return bits; 472 } 473 474 @Override toString()475 public String toString() { 476 return toString(null); 477 } 478 479 /** Transform a bit set into a string by formatting each element as an integer 480 * separator The string to put in between elements 481 * @return A commma-separated list of values 482 */ 483 @Override toString(Grammar g)484 public String toString(Grammar g) { 485 StringBuilder buf = new StringBuilder(); 486 String separator = ","; 487 boolean havePrintedAnElement = false; 488 buf.append('{'); 489 490 for (int i = 0; i < (bits.length << LOG_BITS); i++) { 491 if (member(i)) { 492 if (i > 0 && havePrintedAnElement ) { 493 buf.append(separator); 494 } 495 if ( g!=null ) { 496 buf.append(g.getTokenDisplayName(i)); 497 } 498 else { 499 buf.append(i); 500 } 501 havePrintedAnElement = true; 502 } 503 } 504 buf.append('}'); 505 return buf.toString(); 506 } 507 508 /**Create a string representation where instead of integer elements, the 509 * ith element of vocabulary is displayed instead. Vocabulary is a Vector 510 * of Strings. 511 * separator The string to put in between elements 512 * @return A commma-separated list of character constants. 513 */ toString(String separator, List<String> vocabulary)514 public String toString(String separator, List<String> vocabulary) { 515 if (vocabulary == null) { 516 return toString(null); 517 } 518 String str = ""; 519 for (int i = 0; i < (bits.length << LOG_BITS); i++) { 520 if (member(i)) { 521 if (str.length() > 0) { 522 str += separator; 523 } 524 if (i >= vocabulary.size()) { 525 str += "'" + (char)i + "'"; 526 } 527 else if (vocabulary.get(i) == null) { 528 str += "'" + (char)i + "'"; 529 } 530 else { 531 str += vocabulary.get(i); 532 } 533 } 534 } 535 return str; 536 } 537 538 /** 539 * Dump a comma-separated list of the words making up the bit set. 540 * Split each 64 bit number into two more manageable 32 bit numbers. 541 * This generates a comma-separated list of C++-like unsigned long constants. 542 */ toStringOfHalfWords()543 public String toStringOfHalfWords() { 544 StringBuilder s = new StringBuilder(); 545 for (int i = 0; i < bits.length; i++) { 546 if (i != 0) s.append(", "); 547 long tmp = bits[i]; 548 tmp &= 0xFFFFFFFFL; 549 s.append(tmp); 550 s.append("UL"); 551 s.append(", "); 552 tmp = bits[i] >>> 32; 553 tmp &= 0xFFFFFFFFL; 554 s.append(tmp); 555 s.append("UL"); 556 } 557 return s.toString(); 558 } 559 560 /** 561 * Dump a comma-separated list of the words making up the bit set. 562 * This generates a comma-separated list of Java-like long int constants. 563 */ toStringOfWords()564 public String toStringOfWords() { 565 StringBuilder s = new StringBuilder(); 566 for (int i = 0; i < bits.length; i++) { 567 if (i != 0) s.append(", "); 568 s.append(bits[i]); 569 s.append("L"); 570 } 571 return s.toString(); 572 } 573 toStringWithRanges()574 public String toStringWithRanges() { 575 return toString(); 576 } 577 wordNumber(int bit)578 private static int wordNumber(int bit) { 579 return bit >> LOG_BITS; // bit / BITS 580 } 581 } 582