Click here to Skip to main content
15,896,606 members
Articles / Desktop Programming / MFC

Pretty WinAPI Class

Rate me:
Please Sign up or sign in to vote.
4.90/5 (36 votes)
23 May 20074 min read 96.4K   2.7K   80  
New library version that is not WTL/MFC dependent
/***********************************************************************************
*	File		: NewBValArray.h
*	Description : Header for a MFC CArray-like class.
*				  This new class uses a pre-allocated memory pool for actual data
*				  of the array.This pool can be resized to a bigger capacity but
*				  that action requires a new larger memory pool and a memcpy().
*				  So you should avoid this as you can.
*
*	How to use:
*				  NewBValArray<MyClass,MyClass> rgMyArray(1000);
*				  So rgMyArray will pre-allocates a memory pool of 1000 MyClass items.
*				  NOTE: rgMyArray still a blank array, i.e rgMyArray.GetSize() = 0;as 
*				  long as you don't "add" item to it by Add(), or oprerator[]
*
*	              Others, it can be used the same as MFC CArray, i.e you can safely 
*				  replace all CArray with NewBArray.
*
*   Special features:
*				  I make use of placement new and delete as CArray. So it should works
*				  on others compilers support this C++ standard.(Not test yet)
*
*	Author		: Nguyen Binh		
*	Email       : Ngbinh@glassegg.com
*	Company		: GlassEgg Digital Media
*	Created:	: 15/03/2002.
*   Copyright   : You can use this small source as you like but please drop me a mail.
*   TODO        : 
*					+ Add double-linked list to hold actual data
*					+ Make it thread-safe
***********************************************************************************/

#ifndef __NEWB_VAL_ARRAY_H__
#define __NEWB_VAL_ARRAY_H__

#ifndef __NEWB_CONFIG_H__
#include "NewBConfig.h"
#endif

#ifndef _NEW_
	#include <new>
#endif

template<class TYPE, class ARG_TYPE = const TYPE&>
class NewBValArray 
{
public:
// Construction
	NewBValArray();
	NewBValArray(NEWB_INT nMaxSize);

// Attributes
	NEWB_INT GetSize() const;
	NEWB_INT GetCount() const;
	NEWB_BOOL IsEmpty() const;
	NEWB_INT GetUpperBound() const;
	NEWB_INT SetSize(NEWB_INT nNewSize, NEWB_INT nGrowBy = -1);
	NEWB_INT GetCapacity() const;
	NEWB_INT GetFreeItems() const;

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

	// Accessing elements
	const TYPE& GetAt(NEWB_INT nIndex) const;
	TYPE& GetAt(NEWB_INT nIndex);
	NEWB_VOID SetAt(NEWB_INT nIndex, ARG_TYPE newElement);
	const TYPE& ElementAt(NEWB_INT nIndex) const;
	TYPE& ElementAt(NEWB_INT nIndex);

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

	// Potentially growing the array
	NEWB_VOID SetAtGrow(NEWB_INT nIndex, ARG_TYPE newElement);
	NEWB_INT Add(ARG_TYPE newElement);
	NEWB_INT Append(const NewBValArray& src);
	NEWB_VOID Copy(const NewBValArray& src);

	// overloaded operator helpers
	const TYPE& operator[](NEWB_INT nIndex) const;
	TYPE& operator[](NEWB_INT nIndex);

	// Operations that move elements around
	NEWB_VOID InsertAt(NEWB_INT nIndex, ARG_TYPE newElement, NEWB_INT nCount = 1);
	NEWB_VOID RemoveAt(NEWB_INT nIndex, NEWB_INT nCount = 1);
	NEWB_VOID InsertAt(NEWB_INT nStartIndex, NewBValArray* pNewArray);

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

public:
	~NewBValArray();
};

/////////////////////////////////////////////////////////////////////////////
// NewBValArray<TYPE, ARG_TYPE> inline functions

template<class TYPE, class ARG_TYPE>
NEWB_INLINE NEWB_INT NewBValArray<TYPE, ARG_TYPE>::GetSize() const
{ 
	return m_nSize; 
}

