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