• 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) */
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