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 
33 namespace 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> */
BitSet()66         public BitSet()
67             : this(BITS) {
68         }
69 
70         /** <summary>Construction from a static array of longs</summary> */
BitSet(ulong[] bits)71         public BitSet(ulong[] bits) {
72             _bits = bits;
73         }
74 
75         /** <summary>Construction from a list of integers</summary> */
BitSet(IEnumerable<int> items)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          */
BitSet(int nbits)85         public BitSet(int nbits) {
86             _bits = new ulong[((nbits - 1) >> LOG_BITS) + 1];
87         }
88 
Of(int el)89         public static BitSet Of(int el) {
90             BitSet s = new BitSet(el + 1);
91             s.Add(el);
92             return s;
93         }
94 
Of(int a, int b)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 
Of(int a, int b, int c)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 
Of(int a, int b, int c, int d)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> */
Or(BitSet a)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> */
Add(int el)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          */
GrowToInclude(int bit)141         public void GrowToInclude(int bit) {
142             int newSize = Math.Max(_bits.Length << 1, NumWordsToHold(bit));
143             SetSize(newSize);
144         }
145 
OrInPlace(BitSet a)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          */
SetSize(int nwords)163         private void SetSize(int nwords) {
164             Array.Resize(ref _bits, nwords);
165         }
166 
BitMask(int bitNumber)167         private static ulong BitMask(int bitNumber) {
168             int bitPosition = bitNumber & MOD_MASK; // bitNumber mod BITS
169             return 1UL << bitPosition;
170         }
171 
Clone()172         public object Clone() {
173             return new BitSet((ulong[])_bits.Clone());
174         }
175 
Size()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 
GetHashCode()191         public override int GetHashCode() {
192             throw new System.NotImplementedException();
193         }
194 
Equals(object other)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 
Member(int el)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
Remove(int el)241         public void Remove(int el) {
242             int n = WordNumber(el);
243             if (n < _bits.Length) {
244                 _bits[n] &= ~BitMask(el);
245             }
246         }
247 
IsNil()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 
NumWordsToHold(int el)256         private static int NumWordsToHold(int el) {
257             return (el >> LOG_BITS) + 1;
258         }
259 
NumBits()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> */
LengthInLongWords()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 
ToArray()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 
WordNumber(int bit)288         private static int WordNumber(int bit) {
289             return bit >> LOG_BITS; // bit / BITS
290         }
291 
ToString()292         public override string ToString() {
293             return ToString(null);
294         }
295 
ToString(string[] tokenNames)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