[Scummvm-cvs-logs] SF.net SVN: scummvm:[33419] scummvm/trunk

fingolfin at users.sourceforge.net fingolfin at users.sourceforge.net
Tue Jul 29 19:42:20 CEST 2008


Revision: 33419
          http://scummvm.svn.sourceforge.net/scummvm/?rev=33419&view=rev
Author:   fingolfin
Date:     2008-07-29 17:42:19 +0000 (Tue, 29 Jul 2008)

Log Message:
-----------
Added two new classes, BufferedReadStream & BufferedSeekableReadStream, as proposed on scummvm-devel

Modified Paths:
--------------
    scummvm/trunk/common/stream.cpp
    scummvm/trunk/common/stream.h
    scummvm/trunk/test/common/seekablesubreadstream.h
    scummvm/trunk/test/common/subreadstream.h

Added Paths:
-----------
    scummvm/trunk/test/common/bufferedreadstream.h
    scummvm/trunk/test/common/bufferedseekablereadstream.h

Modified: scummvm/trunk/common/stream.cpp
===================================================================
--- scummvm/trunk/common/stream.cpp	2008-07-29 17:38:07 UTC (rev 33418)
+++ scummvm/trunk/common/stream.cpp	2008-07-29 17:42:19 UTC (rev 33419)
@@ -242,4 +242,85 @@
 	_parentStream->seek(_pos);
 }
 
+BufferedReadStream::BufferedReadStream(ReadStream *parentStream, uint32 bufSize, bool disposeParentStream)
+	: _parentStream(parentStream),
+	_bufSize(bufSize),
+	_disposeParentStream(disposeParentStream) {
+
+	assert(parentStream);
+	_buf = new byte[_bufSize];
+	assert(_buf);
+	_pos = _bufSize = bufSize;
+}
+BufferedReadStream::~BufferedReadStream() {
+	if (_disposeParentStream)
+		delete _parentStream;
+	delete _buf;
+}
+
+uint32 BufferedReadStream::read(void *dataPtr, uint32 dataSize) {
+	uint32 alreadyRead = 0;
+	const uint32 bufBytesLeft = _bufSize - _pos;
+
+	// Check whether the data left in the buffer suffices....
+	if (dataSize > bufBytesLeft) {
+		// Nope, we need to read more data
+
+		// First, flush the buffer, if it is non-empty
+		if (0 < bufBytesLeft) {
+			memcpy(dataPtr, _buf + _pos, bufBytesLeft);
+			_pos = _bufSize;
+			alreadyRead += bufBytesLeft;
+			dataPtr = (byte *)dataPtr + bufBytesLeft;
+			dataSize -= bufBytesLeft;
+		}
+			
+		// At this point the buffer is empty. Now if the read request
+		// exceeds the buffer size, just satisfy it directly.
+		if (dataSize > _bufSize)
+			return alreadyRead + _parentStream->read(dataPtr, dataSize);
+
+		// Refill the buffer.
+		uint32 bytesRead = _parentStream->read(_buf, _bufSize);
+		_pos = 0;
+		
+		// If we didn't read as many bytes as requested, the reason
+		// is EOF or an error. In that case we truncate the buffer
+		// size, as well as the number of  bytes we are going to
+		// return to the caller.
+		if (_bufSize > bytesRead) {
+			_bufSize = bytesRead;
+			if (dataSize > bytesRead)
+				dataSize = bytesRead;
+		}
+	}
+
+	// Satisfy the request from the buffer
+	memcpy(dataPtr, _buf + _pos, dataSize);
+	_pos += dataSize;
+	return alreadyRead + dataSize;
+}
+
+BufferedSeekableReadStream::BufferedSeekableReadStream(SeekableReadStream *parentStream, uint32 bufSize, bool disposeParentStream)
+	: BufferedReadStream(parentStream, bufSize, disposeParentStream),
+	_parentStream(parentStream) {
+}
+
+void BufferedSeekableReadStream::seek(int32 offset, int whence) {
+	// If it is a "local" seek, we may get away with "seeking" around
+	// in the buffer only.
+	// Note: We could try to handle SEEK_END and SEEK_SET, too, but
+	// since they are rarely used, it seems not worth the effort.
+	if (whence == SEEK_CUR && (int)_pos + offset >= 0 && _pos + offset <= _bufSize) {
+		_pos += offset;
+	} else {
+		// Seek was not local enough, so we reset the buffer and
+		// just seeks normally in the parent stream.
+		if (whence == SEEK_CUR)
+			offset -= (_bufSize - _pos);
+		_pos = _bufSize;
+		_parentStream->seek(offset, whence);
+	}
+}
+
 }	// End of namespace Common

