summaryrefslogtreecommitdiff
path: root/binfilter/bf_sw/source/core/bastyp/sw_bparr.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'binfilter/bf_sw/source/core/bastyp/sw_bparr.cxx')
-rw-r--r--binfilter/bf_sw/source/core/bastyp/sw_bparr.cxx586
1 files changed, 586 insertions, 0 deletions
diff --git a/binfilter/bf_sw/source/core/bastyp/sw_bparr.cxx b/binfilter/bf_sw/source/core/bastyp/sw_bparr.cxx
new file mode 100644
index 000000000000..ee680a7532c6
--- /dev/null
+++ b/binfilter/bf_sw/source/core/bastyp/sw_bparr.cxx
@@ -0,0 +1,586 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+
+#include <string.h>
+#include <limits.h>
+#include "bparr.hxx"
+namespace binfilter {
+
+// die Blockverwaltung waechst/schrumpft immer um 20 Bloecke, das sind dann
+// immer ~ 20 * MAXENTRY == 20000 Eintraege
+const USHORT nBlockGrowSize = 20;
+
+#ifndef DBG_UTIL
+
+#define CHECKIDX( p, n, i, c )
+
+#else
+
+#define CHECKIDX( p, n, i, c ) CheckIdx( p, n, i, c );
+
+/*N*/ void CheckIdx( BlockInfo** ppInf, USHORT nBlock, ULONG nSize, USHORT nCur )
+/*N*/ {
+/*N*/ DBG_ASSERT( !nSize || nCur < nBlock, "BigPtrArray: CurIndex steht falsch" );
+/*N*/
+/*N*/ ULONG nIdx = 0;
+/*N*/ for( USHORT nCnt = 0; nCnt < nBlock; ++nCnt, ++ppInf )
+/*N*/ {
+/*N*/ nIdx += (*ppInf)->nElem;
+/*N*/ // Array mit Luecken darf es nicht geben
+/*N*/ DBG_ASSERT( !nCnt || (*(ppInf-1))->nEnd + 1 == (*ppInf)->nStart,
+/*N*/ "BigPtrArray: Luecke in der Verwaltung!" );
+/*N*/ }
+/*N*/
+/*N*/ DBG_ASSERT( nIdx == nSize, "BigPtrArray: Anzahl ungueltig" );
+/*N*/ }
+
+#endif
+
+
+/*N*/ BigPtrArray::BigPtrArray()
+/*N*/ {
+/*N*/ nBlock = nCur = 0;
+/*N*/ nSize = 0;
+/*N*/ nMaxBlock = nBlockGrowSize; // == 20 * 1000 Eintraege
+/*N*/ ppInf = new BlockInfo* [ nMaxBlock ];
+/*N*/ }
+
+
+
+/*N*/ BigPtrArray::~BigPtrArray()
+/*N*/ {
+/*N*/ if( nBlock )
+/*N*/ {
+/*N*/ BlockInfo** pp = ppInf;
+/*N*/ for( USHORT n = 0; n < nBlock; ++n, ++pp )
+/*N*/ {
+/*N*/ delete[] (*pp)->pData;
+/*N*/ delete *pp;
+/*N*/ }
+/*N*/ }
+/*N*/ delete[] ppInf;
+/*N*/ }
+
+// Einfachst-Implementation, evtl. spaeter mal komplexer
+#if 0
+#endif
+
+// Auch der Move ist schlicht. Optimieren ist hier wg. der
+// Stueckelung des Feldes zwecklos!
+
+
+// das Ende ist EXCLUSIV
+
+
+/*N*/ void BigPtrArray::ForEach( ULONG nStart, ULONG nEnd,
+/*N*/ FnForEach fn, void* pArgs )
+/*N*/ {
+/*N*/ if( nEnd > nSize )
+/*N*/ nEnd = nSize;
+/*N*/
+/*N*/ if( nStart < nEnd )
+/*N*/ {
+/*N*/ USHORT cur = Index2Block( nStart );
+/*N*/ BlockInfo** pp = ppInf + cur;
+/*N*/ BlockInfo* p = *pp;
+/*N*/ USHORT nElem = USHORT( nStart - p->nStart );
+/*N*/ ElementPtr* pElem = p->pData + nElem;
+/*N*/ nElem = p->nElem - nElem;
+/*N*/ for(;;)
+/*N*/ {
+/*N*/ if( !(*fn)( *pElem++, pArgs ) || ++nStart >= nEnd )
+/*N*/ break;
+/*N*/
+/*N*/ // naechstes Element
+/*N*/ if( !--nElem )
+/*N*/ {
+/*N*/ // neuer Block
+/*N*/ p = *++pp;
+/*N*/ pElem = p->pData;
+/*N*/ nElem = p->nElem;
+/*N*/ }
+/*N*/ }
+/*N*/ }
+/*N*/ }
+
+
+/*N*/ ElementPtr BigPtrArray::operator[]( ULONG idx ) const
+/*N*/ {
+/*N*/ // weil die Funktion eben doch nicht const ist:
+/*N*/ DBG_ASSERT( idx < nSize, "operator[]: Index aussserhalb" );
+/*N*/ BigPtrArray* pThis = (BigPtrArray*) this;
+/*N*/ USHORT cur = Index2Block( idx );
+/*N*/ BlockInfo* p = ppInf[ cur ];
+/*N*/ pThis->nCur = cur;
+/*N*/ return p->pData[ idx - p->nStart ];
+/*N*/ }
+
+///////////////////////////////////////////////////////////////////////////
+
+// private Methoden
+
+// Suchen des Blocks einer bestimmten Position
+// Algorithmus:
+// 1. Test, ob der letzte Block der gesuchte Block ist
+// 2. Sonderfall: Index = 0?
+// 3. Test der Nachbarbloecke
+
+// 4. Binaere Suche
+
+
+
+/*N*/ USHORT BigPtrArray::Index2Block( ULONG pos ) const
+/*N*/ {
+/*N*/ // zuletzt verwendeter Block?
+/*N*/ BlockInfo* p = ppInf[ nCur ];
+/*N*/ if( p->nStart <= pos && p->nEnd >= pos )
+/*N*/ return nCur;
+/*N*/ // Index = 0?
+/*N*/ if( !pos )
+/*N*/ return 0;
+/*N*/ // Folgeblock?
+/*N*/ if( nCur < ( nBlock - 1 ) )
+/*N*/ {
+/*N*/ p = ppInf[ nCur+1 ];
+/*N*/ if( p->nStart <= pos && p->nEnd >= pos )
+/*N*/ return nCur+1;
+/*N*/ }
+/*N*/ // vorangehender Block?
+/*N*/ else if( pos < p->nStart && nCur > 0 )
+/*N*/ {
+/*N*/ p = ppInf[ nCur-1 ];
+/*N*/ if( p->nStart <= pos && p->nEnd >= pos )
+/*N*/ return nCur-1;
+/*N*/ }
+/*N*/ // Binaere Suche:
+/*N*/ // Diese fuehrt immer zum Erfolg
+/*N*/ USHORT lower = 0, upper = nBlock - 1;
+/*N*/ USHORT cur = 0;
+/*N*/ for(;;)
+/*N*/ {
+/*N*/ USHORT n = lower + ( upper - lower ) / 2;
+/*N*/ cur = ( n == cur ) ? n+1 : n;
+/*N*/ p = ppInf[ cur ];
+/*N*/ if( p->nStart <= pos && p->nEnd >= pos )
+/*N*/ return cur;
+/*N*/ if( p->nStart > pos )
+/*N*/ upper = cur;
+/*N*/ else
+/*N*/ lower = cur;
+/*N*/ }
+/*N*/ }
+
+
+// Update aller Indexbereiche ab einer bestimmten Position
+
+// pos bezeichnet den letzten korrekten Block
+
+/*N*/ void BigPtrArray::UpdIndex( USHORT pos )
+/*N*/ {
+/*N*/ BlockInfo** pp = ppInf + pos;
+/*N*/ ULONG idx = (*pp)->nEnd + 1;
+/*N*/ BlockInfo* p;
+/*N*/ while( ++pos < nBlock )
+/*N*/ {
+/*N*/ p = *++pp;
+/*N*/ p->nStart = idx;
+/*N*/ idx += p->nElem;
+/*N*/ p->nEnd = idx - 1;
+/*N*/ }
+/*N*/ }
+
+// Einrichten eines neuen Blocks an einer bestimmten Position
+
+// Vorhandene Blocks werden nach hinten verschoben
+
+
+
+/*N*/ BlockInfo* BigPtrArray::InsBlock( USHORT pos )
+/*N*/ {
+/*N*/ if( nBlock == nMaxBlock )
+/*N*/ {
+/*N*/ // dann sollte wir mal das Array erweitern
+/*N*/ BlockInfo** ppNew = new BlockInfo* [ nMaxBlock + nBlockGrowSize ];
+/*N*/ memcpy( ppNew, ppInf, nMaxBlock * sizeof( BlockInfo* ));
+/*N*/ delete[] ppInf;
+/*N*/ nMaxBlock += nBlockGrowSize;
+/*N*/ ppInf = ppNew;
+/*N*/ }
+/*N*/ if( pos != nBlock )
+/*N*/ memmove( ppInf + pos+1, ppInf + pos ,
+/*N*/ ( nBlock - pos ) * sizeof (BlockInfo*) );
+/*N*/ ++nBlock;
+/*N*/ BlockInfo* p = new BlockInfo;
+/*N*/ ppInf[ pos ] = p;
+/*N*/
+/*N*/ if( pos )
+/*N*/ p->nStart = p->nEnd = ppInf[ pos-1 ]->nEnd + 1;
+/*N*/ else
+/*N*/ p->nStart = p->nEnd = 0;
+/*N*/ p->nEnd--; // keine Elemente
+/*N*/ p->nElem = 0;
+/*N*/ p->pData = new ElementPtr [ MAXENTRY ];
+/*N*/ p->pBigArr = this;
+/*N*/ return p;
+/*N*/ }
+
+/*N*/ void BigPtrArray::BlockDel( USHORT nDel )
+/*N*/ {
+/*N*/ nBlock -= nDel;
+/*N*/ if( nMaxBlock - nBlock > nBlockGrowSize )
+/*N*/ {
+/*N*/ // dann koennen wir wieder schrumpfen
+/*N*/ nDel = (( nBlock / nBlockGrowSize ) + 1 ) * nBlockGrowSize;
+/*N*/ BlockInfo** ppNew = new BlockInfo* [ nDel ];
+/*N*/ memcpy( ppNew, ppInf, nBlock * sizeof( BlockInfo* ));
+/*N*/ delete[] ppInf;
+/*N*/ ppInf = ppNew;
+/*N*/ nMaxBlock = nDel;
+/*N*/ }
+/*N*/ }
+
+
+/*N*/ void BigPtrArray::Insert( const ElementPtr& rElem, ULONG pos )
+/*N*/ {
+/*N*/ CHECKIDX( ppInf, nBlock, nSize, nCur );
+/*N*/
+/*N*/ BlockInfo* p;
+/*N*/ USHORT cur;
+/*N*/ if( !nSize )
+/*N*/ // Sonderfall: erstes Element einfuegen
+/*N*/ p = InsBlock( cur = 0 );
+/*N*/ else if( pos == nSize )
+/*N*/ {
+/*N*/ // Sonderfall: Einfuegen am Ende
+/*N*/ cur = nBlock - 1;
+/*N*/ p = ppInf[ cur ];
+/*N*/ if( p->nElem == MAXENTRY )
+/*N*/ // Der letzte Block ist voll, neuen anlegen
+/*?*/ p = InsBlock( ++cur );
+/*N*/ }
+/*N*/ else
+/*N*/ {
+/*N*/ // Standardfall:
+/*N*/ cur = Index2Block( pos );
+/*N*/ p = ppInf[ cur ];
+/*N*/ }
+/*N*/ if( p->nElem == MAXENTRY )
+/*N*/ {
+/*N*/ // passt der letzte Eintrag in den naechsten Block?
+/*N*/ BlockInfo* q;
+/*N*/ if( cur < ( nBlock - 1 ) && ppInf[ cur+1 ]->nElem < MAXENTRY )
+/*N*/ {
+/*N*/ q = ppInf[ cur+1 ];
+/*N*/ if( q->nElem )
+/*N*/ {
+/*N*/ register int nCount = q->nElem;
+/*N*/ register ElementPtr *pFrom = q->pData + nCount,
+/*N*/ *pTo = pFrom+1;
+/*N*/ while( nCount-- )
+/*N*/ ++( *--pTo = *--pFrom )->nOffset;
+/*N*/ }
+/*N*/ q->nStart--;
+/*N*/ q->nEnd--;
+/*N*/ }
+/*N*/ else
+/*N*/ {
+/*N*/ // Wenn er auch nicht in den Folgeblock passt, muss ein
+/*N*/ // neuer Block eingefuegt werden
+/*N*/ // erst mal bei Bedarf komprimieren
+/*N*/
+/*N*/ // wenn mehr als 50% "Luft" im Array ist, dann sollte man mal das
+/*N*/ // Compress aufrufen
+/*N*/ if( /*nBlock == nMaxBlock &&*/
+/*N*/ nBlock > ( nSize / ( MAXENTRY / 2 ) ) &&
+/*N*/ cur >= Compress() )
+/*N*/ {
+/*N*/ // es wurde vor der akt. Pos etwas verschoben und alle
+/*N*/ // Pointer koennen ungueltig sein. Also das Insert
+/*N*/ // nochmals aufsetzen
+/*?*/ Insert( rElem, pos );
+/*N*/ return ;
+/*N*/ }
+/*N*/
+/*N*/ q = InsBlock( cur+1 );
+/*N*/ }
+/*N*/
+/*N*/ // Eintrag passt nicht mehr. Dann muss Platz gemacht werden
+/*N*/ ElementPtr pLast = p->pData[ MAXENTRY-1 ];
+/*N*/ pLast->nOffset = 0;
+/*N*/ pLast->pBlock = q;
+/*N*/
+/*N*/ q->pData[ 0 ] = pLast;
+/*N*/ q->nElem++;
+/*N*/ q->nEnd++;
+/*N*/
+/*N*/ p->nEnd--;
+/*N*/ p->nElem--;
+/*N*/ }
+/*N*/ // Nun haben wir einen freien Block am Wickel: eintragen
+/*N*/ pos -= p->nStart;
+/*N*/ DBG_ASSERT( pos < MAXENTRY, "falsche Pos" );
+/*N*/ if( pos != p->nElem )
+/*N*/ {
+/*N*/ register int nCount = p->nElem - USHORT(pos);
+/*N*/ register ElementPtr *pFrom = p->pData + p->nElem,
+/*N*/ *pTo = pFrom + 1;
+/*N*/ while( nCount-- )
+/*N*/ ++( *--pTo = *--pFrom )->nOffset;
+/*N*/ }
+/*N*/ // Element eintragen und Indexe updaten
+/*N*/ ((ElementPtr&)rElem)->nOffset = USHORT(pos);
+/*N*/ ((ElementPtr&)rElem)->pBlock = p;
+/*N*/ p->pData[ pos ] = rElem;
+/*N*/ p->nEnd++;
+/*N*/ p->nElem++;
+/*N*/ nSize++;
+/*N*/ if( cur != ( nBlock - 1 ) ) UpdIndex( cur );
+/*N*/ nCur = cur;
+/*N*/
+/*N*/ CHECKIDX( ppInf, nBlock, nSize, nCur );
+/*N*/ }
+
+/*N*/ void BigPtrArray::Remove( ULONG pos, ULONG n )
+/*N*/ {
+/*N*/ CHECKIDX( ppInf, nBlock, nSize, nCur );
+/*N*/
+/*N*/ USHORT nBlkdel = 0; // entfernte Bloecke
+/*N*/ USHORT cur = Index2Block( pos ); // aktuelle Blocknr
+/*N*/ USHORT nBlk1 = cur; // 1. behandelter Block
+/*N*/ USHORT nBlk1del = USHRT_MAX; // 1. entfernter Block
+/*N*/ BlockInfo* p = ppInf[ cur ];
+/*N*/ pos -= p->nStart;
+/*N*/ ULONG nElem = n;
+/*N*/ while( nElem )
+/*N*/ {
+/*N*/ USHORT nel = p->nElem - USHORT(pos);
+/*N*/ if( ULONG(nel) > nElem )
+/*N*/ nel = USHORT(nElem);
+/*N*/ // Eventuell Elemente verschieben
+/*N*/ if( ( pos + nel ) < ULONG(p->nElem) )
+/*N*/ {
+/*N*/ register ElementPtr *pTo = p->pData + pos,
+/*N*/ *pFrom = pTo + nel;
+/*N*/ register int nCount = p->nElem - nel - USHORT(pos);
+/*N*/ while( nCount-- )
+/*N*/ {
+/*N*/ (*pTo++ = *pFrom++)->nOffset -= nel;
+/*N*/ // (*pTo++)->nOffset -= nel;
+/*N*/ }
+/*N*/ }
+/*N*/ p->nEnd -= nel;
+/*N*/ p->nElem -= nel;
+/*N*/ if( !p->nElem )
+/*N*/ {
+/*N*/ // eventuell Block ganz entfernen
+/*N*/ delete[] p->pData;
+/*N*/ nBlkdel++;
+/*N*/ if( USHRT_MAX == nBlk1del )
+/*N*/ nBlk1del = cur;
+/*N*/ }
+/*N*/ nElem -= nel;
+/*N*/ if( !nElem )
+/*N*/ break;
+/*N*/ p = ppInf[ ++cur ];
+/*N*/ pos = 0;
+/*N*/ }
+/*N*/ // Am Ende die Tabelle updaten, falls Bloecke geloescht waren
+/*N*/ if( nBlkdel )
+/*N*/ {
+/*N*/ // loeschen sollte man immer !!
+/*N*/ for( USHORT i = nBlk1del; i < ( nBlk1del + nBlkdel ); i++ )
+/*N*/ delete ppInf[ i ];
+/*N*/
+/*N*/ if( ( nBlk1del + nBlkdel ) < nBlock )
+/*N*/ {
+/*N*/ memmove( ppInf + nBlk1del, ppInf + nBlk1del + nBlkdel,
+/*N*/ ( nBlock - nBlkdel - nBlk1del ) * sizeof( BlockInfo* ) );
+/*N*/
+/*N*/ // JP 19.07.95: nicht den ersten behandelten, sondern den davor!!
+/*N*/ // UpdateIdx updatet nur alle Nachfolgende!!
+/*N*/ if( !nBlk1 )
+/*N*/ {
+/*N*/ p = ppInf[ 0 ];
+/*N*/ p->nStart = 0;
+/*N*/ p->nEnd = p->nElem-1;
+/*N*/ }
+/*N*/ else
+/*N*/ --nBlk1;
+/*N*/ }
+/*N*/ BlockDel( nBlkdel ); // es wurden Bloecke geloescht
+/*N*/ }
+/*N*/
+/*N*/ nSize -= n;
+/*N*/ if( nBlk1 != ( nBlock - 1 ) && nSize )
+/*N*/ UpdIndex( nBlk1 );
+/*N*/ nCur = nBlk1;
+/*N*/
+/*N*/ // wenn mehr als 50% "Luft" im Array ist, dann sollte man mal das
+/*N*/ // Compress aufrufen
+/*N*/ if( nBlock > ( nSize / ( MAXENTRY / 2 ) ) )
+/*N*/ Compress();
+/*N*/
+/*N*/ CHECKIDX( ppInf, nBlock, nSize, nCur );
+/*N*/ }
+
+
+/*N*/ void BigPtrArray::Replace( ULONG idx, const ElementPtr& rElem)
+/*N*/ {
+/*N*/ // weil die Funktion eben doch nicht const ist:
+/*N*/ DBG_ASSERT( idx < nSize, "Set: Index aussserhalb" );
+/*N*/ BigPtrArray* pThis = (BigPtrArray*) this;
+/*N*/ USHORT cur = Index2Block( idx );
+/*N*/ BlockInfo* p = ppInf[ cur ];
+/*N*/ pThis->nCur = cur;
+/*N*/ ((ElementPtr&)rElem)->nOffset = USHORT(idx - p->nStart);
+/*N*/ ((ElementPtr&)rElem)->pBlock = p;
+/*N*/ p->pData[ idx - p->nStart ] = rElem;
+/*N*/ }
+
+
+// Index eines Eintrags heraussuchen
+// Dies ist der selbe Code wie in ForEach() mit dem Unterschied,
+// dass statt einer Funktion ein Vergleich durchgefuehrt wird.
+// Man haette auch ForEach() nehmen koennen, spart aber durch
+// den fehlenden Call etwas Zeit.
+
+
+
+// Array komprimieren
+
+/*N*/ USHORT BigPtrArray::Compress( short nMax )
+/*N*/ {
+/*N*/ CHECKIDX( ppInf, nBlock, nSize, nCur );
+/*N*/
+/*N*/ // Es wird von vorne nach hinten ueber das InfoBlock Array iteriert.
+/*N*/ // Wenn zwischen durch Block gel”scht werden, dann mussen alle
+/*N*/ // nachfolgenden verschoben werden. Dazu werden die Pointer pp und qq
+/*N*/ // benutzt; wobei pp das "alte" Array, qq das "neue" Array ist.
+/*N*/ BlockInfo** pp = ppInf, **qq = pp;
+/*N*/ BlockInfo* p;
+/*N*/ BlockInfo* pLast; // letzter nicht voller Block
+/*N*/ USHORT nLast = 0; // fehlende Elemente
+/*N*/ USHORT nBlkdel = 0; // Anzahl der geloeschte Bloecke
+/*N*/ USHORT nFirstChgPos = USHRT_MAX; // ab welcher Pos gab es die 1. Aenderung?
+/*N*/
+/*N*/ // von Fuell-Prozenten auf uebrige Eintrage umrechnen
+/*N*/ nMax = MAXENTRY - (long) MAXENTRY * nMax / 100;
+/*N*/
+/*N*/ for( USHORT cur = 0; cur < nBlock; ++cur )
+/*N*/ {
+/*N*/ p = *pp++;
+/*N*/ USHORT n = p->nElem;
+/*N*/ // Testen, ob der noch nicht volle Block so gelassen wird
+/*N*/ // dies ist der Fall, wenn der aktuelle Block gesplittet
+/*N*/ // werden muesste, der noch nicht volle Block aber bereits
+/*N*/ // ueber dem uebergebenen Break-Wert voll ist. In diesem
+/*N*/ // Fall wird von einer weiteren Fuellung (die ja wegen dem
+/*N*/ // zweifachen memmove() zeitaufwendig ist) abgesehen.
+/*N*/ if( nLast && ( n > nLast ) && ( nLast < nMax ) )
+/*N*/ nLast = 0;
+/*N*/ if( nLast )
+/*N*/ {
+/*N*/ if( USHRT_MAX == nFirstChgPos )
+/*N*/ nFirstChgPos = cur;
+/*N*/
+/*N*/ // ein nicht voller Block vorhanden: auffuellen
+/*N*/ if( n > nLast )
+/*N*/ n = nLast;
+/*N*/
+/*N*/ // Elemente uebertragen, vom akt. in den letzten
+/*N*/ register ElementPtr* pElem = pLast->pData + pLast->nElem;
+/*N*/ register ElementPtr* pFrom = p->pData;
+/*N*/ for( register int nCount = n, nOff = pLast->nElem;
+/*N*/ nCount; --nCount, ++pElem )
+/*N*/ *pElem = *pFrom++,
+/*N*/ (*pElem)->pBlock = pLast,
+/*N*/ (*pElem)->nOffset = nOff++;
+/*N*/
+/*N*/ // korrigieren
+/*N*/ pLast->nElem += n;
+/*N*/ nLast -= n;
+/*N*/ p->nElem -= n;
+/*N*/
+/*N*/ // Ist der aktuelle Block dadurch leer geworden?
+/*N*/ if( !p->nElem )
+/*N*/ {
+/*N*/ // dann kann der entfernt werden
+/*N*/ delete[] p->pData;
+/*N*/ delete p, p = 0;
+/*N*/ ++nBlkdel;
+/*N*/ }
+/*N*/ else
+/*N*/ {
+/*N*/ pElem = p->pData, pFrom = pElem + n;
+/*N*/ register int nCount = p->nElem;
+/*N*/ while( nCount-- )
+/*N*/ {
+/*N*/ (*pElem++ = *pFrom++)->nOffset -= n;
+/*N*/ }
+/*N*/ }
+/*N*/ }
+/*N*/
+/*N*/ if( p ) // die Blockinfo wurde nicht geloescht
+/*N*/ {
+/*N*/ *qq++ = p; // dann setze sie an die richtige neue Position
+/*N*/
+/*N*/ // eventuell den letzten halbvollen Block festhalten
+/*N*/ if( !nLast && p->nElem < MAXENTRY )
+/*N*/ {
+/*N*/ pLast = p;
+/*N*/ nLast = MAXENTRY - p->nElem;
+/*N*/ }
+/*N*/ }
+/*N*/ }
+/*N*/
+/*N*/ // Bloecke geloescht wurden, ggfs. das BlockInfo Array verkuerzen
+/*N*/ if( nBlkdel )
+/*N*/ BlockDel( nBlkdel );
+/*N*/
+/*N*/ // Und neu durchindizieren
+/*N*/ p = ppInf[ 0 ];
+/*N*/ p->nEnd = p->nElem - 1;
+/*N*/ UpdIndex( 0 );
+/*N*/
+/*N*/ if( nCur >= nFirstChgPos )
+/*N*/ nCur = 0;
+/*N*/
+/*N*/ CHECKIDX( ppInf, nBlock, nSize, nCur );
+/*N*/
+/*N*/ return nFirstChgPos;
+/*N*/ }
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */