Small style stuff
[zxing.git] / core / src / com / google / zxing / common / BitArray.java
1 /*\r
2  * Copyright 2007 ZXing authors\r
3  *\r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  *\r
8  *      http://www.apache.org/licenses/LICENSE-2.0\r
9  *\r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  */\r
16 \r
17 package com.google.zxing.common;\r
18 \r
19 /**\r
20  * <p>A simple, fast array of bits, represented compactly by an array of ints internally.</p>\r
21  *\r
22  * @author Sean Owen\r
23  */\r
24 public final class BitArray {\r
25 \r
26   // TODO: I have changed these members to be public so ProGuard can inline get() and set(). Ideally\r
27   // they'd be private and we'd use the -allowaccessmodification flag, but Dalvik rejects the\r
28   // resulting binary at runtime on Android. If we find a solution to this, these should be changed\r
29   // back to private.\r
30   public int[] bits;\r
31   public int size;\r
32 \r
33   public BitArray() {\r
34     this.size = 0;\r
35     this.bits = new int[1];\r
36   }\r
37 \r
38   public BitArray(int size) {\r
39     this.size = size;\r
40     this.bits = makeArray(size);\r
41   }\r
42 \r
43   public int getSize() {\r
44     return size;\r
45   }\r
46 \r
47   public int getSizeInBytes() {\r
48     return (size + 7) >> 3;\r
49   }\r
50 \r
51   private void ensureCapacity(int size) {\r
52     if (size > bits.length << 5) {\r
53       int[] newBits = makeArray(size);\r
54       System.arraycopy(bits, 0, newBits, 0, bits.length);\r
55       this.bits = newBits;\r
56     }\r
57   }\r
58 \r
59   /**\r
60    * @param i bit to get\r
61    * @return true iff bit i is set\r
62    */\r
63   public boolean get(int i) {\r
64     return (bits[i >> 5] & (1 << (i & 0x1F))) != 0;\r
65   }\r
66 \r
67   /**\r
68    * Sets bit i.\r
69    *\r
70    * @param i bit to set\r
71    */\r
72   public void set(int i) {\r
73     bits[i >> 5] |= 1 << (i & 0x1F);\r
74   }\r
75 \r
76   /**\r
77    * Flips bit i.\r
78    *\r
79    * @param i bit to set\r
80    */\r
81   public void flip(int i) {\r
82     bits[i >> 5] ^= 1 << (i & 0x1F);\r
83   }\r
84 \r
85   /**\r
86    * Sets a block of 32 bits, starting at bit i.\r
87    *\r
88    * @param i first bit to set\r
89    * @param newBits the new value of the next 32 bits. Note again that the least-significant bit\r
90    * corresponds to bit i, the next-least-significant to i+1, and so on.\r
91    */\r
92   public void setBulk(int i, int newBits) {\r
93     bits[i >> 5] = newBits;\r
94   }\r
95 \r
96   /**\r
97    * Clears all bits (sets to false).\r
98    */\r
99   public void clear() {\r
100     int max = bits.length;\r
101     for (int i = 0; i < max; i++) {\r
102       bits[i] = 0;\r
103     }\r
104   }\r
105 \r
106   /**\r
107    * Efficient method to check if a range of bits is set, or not set.\r
108    *\r
109    * @param start start of range, inclusive.\r
110    * @param end end of range, exclusive\r
111    * @param value if true, checks that bits in range are set, otherwise checks that they are not set\r
112    * @return true iff all bits are set or not set in range, according to value argument\r
113    * @throws IllegalArgumentException if end is less than or equal to start\r
114    */\r
115   public boolean isRange(int start, int end, boolean value) {\r
116     if (end < start) {\r
117       throw new IllegalArgumentException();\r
118     }\r
119     if (end == start) {\r
120       return true; // empty range matches\r
121     }\r
122     end--; // will be easier to treat this as the last actually set bit -- inclusive    \r
123     int firstInt = start >> 5;\r
124     int lastInt = end >> 5;\r
125     for (int i = firstInt; i <= lastInt; i++) {\r
126       int firstBit = i > firstInt ? 0 : start & 0x1F;\r
127       int lastBit = i < lastInt ? 31 : end & 0x1F;\r
128       int mask;\r
129       if (firstBit == 0 && lastBit == 31) {\r
130         mask = -1;\r
131       } else {\r
132         mask = 0;\r
133         for (int j = firstBit; j <= lastBit; j++) {\r
134           mask |= 1 << j;\r
135         }\r
136       }\r
137 \r
138       // Return false if we're looking for 1s and the masked bits[i] isn't all 1s (that is,\r
139       // equals the mask, or we're looking for 0s and the masked portion is not all 0s\r
140       if ((bits[i] & mask) != (value ? mask : 0)) {\r
141         return false;\r
142       }\r
143     }\r
144     return true;\r
145   }\r
146 \r
147   public void appendBit(boolean bit) {\r
148     ensureCapacity(size + 1);\r
149     if (bit) {\r
150       bits[size >> 5] |= (1 << (size & 0x1F));\r
151     }\r
152     size++;\r
153   }\r
154 \r
155   /**\r
156    * Appends the least-significant bits, from value, in order from most-significant to\r
157    * least-significant. For example, appending 6 bits from 0x000001E will append the bits\r
158    * 0, 1, 1, 1, 1, 0 in that order.\r
159    */\r
160   public void appendBits(int value, int numBits) {\r
161     if (numBits < 0 || numBits > 32) {\r
162       throw new IllegalArgumentException("Num bits must be between 0 and 32");\r
163     }\r
164     ensureCapacity(size + numBits);\r
165     for (int numBitsLeft = numBits; numBitsLeft > 0; numBitsLeft--) {\r
166       appendBit(((value >> (numBitsLeft - 1)) & 0x01) == 1);\r
167     }\r
168   }\r
169 \r
170   public void appendBitArray(BitArray other) {\r
171     int otherSize = other.getSize();\r
172     ensureCapacity(size + otherSize);\r
173     for (int i = 0; i < otherSize; i++) {\r
174       appendBit(other.get(i));\r
175     }\r
176   }\r
177 \r
178   public void xor(BitArray other) {\r
179     if (bits.length != other.bits.length) {\r
180       throw new IllegalArgumentException("Sizes don't match");\r
181     }\r
182     for (int i = 0; i < bits.length; i++) {\r
183       // The last byte could be incomplete (i.e. not have 8 bits in\r
184       // it) but there is no problem since 0 XOR 0 == 0.\r
185       bits[i] ^= other.bits[i];\r
186     }\r
187   }\r
188 \r
189   /**\r
190    *\r
191    * @param bitOffset first bit to start writing\r
192    * @param array array to write into. Bytes are written most-significant byte first. This is the opposite\r
193    *  of the internal representation, which is exposed by {@link #getBitArray()}\r
194    * @param offset position in array to start writing\r
195    * @param numBytes how many bytes to write\r
196    */\r
197   public void toBytes(int bitOffset, byte[] array, int offset, int numBytes) {\r
198     for (int i = 0; i < numBytes; i++) {\r
199       int theByte = 0;\r
200       for (int j = 0; j < 8; j++) {\r
201         if (get(bitOffset)) {\r
202           theByte |= 1 << (7 - j);\r
203         }\r
204         bitOffset++;\r
205       }\r
206       array[offset + i] = (byte) theByte;\r
207     }\r
208   }\r
209 \r
210   /**\r
211    * @return underlying array of ints. The first element holds the first 32 bits, and the least\r
212    *         significant bit is bit 0.\r
213    */\r
214   public int[] getBitArray() {\r
215     return bits;\r
216   }\r
217 \r
218   /**\r
219    * Reverses all bits in the array.\r
220    */\r
221   public void reverse() {\r
222     int[] newBits = new int[bits.length];\r
223     int size = this.size;\r
224     for (int i = 0; i < size; i++) {\r
225       if (get(size - i - 1)) {\r
226         newBits[i >> 5] |= 1 << (i & 0x1F);\r
227       }\r
228     }\r
229     bits = newBits;\r
230   }\r
231 \r
232   private static int[] makeArray(int size) {\r
233     return new int[(size + 31) >> 5];\r
234   }\r
235   \r
236   public String toString() {\r
237     StringBuffer result = new StringBuffer(size);\r
238     for (int i = 0; i < size; i++) {\r
239       if ((i & 0x07) == 0) {\r
240         result.append(' ');\r
241       }\r
242       result.append(get(i) ? 'X' : '.');\r
243     }\r
244     return result.toString();\r
245   }\r
246 \r
247 }