音视频同步系列文章之----一种基于RTP协议的客户端媒体流Buffer管理思想(1)

    一、简单介绍一下RTP协议

实时传送协议(Real-time Transport Protocol或简写RTP)是一个网络传输协议,它是由IETF的多媒体传输工作小组1996年RFC 1889中公布的。国际电信联盟ITU-T也发布了自己的RTP文档,作为H.225.0,但是后来当IETF发布了关于它的稳定的标准RFC后就被取消了。它作为因特网标准在RFC 3550(该文档的旧版本是RFC 1889)有详细说明。RFC 3551(STD 65,旧版本是RFC 1890)详细描述了使用最小控制的音频和视频会议。RTP协议常用于流媒体系统(配合RTSP协议),视频会议和一键通Push to Talk)系统(配合H.323或SIP),使它成为IP电话产业的技术基础。RTP协议和RTP控制协议RTCP一起使用,而且它是建立在用户数据报协议上的。

    封包结构如下:

+ 位元 0-1 2 3 4-7 8 9-15 16-31
0 Ver. P X CC M PT 序号
32 Timestamp
64 SSRC identifier
96 ... CSRC identifiers ...
96+(CC×32) Additional header (optional), indicates length "AHL"
96+(CC×32)
+ (X×(AHL+16))
 
Data
 

Ver.(2 位元)是目前协定的版本号码,目前版号是 2。P(1位元)是用于RTP 封包(packet)结束点的预留空间,视封包是否需要多余的填塞空间。X(1位元)是否在使用延伸空间于封包之中。. CC(4位元)包含了 CSRC 数目用于修正标头(fixed header). M (one bit) 是用于应用等级以及其原型(profile)的定义。如果不为零表示目前的资料有特别的程式解译。PT(7 bits)是指payload的格式并决定将如何去由应用程式加以解译。SSRC 是同步化来源。

    上面这段话主要意思是:RTP协议是基于UDP的。该分包结构允许根据具体应用扩展,由X标志决定。一般来说当然是需要扩展的。

    二、指针队列与指针数组管理

    UDP协议无法保证收到的数据包是有序的。也不能保证不丢包。所以,在网络多媒体应用中,客户端必须要有缓冲,排序,丢包处理机制。缓冲区要有数据空间的动态分配和回收机制。所以要利用队列的插入,提取效率优势和数组的排序效率优势。这里介绍指针队列和指针数组的一种管理方法,采用C++实现。

    实际上,如果采用MFC来实现,我们可以借用其CPtrList和CPtrArray类。如果不采用MFC,则要自己实现这两个类。命名为CMyPtrList和CMyPtrArray,其中也要实现CMyPlex类。实现方法如下:

(1)

#ifndef _MYPLEX_H_
#define _MYPLEX_H_
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
// CMyPlex
#ifndef _AFX_PACKING
#define _AFX_PACKING 4
#endif

#ifndef PASCAL
#define PASCAL __stdcall
#endif

#ifdef _AFX_PACKING
#pragma pack(push, _AFX_PACKING)// 按 _AFX_PACKING 大小对其
#endif

struct CMyPlex     // warning variable length structure
{
 CMyPlex* pNext;
#if (_AFX_PACKING >= 8)
 DWORD dwReserved[1];    // align on 8 byte boundary
#endif
 // BYTE data[maxNum*elementSize];
 
 void* data() { return this+1; }
 
 static CMyPlex* PASCAL Create(CMyPlex*& pHead, UINT nMax, UINT cbElement)//add before pHead
 {
  if(nMax <=0 || cbElement <= 0)
   return NULL;
  CMyPlex* p = (CMyPlex*) ::HeapAlloc(::GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CMyPlex) + nMax * cbElement);
  // may throw exception
  if(NULL == p)
   return p;
  p->pNext = pHead;
  pHead = p;  // change head (adds in reverse order for simplicity)
  return p;
 }
 // like 'calloc' but no zero fill
 // may throw memory exceptions
 
 void FreeDataChain()       // free this one and links
 {
  CMyPlex* p = this;
  while (p != NULL)
  {
   BYTE* bytes = (BYTE*) p;
   CMyPlex* pNext = p->pNext;
   ::HeapFree(::GetProcessHeap(),0,bytes);
   p = pNext;
  }
 }
};