template<class TYPE, class ARG_TYPE>
NEWB_INLINE NEWB_INT NewBValArray<TYPE, ARG_TYPE>::GetCount() const
{ 
	return m_nSize; 
}

template<class TYPE, class ARG_TYPE>
NEWB_INLINE NEWB_BOOL NewBValArray<TYPE, ARG_TYPE>::IsEmpty() const
{ 
	return m_nSize == 0; 
}

template<class TYPE, class ARG_TYPE>
NEWB_INLINE NEWB_INT NewBValArray<TYPE, ARG_TYPE>::GetUpperBound() const
{ 
	return m_nSize-1; 
}

template<class TYPE, class ARG_TYPE>
NEWB_INLINE NEWB_INT NewBValArray<TYPE, ARG_TYPE>::GetCapacity() const
{ 
	return m_nMaxSize; 
}

template<class TYPE, class ARG_TYPE>
NEWB_INLINE NEWB_INT NewBValArray<TYPE, ARG_TYPE>::GetFreeItems() const
{ 
	return m_nMaxSize - m_nSize; 
}

template<class TYPE, class ARG_TYPE>
NEWB_INLINE NEWB_VOID NewBValArray<TYPE, ARG_TYPE>::RemoveAll()
{ 
	if (m_pData != NULL)
	{
		for( int i = 0; i < m_nSize; i++ )
			(m_pData + i)->~TYPE();

//			delete[] (NEWB_BYTE*)m_pData;
//			m_pData = NULL;
	}

	m_nSize = 0;
}

template<class TYPE, class ARG_TYPE>
NEWB_INLINE TYPE& NewBValArray<TYPE, ARG_TYPE>::GetAt(NEWB_INT nIndex)
{ 
	NEWB_ASSERT(nIndex >= 0 && nIndex < m_nSize);
	return m_pData[nIndex]; 
}

template<class TYPE, class ARG_TYPE>
NEWB_INLINE const TYPE& NewBValArray<TYPE, ARG_TYPE>::GetAt(NEWB_INT nIndex) const
{ 
	NEWB_ASSERT(nIndex >= 0 && nIndex < m_nSize);
	return m_pData[nIndex]; 
}

template<class TYPE, class ARG_TYPE>
NEWB_INLINE NEWB_VOID NewBValArray<TYPE, ARG_TYPE>::SetAt(NEWB_INT nIndex, ARG_TYPE newElement)
{ 
	NEWB_ASSERT(nIndex >= 0 && nIndex < m_nSize);
	m_pData[nIndex] = newElement; 
}

template<class TYPE, class ARG_TYPE>
NEWB_INLINE const TYPE& NewBValArray<TYPE, ARG_TYPE>::ElementAt(NEWB_INT nIndex) const
{ 
	NEWB_ASSERT(nIndex >= 0 && nIndex < m_nSize);
	return m_pData[nIndex]; 
}

template<class TYPE, class ARG_TYPE>
NEWB_INLINE TYPE& NewBValArray<TYPE, ARG_TYPE>::ElementAt(NEWB_INT nIndex)
{ 
	NEWB_ASSERT(nIndex >= 0 && nIndex < m_nSize);
		return m_pData[nIndex]; 
}

template<class TYPE, class ARG_TYPE>
NEWB_INLINE const TYPE* NewBValArray<TYPE, ARG_TYPE>::GetData() const
{ 
	return (const TYPE*)m_pData; 
}

template<class TYPE, class ARG_TYPE>
NEWB_INLINE TYPE* NewBValArray<TYPE, ARG_TYPE>::GetData()
{ 
	return (TYPE*)m_pData; 
}

template<class TYPE, class ARG_TYPE>
NEWB_INLINE NEWB_INT NewBValArray<TYPE, ARG_TYPE>::Add(ARG_TYPE newElement)
{ 
	NEWB_INT nIndex = m_nSize;

	SetAtGrow(nIndex, newElement);

	m_nSize ++;

	return nIndex; 
}

template<class TYPE, class ARG_TYPE>
NEWB_INLINE const TYPE& NewBValArray<TYPE, ARG_TYPE>::operator[](NEWB_INT nIndex) const
{ 
	return GetAt(nIndex); 
}

