Simplify + optimize VorbisBitArray

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=161796758
This commit is contained in:
olly 2017-07-13 05:59:15 -07:00 committed by Oliver Woodman
parent 90398c5811
commit 8378c3dc1f
2 changed files with 28 additions and 188 deletions

View File

@ -25,36 +25,26 @@ public final class VorbisBitArrayTest extends TestCase {
public void testReadBit() {
VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0x5c, 0x50));
assertFalse(bitArray.readBit());
assertFalse(bitArray.readBit());
assertTrue(bitArray.readBit());
assertTrue(bitArray.readBit());
assertTrue(bitArray.readBit());
assertFalse(bitArray.readBit());
assertTrue(bitArray.readBit());
assertFalse(bitArray.readBit());
assertFalse(bitArray.readBit());
assertFalse(bitArray.readBit());
assertFalse(bitArray.readBit());
assertFalse(bitArray.readBit());
assertTrue(bitArray.readBit());
assertFalse(bitArray.readBit());
assertTrue(bitArray.readBit());
assertFalse(bitArray.readBit());
try {
assertFalse(bitArray.readBit());
fail();
} catch (IllegalStateException e) {/* ignored */}
}
public void testSkipBits() {
VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xF0, 0x0F));
bitArray.skipBits(10);
assertEquals(10, bitArray.getPosition());
assertTrue(bitArray.readBit());
@ -64,27 +54,10 @@ public final class VorbisBitArrayTest extends TestCase {
assertEquals(14, bitArray.getPosition());
assertFalse(bitArray.readBit());
assertFalse(bitArray.readBit());
try {
bitArray.readBit();
fail();
} catch (IllegalStateException e) {
// ignored
}
}
public void testSkipBitsThrowsErrorIfEOB() {
VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xF0, 0x0F));
try {
bitArray.skipBits(17);
fail();
} catch (IllegalStateException e) {/* ignored */}
}
public void testGetPosition() throws Exception {
VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xF0, 0x0F));
assertEquals(0, bitArray.getPosition());
bitArray.readBit();
assertEquals(1, bitArray.getPosition());
@ -96,35 +69,11 @@ public final class VorbisBitArrayTest extends TestCase {
public void testSetPosition() throws Exception {
VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xF0, 0x0F));
assertEquals(0, bitArray.getPosition());
bitArray.setPosition(4);
assertEquals(4, bitArray.getPosition());
bitArray.setPosition(15);
assertFalse(bitArray.readBit());
try {
bitArray.readBit();
fail();
} catch (IllegalStateException e) {/* ignored */}
}
public void testSetPositionIllegalPositions() throws Exception {
VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xF0, 0x0F));
try {
bitArray.setPosition(16);
fail();
} catch (IllegalArgumentException e) {
assertEquals(0, bitArray.getPosition());
}
try {
bitArray.setPosition(-1);
fail();
} catch (IllegalArgumentException e) {
assertEquals(0, bitArray.getPosition());
}
}
public void testReadInt32() {
@ -136,13 +85,11 @@ public final class VorbisBitArrayTest extends TestCase {
public void testReadBits() throws Exception {
VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0x03, 0x22));
assertEquals(3, bitArray.readBits(2));
bitArray.skipBits(6);
assertEquals(2, bitArray.readBits(2));
bitArray.skipBits(2);
assertEquals(2, bitArray.readBits(2));
bitArray.reset();
assertEquals(0x2203, bitArray.readBits(16));
}
@ -156,7 +103,6 @@ public final class VorbisBitArrayTest extends TestCase {
public void testReadBitsBeyondByteBoundaries() throws Exception {
VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xFF, 0x0F, 0xFF, 0x0F));
assertEquals(0x0FFF0FFF, bitArray.readBits(32));
bitArray.reset();
@ -188,83 +134,6 @@ public final class VorbisBitArrayTest extends TestCase {
assertEquals(0, bitArray.getPosition());
bitArray.readBit();
assertEquals(1, bitArray.getPosition());
try {
bitArray.readBits(24);
fail();
} catch (IllegalStateException e) {
assertEquals(1, bitArray.getPosition());
}
}
public void testLimit() {
VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xc0, 0x02), 1);
try {
bitArray.skipBits(9);
fail();
} catch (IllegalStateException e) {
assertEquals(0, bitArray.getPosition());
}
try {
bitArray.readBits(9);
fail();
} catch (IllegalStateException e) {
assertEquals(0, bitArray.getPosition());
}
int byteValue = bitArray.readBits(8);
assertEquals(0xc0, byteValue);
assertEquals(8, bitArray.getPosition());
try {
bitArray.readBit();
fail();
} catch (IllegalStateException e) {
assertEquals(8, bitArray.getPosition());
}
}
public void testBitsLeft() {
VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xc0, 0x02));
assertEquals(16, bitArray.bitsLeft());
assertEquals(bitArray.limit(), bitArray.getPosition() + bitArray.bitsLeft());
bitArray.skipBits(1);
assertEquals(15, bitArray.bitsLeft());
assertEquals(bitArray.limit(), bitArray.getPosition() + bitArray.bitsLeft());
bitArray.skipBits(3);
assertEquals(12, bitArray.bitsLeft());
assertEquals(bitArray.limit(), bitArray.getPosition() + bitArray.bitsLeft());
bitArray.setPosition(6);
assertEquals(10, bitArray.bitsLeft());
assertEquals(bitArray.limit(), bitArray.getPosition() + bitArray.bitsLeft());
bitArray.skipBits(1);
assertEquals(9, bitArray.bitsLeft());
assertEquals(bitArray.limit(), bitArray.getPosition() + bitArray.bitsLeft());
bitArray.skipBits(1);
assertEquals(8, bitArray.bitsLeft());
assertEquals(bitArray.limit(), bitArray.getPosition() + bitArray.bitsLeft());
bitArray.readBits(4);
assertEquals(4, bitArray.bitsLeft());
assertEquals(bitArray.limit(), bitArray.getPosition() + bitArray.bitsLeft());
bitArray.readBits(4);
assertEquals(0, bitArray.bitsLeft());
assertEquals(bitArray.limit(), bitArray.getPosition() + bitArray.bitsLeft());
try {
bitArray.readBit();
fail();
} catch (IllegalStateException e) {
assertEquals(0, bitArray.bitsLeft());
}
}
}