#ifdef _AFX_PACKING
#pragma pack(pop)
#endif

#endif

 

(2)

// MyPtrList.h: interface for the CMyPtrList class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_MYPTRLIST_H__232512D6_124F_4AA3_9300_9B6EE4135EEA__INCLUDED_)
#define AFX_MYPTRLIST_H__232512D6_124F_4AA3_9300_9B6EE4135EEA__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include
#include "MyPlex.h"

#ifndef __AFX_H__
#ifndef __WXLIST__
struct __POSITION { };
typedef __POSITION* POSITION;
#endif
#endif

#ifndef _AFX_PACKING
#define _AFX_PACKING 4
#endif

#ifndef PASCAL
#define PASCAL __stdcall
#endif

class CMyPtrList 
{
protected:
 struct CNode
 {
  CNode *pNext;
  CNode *pPrev;
  void *data;
 };
public:

// Construction
 CMyPtrList(int nBlockSize = 10);

// Attributes (head and tail)
 // count of elements
 int  GetCount() const;
 BOOL IsEmpty() const;

 //peek at head or tail
 void*& GetHead();
 void* GetHead() const;
 void*& GetTail();
 void* GetTail() const;

// Operations
 // get head or tail (and remove it) - don't call on empty list!
 void* RemoveHead();
 void* RemoveTail();

 // add before head or after tail
 POSITION AddHead(void *newElement);
 POSITION AddTail(void *newElement);

 // add another list of elements before head or after tail
 void  AddHead(CMyPtrList *pNewList);
 void  AddTail(CMyPtrList *pNewList);

 // remove all elements
 void  RemoveAll();

 // iteration
 POSITION GetHeadPosition() const;
 POSITION GetTailPosition() const;
 void*& GetNext(POSITION& rPosition); // return *Position++
 void* GetNext(POSITION& rPosition) const; // return *Position++
 void*& GetPrev(POSITION& rPosition); // return *Position--
 void* GetPrev(POSITION& rPosition) const; // return *Position--
 
 // getting/modifying an element at a given position
 void*& GetAt(POSITION position);
 void* GetAt(POSITION position) const;
 void SetAt(POSITION pos, void* newElement);
 
 void RemoveAt(POSITION position);
 
 // helper functions (note: O(n) speed)
 POSITION Find(void* searchValue, POSITION startAfter = NULL) const;
 // defaults to starting at the HEAD
 // return NULL if not found
 POSITION FindIndex(int nIndex) const;
 // get the 'nIndex'th element (may return NULL)
 
 // Implementation
protected:
 CNode* m_pNodeHead;
 CNode* m_pNodeTail;
 int m_nCount;
 CNode* m_pNodeFree;
 struct CMyPlex* m_pBlocks;
 int m_nBlockSize;
 
 CNode* NewNode(CNode*, CNode*);
 void FreeNode(CNode*);

public:
 virtual ~CMyPtrList();

 // local typedefs for class templates
 typedef void* BASE_TYPE;
 typedef void* BASE_ARG_TYPE;

};

#endif // !defined(AFX_MYPTRLIST_H__232512D6_124F_4AA3_9300_9B6EE4135EEA__INCLUDED_)

 

 

(3)

 

// MyPtrList.cpp: implementation of the CMyPtrList class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "MyPtrList.h"

CMyPtrList::CMyPtrList(int nBlockSize)
{
// ASSERT(nBlockSize > 0);
 
 m_nCount = 0;
 m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL;
 m_pBlocks = NULL;
 m_nBlockSize = nBlockSize;
}

void CMyPtrList::RemoveAll()
{
// ASSERT_VALID(this);
 
 // destroy elements
 
 
 m_nCount = 0;
 m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL;
 m_pBlocks->FreeDataChain();
 m_pBlocks = NULL;
}

CMyPtrList::~CMyPtrList()
{
 RemoveAll();
// ASSERT(m_nCount == 0);
}

