一、简单介绍一下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一起使用,而且它是建立在用户数据报协议上的。
封包结构如下:
|
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 <windows.h>
#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);
}
以上为这几个类的实现,作者保留版权。注释比较少,欢迎交流。