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