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 :)