/////////////////////////////////////////////////////////////////////////////
// Node helpers
/*
 * Implementation note: CNode's are stored in CMyPlex blocks and
 *  chained together. Free blocks are maintained in a singly linked list
 *  using the 'pNext' member of CNode with 'm_pNodeFree' as the head.
 *  Used blocks are maintained in a doubly linked list using both 'pNext'
 *  and 'pPrev' as links and 'm_pNodeHead' and 'm_pNodeTail'
 *   as the head/tail.
 *
 * We never free a CMyPlex block unless the List is destroyed or RemoveAll()
 *  is used - so the total number of CMyPlex blocks may grow large depending
 *  on the maximum past size of the list.
 */

CMyPtrList::CNode*
CMyPtrList::NewNode(CMyPtrList::CNode* pPrev, CMyPtrList::CNode* pNext)
{
 if (m_pNodeFree == NULL)// no free node left
 {
  // add another block
  CMyPlex* pNewBlock = CMyPlex::Create(m_pBlocks, m_nBlockSize,
     sizeof(CNode));
  if(NULL == pNewBlock)
   return NULL;
  // chain them into free list
  CNode* pNode = (CNode*) pNewBlock->data();
  // free in reverse order to make it easier to debug
  pNode += m_nBlockSize - 1;
  for (int i = m_nBlockSize-1; i >= 0; i--, pNode--)
  {
   pNode->pNext = m_pNodeFree;
   m_pNodeFree = pNode;
  }
 }
// ASSERT(m_pNodeFree != NULL);  // we must have something
 if(NULL == m_pNodeFree)
  return NULL;
 CMyPtrList::CNode* pNode = m_pNodeFree;//get one from m_pNodeFree list
 m_pNodeFree = m_pNodeFree->pNext;
 pNode->pPrev = pPrev;
 pNode->pNext = pNext;
 m_nCount++;
// ASSERT(m_nCount > 0);  // make sure we don't overflow

 pNode->data = NULL; // start with zero

 return pNode;
}

void CMyPtrList::FreeNode(CMyPtrList::CNode* pNode)
{

 pNode->pNext = m_pNodeFree;
 m_pNodeFree = pNode;
 m_nCount--;
// ASSERT(m_nCount >= 0);  // make sure we don't underflow

 // if no more elements, cleanup completely
 if (m_nCount == 0)
  RemoveAll();
}

/////////////////////////////////////////////////////////////////////////////

POSITION CMyPtrList::AddHead(void* newElement)
{

// ASSERT_VALID(this);

 CNode* pNewNode = NewNode(NULL, m_pNodeHead);
 if(NULL == pNewNode)
  return NULL;
 pNewNode->data = newElement;
 if (m_pNodeHead != NULL)
  m_pNodeHead->pPrev = pNewNode;
 else
  m_pNodeTail = pNewNode;
 m_pNodeHead = pNewNode;
 return (POSITION) pNewNode;

}

POSITION CMyPtrList::AddTail(void* newElement)
{

// ASSERT_VALID(this);

 CNode* pNewNode = NewNode(m_pNodeTail, NULL);
 if(NULL == pNewNode)
  return NULL;
 pNewNode->data = newElement;
 if (m_pNodeTail != NULL)
  m_pNodeTail->pNext = pNewNode;
 else
  m_pNodeHead = pNewNode;
 m_pNodeTail = pNewNode;
 return (POSITION) pNewNode;

}

 

void CMyPtrList::AddHead(CMyPtrList* pNewList)
{
// ASSERT_VALID(this);

// ASSERT(pNewList != NULL);
// ASSERT_KINDOF(CMyPtrList, pNewList);
// ASSERT_VALID(pNewList);

 // add a list of same elements to head (maintain order)
 POSITION pos = pNewList->GetTailPosition();
 while (pos != NULL)
  AddHead(pNewList->GetPrev(pos));////////////////////
}

void CMyPtrList::AddTail(CMyPtrList* pNewList)
{
// ASSERT_VALID(this);
// ASSERT(pNewList != NULL);
// ASSERT_KINDOF(CMyPtrList, pNewList);
// ASSERT_VALID(pNewList);

 // add a list of same elements
 POSITION pos = pNewList->GetHeadPosition();
 while (pos != NULL)
  AddTail(pNewList->GetNext(pos));
}

