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
* @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) {
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;
// mask off lesser bits first
currentBits &= ~((1 << (from & 0x1F)) - 1);
while (currentBits == 0) {
if (++bitsOffset == bits.length) {
return size;
}
currentBits = bits[bitsOffset];
}
return from;
int result = (bitsOffset << 5) + Integer.numberOfTrailingZeros(currentBits);
return result > size ? size : result;
}
/**
* @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,12 +413,10 @@ public final class Code128Reader extends OneDReader {
// 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
// to read off. Would be slightly better to properly read. Here we just skip it:
int width = row.getSize();
while (nextStart < width && row.get(nextStart)) {
nextStart++;
}
if (!row.isRange(nextStart, Math.min(width, nextStart + (nextStart - lastStart) / 2),
false)) {
nextStart = row.getNextUnset(nextStart);
if (!row.isRange(nextStart,
Math.min(row.getSize(), nextStart + (nextStart - lastStart) / 2),
false)) {
throw NotFoundException.getNotFoundInstance();
}

View file

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

View file

@ -277,15 +277,8 @@ public abstract class UPCEANReader extends OneDReader {
int[] counters) throws NotFoundException {
int patternLength = pattern.length;
int width = row.getSize();
boolean isWhite = false;
while (rowOffset < width) {
isWhite = !row.get(rowOffset);
if (whiteFirst == isWhite) {
break;
}
rowOffset++;
}
boolean isWhite = whiteFirst;
rowOffset = whiteFirst ? row.getNextUnset(rowOffset) : row.getNextSet(rowOffset);
int counterPosition = 0;
int patternStart = rowOffset;
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){
int currentPos = initialPos;
boolean current = row.get(currentPos);
while(currentPos < row.getSize() && row.get(currentPos) == current) {
currentPos++;
int currentPos;
if (row.get(initialPos)) {
currentPos = row.getNextUnset(initialPos);
currentPos = row.getNextSet(currentPos);
} else {
currentPos = row.getNextSet(initialPos);
currentPos = row.getNextUnset(currentPos);
}
current = !current;
while(currentPos < row.getSize() && row.get(currentPos) == current) {
currentPos++;
}
return currentPos;
}
@ -237,7 +233,6 @@ public final class RSSExpandedReader extends AbstractRSSReader {
throw nfe;
}
}
return new ExpandedPair(leftChar, rightChar, pattern, mayBeLast);
}
@ -374,10 +369,7 @@ public final class RSSExpandedReader extends AbstractRSSReader {
start = this.startEnd[0];
int firstElementStart = this.startEnd[1] + 1;
while (firstElementStart < row.getSize() && row.get(firstElementStart)) {
firstElementStart++;
}
int firstElementStart = row.getNextUnset(this.startEnd[1] + 1);
end = firstElementStart;
firstCounter = end - this.startEnd[1];

View file

@ -19,6 +19,9 @@ package com.google.zxing.common;
import org.junit.Assert;
import org.junit.Test;
import java.security.SecureRandom;
import java.util.Random;
/**
* @author Sean Owen
*/
@ -35,29 +38,92 @@ public final class BitArrayTestCase extends Assert {
}
@Test
public void testGetNextSet() {
public void testGetNextSet1() {
BitArray array = new BitArray(32);
assertEquals(32, array.getNextSet(0));
assertEquals(32, array.getNextSet(31));
for (int i = 0; i < array.getSize(); i++) {
assertEquals(String.valueOf(i), 32, array.getNextSet(i));
}
array = new BitArray(33);
assertEquals(33, array.getNextSet(0));
assertEquals(33, array.getNextSet(31));
assertEquals(33, array.getNextSet(32));
for (int i = 0; i < array.getSize(); i++) {
assertEquals(String.valueOf(i), 33, array.getNextSet(i));
}
}
@Test
public void testGetNextSet2() {
BitArray array = new BitArray(33);
array.set(31);
assertEquals(31, array.getNextSet(0));
assertEquals(31, array.getNextSet(30));
assertEquals(31, array.getNextSet(31));
assertEquals(33, array.getNextSet(32));
for (int i = 0; i < array.getSize(); i++) {
assertEquals(String.valueOf(i), i <= 31 ? 31 : 33, array.getNextSet(i));
}
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));
for (int i = 0; i < array.getSize(); i++) {
assertEquals(String.valueOf(i), 32, array.getNextSet(i));
}
}
@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
public void testSetBulk() {