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      */
BitArray()60     public BitArray() {
61         this(32);
62     }
63 
BitArray(int size)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 
BitArray(int size, int[] bits)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      */
setMask(int mask)82     public void setMask(int mask) {
83         _mask = mask;
84     }
85 
86     /**
87      * See setMask()
88      */
getMask()89     public int getMask() {
90         return(_mask);
91     }
92 
93     /**
94      * Returns the size of this bit array (in bits).
95      */
size()96     public final int size() {
97         return(_bitSize);
98     }
99 
100     /**
101      * Returns true if the given bit is set
102      */
getBit(int bit)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      */
getNextBit(int startBit)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 
getBitNumber(int pos)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      */
data()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      */
setBit(int bit)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      */
merge(BitArray other)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      */
resize(int newSize)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 
cloneArray()244     public BitArray cloneArray() {
245         return(new BitArray(_intSize, _bits));
246     }
247 
writeExternal(ObjectOutput out)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      */
readExternal(ObjectInput in)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 }
267