/* AbiSource Program Utilities * Copyright (C) 1998 AbiSource, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include #include "ut_assert.h" #include "ut_types.h" #include "ut_growbuf.h" #define DEFAULT_CHUNK 1024*10 #define MIN_CHUNK 256 UT_GrowBuf::UT_GrowBuf(UT_uint32 iChunk) : m_pBuf(0), m_iSize(0), m_iSpace(0) { if (iChunk < MIN_CHUNK) iChunk = DEFAULT_CHUNK; m_iChunk = iChunk; // we defer the g_try_malloc until the first use. } UT_GrowBuf::~UT_GrowBuf() { FREEP(m_pBuf); } bool UT_GrowBuf::_growBuf(UT_uint32 spaceNeeded) { // expand the buffer if necessary to accomidate the requested space. // round up to the next multiple of the chunk size. UT_uint32 newSize = ((m_iSize+spaceNeeded+m_iChunk-1)/m_iChunk)*m_iChunk; UT_GrowBufElement * pNew = static_cast(UT_calloc(newSize,sizeof(*m_pBuf))); // Why not use g_try_realloc ? - fjf if (!pNew) return false; if (m_pBuf) { memmove(pNew,m_pBuf,m_iSize*sizeof(*m_pBuf)); g_free(m_pBuf); } m_pBuf = pNew; m_iSpace = newSize; return true; } bool UT_GrowBuf::append(const UT_GrowBufElement * pValue, UT_uint32 length) { return ins(m_iSize,pValue,length); } bool UT_GrowBuf::ins(UT_uint32 position, const UT_GrowBufElement * pValue, UT_uint32 length) { // insert the given buffer into the growbuf if (!length) { UT_ASSERT(!pValue); return true; } UT_ASSERT(pValue); if (position > m_iSize) { // Situation here: We're inserting after the end of the // buffer that we've previously used (i.e. m_iSize). // Treat the request as if we were starting at m_iSize, // subtracting from position and adding to length. UT_uint32 slack = position - m_iSize; position = m_iSize; length += slack; } if (m_iSpace-m_iSize < length) if (!_growBuf(length)) return false; if (m_iSize > position) memmove(m_pBuf+position+length,m_pBuf+position,(m_iSize-position)*sizeof(*m_pBuf)); m_iSize += length; memmove(m_pBuf+position,pValue,length*sizeof(*m_pBuf)); return true; } bool UT_GrowBuf::ins(UT_uint32 position, UT_uint32 length) { // insert zeroed space into the growbuf if (!length) return true; if (position > m_iSize) { // Situation here: We're inserting after the end of the // buffer that we've previously used (i.e. m_iSize). // Treat the request as if we were starting at m_iSize, // subtracting from position and adding to length. UT_uint32 slack = position - m_iSize; position = m_iSize; length += slack; } if (m_iSpace-m_iSize < length) if (!_growBuf(length)) return false; if (m_iSize > position) memmove(m_pBuf+position+length,m_pBuf+position,(m_iSize-position)*sizeof(*m_pBuf)); m_iSize += length; memset(m_pBuf+position,0,length*sizeof(*m_pBuf)); return true; } bool UT_GrowBuf::del(UT_uint32 position, UT_uint32 amount) { if (!amount) return true; if (!m_pBuf) return false; UT_ASSERT(position < m_iSize); UT_ASSERT(position+amount <= m_iSize); memmove(m_pBuf+position,m_pBuf+position+amount,(m_iSize-position-amount)*sizeof(*m_pBuf)); m_iSize -= amount; UT_uint32 newSpace = ((m_iSize+m_iChunk-1)/m_iChunk)*m_iChunk; //Calculate the new space needed if (newSpace != m_iSpace) { m_pBuf = static_cast(g_try_realloc(m_pBuf, newSpace*sizeof(*m_pBuf))); //Re-allocate to the smaller size m_iSpace = newSpace; //update m_iSpace to the new figure } return true; } UT_uint32 UT_GrowBuf::getLength(void) const { // return the number of items in the buffer return m_iSize; } UT_GrowBufElement * UT_GrowBuf::getPointer(UT_uint32 position) const { // return a read-only pointer to the buffer if (!m_pBuf || !m_iSize) return 0; UT_ASSERT(position < m_iSize); return m_pBuf+position; } bool UT_GrowBuf::overwrite(UT_uint32 position, UT_GrowBufElement * pValue, UT_uint32 length) { // overwrite the current cells at the given position for the given length. if (!length) { UT_ASSERT(!pValue); return true; } UT_ASSERT(pValue); if (m_iSpace < position+length) if (!_growBuf(position+length-m_iSpace)) return false; memmove(m_pBuf+position,pValue,length*sizeof(*m_pBuf)); return true; } void UT_GrowBuf::truncate(UT_uint32 position) { if ((m_pBuf == 0) && (position == 0)) return; if (position < m_iSize) m_iSize = position; UT_uint32 newSpace = ((m_iSize+m_iChunk-1)/m_iChunk)*m_iChunk; //Calculate the new space needed if (newSpace == 0) newSpace = m_iChunk; // In case of UT_GrowBuf::truncate (0) if (newSpace != m_iSpace) { m_pBuf = static_cast(g_try_realloc(m_pBuf, newSpace*sizeof(*m_pBuf))); //Re-allocate to the smaller size m_iSpace = newSpace; //update m_iSpace to the new figure } }