void* CMyPtrList::RemoveHead()
{
// ASSERT_VALID(this);
// ASSERT(m_pNodeHead != NULL);  // don't call on empty list !!!
// ASSERT(AfxIsValidAddress(m_pNodeHead, sizeof(CNode)));

 CNode* pOldNode = m_pNodeHead;
 void* returnValue = pOldNode->data;

 m_pNodeHead = pOldNode->pNext;
 if (m_pNodeHead != NULL)
  m_pNodeHead->pPrev = NULL;
 else
  m_pNodeTail = NULL;
 FreeNode(pOldNode);
 return returnValue;
}

void* CMyPtrList::RemoveTail()
{
// ASSERT_VALID(this);
// ASSERT(m_pNodeTail != NULL);  // don't call on empty list !!!
// ASSERT(AfxIsValidAddress(m_pNodeTail, sizeof(CNode)));

 CNode* pOldNode = m_pNodeTail;
 void* returnValue = pOldNode->data;

 m_pNodeTail = pOldNode->pPrev;
 if (m_pNodeTail != NULL)
  m_pNodeTail->pNext = NULL;
 else
  m_pNodeHead = NULL;
 FreeNode(pOldNode);
 return returnValue;
}

void CMyPtrList::RemoveAt(POSITION position)
{
// ASSERT_VALID(this);

 CNode* pOldNode = (CNode*) position;
// ASSERT(AfxIsValidAddress(pOldNode, sizeof(CNode)));

 // remove pOldNode from list
 if (pOldNode == m_pNodeHead)
 {
  m_pNodeHead = pOldNode->pNext;
 }
 else
 {
//  ASSERT(AfxIsValidAddress(pOldNode->pPrev, sizeof(CNode)));
  pOldNode->pPrev->pNext = pOldNode->pNext;
 }
 if (pOldNode == m_pNodeTail)
 {
  m_pNodeTail = pOldNode->pPrev;
 }
 else
 {
//  ASSERT(AfxIsValidAddress(pOldNode->pNext, sizeof(CNode)));
  pOldNode->pNext->pPrev = pOldNode->pPrev;
 }
 FreeNode(pOldNode);
}


/////////////////////////////////////////////////////////////////////////////
// slow operations
POSITION CMyPtrList::FindIndex(int nIndex) const
{
// ASSERT_VALID(this);

 if (nIndex >= m_nCount || nIndex < 0)
  return NULL;  // went too far

 CNode* pNode = m_pNodeHead;
 while (nIndex--)
 {
//  ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  pNode = pNode->pNext;
 }
 return (POSITION) pNode;
}

POSITION CMyPtrList::Find(void* searchValue, POSITION startAfter) const
{
// ASSERT_VALID(this);

 CNode* pNode = (CNode*) startAfter;
 if (pNode == NULL)
 {
  pNode = m_pNodeHead;  // start at head
 }
 else
 {
//  ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  pNode = pNode->pNext;  // start after the one specified
 }

 for (; pNode != NULL; pNode = pNode->pNext)
  if (pNode->data == searchValue)
   return (POSITION) pNode;
 return NULL;
}

////////////////////////////////////////////////////////////////////////////

int CMyPtrList::GetCount() const
{
 return m_nCount;
}

BOOL CMyPtrList::IsEmpty() const
{
 return m_nCount == 0;
}

void*& CMyPtrList::GetHead()
{
// ASSERT(m_pNodeHead != NULL);
 TRACE(_T("void*& CMyPtrList::GetHead()/n"));
 return m_pNodeHead->data;
}

void* CMyPtrList::GetHead() const
{
// ASSERT(m_pNodeHead != NULL);
 TRACE(_T("void* CMyPtrList::GetHead() const/n"));
 return m_pNodeHead->data;
}

void*& CMyPtrList::GetTail()
{
// ASSERT(m_pNodeTail != NULL);
 return m_pNodeTail->data;
}

void* CMyPtrList::GetTail() const
{
// ASSERT(m_pNodeTail != NULL);
 return m_pNodeTail->data;
}

POSITION CMyPtrList::GetHeadPosition() const
{
 return (POSITION) m_pNodeHead;
}