template<class TYPE, class ARG_TYPE>
NEWB_INLINE TYPE& NewBValArray<TYPE, ARG_TYPE>::operator[](NEWB_INT nIndex)
{ 
	return ElementAt(nIndex); 
}

/////////////////////////////////////////////////////////////////////////////
// NewBValArray<TYPE, ARG_TYPE> out-of-line functions

template<class TYPE, class ARG_TYPE>
NewBValArray<TYPE, ARG_TYPE>::NewBValArray()
{
	m_pData = NULL;
	m_nSize = m_nMaxSize = m_nGrowBy = 0;
}

template<class TYPE, class ARG_TYPE>
NewBValArray<TYPE, ARG_TYPE>::NewBValArray(NEWB_INT nMaxSize)
{
	m_pData = NULL;
	m_nSize = m_nGrowBy = 0;
	m_nMaxSize = nMaxSize;

	// create buffer big enough to hold number of requested elements or
	// m_nGrowBy elements, whichever is larger.
#ifdef SIZE_T_MAX
		NEWB_ASSERT(m_nMaxSize <= SIZE_T_MAX/sizeof(TYPE));    // no overflow
#endif
	m_pData = (TYPE*) new NEWB_BYTE[(size_t)m_nMaxSize * sizeof(TYPE)];
	memset((NEWB_VOID*)m_pData, 0, (size_t)m_nMaxSize * sizeof(TYPE));
}

template<class TYPE, class ARG_TYPE>
NewBValArray<TYPE, ARG_TYPE>::~NewBValArray()
{
	NEWB_ASSERT_VALID(this);

	if (m_pData != NULL)
	{
		for( int i = 0; i < m_nSize; i++ )
			(m_pData + i)->~TYPE();
//			delete ((NEWB_BYTE*)m_pData) (TYPE*)(m_pData + i);
		delete[] (NEWB_BYTE*)m_pData;
	}
}

