blob: 9b2fd82d650488ff550c5ba0e8a5464c099136f1 [file] [log] [blame]
/**************************************************************
*
* 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_tools.hxx"
#ifndef _LIMITS_H
#include <limits.h>
#endif
#ifndef _STRING_H
#include <string.h>
#endif
#ifndef _STDIO_H
#include <stdio.h>
#endif
#include <tools/solar.h>
#include <impcont.hxx>
#include <tools/contnr.hxx>
#include <tools/debug.hxx>
// -----------------------------------------------------------------------
DBG_NAME( CBlock )
DBG_NAME( Container )
/*************************************************************************
|*
|* DbgCheckCBlock()
|*
|* Beschreibung Pruefung eines CBlock fuer Debug-Utilities
|* Ersterstellung MI 30.01.92
|* Letzte Aenderung TH 24.01.96
|*
*************************************************************************/
#ifdef DBG_UTIL
const char* CBlock::DbgCheckCBlock( const void* pBlock )
{
CBlock* p = (CBlock*)pBlock;
if ( p->nCount > p->nSize )
return "nCount > nSize";
if ( p->nSize && !p->pNodes )
return "nSize > 0 && pNodes == NULL";
return NULL;
}
#endif
/*************************************************************************
|*
|* CBlock::CBlock()
|*
|* Beschreibung Construktor des Verwaltungsblocks
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
CBlock::CBlock( sal_uInt16 nInitSize, CBlock* _pPrev, CBlock* _pNext )
{
DBG_CTOR( CBlock, DbgCheckCBlock );
pPrev = _pPrev;
pNext = _pNext;
nSize = nInitSize;
nCount = 0;
// Datenpuffer anlegen
pNodes = new PVOID[nSize];
}
/*************************************************************************
|*
|* CBlock::CBlock()
|*
|* Beschreibung Construktor des Verwaltungsblocks
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
CBlock::CBlock( sal_uInt16 _nSize, CBlock* _pPrev )
{
DBG_CTOR( CBlock, DbgCheckCBlock );
DBG_ASSERT( _nSize, "CBlock::CBlock(): nSize == 0" );
pPrev = _pPrev;
pNext = NULL;
nSize = _nSize;
nCount = _nSize;
// Datenpuffer anlegen und initialisieren
pNodes = new PVOID[nSize];
memset( pNodes, 0, nSize*sizeof(PVOID) );
}
/*************************************************************************
|*
|* CBlock::CBlock()
|*
|* Beschreibung Copy-Construktor des Verwaltungsblocks
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
CBlock::CBlock( const CBlock& r, CBlock* _pPrev )
{
DBG_CTOR( CBlock, DbgCheckCBlock );
DBG_CHKOBJ( &r, CBlock, DbgCheckCBlock );
pPrev = _pPrev;
pNext = NULL;
nSize = r.nSize;
nCount = r.nCount;
// Datenpuffer anlegen und Daten kopieren
pNodes = new PVOID[nSize];
memcpy( pNodes, r.pNodes, nCount*sizeof(PVOID) );
}
/*************************************************************************
|*
|* CBlock::~CBlock()
|*
|* Beschreibung Destruktor des Verwaltungsblocks
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
inline CBlock::~CBlock()
{
DBG_DTOR( CBlock, DbgCheckCBlock );
// Daten loeschen
delete[] pNodes;
}
/*************************************************************************
|*
|* CBlock::Insert()
|*
|* Beschreibung Fuegt einen Pointer ein
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
void CBlock::Insert( void* p, sal_uInt16 nIndex, sal_uInt16 nReSize )
{
DBG_CHKTHIS( CBlock, DbgCheckCBlock );
DBG_ASSERT( nIndex <= nCount, "CBlock::Insert(): Index > nCount" );
// Muss Block realokiert werden
if ( nCount == nSize )
{
// Neue Daten anlegen
nSize = nSize + nReSize; // MSVC warns here if += is used
void** pNewNodes = new PVOID[nSize];
// Wird angehaengt
if ( nCount == nIndex )
{
// Daten kopieren
memcpy( pNewNodes, pNodes, nCount*sizeof(PVOID) );
}
else
{
// Daten kopieren
memcpy( pNewNodes, pNodes, nIndex*sizeof(PVOID) );
memcpy( pNewNodes + nIndex + 1,
pNodes + nIndex,
(nCount-nIndex)*sizeof(PVOID) );
}
// Alte Daten loeschen und neue setzen
delete[] pNodes;
pNodes = pNewNodes;
}
else
{
if ( nIndex < nCount )
{
memmove( pNodes + nIndex + 1,
pNodes + nIndex,
(nCount-nIndex)*sizeof(PVOID) );
}
}
// Neuen Pointer setzen und Elementgroesse erhoehen
pNodes[nIndex] = p;
nCount++;
}
/*************************************************************************
|*
|* CBlock::Split()
|*
|* Beschreibung Fuegt einen Pointer ein und splittet den Block
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
CBlock* CBlock::Split( void* p, sal_uInt16 nIndex, sal_uInt16 nReSize )
{
DBG_CHKTHIS( CBlock, DbgCheckCBlock );
sal_uInt16 nNewSize;
sal_uInt16 nMiddle;
CBlock* pNewBlock;
nMiddle = nCount/2;
if ( ( nIndex == nCount ) || ( nIndex == 0 ) )
nNewSize = nReSize;
else
{
// Der aktuelle Block wird in der Mitte geteilt
nNewSize = (nCount+1) / 2;
if ( nNewSize < nReSize )
nNewSize = nReSize;
else
{
// Neue Groesse muss ein vielfaches von Resize sein
if ( nNewSize % nReSize )
nNewSize += nReSize - (nNewSize % nReSize);
else
nNewSize = nNewSize + nReSize; // MSVC warns here if += is used
}
}
// Vor oder hinter dem aktuellem Block einfuegen?
if ( nIndex > nMiddle )
{
// Neuen Split-Block anlegen und hinter dem aktuellem Block einfuegen
pNewBlock = new CBlock( nNewSize, this, pNext );
if ( pNext )
pNext->pPrev = pNewBlock;
pNext = pNewBlock;
if ( nIndex == nCount )
{
// Neuen Pointer einfuegen
pNewBlock->pNodes[0] = p;
pNewBlock->nCount = 1;
}
else
{
nIndex = nIndex - nMiddle; // MSVC warns here if += is used
// Alles von Mitte bis Index kopieren
if ( nIndex )
memcpy( pNewBlock->pNodes, pNodes+nMiddle, nIndex*sizeof(PVOID) );
// Neuen Pointer einfuegen
pNewBlock->pNodes[nIndex] = p;
// Alles von Mitte bis Ende hinter Index kopieren
memcpy( pNewBlock->pNodes+nIndex+1,
pNodes+nMiddle+nIndex,
(nCount-nMiddle-nIndex) * sizeof(PVOID) );
pNewBlock->nCount = (nCount-nMiddle+1);
nCount = nMiddle;
// Den aktuellen Datenbereich auch halbieren
if ( nSize != nNewSize )
{
void** pNewNodes = new PVOID[nNewSize];
memcpy( pNewNodes, pNodes, nCount*sizeof(PVOID) );
delete[] pNodes;
pNodes = pNewNodes;
nSize = nNewSize;
}
}
}
else
{
// Neuen Split-Block anlegen und vor dem aktuellem Block einfuegen
pNewBlock = new CBlock( nNewSize, pPrev, this );
if ( pPrev )
pPrev->pNext = pNewBlock;
pPrev = pNewBlock;
if ( nIndex == 0 )
{
// Neuen Pointer einfuegen
pNewBlock->pNodes[0] = p;
pNewBlock->nCount = 1;
}
else
{
// Alles von Anfang bis Index kopieren
memcpy( pNewBlock->pNodes, pNodes, nIndex*sizeof(PVOID) );
// Neuen Pointer einfuegen
pNewBlock->pNodes[nIndex] = p;
// Alles von Index bis Mitte hinter Index kopieren
if ( nIndex != nMiddle )
{
memcpy( pNewBlock->pNodes+nIndex+1,
pNodes+nIndex,
(nMiddle-nIndex) * sizeof(PVOID) );
}
pNewBlock->nCount = nMiddle+1;
nCount = nCount - nMiddle; // MSVC warns here if += is used
// Die zweite Haelfte in einen neuen Block kopieren
if ( nSize != nNewSize )
{
void** pNewNodes = new PVOID[nNewSize];
memcpy( pNewNodes, pNodes+nMiddle, nCount*sizeof(PVOID) );
delete[] pNodes;
pNodes = pNewNodes;
nSize = nNewSize;
}
else
memmove( pNodes, pNodes+nMiddle, nCount*sizeof(PVOID) );
}
}
// Neu angelegten Block zurueckgeben, da gegebenfalls die Blockpointer
// im Container angepast werden koennen
return pNewBlock;
}
/*************************************************************************
|*
|* CBlock::Remove()
|*
|* Beschreibung Entfernt einen Pointer
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
void* CBlock::Remove( sal_uInt16 nIndex, sal_uInt16 nReSize )
{
DBG_CHKTHIS( CBlock, DbgCheckCBlock );
// Alten Pointer sichern
void* pOld = pNodes[nIndex];
// 1 Element weniger
nCount--;
// Block verkleinern (wenn Reallokationsgroesse um 4 unterschritten wird)
if ( nCount == (nSize-nReSize-4) )
{
// Neue Daten anlegen
nSize = nSize - nReSize; // MSVC warns here if += is used
void** pNewNodes = new PVOID[nSize];
// Wird letzter Eintrag geloescht
if ( nIndex == nCount )
{
// Daten kopieren
memcpy( pNewNodes, pNodes, nCount*sizeof(PVOID) );
}
else
{
// Daten kopieren
memcpy( pNewNodes, pNodes, nIndex*sizeof(PVOID) );
memcpy( pNewNodes + nIndex, pNodes + nIndex+1,
(nCount-nIndex)*sizeof(PVOID) );
}
// Alte Daten loeschen und neue setzen
delete[] pNodes;
pNodes = pNewNodes;
}
else
{
// Wenn nicht das letzte Element, dann zusammenschieben
if ( nIndex < nCount )
{
memmove( pNodes + nIndex, pNodes + nIndex + 1,
(nCount-nIndex)*sizeof(PVOID) );
}
}
// Alten Pointer zurueckgeben
return pOld;
}
/*************************************************************************
|*
|* CBlock::Replace()
|*
|* Beschreibung Ersetzt einen Pointer
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
inline void* CBlock::Replace( void* p, sal_uInt16 nIndex )
{
DBG_CHKTHIS( CBlock, DbgCheckCBlock );
// Alten Pointer sichern, neuen setzen und alten zurueckgeben
void* pOld = pNodes[nIndex];
pNodes[nIndex] = p;
return pOld;
}
/*************************************************************************
|*
|* CBlock::GetObjectPtr()
|*
|* Beschreibung Gibt einen Pointer auf den Pointer aus dem Block
|* zurueck
|* Ersterstellung TH 26.01.93
|* Letzte Aenderung TH 26.01.93
|*
*************************************************************************/
inline void** CBlock::GetObjectPtr( sal_uInt16 nIndex )
{
DBG_CHKTHIS( CBlock, DbgCheckCBlock );
return &(pNodes[nIndex]);
}
/*************************************************************************
|*
|* CBlock::SetSize()
|*
|* Beschreibung Aendert die Groesse des Blocks
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
void CBlock::SetSize( sal_uInt16 nNewSize )
{
DBG_CHKTHIS( CBlock, DbgCheckCBlock );
DBG_ASSERT( nNewSize, "CBlock::SetSize(): nNewSize == 0" );
// Unterscheidet sich die Groesse
if ( nNewSize != nCount )
{
// Array erweitern
void** pNewNodes = new PVOID[nNewSize];
// Alte Tabelle in die Neue kopieren
if ( nNewSize < nCount )
memcpy( pNewNodes, pNodes, nNewSize*sizeof(PVOID) );
else
{
memcpy( pNewNodes, pNodes, nCount*sizeof(PVOID) );
// Array mit 0 initialisieren
memset( pNewNodes+nCount, 0, (nNewSize-nCount)*sizeof(PVOID) );
}
// Altes Array loeschen und neue Werte setzen
nSize = nNewSize;
nCount = nSize;
delete[] pNodes;
pNodes = pNewNodes;
}
}
//------------------------------------------------------------------------
/*************************************************************************
|*
|* DbgCheckContainer()
|*
|* Beschreibung Pruefung eines Container fuer Debug-Utilities
|* Ersterstellung MI 30.01.92
|* Letzte Aenderung TH 24.01.96
|*
*************************************************************************/
#ifdef DBG_UTIL
const char* Container::DbgCheckContainer( const void* pCont )
{
Container* p = (Container*)pCont;
if ( p->nCount && (!p->pFirstBlock || !p->pLastBlock || !p->pCurBlock) )
return "nCount > 0 but no CBlocks";
return NULL;
}
#endif
/*************************************************************************
|*
|* ImpCopyContainer()
|*
|* Beschreibung Kopiert alle Daten des Containers
|* Ersterstellung TH 24.01.96
|* Letzte Aenderung TH 24.01.96
|*
*************************************************************************/
void Container::ImpCopyContainer( const Container* pCont2 )
{
// Werte vom uebergebenen Container uebernehmen
nCount = pCont2->nCount;
nCurIndex = pCont2->nCurIndex;
nInitSize = pCont2->nInitSize;
nReSize = pCont2->nReSize;
nBlockSize = pCont2->nBlockSize;
// Alle Bloecke kopieren
if ( pCont2->nCount )
{
CBlock* pBlock1;
CBlock* pBlock2;
CBlock* pTempBlock;
// Erstmal ersten Block kopieren
pBlock2 = pCont2->pFirstBlock;
pFirstBlock = new CBlock( *pBlock2, NULL );
// Ist erster Block der Current-Block, dann Current-Block setzen
if ( pBlock2 == pCont2->pCurBlock )
pCurBlock = pFirstBlock;
pBlock1 = pFirstBlock;
pBlock2 = pBlock2->GetNextBlock();
while ( pBlock2 )
{
// Neuen Block anlegen und aus der uebergebenen Liste kopieren
pTempBlock = new CBlock( *pBlock2, pBlock1 );
pBlock1->SetNextBlock( pTempBlock );
pBlock1 = pTempBlock;
// Current-Block beruecksichtigen
if ( pBlock2 == pCont2->pCurBlock )
pCurBlock = pBlock1;
// Auf naechsten Block weitersetzen
pBlock2 = pBlock2->GetNextBlock();
}
// Letzten Block setzen
pLastBlock = pBlock1;
}
else
{
pFirstBlock = NULL;
pLastBlock = NULL;
pCurBlock = NULL;
}
}
/*************************************************************************
|*
|* Container::Container()
|*
|* Beschreibung CONTNR.SDW
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
Container::Container( sal_uInt16 _nBlockSize, sal_uInt16 _nInitSize, sal_uInt16 _nReSize )
{
DBG_CTOR( Container, DbgCheckContainer );
// BlockSize muss mindestens 4 sein und kleiner als 64 KB
if ( _nBlockSize < 4 )
nBlockSize = 4;
else
{
if ( _nBlockSize < CONTAINER_MAXBLOCKSIZE )
nBlockSize = _nBlockSize;
else
nBlockSize = CONTAINER_MAXBLOCKSIZE;
}
// ReSize muss mindestens 2 sein und kleiner als BlockSize
if ( _nReSize >= nBlockSize )
nReSize = nBlockSize;
else
{
if ( _nReSize < 2 )
nReSize = 2;
else
nReSize = _nReSize;
// BlockSize muss ein vielfaches der Resizegroesse sein
if ( nBlockSize % nReSize )
nBlockSize -= nReSize - (nBlockSize % nReSize);
}
// InitSize muss groesser gleich ReSize sein und kleiner als BlockSize
if ( _nInitSize <= nReSize )
nInitSize = nReSize;
else
{
if ( _nInitSize >= nBlockSize )
nInitSize = nBlockSize;
else
{
nInitSize = _nInitSize;
// InitSize muss ein vielfaches der Resizegroesse sein
if ( nInitSize % nReSize )
nInitSize -= nReSize - (nInitSize % nReSize);
}
}
// Werte initialisieren
pFirstBlock = NULL;
pLastBlock = NULL;
pCurBlock = NULL;
nCount = 0;
nCurIndex = 0;
}
/*************************************************************************
|*
|* Container::Container()
|*
|* Beschreibung CONTNR.SDW
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
Container::Container( sal_uIntPtr nSize )
{
DBG_CTOR( Container, DbgCheckContainer );
nCount = nSize;
nCurIndex = 0;
nBlockSize = CONTAINER_MAXBLOCKSIZE;
nInitSize = 1;
nReSize = 1;
if ( !nSize )
{
pFirstBlock = NULL;
pLastBlock = NULL;
pCurBlock = NULL;
}
else
{
// Muss mehr als ein Block angelegt werden
if ( nSize <= nBlockSize )
{
pFirstBlock = new CBlock( (sal_uInt16)nSize, NULL );
pLastBlock = pFirstBlock;
}
else
{
CBlock* pBlock1;
CBlock* pBlock2;
pFirstBlock = new CBlock( nBlockSize, NULL );
pBlock1 = pFirstBlock;
nSize -= nBlockSize;
// Solange die Blockgroesse ueberschritten wird, neue Bloecke anlegen
while ( nSize > nBlockSize )
{
pBlock2 = new CBlock( nBlockSize, pBlock1 );
pBlock1->SetNextBlock( pBlock2 );
pBlock1 = pBlock2;
nSize -= nBlockSize;
}
pLastBlock = new CBlock( (sal_uInt16)nSize, pBlock1 );
pBlock1->SetNextBlock( pLastBlock );
}
pCurBlock = pFirstBlock;
}
}
/*************************************************************************
|*
|* Container::Container()
|*
|* Beschreibung CONTNR.SDW
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
Container::Container( const Container& r )
{
DBG_CTOR( Container, DbgCheckContainer );
// Daten kopieren
ImpCopyContainer( &r );
}
/*************************************************************************
|*
|* Container::~Container()
|*
|* Beschreibung CONTNR.SDW
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
Container::~Container()
{
DBG_DTOR( Container, DbgCheckContainer );
// Alle Bloecke loeschen
CBlock* pBlock = pFirstBlock;
while ( pBlock )
{
CBlock* pTemp = pBlock->GetNextBlock();
delete pBlock;
pBlock = pTemp;
}
}
/*************************************************************************
|*
|* Container::ImpInsert()
|*
|* Beschreibung Interne Methode zum Einfuegen eines Pointers
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung DV 01.07.97
|*
*************************************************************************/
void Container::ImpInsert( void* p, CBlock* pBlock, sal_uInt16 nIndex )
{
DBG_CHKTHIS( Container, DbgCheckContainer );
if ( !nCount )
{
if ( !pBlock )
{
pFirstBlock = new CBlock( nInitSize, NULL, NULL );
pLastBlock = pFirstBlock;
pCurBlock = pFirstBlock;
}
pFirstBlock->Insert( p, nIndex, nReSize );
}
else
{
// Ist im Block die maximale Blockgroesse erreicht,
// dann neuen Block anlegen
if ( pBlock->Count() == nBlockSize )
{
// Block auftrennen
CBlock* pNewBlock = pBlock->Split( p, nIndex, nReSize );
// Wurde Block dahinter angehaegnt
if ( pBlock->pNext == pNewBlock )
{
// Gegebenenfalls LastBlock anpassen
if ( pBlock == pLastBlock )
pLastBlock = pNewBlock;
// Current-Position nachfuehren
if ( pBlock == pCurBlock )
{
if ( pBlock->nCount <= nCurIndex )
{
if ( nIndex <= nCurIndex )
nCurIndex++;
pCurBlock = pNewBlock;
nCurIndex = nCurIndex - pBlock->nCount; // MSVC warns here if += is used
}
}
}
else
{
// Gegebenenfalls FirstBlock anpassen
if ( pBlock == pFirstBlock )
pFirstBlock = pNewBlock;
// Current-Position nachfuehren
if ( pBlock == pCurBlock )
{
if ( nIndex <= nCurIndex )
nCurIndex++;
if ( pNewBlock->nCount <= nCurIndex )
nCurIndex = nCurIndex - pNewBlock->nCount; // MSVC warns here if += is used
else
pCurBlock = pNewBlock;
}
}
}
else
{
// Sonst reicht normales einfuegen in den Block
pBlock->Insert( p, nIndex, nReSize );
// Current-Position nachfuehren
if ( (pBlock == pCurBlock) && (nIndex <= nCurIndex) )
nCurIndex++;
}
}
// Ein neues Item im Container
nCount++;
}
/*************************************************************************
|*
|* Container::Insert()
|*
|* Beschreibung CONTNR.SDW
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
void Container::Insert( void* p )
{
ImpInsert( p, pCurBlock, nCurIndex );
}
/*************************************************************************
|*
|* Container::Insert()
|*
|* Beschreibung CONTNR.SDW
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
void Container::Insert( void* p, sal_uIntPtr nIndex )
{
if ( nCount <= nIndex )
{
if ( pLastBlock )
ImpInsert( p, pLastBlock, pLastBlock->Count() );
else
ImpInsert( p, NULL, 0 );
}
else
{
// Block suchen
CBlock* pTemp = pFirstBlock;
while ( pTemp->Count() < nIndex )
{
nIndex -= pTemp->Count();
pTemp = pTemp->GetNextBlock();
}
ImpInsert( p, pTemp, (sal_uInt16)nIndex );
}
}
/*************************************************************************
|*
|* Container::Insert()
|*
|* Beschreibung CONTNR.SDW
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
void Container::Insert( void* pNew, void* pOld )
{
sal_uIntPtr nIndex = GetPos( pOld );
if ( nIndex != CONTAINER_ENTRY_NOTFOUND )
Insert( pNew, nIndex );
}
/*************************************************************************
|*
|* Container::ImpRemove()
|*
|* Beschreibung Interne Methode zum Entfernen eines Pointers
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
void* Container::ImpRemove( CBlock* pBlock, sal_uInt16 nIndex )
{
DBG_CHKTHIS( Container, DbgCheckContainer );
void* pOld;
// Ist Liste danach leer
if ( nCount == 1 )
{
// Block und CurIndex zuruecksetzen
pOld = pBlock->GetObject( nIndex );
pBlock->Reset();
nCurIndex = 0;
}
else
{
// Ist Block nach Remove leer
if ( pBlock->Count() == 1 )
{
// dann Block entfernen und Block-Pointer umsetzen
if ( pBlock->GetPrevBlock() )
(pBlock->GetPrevBlock())->SetNextBlock( pBlock->GetNextBlock() );
else
pFirstBlock = pBlock->GetNextBlock();
if ( pBlock->GetNextBlock() )
(pBlock->GetNextBlock())->SetPrevBlock( pBlock->GetPrevBlock() );
else
pLastBlock = pBlock->GetPrevBlock();
// Current-Position nachfuehren
if ( pBlock == pCurBlock )
{
if ( pBlock->GetNextBlock() )
{
pCurBlock = pBlock->GetNextBlock();
nCurIndex = 0;
}
else
{
pCurBlock = pBlock->GetPrevBlock();
nCurIndex = pCurBlock->Count()-1;
}
}
pOld = pBlock->GetObject( nIndex );
delete pBlock;
}
else
{
// Sonst Item aus dem Block entfernen
pOld = pBlock->Remove( nIndex, nReSize );
// Current-Position nachfuehren
if ( (pBlock == pCurBlock) &&
((nIndex < nCurIndex) || ((nCurIndex == pBlock->Count()) && nCurIndex)) )
nCurIndex--;
}
}
// Jetzt gibt es ein Item weniger
nCount--;
// Und den Pointer zurueckgeben, der entfernt wurde
return pOld;
}
/*************************************************************************
|*
|* Container::Remove()
|*
|* Beschreibung CONTNR.SDW
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
void* Container::Remove()
{
// Wenn kein Item vorhanden ist, NULL zurueckgeben
if ( !nCount )
return NULL;
else
return ImpRemove( pCurBlock, nCurIndex );
}
/*************************************************************************
|*
|* Container::Remove()
|*
|* Beschreibung CONTNR.SDW
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
void* Container::Remove( sal_uIntPtr nIndex )
{
// Ist Index nicht innerhalb des Containers, dann NULL zurueckgeben
if ( nCount <= nIndex )
return NULL;
else
{
// Block suchen
CBlock* pTemp = pFirstBlock;
while ( pTemp->Count() <= nIndex )
{
nIndex -= pTemp->Count();
pTemp = pTemp->GetNextBlock();
}
return ImpRemove( pTemp, (sal_uInt16)nIndex );
}
}
/*************************************************************************
|*
|* Container::Replace()
|*
|* Beschreibung CONTNR.SDW
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
void* Container::Replace( void* p )
{
DBG_CHKTHIS( Container, DbgCheckContainer );
if ( !nCount )
return NULL;
else
return pCurBlock->Replace( p, nCurIndex );
}
/*************************************************************************
|*
|* Container::Replace()
|*
|* Beschreibung CONTNR.SDW
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
void* Container::Replace( void* p, sal_uIntPtr nIndex )
{
DBG_CHKTHIS( Container, DbgCheckContainer );
// Ist Index nicht innerhalb des Containers, dann NULL zurueckgeben
if ( nCount <= nIndex )
return NULL;
else
{
// Block suchen
CBlock* pTemp = pFirstBlock;
while ( pTemp->Count() <= nIndex )
{
nIndex -= pTemp->Count();
pTemp = pTemp->GetNextBlock();
}
return pTemp->Replace( p, (sal_uInt16)nIndex );
}
}
/*************************************************************************
|*
|* Container::SetSize()
|*
|* Beschreibung CONTNR.SDW
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
void Container::SetSize( sal_uIntPtr nNewSize )
{
DBG_CHKTHIS( Container, DbgCheckContainer );
if ( nNewSize )
{
// Unterscheiden sich die Groessen
if ( nNewSize != nCount )
{
CBlock* pTemp;
sal_uIntPtr nTemp;
// Wird verkleinert
if ( nNewSize < nCount )
{
pTemp = pFirstBlock;
nTemp = 0;
while ( (nTemp+pTemp->Count()) < nNewSize )
{
nTemp += pTemp->Count();
pTemp = pTemp->GetNextBlock();
}
// Alle folgenden Bloecke loeschen
sal_Bool bLast = sal_False;
CBlock* pDelNext;
CBlock* pDelBlock = pTemp->GetNextBlock();
while ( pDelBlock )
{
// Muss CurrentBlock umgesetzt werden
if ( pDelBlock == pCurBlock )
bLast = sal_True;
pDelNext = pDelBlock->GetNextBlock();
delete pDelBlock;
pDelBlock = pDelNext;
}
// Block in der Groesse anpassen, oder bei Groesse 0 loeschen
if ( nNewSize > nTemp )
{
pLastBlock = pTemp;
pTemp->SetNextBlock( NULL );
pTemp->SetSize( (sal_uInt16)(nNewSize-nTemp) );
}
else
{
pLastBlock = pTemp->GetPrevBlock();
pLastBlock->SetNextBlock( NULL );
delete pTemp;
}
nCount = nNewSize;
if ( bLast )
{
pCurBlock = pLastBlock;
nCurIndex = pCurBlock->Count()-1;
}
}
else
{
// Auf den letzen Puffer setzen
pTemp = pLastBlock;
nTemp = nNewSize - nCount;
if ( !pTemp )
{
// Muss mehr als ein Block angelegt werden
if ( nNewSize <= nBlockSize )
{
pFirstBlock = new CBlock( (sal_uInt16)nNewSize, NULL );
pLastBlock = pFirstBlock;
}
else
{
CBlock* pBlock1;
CBlock* pBlock2;
pFirstBlock = new CBlock( nBlockSize, NULL );
pBlock1 = pFirstBlock;
nNewSize -= nBlockSize;
// Solange die Blockgroesse ueberschritten wird, neue Bloecke anlegen
while ( nNewSize > nBlockSize )
{
pBlock2 = new CBlock( nBlockSize, pBlock1 );
pBlock1->SetNextBlock( pBlock2 );
pBlock1 = pBlock2;
nNewSize -= nBlockSize;
}
pLastBlock = new CBlock( (sal_uInt16)nNewSize, pBlock1 );
pBlock1->SetNextBlock( pLastBlock );
}
pCurBlock = pFirstBlock;
}
// Reicht es, den letzen Puffer in der Groesse anzupassen
else if ( (nTemp+pTemp->Count()) <= nBlockSize )
pTemp->SetSize( (sal_uInt16)(nTemp+pTemp->Count()) );
else
{
// Puffer auf max. Blockgroesse setzen
nTemp -= nBlockSize - pTemp->GetSize();
pTemp->SetSize( nBlockSize );
CBlock* pTemp2;
// Solange die Blockgroesse ueberschritten wird,
// neue Bloecke anlegen
while ( nTemp > nBlockSize )
{
pTemp2 = new CBlock( nBlockSize, pTemp );
pTemp->SetNextBlock( pTemp2 );
pTemp = pTemp2;
nTemp -= nBlockSize;
}
// Den letzten Block anlegen
if ( nTemp )
{
pLastBlock = new CBlock( (sal_uInt16)nTemp, pTemp );
pTemp->SetNextBlock( pLastBlock );
}
else
pLastBlock = pTemp;
}
nCount = nNewSize;
}
}
}
else
Clear();
}
/*************************************************************************
|*
|* Container::Clear()
|*
|* Beschreibung CONTNR.SDW
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
void Container::Clear()
{
DBG_CHKTHIS( Container, DbgCheckContainer );
// Erst alle Bloecke loeschen
CBlock* pBlock = pFirstBlock;
while ( pBlock )
{
CBlock* pTemp = pBlock->GetNextBlock();
delete pBlock;
pBlock = pTemp;
}
// Werte zuruecksetzen
pFirstBlock = NULL;
pLastBlock = NULL;
pCurBlock = NULL;
nCount = 0;
nCurIndex = 0;
}
/*************************************************************************
|*
|* Container::GetCurObject()
|*
|* Beschreibung CONTNR.SDW
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
void* Container::GetCurObject() const
{
DBG_CHKTHIS( Container, DbgCheckContainer );
// NULL, wenn Container leer
if ( !nCount )
return NULL;
else
return pCurBlock->GetObject( nCurIndex );
}
/*************************************************************************
|*
|* Container::GetCurPos()
|*
|* Beschreibung CONTNR.SDW
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
sal_uIntPtr Container::GetCurPos() const
{
DBG_CHKTHIS( Container, DbgCheckContainer );
// CONTAINER_ENTRY_NOTFOUND, wenn Container leer
if ( !nCount )
return CONTAINER_ENTRY_NOTFOUND;
else
{
// Block suchen
CBlock* pTemp = pFirstBlock;
sal_uIntPtr nTemp = 0;
while ( pTemp != pCurBlock )
{
nTemp += pTemp->Count();
pTemp = pTemp->GetNextBlock();
}
return nTemp+nCurIndex;
}
}
/*************************************************************************
|*
|* Container::GetObjectPtr()
|*
|* Beschreibung Interne Methode fuer Referenz-Container
|* Ersterstellung TH 26.01.93
|* Letzte Aenderung TH 26.01.93
|*
*************************************************************************/
void** Container::GetObjectPtr( sal_uIntPtr nIndex )
{
DBG_CHKTHIS( Container, DbgCheckContainer );
// Ist Index nicht innerhalb des Containers, dann NULL zurueckgeben
if ( nCount <= nIndex )
return NULL;
else
{
// Block suchen
CBlock* pTemp = pFirstBlock;
while ( pTemp->Count() <= nIndex )
{
nIndex -= pTemp->Count();
pTemp = pTemp->GetNextBlock();
}
// Item innerhalb des gefundenen Blocks zurueckgeben
return pTemp->GetObjectPtr( (sal_uInt16)nIndex );
}
}
/*************************************************************************
|*
|* Container::GetObject()
|*
|* Beschreibung CONTNR.SDW
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
void* Container::GetObject( sal_uIntPtr nIndex ) const
{
DBG_CHKTHIS( Container, DbgCheckContainer );
// Ist Index nicht innerhalb des Containers, dann NULL zurueckgeben
if ( nCount <= nIndex )
return NULL;
else
{
// Block suchen
CBlock* pTemp = pFirstBlock;
while ( pTemp->Count() <= nIndex )
{
nIndex -= pTemp->Count();
pTemp = pTemp->GetNextBlock();
}
// Item innerhalb des gefundenen Blocks zurueckgeben
return pTemp->GetObject( (sal_uInt16)nIndex );
}
}
/*************************************************************************
|*
|* Container::GetPos()
|*
|* Beschreibung CONTNR.SDW
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
sal_uIntPtr Container::GetPos( const void* p ) const
{
DBG_CHKTHIS( Container, DbgCheckContainer );
void** pNodes;
CBlock* pTemp;
sal_uIntPtr nTemp;
sal_uInt16 nBlockCount;
sal_uInt16 i;
// Block suchen
pTemp = pFirstBlock;
nTemp = 0;
while ( pTemp )
{
pNodes = pTemp->GetNodes();
i = 0;
nBlockCount = pTemp->Count();
while ( i < nBlockCount )
{
if ( p == *pNodes )
return nTemp+i;
pNodes++;
i++;
}
nTemp += nBlockCount;
pTemp = pTemp->GetNextBlock();
}
return CONTAINER_ENTRY_NOTFOUND;
}
/*************************************************************************
|*
|* Container::GetPos()
|*
|* Beschreibung CONTNR.SDW
|* Ersterstellung TH 14.09.94
|* Letzte Aenderung TH 14.09.94
|*
*************************************************************************/
sal_uIntPtr Container::GetPos( const void* p, sal_uIntPtr nStartIndex,
sal_Bool bForward ) const
{
DBG_CHKTHIS( Container, DbgCheckContainer );
// Ist Index nicht innerhalb des Containers, dann NOTFOUND zurueckgeben
if ( nCount <= nStartIndex )
return CONTAINER_ENTRY_NOTFOUND;
else
{
void** pNodes;
sal_uInt16 nBlockCount;
sal_uInt16 i;
// Block suchen
CBlock* pTemp = pFirstBlock;
sal_uIntPtr nTemp = 0;
while ( nTemp+pTemp->Count() <= nStartIndex )
{
nTemp += pTemp->Count();
pTemp = pTemp->GetNextBlock();
}
// Jetzt den Pointer suchen
if ( bForward )
{
// Alle Bloecke durchrsuchen
i = (sal_uInt16)(nStartIndex - nTemp);
pNodes = pTemp->GetObjectPtr( i );
do
{
nBlockCount = pTemp->Count();
while ( i < nBlockCount )
{
if ( p == *pNodes )
return nTemp+i;
pNodes++;
i++;
}
nTemp += nBlockCount;
pTemp = pTemp->GetNextBlock();
if ( pTemp )
{
i = 0;
pNodes = pTemp->GetNodes();
}
else
break;
}
while ( sal_True );
}
else
{
// Alle Bloecke durchrsuchen
i = (sal_uInt16)(nStartIndex-nTemp)+1;
pNodes = pTemp->GetObjectPtr( i-1 );
do
{
do
{
if ( p == *pNodes )
return nTemp+i-1;
pNodes--;
i--;
}
while ( i );
nTemp -= pTemp->Count();
pTemp = pTemp->GetPrevBlock();
if ( pTemp )
{
i = pTemp->Count();
// Leere Bloecke in der Kette darf es nicht geben. Nur
// wenn ein Block existiert, darf dieser leer sein
pNodes = pTemp->GetObjectPtr( i-1 );
}
else
break;
}
while ( sal_True );
}
}
return CONTAINER_ENTRY_NOTFOUND;
}
/*************************************************************************
|*
|* Container::Seek()
|*
|* Beschreibung CONTNR.SDW
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
void* Container::Seek( sal_uIntPtr nIndex )
{
DBG_CHKTHIS( Container, DbgCheckContainer );
// Ist der Container leer, dann NULL zurueckgeben
if ( nCount <= nIndex )
return NULL;
else
{
// Block suchen
CBlock* pTemp = pFirstBlock;
while ( pTemp->Count() <= nIndex )
{
nIndex -= pTemp->Count();
pTemp = pTemp->GetNextBlock();
}
// Item innerhalb des gefundenen Blocks zurueckgeben
pCurBlock = pTemp;
nCurIndex = (sal_uInt16)nIndex;
return pCurBlock->GetObject( nCurIndex );
}
}
/*************************************************************************
|*
|* Container::First()
|*
|* Beschreibung CONTNR.SDW
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
void* Container::First()
{
DBG_CHKTHIS( Container, DbgCheckContainer );
// Ist Container leer, dann NULL zurueckgeben
if ( !nCount )
return NULL;
else
{
// Block und Index setzen und ersten Pointer zurueckgeben
pCurBlock = pFirstBlock;
nCurIndex = 0;
return pCurBlock->GetObject( nCurIndex );
}
}
/*************************************************************************
|*
|* Container::Last()
|*
|* Beschreibung CONTNR.SDW
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
void* Container::Last()
{
DBG_CHKTHIS( Container, DbgCheckContainer );
// Ist Container leer, dann NULL zurueckgeben
if ( !nCount )
return NULL;
else
{
// Block und Index setzen und ersten Pointer zurueckgeben
pCurBlock = pLastBlock;
nCurIndex = pCurBlock->Count()-1;
return pCurBlock->GetObject( nCurIndex );
}
}
/*************************************************************************
|*
|* Container::Next()
|*
|* Beschreibung CONTNR.SDW
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
void* Container::Next()
{
DBG_CHKTHIS( Container, DbgCheckContainer );
// Ist Container leer, dann NULL zurueckgeben, ansonsten preufen ob
// naechste Position noch im aktuellen Block ist. Falls nicht, dann
// einen Block weiterschalten (geht ohne Gefahr, da leere Bloecke
// nicht vorkommen duerfen, es sein denn, es ist der einzige).
if ( !nCount )
return NULL;
else if ( (nCurIndex+1) < pCurBlock->Count() )
return pCurBlock->GetObject( ++nCurIndex );
else if ( pCurBlock->GetNextBlock() )
{
pCurBlock = pCurBlock->GetNextBlock();
nCurIndex = 0;
return pCurBlock->GetObject( nCurIndex );
}
else
return NULL;
}
/*************************************************************************
|*
|* Container::Prev()
|*
|* Beschreibung CONTNR.SDW
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
void* Container::Prev()
{
DBG_CHKTHIS( Container, DbgCheckContainer );
// Ist Container leer, dann NULL zurueckgeben, ansonsten preufen ob
// vorherige Position noch im aktuellen Block ist. Falls nicht, dann
// einen Block zurueckschalten (geht ohne Gefahr, da leere Bloecke
// nicht vorkommen duerfen, es sein denn, es ist der einzige).
if ( !nCount )
return NULL;
else if ( nCurIndex )
return pCurBlock->GetObject( --nCurIndex );
else if ( pCurBlock->GetPrevBlock() )
{
pCurBlock = pCurBlock->GetPrevBlock();
nCurIndex = pCurBlock->Count() - 1;
return pCurBlock->GetObject( nCurIndex );
}
else
return NULL;
}
/*************************************************************************
|*
|* Container::operator =()
|*
|* Beschreibung CONTNR.SDW
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
Container& Container::operator =( const Container& r )
{
DBG_CHKTHIS( Container, DbgCheckContainer );
// Erst alle Bloecke loeschen
CBlock* pBlock = pFirstBlock;
while ( pBlock )
{
CBlock* pTemp = pBlock->GetNextBlock();
delete pBlock;
pBlock = pTemp;
}
// Daten kopieren
ImpCopyContainer( &r );
return *this;
}
/*************************************************************************
|*
|* Container::operator ==()
|*
|* Beschreibung CONTNR.SDW
|* Ersterstellung TH 17.09.91
|* Letzte Aenderung TH 17.09.91
|*
*************************************************************************/
sal_Bool Container::operator ==( const Container& r ) const
{
DBG_CHKTHIS( Container, DbgCheckContainer );
if ( nCount != r.nCount )
return sal_False;
sal_uIntPtr i = 0;
while ( i < nCount )
{
if ( GetObject( i ) != r.GetObject( i ) )
return sal_False;
i++;
}
return sal_True;
}