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_soltools.hxx"
34 #include "hashtbl.hxx"
37 // -------------------------------------------------------------
42 enum ETag
{ TAG_EMPTY
, TAG_USED
, TAG_DELETED
};
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
; }
56 { return m_Tag
== TAG_DELETED
|| m_Tag
== TAG_EMPTY
; }
59 { return m_Tag
== TAG_EMPTY
; }
62 { return m_Tag
== TAG_USED
; }
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
70 void* GetObject() const
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 // -------------------------------------------------------------
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
)
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
109 for (ULONG i=0; i<GetSize(); i++)
111 void *pObject = GetObjectAt(i);
114 OnDeleteObject(pObject());
119 // Speicher für HashItems freigeben
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
143 for (i
=0,n
=strlen( Key
); i
<n
; i
++)
145 h
= (h
<<4) + (unsigned long)(unsigned short)Key
[i
];
158 unsigned long HashTable::DHash(const char* Key
, unsigned long lOldHash
) const
160 unsigned long lHash
= lOldHash
;
163 for (i
=0,n
=strlen( Key
); i
<n
; i
++)
166 lHash
+= (unsigned long)(unsigned short)Key
[i
];
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;
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
196 if (FindPos(Key
) != NULL
)
199 unsigned long lPos
= Hash(Key
);
200 HashItem
*pItem
= &m_pData
[lPos
];
204 if (pItem
->IsEmpty())
206 pItem
->SetObject(Key
, pObject
);
214 lPos
= DHash(Key
,lPos
);
215 pItem
= &m_pData
[lPos
];
217 if (pItem
->IsEmpty())
219 pItem
->SetObject(Key
, pObject
);
230 pItem
= &m_pData
[lPos
];
232 while(!pItem
->IsEmpty());
234 pItem
->SetObject(Key
, pObject
);
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
248 unsigned long lPos
= Hash(Key
);
249 HashItem
*pItem
= &m_pData
[lPos
];
252 && !(strcmp( pItem
->GetKey(), Key
)))
259 if (pItem
->IsDeleted() || pItem
->IsUsed())
261 lPos
= DHash(Key
,lPos
);
262 pItem
= &m_pData
[lPos
];
265 && (!strcmp( pItem
->GetKey(), Key
)))
272 if (pItem
->IsDeleted() || pItem
->IsUsed())
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
;
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.
307 HashItem
*pItem
= FindPos(Key
);
310 && ( !strcmp( pItem
->GetKey(), Key
)))
311 return pItem
->GetObject();
316 void* HashTable::Delete( const char * Key
)
317 // Löscht Objekt, das unter Key abgespeichert ist und gibt Verweis
319 // Gibt NULL zurück, wenn Key nicht vorhanden ist.
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
);
328 && ( !strcmp( pItem
->GetKey(), Key
)))
330 void* pObject
= pItem
->GetObject();
333 OnDeleteObject(pObject
);
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
367 // Zustand "Tabelle voll" wird in Insert abgefangen
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
];
385 Insert(pItem
->GetKey(),pItem
->GetObject());
391 // Iterator ---------------------------------------------------------
394 HashTableIterator::HashTableIterator(HashTable
const& aTable
)
400 void* HashTableIterator::GetFirst()
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())
418 return FindValidObject(true /* forward */);
421 void* HashTableIterator::GetPrev()
427 return FindValidObject(false /* backward */);
430 void* HashTableIterator::FindValidObject(bool bForward
)
431 // Sucht nach einem vorhandenen Objekt ab der aktuellen
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
441 // m_lAt ist die gefundene Position
443 void *pObject
= m_aTable
.GetObjectAt(m_lAt
);
448 while (pObject
== NULL
449 && (bForward
? ((m_lAt
+1) < m_aTable
.GetSize())
457 pObject
= m_aTable
.GetObjectAt(m_lAt
);