template<class TYPE, class ARG_TYPE>
NEWB_INT NewBValArray<TYPE, ARG_TYPE>::SetSize(NEWB_INT nNewSize, NEWB_INT nGrowBy)
{
	NEWB_ASSERT_VALID(this);
	NEWB_ASSERT(nNewSize >= 0);

	NEWB_INT i = 0;// iterator

	NEWB_INT nOldSize = m_nSize;
	

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

	if (nNewSize == 0) // Array now contains 0 elements
	{
	//  [3/15/2002]
	//	Remove all "allocate" object but not destroy the main memory

		if (m_pData != NULL)
		{
			// Effective call destructor of each elements
			// i.e counterpart of placement new.
			for(i = 0; i < m_nSize; i++ )
				(m_pData + i)->~TYPE(); 
		}

		m_nSize = 0;
	}
	else if (m_pData == NULL)
	{
		//  [3/15/2002]
		//	Call SetSize() after create object using default constructor
		//  i.e no preserved memory
#ifdef SIZE_T_MAX
		NEWB_ASSERT(nNewSize <= SIZE_T_MAX/sizeof(TYPE));    // no overflow
#endif
		size_t nAllocSize = max(nNewSize, m_nGrowBy);

		//  [3/15/2002]
		//  Really allocate memory to m_pData
		m_pData = (TYPE*) new NEWB_BYTE[(size_t)nAllocSize * sizeof(TYPE)];
		memset((NEWB_VOID*)m_pData, 0, (size_t)nAllocSize * sizeof(TYPE));

		//  [3/15/2002]
		//  Call placement new to "construct" elements
		for(i = 0; i < nNewSize; i++ )
#pragma push_macro("new")
#undef new
			::new( (NEWB_VOID*)( m_pData + i ) ) TYPE;
#pragma pop_macro("new")

		m_nSize = nNewSize;
		m_nMaxSize = nAllocSize;

	}
	else if (nNewSize <= m_nMaxSize)
	{
		// The new size is fits current allocated pool.
		if (nNewSize > m_nSize)
		{
			// initialize the new elements
			memset((NEWB_VOID*)(m_pData + m_nSize), 0, (size_t)(nNewSize-m_nSize) * sizeof(TYPE));

			for(i = 0; i < nNewSize-m_nSize; i++ )
#pragma push_macro("new")
#undef new
				::new( (NEWB_VOID*)( m_pData + m_nSize + i ) ) (TYPE);
#pragma pop_macro("new")

		}
		else if (m_nSize > nNewSize)
		{
			// Need to truncate array -> destroy the old elements
			for(i = 0; i < m_nSize-nNewSize; i++ )
				(m_pData + nNewSize + i)->~TYPE();
		}

		m_nSize = nNewSize;
	}
	else // nNewSize > m_nMaxSize
	{
		// Need to allocate a larger pool -> bad things here

		nGrowBy = m_nGrowBy;

		//  [3/15/2002]
		// Calculate m_nGrowBy
		if (nGrowBy == 0)
		{
			// heuristically determine growth when nGrowBy == 0
			//  (this avoids heap fragmentation in many situations)
			nGrowBy = m_nSize / 8;
			nGrowBy = (nGrowBy < 4) ? 4 : ((nGrowBy > 1024) ? 1024 : nGrowBy);
		}

		//  [3/15/2002]
		//  Calculate new size in bytes of pool
		NEWB_INT nNewMax = 0;
		if (nNewSize < m_nMaxSize + nGrowBy)
			nNewMax = m_nMaxSize + nGrowBy;  // granularity
		else
			nNewMax = nNewSize;  // no slush

		NEWB_ASSERT(nNewMax >= m_nMaxSize);  // no wrap around
#ifdef SIZE_T_MAX
		NEWB_ASSERT(nNewMax <= SIZE_T_MAX/sizeof(TYPE)); // no overflow
#endif
		//  [3/15/2002]
		//  Allocate a new memory pool has enough size
		TYPE* pNewData = (TYPE*) new NEWB_BYTE[(size_t)nNewMax * sizeof(TYPE)];

		// copy new data from old pool
		memcpy(pNewData, m_pData, (size_t)m_nSize * sizeof(TYPE));

		// construct remaining elements by calling placement new
		NEWB_ASSERT(nNewSize > m_nSize);
		memset((NEWB_VOID*)(pNewData + m_nSize), 0, (size_t)(nNewSize-m_nSize) * sizeof(TYPE));

		for( int i = 0; i < nNewSize-m_nSize; i++ )
#pragma push_macro("new")
#undef new
			::new( (NEWB_VOID*)( pNewData + m_nSize + i ) ) TYPE;
#pragma pop_macro("new")

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

	return nOldSize;
}

template<class TYPE, class ARG_TYPE>
NEWB_INT NewBValArray<TYPE, ARG_TYPE>::Append(const NewBValArray& src)
{
	NEWB_ASSERT_VALID(this);
	NEWB_ASSERT(this != &src);   // cannot append to itself

	NEWB_INT nOldSize = m_nSize;
	SetSize(m_nSize + src.m_nSize);
	CopyElements<TYPE>(m_pData + nOldSize, src.m_pData, src.m_nSize);
	return nOldSize;
}

template<class TYPE, class ARG_TYPE>
NEWB_VOID NewBValArray<TYPE, ARG_TYPE>::Copy(const NewBValArray& src)
{
	NEWB_ASSERT_VALID(this);
	NEWB_ASSERT(this != &src);   // cannot append to itself

	SetSize(src.m_nSize);
	CopyElements<TYPE>(m_pData, src.m_pData, src.m_nSize);
}

template<class TYPE, class ARG_TYPE>
NEWB_VOID NewBValArray<TYPE, ARG_TYPE>::FreeExtra()
{
	NEWB_ASSERT_VALID(this);

	if (m_nSize != m_nMaxSize)
	{
		// shrink to desired size
#ifdef SIZE_T_MAX
		NEWB_ASSERT(m_nSize <= SIZE_T_MAX/sizeof(TYPE)); // no overflow
#endif
		TYPE* pNewData = NULL;
		if (m_nSize != 0)
		{
			pNewData = (TYPE*) new NEWB_BYTE[m_nSize * sizeof(TYPE)];
			// copy new data from old
			memcpy(pNewData, m_pData, m_nSize * sizeof(TYPE));
		}

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

template<class TYPE, class ARG_TYPE>
NEWB_VOID NewBValArray<TYPE, ARG_TYPE>::SetAtGrow(NEWB_INT nIndex, ARG_TYPE newElement)
{
	NEWB_ASSERT_VALID(this);
	NEWB_ASSERT(nIndex >= 0);

	if (nIndex >= m_nMaxSize)
		SetSize(nIndex+1, -1); // Need to grow. Bad!!!!

#pragma push_macro("new")
#undef new
	::new( (NEWB_VOID*)( m_pData + nIndex ) ) TYPE;
#pragma pop_macro("new")

	m_pData[nIndex] = newElement;
}

template<class TYPE, class ARG_TYPE>
NEWB_VOID NewBValArray<TYPE, ARG_TYPE>::InsertAt(NEWB_INT nIndex, ARG_TYPE newElement, NEWB_INT nCount /*=1*/)
{
	NEWB_ASSERT_VALID(this);
	NEWB_ASSERT(nIndex >= 0);    // will expand to meet need
	NEWB_ASSERT(nCount > 0);     // zero or negative size not allowed
	
	int i = 0;

	//  [3/15/2002] 
	//  Insert at a position outside current upperbound of elements array
	if (nIndex >= m_nSize)
	{
		// adding after the end of the array
		SetSize(nIndex + nCount, -1);   // grow so nIndex is valid
	}
	else
	{
		// inserting in the middle of the array
		NEWB_INT nOldSize = m_nSize;
		SetSize(m_nSize + nCount, -1);  // grow it to new element size

		// destroy intial data before copying over it
		for( i = 0; i < nCount; i++ )
			(m_pData + nOldSize + i)->~TYPE();

		// shift old data up to fill gap
		memmove(m_pData + nIndex + nCount, m_pData + nIndex,
			(nOldSize-nIndex) * sizeof(TYPE));

		// re-init slots we copied from
		memset((NEWB_VOID*)(m_pData + nIndex), 0, (size_t)nCount * sizeof(TYPE));

		for( i = 0; i < nCount; i++ )
#pragma push_macro("new")
#undef new
			::new( (NEWB_VOID*)( m_pData + nIndex + i ) ) TYPE;
#pragma pop_macro("new")
	}

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

	while (nCount--)
		m_pData[nIndex++] = newElement;
}

template<class TYPE, class ARG_TYPE>
NEWB_VOID NewBValArray<TYPE, ARG_TYPE>::RemoveAt(NEWB_INT nIndex, NEWB_INT nCount)
{
	NEWB_ASSERT_VALID(this);
	NEWB_ASSERT(nIndex >= 0);
	NEWB_ASSERT(nCount >= 0);
	NEWB_ASSERT(nIndex + nCount <= m_nSize);

	// just remove a range
	NEWB_INT nMoveCount = m_nSize - (nIndex + nCount);

	for( int i = 0; i < nCount; i++ )
		(m_pData + nIndex + i)->~TYPE();

	if (nMoveCount)
		memmove( m_pData + nIndex, m_pData + nIndex + nCount,
			(size_t)nMoveCount * sizeof(TYPE));

	m_nSize -= nCount;
}

template<class TYPE, class ARG_TYPE>
NEWB_VOID NewBValArray<TYPE, ARG_TYPE>::InsertAt(NEWB_INT nStartIndex, NewBValArray* pNewArray)
{
	NEWB_ASSERT_VALID(this);
	NEWB_ASSERT(pNewArray != NULL);
	NEWB_ASSERT_VALID(pNewArray);
	NEWB_ASSERT(nStartIndex >= 0);

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

#endif __NEWB_VAL_ARRAY_H__

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Colombia Colombia
My name is Francisco Campos, A developer as you.I have the title of Engineer of Systems of the Universidad Autonoma de Colombia.My real Job Information Security officer, experience in security assessment, applications, and other related subjects.

Francisco.camposg@outlook.com

Comments and Discussions