update dev300-m58
[ooovba.git] / tools / workben / hashtbl.cxx
blobc7ed8597cbe59b30d863655840da6c9ad8573014
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.5 $
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_tools.hxx"
34 #include <tlgen.hxx>
35 #include "hashtbl.hxx"
37 #include <algorithm>
39 // -------------------------------------------------------------
40 // class HashItem
42 class HashItem
44 enum ETag { TAG_EMPTY, TAG_USED, TAG_DELETED };
46 void* m_pObject;
47 ETag m_Tag;
48 String m_Key;
50 public:
51 HashItem() { m_Tag = TAG_EMPTY; m_pObject = NULL; }
53 BOOL IsDeleted() const
54 { return m_Tag == TAG_DELETED; }
56 BOOL IsEmpty() const
57 { return m_Tag == TAG_DELETED || m_Tag == TAG_EMPTY; }
59 BOOL IsFree() const
60 { return m_Tag == TAG_EMPTY; }
62 BOOL IsUsed() const
63 { return m_Tag == TAG_USED; }
65 void Delete()
66 { m_Tag = TAG_DELETED; m_Key = ""; m_pObject = NULL; }
68 String const& GetKey() const
69 { return m_Key; }
71 void* GetObject() const
72 { return m_pObject; }
74 void SetObject(String const Key, void *pObject)
75 { m_Tag = TAG_USED; m_Key = Key; m_pObject = pObject; }
78 // #define MIN(a,b) (a)<(b)?(a):(b)
79 // #define MAX(a,b) (a)>(b)?(a):(b)
81 // -------------------------------------------------------------
82 // class HashTable
85 /*static*/ double HashTable::m_defMaxLoadFactor = 0.8;
86 /*static*/ double HashTable::m_defDefGrowFactor = 2.0;
88 HashTable::HashTable(ULONG lSize, BOOL bOwner, double dMaxLoadFactor, double dGrowFactor)
90 m_lSize = lSize;
91 m_bOwner = bOwner;
92 m_lElem = 0;
93 m_dMaxLoadFactor = std::max(0.5,std::min(1.0,dMaxLoadFactor)); // 0.5 ... 1.0
94 m_dGrowFactor = std::max(1.3,(5.0,dGrowFactor)); // 1.3 ... 5.0
95 m_pData = new HashItem [lSize];
97 // Statistik
98 #ifdef DBG_UTIL
99 m_aStatistic.m_lSingleHash = 0;
100 m_aStatistic.m_lDoubleHash = 0;
101 m_aStatistic.m_lProbe = 0;
102 #endif
105 HashTable::~HashTable()
107 // Wenn die HashTable der Owner der Objecte ist,
108 // müssen die Destruktoren separat gerufen werden.
109 // Dies geschieht über die virtuelle Methode OnDeleteObject()
111 // Problem: Virtuelle Funktionen sind im Destructor nicht virtuell!!
112 // Der Code muß deshalb ins Macro
115 if (m_bOwner)
117 for (ULONG i=0; i<GetSize(); i++)
119 void *pObject = GetObjectAt(i);
121 if (pObject != NULL)
122 OnDeleteObject(pObject());
127 // Speicher für HashItems freigeben
128 delete [] m_pData;
131 void* HashTable::GetObjectAt(ULONG lPos) const
132 // Gibt Objekt zurück, wenn es eines gibt, sonst NULL;
134 DBG_ASSERT(lPos<m_lSize, "HashTable::GetObjectAt()");
136 HashItem *pItem = &m_pData[lPos];
138 return pItem->IsUsed() ? pItem->GetObject() : NULL;
141 void HashTable::OnDeleteObject(void*)
143 DBG_ERROR("HashTable::OnDeleteObject(void*) nicht überladen");
146 ULONG HashTable::Hash(String const& Key) const
149 ULONG lHash = 0;
150 ULONG i,n;
152 for (i=0,n=Key.Len(); i<n; i++)
154 lHash *= 256L;
155 lHash += (ULONG)(USHORT)Key.GetStr()[i];
156 lHash %= m_lSize;
158 return lHash;
161 // Hashfunktion von P.J. Weinberger
162 // aus dem "Drachenbuch" von Aho/Sethi/Ullman
163 ULONG i,n;
164 ULONG h = 0;
165 ULONG g = 0;
167 for (i=0,n=Key.Len(); i<n; i++)
169 h = (h<<4) + (ULONG)(USHORT)Key.GetStr()[i];
170 g = h & 0xf0000000;
172 if (g != 0)
174 h = h ^ (g >> 24);
175 h = h ^ g;
179 return h % m_lSize;
182 ULONG HashTable::DHash(String const& Key, ULONG lOldHash) const
184 ULONG lHash = lOldHash;
185 ULONG i,n;
187 for (i=0,n=Key.Len(); i<n; i++)
189 lHash *= 256L;
190 lHash += (ULONG)(USHORT)Key.GetStr()[i];
191 lHash %= m_lSize;
193 return lHash;
195 /* return
197 lHash
198 + (char)Key.GetStr()[0] * 256
199 + (char)Key.GetStr()[Key.Len()-1]
202 % m_lSize;
206 ULONG HashTable::Probe(ULONG lPos) const
207 // gibt den Folgewert von lPos zurück
209 lPos++; if (lPos==m_lSize) lPos=0;
210 return lPos;
213 BOOL HashTable::IsFull() const
215 return m_lElem>=m_lSize;
218 BOOL HashTable::Insert(String const& Key, void* pObject)
219 // pre: Key ist nicht im Dictionary enthalten, sonst return FALSE
220 // Dictionary ist nicht voll, sonst return FALSE
221 // post: pObject ist unter Key im Dictionary; m_nElem wurde erhöht
223 SmartGrow();
225 if (IsFull())
227 DBG_ERROR("HashTable::Insert() is full");
228 return FALSE;
231 if (FindPos(Key) != NULL )
232 return FALSE;
234 ULONG lPos = Hash(Key);
235 HashItem *pItem = &m_pData[lPos];
237 // first hashing
239 if (pItem->IsEmpty())
241 pItem->SetObject(Key, pObject);
242 m_lElem++;
244 #ifdef DBG_UTIL
245 m_aStatistic.m_lSingleHash++;
246 #endif
248 return TRUE;
251 // double hashing
253 lPos = DHash(Key,lPos);
254 pItem = &m_pData[lPos];
256 if (pItem->IsEmpty())
258 pItem->SetObject(Key, pObject);
259 m_lElem++;
261 #ifdef DBG_UTIL
262 m_aStatistic.m_lDoubleHash++;
263 #endif
265 return TRUE;
268 // linear probing
272 #ifdef DBG_UTIL
273 m_aStatistic.m_lProbe++;
274 #endif
276 lPos = Probe(lPos);
277 pItem = &m_pData[lPos];
279 while(!pItem->IsEmpty());
281 pItem->SetObject(Key, pObject);
282 m_lElem++;
283 return TRUE;
286 HashItem* HashTable::FindPos(String const& Key) const
287 // sucht den Key; gibt Refrenz auf den Eintrag (gefunden)
288 // oder NULL (nicht gefunden) zurück
290 // pre: -
291 // post: -
293 // first hashing
295 ULONG lPos = Hash(Key);
296 HashItem *pItem = &m_pData[lPos];
298 if (pItem->IsUsed()
299 && pItem->GetKey() == Key)
301 return pItem;
304 // double hashing
306 if (pItem->IsDeleted() || pItem->IsUsed())
308 lPos = DHash(Key,lPos);
309 pItem = &m_pData[lPos];
311 if (pItem->IsUsed()
312 && pItem->GetKey() == Key)
314 return pItem;
317 // linear probing
319 if (pItem->IsDeleted() || pItem->IsUsed())
321 ULONG n = 0;
322 BOOL bFound = FALSE;
323 BOOL bEnd = FALSE;
327 n++;
328 lPos = Probe(lPos);
329 pItem = &m_pData[lPos];
331 bFound = pItem->IsUsed()
332 && pItem->GetKey() == Key;
334 bEnd = !(n<m_lSize || pItem->IsFree());
336 while(!bFound && !bEnd);
338 return bFound ? pItem : NULL;
342 // nicht gefunden
344 return NULL;
347 void* HashTable::Find(String const& Key) const
348 // Gibt Verweis des Objektes zurück, das unter Key abgespeichert ist,
349 // oder NULL wenn nicht vorhanden.
351 // pre: -
352 // post: -
354 HashItem *pItem = FindPos(Key);
356 if (pItem != NULL
357 && pItem->GetKey() == Key)
358 return pItem->GetObject();
359 else
360 return NULL;
363 void* HashTable::Delete(String const& Key)
364 // Löscht Objekt, das unter Key abgespeichert ist und gibt Verweis
365 // darauf zurück.
366 // Gibt NULL zurück, wenn Key nicht vorhanden ist.
368 // pre: -
369 // post: Objekt ist nicht mehr enthalten; m_lElem dekrementiert
370 // Wenn die HashTable der Owner ist, wurde das Object gelöscht
372 HashItem *pItem = FindPos(Key);
374 if (pItem != NULL
375 && pItem->GetKey() == Key)
377 void* pObject = pItem->GetObject();
379 if (m_bOwner)
380 OnDeleteObject(pObject);
382 pItem->Delete();
383 m_lElem--;
384 return pObject;
386 else
388 return NULL;
392 double HashTable::CalcLoadFactor() const
393 // prozentuale Belegung der Hashtabelle berechnen
395 return double(m_lElem) / double(m_lSize);
398 void HashTable::SmartGrow()
399 // Achtung: da die Objekte umkopiert werden, darf die OnDeleteObject-Methode
400 // nicht gerufen werden
402 double dLoadFactor = CalcLoadFactor();
404 if (dLoadFactor <= m_dMaxLoadFactor)
405 return; // nothing to grow
407 ULONG lOldSize = m_lSize; // alte Daten sichern
408 HashItem* pOldData = m_pData;
410 m_lSize = ULONG (m_dGrowFactor * m_lSize); // neue Größe
411 m_pData = new HashItem[m_lSize]; // neue Daten holen
413 // kein Speicher:
414 // Zustand "Tabelle voll" wird in Insert abgefangen
416 if (m_pData == NULL)
418 m_lSize = lOldSize;
419 m_pData = pOldData;
420 return;
423 m_lElem = 0; // noch keine neuen Daten
425 // Umkopieren der Daten
427 for (ULONG i=0; i<lOldSize; i++)
429 HashItem *pItem = &pOldData[i];
431 if (pItem->IsUsed())
432 Insert(pItem->GetKey(),pItem->GetObject());
435 delete [] pOldData;
438 // Iterator ---------------------------------------------------------
441 HashTableIterator::HashTableIterator(HashTable const& aTable)
442 : m_aTable(aTable)
444 m_lAt = 0;
447 void* HashTableIterator::GetFirst()
449 m_lAt = 0;
450 return FindValidObject(TRUE /* forward */);
453 void* HashTableIterator::GetLast()
455 m_lAt = m_aTable.GetSize() -1;
456 return FindValidObject(FALSE /* backward */);
459 void* HashTableIterator::GetNext()
461 if (m_lAt+1 >= m_aTable.GetSize())
462 return NULL;
464 m_lAt++;
465 return FindValidObject(TRUE /* forward */);
468 void* HashTableIterator::GetPrev()
470 if (m_lAt <= 0)
471 return NULL;
473 m_lAt--;
474 return FindValidObject(FALSE /* backward */);
477 void* HashTableIterator::FindValidObject(BOOL bForward)
478 // Sucht nach einem vorhandenen Objekt ab der aktuellen
479 // Position.
481 // pre: ab inkl. m_lAt soll die Suche beginnen
482 // post: if not found then
483 // if bForward == TRUE then
484 // m_lAt == m_aTable.GetSize() -1
485 // else
486 // m_lAt == 0
487 // else
488 // m_lAt ist die gefundene Position
490 void *pObject = m_aTable.GetObjectAt(m_lAt);
492 if (pObject != NULL)
493 return pObject;
495 while (pObject == NULL
496 && (bForward ? ((m_lAt+1) < m_aTable.GetSize())
497 : m_lAt > 0))
499 if (bForward)
500 m_lAt++;
501 else
502 m_lAt--;
504 pObject = m_aTable.GetObjectAt(m_lAt);
507 #ifdef DBG_UTIL
509 if (pObject == NULL)
511 DBG_ASSERT(bForward ? m_lAt == m_aTable.GetSize() -1 : m_lAt == 0,
512 "HashTableIterator::FindValidObject()");
515 #endif
517 return pObject;