View File

@ -25,8 +25,9 @@ import com.google.android.exoplayer2.util.Assertions;
*/
/* package */ final class VorbisBitArray {
public final byte[] data;
private final int limit;
private final byte[] data;
private final int byteLimit;
private int byteOffset;
private int bitOffset;
@ -36,18 +37,8 @@ import com.google.android.exoplayer2.util.Assertions;
* @param data the array to wrap.
*/
public VorbisBitArray(byte[] data) {
this(data, data.length);
}
/**
* Creates a new instance that wraps an existing array.
*
* @param data the array to wrap.
* @param limit the limit in bytes.
*/
public VorbisBitArray(byte[] data, int limit) {
this.data = data;
this.limit = limit * 8;
byteLimit = data.length;
}
/**
@ -64,7 +55,9 @@ import com.google.android.exoplayer2.util.Assertions;
* @return {@code true} if the bit is set, {@code false} otherwise.
*/
public boolean readBit() {
return readBits(1) == 1;
boolean returnValue = (((data[byteOffset] & 0xFF) >> bitOffset) & 0x01) == 1;
skipBits(1);
return returnValue;
}
/**
@ -74,53 +67,32 @@ import com.google.android.exoplayer2.util.Assertions;
* @return An integer whose bottom {@code numBits} bits hold the read data.
*/
public int readBits(int numBits) {
Assertions.checkState(getPosition() + numBits <= limit);
if (numBits == 0) {
return 0;
int tempByteOffset = byteOffset;
int bitsRead = Math.min(numBits, 8 - bitOffset);
int returnValue = ((data[tempByteOffset++] & 0xFF) >> bitOffset) & (0xFF >> (8 - bitsRead));
while (bitsRead < numBits) {
returnValue |= (data[tempByteOffset++] & 0xFF) << bitsRead;
bitsRead += 8;
}
int result = 0;
int bitCount = 0;
if (bitOffset != 0) {
bitCount = Math.min(numBits, 8 - bitOffset);
int mask = 0xFF >>> (8 - bitCount);
result = (data[byteOffset] >>> bitOffset) & mask;
bitOffset += bitCount;
if (bitOffset == 8) {
byteOffset++;
bitOffset = 0;
}
}
if (numBits - bitCount > 7) {
int numBytes = (numBits - bitCount) / 8;
for (int i = 0; i < numBytes; i++) {
result |= (data[byteOffset++] & 0xFFL) << bitCount;
bitCount += 8;
}
}
if (numBits > bitCount) {
int bitsOnNextByte = numBits - bitCount;
int mask = 0xFF >>> (8 - bitsOnNextByte);
result |= (data[byteOffset] & mask) << bitCount;
bitOffset += bitsOnNextByte;
}
return result;
returnValue &= 0xFFFFFFFF >>> (32 - numBits);
skipBits(numBits);
return returnValue;
}
/**
* Skips {@code numberOfBits} bits.
*
* @param numberOfBits The number of bits to skip.
* @param numBits The number of bits to skip.
*/
public void skipBits(int numberOfBits) {
Assertions.checkState(getPosition() + numberOfBits <= limit);
byteOffset += numberOfBits / 8;
bitOffset += numberOfBits % 8;
public void skipBits(int numBits) {
int numBytes = numBits / 8;
byteOffset += numBytes;
bitOffset += numBits - (numBytes * 8);
if (bitOffset > 7) {
byteOffset++;
bitOffset -= 8;
}
assertValidOffset();
}
/**
@ -136,23 +108,22 @@ import com.google.android.exoplayer2.util.Assertions;
* @param position The new reading position in bits.
*/
public void setPosition(int position) {
Assertions.checkArgument(position < limit && position >= 0);
byteOffset = position / 8;
bitOffset = position - (byteOffset * 8);
assertValidOffset();
}
/**
* Returns the number of remaining bits.
*/
public int bitsLeft() {
return limit - getPosition();
return (byteLimit - byteOffset) * 8 - bitOffset;
}
/**
* Returns the limit in bits.
**/
public int limit() {
return limit;
private void assertValidOffset() {
// It is fine for position to be at the end of the array, but no further.
Assertions.checkState(byteOffset >= 0
&& (byteOffset < byteLimit || (byteOffset == byteLimit && bitOffset == 0)));
}
}