Faster getNextSet; more gains from getNextUnset

git-svn-id: https://zxing.googlecode.com/svn/trunk@2051 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
srowen 2011-11-25 12:37:39 +00:00
parent b93f68f0db
commit 8f005274c0
6 changed files with 129 additions and 63 deletions

View file

@ -81,27 +81,46 @@ public final class BitArray {
/** /**
* @param from first bit to check * @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 * @return index of first bit that is set, starting from the given index, or size if none are set
* at or beyond this given index
* @see #getNextUnset(int)
*/ */
public int getNextSet(int from) { public int getNextSet(int from) {
int size = this.size;
if (from >= size) { if (from >= size) {
return size; return size;
} }
int bitsOffset = from >> 5; int bitsOffset = from >> 5;
int currentBits = bits[bitsOffset]; int currentBits = bits[bitsOffset];
int mask = 1 << (from & 0x1F); // mask off lesser bits first
while ((currentBits & mask) == 0) { currentBits &= ~((1 << (from & 0x1F)) - 1);
if (++from >= size) { while (currentBits == 0) {
break; if (++bitsOffset == bits.length) {
return size;
} }
if (mask == 0x80000000) { currentBits = bits[bitsOffset];
mask = 1;
currentBits = bits[++bitsOffset];
} else {
mask <<= 1;
} }
int result = (bitsOffset << 5) + Integer.numberOfTrailingZeros(currentBits);
return result > size ? size : result;
} }
return from;
/**
* @see #getNextSet(int)
*/
public int getNextUnset(int from) {
if (from >= size) {
return size;
}
int bitsOffset = from >> 5;
int currentBits = ~bits[bitsOffset];
// mask off lesser bits first
currentBits &= ~((1 << (from & 0x1F)) - 1);
while (currentBits == 0) {
if (++bitsOffset == bits.length) {
return size;
}
currentBits = ~bits[bitsOffset];
}
int result = (bitsOffset << 5) + Integer.numberOfTrailingZeros(currentBits);
return result > size ? size : result;
} }
/** /**

View file

@ -413,11 +413,9 @@ public final class Code128Reader extends OneDReader {
// Check for ample whitespace following pattern, but, to do this we first need to remember that // Check for ample whitespace following pattern, but, to do this we first need to remember that
// we fudged decoding CODE_STOP since it actually has 7 bars, not 6. There is a black bar left // we fudged decoding CODE_STOP since it actually has 7 bars, not 6. There is a black bar left
// to read off. Would be slightly better to properly read. Here we just skip it: // to read off. Would be slightly better to properly read. Here we just skip it:
int width = row.getSize(); nextStart = row.getNextUnset(nextStart);
while (nextStart < width && row.get(nextStart)) { if (!row.isRange(nextStart,
nextStart++; Math.min(row.getSize(), nextStart + (nextStart - lastStart) / 2),
}
if (!row.isRange(nextStart, Math.min(width, nextStart + (nextStart - lastStart) / 2),
false)) { false)) {
throw NotFoundException.getNotFoundInstance(); throw NotFoundException.getNotFoundInstance();
} }

View file

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

View file

@ -277,15 +277,8 @@ public abstract class UPCEANReader extends OneDReader {
int[] counters) throws NotFoundException { int[] counters) throws NotFoundException {
int patternLength = pattern.length; int patternLength = pattern.length;
int width = row.getSize(); int width = row.getSize();
boolean isWhite = false; boolean isWhite = whiteFirst;
while (rowOffset < width) { rowOffset = whiteFirst ? row.getNextUnset(rowOffset) : row.getNextSet(rowOffset);
isWhite = !row.get(rowOffset);
if (whiteFirst == isWhite) {
break;
}
rowOffset++;
}
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++) {

View file

@ -190,18 +190,14 @@ public final class RSSExpandedReader extends AbstractRSSReader {
} }
private static int getNextSecondBar(BitArray row, int initialPos){ private static int getNextSecondBar(BitArray row, int initialPos){
int currentPos = initialPos; int currentPos;
boolean current = row.get(currentPos); if (row.get(initialPos)) {
currentPos = row.getNextUnset(initialPos);
while(currentPos < row.getSize() && row.get(currentPos) == current) { currentPos = row.getNextSet(currentPos);
currentPos++; } else {
currentPos = row.getNextSet(initialPos);
currentPos = row.getNextUnset(currentPos);
} }
current = !current;
while(currentPos < row.getSize() && row.get(currentPos) == current) {
currentPos++;
}
return currentPos; return currentPos;
} }
@ -237,7 +233,6 @@ public final class RSSExpandedReader extends AbstractRSSReader {
throw nfe; throw nfe;
} }
} }
return new ExpandedPair(leftChar, rightChar, pattern, mayBeLast); return new ExpandedPair(leftChar, rightChar, pattern, mayBeLast);
} }
@ -374,10 +369,7 @@ public final class RSSExpandedReader extends AbstractRSSReader {
start = this.startEnd[0]; start = this.startEnd[0];
int firstElementStart = this.startEnd[1] + 1; int firstElementStart = row.getNextUnset(this.startEnd[1] + 1);
while (firstElementStart < row.getSize() && row.get(firstElementStart)) {
firstElementStart++;
}
end = firstElementStart; end = firstElementStart;
firstCounter = end - this.startEnd[1]; firstCounter = end - this.startEnd[1];

View file

@ -19,6 +19,9 @@ package com.google.zxing.common;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import java.security.SecureRandom;
import java.util.Random;
/** /**
* @author Sean Owen * @author Sean Owen
*/ */
@ -35,29 +38,92 @@ public final class BitArrayTestCase extends Assert {
} }
@Test @Test
public void testGetNextSet() { public void testGetNextSet1() {
BitArray array = new BitArray(32); BitArray array = new BitArray(32);
assertEquals(32, array.getNextSet(0)); for (int i = 0; i < array.getSize(); i++) {
assertEquals(32, array.getNextSet(31)); assertEquals(String.valueOf(i), 32, array.getNextSet(i));
}
array = new BitArray(33); array = new BitArray(33);
assertEquals(33, array.getNextSet(0)); for (int i = 0; i < array.getSize(); i++) {
assertEquals(33, array.getNextSet(31)); assertEquals(String.valueOf(i), 33, array.getNextSet(i));
assertEquals(33, array.getNextSet(32)); }
}
@Test
public void testGetNextSet2() {
BitArray array = new BitArray(33);
array.set(31); array.set(31);
assertEquals(31, array.getNextSet(0)); for (int i = 0; i < array.getSize(); i++) {
assertEquals(31, array.getNextSet(30)); assertEquals(String.valueOf(i), i <= 31 ? 31 : 33, array.getNextSet(i));
assertEquals(31, array.getNextSet(31)); }
assertEquals(33, array.getNextSet(32));
array = new BitArray(33); array = new BitArray(33);
array.set(32); array.set(32);
assertEquals(32, array.getNextSet(0)); for (int i = 0; i < array.getSize(); i++) {
assertEquals(32, array.getNextSet(30)); assertEquals(String.valueOf(i), 32, array.getNextSet(i));
assertEquals(32, array.getNextSet(31));
assertEquals(32, array.getNextSet(32));
} }
}
@Test
public void testGetNextSet3() {
BitArray array = new BitArray(63);
array.set(31);
array.set(32);
for (int i = 0; i < array.getSize(); i++) {
int expected;
if (i <= 31) {
expected = 31;
} else if (i == 32) {
expected = 32;
} else {
expected = 63;
}
assertEquals(String.valueOf(i), expected, array.getNextSet(i));
}
}
@Test
public void testGetNextSet4() {
BitArray array = new BitArray(63);
array.set(33);
array.set(40);
for (int i = 0; i < array.getSize(); i++) {
int expected;
if (i <= 33) {
expected = 33;
} else if (i <= 40) {
expected = 40;
} else {
expected = 63;
}
assertEquals(String.valueOf(i), expected, array.getNextSet(i));
}
}
@Test
public void testGetNextSet5() {
Random r = new SecureRandom(new byte[] {(byte) 0xDE, (byte) 0xAD, (byte) 0xBE, (byte) 0xEF});
for (int i = 0; i < 10; i++) {
BitArray array = new BitArray(1 + r.nextInt(100));
int numSet = r.nextInt(20);
for (int j = 0; j < numSet; j++) {
array.set(r.nextInt(array.getSize()));
}
int numQueries = r.nextInt(20);
for (int j = 0; j < numQueries; j++) {
int query = r.nextInt(array.getSize());
int expected = query;
while (expected < array.getSize() && !array.get(expected)) {
expected++;
}
int actual = array.getNextSet(query);
if (actual != expected) {
array.getNextSet(query);
}
assertEquals(expected, actual);
}
}
}
@Test @Test
public void testSetBulk() { public void testSetBulk() {