1	package antlr.collections.impl;
2	
3	import antlr.CharFormatter;
4	
5	/**A BitSet to replace java.util.BitSet.
6	 * Primary differences are that most set operators return new sets
7	 * as opposed to oring and anding "in place".  Further, a number of
8	 * operations were added.  I cannot contain a BitSet because there
9	 * is no way to access the internal bits (which I need for speed)
10	 * and, because it is final, I cannot subclass to add functionality.
11	 * Consider defining set degree.  Without access to the bits, I must
12	 * call a method n times to test the ith bit...ack!
13	 *
14	 * Also seems like or() from util is wrong when size of incoming set is bigger
15	 * than this.bits.length.
16	 *
17	 * @author Terence Parr, MageLang Institute
18	 * @author <br><a href="mailto:pete@yamuna.demon.co.uk">Pete Wells</a>
19	 */
20	public class BitSet implements Cloneable {
21		protected final static int BITS = 64;    // number of bits / long
22		protected final static int NIBBLE = 4;
23		protected final static int LOG_BITS = 6; // 2^6 == 64
24		/* We will often need to do a mod operator (i mod nbits).  Its turns out
25		 * that, for powers of two, this mod operation is same as (i & (nbits-1)).
26		 * Since mod is slow, we use a precomputed mod mask to do the mod instead.
27		 */
28		protected final static int MOD_MASK = BITS-1;
29		protected long bits[];
30	
31	
32		/** Construct a bitset of size one word (64 bits) */
33		public BitSet() {
34			this(BITS);
35		}
36		/** Construction from a static array of longs */
37		public BitSet(long[] bits_)
38		{
39			bits = bits_;
40		}
41		/** Construct a bitset given the size
42		 * @param nbits The size of the bitset in bits
43		 */
44		public BitSet(int nbits) {
45			bits = new long[((nbits-1) >> LOG_BITS) + 1];
46		}
47		// or this element into this set (grow as necessary to accommodate)
48		public void add(int el) {
49			//System.out.println("add("+el+")");
50			int n = wordNumber(el);
51			//System.out.println("word number is "+n);
52			//System.out.println("bits.length "+bits.length);
53			if (n >= bits.length) {
54				growToInclude(el);
55			}
56			bits[n] |= bitMask(el);
57		}
58		public BitSet and(BitSet a) {
59			BitSet s = (BitSet)this.clone();
60			s.andInPlace(a);
61			return s;
62		}
63		public void andInPlace(BitSet a) {
64			int min = Math.min(bits.length, a.bits.length);
65			for (int i = min-1; i >= 0; i--) {
66				bits[i] &= a.bits[i];
67			}
68			// clear all bits in this not present in a (if this bigger than a).
69			for (int i = min; i < bits.length ; i++) {
70				bits[i] = 0;
71			}
72		}
73		private final long bitMask(int bitNumber) {
74			int bitPosition = bitNumber&MOD_MASK; // bitNumber mod BITS
75			return 1L << bitPosition;
76		}
77		public void clear() {
78			for (int i = bits.length-1; i >= 0; i--) {
79				bits[i] = 0;
80			}
81		}
82		public void clear(int el) {
83			int n = wordNumber(el);
84			if (n >= bits.length) {	// grow as necessary to accommodate
85				growToInclude(el);
86			}
87			bits[n] &= ~bitMask(el);
88		}
89		public Object clone() {
90			BitSet s;
91			try {
92				s = (BitSet)super.clone();
93				s.bits = new long[bits.length];
94				System.arraycopy(bits, 0, s.bits, 0, bits.length);
95			}
96			catch (CloneNotSupportedException e) {
97				throw new InternalError();
98			}
99			return s;
100		}
101		public int degree() {
102			int deg = 0;
103			for (int i=bits.length-1; i>=0; i--) {
104				long word = bits[i];
105				if (word != 0L) {
106					for (int bit=BITS-1; bit>=0; bit--) {
107						if ( (word & (1L << bit)) != 0 ) {
108							deg++;
109						}
110					}
111				}
112			}
113			return deg;
114		}
115		// code "inherited" from java.util.BitSet
116		public boolean equals(Object obj) {
117			if ((obj != null) && (obj instanceof BitSet)) {
118				BitSet set = (BitSet)obj;
119	
120				int n = Math.min(bits.length, set.bits.length);
121				for (int i = n ; i-- > 0 ;) {
122				if (bits[i] != set.bits[i]) {
123					return false;
124				}
125				}
126				if (bits.length > n) {
127				for (int i = bits.length ; i-- > n ;) {
128					if (bits[i] != 0) {
129					return false;
130					}
131				}
132				} else if (set.bits.length > n) {
133				for (int i = set.bits.length ; i-- > n ;) {
134					if (set.bits[i] != 0) {
135					return false;
136					}
137				}
138				}
139				return true;
140			}
141			return false;
142		}
143		/** Find ranges in a set element array.
144		 * @param elems The array of elements representing the set, usually from Bit
145	Set.toArray().
146		 * @return Vector of ranges.
147		 */
148		public static Vector getRanges(int[] elems) {
149			if (elems.length==0) {
150				return null;
151			}
152			int begin = elems[0];
153			int end = elems[elems.length-1];
154			if ( elems.length<=2 ) {
155				// Not enough elements for a range expression
156				return null;
157			}
158	
159			Vector ranges = new Vector(5);
160			// look for ranges
161			for (int i=0; i<elems.length-2; i++) {
162				int lastInRange;
163				lastInRange = elems.length-1;
164				for (int j=i+1; j<elems.length; j++) {
165					if ( elems[j] != elems[j-1]+1 ) {
166						lastInRange = j-1;
167						break;
168					}
169				}
170				// found a range
171				if ( lastInRange-i > 2 ) {
172					ranges.appendElement(new IntRange(elems[i],elems[lastInRange]));
173				}
174			}
175			return ranges;
176		}
177		/**
178		 * Grows the set to a larger number of bits.
179		 * @param bit element that must fit in set
180		 */
181		public void growToInclude(int bit) {
182			int newSize = Math.max(bits.length<<1, numWordsToHold(bit));
183			long newbits[] = new long[newSize];
184			System.arraycopy(bits, 0, newbits, 0, bits.length);
185			bits = newbits;
186		}
187		public boolean member(int el) {
188			int n = wordNumber(el);
189			if (n > bits.length) return false;
190			return (bits[n] & bitMask(el)) != 0;
191		}
192		public boolean nil() {
193			for (int i=bits.length-1; i>=0; i--) {
194				if ( bits[i]!=0 ) return false;
195			}
196			return true;
197		}
198		public BitSet not() {
199			BitSet s = (BitSet)this.clone();
200			s.notInPlace();
201			return s;
202		}
203		public void notInPlace() {
204			for (int i = bits.length-1; i >= 0; i--) {
205				bits[i] = ~bits[i];
206			}
207		}
208		/** complement bits in the range 0..maxBit. */
209		public void notInPlace(int maxBit) {
210			notInPlace(0, maxBit);
211		}
212		/** complement bits in the range minBit..maxBit.*/
213		public void notInPlace(int minBit, int maxBit) {
214			// make sure that we have room for maxBit
215			growToInclude(maxBit);
216			for (int i = minBit; i <= maxBit; i++) {
217				int n = wordNumber(i);
218				bits[n] ^= bitMask(i);
219			}
220		}
221		private final int numWordsToHold(int el) {
222			return (el>>LOG_BITS) + 1;
223		}
224		public static BitSet of(int el) {
225			BitSet s = new BitSet(el+1);
226			s.add(el);
227			return s;
228		}
229		/** return this | a in a new set */
230		public BitSet or(BitSet a) {
231			BitSet s = (BitSet)this.clone();
232			s.orInPlace(a);
233			return s;
234		}
235		public void orInPlace(BitSet a) {
236			// If this is smaller than a, grow this first
237			if ( a.bits.length > bits.length ) {
238				setSize(a.bits.length);
239			}
240			int min = Math.min(bits.length, a.bits.length);
241			for (int i = min-1; i >= 0; i--) {
242				bits[i] |= a.bits[i];
243			}
244		}
245		// remove this element from this set (grow as necessary to accommodate)
246		public void remove(int el) {
247			int n = wordNumber(el);
248			if (n >= bits.length) {
249				growToInclude(el);
250			}
251			bits[n] &= ~bitMask(el);
252		}
253		/**
254		 * Sets the size of a set.
255		 * @param nwords how many words the new set should be
256		 */
257		private void setSize(int nwords) {
258			long newbits[] = new long[nwords];
259			int n = Math.min(nwords, bits.length);
260			System.arraycopy(bits, 0, newbits, 0, n);
261			bits = newbits;
262		}
263		public int size() {
264			return bits.length << LOG_BITS; // num words * bits per word
265		}
266		/**Is this contained within a? */
267		public boolean subset(BitSet a) {
268			if ( a==null || !(a instanceof BitSet) ) return false;
269			return this.and(a).equals(this);
270		}
271		/**Subtract the elements of 'a' from 'this' in-place.
272		 * Basically, just turn off all bits of 'this' that are in 'a'.
273		 */
274		public void subtractInPlace(BitSet a) {
275			if ( a==null ) return;
276			// for all words of 'a', turn off corresponding bits of 'this'
277			for (int i = 0; i<bits.length&&i<a.bits.length; i++) {
278				bits[i] &= ~a.bits[i];
279			}
280		}
281		public int[] toArray() {
282			int[] elems = new int[degree()];
283			int en = 0;
284			for (int i = 0; i < (bits.length << LOG_BITS); i++) {
285				if (member(i)) {
286					elems[en++] = i;
287				}
288			}
289			return elems;
290		}
291		public String toString() {
292			return toString(",");
293		}
294		/** Transform a bit set into a string by formatting each element as an integer
295		 * @separator The string to put in between elements
296		 * @return A commma-separated list of values
297		 */
298		public String toString(String separator) {
299			String str = "";
300			for (int i = 0; i < (bits.length << LOG_BITS); i++) {
301				if (member(i)) {
302					if (str.length() > 0) {
303						str += separator;
304					}
305					str = str + i;
306				}
307			}
308			return str;
309		}
310		/** Transform a bit set into a string of characters.
311		 * @separator The string to put in between elements
312		 * @param formatter An object implementing the CharFormatter interface.
313		 * @return A commma-separated list of character constants.
314		 */
315		public String toString(String separator, CharFormatter formatter) {
316			String str = "";
317	
318			for (int i = 0; i < (bits.length << LOG_BITS); i++) {
319				if (member(i)) {
320					if (str.length() > 0) {
321						str += separator;
322					}
323					str = str + formatter.literalChar(i);
324				}
325			}
326			return str;
327		}
328		/**Create a string representation where instead of integer elements, the
329		 * ith element of vocabulary is displayed instead.  Vocabulary is a Vector
330		 * of Strings.
331		 * @separator The string to put in between elements
332		 * @return A commma-separated list of character constants.
333		 */
334		public String toString(String separator, Vector vocabulary) {
335			if ( vocabulary == null ) {
336				return toString(separator);
337			}
338			String str = "";
339			for (int i = 0; i < (bits.length << LOG_BITS); i++) {
340				if (member(i)) {
341					if (str.length() > 0) {
342						str += separator;
343					}
344					if ( i>=vocabulary.size() ) {
345						str += "<bad element "+i+">";
346					}
347					else if ( vocabulary.elementAt(i)==null ) {
348						str += "<"+i+">";
349					}
350					else {
351						str += (String)vocabulary.elementAt(i);
352					}
353				}
354			}
355			return str;
356		}
357		/**
358		 * Dump a comma-separated list of the words making up the bit set.
359		 * Split each 64 bit number into two more manageable 32 bit numbers.
360		 * This generates a comma-separated list of C++-like unsigned long constants.
361		 */
362		public String toStringOfHalfWords()
363		{
364			String s = new String();
365			for (int i = 0; i < bits.length; i++)
366			{
367				if (i!=0) s += ", ";
368				long tmp = bits[i];
369				tmp &= 0xFFFFFFFFL;
370				s += (tmp + "UL");
371				s += ", ";
372				tmp = bits[i]>>>32;
373				tmp &= 0xFFFFFFFFL;
374				s += (tmp + "UL");
375			}
376			return s;
377		}
378		/** 
379		 * Dump a comma-separated list of the words making up the bit set.
380		 * This generates a comma-separated list of Java-like long int constants.
381		 */
382		public String toStringOfWords()
383		{
384			String s = new String();
385			for (int i = 0; i < bits.length; i++)
386			{
387				if (i!=0) s += ", ";
388				s += (bits[i] + "L");
389			}
390			return s;
391		}
392		/** Print out the bit set but collapse char ranges.
393		 */
394		public String toStringWithRanges(String separator, CharFormatter formatter) {
395			String str = "";
396			int[] elems = this.toArray();
397			if (elems.length==0) {
398				return "";
399			}
400			// look for ranges
401			int i=0;
402			while (i<elems.length) {
403				int lastInRange;
404				lastInRange = 0;
405				for (int j=i+1; j<elems.length; j++) {
406					if ( elems[j] != elems[j-1]+1 ) {
407						break;
408					}
409					lastInRange = j;
410				}
411				// found a range
412				if (str.length() > 0) {
413					str += separator;
414				}
415				if ( lastInRange-i >= 2 ) {
416					str += formatter.literalChar(elems[i]);
417					str += "..";
418					str += formatter.literalChar(elems[lastInRange]);
419					i = lastInRange;	// skip past end of range for next range
420				}
421				else {	// no range, just print current char and move on
422					str += formatter.literalChar(elems[i]);
423				}
424				i++;
425			}
426			return str;
427		}
428		private final int wordNumber(int bit) {
429			return bit>>LOG_BITS; // bit / BITS
430		}
431	}
432