POSITION CMyPtrList::GetTailPosition() const
{
 return (POSITION) m_pNodeTail;
}

void*& CMyPtrList::GetNext(POSITION& rPosition) // return *Position++
{
 CNode* pNode = (CNode*) rPosition;
// ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
 rPosition = (POSITION) pNode->pNext;
 return pNode->data;
}

void* CMyPtrList::GetNext(POSITION& rPosition) const // return *Position++
{
 CNode* pNode = (CNode*) rPosition;
// ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
 rPosition = (POSITION) pNode->pNext;
 return pNode->data;
}

void*& CMyPtrList::GetPrev(POSITION& rPosition) // return *Position--
{
 CNode* pNode = (CNode*) rPosition;
// ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
 rPosition = (POSITION) pNode->pPrev;
 return pNode->data;
}

void* CMyPtrList::GetPrev(POSITION& rPosition) const // return *Position--
{
 CNode* pNode = (CNode*) rPosition;
// ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
 rPosition = (POSITION) pNode->pPrev;
 return pNode->data;
}

void*& CMyPtrList::GetAt(POSITION position)
{
 CNode* pNode = (CNode*) position;
// ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
 return pNode->data;
}

void* CMyPtrList::GetAt(POSITION position) const
{
 CNode* pNode = (CNode*) position;
// ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
 return pNode->data;
}

void CMyPtrList::SetAt(POSITION pos, void* newElement)
{
 CNode* pNode = (CNode*) pos;
// ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
 pNode->data = newElement;
}

 

 

(4)

 

// MyPtrArray.h: interface for the CMyPtrArray class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_MYPTRARRAY_H__F3EFB05A_761F_4769_A789_4DC9EF144E6E__INCLUDED_)
#define AFX_MYPTRARRAY_H__F3EFB05A_761F_4769_A789_4DC9EF144E6E__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

//#define SIZE_T_MAX 0xffffffff

class CMyPtrArray 
{
public:
 CMyPtrArray();
 virtual ~CMyPtrArray();
public:
 int  GetSize() const;
 int  GetUpperBound() const;
 void SetSize(int nNewSize,int nGrowBy = -1);
 void FreeExtra();
 void RemoveAll();

 void* GetAt(int nIndex) const;
 void SetAt(int nIndex,void *newElement);
 // Direct Access to the element data (may return NULL)
 const void** GetData() const;
 void** GetData();

 // Potentially growing the array
 void SetAtGrow(int nIndex, void* newElement);

 int Add(void* newElement);

 int Append(const CMyPtrArray& src);
 void Copy(const CMyPtrArray& src);

 // overloaded operator helpers
 void* operator[](int nIndex) const;

 // Operations that move elements around
 void InsertAt(int nIndex, void* newElement, int nCount = 1);

 void RemoveAt(int nIndex, int nCount = 1);
 void InsertAt(int nStartIndex, CMyPtrArray* pNewArray);

private:
 void** m_pData;//pointer to pointer ,first address of pointer array
 int  m_nSize;
 int  m_nMaxSize;
 int  m_nGrowBy;
};

#endif // !defined(AFX_MYPTRARRAY_H__F3EFB05A_761F_4769_A789_4DC9EF144E6E__INCLUDED_)

 

 

(5)

 

// MyPtrArray.cpp: implementation of the CMyPtrArray class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "MyPtrArray.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CMyPtrArray::CMyPtrArray()
{
 m_pData = NULL;
 m_nSize = m_nMaxSize = m_nGrowBy = 0;
}

CMyPtrArray::~CMyPtrArray()
{
 if(m_pData)
  VirtualFree(m_pData,0,MEM_RELEASE);
// delete[] (BYTE *)m_pData;
}

