• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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