1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Licensed to the Apache Software Foundation (ASF) under one or more
   7  * contributor license agreements.  See the NOTICE file distributed with
   8  * this work for additional information regarding copyright ownership.
   9  * The ASF licenses this file to You under the Apache License, Version 2.0
  10  * (the "License"); you may not use this file except in compliance with
  11  * the License.  You may obtain a copy of the License at
  12  *
  13  *      http://www.apache.org/licenses/LICENSE-2.0
  14  *
  15  * Unless required by applicable law or agreed to in writing, software
  16  * distributed under the License is distributed on an "AS IS" BASIS,
  17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18  * See the License for the specific language governing permissions and
  19  * limitations under the License.
  20  */
  21 
  22 package com.sun.org.apache.xalan.internal.xsltc.dom;
  23 
  24 import java.io.Externalizable;
  25 import java.io.IOException;
  26 import java.io.ObjectInput;
  27 import java.io.ObjectOutput;
  28 
  29 import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
  30 
  31 
  32 /**
  33  * @author Morten Jorgensen
  34  */
  35 public class BitArray implements Externalizable {
  36     static final long serialVersionUID = -4876019880708377663L;
  37 
  38     private int[] _bits;
  39     private int   _bitSize;
  40     private int   _intSize;
  41     private int   _mask;
  42 
  43     // This table is used to prevent expensive shift operations
  44     // (These operations are inexpensive on CPUs but very expensive on JVMs.)
  45     private final static int[] _masks = {
  46         0x80000000, 0x40000000, 0x20000000, 0x10000000,
  47         0x08000000, 0x04000000, 0x02000000, 0x01000000,
  48         0x00800000, 0x00400000, 0x00200000, 0x00100000,
  49         0x00080000, 0x00040000, 0x00020000, 0x00010000,
  50         0x00008000, 0x00004000, 0x00002000, 0x00001000,
  51         0x00000800, 0x00000400, 0x00000200, 0x00000100,
  52         0x00000080, 0x00000040, 0x00000020, 0x00000010,
  53         0x00000008, 0x00000004, 0x00000002, 0x00000001 };
  54 
  55     private final static boolean DEBUG_ASSERTIONS = false;
  56 
  57     /**
  58      * Constructor. Defines the initial size of the bit array (in bits).
  59      */
  60     public BitArray() {
  61         this(32);
  62     }
  63 
  64     public BitArray(int size) {
  65         if (size < 32) size = 32;
  66         _bitSize = size;
  67         _intSize = (_bitSize >>> 5) + 1;
  68         _bits = new int[_intSize + 1];
  69     }
  70 
  71     public BitArray(int size, int[] bits) {
  72         if (size < 32) size = 32;
  73         _bitSize = size;
  74         _intSize = (_bitSize >>> 5) + 1;
  75         _bits = bits;
  76     }
  77 
  78     /**
  79      * Set the mask for this bit array. The upper 8 bits of this mask
  80      * indicate the DOM in which the nodes in this array belong.
  81      */
  82     public void setMask(int mask) {
  83         _mask = mask;
  84     }
  85 
  86     /**
  87      * See setMask()
  88      */
  89     public int getMask() {
  90         return(_mask);
  91     }
  92 
  93     /**
  94      * Returns the size of this bit array (in bits).
  95      */
  96     public final int size() {
  97         return(_bitSize);
  98     }
  99 
 100     /**
 101      * Returns true if the given bit is set
 102      */
 103     public final boolean getBit(int bit) {
 104         if (DEBUG_ASSERTIONS) {
 105             if (bit >= _bitSize) {
 106                 throw new Error(
 107                              "Programmer's assertion in  BitArray.getBit");
 108             }
 109         }
 110 
 111         return((_bits[bit>>>5] & _masks[bit%32]) != 0);
 112     }
 113 
 114     /**
 115      * Returns the next set bit from a given position
 116      */
 117     public final int getNextBit(int startBit) {
 118         for (int i = (startBit >>> 5) ; i<=_intSize; i++) {
 119             int bits = _bits[i];
 120             if (bits != 0) {
 121                 for (int b = (startBit % 32); b<32; b++) {
 122                     if ((bits & _masks[b]) != 0) {
 123                         return((i << 5) + b);
 124                     }
 125                 }
 126             }
 127             startBit = 0;
 128         }
 129         return(DTMAxisIterator.END);
 130     }
 131 
 132     /**
 133      * This method returns the Nth bit that is set in the bit array. The
 134      * current position is cached in the following 4 variables and will
 135      * help speed up a sequence of next() call in an index iterator. This
 136      * method is a mess, but it is fast and it works, so don't fuck with it.
 137      */
 138     private int _pos = Integer.MAX_VALUE;
 139     private int _node = 0;
 140     private int _int = 0;
 141     private int _bit = 0;
 142 
 143     public final int getBitNumber(int pos) {
 144 
 145         // Return last node if position we're looking for is the same
 146         if (pos == _pos) return(_node);
 147 
 148         // Start from beginning of position we're looking for is before
 149         // the point where we left off the last time.
 150         if (pos < _pos) {
 151             _int = _bit = _pos = 0;
 152         }
 153 
 154         // Scan through the bit array - skip integers that have no bits set
 155         for ( ; _int <= _intSize; _int++) {
 156             int bits = _bits[_int];
 157             if (bits != 0) { // Any bits set?
 158                 for ( ; _bit < 32; _bit++) {
 159                     if ((bits & _masks[_bit]) != 0) {
 160                         if (++_pos == pos) {
 161                             _node = ((_int << 5) + _bit) - 1;
 162                             return (_node);
 163                         }
 164                     }
 165                 }
 166                 _bit = 0;
 167             }
 168         }
 169         return(0);
 170     }
 171 
 172     /**
 173      * Returns the integer array in which the bit array is contained
 174      */
 175     public final int[] data() {
 176         return(_bits);
 177     }
 178 
 179     int _first = Integer.MAX_VALUE; // The index where first set bit is
 180     int _last  = Integer.MIN_VALUE; // The _INTEGER INDEX_ where last set bit is
 181 
 182     /**
 183      * Sets a given bit
 184      */
 185     public final void setBit(int bit) {
 186         if (DEBUG_ASSERTIONS) {
 187             if (bit >= _bitSize) {
 188                 throw new Error(
 189                              "Programmer's assertion in  BitArray.getBit");
 190             }
 191         }
 192 
 193         if (bit >= _bitSize) return;
 194         final int i = (bit >>> 5);
 195         if (i < _first) _first = i;
 196         if (i > _last) _last = i;
 197         _bits[i] |= _masks[bit % 32];
 198     }
 199 
 200     /**
 201      * Merge two bit arrays. This currently only works for nodes from
 202      * a single DOM (because there is only one _mask per array).
 203      */
 204     public final BitArray merge(BitArray other) {
 205         // Take other array's bits if we have node set
 206         if (_last == -1) {
 207             _bits = other._bits;
 208         }
 209         // Only merge if other array has any bits set
 210         else if (other._last != -1) {
 211             int start = (_first < other._first) ? _first : other._first;
 212             int stop  = (_last > other._last) ? _last : other._last;
 213 
 214             // Merge these bits into other array if other array is larger
 215             if (other._intSize > _intSize) {
 216                 if (stop > _intSize) stop = _intSize;
 217                 for (int i=start; i<=stop; i++)
 218                     other._bits[i] |= _bits[i];
 219                 _bits = other._bits;
 220             }
 221             // Merge other bits into this array if this arrai is large/equal.
 222             else {
 223                 if (stop > other._intSize) stop = other._intSize;
 224                 for (int i=start; i<=stop; i++)
 225                     _bits[i] |= other._bits[i];
 226             }
 227         }
 228         return(this);
 229     }
 230 
 231     /**
 232      * Resizes the bit array - try to avoid using this method!!!
 233      */
 234     public final void resize(int newSize) {
 235         if (newSize > _bitSize) {
 236             _intSize = (newSize >>> 5) + 1;
 237             final int[] newBits = new int[_intSize + 1];
 238             System.arraycopy(_bits, 0, newBits, 0, (_bitSize>>>5) + 1);
 239             _bits = newBits;
 240             _bitSize = newSize;
 241         }
 242     }
 243 
 244     public BitArray cloneArray() {
 245         return(new BitArray(_intSize, _bits));
 246     }
 247 
 248     public void writeExternal(ObjectOutput out) throws IOException {
 249         out.writeInt(_bitSize);
 250         out.writeInt(_mask);
 251         out.writeObject(_bits);
 252         out.flush();
 253     }
 254 
 255     /**
 256      * Read the whole tree from a file (serialized)
 257      */
 258     public void readExternal(ObjectInput in)
 259         throws IOException, ClassNotFoundException {
 260         _bitSize = in.readInt();
 261         _intSize = (_bitSize >>> 5) + 1;
 262         _mask    = in.readInt();
 263         _bits    = (int[])in.readObject();
 264     }
 265 
 266 }