Modified: scummvm/trunk/common/stream.h
===================================================================
--- scummvm/trunk/common/stream.h	2008-07-29 17:38:07 UTC (rev 33418)
+++ scummvm/trunk/common/stream.h	2008-07-29 17:42:19 UTC (rev 33419)
@@ -350,15 +350,17 @@
 class SubReadStream : virtual public ReadStream {
 protected:
 	ReadStream *_parentStream;
+	bool _disposeParentStream;
 	uint32 _pos;
 	uint32 _end;
-	bool _disposeParentStream;
 public:
 	SubReadStream(ReadStream *parentStream, uint32 end, bool disposeParentStream = false)
 		: _parentStream(parentStream),
 		  _pos(0),
 		  _end(end),
-		  _disposeParentStream(disposeParentStream) {}
+		  _disposeParentStream(disposeParentStream) {
+		assert(parentStream);
+	}
 	~SubReadStream() {
 		if (_disposeParentStream) delete _parentStream;
 	}
@@ -414,8 +416,49 @@
 	}
 };
 
+/**
+ * Wrapper class which adds buffering to any given ReadStream.
+ * Users can specify how big the buffer should be, and whether the
+ * wrapped stream should be disposed when the wrapper is disposed.
+ */
+class BufferedReadStream : virtual public ReadStream {
+protected:
+	ReadStream *_parentStream;
+	bool _disposeParentStream;
+	byte *_buf;
+	uint32 _pos;
+	uint32 _bufSize;
 
+public:
+	BufferedReadStream(ReadStream *parentStream, uint32 bufSize, bool disposeParentStream = false);
+	~BufferedReadStream();
+
+	virtual bool eos() const { return (_pos == _bufSize) && _parentStream->eos(); }
+	virtual bool ioFailed() const { return _parentStream->ioFailed(); }
+	virtual void clearIOFailed() { _parentStream->clearIOFailed(); }
+
+	virtual uint32 read(void *dataPtr, uint32 dataSize);
+};
+
 /**
+ * Wrapper class which adds buffering to any given SeekableReadStream.
+ * @see BufferedReadStream
+ */
+class BufferedSeekableReadStream : public BufferedReadStream, public SeekableReadStream {
+protected:
+	SeekableReadStream *_parentStream;
+public:
+	BufferedSeekableReadStream(SeekableReadStream *parentStream, uint32 bufSize, bool disposeParentStream = false);
+
+	virtual uint32 pos() const { return _parentStream->pos() - (_bufSize - _pos); }
+	virtual uint32 size() const { return _parentStream->size(); }
+
+	virtual void seek(int32 offset, int whence = SEEK_SET);
+};
+
+
+
+/**
  * Simple memory based 'stream', which implements the ReadStream interface for
  * a plain memory block.
  */

