xref: /trunk/main/soltools/ldump/hashtbl.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
29*cdf0e10cSrcweir #include "precompiled_soltools.hxx"
30*cdf0e10cSrcweir 
31*cdf0e10cSrcweir #include "hashtbl.hxx"
32*cdf0e10cSrcweir #include <string.h>
33*cdf0e10cSrcweir 
34*cdf0e10cSrcweir // -------------------------------------------------------------
35*cdf0e10cSrcweir // class HashItem
36*cdf0e10cSrcweir //
37*cdf0e10cSrcweir class HashItem
38*cdf0e10cSrcweir {
39*cdf0e10cSrcweir     enum ETag { TAG_EMPTY, TAG_USED, TAG_DELETED };
40*cdf0e10cSrcweir 
41*cdf0e10cSrcweir     void*   m_pObject;
42*cdf0e10cSrcweir     ETag    m_Tag;
43*cdf0e10cSrcweir     char*   m_Key;
44*cdf0e10cSrcweir 
45*cdf0e10cSrcweir public:
46*cdf0e10cSrcweir     HashItem() { m_Tag = TAG_EMPTY; m_Key = NULL; m_pObject = NULL; }
47*cdf0e10cSrcweir     ~HashItem() { delete [] m_Key; }
48*cdf0e10cSrcweir 
49*cdf0e10cSrcweir     bool IsDeleted() const
50*cdf0e10cSrcweir     {   return m_Tag == TAG_DELETED; }
51*cdf0e10cSrcweir 
52*cdf0e10cSrcweir     bool IsEmpty() const
53*cdf0e10cSrcweir     {   return m_Tag == TAG_DELETED || m_Tag == TAG_EMPTY; }
54*cdf0e10cSrcweir 
55*cdf0e10cSrcweir     bool IsFree() const
56*cdf0e10cSrcweir     {   return m_Tag == TAG_EMPTY; }
57*cdf0e10cSrcweir 
58*cdf0e10cSrcweir     bool IsUsed() const
59*cdf0e10cSrcweir     {   return m_Tag == TAG_USED; }
60*cdf0e10cSrcweir 
61*cdf0e10cSrcweir     void Delete()
62*cdf0e10cSrcweir     { m_Tag = TAG_DELETED; delete [] m_Key; m_Key = new char[ 1 ]; m_Key[ 0 ] = 0; m_pObject = NULL; }
63*cdf0e10cSrcweir 
64*cdf0e10cSrcweir     const char *GetKey() const
65*cdf0e10cSrcweir     { return m_Key; }
66*cdf0e10cSrcweir 
67*cdf0e10cSrcweir     void* GetObject() const
68*cdf0e10cSrcweir     { return m_pObject; }
69*cdf0e10cSrcweir 
70*cdf0e10cSrcweir     void SetObject(const char * Key, void *pObject)
71*cdf0e10cSrcweir     { m_Tag = TAG_USED; delete [] m_Key; m_Key = new char[ strlen( Key ) + 1 ]; strcpy( m_Key, Key ); m_pObject = pObject; }
72*cdf0e10cSrcweir };
73*cdf0e10cSrcweir 
74*cdf0e10cSrcweir #define MIN(a,b) (a)<(b)?(a):(b)
75*cdf0e10cSrcweir #define MAX(a,b) (a)>(b)?(a):(b)
76*cdf0e10cSrcweir 
77*cdf0e10cSrcweir // -------------------------------------------------------------
78*cdf0e10cSrcweir // class HashTable
79*cdf0e10cSrcweir //
80*cdf0e10cSrcweir 
81*cdf0e10cSrcweir /*static*/ double HashTable::m_defMaxLoadFactor = 0.5;
82*cdf0e10cSrcweir /*static*/ double HashTable::m_defDefGrowFactor = 2.0;
83*cdf0e10cSrcweir 
84*cdf0e10cSrcweir HashTable::HashTable(unsigned long lSize, bool bOwner, double dMaxLoadFactor, double dGrowFactor)
85*cdf0e10cSrcweir {
86*cdf0e10cSrcweir     m_lSize          = lSize;
87*cdf0e10cSrcweir     m_bOwner         = bOwner;
88*cdf0e10cSrcweir     m_lElem          = 0;
89*cdf0e10cSrcweir     m_dMaxLoadFactor = MAX(0.5,MIN(1.0,dMaxLoadFactor));  // 0.5 ... 1.0
90*cdf0e10cSrcweir     m_dGrowFactor    = MAX(2.0,MIN(5.0,dGrowFactor));     // 1.3 ... 5.0
91*cdf0e10cSrcweir     m_pData          = new HashItem [lSize];
92*cdf0e10cSrcweir }
93*cdf0e10cSrcweir 
94*cdf0e10cSrcweir HashTable::~HashTable()
95*cdf0e10cSrcweir {
96*cdf0e10cSrcweir     // Wenn die HashTable der Owner der Objecte ist,
97*cdf0e10cSrcweir     // m�ssen die Destruktoren separat gerufen werden.
98*cdf0e10cSrcweir     // Dies geschieht �ber die virtuelle Methode OnDeleteObject()
99*cdf0e10cSrcweir     //
100*cdf0e10cSrcweir     // Problem: Virtuelle Funktionen sind im Destructor nicht virtuell!!
101*cdf0e10cSrcweir     //          Der Code mu� deshalb ins Macro
102*cdf0e10cSrcweir 
103*cdf0e10cSrcweir     /*
104*cdf0e10cSrcweir     if (m_bOwner)
105*cdf0e10cSrcweir     {
106*cdf0e10cSrcweir         for (ULONG i=0; i<GetSize(); i++)
107*cdf0e10cSrcweir         {
108*cdf0e10cSrcweir             void *pObject = GetObjectAt(i);
109*cdf0e10cSrcweir 
110*cdf0e10cSrcweir             if (pObject != NULL)
111*cdf0e10cSrcweir                 OnDeleteObject(pObject());
112*cdf0e10cSrcweir         }
113*cdf0e10cSrcweir     }
114*cdf0e10cSrcweir     */
115*cdf0e10cSrcweir 
116*cdf0e10cSrcweir     // Speicher f�r HashItems freigeben
117*cdf0e10cSrcweir     delete [] m_pData;
118*cdf0e10cSrcweir }
119*cdf0e10cSrcweir 
120*cdf0e10cSrcweir void* HashTable::GetObjectAt(unsigned long lPos) const
121*cdf0e10cSrcweir // Gibt Objekt zur�ck, wenn es eines gibt, sonst NULL;
122*cdf0e10cSrcweir {
123*cdf0e10cSrcweir     HashItem *pItem = &m_pData[lPos];
124*cdf0e10cSrcweir 
125*cdf0e10cSrcweir     return pItem->IsUsed() ? pItem->GetObject() : NULL;
126*cdf0e10cSrcweir }
127*cdf0e10cSrcweir 
128*cdf0e10cSrcweir void HashTable::OnDeleteObject(void*)
129*cdf0e10cSrcweir {
130*cdf0e10cSrcweir }
131*cdf0e10cSrcweir 
132*cdf0e10cSrcweir unsigned long HashTable::Hash(const char *Key) const
133*cdf0e10cSrcweir {
134*cdf0e10cSrcweir     // Hashfunktion von P.J. Weinberger
135*cdf0e10cSrcweir     // aus dem "Drachenbuch" von Aho/Sethi/Ullman
136*cdf0e10cSrcweir     unsigned long i,n;
137*cdf0e10cSrcweir     unsigned long h = 0;
138*cdf0e10cSrcweir     unsigned long g = 0;
139*cdf0e10cSrcweir 
140*cdf0e10cSrcweir     for (i=0,n=strlen( Key ); i<n; i++)
141*cdf0e10cSrcweir     {
142*cdf0e10cSrcweir         h = (h<<4) + (unsigned long)(unsigned short)Key[i];
143*cdf0e10cSrcweir         g = h & 0xf0000000;
144*cdf0e10cSrcweir 
145*cdf0e10cSrcweir         if (g != 0)
146*cdf0e10cSrcweir         {
147*cdf0e10cSrcweir             h = h ^ (g >> 24);
148*cdf0e10cSrcweir             h = h ^ g;
149*cdf0e10cSrcweir         }
150*cdf0e10cSrcweir     }
151*cdf0e10cSrcweir 
152*cdf0e10cSrcweir     return h % m_lSize;
153*cdf0e10cSrcweir }
154*cdf0e10cSrcweir 
155*cdf0e10cSrcweir unsigned long HashTable::DHash(const char* Key, unsigned long lOldHash) const
156*cdf0e10cSrcweir {
157*cdf0e10cSrcweir     unsigned long lHash = lOldHash;
158*cdf0e10cSrcweir     unsigned long i,n;
159*cdf0e10cSrcweir 
160*cdf0e10cSrcweir     for (i=0,n=strlen( Key ); i<n; i++)
161*cdf0e10cSrcweir     {
162*cdf0e10cSrcweir         lHash *= 256L;
163*cdf0e10cSrcweir         lHash += (unsigned long)(unsigned short)Key[i];
164*cdf0e10cSrcweir         lHash %= m_lSize;
165*cdf0e10cSrcweir     }
166*cdf0e10cSrcweir     return lHash;
167*cdf0e10cSrcweir }
168*cdf0e10cSrcweir 
169*cdf0e10cSrcweir unsigned long HashTable::Probe(unsigned long lPos) const
170*cdf0e10cSrcweir // gibt den Folgewert von lPos zur�ck
171*cdf0e10cSrcweir {
172*cdf0e10cSrcweir     lPos++; if (lPos==m_lSize) lPos=0;
173*cdf0e10cSrcweir     return lPos;
174*cdf0e10cSrcweir }
175*cdf0e10cSrcweir 
176*cdf0e10cSrcweir bool HashTable::IsFull() const
177*cdf0e10cSrcweir {
178*cdf0e10cSrcweir     return m_lElem>=m_lSize;
179*cdf0e10cSrcweir }
180*cdf0e10cSrcweir 
181*cdf0e10cSrcweir bool HashTable::Insert(const char * Key, void* pObject)
182*cdf0e10cSrcweir // pre:  Key ist nicht im Dictionary enthalten, sonst return FALSE
183*cdf0e10cSrcweir //       Dictionary ist nicht voll, sonst return FALSE
184*cdf0e10cSrcweir // post: pObject ist unter Key im Dictionary; m_nElem wurde erh�ht
185*cdf0e10cSrcweir {
186*cdf0e10cSrcweir     SmartGrow();
187*cdf0e10cSrcweir 
188*cdf0e10cSrcweir     if (IsFull())
189*cdf0e10cSrcweir     {
190*cdf0e10cSrcweir         return false;
191*cdf0e10cSrcweir     }
192*cdf0e10cSrcweir 
193*cdf0e10cSrcweir     if (FindPos(Key) != NULL )
194*cdf0e10cSrcweir         return false;
195*cdf0e10cSrcweir 
196*cdf0e10cSrcweir     unsigned long     lPos  = Hash(Key);
197*cdf0e10cSrcweir     HashItem *pItem = &m_pData[lPos];
198*cdf0e10cSrcweir 
199*cdf0e10cSrcweir     // first hashing
200*cdf0e10cSrcweir     //
201*cdf0e10cSrcweir     if (pItem->IsEmpty())
202*cdf0e10cSrcweir     {
203*cdf0e10cSrcweir         pItem->SetObject(Key, pObject);
204*cdf0e10cSrcweir         m_lElem++;
205*cdf0e10cSrcweir 
206*cdf0e10cSrcweir         return true;
207*cdf0e10cSrcweir     }
208*cdf0e10cSrcweir 
209*cdf0e10cSrcweir     // double hashing
210*cdf0e10cSrcweir     //
211*cdf0e10cSrcweir     lPos  = DHash(Key,lPos);
212*cdf0e10cSrcweir     pItem = &m_pData[lPos];
213*cdf0e10cSrcweir 
214*cdf0e10cSrcweir     if (pItem->IsEmpty())
215*cdf0e10cSrcweir     {
216*cdf0e10cSrcweir         pItem->SetObject(Key, pObject);
217*cdf0e10cSrcweir         m_lElem++;
218*cdf0e10cSrcweir 
219*cdf0e10cSrcweir         return true;
220*cdf0e10cSrcweir     }
221*cdf0e10cSrcweir 
222*cdf0e10cSrcweir     // linear probing
223*cdf0e10cSrcweir     //
224*cdf0e10cSrcweir     do
225*cdf0e10cSrcweir     {
226*cdf0e10cSrcweir         lPos  = Probe(lPos);
227*cdf0e10cSrcweir         pItem = &m_pData[lPos];
228*cdf0e10cSrcweir     }
229*cdf0e10cSrcweir     while(!pItem->IsEmpty());
230*cdf0e10cSrcweir 
231*cdf0e10cSrcweir     pItem->SetObject(Key, pObject);
232*cdf0e10cSrcweir     m_lElem++;
233*cdf0e10cSrcweir     return true;
234*cdf0e10cSrcweir }
235*cdf0e10cSrcweir 
236*cdf0e10cSrcweir HashItem* HashTable::FindPos(const char * Key) const
237*cdf0e10cSrcweir // sucht den Key; gibt Refrenz auf den Eintrag (gefunden)
238*cdf0e10cSrcweir // oder NULL (nicht gefunden) zur�ck
239*cdf0e10cSrcweir //
240*cdf0e10cSrcweir // pre:  -
241*cdf0e10cSrcweir // post: -
242*cdf0e10cSrcweir {
243*cdf0e10cSrcweir     // first hashing
244*cdf0e10cSrcweir     //
245*cdf0e10cSrcweir     unsigned long     lPos  = Hash(Key);
246*cdf0e10cSrcweir     HashItem *pItem = &m_pData[lPos];
247*cdf0e10cSrcweir 
248*cdf0e10cSrcweir     if (pItem->IsUsed()
249*cdf0e10cSrcweir     &&  !(strcmp( pItem->GetKey(), Key )))
250*cdf0e10cSrcweir     {
251*cdf0e10cSrcweir         return pItem;
252*cdf0e10cSrcweir     }
253*cdf0e10cSrcweir 
254*cdf0e10cSrcweir     // double hashing
255*cdf0e10cSrcweir     //
256*cdf0e10cSrcweir     if (pItem->IsDeleted() || pItem->IsUsed())
257*cdf0e10cSrcweir     {
258*cdf0e10cSrcweir         lPos  = DHash(Key,lPos);
259*cdf0e10cSrcweir         pItem = &m_pData[lPos];
260*cdf0e10cSrcweir 
261*cdf0e10cSrcweir         if (pItem->IsUsed()
262*cdf0e10cSrcweir         &&  (!strcmp( pItem->GetKey(), Key)))
263*cdf0e10cSrcweir         {
264*cdf0e10cSrcweir             return pItem;
265*cdf0e10cSrcweir         }
266*cdf0e10cSrcweir 
267*cdf0e10cSrcweir         // linear probing
268*cdf0e10cSrcweir         //
269*cdf0e10cSrcweir         if (pItem->IsDeleted() || pItem->IsUsed())
270*cdf0e10cSrcweir         {
271*cdf0e10cSrcweir             unsigned long n      = 0;
272*cdf0e10cSrcweir             bool  bFound = false;
273*cdf0e10cSrcweir             bool  bEnd   = false;
274*cdf0e10cSrcweir 
275*cdf0e10cSrcweir             do
276*cdf0e10cSrcweir             {
277*cdf0e10cSrcweir                 n++;
278*cdf0e10cSrcweir                 lPos   = Probe(lPos);
279*cdf0e10cSrcweir                 pItem  = &m_pData[lPos];
280*cdf0e10cSrcweir 
281*cdf0e10cSrcweir                 bFound =  pItem->IsUsed()
282*cdf0e10cSrcweir                        && !( strcmp( pItem->GetKey(), Key ));
283*cdf0e10cSrcweir 
284*cdf0e10cSrcweir                 bEnd = !(n<m_lSize || pItem->IsFree());
285*cdf0e10cSrcweir             }
286*cdf0e10cSrcweir             while(!bFound && !bEnd);
287*cdf0e10cSrcweir 
288*cdf0e10cSrcweir             return bFound ? pItem : NULL;
289*cdf0e10cSrcweir         }
290*cdf0e10cSrcweir     }
291*cdf0e10cSrcweir 
292*cdf0e10cSrcweir     // nicht gefunden
293*cdf0e10cSrcweir     //
294*cdf0e10cSrcweir     return NULL;
295*cdf0e10cSrcweir }
296*cdf0e10cSrcweir 
297*cdf0e10cSrcweir void* HashTable::Find(const char *Key) const
298*cdf0e10cSrcweir // Gibt Verweis des Objektes zur�ck, das unter Key abgespeichert ist,
299*cdf0e10cSrcweir // oder NULL wenn nicht vorhanden.
300*cdf0e10cSrcweir //
301*cdf0e10cSrcweir // pre:  -
302*cdf0e10cSrcweir // post: -
303*cdf0e10cSrcweir {
304*cdf0e10cSrcweir     HashItem *pItem = FindPos(Key);
305*cdf0e10cSrcweir 
306*cdf0e10cSrcweir     if (pItem != NULL
307*cdf0e10cSrcweir     && ( !strcmp( pItem->GetKey(), Key )))
308*cdf0e10cSrcweir         return pItem->GetObject();
309*cdf0e10cSrcweir     else
310*cdf0e10cSrcweir         return NULL;
311*cdf0e10cSrcweir }
312*cdf0e10cSrcweir 
313*cdf0e10cSrcweir void* HashTable::Delete( const char * Key)
314*cdf0e10cSrcweir // L�scht Objekt, das unter Key abgespeichert ist und gibt Verweis
315*cdf0e10cSrcweir // darauf zur�ck.
316*cdf0e10cSrcweir // Gibt NULL zur�ck, wenn Key nicht vorhanden ist.
317*cdf0e10cSrcweir //
318*cdf0e10cSrcweir // pre:  -
319*cdf0e10cSrcweir // post: Objekt ist nicht mehr enthalten; m_lElem dekrementiert
320*cdf0e10cSrcweir //       Wenn die HashTable der Owner ist, wurde das Object gel�scht
321*cdf0e10cSrcweir {
322*cdf0e10cSrcweir     HashItem *pItem = FindPos(Key);
323*cdf0e10cSrcweir 
324*cdf0e10cSrcweir     if (pItem != NULL
325*cdf0e10cSrcweir     &&  ( !strcmp( pItem->GetKey(), Key )))
326*cdf0e10cSrcweir     {
327*cdf0e10cSrcweir         void* pObject = pItem->GetObject();
328*cdf0e10cSrcweir 
329*cdf0e10cSrcweir         if (m_bOwner)
330*cdf0e10cSrcweir             OnDeleteObject(pObject);
331*cdf0e10cSrcweir 
332*cdf0e10cSrcweir         pItem->Delete();
333*cdf0e10cSrcweir         m_lElem--;
334*cdf0e10cSrcweir         return pObject;
335*cdf0e10cSrcweir     }
336*cdf0e10cSrcweir     else
337*cdf0e10cSrcweir     {
338*cdf0e10cSrcweir         return NULL;
339*cdf0e10cSrcweir     }
340*cdf0e10cSrcweir }
341*cdf0e10cSrcweir 
342*cdf0e10cSrcweir double HashTable::CalcLoadFactor() const
343*cdf0e10cSrcweir // prozentuale Belegung der Hashtabelle berechnen
344*cdf0e10cSrcweir {
345*cdf0e10cSrcweir     return double(m_lElem) / double(m_lSize);
346*cdf0e10cSrcweir }
347*cdf0e10cSrcweir 
348*cdf0e10cSrcweir void HashTable::SmartGrow()
349*cdf0e10cSrcweir // Achtung: da die Objekte umkopiert werden, darf die OnDeleteObject-Methode
350*cdf0e10cSrcweir //          nicht gerufen werden
351*cdf0e10cSrcweir {
352*cdf0e10cSrcweir     double dLoadFactor = CalcLoadFactor();
353*cdf0e10cSrcweir 
354*cdf0e10cSrcweir     if (dLoadFactor <= m_dMaxLoadFactor)
355*cdf0e10cSrcweir         return; // nothing to grow
356*cdf0e10cSrcweir 
357*cdf0e10cSrcweir     unsigned long     lOldSize = m_lSize;              // alte Daten sichern
358*cdf0e10cSrcweir     HashItem* pOldData = m_pData;
359*cdf0e10cSrcweir 
360*cdf0e10cSrcweir     m_lSize = (unsigned long) (m_dGrowFactor * m_lSize); // neue Gr��e
361*cdf0e10cSrcweir     m_pData = new HashItem[m_lSize];           // neue Daten holen
362*cdf0e10cSrcweir 
363*cdf0e10cSrcweir     // kein Speicher:
364*cdf0e10cSrcweir     // Zustand "Tabelle voll" wird in Insert abgefangen
365*cdf0e10cSrcweir     //
366*cdf0e10cSrcweir     if (m_pData == NULL)
367*cdf0e10cSrcweir     {
368*cdf0e10cSrcweir         m_lSize = lOldSize;
369*cdf0e10cSrcweir         m_pData = pOldData;
370*cdf0e10cSrcweir         return;
371*cdf0e10cSrcweir     }
372*cdf0e10cSrcweir 
373*cdf0e10cSrcweir     m_lElem = 0;                               // noch keine neuen Daten
374*cdf0e10cSrcweir 
375*cdf0e10cSrcweir     // Umkopieren der Daten
376*cdf0e10cSrcweir     //
377*cdf0e10cSrcweir     for (unsigned long i=0; i<lOldSize; i++)
378*cdf0e10cSrcweir     {
379*cdf0e10cSrcweir         HashItem *pItem = &pOldData[i];
380*cdf0e10cSrcweir 
381*cdf0e10cSrcweir         if (pItem->IsUsed())
382*cdf0e10cSrcweir             Insert(pItem->GetKey(),pItem->GetObject());
383*cdf0e10cSrcweir     }
384*cdf0e10cSrcweir 
385*cdf0e10cSrcweir     delete [] pOldData;
386*cdf0e10cSrcweir }
387*cdf0e10cSrcweir 
388*cdf0e10cSrcweir // Iterator ---------------------------------------------------------
389*cdf0e10cSrcweir //
390*cdf0e10cSrcweir 
391*cdf0e10cSrcweir HashTableIterator::HashTableIterator(HashTable const& aTable)
392*cdf0e10cSrcweir : m_aTable(aTable)
393*cdf0e10cSrcweir {
394*cdf0e10cSrcweir     m_lAt = 0;
395*cdf0e10cSrcweir }
396*cdf0e10cSrcweir 
397*cdf0e10cSrcweir void* HashTableIterator::GetFirst()
398*cdf0e10cSrcweir {
399*cdf0e10cSrcweir     m_lAt = 0;
400*cdf0e10cSrcweir     return FindValidObject(true /* forward */);
401*cdf0e10cSrcweir }
402*cdf0e10cSrcweir 
403*cdf0e10cSrcweir void* HashTableIterator::GetLast()
404*cdf0e10cSrcweir {
405*cdf0e10cSrcweir     m_lAt = m_aTable.GetSize() -1;
406*cdf0e10cSrcweir     return FindValidObject(false /* backward */);
407*cdf0e10cSrcweir }
408*cdf0e10cSrcweir 
409*cdf0e10cSrcweir void* HashTableIterator::GetNext()
410*cdf0e10cSrcweir {
411*cdf0e10cSrcweir     if (m_lAt+1 >= m_aTable.GetSize())
412*cdf0e10cSrcweir         return NULL;
413*cdf0e10cSrcweir 
414*cdf0e10cSrcweir     m_lAt++;
415*cdf0e10cSrcweir     return FindValidObject(true /* forward */);
416*cdf0e10cSrcweir }
417*cdf0e10cSrcweir 
418*cdf0e10cSrcweir void* HashTableIterator::GetPrev()
419*cdf0e10cSrcweir {
420*cdf0e10cSrcweir     if (m_lAt <= 0)
421*cdf0e10cSrcweir         return NULL;
422*cdf0e10cSrcweir 
423*cdf0e10cSrcweir     m_lAt--;
424*cdf0e10cSrcweir     return FindValidObject(false /* backward */);
425*cdf0e10cSrcweir }
426*cdf0e10cSrcweir 
427*cdf0e10cSrcweir void* HashTableIterator::FindValidObject(bool bForward)
428*cdf0e10cSrcweir // Sucht nach einem vorhandenen Objekt ab der aktuellen
429*cdf0e10cSrcweir // Position.
430*cdf0e10cSrcweir //
431*cdf0e10cSrcweir // pre:  ab inkl. m_lAt soll die Suche beginnen
432*cdf0e10cSrcweir // post: if not found then
433*cdf0e10cSrcweir //          if bForward == TRUE then
434*cdf0e10cSrcweir //              m_lAt == m_aTable.GetSize() -1
435*cdf0e10cSrcweir //          else
436*cdf0e10cSrcweir //              m_lAt == 0
437*cdf0e10cSrcweir //       else
438*cdf0e10cSrcweir //          m_lAt ist die gefundene Position
439*cdf0e10cSrcweir {
440*cdf0e10cSrcweir     void *pObject = m_aTable.GetObjectAt(m_lAt);
441*cdf0e10cSrcweir 
442*cdf0e10cSrcweir     if (pObject != NULL)
443*cdf0e10cSrcweir         return pObject;
444*cdf0e10cSrcweir 
445*cdf0e10cSrcweir     while (pObject == NULL
446*cdf0e10cSrcweir        && (bForward ? ((m_lAt+1) < m_aTable.GetSize())
447*cdf0e10cSrcweir                     :   m_lAt    > 0))
448*cdf0e10cSrcweir     {
449*cdf0e10cSrcweir         if (bForward)
450*cdf0e10cSrcweir             m_lAt++;
451*cdf0e10cSrcweir         else
452*cdf0e10cSrcweir             m_lAt--;
453*cdf0e10cSrcweir 
454*cdf0e10cSrcweir         pObject = m_aTable.GetObjectAt(m_lAt);
455*cdf0e10cSrcweir     }
456*cdf0e10cSrcweir 
457*cdf0e10cSrcweir     return pObject;
458*cdf0e10cSrcweir }
459