001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.activemq.util;
018    
019    import java.io.DataInput;
020    import java.io.DataOutput;
021    import java.io.IOException;
022    import java.io.Serializable;
023    
024    /**
025     * Simple BitArray to enable setting multiple boolean values efficently Used
026     * instead of BitSet because BitSet does not allow for efficent serialization.
027     * Will store up to 64 boolean values
028     * 
029     * 
030     */
031    public class BitArray implements Serializable {
032        
033        private static final long serialVersionUID = 1L;
034        
035        static final int LONG_SIZE = 64;
036        static final int INT_SIZE = 32;
037        static final int SHORT_SIZE = 16;
038        static final int BYTE_SIZE = 8;
039        private static final long[] BIT_VALUES = {0x0000000000000001L, 0x0000000000000002L, 0x0000000000000004L,
040                                                  0x0000000000000008L, 0x0000000000000010L, 0x0000000000000020L,
041                                                  0x0000000000000040L, 0x0000000000000080L, 0x0000000000000100L,
042                                                  0x0000000000000200L, 0x0000000000000400L, 0x0000000000000800L,
043                                                  0x0000000000001000L, 0x0000000000002000L, 0x0000000000004000L,
044                                                  0x0000000000008000L, 0x0000000000010000L, 0x0000000000020000L,
045                                                  0x0000000000040000L, 0x0000000000080000L, 0x0000000000100000L,
046                                                  0x0000000000200000L, 0x0000000000400000L, 0x0000000000800000L,
047                                                  0x0000000001000000L, 0x0000000002000000L, 0x0000000004000000L,
048                                                  0x0000000008000000L, 0x0000000010000000L, 0x0000000020000000L,
049                                                  0x0000000040000000L, 0x0000000080000000L, 0x0000000100000000L,
050                                                  0x0000000200000000L, 0x0000000400000000L, 0x0000000800000000L,
051                                                  0x0000001000000000L, 0x0000002000000000L, 0x0000004000000000L,
052                                                  0x0000008000000000L, 0x0000010000000000L, 0x0000020000000000L,
053                                                  0x0000040000000000L, 0x0000080000000000L, 0x0000100000000000L,
054                                                  0x0000200000000000L, 0x0000400000000000L, 0x0000800000000000L,
055                                                  0x0001000000000000L, 0x0002000000000000L, 0x0004000000000000L,
056                                                  0x0008000000000000L, 0x0010000000000000L, 0x0020000000000000L,
057                                                  0x0040000000000000L, 0x0080000000000000L, 0x0100000000000000L,
058                                                  0x0200000000000000L, 0x0400000000000000L, 0x0800000000000000L,
059                                                  0x1000000000000000L, 0x2000000000000000L, 0x4000000000000000L,
060                                                  0x8000000000000000L};
061        private long bits;
062        private int length;
063    
064        /**
065         * @return the length of bits set
066         */
067        public int length() {
068            return length;
069        }
070    
071        /**
072         * @return the long containing the bits
073         */
074        public long getBits() {
075            return bits;
076        }
077    
078        /**
079         * set the boolean value at the index
080         * 
081         * @param index
082         * @param flag
083         * @return the old value held at this index
084         */
085        public boolean set(int index, boolean flag) {
086            length = Math.max(length, index + 1);
087            boolean oldValue = (bits & BIT_VALUES[index]) != 0;
088            if (flag) {
089                bits |= BIT_VALUES[index];
090            } else if (oldValue) {
091                bits &= ~(BIT_VALUES[index]);
092            }
093            return oldValue;
094        }
095    
096        /**
097         * @param index
098         * @return the boolean value at this index
099         */
100        public boolean get(int index) {
101            return (bits & BIT_VALUES[index]) != 0;
102        }
103    
104        /**
105         * reset all the bit values to false
106         */
107        public void reset() {
108            bits = 0;
109        }
110    
111        /**
112         * reset all the bits to the value supplied
113         * 
114         * @param bits
115         */
116        public void reset(long bits) {
117            this.bits = bits;
118        }
119    
120        private void writeObject(java.io.ObjectOutputStream out) throws IOException {
121            writeToStream(out);
122        }
123        
124        private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
125            readFromStream(in);
126        }
127        
128        /**
129         * write the bits to an output stream
130         * 
131         * @param dataOut
132         * @throws IOException
133         */
134        public void writeToStream(DataOutput dataOut) throws IOException {
135            dataOut.writeByte(length);
136            if (length <= BYTE_SIZE) {
137                dataOut.writeByte((byte)bits);
138            } else if (length <= SHORT_SIZE) {
139                dataOut.writeShort((short)bits);
140            } else if (length <= INT_SIZE) {
141                dataOut.writeInt((int)bits);
142            } else {
143                dataOut.writeLong(bits);
144            }
145        }
146    
147        /**
148         * read the bits from an input stream
149         * 
150         * @param dataIn
151         * @throws IOException
152         */
153        public void readFromStream(DataInput dataIn) throws IOException {
154            length = dataIn.readByte();
155            if (length <= BYTE_SIZE) {
156                bits = dataIn.readByte();
157            } else if (length <= SHORT_SIZE) {
158                bits = dataIn.readShort();
159            } else if (length <= INT_SIZE) {
160                bits = dataIn.readInt();
161            } else {
162                bits = dataIn.readLong();
163            }
164        }
165    }