CByteArray源码解析

(1)CByteArray简介

    CByteArray是MFC中BYTE一种集合类,用于申明CByteArray类的数据,并且用相关函数对其进行处理。该类是8位无符号整数 BYTE类型,范围0—255,头文件是Afxcoll.h。

类CByteArray支持以字节为单位动态建立数组

类CByteArray的成员函数与类CObArray的成员函数类似。因此,也可以参考类CObArray的文档。只需把函数参数或返回值中出现的CObject指针换成BYTE就可以了。例如,类CObArray中的函数:

在使用数组之前,要调用SetSize设置它的大小并分配内存。如果没有使用SetSize,在数组中增加元素会引起数组内存空间频繁的重新分配以及数据拷贝。内存频繁的重新分配和数据拷贝会影响性能并造成内存碎片

(2)CByteArray成员函数

构造函数

CByteArray构造一个空的字节数组

边界

GetSize数组中元素的个数(数组大小)
GetUpperBound返回数组的最大有效下标
SetSize设置数组元素的个数(数组大小)

操作

FreeExtra释放数组中当前已有数据的最大上界后所有未占用的内存
RemoveAll删除数组中所有的元素

元素存取

GetAt返回指定下标处的数组元素的值
SetAt数组中指定下标的元素赋值,但不能动态增长数组(指定的下标不能越界)
ElementAt返回对数组中某个字节的临时参考
GetData允许访问数组中的元素。可以为NULL

数组增长

SetAtGrow数组中指定下标的元素赋值,在下标越界时动态增长数组Add在数组末尾增添一个元素,必要时增长数组Append在数组末尾接上另一个数组,必要时增长数组
Copy把另一个数组的内容拷贝到本数组,必要时增长数组

插入/删除

InsertAt在指定的下标处插入元素(或另外一个数组的内容)
RemoveAt删除指定下标处的一个元素
操作符operator[]取指定下标处元素的值,或者给其赋值
(3)源码

CByteArray.h

/
//
// 整理的微软CByteArray源码,删除了部分功能(如Serialize/Dump/AssertValid等)
//
/


#ifndef _ByteArray_H__
#define _ByteArray_H__

class CByteArray : public CObject
{
public:
	// Construction
	CByteArray();

	// Attributes
	INT_PTR GetSize() const;
	INT_PTR GetCount() const;
	BOOL IsEmpty() const;
	INT_PTR GetUpperBound() const;
	void SetSize(INT_PTR nNewSize, INT_PTR nGrowBy = -1);

	// Operations
	// Clean up
	void FreeExtra();
	void RemoveAll();

	// Accessing elements
	BYTE GetAt(INT_PTR nIndex) const;
	void SetAt(INT_PTR nIndex, BYTE newElement);

	BYTE& ElementAt(INT_PTR nIndex);

	// Direct Access to the element data (may return NULL)
	const BYTE* GetData() const;
	BYTE* GetData();

	// Potentially growing the array
	void SetAtGrow(INT_PTR nIndex, BYTE newElement);

	INT_PTR Add(BYTE newElement);

	INT_PTR Append(const CByteArray& src);
	void Copy(const CByteArray& src);

	// overloaded operator helpers
	BYTE operator[](INT_PTR nIndex) const;
	BYTE& operator[](INT_PTR nIndex);

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

	void RemoveAt(INT_PTR nIndex, INT_PTR nCount = 1);
	void InsertAt(INT_PTR nStartIndex, CByteArray* pNewArray);

	// Implementation
protected:
	BYTE* m_pData;       // the actual array of data
	INT_PTR m_nSize;     // # of elements (upperBound - 1)
	INT_PTR m_nMaxSize;  // max allocated
	INT_PTR m_nGrowBy;   // grow amount

public:
	~CByteArray();

protected:
	// local typedefs for class templates
	typedef BYTE BASE_TYPE;
	typedef BYTE BASE_ARG_TYPE;
};

#endif


CByteArray.cpp

/
//
// 整理的微软CByteArray源码,删除了部分功能(如Serialize/Dump/AssertValid等)
// Implementation of parameterized Array
//
/
// NOTE: we allocate an array of 'm_nMaxSize' elements, but only
//  the current size 'm_nSize' contains properly constructed
//  objects.

#include "stdafx.h"
#include 
#include "ByteArray.h"

/

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

CByteArray::~CByteArray()
{
	ASSERT_VALID(this);

	delete[] (BYTE*)m_pData;
}

