001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements. See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership. The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the  "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    /*
019     * $Id: BitArray.java 478667 2006-11-23 20:50:36Z minchau $
020     */
021    
022    package org.apache.xalan.xsltc.dom;
023    
024    import java.io.Externalizable;
025    import java.io.IOException;
026    import java.io.ObjectInput;
027    import java.io.ObjectOutput;
028    
029    import org.apache.xml.dtm.DTMAxisIterator;
030    
031    
032    /**
033     * @author Morten Jorgensen
034     */
035    public class BitArray implements Externalizable {
036        static final long serialVersionUID = -4876019880708377663L;
037    
038        private int[] _bits;
039        private int   _bitSize;
040        private int   _intSize;
041        private int   _mask;
042    
043        // This table is used to prevent expensive shift operations
044        // (These operations are inexpensive on CPUs but very expensive on JVMs.)
045        private final static int[] _masks = {
046            0x80000000, 0x40000000, 0x20000000, 0x10000000,
047            0x08000000, 0x04000000, 0x02000000, 0x01000000,
048            0x00800000, 0x00400000, 0x00200000, 0x00100000,
049            0x00080000, 0x00040000, 0x00020000, 0x00010000,
050            0x00008000, 0x00004000, 0x00002000, 0x00001000,
051            0x00000800, 0x00000400, 0x00000200, 0x00000100,
052            0x00000080, 0x00000040, 0x00000020, 0x00000010,
053            0x00000008, 0x00000004, 0x00000002, 0x00000001 };
054    
055        private final static boolean DEBUG_ASSERTIONS = false;
056        
057        /**
058         * Constructor. Defines the initial size of the bit array (in bits).
059         */
060        public BitArray() {
061            this(32);
062        }
063    
064        public BitArray(int size) {        
065            if (size < 32) size = 32;
066            _bitSize = size;
067            _intSize = (_bitSize >>> 5) + 1;
068            _bits = new int[_intSize + 1];
069        }
070    
071        public BitArray(int size, int[] bits) {
072            if (size < 32) size = 32;
073            _bitSize = size;
074            _intSize = (_bitSize >>> 5) + 1;
075            _bits = bits;
076        }
077    
078        /**
079         * Set the mask for this bit array. The upper 8 bits of this mask
080         * indicate the DOM in which the nodes in this array belong.
081         */    
082        public void setMask(int mask) {
083            _mask = mask;
084        }
085    
086        /**
087         * See setMask()
088         */
089        public int getMask() {
090            return(_mask);
091        }
092    
093        /**
094         * Returns the size of this bit array (in bits).
095         */
096        public final int size() {
097            return(_bitSize);
098        }
099    
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 change 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    }