1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: hashtbl.cxx,v $
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"
35 #include "hashtbl.hxx"
39 // -------------------------------------------------------------
44 enum ETag
{ TAG_EMPTY
, TAG_USED
, TAG_DELETED
};
51 HashItem() { m_Tag
= TAG_EMPTY
; m_pObject
= NULL
; }
53 BOOL
IsDeleted() const
54 { return m_Tag
== TAG_DELETED
; }
57 { return m_Tag
== TAG_DELETED
|| m_Tag
== TAG_EMPTY
; }
60 { return m_Tag
== TAG_EMPTY
; }
63 { return m_Tag
== TAG_USED
; }
66 { m_Tag
= TAG_DELETED
; m_Key
= ""; m_pObject
= NULL
; }
68 String
const& GetKey() const
71 void* GetObject() const
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 // -------------------------------------------------------------
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
)
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
];
99 m_aStatistic
.m_lSingleHash
= 0;
100 m_aStatistic
.m_lDoubleHash
= 0;
101 m_aStatistic
.m_lProbe
= 0;
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
117 for (ULONG i=0; i<GetSize(); i++)
119 void *pObject = GetObjectAt(i);
122 OnDeleteObject(pObject());
127 // Speicher für HashItems freigeben
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
152 for (i=0,n=Key.Len(); i<n; i++)
155 lHash += (ULONG)(USHORT)Key.GetStr()[i];
161 // Hashfunktion von P.J. Weinberger
162 // aus dem "Drachenbuch" von Aho/Sethi/Ullman
167 for (i
=0,n
=Key
.Len(); i
<n
; i
++)
169 h
= (h
<<4) + (ULONG
)(USHORT
)Key
.GetStr()[i
];
182 ULONG
HashTable::DHash(String
const& Key
, ULONG lOldHash
) const
184 ULONG lHash
= lOldHash
;
187 for (i
=0,n
=Key
.Len(); i
<n
; i
++)
190 lHash
+= (ULONG
)(USHORT
)Key
.GetStr()[i
];
198 + (char)Key.GetStr()[0] * 256
199 + (char)Key.GetStr()[Key.Len()-1]
206 ULONG
HashTable::Probe(ULONG lPos
) const
207 // gibt den Folgewert von lPos zurück
209 lPos
++; if (lPos
==m_lSize
) lPos
=0;
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
227 DBG_ERROR("HashTable::Insert() is full");
231 if (FindPos(Key
) != NULL
)
234 ULONG lPos
= Hash(Key
);
235 HashItem
*pItem
= &m_pData
[lPos
];
239 if (pItem
->IsEmpty())
241 pItem
->SetObject(Key
, pObject
);
245 m_aStatistic
.m_lSingleHash
++;
253 lPos
= DHash(Key
,lPos
);
254 pItem
= &m_pData
[lPos
];
256 if (pItem
->IsEmpty())
258 pItem
->SetObject(Key
, pObject
);
262 m_aStatistic
.m_lDoubleHash
++;
273 m_aStatistic
.m_lProbe
++;
277 pItem
= &m_pData
[lPos
];
279 while(!pItem
->IsEmpty());
281 pItem
->SetObject(Key
, pObject
);
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
295 ULONG lPos
= Hash(Key
);
296 HashItem
*pItem
= &m_pData
[lPos
];
299 && pItem
->GetKey() == Key
)
306 if (pItem
->IsDeleted() || pItem
->IsUsed())
308 lPos
= DHash(Key
,lPos
);
309 pItem
= &m_pData
[lPos
];
312 && pItem
->GetKey() == Key
)
319 if (pItem
->IsDeleted() || pItem
->IsUsed())
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
;
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.
354 HashItem
*pItem
= FindPos(Key
);
357 && pItem
->GetKey() == Key
)
358 return pItem
->GetObject();
363 void* HashTable::Delete(String
const& Key
)
364 // Löscht Objekt, das unter Key abgespeichert ist und gibt Verweis
366 // Gibt NULL zurück, wenn Key nicht vorhanden ist.
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
);
375 && pItem
->GetKey() == Key
)
377 void* pObject
= pItem
->GetObject();
380 OnDeleteObject(pObject
);
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
414 // Zustand "Tabelle voll" wird in Insert abgefangen
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
];
432 Insert(pItem
->GetKey(),pItem
->GetObject());
438 // Iterator ---------------------------------------------------------
441 HashTableIterator::HashTableIterator(HashTable
const& aTable
)
447 void* HashTableIterator::GetFirst()
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())
465 return FindValidObject(TRUE
/* forward */);
468 void* HashTableIterator::GetPrev()
474 return FindValidObject(FALSE
/* backward */);
477 void* HashTableIterator::FindValidObject(BOOL bForward
)
478 // Sucht nach einem vorhandenen Objekt ab der aktuellen
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
488 // m_lAt ist die gefundene Position
490 void *pObject
= m_aTable
.GetObjectAt(m_lAt
);
495 while (pObject
== NULL
496 && (bForward
? ((m_lAt
+1) < m_aTable
.GetSize())
504 pObject
= m_aTable
.GetObjectAt(m_lAt
);
511 DBG_ASSERT(bForward
? m_lAt
== m_aTable
.GetSize() -1 : m_lAt
== 0,
512 "HashTableIterator::FindValidObject()");