YXD's Blog

Home Contact Syndicate this Site (RSS 2.0) Syndicate this Site (Atom) 登录
  随笔 18 :: 收藏 1 :: 评论 0 :: 寻迹: 1

随笔

随笔归档

收藏

图库

Friends' Blogs

from cndev

Technical Blogs

2004-12-20 #

早先简单封装了一个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之间的直接通信支持,不过比较容易实现。

发表于 @ 14:31 | 评论与反馈 (6)