Home | History | Annotate | Download | only in Antlr.Runtime
      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> */
     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