/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sfx2.hxx"

#ifndef GCC
#endif

#include <sfx2/minarray.hxx>

// -----------------------------------------------------------------------

SfxPtrArr::SfxPtrArr( sal_uInt8 nInitSize, sal_uInt8 nGrowSize ):
	nUsed( 0 ),
	nGrow( nGrowSize ? nGrowSize : 1 ),
	nUnused( nInitSize )
{
	DBG_MEMTEST();
	sal_uInt16 nMSCBug = nInitSize;

	if ( nMSCBug > 0 )
		pData = new void*[nMSCBug];
	else
		pData = 0;
}

// -----------------------------------------------------------------------

SfxPtrArr::SfxPtrArr( const SfxPtrArr& rOrig )
{
	DBG_MEMTEST();
	nUsed = rOrig.nUsed;
	nGrow = rOrig.nGrow;
	nUnused = rOrig.nUnused;

	if ( rOrig.pData != 0 )
	{
		pData = new void*[nUsed+nUnused];
		memcpy( pData, rOrig.pData, nUsed*sizeof(void*) );
	}
	else
		pData = 0;
}

// -----------------------------------------------------------------------

SfxPtrArr::~SfxPtrArr()
{
	DBG_MEMTEST();
	delete [] pData;
}

// -----------------------------------------------------------------------

SfxPtrArr& SfxPtrArr::operator=( const SfxPtrArr& rOrig )
{
	DBG_MEMTEST();

	delete [] pData;

	nUsed = rOrig.nUsed;
	nGrow = rOrig.nGrow;
	nUnused = rOrig.nUnused;

	if ( rOrig.pData != 0 )
	{
		pData = new void*[nUsed+nUnused];
		memcpy( pData, rOrig.pData, nUsed*sizeof(void*) );
	}
	else
		pData = 0;
	return *this;
}

// -----------------------------------------------------------------------

void SfxPtrArr::Append( void* aElem )
{
	DBG_MEMTEST();
	DBG_ASSERT( sal::static_int_cast< unsigned >(nUsed+1) < ( USHRT_MAX / sizeof(void*) ), "array too large" );
	// musz das Array umkopiert werden?
	if ( nUnused == 0 )
	{
		sal_uInt16 nNewSize = (nUsed == 1) ? (nGrow==1 ? 2 : nGrow) : nUsed+nGrow;
		void** pNewData = new void*[nNewSize];
		if ( pData )
		{
			DBG_ASSERT( nUsed <= nNewSize, "" );
			memmove( pNewData, pData, sizeof(void*)*nUsed );
			delete [] pData;
		}
		nUnused = sal::static_int_cast< sal_uInt8 >(nNewSize-nUsed);
		pData = pNewData;
	}

	// jetzt hinten in den freien Raum schreiben
	pData[nUsed] = aElem;
	++nUsed;
	--nUnused;
}

// -----------------------------------------------------------------------

sal_uInt16 SfxPtrArr::Remove( sal_uInt16 nPos, sal_uInt16 nLen )
{
	DBG_MEMTEST();
	// nLen adjustieren, damit nicht ueber das Ende hinaus geloescht wird
	nLen = Min( (sal_uInt16)(nUsed-nPos), nLen );

	// einfache Aufgaben erfordern einfache Loesungen!
	if ( nLen == 0 )
		return 0;

	// bleibt vielleicht keiner uebrig
	if ( (nUsed-nLen) == 0 )
	{
		delete [] pData;
		pData = 0;
		nUsed = 0;
		nUnused = 0;
		return nLen;
	}

	// feststellen, ob das Array dadurch physikalisch schrumpft...
	if ( (nUnused+nLen) >= nGrow )
	{
		// auf die naechste Grow-Grenze aufgerundet verkleinern
		sal_uInt16 nNewUsed = nUsed-nLen;
		sal_uInt16 nNewSize = ((nNewUsed+nGrow-1)/nGrow) * nGrow;
		DBG_ASSERT( nNewUsed <= nNewSize && nNewUsed+nGrow > nNewSize,
					"shrink size computation failed" );
		void** pNewData = new void*[nNewSize];
		if ( nPos > 0 )
		{
			DBG_ASSERT( nPos <= nNewSize, "" );
			memmove( pNewData, pData, sizeof(void*)*nPos );
		}
		if ( nNewUsed != nPos )
			memmove( pNewData+nPos, pData+nPos+nLen,
					 sizeof(void*)*(nNewUsed-nPos) );
		delete [] pData;
		pData = pNewData;
		nUsed = nNewUsed;
		nUnused = sal::static_int_cast< sal_uInt8 >(nNewSize - nNewUsed);
		return nLen;
	}

	// in allen anderen Faellen nur zusammenschieben
	if ( nUsed-nPos-nLen > 0 )
		memmove( pData+nPos, pData+nPos+nLen, (nUsed-nPos-nLen)*sizeof(void*) );
	nUsed = nUsed - nLen;
	nUnused = sal::static_int_cast< sal_uInt8 >(nUnused + nLen);
	return nLen;
}