void CByteArray::SetSize(INT_PTR nNewSize, INT_PTR nGrowBy) //重点学习
{
	ASSERT_VALID(this);
	ASSERT(nNewSize >= 0);

	if(nNewSize < 0 )
		AfxThrowInvalidArgException();

	if (nGrowBy >= 0)
		m_nGrowBy = nGrowBy;  // set new size

	if (nNewSize == 0)
	{
		// shrink to nothing
		delete[] (BYTE*)m_pData;
		m_pData = NULL;
		m_nSize = m_nMaxSize = 0;
	}
	else if (m_pData == NULL)
	{
		// create one with exact size
#ifdef SIZE_T_MAX
		ENSURE_ARG(nNewSize <= SIZE_T_MAX/sizeof(BYTE));    // no overflow
#endif
		m_pData = (BYTE*) new BYTE[nNewSize * sizeof(BYTE)];

		memset(m_pData, 0, nNewSize * sizeof(BYTE));  // 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(BYTE));
		}

		m_nSize = nNewSize;
	}
	else
	{
		// otherwise, grow array
		INT_PTR nGrowArrayBy = m_nGrowBy;
		if (nGrowArrayBy == 0)
		{
			// heuristically determine growth when nGrowArrayBy == 0
			// (this avoids heap fragmentation in many situations)
			nGrowArrayBy = min(1024, max(4, m_nSize / 8));
		}

		INT_PTR nNewMax;
		if (nNewSize < m_nMaxSize + nGrowArrayBy)
			nNewMax = m_nMaxSize + nGrowArrayBy;  // granularity
		else
			nNewMax = nNewSize;  // no slush

		ASSERT(nNewMax >= m_nMaxSize);  // no wrap around

		if(nNewMax  < m_nMaxSize)
			AfxThrowInvalidArgException();

#ifdef SIZE_T_MAX
		ASSERT(nNewMax <= SIZE_T_MAX/sizeof(BYTE)); // no overflow
#endif
		BYTE* pNewData = (BYTE*) new BYTE[nNewMax * sizeof(BYTE)];

		// copy new data from old 
		Checked::memcpy_s(pNewData, nNewMax * sizeof(BYTE), 
			m_pData, m_nSize * sizeof(BYTE));

		// construct remaining elements
		ASSERT(nNewSize > m_nSize);

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

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

INT_PTR CByteArray::Append(const CByteArray& src)
{
	ASSERT_VALID(this);
	ASSERT(this != &src);   // cannot append to itself

	if(this == &src)
		AfxThrowInvalidArgException();

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

	Checked::memcpy_s(m_pData + nOldSize, src.m_nSize * sizeof(BYTE),
		src.m_pData, src.m_nSize * sizeof(BYTE));

	return nOldSize;
}

void CByteArray::Copy(const CByteArray& src)
{
	ASSERT_VALID(this);
	ASSERT(this != &src);   // cannot append to itself

	if(this != &src)
	{
		SetSize(src.m_nSize);

		Checked::memcpy_s(m_pData, src.m_nSize * sizeof(BYTE),
			src.m_pData, src.m_nSize * sizeof(BYTE));
	}
}

void CByteArray::FreeExtra()
{
	ASSERT_VALID(this);

	if (m_nSize != m_nMaxSize)
	{
		// shrink to desired size
#ifdef SIZE_T_MAX
		ASSERT(m_nSize <= SIZE_T_MAX/sizeof(BYTE)); // no overflow
#endif
		BYTE* pNewData = NULL;
		if (m_nSize != 0)
		{
			pNewData = (BYTE*) new BYTE[m_nSize * sizeof(BYTE)];

			// copy new data from old 
			Checked::memcpy_s(pNewData, m_nSize * sizeof(BYTE), 
				m_pData, m_nSize * sizeof(BYTE));
		}

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

/
void CByteArray::SetAtGrow(INT_PTR nIndex, BYTE newElement)
{
	ASSERT_VALID(this);
	ASSERT(nIndex >= 0);

	if(nIndex < 0)
		AfxThrowInvalidArgException();

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

void CByteArray::InsertAt(INT_PTR nIndex, BYTE newElement, INT_PTR nCount)
{
	ASSERT_VALID(this);
	ASSERT(nIndex >= 0);    // will expand to meet need
	ASSERT(nCount > 0);     // zero or negative size not allowed

	if(nIndex < 0 || nCount <= 0)
		AfxThrowInvalidArgException();

	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_PTR nOldSize = m_nSize;
		SetSize(m_nSize + nCount);  // grow it to new size

		// shift old data up to fill gap 
		Checked::memmove_s(&m_pData[nIndex+nCount], (m_nSize-(nCount+nIndex)) * sizeof(BYTE), 
			&m_pData[nIndex], (nOldSize-nIndex) * sizeof(BYTE));

		// re-init slots we copied from
		memset(&m_pData[nIndex], 0, nCount * sizeof(BYTE));
	}

	// insert new value in the gap
	ASSERT(nIndex + nCount <= m_nSize);

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

void CByteArray::RemoveAt(INT_PTR nIndex, INT_PTR nCount)
{
	ASSERT_VALID(this);
	ASSERT(nIndex >= 0);
	ASSERT(nCount >= 0);
	INT_PTR nUpperBound = nIndex + nCount;
	ASSERT(nUpperBound <= m_nSize && nUpperBound >= nIndex && nUpperBound >= nCount);

	if(nIndex < 0 || nCount < 0 || (nUpperBound > m_nSize) || (nUpperBound < nIndex) || (nUpperBound < nCount))
		AfxThrowInvalidArgException();

	// just remove a range
	INT_PTR nMoveCount = m_nSize - (nUpperBound);

	if (nMoveCount)
	{
		Checked::memmove_s(&m_pData[nIndex], (size_t)nMoveCount * sizeof(BYTE), 
			&m_pData[nUpperBound], (size_t)nMoveCount * sizeof(BYTE));
	}

	m_nSize -= nCount;
}

void CByteArray::InsertAt(INT_PTR nStartIndex, CByteArray* pNewArray)
{
	ASSERT_VALID(this);
	ASSERT(pNewArray != NULL);
	ASSERT_KINDOF(CByteArray, pNewArray);
	ASSERT_VALID(pNewArray);
	ASSERT(nStartIndex >= 0);

	if(pNewArray == NULL || nStartIndex < 0)
		AfxThrowInvalidArgException();

	if (pNewArray->GetSize() > 0)
	{
		InsertAt(nStartIndex, pNewArray->GetAt(0), pNewArray->GetSize());

		for (INT_PTR i = 0; i < pNewArray->GetSize(); i++)
			SetAt(nStartIndex + i, pNewArray->GetAt(i));
	}
}

INT_PTR CByteArray::GetSize() const
{ 
	return m_nSize; 
}

INT_PTR CByteArray::GetCount() const
{ 
	return m_nSize; 
}

BOOL CByteArray::IsEmpty() const
{ 
	return m_nSize == 0; 
}

INT_PTR CByteArray::GetUpperBound() const
{ 
	return m_nSize-1;
}

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

BYTE CByteArray::GetAt(INT_PTR nIndex) const
{ 
	ASSERT(nIndex >= 0 && nIndex < m_nSize);
	if( nIndex < 0 || nIndex >= m_nSize )
		AfxThrowInvalidArgException();

	return m_pData[nIndex]; 
}

void CByteArray::SetAt(INT_PTR nIndex, BYTE newElement)
{ 
	ASSERT(nIndex >= 0 && nIndex < m_nSize);

	if( nIndex < 0 || nIndex >= m_nSize )
		AfxThrowInvalidArgException();

	m_pData[nIndex] = newElement; 
}

BYTE& CByteArray::ElementAt(INT_PTR nIndex)
{ 
	ASSERT(nIndex >= 0 && nIndex < m_nSize);

	if( nIndex < 0 || nIndex >= m_nSize )
		AfxThrowInvalidArgException();

	return m_pData[nIndex]; 
}

const BYTE* CByteArray::GetData() const
{ 
	return (const BYTE*)m_pData; 
}

BYTE* CByteArray::GetData()
{ 
	return (BYTE*)m_pData; 
}

INT_PTR CByteArray::Add(BYTE newElement)
{ 
	INT_PTR nIndex = m_nSize;
	SetAtGrow(nIndex, newElement);
	return nIndex; 
}

BYTE CByteArray::operator[](INT_PTR nIndex) const
{ 
	return GetAt(nIndex); 
}

BYTE& CByteArray::operator[](INT_PTR nIndex)
{ 
	return ElementAt(nIndex); 
}

/

注:简介部分内容参考百度百科

你可能感兴趣的:(数据结构)