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 {
35     using System.Collections.Generic;
36 
37     using Array = System.Array;
38     using CLSCompliant = System.CLSCompliantAttribute;
39     using ICloneable = System.ICloneable;
40     using Math = System.Math;
41     using StringBuilder = System.Text.StringBuilder;
42 
43     /** <summary>
44      *  A stripped-down version of org.antlr.misc.BitSet that is just
45      *  good enough to handle runtime requirements such as FOLLOW sets
46      *  for automatic error recovery.
47      *  </summary>
48      */
49     [System.Serializable]
50     public sealed class BitSet : ICloneable
51     {
52         private const int BITS = 64;    // number of bits / long
53         private const int LOG_BITS = 6; // 2^6 == 64
54 
55         /** <summary>
56          *  We will often need to do a mod operator (i mod nbits).  Its
57          *  turns out that, for powers of two, this mod operation is
58          *  same as (i & (nbits-1)).  Since mod is slow, we use a
59          *  precomputed mod mask to do the mod instead.
60          *  </summary>
61          */
62         private const int MOD_MASK = BITS - 1;
63 
64         /** <summary>The actual data bits</summary> */
65         ulong[] _bits;
66 
67         /** <summary>Construct a bitset of size one word (64 bits)</summary> */
BitSet()68         public BitSet()
69             : this( BITS )
70         {
71         }
72 
73         /** <summary>Construction from a static array of longs</summary> */
74         [CLSCompliant( false )]
BitSet( ulong[] bits )75         public BitSet( ulong[] bits )
76         {
77             _bits = bits;
78         }
79 
80         /** <summary>Construction from a list of integers</summary> */
BitSet( IEnumerable<int> items )81         public BitSet( IEnumerable<int> items )
82             : this()
83         {
84             foreach ( int i in items )
85                 Add( i );
86         }
87 
88         /** <summary>Construct a bitset given the size</summary>
89          *  <param name="nbits">The size of the bitset in bits</param>
90          */
BitSet( int nbits )91         public BitSet( int nbits )
92         {
93             _bits = new ulong[( ( nbits - 1 ) >> LOG_BITS ) + 1];
94         }
95 
Of( int el )96         public static BitSet Of( int el )
97         {
98             BitSet s = new BitSet( el + 1 );
99             s.Add( el );
100             return s;
101         }
102 
Of( int a, int b )103         public static BitSet Of( int a, int b )
104         {
105             BitSet s = new BitSet( Math.Max( a, b ) + 1 );
106             s.Add( a );
107             s.Add( b );
108             return s;
109         }
110 
Of( int a, int b, int c )111         public static BitSet Of( int a, int b, int c )
112         {
113             BitSet s = new BitSet();
114             s.Add( a );
115             s.Add( b );
116             s.Add( c );
117             return s;
118         }
119 
Of( int a, int b, int c, int d )120         public static BitSet Of( int a, int b, int c, int d )
121         {
122             BitSet s = new BitSet();
123             s.Add( a );
124             s.Add( b );
125             s.Add( c );
126             s.Add( d );
127             return s;
128         }
129 
130         /** <summary>return this | a in a new set</summary> */
Or( BitSet a )131         public BitSet Or( BitSet a )
132         {
133             if ( a == null )
134             {
135                 return this;
136             }
137             BitSet s = (BitSet)this.Clone();
138             s.OrInPlace( a );
139             return s;
140         }
141 
142         /** <summary>or this element into this set (grow as necessary to accommodate)</summary> */
Add( int el )143         public void Add( int el )
144         {
145             int n = WordNumber( el );
146             if ( n >= _bits.Length )
147             {
148                 GrowToInclude( el );
149             }
150             _bits[n] |= BitMask( el );
151         }
152 
153         /** <summary>Grows the set to a larger number of bits.</summary>
154          *  <param name="bit">element that must fit in set</param>
155          */
GrowToInclude( int bit )156         public void GrowToInclude( int bit )
157         {
158             int newSize = Math.Max( _bits.Length << 1, NumWordsToHold( bit ) );
159             SetSize(newSize);
160         }
161 
OrInPlace( BitSet a )162         public void OrInPlace( BitSet a )
163         {
164             if ( a == null )
165             {
166                 return;
167             }
168             // If this is smaller than a, grow this first
169             if ( a._bits.Length > _bits.Length )
170             {
171                 SetSize( a._bits.Length );
172             }
173             int min = Math.Min( _bits.Length, a._bits.Length );
174             for ( int i = min - 1; i >= 0; i-- )
175             {
176                 _bits[i] |= a._bits[i];
177             }
178         }
179 
180         /** <summary>Sets the size of a set.</summary>
181          *  <param name="nwords">how many words the new set should be</param>
182          */
SetSize( int nwords )183         private void SetSize( int nwords )
184         {
185             Array.Resize(ref _bits, nwords);
186         }
187 
BitMask( int bitNumber )188         private static ulong BitMask( int bitNumber )
189         {
190             int bitPosition = bitNumber & MOD_MASK; // bitNumber mod BITS
191             return 1UL << bitPosition;
192         }
193 
Clone()194         public object Clone()
195         {
196             return new BitSet( (ulong[])_bits.Clone() );
197         }
198 
Size()199         public int Size()
200         {
201             int deg = 0;
202             for ( int i = _bits.Length - 1; i >= 0; i-- )
203             {
204                 ulong word = _bits[i];
205                 if ( word != 0L )
206                 {
207                     for ( int bit = BITS - 1; bit >= 0; bit-- )
208                     {
209                         if ( ( word & ( 1UL << bit ) ) != 0 )
210                         {
211                             deg++;
212                         }
213                     }
214                 }
215             }
216             return deg;
217         }
218 
GetHashCode()219         public override int GetHashCode()
220         {
221             throw new System.NotImplementedException();
222         }
223 
Equals( object other )224         public override bool Equals( object other )
225         {
226             if ( other == null || !( other is BitSet ) )
227             {
228                 return false;
229             }
230 
231             BitSet otherSet = (BitSet)other;
232 
233             int n = Math.Min( this._bits.Length, otherSet._bits.Length );
234 
235             // for any bits in common, compare
236             for ( int i = 0; i < n; i++ )
237             {
238                 if ( this._bits[i] != otherSet._bits[i] )
239                 {
240                     return false;
241                 }
242             }
243 
244             // make sure any extra bits are off
245 
246             if ( this._bits.Length > n )
247             {
248                 for ( int i = n + 1; i < this._bits.Length; i++ )
249                 {
250                     if ( this._bits[i] != 0 )
251                     {
252                         return false;
253                     }
254                 }
255             }
256             else if ( otherSet._bits.Length > n )
257             {
258                 for ( int i = n + 1; i < otherSet._bits.Length; i++ )
259                 {
260                     if ( otherSet._bits[i] != 0 )
261                     {
262                         return false;
263                     }
264                 }
265             }
266 
267             return true;
268         }
269 
Member( int el )270         public bool Member( int el )
271         {
272             if ( el < 0 )
273             {
274                 return false;
275             }
276             int n = WordNumber( el );
277             if ( n >= _bits.Length )
278                 return false;
279             return ( _bits[n] & BitMask( el ) ) != 0;
280         }
281 
282         // remove this element from this set
Remove( int el )283         public void Remove( int el )
284         {
285             int n = WordNumber( el );
286             if ( n < _bits.Length )
287             {
288                 _bits[n] &= ~BitMask( el );
289             }
290         }
291 
IsNil()292         public bool IsNil()
293         {
294             for ( int i = _bits.Length - 1; i >= 0; i-- )
295             {
296                 if ( _bits[i] != 0 )
297                     return false;
298             }
299             return true;
300         }
301 
NumWordsToHold( int el )302         private static int NumWordsToHold( int el )
303         {
304             return ( el >> LOG_BITS ) + 1;
305         }
306 
NumBits()307         public int NumBits()
308         {
309             return _bits.Length << LOG_BITS; // num words * bits per word
310         }
311 
312         /** <summary>return how much space is being used by the bits array not how many actually have member bits on.</summary> */
LengthInLongWords()313         public int LengthInLongWords()
314         {
315             return _bits.Length;
316         }
317 
318         /**Is this contained within a? */
319         /*
320         public boolean subset(BitSet a) {
321             if (a == null || !(a instanceof BitSet)) return false;
322             return this.and(a).equals(this);
323         }
324         */
325 
ToArray()326         public int[] ToArray()
327         {
328             int[] elems = new int[Size()];
329             int en = 0;
330             for ( int i = 0; i < ( _bits.Length << LOG_BITS ); i++ )
331             {
332                 if ( Member( i ) )
333                 {
334                     elems[en++] = i;
335                 }
336             }
337             return elems;
338         }
339 
WordNumber( int bit )340         private static int WordNumber( int bit )
341         {
342             return bit >> LOG_BITS; // bit / BITS
343         }
344 
ToString()345         public override string ToString()
346         {
347             return ToString( null );
348         }
349 
ToString( string[] tokenNames )350         public string ToString( string[] tokenNames )
351         {
352             StringBuilder buf = new StringBuilder();
353             string separator = ",";
354             bool havePrintedAnElement = false;
355             buf.Append( '{' );
356 
357             for ( int i = 0; i < ( _bits.Length << LOG_BITS ); i++ )
358             {
359                 if ( Member( i ) )
360                 {
361                     if ( i > 0 && havePrintedAnElement )
362                     {
363                         buf.Append( separator );
364                     }
365                     if ( tokenNames != null )
366                     {
367                         buf.Append( tokenNames[i] );
368                     }
369                     else
370                     {
371                         buf.Append( i );
372                     }
373                     havePrintedAnElement = true;
374                 }
375             }
376             buf.Append( '}' );
377             return buf.ToString();
378         }
379     }
380 }
381