// -----------------------------------------------------------------------

sal_Bool SfxPtrArr::Remove( void* aElem )
{
	DBG_MEMTEST();
	// einfache Aufgaben ...
	if ( nUsed == 0 )
		return sal_False;

	// rueckwaerts, da meist der letzte zuerst wieder entfernt wird
	void* *pIter = pData + nUsed - 1;
	for ( sal_uInt16 n = 0; n < nUsed; ++n, --pIter )
		if ( *pIter == aElem )
		{
			Remove(nUsed-n-1, 1);
			return sal_True;
		}
	return sal_False;
}

// -----------------------------------------------------------------------

sal_Bool SfxPtrArr::Replace( void* aOldElem, void* aNewElem )
{
	DBG_MEMTEST();
	// einfache Aufgaben ...
	if ( nUsed == 0 )
		return sal_False;

	// rueckwaerts, da meist der letzte zuerst wieder entfernt wird
	void* *pIter = pData + nUsed - 1;
	for ( sal_uInt16 n = 0; n < nUsed; ++n, --pIter )
		if ( *pIter == aOldElem )
		{
			pData[nUsed-n-1] = aNewElem;
			return sal_True;
		}
	return sal_False;
}

// -----------------------------------------------------------------------

sal_Bool SfxPtrArr::Contains( const void* rItem ) const
{
	DBG_MEMTEST();
	if ( !nUsed )
		return sal_False;

	for ( sal_uInt16 n = 0; n < nUsed; ++n )
	{
		void* p = GetObject(n);
		if ( p == rItem )
			return sal_True;
	}

	return sal_False;
}

// -----------------------------------------------------------------------

void SfxPtrArr::Insert( sal_uInt16 nPos, void* rElem )
{
	DBG_MEMTEST();
	DBG_ASSERT( sal::static_int_cast< unsigned >(nUsed+1) < ( USHRT_MAX / sizeof(void*) ), "array too large" );
	// musz das Array umkopiert werden?
	if ( nUnused == 0 )
	{
		// auf die naechste Grow-Grenze aufgerundet vergroeszern
		sal_uInt16 nNewSize = nUsed+nGrow;
		void** pNewData = new void*[nNewSize];

		if ( pData )
		{
			DBG_ASSERT( nUsed < nNewSize, "" );
			memmove( pNewData, pData, sizeof(void*)*nUsed );
			delete [] pData;
		}
		nUnused = sal::static_int_cast< sal_uInt8 >(nNewSize-nUsed);
		pData = pNewData;
	}

	// jetzt den hinteren Teil verschieben
	if ( nPos < nUsed )
		memmove( pData+nPos+1, pData+nPos, (nUsed-nPos)*sizeof(void*) );

	// jetzt in den freien Raum schreiben
	memmove( pData+nPos, &rElem, sizeof(void*) );
	nUsed += 1;
	nUnused -= 1;
}

// class ByteArr ---------------------------------------------------------

ByteArr::ByteArr( sal_uInt8 nInitSize, sal_uInt8 nGrowSize ):
	nUsed( 0 ),
	nGrow( nGrowSize ? nGrowSize : 1 ),
	nUnused( nInitSize )
{
	DBG_MEMTEST();
	sal_uInt16 nMSCBug = nInitSize;

	if ( nInitSize > 0 )
		pData = new char[nMSCBug];
	else
		pData = 0;
}

// -----------------------------------------------------------------------

ByteArr::ByteArr( const ByteArr& rOrig )
{
	DBG_MEMTEST();
	nUsed = rOrig.nUsed;
	nGrow = rOrig.nGrow;
	nUnused = rOrig.nUnused;

	if ( rOrig.pData != 0 )
	{
		pData = new char[nUsed+nUnused];
		memcpy( pData, rOrig.pData, nUsed*sizeof(char) );
	}
	else
		pData = 0;
}

