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 }