diff --git a/common/bitstream.h b/common/bitstream.h index c5226d512492..e867d86ea77b 100644 --- a/common/bitstream.h +++ b/common/bitstream.h @@ -269,6 +269,152 @@ class BitStreamImpl { } }; + + +/** + * A cut-down version of MemoryReadStream specifically for use with BitStream. + * It removes the virtual call overhead for reading bytes from a memory buffer, + * and allows directly inlining this access. + * + * The code duplication with MemoryReadStream is not ideal. + * It might be possible to avoid this by making this a final subclass of + * MemoryReadStream, but that is a C++11 feature. + */ +class BitStreamMemoryStream { +private: + const byte * const _ptrOrig; + const byte *_ptr; + const uint32 _size; + uint32 _pos; + DisposeAfterUse::Flag _disposeMemory; + bool _eos; + +public: + BitStreamMemoryStream(const byte *dataPtr, uint32 dataSize, DisposeAfterUse::Flag disposeMemory = DisposeAfterUse::NO) : + _ptrOrig(dataPtr), + _ptr(dataPtr), + _size(dataSize), + _pos(0), + _disposeMemory(disposeMemory), + _eos(false) {} + + ~BitStreamMemoryStream() { + if (_disposeMemory) + free(const_cast(_ptrOrig)); + } + + bool eos() const { + return _eos; + } + + bool err() const { + return false; + } + + int32 pos() const { + return _pos; + } + + int32 size() const { + return _size; + } + + bool seek(uint32 offset) { + assert(offset <= _size); + + _eos = false; + _pos = offset; + _ptr = _ptrOrig + _pos; + return true; + } + + byte readByte() { + if (_pos >= _size) { + _eos = true; + return 0; + } + + _pos++; + return *_ptr++; + } + + uint16 readUint16LE() { + if (_pos + 2 > _size) { + _eos = true; + if (_pos < _size) { + _pos++; + return *_ptr++; + } else { + return 0; + } + } + + uint16 val = READ_LE_UINT16(_ptr); + + _pos += 2; + _ptr += 2; + + return val; + } + + uint16 readUint16BE() { + if (_pos + 2 > _size) { + _eos = true; + if (_pos < _size) { + _pos++; + return (*_ptr++) << 8; + } else { + return 0; + } + } + + uint16 val = READ_LE_UINT16(_ptr); + + _pos += 2; + _ptr += 2; + + return val; + } + + uint32 readUint32LE() { + if (_pos + 4 > _size) { + uint32 val = readByte(); + val |= (uint32)readByte() << 8; + val |= (uint32)readByte() << 16; + val |= (uint32)readByte() << 24; + + return val; + } + + uint32 val = READ_LE_UINT32(_ptr); + + _pos += 4; + _ptr += 4; + + return val; + } + + uint32 readUint32BE() { + if (_pos + 4 > _size) { + uint32 val = (uint32)readByte() << 24; + val |= (uint32)readByte() << 16; + val |= (uint32)readByte() << 8; + val |= (uint32)readByte(); + + return val; + } + + uint32 val = READ_BE_UINT32(_ptr); + + _pos += 4; + _ptr += 4; + + return val; + } + +}; + + // typedefs for various memory layouts. /** 8-bit data, MSB to LSB. */ @@ -294,6 +440,32 @@ typedef BitStreamImpl BitStream32BEMSB; /** 32-bit big-endian data, LSB to MSB. */ typedef BitStreamImpl BitStream32BELSB; + + +/** 8-bit data, MSB to LSB. */ +typedef BitStreamImpl BitStreamMemory8MSB; +/** 8-bit data, LSB to MSB. */ +typedef BitStreamImpl BitStreamMemory8LSB; + +/** 16-bit little-endian data, MSB to LSB. */ +typedef BitStreamImpl BitStreamMemory16LEMSB; +/** 16-bit little-endian data, LSB to MSB. */ +typedef BitStreamImpl BitStreamMemory16LELSB; +/** 16-bit big-endian data, MSB to LSB. */ +typedef BitStreamImpl BitStreamMemory16BEMSB; +/** 16-bit big-endian data, LSB to MSB. */ +typedef BitStreamImpl BitStreamMemory16BELSB; + +/** 32-bit little-endian data, MSB to LSB. */ +typedef BitStreamImpl BitStreamMemory32LEMSB; +/** 32-bit little-endian data, LSB to MSB. */ +typedef BitStreamImpl BitStreamMemory32LELSB; +/** 32-bit big-endian data, MSB to LSB. */ +typedef BitStreamImpl BitStreamMemory32BEMSB; +/** 32-bit big-endian data, LSB to MSB. */ +typedef BitStreamImpl BitStreamMemory32BELSB; + + } // End of namespace Common #endif // COMMON_BITSTREAM_H diff --git a/test/common/bitstream.h b/test/common/bitstream.h index 3f6a15fcd879..0488169183cd 100644 --- a/test/common/bitstream.h +++ b/test/common/bitstream.h @@ -5,13 +5,14 @@ class BitStreamTestSuite : public CxxTest::TestSuite { - public: - void test_get_bit() { +private: + template + void tmpl_get_bit() { byte contents[] = { 'a' }; - Common::MemoryReadStream ms(contents, sizeof(contents)); + MS ms(contents, sizeof(contents)); - Common::BitStream8MSB bs(ms); + BS bs(ms); TS_ASSERT_EQUALS(bs.pos(), 0u); TS_ASSERT_EQUALS(bs.getBit(), 0u); TS_ASSERT_EQUALS(bs.getBit(), 1u); @@ -19,13 +20,20 @@ class BitStreamTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS(bs.pos(), 3u); TS_ASSERT(!bs.eos()); } +public: + void test_get_bit() { + tmpl_get_bit(); + tmpl_get_bit(); + } - void test_get_bits() { +private: + template + void tmpl_get_bits() { byte contents[] = { 'a', 'b' }; - Common::MemoryReadStream ms(contents, sizeof(contents)); + MS ms(contents, sizeof(contents)); - Common::BitStream8MSB bs(ms); + BS bs(ms); TS_ASSERT_EQUALS(bs.pos(), 0u); TS_ASSERT_EQUALS(bs.getBits(3), 3u); TS_ASSERT_EQUALS(bs.pos(), 3u); @@ -33,13 +41,20 @@ class BitStreamTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS(bs.pos(), 11u); TS_ASSERT(!bs.eos()); } +public: + void test_get_bits() { + tmpl_get_bits(); + tmpl_get_bits(); + } - void test_skip() { +private: + template + void tmpl_skip() { byte contents[] = { 'a', 'b' }; - Common::MemoryReadStream ms(contents, sizeof(contents)); + MS ms(contents, sizeof(contents)); - Common::BitStream8MSB bs(ms); + BS bs(ms); TS_ASSERT_EQUALS(bs.pos(), 0u); bs.skip(5); TS_ASSERT_EQUALS(bs.pos(), 5u); @@ -48,13 +63,20 @@ class BitStreamTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS(bs.getBits(3), 6u); TS_ASSERT(!bs.eos()); } +public: + void test_skip() { + tmpl_skip(); + tmpl_skip(); + } - void test_rewind() { +private: + template + void tmpl_rewind() { byte contents[] = { 'a' }; - Common::MemoryReadStream ms(contents, sizeof(contents)); + MS ms(contents, sizeof(contents)); - Common::BitStream8MSB bs(ms); + BS bs(ms); TS_ASSERT_EQUALS(bs.pos(), 0u); bs.skip(5); TS_ASSERT_EQUALS(bs.pos(), 5u); @@ -65,13 +87,20 @@ class BitStreamTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS(bs.size(), 8u); } +public: + void test_rewind() { + tmpl_rewind(); + tmpl_rewind(); + } - void test_peek_bit() { +private: + template + void tmpl_peek_bit() { byte contents[] = { 'a' }; - Common::MemoryReadStream ms(contents, sizeof(contents)); + MS ms(contents, sizeof(contents)); - Common::BitStream8MSB bs(ms); + BS bs(ms); TS_ASSERT_EQUALS(bs.pos(), 0u); TS_ASSERT_EQUALS(bs.peekBit(), 0u); TS_ASSERT_EQUALS(bs.pos(), 0u); @@ -81,13 +110,20 @@ class BitStreamTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS(bs.pos(), 1u); TS_ASSERT(!bs.eos()); } +public: + void test_peek_bit() { + tmpl_peek_bit(); + tmpl_peek_bit(); + } - void test_peek_bits() { +private: + template + void tmpl_peek_bits() { byte contents[] = { 'a', 'b' }; - Common::MemoryReadStream ms(contents, sizeof(contents)); + MS ms(contents, sizeof(contents)); - Common::BitStream8MSB bs(ms); + BS bs(ms); TS_ASSERT_EQUALS(bs.pos(), 0u); TS_ASSERT_EQUALS(bs.peekBits(3), 3u); TS_ASSERT_EQUALS(bs.pos(), 0u); @@ -100,13 +136,20 @@ class BitStreamTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS(bs.peekBits(5), 2u); TS_ASSERT(!bs.eos()); } +public: + void test_peek_bits() { + tmpl_peek_bits(); + tmpl_peek_bits(); + } - void test_eos() { +private: + template + void tmpl_eos() { byte contents[] = { 'a', 'b' }; - Common::MemoryReadStream ms(contents, sizeof(contents)); + MS ms(contents, sizeof(contents)); - Common::BitStream8MSB bs(ms); + BS bs(ms); bs.skip(11); TS_ASSERT_EQUALS(bs.pos(), 11u); TS_ASSERT_EQUALS(bs.getBits(5), 2u); @@ -116,13 +159,20 @@ class BitStreamTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS(bs.pos(), 0u); TS_ASSERT(!bs.eos()); } +public: + void test_eos() { + tmpl_eos(); + tmpl_eos(); + } - void test_get_bits_lsb() { +private: + template + void tmpl_get_bits_lsb() { byte contents[] = { 'a', 'b' }; - Common::MemoryReadStream ms(contents, sizeof(contents)); + MS ms(contents, sizeof(contents)); - Common::BitStream8LSB bs(ms); + BS bs(ms); TS_ASSERT_EQUALS(bs.pos(), 0u); TS_ASSERT_EQUALS(bs.getBits(3), 1u); TS_ASSERT_EQUALS(bs.pos(), 3u); @@ -130,13 +180,20 @@ class BitStreamTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS(bs.pos(), 11u); TS_ASSERT(!bs.eos()); } +public: + void test_get_bits_lsb() { + tmpl_get_bits_lsb(); + tmpl_get_bits_lsb(); + } - void test_peek_bits_lsb() { +private: + template + void tmpl_peek_bits_lsb() { byte contents[] = { 'a', 'b' }; - Common::MemoryReadStream ms(contents, sizeof(contents)); + MS ms(contents, sizeof(contents)); - Common::BitStream8LSB bs(ms); + BS bs(ms); TS_ASSERT_EQUALS(bs.pos(), 0u); TS_ASSERT_EQUALS(bs.peekBits(3), 1u); TS_ASSERT_EQUALS(bs.pos(), 0u); @@ -149,4 +206,9 @@ class BitStreamTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS(bs.peekBits(5), 12u); TS_ASSERT(!bs.eos()); } +public: + void test_peek_bits_lsb() { + tmpl_peek_bits_lsb(); + tmpl_peek_bits_lsb(); + } };