// -----------------------------------------------------------------------

ByteArr::~ByteArr()
{
	DBG_MEMTEST();
	delete [] pData;
}

// -----------------------------------------------------------------------

ByteArr& ByteArr::operator=( const ByteArr& rOrig )
{
	DBG_MEMTEST();

	delete [] pData;

	nUsed = rOrig.nUsed;
	nGrow = rOrig.nGrow;
	nUnused = rOrig.nUnused;

	if ( rOrig.pData != 0 )
	{
		pData = new char[nUsed+nUnused];
		memcpy( pData, rOrig.pData, nUsed*sizeof(char) );
	}
	else
		pData = 0;
	return *this;
}

// -----------------------------------------------------------------------

void ByteArr::Append( char aElem )
{
	DBG_MEMTEST();
	// musz das Array umkopiert werden?
	if ( nUnused == 0 )
	{
		sal_uInt16 nNewSize = (nUsed == 1) ? (nGrow==1 ? 2 : nGrow) : nUsed+nGrow;
		char* pNewData = new char[nNewSize];
		if ( pData )
		{
			DBG_ASSERT( nUsed <= nNewSize, "" );
			memmove( pNewData, pData, sizeof(char)*nUsed );
			delete [] pData;
		}
		nUnused = sal::static_int_cast< sal_uInt8 >(nNewSize-nUsed);
		pData = pNewData;
	}

	// jetzt hinten in den freien Raum schreiben
	pData[nUsed] = aElem;
	++nUsed;
	--nUnused;
}

// -----------------------------------------------------------------------

sal_uInt16 ByteArr::Remove( sal_uInt16 nPos, sal_uInt16 nLen )
{
	DBG_MEMTEST();
	// nLen adjustieren, damit nicht ueber das Ende hinaus geloescht wird
	nLen = Min( (sal_uInt16)(nUsed-nPos), nLen );

	// einfache Aufgaben erfordern einfache Loesungen!
	if ( nLen == 0 )
		return 0;

	// bleibt vielleicht keiner uebrig
	if ( (nUsed-nLen) == 0 )
	{
		delete [] pData;
		pData = 0;
		nUsed = 0;
		nUnused = 0;
		return nLen;
	}

	// feststellen, ob das Array dadurch physikalisch schrumpft...
	if ( (nUnused+nLen) >= nGrow )
	{
		// auf die naechste Grow-Grenze aufgerundet verkleinern
		sal_uInt16 nNewUsed = nUsed-nLen;
		sal_uInt16 nNewSize = ((nNewUsed+nGrow-1)/nGrow) * nGrow;
		DBG_ASSERT( nNewUsed <= nNewSize && nNewUsed+nGrow > nNewSize,
					"shrink size computation failed" );
		char* pNewData = new char[nNewSize];
		if ( nPos > 0 )
		{
			DBG_ASSERT( nPos <= nNewSize, "" );
			memmove( pNewData, pData, sizeof(char)*nPos );
		}
		if ( nNewUsed != nPos )
			memmove( pNewData+nPos, pData+nPos+nLen,
					 sizeof(char)*(nNewUsed-nPos) );
		delete [] pData;
		pData = pNewData;
		nUsed = nNewUsed;
		nUnused = sal::static_int_cast< sal_uInt8 >(nNewSize - nNewUsed);
		return nLen;
	}

	// in allen anderen Faellen nur zusammenschieben
	if ( nUsed-nPos-nLen > 0 )
		memmove( pData+nPos, pData+nPos+nLen, (nUsed-nPos-nLen)*sizeof(char) );
	nUsed = nUsed - nLen;
	nUnused = sal::static_int_cast< sal_uInt8 >(nUnused + nLen);
	return nLen;
}

// -----------------------------------------------------------------------

sal_Bool ByteArr::Remove( char aElem )
{
	DBG_MEMTEST();
	// einfache Aufgaben ...
	if ( nUsed == 0 )
		return sal_False;

	// rueckwaerts, da meist der letzte zuerst wieder entfernt wird
	char *pIter = pData + nUsed - 1;
	for ( sal_uInt16 n = 0; n < nUsed; ++n, --pIter )
		if ( *pIter == aElem )
		{
			Remove(nUsed-n-1, 1);
			return sal_True;
		}
	return sal_False;
}

// -----------------------------------------------------------------------

