xref: /trunk/main/tools/source/memtools/contnr.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_tools.hxx"
30 
31 #ifndef _LIMITS_H
32 #include <limits.h>
33 #endif
34 
35 #ifndef _STRING_H
36 #include <string.h>
37 #endif
38 
39 #ifndef _STDIO_H
40 #include <stdio.h>
41 #endif
42 #include <tools/solar.h>
43 #include <impcont.hxx>
44 #include <tools/contnr.hxx>
45 #include <tools/debug.hxx>
46 
47 // -----------------------------------------------------------------------
48 
49 DBG_NAME( CBlock )
50 DBG_NAME( Container )
51 
52 /*************************************************************************
53 |*
54 |*    DbgCheckCBlock()
55 |*
56 |*    Beschreibung      Pruefung eines CBlock fuer Debug-Utilities
57 |*    Ersterstellung    MI 30.01.92
58 |*    Letzte Aenderung  TH 24.01.96
59 |*
60 *************************************************************************/
61 
62 #ifdef DBG_UTIL
63 const char* CBlock::DbgCheckCBlock( const void* pBlock )
64 {
65     CBlock* p = (CBlock*)pBlock;
66 
67     if ( p->nCount > p->nSize )
68         return "nCount > nSize";
69 
70     if ( p->nSize && !p->pNodes )
71         return "nSize > 0 && pNodes == NULL";
72 
73     return NULL;
74 }
75 #endif
76 
77 /*************************************************************************
78 |*
79 |*    CBlock::CBlock()
80 |*
81 |*    Beschreibung      Construktor des Verwaltungsblocks
82 |*    Ersterstellung    TH 17.09.91
83 |*    Letzte Aenderung  TH 17.09.91
84 |*
85 *************************************************************************/
86 
87 CBlock::CBlock( sal_uInt16 nInitSize, CBlock* _pPrev, CBlock* _pNext )
88 {
89     DBG_CTOR( CBlock, DbgCheckCBlock );
90 
91     pPrev   = _pPrev;
92     pNext   = _pNext;
93     nSize   = nInitSize;
94     nCount  = 0;
95 
96     // Datenpuffer anlegen
97     pNodes = new PVOID[nSize];
98 }
99 
100 /*************************************************************************
101 |*
102 |*    CBlock::CBlock()
103 |*
104 |*    Beschreibung      Construktor des Verwaltungsblocks
105 |*    Ersterstellung    TH 17.09.91
106 |*    Letzte Aenderung  TH 17.09.91
107 |*
108 *************************************************************************/
109 
110 CBlock::CBlock( sal_uInt16 _nSize, CBlock* _pPrev )
111 {
112     DBG_CTOR( CBlock, DbgCheckCBlock );
113     DBG_ASSERT( _nSize, "CBlock::CBlock(): nSize == 0" );
114 
115     pPrev   = _pPrev;
116     pNext   = NULL;
117     nSize   = _nSize;
118     nCount  = _nSize;
119 
120     // Datenpuffer anlegen und initialisieren
121     pNodes = new PVOID[nSize];
122     memset( pNodes, 0, nSize*sizeof(PVOID) );
123 }
124 
125 /*************************************************************************
126 |*
127 |*    CBlock::CBlock()
128 |*
129 |*    Beschreibung      Copy-Construktor des Verwaltungsblocks
130 |*    Ersterstellung    TH 17.09.91
131 |*    Letzte Aenderung  TH 17.09.91
132 |*
133 *************************************************************************/
134 
135 CBlock::CBlock( const CBlock& r, CBlock* _pPrev )
136 {
137     DBG_CTOR( CBlock, DbgCheckCBlock );
138     DBG_CHKOBJ( &r, CBlock, DbgCheckCBlock );
139 
140     pPrev   = _pPrev;
141     pNext   = NULL;
142     nSize   = r.nSize;
143     nCount  = r.nCount;
144 
145     // Datenpuffer anlegen und Daten kopieren
146     pNodes = new PVOID[nSize];
147     memcpy( pNodes, r.pNodes, nCount*sizeof(PVOID) );
148 }
149 
150 /*************************************************************************
151 |*
152 |*    CBlock::~CBlock()
153 |*
154 |*    Beschreibung      Destruktor des Verwaltungsblocks
155 |*    Ersterstellung    TH 17.09.91
156 |*    Letzte Aenderung  TH 17.09.91
157 |*
158 *************************************************************************/
159 
160 inline CBlock::~CBlock()
161 {
162     DBG_DTOR( CBlock, DbgCheckCBlock );
163 
164     // Daten loeschen
165     delete[] pNodes;
166 }
167 
168 /*************************************************************************
169 |*
170 |*    CBlock::Insert()
171 |*
172 |*    Beschreibung      Fuegt einen Pointer ein
173 |*    Ersterstellung    TH 17.09.91
174 |*    Letzte Aenderung  TH 17.09.91
175 |*
176 *************************************************************************/
177 
178 void CBlock::Insert( void* p, sal_uInt16 nIndex, sal_uInt16 nReSize )
179 {
180     DBG_CHKTHIS( CBlock, DbgCheckCBlock );
181     DBG_ASSERT( nIndex <= nCount, "CBlock::Insert(): Index > nCount" );
182 
183     // Muss Block realokiert werden
184     if ( nCount == nSize )
185     {
186         // Neue Daten anlegen
187         nSize = nSize + nReSize;    // MSVC warns here if += is used
188         void** pNewNodes = new PVOID[nSize];
189 
190         // Wird angehaengt
191         if ( nCount == nIndex )
192         {
193             // Daten kopieren
194             memcpy( pNewNodes, pNodes, nCount*sizeof(PVOID) );
195         }
196         else
197         {
198             // Daten kopieren
199             memcpy( pNewNodes, pNodes, nIndex*sizeof(PVOID) );
200             memcpy( pNewNodes + nIndex + 1,
201                     pNodes + nIndex,
202                     (nCount-nIndex)*sizeof(PVOID) );
203         }
204 
205         // Alte Daten loeschen und neue setzen
206         delete[] pNodes;
207         pNodes = pNewNodes;
208     }
209     else
210     {
211         if ( nIndex < nCount )
212         {
213             memmove( pNodes + nIndex + 1,
214                      pNodes + nIndex,
215                      (nCount-nIndex)*sizeof(PVOID) );
216         }
217     }
218 
219     // Neuen Pointer setzen und Elementgroesse erhoehen
220     pNodes[nIndex] = p;
221     nCount++;
222 }
223 
224 /*************************************************************************
225 |*
226 |*    CBlock::Split()
227 |*
228 |*    Beschreibung      Fuegt einen Pointer ein und splittet den Block
229 |*    Ersterstellung    TH 17.09.91
230 |*    Letzte Aenderung  TH 17.09.91
231 |*
232 *************************************************************************/
233 
234 CBlock* CBlock::Split( void* p, sal_uInt16 nIndex, sal_uInt16 nReSize )
235 {
236     DBG_CHKTHIS( CBlock, DbgCheckCBlock );
237 
238     sal_uInt16  nNewSize;
239     sal_uInt16  nMiddle;
240     CBlock* pNewBlock;
241 
242     nMiddle = nCount/2;
243 
244     if ( ( nIndex == nCount ) || ( nIndex == 0 ) )
245         nNewSize = nReSize;
246     else
247     {
248         // Der aktuelle Block wird in der Mitte geteilt
249         nNewSize = (nCount+1) / 2;
250 
251         if ( nNewSize < nReSize )
252             nNewSize = nReSize;
253         else
254         {
255             // Neue Groesse muss ein vielfaches von Resize sein
256             if ( nNewSize % nReSize )
257                 nNewSize += nReSize - (nNewSize % nReSize);
258             else
259                 nNewSize = nNewSize + nReSize;  // MSVC warns here if += is used
260         }
261     }
262 
263     // Vor oder hinter dem aktuellem Block einfuegen?
264     if ( nIndex > nMiddle )
265     {
266         // Neuen Split-Block anlegen und hinter dem aktuellem Block einfuegen
267         pNewBlock = new CBlock( nNewSize, this, pNext );
268 
269         if ( pNext )
270             pNext->pPrev = pNewBlock;
271         pNext = pNewBlock;
272 
273         if ( nIndex == nCount )
274         {
275             // Neuen Pointer einfuegen
276             pNewBlock->pNodes[0] = p;
277             pNewBlock->nCount = 1;
278         }
279         else
280         {
281             nIndex = nIndex - nMiddle;  // MSVC warns here if += is used
282             // Alles von Mitte bis Index kopieren
283             if ( nIndex )
284                 memcpy( pNewBlock->pNodes, pNodes+nMiddle, nIndex*sizeof(PVOID) );
285 
286             // Neuen Pointer einfuegen
287             pNewBlock->pNodes[nIndex] = p;
288 
289             // Alles von Mitte bis Ende hinter Index kopieren
290             memcpy( pNewBlock->pNodes+nIndex+1,
291                     pNodes+nMiddle+nIndex,
292                     (nCount-nMiddle-nIndex) * sizeof(PVOID) );
293 
294             pNewBlock->nCount = (nCount-nMiddle+1);
295             nCount = nMiddle;
296 
297             // Den aktuellen Datenbereich auch halbieren
298             if ( nSize != nNewSize )
299             {
300                 void** pNewNodes = new PVOID[nNewSize];
301                 memcpy( pNewNodes, pNodes, nCount*sizeof(PVOID) );
302                 delete[] pNodes;
303                 pNodes = pNewNodes;
304                 nSize = nNewSize;
305             }
306         }
307     }
308     else
309     {
310         // Neuen Split-Block anlegen und vor dem aktuellem Block einfuegen
311         pNewBlock = new CBlock( nNewSize, pPrev, this );
312 
313         if ( pPrev )
314             pPrev->pNext = pNewBlock;
315         pPrev = pNewBlock;
316 
317         if ( nIndex == 0 )
318         {
319             // Neuen Pointer einfuegen
320             pNewBlock->pNodes[0] = p;
321             pNewBlock->nCount = 1;
322         }
323         else
324         {
325             // Alles von Anfang bis Index kopieren
326             memcpy( pNewBlock->pNodes, pNodes, nIndex*sizeof(PVOID) );
327 
328             // Neuen Pointer einfuegen
329             pNewBlock->pNodes[nIndex] = p;
330 
331             // Alles von Index bis Mitte hinter Index kopieren
332             if ( nIndex != nMiddle )
333             {
334                 memcpy( pNewBlock->pNodes+nIndex+1,
335                         pNodes+nIndex,
336                         (nMiddle-nIndex) * sizeof(PVOID) );
337             }
338 
339             pNewBlock->nCount = nMiddle+1;
340             nCount = nCount - nMiddle;  // MSVC warns here if += is used
341 
342             // Die zweite Haelfte in einen neuen Block kopieren
343             if ( nSize != nNewSize )
344             {
345                 void** pNewNodes = new PVOID[nNewSize];
346                 memcpy( pNewNodes, pNodes+nMiddle, nCount*sizeof(PVOID) );
347                 delete[] pNodes;
348                 pNodes = pNewNodes;
349                 nSize = nNewSize;
350             }
351             else
352                 memmove( pNodes, pNodes+nMiddle, nCount*sizeof(PVOID) );
353         }
354     }
355 
356     // Neu angelegten Block zurueckgeben, da gegebenfalls die Blockpointer
357     // im Container angepast werden koennen
358     return pNewBlock;
359 }
360 
361 /*************************************************************************
362 |*
363 |*    CBlock::Remove()
364 |*
365 |*    Beschreibung      Entfernt einen Pointer
366 |*    Ersterstellung    TH 17.09.91
367 |*    Letzte Aenderung  TH 17.09.91
368 |*
369 *************************************************************************/
370 
371 void* CBlock::Remove( sal_uInt16 nIndex, sal_uInt16 nReSize )
372 {
373     DBG_CHKTHIS( CBlock, DbgCheckCBlock );
374 
375     // Alten Pointer sichern
376     void* pOld = pNodes[nIndex];
377 
378     // 1 Element weniger
379     nCount--;
380 
381     // Block verkleinern (wenn Reallokationsgroesse um 4 unterschritten wird)
382     if ( nCount == (nSize-nReSize-4) )
383     {
384         // Neue Daten anlegen
385         nSize = nSize - nReSize;    // MSVC warns here if += is used
386         void** pNewNodes = new PVOID[nSize];
387 
388         // Wird letzter Eintrag geloescht
389         if ( nIndex == nCount )
390         {
391             // Daten kopieren
392             memcpy( pNewNodes, pNodes, nCount*sizeof(PVOID) );
393         }
394         else
395         {
396             // Daten kopieren
397             memcpy( pNewNodes, pNodes, nIndex*sizeof(PVOID) );
398             memcpy( pNewNodes + nIndex, pNodes + nIndex+1,
399                     (nCount-nIndex)*sizeof(PVOID) );
400         }
401 
402         // Alte Daten loeschen und neue setzen
403         delete[] pNodes;
404         pNodes = pNewNodes;
405     }
406     else
407     {
408         // Wenn nicht das letzte Element, dann zusammenschieben
409         if ( nIndex < nCount )
410         {
411             memmove( pNodes + nIndex, pNodes + nIndex + 1,
412                      (nCount-nIndex)*sizeof(PVOID) );
413         }
414     }
415 
416     // Alten Pointer zurueckgeben
417     return pOld;
418 }
419 
420 /*************************************************************************
421 |*
422 |*    CBlock::Replace()
423 |*
424 |*    Beschreibung      Ersetzt einen Pointer
425 |*    Ersterstellung    TH 17.09.91
426 |*    Letzte Aenderung  TH 17.09.91
427 |*
428 *************************************************************************/
429 
430 inline void* CBlock::Replace( void* p, sal_uInt16 nIndex )
431 {
432     DBG_CHKTHIS( CBlock, DbgCheckCBlock );
433 
434     // Alten Pointer sichern, neuen setzen und alten zurueckgeben
435     void* pOld = pNodes[nIndex];
436     pNodes[nIndex] = p;
437     return pOld;
438 }
439 
440 /*************************************************************************
441 |*
442 |*    CBlock::GetObjectPtr()
443 |*
444 |*    Beschreibung      Gibt einen Pointer auf den Pointer aus dem Block
445 |*                      zurueck
446 |*    Ersterstellung    TH 26.01.93
447 |*    Letzte Aenderung  TH 26.01.93
448 |*
449 *************************************************************************/
450 
451 inline void** CBlock::GetObjectPtr( sal_uInt16 nIndex )
452 {
453     DBG_CHKTHIS( CBlock, DbgCheckCBlock );
454 
455     return &(pNodes[nIndex]);
456 }
457 
458 /*************************************************************************
459 |*
460 |*    CBlock::SetSize()
461 |*
462 |*    Beschreibung      Aendert die Groesse des Blocks
463 |*    Ersterstellung    TH 17.09.91
464 |*    Letzte Aenderung  TH 17.09.91
465 |*
466 *************************************************************************/
467 
468 void CBlock::SetSize( sal_uInt16 nNewSize )
469 {
470     DBG_CHKTHIS( CBlock, DbgCheckCBlock );
471     DBG_ASSERT( nNewSize, "CBlock::SetSize(): nNewSize == 0" );
472 
473     // Unterscheidet sich die Groesse
474     if ( nNewSize != nCount )
475     {
476         // Array erweitern
477         void** pNewNodes = new PVOID[nNewSize];
478 
479         // Alte Tabelle in die Neue kopieren
480         if ( nNewSize < nCount )
481             memcpy( pNewNodes, pNodes, nNewSize*sizeof(PVOID) );
482         else
483         {
484             memcpy( pNewNodes, pNodes, nCount*sizeof(PVOID) );
485 
486             // Array mit 0 initialisieren
487             memset( pNewNodes+nCount, 0, (nNewSize-nCount)*sizeof(PVOID) );
488         }
489 
490         // Altes Array loeschen und neue Werte setzen
491         nSize  = nNewSize;
492         nCount = nSize;
493         delete[] pNodes;
494         pNodes = pNewNodes;
495     }
496 }
497 
498 //------------------------------------------------------------------------
499 
500 /*************************************************************************
501 |*
502 |*    DbgCheckContainer()
503 |*
504 |*    Beschreibung      Pruefung eines Container fuer Debug-Utilities
505 |*    Ersterstellung    MI 30.01.92
506 |*    Letzte Aenderung  TH 24.01.96
507 |*
508 *************************************************************************/
509 
510 #ifdef DBG_UTIL
511 const char* Container::DbgCheckContainer( const void* pCont )
512 {
513     Container* p = (Container*)pCont;
514 
515     if ( p->nCount && (!p->pFirstBlock || !p->pLastBlock || !p->pCurBlock) )
516         return "nCount > 0 but no CBlocks";
517 
518     return NULL;
519 }
520 #endif
521 
522 /*************************************************************************
523 |*
524 |*    ImpCopyContainer()
525 |*
526 |*    Beschreibung      Kopiert alle Daten des Containers
527 |*    Ersterstellung    TH 24.01.96
528 |*    Letzte Aenderung  TH 24.01.96
529 |*
530 *************************************************************************/
531 
532 void Container::ImpCopyContainer( const Container* pCont2 )
533 {
534     // Werte vom uebergebenen Container uebernehmen
535     nCount     = pCont2->nCount;
536     nCurIndex  = pCont2->nCurIndex;
537     nInitSize  = pCont2->nInitSize;
538     nReSize    = pCont2->nReSize;
539     nBlockSize = pCont2->nBlockSize;
540 
541     // Alle Bloecke kopieren
542     if ( pCont2->nCount )
543     {
544         CBlock* pBlock1;
545         CBlock* pBlock2;
546         CBlock* pTempBlock;
547 
548         // Erstmal ersten Block kopieren
549         pBlock2 = pCont2->pFirstBlock;
550         pFirstBlock = new CBlock( *pBlock2, NULL );
551         // Ist erster Block der Current-Block, dann Current-Block setzen
552         if ( pBlock2 == pCont2->pCurBlock )
553             pCurBlock = pFirstBlock;
554         pBlock1 = pFirstBlock;
555         pBlock2 = pBlock2->GetNextBlock();
556         while ( pBlock2 )
557         {
558             // Neuen Block anlegen und aus der uebergebenen Liste kopieren
559             pTempBlock = new CBlock( *pBlock2, pBlock1 );
560             pBlock1->SetNextBlock( pTempBlock );
561             pBlock1 = pTempBlock;
562 
563             // Current-Block beruecksichtigen
564             if ( pBlock2 == pCont2->pCurBlock )
565                 pCurBlock = pBlock1;
566 
567             // Auf naechsten Block weitersetzen
568             pBlock2 = pBlock2->GetNextBlock();
569         }
570 
571         // Letzten Block setzen
572         pLastBlock = pBlock1;
573     }
574     else
575     {
576         pFirstBlock = NULL;
577         pLastBlock  = NULL;
578         pCurBlock   = NULL;
579     }
580 }
581 
582 /*************************************************************************
583 |*
584 |*    Container::Container()
585 |*
586 |*    Beschreibung      CONTNR.SDW
587 |*    Ersterstellung    TH 17.09.91
588 |*    Letzte Aenderung  TH 17.09.91
589 |*
590 *************************************************************************/
591 
592 Container::Container( sal_uInt16 _nBlockSize, sal_uInt16 _nInitSize, sal_uInt16 _nReSize )
593 {
594     DBG_CTOR( Container, DbgCheckContainer );
595 
596     // BlockSize muss mindestens 4 sein und kleiner als 64 KB
597     if ( _nBlockSize < 4 )
598         nBlockSize = 4;
599     else
600     {
601         if ( _nBlockSize < CONTAINER_MAXBLOCKSIZE )
602             nBlockSize = _nBlockSize;
603         else
604             nBlockSize = CONTAINER_MAXBLOCKSIZE;
605     }
606 
607     // ReSize muss mindestens 2 sein und kleiner als BlockSize
608     if ( _nReSize >= nBlockSize )
609         nReSize = nBlockSize;
610     else
611     {
612         if ( _nReSize < 2 )
613             nReSize = 2;
614         else
615             nReSize = _nReSize;
616 
617         // BlockSize muss ein vielfaches der Resizegroesse sein
618         if ( nBlockSize % nReSize )
619             nBlockSize -= nReSize - (nBlockSize % nReSize);
620     }
621 
622     // InitSize muss groesser gleich ReSize sein und kleiner als BlockSize
623     if ( _nInitSize <= nReSize )
624         nInitSize = nReSize;
625     else
626     {
627         if ( _nInitSize >= nBlockSize )
628             nInitSize = nBlockSize;
629         else
630         {
631             nInitSize = _nInitSize;
632 
633             // InitSize muss ein vielfaches der Resizegroesse sein
634             if ( nInitSize % nReSize )
635                 nInitSize -= nReSize - (nInitSize % nReSize);
636         }
637     }
638 
639     // Werte initialisieren
640     pFirstBlock = NULL;
641     pLastBlock  = NULL;
642     pCurBlock   = NULL;
643     nCount      = 0;
644     nCurIndex   = 0;
645 }
646 
647 /*************************************************************************
648 |*
649 |*    Container::Container()
650 |*
651 |*    Beschreibung      CONTNR.SDW
652 |*    Ersterstellung    TH 17.09.91
653 |*    Letzte Aenderung  TH 17.09.91
654 |*
655 *************************************************************************/
656 
657 Container::Container( sal_uIntPtr nSize )
658 {
659     DBG_CTOR( Container, DbgCheckContainer );
660 
661     nCount     = nSize;
662     nCurIndex  = 0;
663     nBlockSize = CONTAINER_MAXBLOCKSIZE;
664     nInitSize  = 1;
665     nReSize    = 1;
666 
667     if ( !nSize )
668     {
669         pFirstBlock = NULL;
670         pLastBlock  = NULL;
671         pCurBlock   = NULL;
672     }
673     else
674     {
675         // Muss mehr als ein Block angelegt werden
676         if ( nSize <= nBlockSize )
677         {
678             pFirstBlock = new CBlock( (sal_uInt16)nSize, NULL );
679             pLastBlock = pFirstBlock;
680         }
681         else
682         {
683             CBlock* pBlock1;
684             CBlock* pBlock2;
685 
686             pFirstBlock = new CBlock( nBlockSize, NULL );
687             pBlock1 = pFirstBlock;
688             nSize -= nBlockSize;
689 
690             // Solange die Blockgroesse ueberschritten wird, neue Bloecke anlegen
691             while ( nSize > nBlockSize )
692             {
693                 pBlock2 = new CBlock( nBlockSize, pBlock1 );
694                 pBlock1->SetNextBlock( pBlock2 );
695                 pBlock1 = pBlock2;
696                 nSize -= nBlockSize;
697             }
698 
699             pLastBlock = new CBlock( (sal_uInt16)nSize, pBlock1 );
700             pBlock1->SetNextBlock( pLastBlock );
701         }
702 
703         pCurBlock  = pFirstBlock;
704     }
705 }
706 
707 /*************************************************************************
708 |*
709 |*    Container::Container()
710 |*
711 |*    Beschreibung      CONTNR.SDW
712 |*    Ersterstellung    TH 17.09.91
713 |*    Letzte Aenderung  TH 17.09.91
714 |*
715 *************************************************************************/
716 
717 Container::Container( const Container& r )
718 {
719     DBG_CTOR( Container, DbgCheckContainer );
720 
721     // Daten kopieren
722     ImpCopyContainer( &r );
723 }
724 
725 /*************************************************************************
726 |*
727 |*    Container::~Container()
728 |*
729 |*    Beschreibung      CONTNR.SDW
730 |*    Ersterstellung    TH 17.09.91
731 |*    Letzte Aenderung  TH 17.09.91
732 |*
733 *************************************************************************/
734 
735 Container::~Container()
736 {
737     DBG_DTOR( Container, DbgCheckContainer );
738 
739     // Alle Bloecke loeschen
740     CBlock* pBlock = pFirstBlock;
741     while ( pBlock )
742     {
743         CBlock* pTemp = pBlock->GetNextBlock();
744         delete pBlock;
745         pBlock = pTemp;
746     }
747 }
748 
749 /*************************************************************************
750 |*
751 |*    Container::ImpInsert()
752 |*
753 |*    Beschreibung      Interne Methode zum Einfuegen eines Pointers
754 |*    Ersterstellung    TH 17.09.91
755 |*    Letzte Aenderung  DV 01.07.97
756 |*
757 *************************************************************************/
758 
759 void Container::ImpInsert( void* p, CBlock* pBlock, sal_uInt16 nIndex )
760 {
761     DBG_CHKTHIS( Container, DbgCheckContainer );
762 
763     if ( !nCount )
764     {
765         if ( !pBlock )
766         {
767             pFirstBlock = new CBlock( nInitSize, NULL, NULL );
768             pLastBlock  = pFirstBlock;
769             pCurBlock   = pFirstBlock;
770         }
771         pFirstBlock->Insert( p, nIndex, nReSize );
772     }
773     else
774     {
775         // Ist im Block die maximale Blockgroesse erreicht,
776         // dann neuen Block anlegen
777         if ( pBlock->Count() == nBlockSize )
778         {
779             // Block auftrennen
780             CBlock* pNewBlock = pBlock->Split( p, nIndex, nReSize );
781 
782             // Wurde Block dahinter angehaegnt
783             if ( pBlock->pNext == pNewBlock )
784             {
785                 // Gegebenenfalls LastBlock anpassen
786                 if ( pBlock == pLastBlock )
787                     pLastBlock = pNewBlock;
788 
789                 // Current-Position nachfuehren
790                 if ( pBlock == pCurBlock )
791                 {
792                     if ( pBlock->nCount <= nCurIndex )
793                     {
794                         if ( nIndex <= nCurIndex )
795                             nCurIndex++;
796                         pCurBlock  = pNewBlock;
797                         nCurIndex = nCurIndex - pBlock->nCount; // MSVC warns here if += is used
798                     }
799                 }
800             }
801             else
802             {
803                 // Gegebenenfalls FirstBlock anpassen
804                 if ( pBlock == pFirstBlock )
805                     pFirstBlock = pNewBlock;
806 
807                 // Current-Position nachfuehren
808                 if ( pBlock == pCurBlock )
809                 {
810                     if ( nIndex <= nCurIndex )
811                         nCurIndex++;
812                     if ( pNewBlock->nCount <= nCurIndex )
813                         nCurIndex = nCurIndex - pNewBlock->nCount;  // MSVC warns here if += is used
814                     else
815                         pCurBlock = pNewBlock;
816                 }
817             }
818         }
819         else
820         {
821             // Sonst reicht normales einfuegen in den Block
822             pBlock->Insert( p, nIndex, nReSize );
823 
824             // Current-Position nachfuehren
825             if ( (pBlock == pCurBlock) && (nIndex <= nCurIndex) )
826                 nCurIndex++;
827         }
828     }
829 
830     // Ein neues Item im Container
831     nCount++;
832 }
833 
834 /*************************************************************************
835 |*
836 |*    Container::Insert()
837 |*
838 |*    Beschreibung      CONTNR.SDW
839 |*    Ersterstellung    TH 17.09.91
840 |*    Letzte Aenderung  TH 17.09.91
841 |*
842 *************************************************************************/
843 
844 void Container::Insert( void* p )
845 {
846     ImpInsert( p, pCurBlock, nCurIndex );
847 }
848 
849 /*************************************************************************
850 |*
851 |*    Container::Insert()
852 |*
853 |*    Beschreibung      CONTNR.SDW
854 |*    Ersterstellung    TH 17.09.91
855 |*    Letzte Aenderung  TH 17.09.91
856 |*
857 *************************************************************************/
858 
859 void Container::Insert( void* p, sal_uIntPtr nIndex )
860 {
861     if ( nCount <= nIndex )
862     {
863         if ( pLastBlock )
864             ImpInsert( p, pLastBlock, pLastBlock->Count() );
865         else
866             ImpInsert( p, NULL, 0 );
867     }
868     else
869     {
870         // Block suchen
871         CBlock* pTemp = pFirstBlock;
872         while ( pTemp->Count() < nIndex )
873         {
874             nIndex -= pTemp->Count();
875             pTemp   = pTemp->GetNextBlock();
876         }
877 
878         ImpInsert( p, pTemp, (sal_uInt16)nIndex );
879     }
880 }
881 
882 /*************************************************************************
883 |*
884 |*    Container::Insert()
885 |*
886 |*    Beschreibung      CONTNR.SDW
887 |*    Ersterstellung    TH 17.09.91
888 |*    Letzte Aenderung  TH 17.09.91
889 |*
890 *************************************************************************/
891 
892 void Container::Insert( void* pNew, void* pOld )
893 {
894     sal_uIntPtr nIndex = GetPos( pOld );
895     if ( nIndex != CONTAINER_ENTRY_NOTFOUND )
896         Insert( pNew, nIndex );
897 }
898 
899 /*************************************************************************
900 |*
901 |*    Container::ImpRemove()
902 |*
903 |*    Beschreibung      Interne Methode zum Entfernen eines Pointers
904 |*    Ersterstellung    TH 17.09.91
905 |*    Letzte Aenderung  TH 17.09.91
906 |*
907 *************************************************************************/
908 
909 void* Container::ImpRemove( CBlock* pBlock, sal_uInt16 nIndex )
910 {
911     DBG_CHKTHIS( Container, DbgCheckContainer );
912 
913     void* pOld;
914 
915     // Ist Liste danach leer
916     if ( nCount == 1 )
917     {
918         // Block und CurIndex zuruecksetzen
919         pOld = pBlock->GetObject( nIndex );
920         pBlock->Reset();
921         nCurIndex = 0;
922     }
923     else
924     {
925         // Ist Block nach Remove leer
926         if ( pBlock->Count() == 1 )
927         {
928             // dann Block entfernen und Block-Pointer umsetzen
929             if ( pBlock->GetPrevBlock() )
930                 (pBlock->GetPrevBlock())->SetNextBlock( pBlock->GetNextBlock() );
931             else
932                 pFirstBlock = pBlock->GetNextBlock();
933 
934             if ( pBlock->GetNextBlock() )
935                 (pBlock->GetNextBlock())->SetPrevBlock( pBlock->GetPrevBlock() );
936             else
937                 pLastBlock = pBlock->GetPrevBlock();
938 
939             // Current-Position nachfuehren
940             if ( pBlock == pCurBlock )
941             {
942                 if ( pBlock->GetNextBlock() )
943                 {
944                     pCurBlock = pBlock->GetNextBlock();
945                     nCurIndex = 0;
946                 }
947                 else
948                 {
949                     pCurBlock = pBlock->GetPrevBlock();
950                     nCurIndex = pCurBlock->Count()-1;
951                 }
952             }
953 
954             pOld = pBlock->GetObject( nIndex );
955             delete pBlock;
956         }
957         else
958         {
959             // Sonst Item aus dem Block entfernen
960             pOld = pBlock->Remove( nIndex, nReSize );
961 
962             // Current-Position nachfuehren
963             if ( (pBlock == pCurBlock) &&
964                  ((nIndex < nCurIndex) || ((nCurIndex == pBlock->Count()) && nCurIndex)) )
965                 nCurIndex--;
966         }
967     }
968 
969     // Jetzt gibt es ein Item weniger
970     nCount--;
971 
972     // Und den Pointer zurueckgeben, der entfernt wurde
973     return pOld;
974 }
975 
976 /*************************************************************************
977 |*
978 |*    Container::Remove()
979 |*
980 |*    Beschreibung      CONTNR.SDW
981 |*    Ersterstellung    TH 17.09.91
982 |*    Letzte Aenderung  TH 17.09.91
983 |*
984 *************************************************************************/
985 
986 void* Container::Remove()
987 {
988     // Wenn kein Item vorhanden ist, NULL zurueckgeben
989     if ( !nCount )
990         return NULL;
991     else
992         return ImpRemove( pCurBlock, nCurIndex );
993 }
994 
995 /*************************************************************************
996 |*
997 |*    Container::Remove()
998 |*
999 |*    Beschreibung      CONTNR.SDW
1000 |*    Ersterstellung    TH 17.09.91
1001 |*    Letzte Aenderung  TH 17.09.91
1002 |*
1003 *************************************************************************/
1004 
1005 void* Container::Remove( sal_uIntPtr nIndex )
1006 {
1007     // Ist Index nicht innerhalb des Containers, dann NULL zurueckgeben
1008     if ( nCount <= nIndex )
1009         return NULL;
1010     else
1011     {
1012         // Block suchen
1013         CBlock* pTemp = pFirstBlock;
1014         while ( pTemp->Count() <= nIndex )
1015         {
1016             nIndex -= pTemp->Count();
1017             pTemp   = pTemp->GetNextBlock();
1018         }
1019 
1020         return ImpRemove( pTemp, (sal_uInt16)nIndex );
1021     }
1022 }
1023 
1024 /*************************************************************************
1025 |*
1026 |*    Container::Replace()
1027 |*
1028 |*    Beschreibung      CONTNR.SDW
1029 |*    Ersterstellung    TH 17.09.91
1030 |*    Letzte Aenderung  TH 17.09.91
1031 |*
1032 *************************************************************************/
1033 
1034 void* Container::Replace( void* p )
1035 {
1036     DBG_CHKTHIS( Container, DbgCheckContainer );
1037 
1038     if ( !nCount )
1039         return NULL;
1040     else
1041         return pCurBlock->Replace( p, nCurIndex );
1042 }
1043 
1044 /*************************************************************************
1045 |*
1046 |*    Container::Replace()
1047 |*
1048 |*    Beschreibung      CONTNR.SDW
1049 |*    Ersterstellung    TH 17.09.91
1050 |*    Letzte Aenderung  TH 17.09.91
1051 |*
1052 *************************************************************************/
1053 
1054 void* Container::Replace( void* p, sal_uIntPtr nIndex )
1055 {
1056     DBG_CHKTHIS( Container, DbgCheckContainer );
1057 
1058     // Ist Index nicht innerhalb des Containers, dann NULL zurueckgeben
1059     if ( nCount <= nIndex )
1060         return NULL;
1061     else
1062     {
1063         // Block suchen
1064         CBlock* pTemp = pFirstBlock;
1065         while ( pTemp->Count() <= nIndex )
1066         {
1067             nIndex -= pTemp->Count();
1068             pTemp   = pTemp->GetNextBlock();
1069         }
1070 
1071         return pTemp->Replace( p, (sal_uInt16)nIndex );
1072     }
1073 }
1074 
1075 /*************************************************************************
1076 |*
1077 |*    Container::SetSize()
1078 |*
1079 |*    Beschreibung      CONTNR.SDW
1080 |*    Ersterstellung    TH 17.09.91
1081 |*    Letzte Aenderung  TH 17.09.91
1082 |*
1083 *************************************************************************/
1084 
1085 void Container::SetSize( sal_uIntPtr nNewSize )
1086 {
1087     DBG_CHKTHIS( Container, DbgCheckContainer );
1088 
1089     if ( nNewSize )
1090     {
1091         // Unterscheiden sich die Groessen
1092         if ( nNewSize != nCount )
1093         {
1094             CBlock* pTemp;
1095             sal_uIntPtr nTemp;
1096 
1097             // Wird verkleinert
1098             if ( nNewSize < nCount )
1099             {
1100                 pTemp = pFirstBlock;
1101                 nTemp = 0;
1102                 while ( (nTemp+pTemp->Count()) < nNewSize )
1103                 {
1104                     nTemp += pTemp->Count();
1105                     pTemp  = pTemp->GetNextBlock();
1106                 }
1107 
1108                 // Alle folgenden Bloecke loeschen
1109                 sal_Bool    bLast = sal_False;
1110                 CBlock* pDelNext;
1111                 CBlock* pDelBlock = pTemp->GetNextBlock();
1112                 while ( pDelBlock )
1113                 {
1114                     // Muss CurrentBlock umgesetzt werden
1115                     if ( pDelBlock == pCurBlock )
1116                         bLast = sal_True;
1117                     pDelNext = pDelBlock->GetNextBlock();
1118                     delete pDelBlock;
1119                     pDelBlock = pDelNext;
1120                 }
1121 
1122                 // Block in der Groesse anpassen, oder bei Groesse 0 loeschen
1123                 if ( nNewSize > nTemp )
1124                 {
1125                     pLastBlock = pTemp;
1126                     pTemp->SetNextBlock( NULL );
1127                     pTemp->SetSize( (sal_uInt16)(nNewSize-nTemp) );
1128                 }
1129                 else
1130                 {
1131                     pLastBlock = pTemp->GetPrevBlock();
1132                     pLastBlock->SetNextBlock( NULL );
1133                     delete pTemp;
1134                 }
1135 
1136                 nCount = nNewSize;
1137                 if ( bLast )
1138                 {
1139                     pCurBlock = pLastBlock;
1140                     nCurIndex = pCurBlock->Count()-1;
1141                 }
1142             }
1143             else
1144             {
1145                 // Auf den letzen Puffer setzen
1146                 pTemp = pLastBlock;
1147                 nTemp = nNewSize - nCount;
1148 
1149                 if ( !pTemp )
1150                 {
1151                     // Muss mehr als ein Block angelegt werden
1152                     if ( nNewSize <= nBlockSize )
1153                     {
1154                         pFirstBlock = new CBlock( (sal_uInt16)nNewSize, NULL );
1155                         pLastBlock = pFirstBlock;
1156                     }
1157                     else
1158                     {
1159                         CBlock* pBlock1;
1160                         CBlock* pBlock2;
1161 
1162                         pFirstBlock = new CBlock( nBlockSize, NULL );
1163                         pBlock1 = pFirstBlock;
1164                         nNewSize -= nBlockSize;
1165 
1166                         // Solange die Blockgroesse ueberschritten wird, neue Bloecke anlegen
1167                         while ( nNewSize > nBlockSize )
1168                         {
1169                             pBlock2 = new CBlock( nBlockSize, pBlock1 );
1170                             pBlock1->SetNextBlock( pBlock2 );
1171                             pBlock1 = pBlock2;
1172                             nNewSize -= nBlockSize;
1173                         }
1174 
1175                         pLastBlock = new CBlock( (sal_uInt16)nNewSize, pBlock1 );
1176                         pBlock1->SetNextBlock( pLastBlock );
1177                     }
1178 
1179                     pCurBlock  = pFirstBlock;
1180                 }
1181                 // Reicht es, den letzen Puffer in der Groesse anzupassen
1182                 else if ( (nTemp+pTemp->Count()) <= nBlockSize )
1183                     pTemp->SetSize( (sal_uInt16)(nTemp+pTemp->Count()) );
1184                 else
1185                 {
1186                     // Puffer auf max. Blockgroesse setzen
1187                     nTemp -= nBlockSize - pTemp->GetSize();
1188                     pTemp->SetSize( nBlockSize );
1189 
1190                     CBlock* pTemp2;
1191                     // Solange die Blockgroesse ueberschritten wird,
1192                     // neue Bloecke anlegen
1193                     while ( nTemp > nBlockSize )
1194                     {
1195                         pTemp2 = new CBlock( nBlockSize, pTemp );
1196                         pTemp->SetNextBlock( pTemp2 );
1197                         pTemp = pTemp2;
1198                         nTemp -= nBlockSize;
1199                     }
1200 
1201                     // Den letzten Block anlegen
1202                     if ( nTemp )
1203                     {
1204                         pLastBlock = new CBlock( (sal_uInt16)nTemp, pTemp );
1205                         pTemp->SetNextBlock( pLastBlock );
1206                     }
1207                     else
1208                         pLastBlock = pTemp;
1209                 }
1210 
1211                 nCount = nNewSize;
1212             }
1213         }
1214     }
1215     else
1216         Clear();
1217 }
1218 
1219 /*************************************************************************
1220 |*
1221 |*    Container::Clear()
1222 |*
1223 |*    Beschreibung      CONTNR.SDW
1224 |*    Ersterstellung    TH 17.09.91
1225 |*    Letzte Aenderung  TH 17.09.91
1226 |*
1227 *************************************************************************/
1228 
1229 void Container::Clear()
1230 {
1231     DBG_CHKTHIS( Container, DbgCheckContainer );
1232 
1233     // Erst alle Bloecke loeschen
1234     CBlock* pBlock = pFirstBlock;
1235     while ( pBlock )
1236     {
1237         CBlock* pTemp = pBlock->GetNextBlock();
1238         delete pBlock;
1239         pBlock = pTemp;
1240     }
1241 
1242     // Werte zuruecksetzen
1243     pFirstBlock = NULL;
1244     pLastBlock  = NULL;
1245     pCurBlock   = NULL;
1246     nCount      = 0;
1247     nCurIndex   = 0;
1248 }
1249 
1250 /*************************************************************************
1251 |*
1252 |*    Container::GetCurObject()
1253 |*
1254 |*    Beschreibung      CONTNR.SDW
1255 |*    Ersterstellung    TH 17.09.91
1256 |*    Letzte Aenderung  TH 17.09.91
1257 |*
1258 *************************************************************************/
1259 
1260 void* Container::GetCurObject() const
1261 {
1262     DBG_CHKTHIS( Container, DbgCheckContainer );
1263 
1264     // NULL, wenn Container leer
1265     if ( !nCount )
1266         return NULL;
1267     else
1268         return pCurBlock->GetObject( nCurIndex );
1269 }
1270 
1271 /*************************************************************************
1272 |*
1273 |*    Container::GetCurPos()
1274 |*
1275 |*    Beschreibung      CONTNR.SDW
1276 |*    Ersterstellung    TH 17.09.91
1277 |*    Letzte Aenderung  TH 17.09.91
1278 |*
1279 *************************************************************************/
1280 
1281 sal_uIntPtr Container::GetCurPos() const
1282 {
1283     DBG_CHKTHIS( Container, DbgCheckContainer );
1284 
1285     // CONTAINER_ENTRY_NOTFOUND, wenn Container leer
1286     if ( !nCount )
1287         return CONTAINER_ENTRY_NOTFOUND;
1288     else
1289     {
1290         // Block suchen
1291         CBlock* pTemp = pFirstBlock;
1292         sal_uIntPtr nTemp = 0;
1293         while ( pTemp != pCurBlock )
1294         {
1295             nTemp += pTemp->Count();
1296             pTemp  = pTemp->GetNextBlock();
1297         }
1298 
1299         return nTemp+nCurIndex;
1300     }
1301 }
1302 
1303 /*************************************************************************
1304 |*
1305 |*    Container::GetObjectPtr()
1306 |*
1307 |*    Beschreibung      Interne Methode fuer Referenz-Container
1308 |*    Ersterstellung    TH 26.01.93
1309 |*    Letzte Aenderung  TH 26.01.93
1310 |*
1311 *************************************************************************/
1312 
1313 void** Container::GetObjectPtr( sal_uIntPtr nIndex )
1314 {
1315     DBG_CHKTHIS( Container, DbgCheckContainer );
1316 
1317     // Ist Index nicht innerhalb des Containers, dann NULL zurueckgeben
1318     if ( nCount <= nIndex )
1319         return NULL;
1320     else
1321     {
1322         // Block suchen
1323         CBlock* pTemp = pFirstBlock;
1324         while ( pTemp->Count() <= nIndex )
1325         {
1326             nIndex -= pTemp->Count();
1327             pTemp   = pTemp->GetNextBlock();
1328         }
1329 
1330         // Item innerhalb des gefundenen Blocks zurueckgeben
1331         return pTemp->GetObjectPtr( (sal_uInt16)nIndex );
1332     }
1333 }
1334 
1335 /*************************************************************************
1336 |*
1337 |*    Container::GetObject()
1338 |*
1339 |*    Beschreibung      CONTNR.SDW
1340 |*    Ersterstellung    TH 17.09.91
1341 |*    Letzte Aenderung  TH 17.09.91
1342 |*
1343 *************************************************************************/
1344 
1345 void* Container::GetObject( sal_uIntPtr nIndex ) const
1346 {
1347     DBG_CHKTHIS( Container, DbgCheckContainer );
1348 
1349     // Ist Index nicht innerhalb des Containers, dann NULL zurueckgeben
1350     if ( nCount <= nIndex )
1351         return NULL;
1352     else
1353     {
1354         // Block suchen
1355         CBlock* pTemp = pFirstBlock;
1356         while ( pTemp->Count() <= nIndex )
1357         {
1358             nIndex -= pTemp->Count();
1359             pTemp   = pTemp->GetNextBlock();
1360         }
1361 
1362         // Item innerhalb des gefundenen Blocks zurueckgeben
1363         return pTemp->GetObject( (sal_uInt16)nIndex );
1364     }
1365 }
1366 
1367 /*************************************************************************
1368 |*
1369 |*    Container::GetPos()
1370 |*
1371 |*    Beschreibung      CONTNR.SDW
1372 |*    Ersterstellung    TH 17.09.91
1373 |*    Letzte Aenderung  TH 17.09.91
1374 |*
1375 *************************************************************************/
1376 
1377 sal_uIntPtr Container::GetPos( const void* p ) const
1378 {
1379     DBG_CHKTHIS( Container, DbgCheckContainer );
1380 
1381     void**  pNodes;
1382     CBlock* pTemp;
1383     sal_uIntPtr nTemp;
1384     sal_uInt16  nBlockCount;
1385     sal_uInt16  i;
1386 
1387     // Block suchen
1388     pTemp = pFirstBlock;
1389     nTemp = 0;
1390     while ( pTemp )
1391     {
1392         pNodes = pTemp->GetNodes();
1393         i = 0;
1394         nBlockCount = pTemp->Count();
1395         while ( i < nBlockCount )
1396         {
1397             if ( p == *pNodes )
1398                 return nTemp+i;
1399             pNodes++;
1400             i++;
1401         }
1402         nTemp += nBlockCount;
1403         pTemp  = pTemp->GetNextBlock();
1404     }
1405 
1406     return CONTAINER_ENTRY_NOTFOUND;
1407 }
1408 
1409 /*************************************************************************
1410 |*
1411 |*    Container::GetPos()
1412 |*
1413 |*    Beschreibung      CONTNR.SDW
1414 |*    Ersterstellung    TH 14.09.94
1415 |*    Letzte Aenderung  TH 14.09.94
1416 |*
1417 *************************************************************************/
1418 
1419 sal_uIntPtr Container::GetPos( const void* p, sal_uIntPtr nStartIndex,
1420                          sal_Bool bForward ) const
1421 {
1422     DBG_CHKTHIS( Container, DbgCheckContainer );
1423 
1424     // Ist Index nicht innerhalb des Containers, dann NOTFOUND zurueckgeben
1425     if ( nCount <= nStartIndex )
1426         return CONTAINER_ENTRY_NOTFOUND;
1427     else
1428     {
1429         void**  pNodes;
1430         sal_uInt16  nBlockCount;
1431         sal_uInt16  i;
1432 
1433         // Block suchen
1434         CBlock* pTemp = pFirstBlock;
1435         sal_uIntPtr nTemp = 0;
1436         while ( nTemp+pTemp->Count() <= nStartIndex )
1437         {
1438             nTemp += pTemp->Count();
1439             pTemp  = pTemp->GetNextBlock();
1440         }
1441 
1442         // Jetzt den Pointer suchen
1443         if ( bForward )
1444         {
1445             // Alle Bloecke durchrsuchen
1446             i = (sal_uInt16)(nStartIndex - nTemp);
1447             pNodes = pTemp->GetObjectPtr( i );
1448             do
1449             {
1450                 nBlockCount = pTemp->Count();
1451                 while ( i < nBlockCount )
1452                 {
1453                     if ( p == *pNodes )
1454                         return nTemp+i;
1455                     pNodes++;
1456                     i++;
1457                 }
1458                 nTemp += nBlockCount;
1459                 pTemp  = pTemp->GetNextBlock();
1460                 if ( pTemp )
1461                 {
1462                     i = 0;
1463                     pNodes = pTemp->GetNodes();
1464                 }
1465                 else
1466                     break;
1467             }
1468             while ( sal_True );
1469         }
1470         else
1471         {
1472             // Alle Bloecke durchrsuchen
1473             i = (sal_uInt16)(nStartIndex-nTemp)+1;
1474             pNodes = pTemp->GetObjectPtr( i-1 );
1475             do
1476             {
1477                 do
1478                 {
1479                     if ( p == *pNodes )
1480                         return nTemp+i-1;
1481                     pNodes--;
1482                     i--;
1483                 }
1484                 while ( i );
1485                 nTemp -= pTemp->Count();
1486                 pTemp  = pTemp->GetPrevBlock();
1487                 if ( pTemp )
1488                 {
1489                     i = pTemp->Count();
1490                     // Leere Bloecke in der Kette darf es nicht geben. Nur
1491                     // wenn ein Block existiert, darf dieser leer sein
1492                     pNodes = pTemp->GetObjectPtr( i-1 );
1493                 }
1494                 else
1495                     break;
1496             }
1497             while ( sal_True );
1498         }
1499     }
1500 
1501     return CONTAINER_ENTRY_NOTFOUND;
1502 }
1503 
1504 /*************************************************************************
1505 |*
1506 |*    Container::Seek()
1507 |*
1508 |*    Beschreibung      CONTNR.SDW
1509 |*    Ersterstellung    TH 17.09.91
1510 |*    Letzte Aenderung  TH 17.09.91
1511 |*
1512 *************************************************************************/
1513 
1514 void* Container::Seek( sal_uIntPtr nIndex )
1515 {
1516     DBG_CHKTHIS( Container, DbgCheckContainer );
1517 
1518     // Ist der Container leer, dann NULL zurueckgeben
1519     if ( nCount <= nIndex )
1520         return NULL;
1521     else
1522     {
1523         // Block suchen
1524         CBlock* pTemp = pFirstBlock;
1525         while ( pTemp->Count() <= nIndex )
1526         {
1527             nIndex -= pTemp->Count();
1528             pTemp   = pTemp->GetNextBlock();
1529         }
1530 
1531         // Item innerhalb des gefundenen Blocks zurueckgeben
1532         pCurBlock = pTemp;
1533         nCurIndex = (sal_uInt16)nIndex;
1534         return pCurBlock->GetObject( nCurIndex );
1535     }
1536 }
1537 
1538 /*************************************************************************
1539 |*
1540 |*    Container::First()
1541 |*
1542 |*    Beschreibung      CONTNR.SDW
1543 |*    Ersterstellung    TH 17.09.91
1544 |*    Letzte Aenderung  TH 17.09.91
1545 |*
1546 *************************************************************************/
1547 
1548 void* Container::First()
1549 {
1550     DBG_CHKTHIS( Container, DbgCheckContainer );
1551 
1552     // Ist Container leer, dann NULL zurueckgeben
1553     if ( !nCount )
1554         return NULL;
1555     else
1556     {
1557         // Block und Index setzen und ersten Pointer zurueckgeben
1558         pCurBlock = pFirstBlock;
1559         nCurIndex = 0;
1560         return pCurBlock->GetObject( nCurIndex );
1561     }
1562 }
1563 
1564 /*************************************************************************
1565 |*
1566 |*    Container::Last()
1567 |*
1568 |*    Beschreibung      CONTNR.SDW
1569 |*    Ersterstellung    TH 17.09.91
1570 |*    Letzte Aenderung  TH 17.09.91
1571 |*
1572 *************************************************************************/
1573 
1574 void* Container::Last()
1575 {
1576     DBG_CHKTHIS( Container, DbgCheckContainer );
1577 
1578     // Ist Container leer, dann NULL zurueckgeben
1579     if ( !nCount )
1580         return NULL;
1581     else
1582     {
1583         // Block und Index setzen und ersten Pointer zurueckgeben
1584         pCurBlock = pLastBlock;
1585         nCurIndex = pCurBlock->Count()-1;
1586         return pCurBlock->GetObject( nCurIndex );
1587     }
1588 }
1589 
1590 /*************************************************************************
1591 |*
1592 |*    Container::Next()
1593 |*
1594 |*    Beschreibung      CONTNR.SDW
1595 |*    Ersterstellung    TH 17.09.91
1596 |*    Letzte Aenderung  TH 17.09.91
1597 |*
1598 *************************************************************************/
1599 
1600 void* Container::Next()
1601 {
1602     DBG_CHKTHIS( Container, DbgCheckContainer );
1603 
1604     // Ist Container leer, dann NULL zurueckgeben, ansonsten preufen ob
1605     // naechste Position noch im aktuellen Block ist. Falls nicht, dann
1606     // einen Block weiterschalten (geht ohne Gefahr, da leere Bloecke
1607     // nicht vorkommen duerfen, es sein denn, es ist der einzige).
1608     if ( !nCount )
1609         return NULL;
1610     else if ( (nCurIndex+1) < pCurBlock->Count() )
1611         return pCurBlock->GetObject( ++nCurIndex );
1612     else if ( pCurBlock->GetNextBlock() )
1613     {
1614         pCurBlock = pCurBlock->GetNextBlock();
1615         nCurIndex = 0;
1616         return pCurBlock->GetObject( nCurIndex );
1617     }
1618     else
1619         return NULL;
1620 }
1621 
1622 /*************************************************************************
1623 |*
1624 |*    Container::Prev()
1625 |*
1626 |*    Beschreibung      CONTNR.SDW
1627 |*    Ersterstellung    TH 17.09.91
1628 |*    Letzte Aenderung  TH 17.09.91
1629 |*
1630 *************************************************************************/
1631 
1632 void* Container::Prev()
1633 {
1634     DBG_CHKTHIS( Container, DbgCheckContainer );
1635 
1636     // Ist Container leer, dann NULL zurueckgeben, ansonsten preufen ob
1637     // vorherige Position noch im aktuellen Block ist. Falls nicht, dann
1638     // einen Block zurueckschalten (geht ohne Gefahr, da leere Bloecke
1639     // nicht vorkommen duerfen, es sein denn, es ist der einzige).
1640     if ( !nCount )
1641         return NULL;
1642     else if ( nCurIndex )
1643         return pCurBlock->GetObject( --nCurIndex );
1644     else if ( pCurBlock->GetPrevBlock() )
1645     {
1646         pCurBlock = pCurBlock->GetPrevBlock();
1647         nCurIndex = pCurBlock->Count() - 1;
1648         return pCurBlock->GetObject( nCurIndex );
1649     }
1650     else
1651         return NULL;
1652 }
1653 
1654 /*************************************************************************
1655 |*
1656 |*    Container::operator =()
1657 |*
1658 |*    Beschreibung      CONTNR.SDW
1659 |*    Ersterstellung    TH 17.09.91
1660 |*    Letzte Aenderung  TH 17.09.91
1661 |*
1662 *************************************************************************/
1663 
1664 Container& Container::operator =( const Container& r )
1665 {
1666     DBG_CHKTHIS( Container, DbgCheckContainer );
1667 
1668     // Erst alle Bloecke loeschen
1669     CBlock* pBlock = pFirstBlock;
1670     while ( pBlock )
1671     {
1672         CBlock* pTemp = pBlock->GetNextBlock();
1673         delete pBlock;
1674         pBlock = pTemp;
1675     }
1676 
1677     // Daten kopieren
1678     ImpCopyContainer( &r );
1679     return *this;
1680 }
1681 
1682 /*************************************************************************
1683 |*
1684 |*    Container::operator ==()
1685 |*
1686 |*    Beschreibung      CONTNR.SDW
1687 |*    Ersterstellung    TH 17.09.91
1688 |*    Letzte Aenderung  TH 17.09.91
1689 |*
1690 *************************************************************************/
1691 
1692 sal_Bool Container::operator ==( const Container& r ) const
1693 {
1694     DBG_CHKTHIS( Container, DbgCheckContainer );
1695 
1696     if ( nCount != r.nCount )
1697         return sal_False;
1698 
1699     sal_uIntPtr i = 0;
1700     while ( i < nCount )
1701     {
1702         if ( GetObject( i ) != r.GetObject( i ) )
1703             return sal_False;
1704         i++;
1705     }
1706 
1707     return sal_True;
1708 }
1709