Kirjoittaja: Asko Telinen
Kirjoitettu: 02.12.2004 – 02.12.2004
Tagit: koodi näytille, vinkki
Tulipa sitten kirjoitettua sellainen muun ohella kun kyllästyin kirjoittamaan aina malloc/calloc varaaman muistin käsittelyyn liittyvää koodia.
// Tiedosto : DynamicBuffer.h
#ifndef ___DYNAMIC_BUFFER__H__D31DFCFB_5BCE_4556_A1B8_FE2D98523A1F__DEFINED__
#define ___DYNAMIC_BUFFER__H__D31DFCFB_5BCE_4556_A1B8_FE2D98523A1F__DEFINED__
#include <stdlib.h>
#include <memory.h>
#include <string.h>
namespace atlib {
// Error messages
static const char *BUFFERERROR_INDEX_OUT_OF_BOUNDS = "Invalid index !!!";
static const char *BUFFERERROR_OUT_OF_MEMORY = "Not enough memory to complete requested operation !!!";
static const char *BUFFERERROR_INVALID_BUFFER = "Buffer is not allocated yet !!!";
static const char *BUFFERERROR_INVALID_PARAMETER = "The parameter is incorrect !!!";
// block size
#ifndef BLOCK
#define BLOCK unsigned char
#endif
#define CHECK_BUFFER(buffer) { if ( !buffer ) { throw BUFFERERROR_INVALID_BUFFER; } }
#define CHECK_INDEX(Index) { if ( Index >= getSize() ) { throw BUFFERERROR_INDEX_OUT_OF_BOUNDS; } }
typedef unsigned long INDEX_TYPE;
// error index
static const INDEX_TYPE npos = (INDEX_TYPE)(-1);
template<class __DataType>
class DynamicBuffer {
public:
typedef __DataType DATA;
typedef __DataType* LPDATA;
typedef const __DataType* LPCDATA;
protected:
LPDATA m_pBuffer; // Actual data
INDEX_TYPE m_Size; // Allocated size (in block size)
static unsigned short BLOCKSIZE();
bool DoInsert(LPCDATA lpSourceData, INDEX_TYPE ulSourceSize, INDEX_TYPE ulOffset);
virtual void Copy(INDEX_TYPE ulStartIndex, LPCDATA lpSourceData, INDEX_TYPE ulSourceSize);
virtual void Move(INDEX_TYPE ulDestinationIndex, INDEX_TYPE ulSourceIndex, INDEX_TYPE ulCount);
public:
DynamicBuffer(INDEX_TYPE ulSize = 0);
DynamicBuffer(const DynamicBuffer<__DataType> &db); // copy constructor
virtual ~DynamicBuffer();
void Fill(__DataType Value);
void Fill(__DataType Value, INDEX_TYPE ulOffset);
void Fill(__DataType Value, INDEX_TYPE ulOffset, INDEX_TYPE ulCount);
virtual bool Allocate(INDEX_TYPE ulSize);
void Release();
void setAt(INDEX_TYPE ulIndex, __DataType NewValue);
__DataType getAt(INDEX_TYPE ulIndex) const;
bool Append(const DynamicBuffer<__DataType> &Source);
bool Append(LPCDATA lpSource, INDEX_TYPE lpDataSize);
bool Append(__DataType Data);
bool Insert(const DynamicBuffer<__DataType> &Source, INDEX_TYPE ulOffset);
bool Insert(const DynamicBuffer<__DataType> &Source, LPCDATA lpBeginPtr);
bool Insert(LPCDATA lpSource, INDEX_TYPE ulDataSize, INDEX_TYPE ulOffset);
bool Insert(LPCDATA lpSource, INDEX_TYPE ulDataSize, LPCDATA lpBeginPtr);
bool Insert(__DataType Data, INDEX_TYPE ulOffset);
bool Insert(__DataType Data, LPCDATA lpBeginPtr);
virtual __DataType Replace(__DataType Data, INDEX_TYPE ulOffset);
virtual __DataType Replace(__DataType Data, LPCDATA lpBeginPtr);
virtual bool Replace(const DynamicBuffer<__DataType> &Source, INDEX_TYPE ulOffset, INDEX_TYPE ulCount);
virtual bool Replace(const DynamicBuffer<__DataType> &Source, LPCDATA lpBeginPtr, LPCDATA lpEndPtr);
virtual bool Replace(LPCDATA lpSource, INDEX_TYPE ulDataSize, INDEX_TYPE ulOffset, INDEX_TYPE ulCount);
virtual bool Replace(LPCDATA lpSource, INDEX_TYPE ulDataSize, LPCDATA lpBeginPtr, LPCDATA lpEndPtr);
bool Erase(INDEX_TYPE ulOffset, INDEX_TYPE ulCount);
bool Erase(LPCDATA lpBeginPtr, LPCDATA lpEndPtr);
virtual void setBuffer(LPDATA lpNewBuffer, INDEX_TYPE ulBufferSize);
virtual LPDATA getBuffer() { return m_pBuffer; }
virtual INDEX_TYPE ptrToOffset(LPCDATA lpPtr) const;
virtual bool getSlice(LPCDATA lpBeginPtr, LPCDATA lpEndPtr, DynamicBuffer<__DataType> &Result) const;
virtual bool getSlice(INDEX_TYPE ulOffset, INDEX_TYPE ulCount, DynamicBuffer<__DataType> &Result) const;
// size
virtual INDEX_TYPE getSize() const { return m_Size; }
virtual INDEX_TYPE getByteSize() const { return getSize() * BLOCKSIZE(); }
virtual bool setSize(INDEX_TYPE ulNewSize);
///////////////////////////////////////////////////////////////////////////////////////////////////
// operator overloading
__DataType operator[](INDEX_TYPE ulIndex) const { return getAt(ulIndex); }
//DynamicBuffer<__DataType> & operator+(DynamicBuffer<__DataType> &db);
virtual DynamicBuffer<__DataType> & operator=(const DynamicBuffer<__DataType> &db);
virtual DynamicBuffer<__DataType> & operator+=(const DynamicBuffer<__DataType> &db);
virtual bool operator==(const DynamicBuffer<__DataType> &db);
virtual bool operator!=(const DynamicBuffer<__DataType> &db);
virtual bool operator!() const { return (m_pBuffer == NULL); }
operator LPCDATA() const { return (LPCDATA)m_pBuffer; }
operator LPDATA() { return (LPDATA)m_pBuffer; }
/*------------------------------------------------------------------------------------------------*/
};
///////////////////////////////////////////////////////////////////////////////////////////////////
// Static members
// Retuns __DataType size in bytes
template<class __DataType>
unsigned short DynamicBuffer<__DataType>::BLOCKSIZE()
{
return sizeof(__DataType) * sizeof(BLOCK);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// Copy constructor
template<class __DataType>
DynamicBuffer<__DataType>::DynamicBuffer(const DynamicBuffer<__DataType> &db) : m_pBuffer(NULL), m_Size(0)
{
*this = db;
}
template<class __DataType>
DynamicBuffer<__DataType>::DynamicBuffer(INDEX_TYPE ulSize) : m_pBuffer(NULL), m_Size(0)
{
if ( !Allocate(ulSize) ) {
throw BUFFERERROR_OUT_OF_MEMORY;
}
}
template<class __DataType>
DynamicBuffer<__DataType>::~DynamicBuffer()
{
Release();
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// Utility methods
template<class __DataType>
void DynamicBuffer<__DataType>::Copy(INDEX_TYPE ulStartIndex, LPCDATA lpSourceData, INDEX_TYPE ulSourceSize)
{
memcpy(m_pBuffer + ulStartIndex, lpSourceData, ulSourceSize * BLOCKSIZE());
}
template<class __DataType>
void DynamicBuffer<__DataType>::Move(INDEX_TYPE ulDestinationIndex, INDEX_TYPE ulSourceIndex, INDEX_TYPE ulCount)
{
memmove(m_pBuffer + ulDestinationIndex, m_pBuffer + ulSourceIndex, ulCount * BLOCKSIZE());
}
template<class __DataType>
INDEX_TYPE DynamicBuffer<__DataType>::ptrToOffset(LPCDATA lpPtr) const
{
CHECK_BUFFER(m_pBuffer);
if ( !lpPtr || lpPtr > m_pBuffer + getSize() || lpPtr < m_pBuffer ) {
return npos;
}
return (INDEX_TYPE)(lpPtr - m_pBuffer);
}
template<class __DataType>
void DynamicBuffer<__DataType>::setAt(INDEX_TYPE ulIndex, __DataType NewValue)
{
CHECK_BUFFER(m_pBuffer);
CHECK_INDEX(ulIndex);
(DATA)m_pBuffer[ulIndex] = NewValue;
}
template<class __DataType>
__DataType DynamicBuffer<__DataType>::getAt(INDEX_TYPE ulIndex) const
{
CHECK_INDEX(ulIndex);
return (__DataType)m_pBuffer[ulIndex];
}
// Set the allocated memory size. New size is in block size
template<class __DataType>
bool DynamicBuffer<__DataType>::setSize(INDEX_TYPE ulNewSize)
{
if ( ulNewSize == getSize() ) {
return true;
}
if ( ulNewSize == 0 ) {
Release();
}
else {
if ( !m_pBuffer ) {
return Allocate(ulNewSize);
}
else {
m_pBuffer = (LPDATA)realloc(m_pBuffer, ulNewSize * BLOCKSIZE());
if ( !m_pBuffer ) {
return false;
}
if ( ulNewSize > getSize() ) {
// Pad with zeros
memset(m_pBuffer + getSize(), 0, (ulNewSize - getSize()) * BLOCKSIZE());
}
}
}
m_Size = ulNewSize;
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//
// MODIFY
//
///////////////////////////////////////////////////////////////////////////////////////////////////
template<class __DataType>
void DynamicBuffer<__DataType>::setBuffer(LPDATA lpNewBuffer, INDEX_TYPE ulBufferSize)
{
Release();
if ( lpNewBuffer && ulBufferSize ) {
m_pBuffer = lpNewBuffer;
m_Size = ulBufferSize;
}
else {
throw BUFFERERROR_INVALID_PARAMETER;
}
}
/*------------------------------------------------------------------------------------------------*/
// Append
template<class __DataType>
bool DynamicBuffer<__DataType>::Append(const DynamicBuffer<__DataType> &Source)
{
return Insert(Source, getSize());
}
template<class __DataType>
bool DynamicBuffer<__DataType>::Append(__DataType Data)
{
return Insert(Data, getSize());
}
template<class __DataType>
bool DynamicBuffer<__DataType>::Append(LPCDATA lpSource, INDEX_TYPE lpDataSize)
{
return Insert(lpSource, lpDataSize, getSize());
}
/*------------------------------------------------------------------------------------------------*/
// Insert
template<class __DataType>
bool DynamicBuffer<__DataType>::DoInsert(LPCDATA lpSourceData, INDEX_TYPE ulSourceSize, INDEX_TYPE ulOffset)
{
if ( !lpSourceData ) {
return true;
}
// We need to check it before setting new size because the m_pBuffer pointer might change...
bool bDuplicate = (lpSourceData == m_pBuffer);
LPDATA tmp_buffer = NULL;
if ( bDuplicate ) { // same object, so we duplicate it
// Create copy of current data
tmp_buffer = (LPDATA)calloc(ulSourceSize, BLOCKSIZE());
if ( !tmp_buffer ) {
return false;
}
memcpy(tmp_buffer, m_pBuffer, ulSourceSize * BLOCKSIZE());
}
if ( !setSize(getSize() + ulSourceSize) ) {
if ( tmp_buffer ) {
free((void *)tmp_buffer);
}
return false;
}
// Define source data
LPDATA lpSource = (LPDATA)lpSourceData;
if ( bDuplicate ) { // same object
lpSource = tmp_buffer;
}
if ( ulOffset >= getSize() - ulSourceSize ) {
// Append
Copy(getSize() - ulSourceSize, lpSource, ulSourceSize);
}
else {
// Insert
Move(ulOffset + ulSourceSize, ulOffset, getSize() - ulOffset - ulSourceSize);
Copy(ulOffset, lpSource, ulSourceSize);
}
if ( tmp_buffer ) {
free((void *)tmp_buffer);
}
return true;
}
template<class __DataType>
bool DynamicBuffer<__DataType>::Insert(LPCDATA lpSource, INDEX_TYPE ulDataSize, INDEX_TYPE ulOffset)
{
return DoInsert(lpSource, ulDataSize, ulOffset);
}
template<class __DataType>
bool DynamicBuffer<__DataType>::Insert(const DynamicBuffer<__DataType> &Source, INDEX_TYPE ulOffset)
{
return DoInsert((LPCDATA)Source, Source.getSize(), ulOffset);
}
template<class __DataType>
bool DynamicBuffer<__DataType>::Insert(__DataType Data, INDEX_TYPE ulOffset)
{
CHECK_BUFFER(m_pBuffer);
if ( !setSize(getSize() + 1) ) {
return false;
}
if ( ulOffset >= getSize() - 1 ) { // new size is one block bigger
// Append
setAt(getSize() - 1, Data); // set last block
}
else {
// Insert
memmove(m_pBuffer + ulOffset + 1, m_pBuffer + ulOffset, (getSize() - ulOffset - 1) * BLOCKSIZE());
setAt(ulOffset, Data);
}
return true;
}
template<class __DataType>
bool DynamicBuffer<__DataType>::Insert(LPCDATA lpSource, INDEX_TYPE ulDataSize, LPCDATA lpBeginPtr)
{
INDEX_TYPE ulOffset = PtrToOffset(lpBeginPtr);
if ( ulOffset == npos ) {
return false;
}
return Insert(lpSource, ulDataSize, ulOffset);
}
template<class __DataType>
bool DynamicBuffer<__DataType>::Insert(__DataType Data, LPCDATA lpBeginPtr)
{
INDEX_TYPE ulOffset = PtrToOffset(lpBeginPtr);
if ( ulOffset == npos ) {
return false;
}
return Insert(Data, ulOffset);
}
template<class __DataType>
bool DynamicBuffer<__DataType>::Insert(const DynamicBuffer<__DataType> &Source, LPCDATA lpBeginPtr)
{
INDEX_TYPE ulOffset = PtrToOffset(lpBeginPtr);
if ( ulOffset == npos ) {
return false;
}
return Insert(Source, ulOffset);
}
/*------------------------------------------------------------------------------------------------*/
// Erase
template<class __DataType>
bool DynamicBuffer<__DataType>::Erase(INDEX_TYPE ulOffset, INDEX_TYPE ulCount)
{
CHECK_BUFFER(m_pBuffer);
if ( ulOffset + ulCount > getSize() ) {
throw BUFFERERROR_INVALID_PARAMETER;
}
// Check special cases
if ( ulOffset + ulCount == getSize() ) { // Delete from end of the buffer ?
if ( ulOffset == 0 ) { // Delete whole buffer?
Release();
return true;
}
return setSize(ulOffset - 1);
}
// move the memory after the block we´re erasing
memmove(m_pBuffer + ulOffset, m_pBuffer + ulOffset + ulCount, (getSize() - (ulOffset + ulCount)) * BLOCKSIZE());
// set new size
return setSize(getSize() - ulCount);
}
template<class __DataType>
bool DynamicBuffer<__DataType>::Erase(LPCDATA lpBeginPtr, LPCDATA lpEndPtr)
{
INDEX_TYPE ulOffset = PtrToOffset(lpBeginPtr);
INDEX_TYPE ulCount = PtrToOffset(lpEndPtr);
if ( ulOffset == npos || ulCount == npos || ulCount < ulOffset ) {
return false;
}
// Calculate count
ulCount = ulCount - ulOffset + 1;
return Erase(ulOffset, ulCount);
}
/*------------------------------------------------------------------------------------------------*/
// Replace
template<class __DataType>
__DataType DynamicBuffer<__DataType>::Replace(__DataType Data, INDEX_TYPE ulOffset)
{
__DataType retval = getAt(ulOffset);
setAt(ulOffset, Data);
return retval;
}
template<class __DataType>
bool DynamicBuffer<__DataType>::Replace(const DynamicBuffer<__DataType> &Source, INDEX_TYPE ulOffset, INDEX_TYPE ulCount)
{
if ( &Source == this ) {
throw BUFFERERROR_INVALID_PARAMETER;
}
if ( Erase(ulOffset, ulCount) ) {
return Insert(Source, ulOffset);
}
return false;
}
template<class __DataType>
bool DynamicBuffer<__DataType>::Replace(LPCDATA lpSource, INDEX_TYPE ulDataSize, INDEX_TYPE ulOffset, INDEX_TYPE ulCount)
{
if ( m_pBuffer && (m_pBuffer == lpSource) ) {
throw BUFFERERROR_INVALID_PARAMETER;
}
if ( Erase(ulOffset, ulCount) ) {
return DoInsert(lpSource, ulDataSize, ulOffset);
}
return false;
}
template<class __DataType>
bool DynamicBuffer<__DataType>::Replace(LPCDATA lpSource, INDEX_TYPE ulDataSize, LPCDATA lpBeginPtr, LPCDATA lpEndPtr)
{
INDEX_TYPE ulOffset = ptrToOffset(lpBeginPtr);
INDEX_TYPE ulCount = ptrToOffset(lpEndPtr);
if ( ulOffset == npos || ulCount == npos || ulCount < ulOffset ) {
return false;
}
// Calculate count
ulCount = ulCount - ulOffset + 1;
return Replace(lpSource, ulDataSize, ulOffset, ulCount);
}
template<class __DataType>
bool DynamicBuffer<__DataType>::Replace(const DynamicBuffer<__DataType> &Source, LPCDATA lpBeginPtr, LPCDATA lpEndPtr)
{
INDEX_TYPE ulOffset = ptrToOffset(lpBeginPtr);
INDEX_TYPE ulCount = ptrToOffset(lpEndPtr);
if ( ulOffset == npos || ulCount == npos || ulCount < ulOffset ) {
return false;
}
// Calculate count
ulCount = ulCount - ulOffset + 1;
return Replace(Source, ulOffset, ulCount);
}
template<class __DataType>
__DataType DynamicBuffer<__DataType>::Replace(__DataType Data, LPCDATA lpBeginPtr)
{
INDEX_TYPE ulOffset = ptrToOffset(lpBeginPtr);
if ( ulOffset == npos ) {
return false;
}
return Replace(Data, ulOffset);
}
/*------------------------------------------------------------------------------------------------*/
// Slice
template<class __DataType>
bool DynamicBuffer<__DataType>::getSlice(LPCDATA lpBeginPtr, LPCDATA lpEndPtr, DynamicBuffer<__DataType> &Result) const
{
Result.Release();
INDEX_TYPE ulOffset = ptrToOffset(lpBeginPtr);
INDEX_TYPE ulCount = ptrToOffset(lpEndPtr);
if ( ulOffset == npos || ulCount == npos || ulCount < ulOffset ) {
return false;
}
ulCount = ulCount - ulOffset + 1;
return getSlice(ulOffset, ulCount, Result);
}
template<class __DataType>
bool DynamicBuffer<__DataType>::getSlice(INDEX_TYPE ulOffset, INDEX_TYPE ulCount, DynamicBuffer<__DataType> &Result) const
{
CHECK_BUFFER(m_pBuffer);
Result.Release();
if ( ulOffset + ulCount > getSize() ) {
return false;
}
if ( ulCount == 0 ) {
return true;
}
if ( !Result.setSize(ulCount) ) {
return false;
}
memcpy(Result.getBuffer(), m_pBuffer + ulOffset, ulCount * BLOCKSIZE());
return true;
}
/*------------------------------------------------------------------------------------------------*/
// Fill
template<class __DataType>
void DynamicBuffer<__DataType>::Fill(__DataType Value)
{
Fill(Value, 0, getSize());
}
template<class __DataType>
void DynamicBuffer<__DataType>::Fill(__DataType Value, INDEX_TYPE ulOffset)
{
Fill(Value, ulOffset, getSize() - ulOffset);
}
template<class __DataType>
void DynamicBuffer<__DataType>::Fill(__DataType Value, INDEX_TYPE ulOffset, INDEX_TYPE ulCount)
{
if ( ulOffset + ulCount > getSize() ) {
throw BUFFERERROR_INVALID_INDEX;
}
for ( INDEX_TYPE m = 0; m < ulCount / 2; m++ ) {
setAt(ulOffset + m, Value);
setAt(ulOffset + ulCount - 1 - m, Value);
}
if ( ulCount % 2 != 0 ) { // not even
setAt(ulOffset + ulCount / 2, Value);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//
// Operator overloading
//
///////////////////////////////////////////////////////////////////////////////////////////////////
template<class __DataType>
DynamicBuffer<__DataType> & DynamicBuffer<__DataType>::operator+=(const DynamicBuffer<__DataType> &db)
{
Append(db);
return *this;
}
template<class __DataType>
DynamicBuffer<__DataType> & DynamicBuffer<__DataType>::operator=(const DynamicBuffer<__DataType> &db)
{
if ( &db == this ) {
return *this;
}
if ( db.getSize() != getSize() ) {
if ( db.getSize() == 0 ) {
Release();
}
else if ( !setSize(db.getSize()) ) {
throw BUFFERERROR_OUT_OF_MEMORY;
}
}
if ( getSize() > 0 ) {
Copy(0, db.m_pBuffer, getSize());
}
return *this;
}
template<class __DataType>
bool DynamicBuffer<__DataType>::operator==(const DynamicBuffer<__DataType> &db)
{
if ( &db == this ) {
return true;
}
if ( !m_pBuffer || !db.m_pBuffer || getSize() != db.getSize() ) {
return false;
}
return (memcmp(m_pBuffer, db.m_pBuffer, getSize()) == 0);
}
template<class __DataType>
bool DynamicBuffer<__DataType>::operator!=(const DynamicBuffer<__DataType> &db)
{
return !(*this == db);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//
// Data allocation and release
//
///////////////////////////////////////////////////////////////////////////////////////////////////
// Allocates memory. Releases already allocated memory, if any.
// Size is in block size
template<class __DataType>
bool DynamicBuffer<__DataType>::Allocate(INDEX_TYPE ulSize)
{
Release();
if ( ulSize > 0 ) {
// Allocate moemory
m_pBuffer = (LPDATA)calloc(ulSize, BLOCKSIZE());
if ( !m_pBuffer ) {
return false;
}
m_Size = ulSize;
}
return true;
}
template<class __DataType>
void DynamicBuffer<__DataType>::Release()
{
if ( m_pBuffer ) {
free((void *)m_pBuffer);
m_pBuffer = NULL;
m_Size = 0;
}
}
} // namespace
#endif // ___DYNAMIC_BUFFER__H__D31DFCFB_5BCE_4556_A1B8_FE2D98523A1F__DEFINED__Esimerkki:
DynamicBuffer<long> buff(80); // varaa dynaamista muistia 80 long tyyppiselle luvulle buff.setAt(15) = 27; long luku16 = buff[15]; DynamicBuffer<long buff2; //Haetaan 10 lukua luvusta 16 alkaen. buff.getSlice(15, 10, buff2); //jne...aika suoraviivaista...
Okein nätti.
"__":n sisältävät symbolit on määrittelyn mukaan varattu kääntäjän/ympäristön määrittelyihin.
Eikö auto_prt riitä?
Se on auto_ptr. *nus nus* :)
Tosta taitaa puuttua BUFFERERROR_INVALID_INDEX-ilmoitus, mutta sen nyt laittaa sinne nopeasti.
Saakos tuota muuten suoraan käyttää omissa ohjelmissa jos laittaa sinun nimesi tekijäluetteloon?
EDIT:
Ja onko tuossa esimerkissä ihan kaikki funktiot?
Tupla EDIT: Eikun joo, nuo onkin aika suoraviivaiset niinkuin sanoit :)