sal_Bool ByteArr::Contains( const char rItem ) const
{
	DBG_MEMTEST();
	if ( !nUsed )
		return sal_False;

	for ( sal_uInt16 n = 0; n < nUsed; ++n )
	{
		char p = GetObject(n);
		if ( p == rItem )
			return sal_True;
	}

	return sal_False;
}

// -----------------------------------------------------------------------

void ByteArr::Insert( sal_uInt16 nPos, char rElem )
{
	DBG_MEMTEST();
	// musz das Array umkopiert werden?
	if ( nUnused == 0 )
	{
		// auf die naechste Grow-Grenze aufgerundet vergroeszern
		sal_uInt16 nNewSize = nUsed+nGrow;
		char* pNewData = new char[nNewSize];

		if ( pData )
		{
			DBG_ASSERT( nUsed < nNewSize, "" );
			memmove( pNewData, pData, sizeof(char)*nUsed );
			delete [] pData;
		}
		nUnused = sal::static_int_cast< sal_uInt8 >(nNewSize-nUsed);
		pData = pNewData;
	}

	// jetzt den hinteren Teil verschieben
	if ( nPos < nUsed )
		memmove( pData+nPos+1, pData+nPos, (nUsed-nPos)*sizeof(char) );

	// jetzt in den freien Raum schreiben
	memmove( pData+nPos, &rElem, sizeof(char) );
	nUsed += 1;
	nUnused -= 1;
}

// -----------------------------------------------------------------------

char ByteArr::operator[]( sal_uInt16 nPos ) const
{
	DBG_MEMTEST();
	DBG_ASSERT( nPos < nUsed, "" );
	return *(pData+nPos);
}

// -----------------------------------------------------------------------

char& ByteArr::operator [] (sal_uInt16 nPos)
{
	DBG_MEMTEST();
	DBG_ASSERT( nPos < nUsed, "" );
	return *(pData+nPos);
}

// class WordArr ---------------------------------------------------------

WordArr::WordArr( sal_uInt8 nInitSize, sal_uInt8 nGrowSize ):
	nUsed( 0 ),
	nGrow( nGrowSize ? nGrowSize : 1 ),
	nUnused( nInitSize )
{
	DBG_MEMTEST();
	sal_uInt16 nMSCBug = nInitSize;

	if ( nInitSize > 0 )
		pData = new short[nMSCBug];
	else
		pData = 0;
}

// -----------------------------------------------------------------------

WordArr::WordArr( const WordArr& rOrig )
{
	DBG_MEMTEST();
	nUsed = rOrig.nUsed;
	nGrow = rOrig.nGrow;
	nUnused = rOrig.nUnused;

	if ( rOrig.pData != 0 )
	{
		pData = new short[nUsed+nUnused];
		memcpy( pData, rOrig.pData, nUsed*sizeof(short) );
	}
	else
		pData = 0;
}

// -----------------------------------------------------------------------

WordArr::~WordArr()
{
	DBG_MEMTEST();
	delete [] pData;
}

// -----------------------------------------------------------------------

WordArr& WordArr::operator=( const WordArr& rOrig )
{
	DBG_MEMTEST();

	delete [] pData;

	nUsed = rOrig.nUsed;
	nGrow = rOrig.nGrow;
	nUnused = rOrig.nUnused;

	if ( rOrig.pData != 0 )
	{
		pData = new short[nUsed+nUnused];
		memcpy( pData, rOrig.pData, nUsed*sizeof(short) );
	}
	else
		pData = 0;
	return *this;
}

// -----------------------------------------------------------------------

void WordArr::Append( short aElem )
{
	DBG_MEMTEST();
	// musz das Array umkopiert werden?
	if ( nUnused == 0 )
	{
		sal_uInt16 nNewSize = (nUsed == 1) ? (nGrow==1 ? 2 : nGrow) : nUsed+nGrow;
		short* pNewData = new short[nNewSize];
		if ( pData )
		{
			DBG_ASSERT( nUsed <= nNewSize, " " );
			memmove( pNewData, pData, sizeof(short)*nUsed );
			delete [] pData;
		}
		nUnused = sal::static_int_cast< sal_uInt8 >(nNewSize-nUsed);
		pData = pNewData;
	}

	// jetzt hinten in den freien Raum schreiben
	pData[nUsed] = aElem;
	++nUsed;
	--nUnused;
}

// -----------------------------------------------------------------------