void CMyPtrArray::SetSize(int nNewSize, int nGrowBy)
{
 if(0 > nNewSize)
  return ;

 if (nGrowBy != -1)
  m_nGrowBy = nGrowBy;  // set new size

 if (0 == nNewSize)
 {
  // shrink to nothing
  if(m_pData)
   VirtualFree(m_pData,0,MEM_RELEASE);
//  delete[] (BYTE*)m_pData;
  m_pData = NULL;
  m_nSize = m_nMaxSize = 0;
 }
 else if (NULL == m_pData)
 {
  // create one with exact size

#ifdef SIZE_T_MAX
  if(nNewSize > SIZE_T_MAX / sizeof(void *))
   return ;
#endif
//  m_pData = (void**) new BYTE[nNewSize * sizeof(void*)];
  m_pData = (void **)VirtualAlloc(NULL,nNewSize * sizeof(void *),MEM_COMMIT,PAGE_READWRITE);
  if(NULL == m_pData)
   return ;
  memset(m_pData, 0, nNewSize * sizeof(void*));  // zero fill

  m_nSize = m_nMaxSize = nNewSize;
 }
 else if (nNewSize <= m_nMaxSize)
 {
  // it fits
  if (nNewSize > m_nSize)
  {
   // initialize the new elements

   memset(&m_pData[m_nSize], 0, (nNewSize-m_nSize) * sizeof(void*));

  }

  m_nSize = nNewSize;
 }
 else
 {
  // otherwise, grow array
  int nGrowBy = m_nGrowBy;
  if (nGrowBy == 0)
  {
   // heuristically determine growth when nGrowBy == 0
   //  (this avoids heap fragmentation in many situations)
   nGrowBy = min(1024, max(4, m_nSize / 8));
  }
  int nNewMax;
  if (nNewSize < m_nMaxSize + nGrowBy)
   nNewMax = m_nMaxSize + nGrowBy;  // granularity
  else
   nNewMax = nNewSize;  // no slush

  if(nNewMax < m_nMaxSize)  // no wrap around
   return;
#ifdef SIZE_T_MAX
  if(nNewMax > SIZE_T_MAX / sizeof(void *))
   return ;
#endif
//  void** pNewData = (void**) new BYTE[nNewMax * sizeof(void*)];
  void** pNewData = (void **)VirtualAlloc(NULL,nNewMax * sizeof(void *),MEM_COMMIT,PAGE_READWRITE);
  if(NULL == pNewData)
   return;
  // copy new data from old
  memcpy(pNewData, m_pData, m_nSize * sizeof(void*));

  // construct remaining elements
  if(nNewSize <= m_nSize)
   return ;

  memset(&pNewData[m_nSize], 0, (nNewSize-m_nSize) * sizeof(void*));


  // get rid of old stuff (note: no destructors called)
  VirtualFree(m_pData,0,MEM_RELEASE);
//  delete[] (BYTE*)m_pData;
  m_pData = pNewData;
  m_nSize = nNewSize;
  m_nMaxSize = nNewMax;
 }
}

int CMyPtrArray::Append(const CMyPtrArray& src)
{
 if(IsBadReadPtr(this,sizeof(CMyPtrArray)))
  return 0;
 if(this == &src)
  return 0;

 int nOldSize = m_nSize;
 SetSize(m_nSize + src.m_nSize);

 memcpy(m_pData + nOldSize, src.m_pData, src.m_nSize * sizeof(void*));

 return nOldSize;
}

void CMyPtrArray::Copy(const CMyPtrArray& src)
{
 if(IsBadReadPtr(this,sizeof(CMyPtrArray)))
  return ;
 if(this == &src)
  return ;

 SetSize(src.m_nSize);

 memcpy(m_pData, src.m_pData, src.m_nSize * sizeof(void*));

}

void CMyPtrArray::FreeExtra()
{
 if(IsBadReadPtr(this,sizeof(CMyPtrArray)))
  return ;

 if (m_nSize != m_nMaxSize)
 {
  // shrink to desired size
#ifdef SIZE_T_MAX
  if(m_nSize > SIZE_T_MAX / sizeof(void *))
   return ;
#endif
  void** pNewData = NULL;
  if (m_nSize != 0)
  {
//   pNewData = (void**) new BYTE[m_nSize * sizeof(void*)];
   pNewData = (void**)VirtualAlloc(NULL,m_nSize * sizeof(void *),MEM_COMMIT,PAGE_READWRITE);
   // copy new data from old
   memcpy(pNewData, m_pData, m_nSize * sizeof(void*));
  }

  // get rid of old stuff (note: no destructors called)
//  delete[] (BYTE*)m_pData;
  if(m_pData)
   VirtualFree(m_pData,0,MEM_RELEASE);
  m_pData = pNewData;
  m_nMaxSize = m_nSize;
 }
}