Added: scummvm/trunk/test/common/bufferedreadstream.h
===================================================================
--- scummvm/trunk/test/common/bufferedreadstream.h	                        (rev 0)
+++ scummvm/trunk/test/common/bufferedreadstream.h	2008-07-29 17:42:19 UTC (rev 33419)
@@ -0,0 +1,27 @@
+#include <cxxtest/TestSuite.h>
+
+#include "common/stream.h"
+
+class BufferedReadStreamTestSuite : public CxxTest::TestSuite {
+	public:
+	void test_traverse(void) {
+		byte contents[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+		Common::MemoryReadStream ms(contents, 10);
+
+		// Use a buffer size of 4 -- note that 10 % 4 != 0,
+		// so we test what happens if the cache can't be completly
+		// refilled.
+		Common::BufferedReadStream srs(&ms, 4);
+
+		int i;
+		byte b;
+		for (i = 0; i < 10; ++i) {
+			TS_ASSERT( !srs.eos() );
+
+			b = srs.readByte();
+			TS_ASSERT_EQUALS( i, b );
+		}
+
+		TS_ASSERT( srs.eos() );
+	}
+};


Property changes on: scummvm/trunk/test/common/bufferedreadstream.h
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Added: scummvm/trunk/test/common/bufferedseekablereadstream.h
===================================================================
--- scummvm/trunk/test/common/bufferedseekablereadstream.h	                        (rev 0)
+++ scummvm/trunk/test/common/bufferedseekablereadstream.h	2008-07-29 17:42:19 UTC (rev 33419)
@@ -0,0 +1,65 @@
+#include <cxxtest/TestSuite.h>
+
+#include "common/stream.h"
+
+class BufferedSeekableReadStreamTestSuite : public CxxTest::TestSuite {
+	public:
+	void test_traverse(void) {
+		byte contents[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+		Common::MemoryReadStream ms(contents, 10);
+
+		Common::BufferedSeekableReadStream ssrs(&ms, 4);
+
+		int i;
+		byte b;
+		for (i = 0; i < 10; ++i) {
+			TS_ASSERT( !ssrs.eos() );
+
+			TS_ASSERT_EQUALS( i, ssrs.pos() );
+
+			ssrs.read(&b, 1);
+			TS_ASSERT_EQUALS( i, b );
+		}
+
+		TS_ASSERT( ssrs.eos() );
+	}
+
+	void test_seek(void) {
+		byte contents[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+		Common::MemoryReadStream ms(contents, 10);
+
+		Common::BufferedSeekableReadStream ssrs(&ms, 4);
+		byte b;
+
+		TS_ASSERT_EQUALS( ssrs.pos(), (uint32)0 );
+
+		ssrs.seek(1, SEEK_SET);
+		TS_ASSERT_EQUALS( ssrs.pos(), (uint32)1 );
+		b = ssrs.readByte();
+		TS_ASSERT_EQUALS( b, 1 );
+
+		ssrs.seek(5, SEEK_CUR);
+		TS_ASSERT_EQUALS( ssrs.pos(), (uint32)7 );
+		b = ssrs.readByte();
+		TS_ASSERT_EQUALS( b, 7 );
+
+		ssrs.seek(-3, SEEK_CUR);
+		TS_ASSERT_EQUALS( ssrs.pos(), (uint32)5 );
+		b = ssrs.readByte();
+		TS_ASSERT_EQUALS( b, 5 );
+
+		ssrs.seek(0, SEEK_END);
+		TS_ASSERT_EQUALS( ssrs.pos(), (uint32)10 );
+		TS_ASSERT( ssrs.eos() );
+
+		ssrs.seek(3, SEEK_END);
+		TS_ASSERT_EQUALS( ssrs.pos(), (uint32)7 );
+		b = ssrs.readByte();
+		TS_ASSERT_EQUALS( b, 7 );
+
+		ssrs.seek(8, SEEK_END);
+		TS_ASSERT_EQUALS( ssrs.pos(), (uint32)2 );
+		b = ssrs.readByte();
+		TS_ASSERT_EQUALS( b, 2 );
+	}
+};


Property changes on: scummvm/trunk/test/common/bufferedseekablereadstream.h
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Modified: scummvm/trunk/test/common/seekablesubreadstream.h
===================================================================
--- scummvm/trunk/test/common/seekablesubreadstream.h	2008-07-29 17:38:07 UTC (rev 33418)
+++ scummvm/trunk/test/common/seekablesubreadstream.h	2008-07-29 17:42:19 UTC (rev 33419)
@@ -2,22 +2,19 @@
 
 #include "common/stream.h"
 
-class SeekableSubReadStreamTestSuite : public CxxTest::TestSuite
-{
+class SeekableSubReadStreamTestSuite : public CxxTest::TestSuite {
 	public:
-	void test_traverse( void )
-	{
+	void test_traverse(void) {
 		byte contents[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
-		Common::MemoryReadStream ms = Common::MemoryReadStream(contents, 10);
+		Common::MemoryReadStream ms(contents, 10);
 
 		int start = 2, end = 8;
 
-		Common::SeekableSubReadStream ssrs = Common::SeekableSubReadStream(&ms, start, end);
+		Common::SeekableSubReadStream ssrs(&ms, start, end);
 
 		int i;
 		byte b;
-		for (i = start; i < end; ++i)
-		{
+		for (i = start; i < end; ++i) {
 			TS_ASSERT( !ssrs.eos() );
 
 			TS_ASSERT_EQUALS( uint32(i - start), ssrs.pos() );
@@ -29,12 +26,11 @@
 		TS_ASSERT( ssrs.eos() );
 	}
 
-	void test_seek( void )
-	{
+	void test_seek(void) {
 		byte contents[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
-		Common::MemoryReadStream ms = Common::MemoryReadStream(contents, 10);
+		Common::MemoryReadStream ms(contents, 10);
 
-		Common::SeekableSubReadStream ssrs = Common::SeekableSubReadStream(&ms, 1, 9);
+		Common::SeekableSubReadStream ssrs(&ms, 1, 9);
 		byte b;
 
 		TS_ASSERT_EQUALS( ssrs.pos(), (uint32)0 );

Modified: scummvm/trunk/test/common/subreadstream.h
===================================================================
--- scummvm/trunk/test/common/subreadstream.h	2008-07-29 17:38:07 UTC (rev 33418)
+++ scummvm/trunk/test/common/subreadstream.h	2008-07-29 17:42:19 UTC (rev 33419)
@@ -2,25 +2,22 @@
 
 #include "common/stream.h"
 
-class SubReadStreamTestSuite : public CxxTest::TestSuite
-{
+class SubReadStreamTestSuite : public CxxTest::TestSuite {
 	public:
-	void test_traverse( void )
-	{
+	void test_traverse(void) {
 		byte contents[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
-		Common::MemoryReadStream ms = Common::MemoryReadStream(contents, 10);
+		Common::MemoryReadStream ms(contents, 10);
 
 		int end = 5;
 
-		Common::SubReadStream srs = Common::SubReadStream(&ms, end);
+		Common::SubReadStream srs(&ms, end);
 
 		int i;
 		byte b;
-		for (i = 0; i < end; ++i)
-		{
+		for (i = 0; i < end; ++i) {
 			TS_ASSERT( !srs.eos() );
 
-			srs.read(&b, 1);
+			b = srs.readByte();
 			TS_ASSERT_EQUALS( i, b );
 		}
 


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list