update dev300-m58
[ooovba.git] / soltools / ldump / hashtbl.cxx
blob875c633c2d4f67dd58277b4982cc979ea6d8e41c
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: hashtbl.cxx,v $
10 * $Revision: 1.7 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_soltools.hxx"
34 #include "hashtbl.hxx"
35 #include <string.h>
37 // -------------------------------------------------------------
38 // class HashItem
40 class HashItem
42 enum ETag { TAG_EMPTY, TAG_USED, TAG_DELETED };
44 void* m_pObject;
45 ETag m_Tag;
46 char* m_Key;
48 public:
49 HashItem() { m_Tag = TAG_EMPTY; m_Key = NULL; m_pObject = NULL; }
50 ~HashItem() { delete [] m_Key; }
52 bool IsDeleted() const
53 { return m_Tag == TAG_DELETED; }
55 bool IsEmpty() const
56 { return m_Tag == TAG_DELETED || m_Tag == TAG_EMPTY; }
58 bool IsFree() const
59 { return m_Tag == TAG_EMPTY; }
61 bool IsUsed() const
62 { return m_Tag == TAG_USED; }
64 void Delete()
65 { m_Tag = TAG_DELETED; delete [] m_Key; m_Key = new char[ 1 ]; m_Key[ 0 ] = 0; m_pObject = NULL; }
67 const char *GetKey() const
68 { return m_Key; }
70 void* GetObject() const
71 { return m_pObject; }
73 void SetObject(const char * Key, void *pObject)
74 { m_Tag = TAG_USED; delete [] m_Key; m_Key = new char[ strlen( Key ) + 1 ]; strcpy( m_Key, Key ); m_pObject = pObject; }
77 #define MIN(a,b) (a)<(b)?(a):(b)
78 #define MAX(a,b) (a)>(b)?(a):(b)
80 // -------------------------------------------------------------
81 // class HashTable
84 /*static*/ double HashTable::m_defMaxLoadFactor = 0.5;
85 /*static*/ double HashTable::m_defDefGrowFactor = 2.0;
87 HashTable::HashTable(unsigned long lSize, bool bOwner, double dMaxLoadFactor, double dGrowFactor)
89 m_lSize = lSize;
90 m_bOwner = bOwner;
91 m_lElem = 0;
92 m_dMaxLoadFactor = MAX(0.5,MIN(1.0,dMaxLoadFactor)); // 0.5 ... 1.0
93 m_dGrowFactor = MAX(2.0,MIN(5.0,dGrowFactor)); // 1.3 ... 5.0
94 m_pData = new HashItem [lSize];
97 HashTable::~HashTable()
99 // Wenn die HashTable der Owner der Objecte ist,
100 // müssen die Destruktoren separat gerufen werden.
101 // Dies geschieht über die virtuelle Methode OnDeleteObject()
103 // Problem: Virtuelle Funktionen sind im Destructor nicht virtuell!!
104 // Der Code muß deshalb ins Macro
107 if (m_bOwner)
109 for (ULONG i=0; i<GetSize(); i++)
111 void *pObject = GetObjectAt(i);
113 if (pObject != NULL)
114 OnDeleteObject(pObject());
119 // Speicher für HashItems freigeben
120 delete [] m_pData;
123 void* HashTable::GetObjectAt(unsigned long lPos) const
124 // Gibt Objekt zurück, wenn es eines gibt, sonst NULL;
126 HashItem *pItem = &m_pData[lPos];
128 return pItem->IsUsed() ? pItem->GetObject() : NULL;
131 void HashTable::OnDeleteObject(void*)
135 unsigned long HashTable::Hash(const char *Key) const
137 // Hashfunktion von P.J. Weinberger
138 // aus dem "Drachenbuch" von Aho/Sethi/Ullman
139 unsigned long i,n;
140 unsigned long h = 0;
141 unsigned long g = 0;
143 for (i=0,n=strlen( Key ); i<n; i++)
145 h = (h<<4) + (unsigned long)(unsigned short)Key[i];
146 g = h & 0xf0000000;
148 if (g != 0)
150 h = h ^ (g >> 24);
151 h = h ^ g;
155 return h % m_lSize;
158 unsigned long HashTable::DHash(const char* Key, unsigned long lOldHash) const
160 unsigned long lHash = lOldHash;
161 unsigned long i,n;
163 for (i=0,n=strlen( Key ); i<n; i++)
165 lHash *= 256L;
166 lHash += (unsigned long)(unsigned short)Key[i];
167 lHash %= m_lSize;
169 return lHash;
172 unsigned long HashTable::Probe(unsigned long lPos) const
173 // gibt den Folgewert von lPos zurück
175 lPos++; if (lPos==m_lSize) lPos=0;
176 return lPos;
179 bool HashTable::IsFull() const
181 return m_lElem>=m_lSize;
184 bool HashTable::Insert(const char * Key, void* pObject)
185 // pre: Key ist nicht im Dictionary enthalten, sonst return FALSE
186 // Dictionary ist nicht voll, sonst return FALSE
187 // post: pObject ist unter Key im Dictionary; m_nElem wurde erhöht
189 SmartGrow();
191 if (IsFull())
193 return false;
196 if (FindPos(Key) != NULL )
197 return false;
199 unsigned long lPos = Hash(Key);
200 HashItem *pItem = &m_pData[lPos];
202 // first hashing
204 if (pItem->IsEmpty())
206 pItem->SetObject(Key, pObject);
207 m_lElem++;
209 return true;
212 // double hashing
214 lPos = DHash(Key,lPos);
215 pItem = &m_pData[lPos];
217 if (pItem->IsEmpty())
219 pItem->SetObject(Key, pObject);
220 m_lElem++;
222 return true;
225 // linear probing
229 lPos = Probe(lPos);
230 pItem = &m_pData[lPos];
232 while(!pItem->IsEmpty());
234 pItem->SetObject(Key, pObject);
235 m_lElem++;
236 return true;
239 HashItem* HashTable::FindPos(const char * Key) const
240 // sucht den Key; gibt Refrenz auf den Eintrag (gefunden)
241 // oder NULL (nicht gefunden) zurück
243 // pre: -
244 // post: -
246 // first hashing
248 unsigned long lPos = Hash(Key);
249 HashItem *pItem = &m_pData[lPos];
251 if (pItem->IsUsed()
252 && !(strcmp( pItem->GetKey(), Key )))
254 return pItem;
257 // double hashing
259 if (pItem->IsDeleted() || pItem->IsUsed())
261 lPos = DHash(Key,lPos);
262 pItem = &m_pData[lPos];
264 if (pItem->IsUsed()
265 && (!strcmp( pItem->GetKey(), Key)))
267 return pItem;
270 // linear probing
272 if (pItem->IsDeleted() || pItem->IsUsed())
274 unsigned long n = 0;
275 bool bFound = false;
276 bool bEnd = false;
280 n++;
281 lPos = Probe(lPos);
282 pItem = &m_pData[lPos];
284 bFound = pItem->IsUsed()
285 && !( strcmp( pItem->GetKey(), Key ));
287 bEnd = !(n<m_lSize || pItem->IsFree());
289 while(!bFound && !bEnd);
291 return bFound ? pItem : NULL;
295 // nicht gefunden
297 return NULL;
300 void* HashTable::Find(const char *Key) const
301 // Gibt Verweis des Objektes zurück, das unter Key abgespeichert ist,
302 // oder NULL wenn nicht vorhanden.
304 // pre: -
305 // post: -
307 HashItem *pItem = FindPos(Key);
309 if (pItem != NULL
310 && ( !strcmp( pItem->GetKey(), Key )))
311 return pItem->GetObject();
312 else
313 return NULL;
316 void* HashTable::Delete( const char * Key)
317 // Löscht Objekt, das unter Key abgespeichert ist und gibt Verweis
318 // darauf zurück.
319 // Gibt NULL zurück, wenn Key nicht vorhanden ist.
321 // pre: -
322 // post: Objekt ist nicht mehr enthalten; m_lElem dekrementiert
323 // Wenn die HashTable der Owner ist, wurde das Object gelöscht
325 HashItem *pItem = FindPos(Key);
327 if (pItem != NULL
328 && ( !strcmp( pItem->GetKey(), Key )))
330 void* pObject = pItem->GetObject();
332 if (m_bOwner)
333 OnDeleteObject(pObject);
335 pItem->Delete();
336 m_lElem--;
337 return pObject;
339 else
341 return NULL;
345 double HashTable::CalcLoadFactor() const
346 // prozentuale Belegung der Hashtabelle berechnen
348 return double(m_lElem) / double(m_lSize);
351 void HashTable::SmartGrow()
352 // Achtung: da die Objekte umkopiert werden, darf die OnDeleteObject-Methode
353 // nicht gerufen werden
355 double dLoadFactor = CalcLoadFactor();
357 if (dLoadFactor <= m_dMaxLoadFactor)
358 return; // nothing to grow
360 unsigned long lOldSize = m_lSize; // alte Daten sichern
361 HashItem* pOldData = m_pData;
363 m_lSize = (unsigned long) (m_dGrowFactor * m_lSize); // neue Größe
364 m_pData = new HashItem[m_lSize]; // neue Daten holen
366 // kein Speicher:
367 // Zustand "Tabelle voll" wird in Insert abgefangen
369 if (m_pData == NULL)
371 m_lSize = lOldSize;
372 m_pData = pOldData;
373 return;
376 m_lElem = 0; // noch keine neuen Daten
378 // Umkopieren der Daten
380 for (unsigned long i=0; i<lOldSize; i++)
382 HashItem *pItem = &pOldData[i];
384 if (pItem->IsUsed())
385 Insert(pItem->GetKey(),pItem->GetObject());
388 delete [] pOldData;
391 // Iterator ---------------------------------------------------------
394 HashTableIterator::HashTableIterator(HashTable const& aTable)
395 : m_aTable(aTable)
397 m_lAt = 0;
400 void* HashTableIterator::GetFirst()
402 m_lAt = 0;
403 return FindValidObject(true /* forward */);
406 void* HashTableIterator::GetLast()
408 m_lAt = m_aTable.GetSize() -1;
409 return FindValidObject(false /* backward */);
412 void* HashTableIterator::GetNext()
414 if (m_lAt+1 >= m_aTable.GetSize())
415 return NULL;
417 m_lAt++;
418 return FindValidObject(true /* forward */);
421 void* HashTableIterator::GetPrev()
423 if (m_lAt <= 0)
424 return NULL;
426 m_lAt--;
427 return FindValidObject(false /* backward */);
430 void* HashTableIterator::FindValidObject(bool bForward)
431 // Sucht nach einem vorhandenen Objekt ab der aktuellen
432 // Position.
434 // pre: ab inkl. m_lAt soll die Suche beginnen
435 // post: if not found then
436 // if bForward == TRUE then
437 // m_lAt == m_aTable.GetSize() -1
438 // else
439 // m_lAt == 0
440 // else
441 // m_lAt ist die gefundene Position
443 void *pObject = m_aTable.GetObjectAt(m_lAt);
445 if (pObject != NULL)
446 return pObject;
448 while (pObject == NULL
449 && (bForward ? ((m_lAt+1) < m_aTable.GetSize())
450 : m_lAt > 0))
452 if (bForward)
453 m_lAt++;
454 else
455 m_lAt--;
457 pObject = m_aTable.GetObjectAt(m_lAt);
460 return pObject;