Another half-percent from specializing some operations on bit arrays

git-svn-id: https://zxing.googlecode.com/svn/trunk@2050 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
srowen 2011-11-25 01:17:28 +00:00
parent 35cf29b720
commit b93f68f0db
13 changed files with 87 additions and 87 deletions

View file

@ -78,6 +78,32 @@ public final class BitArray {
bits[i >> 5] ^= 1 << (i & 0x1F); bits[i >> 5] ^= 1 << (i & 0x1F);
} }
/**
* @param from first bit to check
* @return index of first bit that is set, starting from the given index, or size if none are set
*/
public int getNextSet(int from) {
int size = this.size;
if (from >= size) {
return size;
}
int bitsOffset = from >> 5;
int currentBits = bits[bitsOffset];
int mask = 1 << (from & 0x1F);
while ((currentBits & mask) == 0) {
if (++from >= size) {
break;
}
if (mask == 0x80000000) {
mask = 1;
currentBits = bits[++bitsOffset];
} else {
mask <<= 1;
}
}
return from;
}
/** /**
* Sets a block of 32 bits, starting at bit i. * Sets a block of 32 bits, starting at bit i.
* *

View file

@ -144,6 +144,14 @@ public final class BitMatrix {
return row; return row;
} }
/**
* @param y row to set
* @param row {@link BitArray} to copy from
*/
public void setRow(int y, BitArray row) {
System.arraycopy(row.getBitArray(), 0, bits, y * rowSize, rowSize);
}
/** /**
* This is useful in detecting the enclosing rectangle of a 'pure' barcode. * This is useful in detecting the enclosing rectangle of a 'pure' barcode.
* *

View file

@ -66,13 +66,9 @@ public final class CodaBarReader extends OneDReader {
throws NotFoundException { throws NotFoundException {
int[] start = findAsteriskPattern(row); int[] start = findAsteriskPattern(row);
start[1] = 0; // BAS: settings this to 0 improves the recognition rate somehow? start[1] = 0; // BAS: settings this to 0 improves the recognition rate somehow?
int nextStart = start[1];
int end = row.getSize();
// Read off white space // Read off white space
while (nextStart < end && !row.get(nextStart)) { int nextStart = row.getNextSet(start[1]);
nextStart++; int end = row.getSize();
}
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
int[] counters = new int[7]; int[] counters = new int[7];
@ -95,9 +91,7 @@ public final class CodaBarReader extends OneDReader {
} }
// Read off white space // Read off white space
while (nextStart < end && !row.get(nextStart)) { nextStart = row.getNextSet(nextStart);
nextStart++;
}
} while (nextStart < end); // no fixed end pattern so keep on reading while data is available } while (nextStart < end); // no fixed end pattern so keep on reading while data is available
// Look for whitespace after pattern: // Look for whitespace after pattern:
@ -157,13 +151,7 @@ public final class CodaBarReader extends OneDReader {
private static int[] findAsteriskPattern(BitArray row) throws NotFoundException { private static int[] findAsteriskPattern(BitArray row) throws NotFoundException {
int width = row.getSize(); int width = row.getSize();
int rowOffset = 0; int rowOffset = row.getNextSet(0);
while (rowOffset < width) {
if (row.get(rowOffset)) {
break;
}
rowOffset++;
}
int counterPosition = 0; int counterPosition = 0;
int[] counters = new int[7]; int[] counters = new int[7];
@ -172,8 +160,7 @@ public final class CodaBarReader extends OneDReader {
int patternLength = counters.length; int patternLength = counters.length;
for (int i = rowOffset; i < width; i++) { for (int i = rowOffset; i < width; i++) {
boolean pixel = row.get(i); if (row.get(i) ^ isWhite) {
if (pixel ^ isWhite) {
counters[counterPosition]++; counters[counterPosition]++;
} else { } else {
if (counterPosition == patternLength - 1) { if (counterPosition == patternLength - 1) {

View file

@ -168,13 +168,7 @@ public final class Code128Reader extends OneDReader {
private static int[] findStartPattern(BitArray row) throws NotFoundException { private static int[] findStartPattern(BitArray row) throws NotFoundException {
int width = row.getSize(); int width = row.getSize();
int rowOffset = 0; int rowOffset = row.getNextSet(0);
while (rowOffset < width) {
if (row.get(rowOffset)) {
break;
}
rowOffset++;
}
int counterPosition = 0; int counterPosition = 0;
int[] counters = new int[6]; int[] counters = new int[6];
@ -183,8 +177,7 @@ public final class Code128Reader extends OneDReader {
int patternLength = counters.length; int patternLength = counters.length;
for (int i = rowOffset; i < width; i++) { for (int i = rowOffset; i < width; i++) {
boolean pixel = row.get(i); if (row.get(i) ^ isWhite) {
if (pixel ^ isWhite) {
counters[counterPosition]++; counters[counterPosition]++;
} else { } else {
if (counterPosition == patternLength - 1) { if (counterPosition == patternLength - 1) {

View file

@ -98,13 +98,9 @@ public final class Code39Reader extends OneDReader {
int[] counters = new int[9]; int[] counters = new int[9];
int[] start = findAsteriskPattern(row, counters); int[] start = findAsteriskPattern(row, counters);
int nextStart = start[1];
int end = row.getSize();
// Read off white space // Read off white space
while (nextStart < end && !row.get(nextStart)) { int nextStart = row.getNextSet(start[1]);
nextStart++; int end = row.getSize();
}
StringBuilder result = new StringBuilder(20); StringBuilder result = new StringBuilder(20);
char decodedChar; char decodedChar;
@ -122,11 +118,9 @@ public final class Code39Reader extends OneDReader {
nextStart += counter; nextStart += counter;
} }
// Read off white space // Read off white space
while (nextStart < end && !row.get(nextStart)) { nextStart = row.getNextSet(nextStart);
nextStart++;
}
} while (decodedChar != '*'); } while (decodedChar != '*');
result.deleteCharAt(result.length() - 1); // remove asterisk result.setLength(result.length() - 1); // remove asterisk
// Look for whitespace after pattern: // Look for whitespace after pattern:
int lastPatternSize = 0; int lastPatternSize = 0;
@ -136,7 +130,7 @@ public final class Code39Reader extends OneDReader {
int whiteSpaceAfterEnd = nextStart - lastStart - lastPatternSize; int whiteSpaceAfterEnd = nextStart - lastStart - lastPatternSize;
// If 50% of last pattern size, following last pattern, is not whitespace, fail // If 50% of last pattern size, following last pattern, is not whitespace, fail
// (but if it's whitespace to the very end of the image, that's OK) // (but if it's whitespace to the very end of the image, that's OK)
if (nextStart != end && whiteSpaceAfterEnd / 2 < lastPatternSize) { if (nextStart != end && (whiteSpaceAfterEnd >> 1) < lastPatternSize) {
throw NotFoundException.getNotFoundInstance(); throw NotFoundException.getNotFoundInstance();
} }
@ -149,7 +143,7 @@ public final class Code39Reader extends OneDReader {
if (result.charAt(max) != ALPHABET[total % 43]) { if (result.charAt(max) != ALPHABET[total % 43]) {
throw ChecksumException.getChecksumInstance(); throw ChecksumException.getChecksumInstance();
} }
result.deleteCharAt(max); result.setLength(max);
} }
if (result.length() < 4) { if (result.length() < 4) {
@ -178,13 +172,7 @@ public final class Code39Reader extends OneDReader {
private static int[] findAsteriskPattern(BitArray row, int[] counters) throws NotFoundException { private static int[] findAsteriskPattern(BitArray row, int[] counters) throws NotFoundException {
int width = row.getSize(); int width = row.getSize();
int rowOffset = 0; int rowOffset = row.getNextSet(0);
while (rowOffset < width) {
if (row.get(rowOffset)) {
break;
}
rowOffset++;
}
int counterPosition = 0; int counterPosition = 0;
int patternStart = rowOffset; int patternStart = rowOffset;
@ -192,14 +180,13 @@ public final class Code39Reader extends OneDReader {
int patternLength = counters.length; int patternLength = counters.length;
for (int i = rowOffset; i < width; i++) { for (int i = rowOffset; i < width; i++) {
boolean pixel = row.get(i); if (row.get(i) ^ isWhite) {
if (pixel ^ isWhite) {
counters[counterPosition]++; counters[counterPosition]++;
} else { } else {
if (counterPosition == patternLength - 1) { if (counterPosition == patternLength - 1) {
if (toNarrowWidePattern(counters) == ASTERISK_ENCODING) { if (toNarrowWidePattern(counters) == ASTERISK_ENCODING) {
// Look for whitespace before start pattern, >= 50% of width of start pattern // Look for whitespace before start pattern, >= 50% of width of start pattern
if (row.isRange(Math.max(0, patternStart - (i - patternStart) / 2), patternStart, false)) { if (row.isRange(Math.max(0, patternStart - ((i - patternStart) >> 1)), patternStart, false)) {
return new int[]{patternStart, i}; return new int[]{patternStart, i};
} }
} }

View file

@ -58,13 +58,9 @@ public final class Code93Reader extends OneDReader {
throws NotFoundException, ChecksumException, FormatException { throws NotFoundException, ChecksumException, FormatException {
int[] start = findAsteriskPattern(row); int[] start = findAsteriskPattern(row);
int nextStart = start[1];
int end = row.getSize();
// Read off white space // Read off white space
while (nextStart < end && !row.get(nextStart)) { int nextStart = row.getNextSet(start[1]);
nextStart++; int end = row.getSize();
}
StringBuilder result = new StringBuilder(20); StringBuilder result = new StringBuilder(20);
int[] counters = new int[6]; int[] counters = new int[6];
@ -83,9 +79,7 @@ public final class Code93Reader extends OneDReader {
nextStart += counter; nextStart += counter;
} }
// Read off white space // Read off white space
while (nextStart < end && !row.get(nextStart)) { nextStart = row.getNextSet(nextStart);
nextStart++;
}
} while (decodedChar != '*'); } while (decodedChar != '*');
result.deleteCharAt(result.length() - 1); // remove asterisk result.deleteCharAt(result.length() - 1); // remove asterisk
@ -119,13 +113,7 @@ public final class Code93Reader extends OneDReader {
private static int[] findAsteriskPattern(BitArray row) throws NotFoundException { private static int[] findAsteriskPattern(BitArray row) throws NotFoundException {
int width = row.getSize(); int width = row.getSize();
int rowOffset = 0; int rowOffset = row.getNextSet(0);
while (rowOffset < width) {
if (row.get(rowOffset)) {
break;
}
rowOffset++;
}
int counterPosition = 0; int counterPosition = 0;
int[] counters = new int[6]; int[] counters = new int[6];
@ -134,8 +122,7 @@ public final class Code93Reader extends OneDReader {
int patternLength = counters.length; int patternLength = counters.length;
for (int i = rowOffset; i < width; i++) { for (int i = rowOffset; i < width; i++) {
boolean pixel = row.get(i); if (row.get(i) ^ isWhite) {
if (pixel ^ isWhite) {
counters[counterPosition]++; counters[counterPosition]++;
} else { } else {
if (counterPosition == patternLength - 1) { if (counterPosition == patternLength - 1) {

View file

@ -227,13 +227,7 @@ public final class ITFReader extends OneDReader {
*/ */
private static int skipWhiteSpace(BitArray row) throws NotFoundException { private static int skipWhiteSpace(BitArray row) throws NotFoundException {
int width = row.getSize(); int width = row.getSize();
int endStart = 0; int endStart = row.getNextSet(0);
while (endStart < width) {
if (row.get(endStart)) {
break;
}
endStart++;
}
if (endStart == width) { if (endStart == width) {
throw NotFoundException.getNotFoundInstance(); throw NotFoundException.getNotFoundInstance();
} }
@ -300,8 +294,7 @@ public final class ITFReader extends OneDReader {
int counterPosition = 0; int counterPosition = 0;
int patternStart = rowOffset; int patternStart = rowOffset;
for (int x = rowOffset; x < width; x++) { for (int x = rowOffset; x < width; x++) {
boolean pixel = row.get(x); if (row.get(x) ^ isWhite) {
if (pixel ^ isWhite) {
counters[counterPosition]++; counters[counterPosition]++;
} else { } else {
if (counterPosition == patternLength - 1) { if (counterPosition == patternLength - 1) {

View file

@ -203,8 +203,7 @@ public abstract class OneDReader implements Reader {
int counterPosition = 0; int counterPosition = 0;
int i = start; int i = start;
while (i < end) { while (i < end) {
boolean pixel = row.get(i); if (row.get(i) ^ isWhite) { // that is, exactly one is true
if (pixel ^ isWhite) { // that is, exactly one is true
counters[counterPosition]++; counters[counterPosition]++;
} else { } else {
counterPosition++; counterPosition++;

View file

@ -85,9 +85,7 @@ final class UPCEANExtensionSupport {
} }
if (x != 4) { if (x != 4) {
// Read off separator if not last // Read off separator if not last
while (rowOffset < end && !row.get(rowOffset)) { rowOffset = row.getNextSet(rowOffset);
rowOffset++;
}
while (rowOffset < end && row.get(rowOffset)) { while (rowOffset < end && row.get(rowOffset)) {
rowOffset++; rowOffset++;
} }

View file

@ -289,8 +289,7 @@ public abstract class UPCEANReader extends OneDReader {
int counterPosition = 0; int counterPosition = 0;
int patternStart = rowOffset; int patternStart = rowOffset;
for (int x = rowOffset; x < width; x++) { for (int x = rowOffset; x < width; x++) {
boolean pixel = row.get(x); if (row.get(x) ^ isWhite) {
if (pixel ^ isWhite) {
counters[counterPosition]++; counters[counterPosition]++;
} else { } else {
if (counterPosition == patternLength - 1) { if (counterPosition == patternLength - 1) {

View file

@ -303,8 +303,7 @@ public final class RSS14Reader extends AbstractRSSReader {
int counterPosition = 0; int counterPosition = 0;
int patternStart = rowOffset; int patternStart = rowOffset;
for (int x = rowOffset; x < width; x++) { for (int x = rowOffset; x < width; x++) {
boolean pixel = row.get(x); if (row.get(x) ^ isWhite) {
if (pixel ^ isWhite) {
counters[counterPosition]++; counters[counterPosition]++;
} else { } else {
if (counterPosition == 3) { if (counterPosition == 3) {

View file

@ -306,8 +306,7 @@ public final class RSSExpandedReader extends AbstractRSSReader {
int counterPosition = 0; int counterPosition = 0;
int patternStart = rowOffset; int patternStart = rowOffset;
for (int x = rowOffset; x < width; x++) { for (int x = rowOffset; x < width; x++) {
boolean pixel = row.get(x); if (row.get(x) ^ isWhite) {
if (pixel ^ isWhite) {
counters[counterPosition]++; counters[counterPosition]++;
} else { } else {
if (counterPosition == 3) { if (counterPosition == 3) {

View file

@ -34,6 +34,31 @@ public final class BitArrayTestCase extends Assert {
} }
} }
@Test
public void testGetNextSet() {
BitArray array = new BitArray(32);
assertEquals(32, array.getNextSet(0));
assertEquals(32, array.getNextSet(31));
array = new BitArray(33);
assertEquals(33, array.getNextSet(0));
assertEquals(33, array.getNextSet(31));
assertEquals(33, array.getNextSet(32));
array.set(31);
assertEquals(31, array.getNextSet(0));
assertEquals(31, array.getNextSet(30));
assertEquals(31, array.getNextSet(31));
assertEquals(33, array.getNextSet(32));
array = new BitArray(33);
array.set(32);
assertEquals(32, array.getNextSet(0));
assertEquals(32, array.getNextSet(30));
assertEquals(32, array.getNextSet(31));
assertEquals(32, array.getNextSet(32));
}
@Test @Test
public void testSetBulk() { public void testSetBulk() {
BitArray array = new BitArray(64); BitArray array = new BitArray(64);