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 */
28package org.antlr.misc;
29
30import org.antlr.analysis.Label;
31import org.antlr.tool.Grammar;
32
33import java.util.Collection;
34import java.util.Iterator;
35import java.util.List;
36import 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 */
53public 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) */
68    public BitSet() {
69        this(BITS);
70    }
71
72    /** Construction from a static array of longs */
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     */
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    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
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
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
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
151    public IntSet and(IntSet a) {
152        BitSet s = (BitSet)this.clone();
153        s.andInPlace((BitSet)a);
154        return s;
155    }
156
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
168    private final static long bitMask(int bitNumber) {
169        int bitPosition = bitNumber & MOD_MASK; // bitNumber mod BITS
170        return 1L << bitPosition;
171    }
172
173    public void clear() {
174        for (int i = bits.length - 1; i >= 0; i--) {
175            bits[i] = 0;
176        }
177    }
178
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
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
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
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     */
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
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    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
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
287    public IntSet complement() {
288        BitSet s = (BitSet)this.clone();
289        s.notInPlace();
290        return s;
291    }
292
293    public IntSet complement(IntSet set) {
294		if ( set==null ) {
295			return this.complement();
296		}
297        return set.subtract(this);
298    }
299
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. */
307    public void notInPlace(int maxBit) {
308        notInPlace(0, maxBit);
309    }
310
311    /** complement bits in the range minBit..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
321    private final int numWordsToHold(int el) {
322        return (el >> LOG_BITS) + 1;
323    }
324
325    public static BitSet of(int el) {
326        BitSet s = new BitSet(el + 1);
327        s.add(el);
328        return s;
329    }
330
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
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
357    public static BitSet of(Map elements) {
358        return BitSet.of(elements.keySet());
359    }
360
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 */
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
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
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     */
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
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     */
421    public int lengthInLongWords() {
422        return bits.length;
423    }
424
425    /**Is this contained within 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     */
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
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
450	public List toList() {
451		throw new NoSuchMethodError("BitSet.toList() unimplemented");
452	}
453
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
465    public long[] toPackedArray() {
466        return bits;
467    }
468
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     */
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     */
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     */
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     */
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
567    public String toStringWithRanges() {
568        return toString();
569    }
570
571    private final static int wordNumber(int bit) {
572        return bit >> LOG_BITS; // bit / BITS
573    }
574}
575