1/*
2 * [The "BSD licence"]
3 * Copyright (c) 2005-2008 Terence Parr
4 * All rights reserved.
5 *
6 * Conversion to C#:
7 * Copyright (c) 2008-2009 Sam Harwell, Pixel Mine, Inc.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. The name of the author may not be used to endorse or promote products
19 *    derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33namespace Antlr.Runtime {
34    using System.Collections.Generic;
35
36    using Array = System.Array;
37    using CLSCompliant = System.CLSCompliantAttribute;
38    using ICloneable = System.ICloneable;
39    using Math = System.Math;
40    using StringBuilder = System.Text.StringBuilder;
41
42    /** <summary>
43     *  A stripped-down version of org.antlr.misc.BitSet that is just
44     *  good enough to handle runtime requirements such as FOLLOW sets
45     *  for automatic error recovery.
46     *  </summary>
47     */
48    [System.Serializable]
49    public sealed class BitSet : ICloneable {
50        private const int BITS = 64;    // number of bits / long
51        private const int LOG_BITS = 6; // 2^6 == 64
52
53        /** <summary>
54         *  We will often need to do a mod operator (i mod nbits).  Its
55         *  turns out that, for powers of two, this mod operation is
56         *  same as (i & (nbits-1)).  Since mod is slow, we use a
57         *  precomputed mod mask to do the mod instead.
58         *  </summary>
59         */
60        private const int MOD_MASK = BITS - 1;
61
62        /** <summary>The actual data bits</summary> */
63        ulong[] _bits;
64
65        /** <summary>Construct a bitset of size one word (64 bits)</summary> */
66        public BitSet()
67            : this(BITS) {
68        }
69
70        /** <summary>Construction from a static array of longs</summary> */
71        public BitSet(ulong[] bits) {
72            _bits = bits;
73        }
74
75        /** <summary>Construction from a list of integers</summary> */
76        public BitSet(IEnumerable<int> items)
77            : this() {
78            foreach (int i in items)
79                Add(i);
80        }
81
82        /** <summary>Construct a bitset given the size</summary>
83         *  <param name="nbits">The size of the bitset in bits</param>
84         */
85        public BitSet(int nbits) {
86            _bits = new ulong[((nbits - 1) >> LOG_BITS) + 1];
87        }
88
89        public static BitSet Of(int el) {
90            BitSet s = new BitSet(el + 1);
91            s.Add(el);
92            return s;
93        }
94
95        public static BitSet Of(int a, int b) {
96            BitSet s = new BitSet(Math.Max(a, b) + 1);
97            s.Add(a);
98            s.Add(b);
99            return s;
100        }
101
102        public static BitSet Of(int a, int b, int c) {
103            BitSet s = new BitSet();
104            s.Add(a);
105            s.Add(b);
106            s.Add(c);
107            return s;
108        }
109
110        public static BitSet Of(int a, int b, int c, int d) {
111            BitSet s = new BitSet();
112            s.Add(a);
113            s.Add(b);
114            s.Add(c);
115            s.Add(d);
116            return s;
117        }
118
119        /** <summary>return this | a in a new set</summary> */
120        public BitSet Or(BitSet a) {
121            if (a == null) {
122                return this;
123            }
124            BitSet s = (BitSet)this.Clone();
125            s.OrInPlace(a);
126            return s;
127        }
128
129        /** <summary>or this element into this set (grow as necessary to accommodate)</summary> */
130        public void Add(int el) {
131            int n = WordNumber(el);
132            if (n >= _bits.Length) {
133                GrowToInclude(el);
134            }
135            _bits[n] |= BitMask(el);
136        }
137
138        /** <summary>Grows the set to a larger number of bits.</summary>
139         *  <param name="bit">element that must fit in set</param>
140         */
141        public void GrowToInclude(int bit) {
142            int newSize = Math.Max(_bits.Length << 1, NumWordsToHold(bit));
143            SetSize(newSize);
144        }
145
146        public void OrInPlace(BitSet a) {
147            if (a == null) {
148                return;
149            }
150            // If this is smaller than a, grow this first
151            if (a._bits.Length > _bits.Length) {
152                SetSize(a._bits.Length);
153            }
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        }
159
160        /** <summary>Sets the size of a set.</summary>
161         *  <param name="nwords">how many words the new set should be</param>
162         */
163        private void SetSize(int nwords) {
164            Array.Resize(ref _bits, nwords);
165        }
166
167        private static ulong BitMask(int bitNumber) {
168            int bitPosition = bitNumber & MOD_MASK; // bitNumber mod BITS
169            return 1UL << bitPosition;
170        }
171
172        public object Clone() {
173            return new BitSet((ulong[])_bits.Clone());
174        }
175
176        public int Size() {
177            int deg = 0;
178            for (int i = _bits.Length - 1; i >= 0; i--) {
179                ulong word = _bits[i];
180                if (word != 0L) {
181                    for (int bit = BITS - 1; bit >= 0; bit--) {
182                        if ((word & (1UL << bit)) != 0) {
183                            deg++;
184                        }
185                    }
186                }
187            }
188            return deg;
189        }
190
191        public override int GetHashCode() {
192            throw new System.NotImplementedException();
193        }
194
195        public override bool Equals(object other) {
196            if (other == null || !(other is BitSet)) {
197                return false;
198            }
199
200            BitSet otherSet = (BitSet)other;
201
202            int n = Math.Min(this._bits.Length, otherSet._bits.Length);
203
204            // for any bits in common, compare
205            for (int i = 0; i < n; i++) {
206                if (this._bits[i] != otherSet._bits[i]) {
207                    return false;
208                }
209            }
210
211            // make sure any extra bits are off
212
213            if (this._bits.Length > n) {
214                for (int i = n + 1; i < this._bits.Length; i++) {
215                    if (this._bits[i] != 0) {
216                        return false;
217                    }
218                }
219            } else if (otherSet._bits.Length > n) {
220                for (int i = n + 1; i < otherSet._bits.Length; i++) {
221                    if (otherSet._bits[i] != 0) {
222                        return false;
223                    }
224                }
225            }
226
227            return true;
228        }
229
230        public bool Member(int el) {
231            if (el < 0) {
232                return false;
233            }
234            int n = WordNumber(el);
235            if (n >= _bits.Length)
236                return false;
237            return (_bits[n] & BitMask(el)) != 0;
238        }
239
240        // remove this element from this set
241        public void Remove(int el) {
242            int n = WordNumber(el);
243            if (n < _bits.Length) {
244                _bits[n] &= ~BitMask(el);
245            }
246        }
247
248        public bool IsNil() {
249            for (int i = _bits.Length - 1; i >= 0; i--) {
250                if (_bits[i] != 0)
251                    return false;
252            }
253            return true;
254        }
255
256        private static int NumWordsToHold(int el) {
257            return (el >> LOG_BITS) + 1;
258        }
259
260        public int NumBits() {
261            return _bits.Length << LOG_BITS; // num words * bits per word
262        }
263
264        /** <summary>return how much space is being used by the bits array not how many actually have member bits on.</summary> */
265        public int LengthInLongWords() {
266            return _bits.Length;
267        }
268
269        /**Is this contained within a? */
270        /*
271        public boolean subset(BitSet a) {
272            if (a == null || !(a instanceof BitSet)) return false;
273            return this.and(a).equals(this);
274        }
275        */
276
277        public int[] ToArray() {
278            int[] elems = new int[Size()];
279            int en = 0;
280            for (int i = 0; i < (_bits.Length << LOG_BITS); i++) {
281                if (Member(i)) {
282                    elems[en++] = i;
283                }
284            }
285            return elems;
286        }
287
288        private static int WordNumber(int bit) {
289            return bit >> LOG_BITS; // bit / BITS
290        }
291
292        public override string ToString() {
293            return ToString(null);
294        }
295
296        public string ToString(string[] tokenNames) {
297            StringBuilder buf = new StringBuilder();
298            string separator = ",";
299            bool havePrintedAnElement = false;
300            buf.Append('{');
301
302            for (int i = 0; i < (_bits.Length << LOG_BITS); i++) {
303                if (Member(i)) {
304                    if (i > 0 && havePrintedAnElement) {
305                        buf.Append(separator);
306                    }
307                    if (tokenNames != null) {
308                        buf.Append(tokenNames[i]);
309                    } else {
310                        buf.Append(i);
311                    }
312                    havePrintedAnElement = true;
313                }
314            }
315            buf.Append('}');
316            return buf.ToString();
317        }
318    }
319}
320