/////////////////////////////////////////////////////////////////////////////

void CMyPtrArray::SetAtGrow(int nIndex, void* newElement)
{
 if(IsBadReadPtr(this,sizeof(CMyPtrArray)))
  return ;
 if(nIndex < 0)
  return ;

 if (nIndex >= m_nSize)
  SetSize(nIndex+1);
 m_pData[nIndex] = newElement;
}

void CMyPtrArray::InsertAt(int nIndex, void* newElement, int nCount)
{
 if(IsBadReadPtr(this,sizeof(CMyPtrArray)))
  return ;
 if(nIndex < 0 || nCount <= 0)
  return ;

 if (nIndex >= m_nSize)
 {
  // adding after the end of the array
  SetSize(nIndex + nCount);  // grow so nIndex is valid
 }
 else
 {
  // inserting in the middle of the array
  int nOldSize = m_nSize;
  SetSize(m_nSize + nCount);  // grow it to new size
  // shift old data up to fill gap
  memmove(&m_pData[nIndex+nCount], &m_pData[nIndex],
   (nOldSize-nIndex) * sizeof(void*));

  // re-init slots we copied from

  memset(&m_pData[nIndex], 0, nCount * sizeof(void*));

 }

 // insert new value in the gap
 if(nIndex + nCount > m_nSize)
  return ;

 // copy elements into the empty space
 while (nCount--)
  m_pData[nIndex++] = newElement;

}

void CMyPtrArray::RemoveAt(int nIndex, int nCount)
{
 if(IsBadReadPtr(this,sizeof(CMyPtrArray)))
  return ;
 if(nIndex < 0 || nCount < 0 || nIndex + nCount > m_nSize)
  return;
 // just remove a range
 int nMoveCount = m_nSize - (nIndex + nCount);

 if (nMoveCount)
  memmove(&m_pData[nIndex], &m_pData[nIndex + nCount],
   nMoveCount * sizeof(void*));
 m_nSize -= nCount;
}

void CMyPtrArray::InsertAt(int nStartIndex, CMyPtrArray* pNewArray)
{
 if(IsBadReadPtr(this,sizeof(CMyPtrArray)))
  return ;
 if(NULL == pNewArray || nStartIndex < 0)
  return ;
 if(IsBadReadPtr(pNewArray,sizeof(CMyPtrArray)))
  return;

 if (pNewArray->GetSize() > 0)
 {
  InsertAt(nStartIndex, pNewArray->GetAt(0), pNewArray->GetSize());
  for (int i = 0; i < pNewArray->GetSize(); i++)
   SetAt(nStartIndex + i, pNewArray->GetAt(i));
 }
}

int CMyPtrArray::GetSize() const
{
 return m_nSize;
}

int CMyPtrArray::GetUpperBound() const
{
 return m_nSize-1;
}

void CMyPtrArray::RemoveAll()
{
 SetSize(0);
}

void* CMyPtrArray::GetAt(int nIndex) const
{
 if(nIndex < 0 || nIndex >= m_nSize)
  return NULL;
 return m_pData[nIndex];
}

void CMyPtrArray::SetAt(int nIndex, void* newElement)
{
 if(nIndex < 0 || nIndex >= m_nSize)
  return;
 m_pData[nIndex] = newElement;
}

const void** CMyPtrArray::GetData() const
{
 return (const void**)m_pData;
}

void** CMyPtrArray::GetData()
{
 return (void**)m_pData;
}

int CMyPtrArray::Add(void* newElement)
{
 int nIndex = m_nSize;
 SetAtGrow(nIndex, newElement);
 return nIndex;
}

void* CMyPtrArray::operator[](int nIndex) const
{
 return GetAt(nIndex);
}

 

以上为这几个类的实现,作者保留版权。注释比较少,欢迎交流。

 

 

 

 

 

 

 

 

 

 


 

 

 

 

 

 

 

    

你可能感兴趣的:(buffer,null,byte,pascal,list,视频会议)