早先简单封装了一个CByteStream类(继承了IStream COM接口),但是很低效,且不够灵活。利用周末的两天实现了如下定义的通用内存流类。
template
<
class _Ty,
template < class > class _ThreadingModel = DefaultThreadingModel,
template < class > class _Allocator = ::std::allocator,
class _Size = long,
_Size _block_size = 4096
>
class MemoryStream: public _ThreadingModel< MemoryStream< _Ty, _ThreadingModel, _Allocator > >
{
public:
typedef _Ty value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef _ThreadingModel< MemoryStream< _Ty, _ThreadingModel, _Allocator > > ThreadingModel;
typedef _Allocator< _Ty > block_allocator;
typedef _Size size_t;
//
// ...
//
}
除了内存管理器(Allocator)外与内存相关访问的封装:
template < class _Ty, class _Size = unsigned int >
struct MemCopier
{
_Ty* operator()( _Ty* pDest, const _Ty* pSrc, _Size cbCopy )
{
::memcpy( pDest, pSrc, cbCopy * sizeof( _Ty ) );
return pDest;
}
};
提供如下公开的调用接口:
函数:
// Read a specified number of type_sizes from the stream object
// into memory, starting at the current seek pointer.
// Return the actual number of type_sizes read from the stream
// object.
size_t Read( pointer pBuf, size_t cbRead )
// Write a specified number of type_sizes into the stream object
// starting at the current seek pointer.
// Return the actual number of type_sizes written into the stream
// object.
size_t Write( const_pointer pBuf, size_t cbWrite )
// Copy a specified number of bytes from the current seek pointer
// in the stream to the current seek pointer in another stream.
size_t CopyTo( MemoryStream& stream, size_t cbCopy )
// Generic version of CopyTo function
template < class _OutStream >
size_t CopyTo( _OutStream& stream, size_t cbCopy )
// Getneric CopyFrom function
template < class _InStream >
size_t CopyFrom( const _InStream& stream, size_t cbCopy )
// Move the stream pointer to a specified location.
// Return the new position of the stream pointer.
size_t Seek( size_t offset, int nSeekMode = MemoryBase::seek_cur )
// Release the memory space occupied by the stream object.
void Clear()
// Return the number of type_sizes of the data existing in the
// stream object.
size_t GetSize() const
// Return the current position of the pointer of the stream object.
size_t Tell() const
// Judge whether the stream pointer is at the end of the stream
// object.
bool End() const
// Judge whether the stream object has data.
bool Empty() const
操作符:
MemoryStream& operator = ( const MemoryStream& stream )
// operator >>
MemoryStream& operator >> ( const_reference vInput )
MemoryStream& operator >> ( const_pointer pInput )
template < class _InStream >
MemoryStream& operator >> ( const _InStream& stream )
MemoryStream& operator >> ( MemoryStream& stream )
// operator <<
MemoryStream& operator << ( reference vOutput )
MemoryStream& operator << ( pointer pOutput )
template < class _OutStream >
MemoryStream& operator << ( _OutStream& stream )
MemoryStream& operator << ( MemoryStream& stream )
几个测试用例如下:
void Test1()
{
fstream infile;
infile.open( "E:\\yxd\\fuzhuang.mpg", ios_base::in | ios_base::binary );
MemoryStream< char > theStream;
theStream >> infile;
infile.close();
fstream outfile;
outfile.open( "E:\\fuzhuang.mpg", ios_base::out | ios_base::binary );
theStream.Seek( 0, MemoryBase::seek_set );
theStream << outfile;
outfile.close();
}
void Test2()
{
MemoryStream< char > theStream;
for ( char n = 'a'; n < 'z' + 1; ++ n )
theStream >> n;
theStream >> 'A';
theStream.Seek( 0, MemoryBase::seek_set );
theStream << cout;
cout << endl;
char szText[] = "this is a test.";
theStream.Write( szText, MemoryStream< char >::size_t( strlen( szText ) ) );
theStream.Seek( 0, MemoryBase::seek_set );
theStream << cout;
cout << endl;
theStream.Seek( 10, MemoryBase::seek_end );
theStream << cout;
cout << endl;
theStream.Seek( -20, MemoryBase::seek_cur );
theStream << cout;
cout << endl;
MemoryStream< char > theStream1( theStream );
theStream1 << cout;
cout << endl;
MemoryStream< char > theStream2 = theStream1;
theStream2 << cout;
cout << endl;
MemoryStream< char > theStream3;
theStream2.Seek( 13, MemoryBase::seek_set );
theStream3 >> theStream2;
theStream3.Seek( 0, MemoryBase::seek_set );
theStream3 << cout;
cout << endl;
char szRead[256] = { 0 };
theStream.Seek( 0, MemoryBase::seek_set );
cout << "Total read size is " << theStream.Read( szRead, 256 ) << " bytes:" << endl;
cout << szRead << endl;
}
void Test3()
{
MemoryStream< char > theStream1;
theStream1.CopyFrom( cin, 10 );
theStream1.Seek( -10 );
theStream1 << cout;
cout << endl;
theStream1.Seek( 0, MemoryBase::seek_set );
MemoryStream< char > theStream2;
theStream1.CopyTo( theStream2, theStream2.GetSize() );
theStream2.Seek( 0, MemoryBase::seek_set );
theStream2 << cout;
cout << endl;
MemoryStream< char > theStream3;
theStream1.Seek( 5, MemoryBase::seek_set );
cout << "Copied " << theStream1.CopyTo( theStream3, theStream1.GetSize() ) << " bytes from theStream1 to theStream3:" << endl;
theStream3.Seek( 0, MemoryBase::seek_set );
theStream3 << cout;
cout << endl;
}
void Test4()
{
MemoryStream< char, ::Loki::ObjectLevelLockable >* theLockableStream = new MemoryStream< char, ::Loki::ObjectLevelLockable >;
for ( unsigned char c = 0; c < 255; ++ c )
*theLockableStream >> char( c );
theLockableStream->Seek( 0, MemoryBase::seek_set );
*theLockableStream << cout;
cout << endl;
//RunStreamPrint( theLockableStream );// Thread #1
//RunStreamPrint( theLockableStream );// Thread #2
//RunStreamPrint( theLockableStream );// Thread #3
//RunStreamPrint( theLockableStream );// Thread #4
//RunStreamPrint( theLockableStream );// Thread #5
//RunStreamPrint( theLockableStream );// Thread #6
}
MemoryStream内部的内存组织方式采用的是基于::std::map这样的索引方式,采用散列的方式在大多数情况下性能应该会有更好的表现,但是这样代码的复杂性会增加,所以我就借用了::std::map,这层针对MemoryStream内部内存结构的组织策略原本也向上一层延迟,交给用户自己决定,但是还是复杂性太高,俺也没想出太好的方法,并且不像线程模型、allocator这样的有很多现成的东西可供选择。另外暂时还缺少对模板参数_Ty一样的MemoryStream之间的直接通信支持,不过比较容易实现。