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{
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> */
68        public BitSet()
69            : this( BITS )
70        {
71        }
72
73        /** <summary>Construction from a static array of longs</summary> */
74        [CLSCompliant( false )]
75        public BitSet( ulong[] bits )
76        {
77            _bits = bits;
78        }
79
80        /** <summary>Construction from a list of integers</summary> */
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         */
91        public BitSet( int nbits )
92        {
93            _bits = new ulong[( ( nbits - 1 ) >> LOG_BITS ) + 1];
94        }
95
96        public static BitSet Of( int el )
97        {
98            BitSet s = new BitSet( el + 1 );
99            s.Add( el );
100            return s;
101        }
102
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
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
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> */
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> */
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         */
156        public void GrowToInclude( int bit )
157        {
158            int newSize = Math.Max( _bits.Length << 1, NumWordsToHold( bit ) );
159            SetSize(newSize);
160        }
161
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         */
183        private void SetSize( int nwords )
184        {
185            Array.Resize(ref _bits, nwords);
186        }
187
188        private static ulong BitMask( int bitNumber )
189        {
190            int bitPosition = bitNumber & MOD_MASK; // bitNumber mod BITS
191            return 1UL << bitPosition;
192        }
193
194        public object Clone()
195        {
196            return new BitSet( (ulong[])_bits.Clone() );
197        }
198
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
219        public override int GetHashCode()
220        {
221            throw new System.NotImplementedException();
222        }
223
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
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
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
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
302        private static int NumWordsToHold( int el )
303        {
304            return ( el >> LOG_BITS ) + 1;
305        }
306
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> */
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
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
340        private static int WordNumber( int bit )
341        {
342            return bit >> LOG_BITS; // bit / BITS
343        }
344
345        public override string ToString()
346        {
347            return ToString( null );
348        }
349
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