利用内存chunk充当数据buffer的vector的实现,和STL vector 有接口操作性能比较

来源:互联网 发布:阿里云虚拟主机 mysql 编辑:程序博客网 时间:2024/04/29 20:52

问题描述:

1.vector是最常用到的容器,它其实是一种自动扩充的动态数组,底层实现通过两倍扩展,

   所以再不能预知要存入元素多少时,难免要两倍扩展,这带来了拷贝所存对象的开销;

2.本文尝试利用memory chunk作为底层存储容器来避免动态扩展时copy 开销;

3.本实现屏蔽了STL  vector 一些接口比如erase,主要是为了减轻实现复杂性考虑;

4.它支持两边插入和删除操作,其接口功能完全等同于STL 的deque;

5.和STL vector 做了push_back, pop_back, at 操作性能比较,结果如下:

    1)push_back 操作,性能改善了4-5倍;

    2)at操作,基本上相当;

    3)pop_back性能变慢了3-4倍;

    4)  尽管pop_back性能变慢了,但是我的实现内存大小是可伸缩的;


程序代码:


#ifndef _ALVECTOR_H_#define _ALVECTOR_H_#include <vector>#include "windows.h"/** the class encapsulate dynamic array the same as STL vector from function* it have different underlying storage with STL vector* it apply to memory chunk tech linked the chunk by next point* it have good insert performance because no copy burden when full storage* */template<class T>class AlVector{public:/** memory chunk(storage chunk) for interval using **/enum {KSlotCount = 64};int m_totalCount;int m_count;struct Buffer{T        buf[KSlotCount];Buffer*  next;Buffer():next(0){memset( buf, 0x00, sizeof(buf) );}};/** Constructor**/AlVector():m_totalCount(0), m_count(0),       m_chunkHead(0), m_chunkSize(0),    m_chunkCapacity(0){InitChunkIndex();m_dataBuffer = &m_initBuffer;AssignChunkIndex( m_dataBuffer );}/** Copy Constructor**/AlVector( const AlVector& rhs ){size_t len = rhs.Size();for( size_t i = 0; i < len; i++ )this->PushBack( rhs[i] );}/** Assignment operator overload**/AlVector& operator = ( const AlVector& rhs ){if( this != &rhs ){Clear();size_t len = rhs.Size();for( size_t i = 0; i < len; i++ )this->PushBack( rhs[i] );}return *this;}/** Destructor**/~AlVector(){Clear();}/****/T& operator [] ( size_t index ){return At( index );}/****/const T& operator[] ( size_t index ) const {return At( index );}/** Check whether or not exist element**/bool IsEmpty(){return m_totalCount == 0;}/** Retrieve the number of elements in container**/size_t Size() const {return m_totalCount;}/** Clear all object pushed and memory**/void Clear(){while( m_dataBuffer != &m_initBuffer ){Buffer* buf = m_dataBuffer;m_dataBuffer = m_dataBuffer->next;delete buf;}delete [] m_chunkHead;m_chunkHead = 0;m_chunkSize = m_chunkCapacity = 0;}/** Push element to container tail **/void PushBack( const T& data ){*Push() = data;}/** Pop element from container tail**/void PopBack(){m_totalCount--;if( --m_count == 0 ){if( m_dataBuffer != &m_initBuffer ){Buffer* buf = m_dataBuffer;m_dataBuffer = m_dataBuffer->next;//importantm_chunkHead[m_chunkSize] = 0;m_chunkSize--;delete buf;buf = 0;// reset the value of m_countm_count = KSlotCount;}}}/** Retrieve the element of header in container**/T& Front(){return m_chunkHead[0]->buf[0];}/** Retrieve the element of header in container**/const T& Front() const{return Front();}/** Retrieve the element of tail in container**/T& Back(){return Back()}/** Retrieve the element of tail in container**/const T& Back() const {assert( m_count > 0 );return m_dataBuffer[ m_count - 1 ];}/** Retrieve the element by terms of position index**/T& At( size_t index ){assert( index < m_totalCount );if( index < KSlotCount )return m_initBuffer.buf[index];return m_chunkHead[index / KSlotCount]->buf[index % KSlotCount];}/** Retrieve the element by terms of position index**/const T& At( size_t index ) const {assert( index < m_totalCount );if( index < KSlotCount )return m_initBuffer.buf[index];return m_chunkHead[index / KSlotCount]->buf[index % KSlotCount];}protected:/****/T* Push(){if( KSlotCount == m_count ){Buffer* buf = new Buffer;assert( buf );buf->next = m_dataBuffer;m_dataBuffer = buf;//importantAssignChunkIndex( buf );//reset the value of value in single bufferm_count = 0;}m_totalCount++;return &m_dataBuffer->buf[m_count++];}/** Init the array of index of buffer pointer **/void InitChunkIndex(){m_chunkCapacity = KSlotCount;m_chunkHead = new Buffer*[m_chunkCapacity];memset( m_chunkHead, 0x00, sizeof(Buffer*)* m_chunkCapacity );m_chunkSize;}/** Store currently buffer pointer to array of index **/void AssignChunkIndex( Buffer* curBuffer ){if( m_chunkSize >= m_chunkCapacity ){m_chunkCapacity += 2;// importantm_chunkCapacity <<= 1;Buffer** newHead = new Buffer*[ m_chunkCapacity ];memset( newHead, 0x00, sizeof(Buffer*)* m_chunkCapacity );if( m_chunkHead ){memcpy( newHead, m_chunkHead, sizeof(Buffer*) * m_chunkSize );delete [] m_chunkHead;}m_chunkHead = newHead;}m_chunkHead[m_chunkSize++] = curBuffer;}protected:Buffer     m_initBuffer; // static storage for a small amount object operationBuffer*    m_dataBuffer; // currently the pointer of buffer of storageBuffer**    m_chunkHead;  // the array of index of buffer of storage allocatedsize_t      m_chunkSize;  // the length of array of index of buffersize_t      m_chunkCapacity; // the capacity of ...};/** Test STL vector**/void TestSTLVector(){std::vector<int> stlVec;int len = 64 * 100000;printf("STL Vector test result : \n " );unsigned long start= GetTickCount();for( int i = 0; i < len; i++ ){stlVec.push_back( i );}unsigned long interval = GetTickCount() - start;printf( "insert operation consume time is %d  in STL vector\n", interval );start= GetTickCount();for( int i = 0; i < len; i++ ){assert( stlVec[i] == i );}interval = GetTickCount() - start;printf( "retrieve operation consume time is %d  in STL vector\n", interval );    start= GetTickCount();for( int i = 0; i < len; i++ ){stlVec.pop_back();}interval = GetTickCount() - start;printf( "pop operation consume time is %d  in STL vector\n", interval );assert( stlVec.size() == 0 );}/** Test AlVector**/void TestVector(){int len = 64 * 100000;AlVector<int> vecObj;printf("AlVector Vector test result : \n " );unsigned long start= GetTickCount();for( int i = 0; i < len; i++ ){vecObj.PushBack( i );}unsigned long interval = GetTickCount() - start;printf( "insert operation consume time is %d  in AlVector \n", interval );start= GetTickCount();for( int i = 0; i < len; i++ ){assert( vecObj[i] == i );}interval = GetTickCount() - start;printf( "retrieve operation consume time is %d  in AlVector\n", interval );start= GetTickCount();for( int i = 0; i < len; i++ ){vecObj.PopBack();}interval = GetTickCount() - start;printf( "pop operation consume time is %d  in AlVector\n", interval );assert( vecObj.Size() == 0 );vecObj.Clear();}/** Test interface **/void TestVectorSuite(){TestVector();TestSTLVector();}#endif 

compile and run in visual studio 2005
test result as follows:



1 0