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