sal_uInt16 WordArr::Remove( sal_uInt16 nPos, sal_uInt16 nLen )
{
	DBG_MEMTEST();
	// nLen adjustieren, damit nicht ueber das Ende hinaus geloescht wird
	nLen = Min( (sal_uInt16)(nUsed-nPos), nLen );

	// einfache Aufgaben erfordern einfache Loesungen!
	if ( nLen == 0 )
		return 0;

	// bleibt vielleicht keiner uebrig
	if ( (nUsed-nLen) == 0 )
	{
		delete [] pData;
		pData = 0;
		nUsed = 0;
		nUnused = 0;
		return nLen;
	}

	// feststellen, ob das Array dadurch physikalisch schrumpft...
	if ( (nUnused+nLen) >= nGrow )
	{
		// auf die naechste Grow-Grenze aufgerundet verkleinern
		sal_uInt16 nNewUsed = nUsed-nLen;
		sal_uInt16 nNewSize = ((nNewUsed+nGrow-1)/nGrow) * nGrow;
		DBG_ASSERT( nNewUsed <= nNewSize && nNewUsed+nGrow > nNewSize,
					"shrink size computation failed" );
		short* pNewData = new short[nNewSize];
		if ( nPos > 0 )
		{
			DBG_ASSERT( nPos <= nNewSize, "" );
			memmove( pNewData, pData, sizeof(short)*nPos );
		}
		if ( nNewUsed != nPos )
			memmove( pNewData+nPos, pData+nPos+nLen,
					 sizeof(short)*(nNewUsed-nPos) );
			delete [] pData;
		pData = pNewData;
		nUsed = nNewUsed;
		nUnused = sal::static_int_cast< sal_uInt8 >(nNewSize - nNewUsed);
		return nLen;
	}

	// in allen anderen Faellen nur zusammenschieben
	if ( nUsed-nPos-nLen > 0 )
		memmove( pData+nPos, pData+nPos+nLen, (nUsed-nPos-nLen)*sizeof(short) );
	nUsed = nUsed - nLen;
	nUnused = sal::static_int_cast< sal_uInt8 >(nUnused + nLen);
	return nLen;
}

// -----------------------------------------------------------------------

sal_Bool WordArr::Remove( short aElem )
{
	DBG_MEMTEST();
	// einfache Aufgaben ...
	if ( nUsed == 0 )
		return sal_False;

	// rueckwaerts, da meist der letzte zuerst wieder entfernt wird
	short *pIter = pData + nUsed - 1;
	for ( sal_uInt16 n = 0; n < nUsed; ++n, --pIter )
		if ( *pIter == aElem )
		{
			Remove(nUsed-n-1, 1);
			return sal_True;
		}
	return sal_False;
}

// -----------------------------------------------------------------------

sal_Bool WordArr::Contains( const short rItem ) const
{
	DBG_MEMTEST();
	if ( !nUsed )
		return sal_False;

	for ( sal_uInt16 n = 0; n < nUsed; ++n )
	{
		short p = GetObject(n);
		if ( p == rItem )
			return sal_True;
	}

	return sal_False;
}

// -----------------------------------------------------------------------

void WordArr::Insert( sal_uInt16 nPos, short rElem )
{
	DBG_MEMTEST();
	// musz das Array umkopiert werden?
	if ( nUnused == 0 )
	{
		// auf die naechste Grow-Grenze aufgerundet vergroeszern
		sal_uInt16 nNewSize = nUsed+nGrow;
		short* pNewData = new short[nNewSize];

		if ( pData )
		{
			DBG_ASSERT( nUsed < nNewSize, "" );
			memmove( pNewData, pData, sizeof(short)*nUsed );
			delete [] pData;
		}
		nUnused = sal::static_int_cast< sal_uInt8 >(nNewSize-nUsed);
		pData = pNewData;
	}

	// jetzt den hinteren Teil verschieben
	if ( nPos < nUsed )
		memmove( pData+nPos+1, pData+nPos, (nUsed-nPos)*sizeof(short) );

	// jetzt in den freien Raum schreiben
	memmove( pData+nPos, &rElem, sizeof(short) );
	nUsed += 1;
	nUnused -= 1;
}

// -----------------------------------------------------------------------

short WordArr::operator[]( sal_uInt16 nPos ) const
{
	DBG_MEMTEST();
	DBG_ASSERT( nPos < nUsed, "" );
	return *(pData+nPos);
}

// -----------------------------------------------------------------------

short& WordArr::operator [] (sal_uInt16 nPos)
{
	DBG_MEMTEST();
	DBG_ASSERT( nPos < nUsed, "" );
	return *(pData+nPos);
}


