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 */
017package org.apache.activemq.util;
018
019import java.io.DataInput;
020import java.io.DataOutput;
021import java.io.IOException;
022import 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 */
031public 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}