Commit 8378c3dc by olly Committed by Oliver Woodman

Simplify + optimize VorbisBitArray

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=161796758
parent 90398c58
...@@ -25,36 +25,26 @@ public final class VorbisBitArrayTest extends TestCase { ...@@ -25,36 +25,26 @@ public final class VorbisBitArrayTest extends TestCase {
public void testReadBit() { public void testReadBit() {
VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0x5c, 0x50)); VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0x5c, 0x50));
assertFalse(bitArray.readBit()); assertFalse(bitArray.readBit());
assertFalse(bitArray.readBit()); assertFalse(bitArray.readBit());
assertTrue(bitArray.readBit()); assertTrue(bitArray.readBit());
assertTrue(bitArray.readBit()); assertTrue(bitArray.readBit());
assertTrue(bitArray.readBit()); assertTrue(bitArray.readBit());
assertFalse(bitArray.readBit()); assertFalse(bitArray.readBit());
assertTrue(bitArray.readBit()); assertTrue(bitArray.readBit());
assertFalse(bitArray.readBit()); assertFalse(bitArray.readBit());
assertFalse(bitArray.readBit()); assertFalse(bitArray.readBit());
assertFalse(bitArray.readBit()); assertFalse(bitArray.readBit());
assertFalse(bitArray.readBit()); assertFalse(bitArray.readBit());
assertFalse(bitArray.readBit()); assertFalse(bitArray.readBit());
assertTrue(bitArray.readBit()); assertTrue(bitArray.readBit());
assertFalse(bitArray.readBit()); assertFalse(bitArray.readBit());
assertTrue(bitArray.readBit()); assertTrue(bitArray.readBit());
assertFalse(bitArray.readBit()); assertFalse(bitArray.readBit());
try {
assertFalse(bitArray.readBit());
fail();
} catch (IllegalStateException e) {/* ignored */}
} }
public void testSkipBits() { public void testSkipBits() {
VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xF0, 0x0F)); VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xF0, 0x0F));
bitArray.skipBits(10); bitArray.skipBits(10);
assertEquals(10, bitArray.getPosition()); assertEquals(10, bitArray.getPosition());
assertTrue(bitArray.readBit()); assertTrue(bitArray.readBit());
...@@ -64,27 +54,10 @@ public final class VorbisBitArrayTest extends TestCase { ...@@ -64,27 +54,10 @@ public final class VorbisBitArrayTest extends TestCase {
assertEquals(14, bitArray.getPosition()); assertEquals(14, bitArray.getPosition());
assertFalse(bitArray.readBit()); assertFalse(bitArray.readBit());
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 { public void testGetPosition() throws Exception {
VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xF0, 0x0F)); VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xF0, 0x0F));
assertEquals(0, bitArray.getPosition()); assertEquals(0, bitArray.getPosition());
bitArray.readBit(); bitArray.readBit();
assertEquals(1, bitArray.getPosition()); assertEquals(1, bitArray.getPosition());
...@@ -96,35 +69,11 @@ public final class VorbisBitArrayTest extends TestCase { ...@@ -96,35 +69,11 @@ public final class VorbisBitArrayTest extends TestCase {
public void testSetPosition() throws Exception { public void testSetPosition() throws Exception {
VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xF0, 0x0F)); VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xF0, 0x0F));
assertEquals(0, bitArray.getPosition()); assertEquals(0, bitArray.getPosition());
bitArray.setPosition(4); bitArray.setPosition(4);
assertEquals(4, bitArray.getPosition()); assertEquals(4, bitArray.getPosition());
bitArray.setPosition(15); bitArray.setPosition(15);
assertFalse(bitArray.readBit()); 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() { public void testReadInt32() {
...@@ -136,13 +85,11 @@ public final class VorbisBitArrayTest extends TestCase { ...@@ -136,13 +85,11 @@ public final class VorbisBitArrayTest extends TestCase {
public void testReadBits() throws Exception { public void testReadBits() throws Exception {
VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0x03, 0x22)); VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0x03, 0x22));
assertEquals(3, bitArray.readBits(2)); assertEquals(3, bitArray.readBits(2));
bitArray.skipBits(6); bitArray.skipBits(6);
assertEquals(2, bitArray.readBits(2)); assertEquals(2, bitArray.readBits(2));
bitArray.skipBits(2); bitArray.skipBits(2);
assertEquals(2, bitArray.readBits(2)); assertEquals(2, bitArray.readBits(2));
bitArray.reset(); bitArray.reset();
assertEquals(0x2203, bitArray.readBits(16)); assertEquals(0x2203, bitArray.readBits(16));
} }
...@@ -156,7 +103,6 @@ public final class VorbisBitArrayTest extends TestCase { ...@@ -156,7 +103,6 @@ public final class VorbisBitArrayTest extends TestCase {
public void testReadBitsBeyondByteBoundaries() throws Exception { public void testReadBitsBeyondByteBoundaries() throws Exception {
VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xFF, 0x0F, 0xFF, 0x0F)); VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xFF, 0x0F, 0xFF, 0x0F));
assertEquals(0x0FFF0FFF, bitArray.readBits(32)); assertEquals(0x0FFF0FFF, bitArray.readBits(32));
bitArray.reset(); bitArray.reset();
...@@ -188,83 +134,6 @@ public final class VorbisBitArrayTest extends TestCase { ...@@ -188,83 +134,6 @@ public final class VorbisBitArrayTest extends TestCase {
assertEquals(0, bitArray.getPosition()); assertEquals(0, bitArray.getPosition());
bitArray.readBit(); bitArray.readBit();
assertEquals(1, bitArray.getPosition()); 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());
}
} }
} }
...@@ -25,8 +25,9 @@ import com.google.android.exoplayer2.util.Assertions; ...@@ -25,8 +25,9 @@ import com.google.android.exoplayer2.util.Assertions;
*/ */
/* package */ final class VorbisBitArray { /* package */ final class VorbisBitArray {
public final byte[] data; private final byte[] data;
private final int limit; private final int byteLimit;
private int byteOffset; private int byteOffset;
private int bitOffset; private int bitOffset;
...@@ -36,18 +37,8 @@ import com.google.android.exoplayer2.util.Assertions; ...@@ -36,18 +37,8 @@ import com.google.android.exoplayer2.util.Assertions;
* @param data the array to wrap. * @param data the array to wrap.
*/ */
public VorbisBitArray(byte[] data) { 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.data = data;
this.limit = limit * 8; byteLimit = data.length;
} }
/** /**
...@@ -64,7 +55,9 @@ import com.google.android.exoplayer2.util.Assertions; ...@@ -64,7 +55,9 @@ import com.google.android.exoplayer2.util.Assertions;
* @return {@code true} if the bit is set, {@code false} otherwise. * @return {@code true} if the bit is set, {@code false} otherwise.
*/ */
public boolean readBit() { 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; ...@@ -74,53 +67,32 @@ import com.google.android.exoplayer2.util.Assertions;
* @return An integer whose bottom {@code numBits} bits hold the read data. * @return An integer whose bottom {@code numBits} bits hold the read data.
*/ */
public int readBits(int numBits) { public int readBits(int numBits) {
Assertions.checkState(getPosition() + numBits <= limit); int tempByteOffset = byteOffset;
if (numBits == 0) { int bitsRead = Math.min(numBits, 8 - bitOffset);
return 0; int returnValue = ((data[tempByteOffset++] & 0xFF) >> bitOffset) & (0xFF >> (8 - bitsRead));
} while (bitsRead < numBits) {
int result = 0; returnValue |= (data[tempByteOffset++] & 0xFF) << bitsRead;
int bitCount = 0; bitsRead += 8;
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;
} }
} returnValue &= 0xFFFFFFFF >>> (32 - numBits);
skipBits(numBits);
if (numBits > bitCount) { return returnValue;
int bitsOnNextByte = numBits - bitCount;
int mask = 0xFF >>> (8 - bitsOnNextByte);
result |= (data[byteOffset] & mask) << bitCount;
bitOffset += bitsOnNextByte;
}
return result;
} }
/** /**
* Skips {@code numberOfBits} bits. * 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) { public void skipBits(int numBits) {
Assertions.checkState(getPosition() + numberOfBits <= limit); int numBytes = numBits / 8;
byteOffset += numberOfBits / 8; byteOffset += numBytes;
bitOffset += numberOfBits % 8; bitOffset += numBits - (numBytes * 8);
if (bitOffset > 7) { if (bitOffset > 7) {
byteOffset++; byteOffset++;
bitOffset -= 8; bitOffset -= 8;
} }
assertValidOffset();
} }
/** /**
...@@ -136,23 +108,22 @@ import com.google.android.exoplayer2.util.Assertions; ...@@ -136,23 +108,22 @@ import com.google.android.exoplayer2.util.Assertions;
* @param position The new reading position in bits. * @param position The new reading position in bits.
*/ */
public void setPosition(int position) { public void setPosition(int position) {
Assertions.checkArgument(position < limit && position >= 0);
byteOffset = position / 8; byteOffset = position / 8;
bitOffset = position - (byteOffset * 8); bitOffset = position - (byteOffset * 8);
assertValidOffset();
} }
/** /**
* Returns the number of remaining bits. * Returns the number of remaining bits.
*/ */
public int bitsLeft() { public int bitsLeft() {
return limit - getPosition(); return (byteLimit - byteOffset) * 8 - bitOffset;
} }
/** private void assertValidOffset() {
* Returns the limit in bits. // It is fine for position to be at the end of the array, but no further.
**/ Assertions.checkState(byteOffset >= 0
public int limit() { && (byteOffset < byteLimit || (byteOffset == byteLimit && bitOffset == 0)));
return limit;
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment