6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
8 Permission is hereby granted, free of charge, to any person obtaining a copy of
9 this software and associated documentation files (the "Software"), to deal in
10 the Software without restriction, including without limitation the rights to
11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12 of the Software, and to permit persons to whom the Software is furnished to do
13 so, subject to the following conditions:
15 The above copyright notice and this permission notice applies to all licensees
16 and shall be included in all copies or substantial portions of the Software.
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 Except as contained in this notice, the name of Be Incorporated shall not be
26 used in advertising or otherwise to promote the sale, use or other dealings in
27 this Software without prior written authorization from Be Incorporated.
29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
30 of Be Incorporated in the United States and other countries. Other brand product
31 names are registered trademarks or trademarks of their respective holders.
36 // * removed need for exceptions
38 // * implemented rehashing
39 // * added RemoveAll()
41 // * shrinking of element vectors
43 // Hash table with open addresssing
45 #ifndef __OPEN_HASH_TABLE__
46 #define __OPEN_HASH_TABLE__
51 // don't include <Debug.h>
52 #ifndef _OPEN_HASH_TABLE_ASSERT
53 # define _OPEN_HASH_TABLE_ASSERT(E) (void)0
55 #ifndef _OPEN_HASH_TABLE_TRESPASS
56 # define _OPEN_HASH_TABLE_TRESPASS() (void)0
61 template <class Element
>
63 // element vector for OpenHashTable needs to implement this
66 Element
&At(int32 index
);
68 int32
IndexOf(const Element
&) const;
69 void Remove(int32 index
);
72 class OpenHashElement
{
75 bool operator==(const OpenHashElement
&) const;
76 void Adopt(OpenHashElement
&);
77 // low overhead copy, original element is in undefined state
78 // after call (calls Adopt on BString members, etc.)
82 const uint32 kPrimes
[] = {
83 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139,
84 524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393, 67108859,
85 134217689, 268435399, 536870909, 1073741789, 2147483647, 0
88 template <class Element
, class ElementVec
= ElementVector
<Element
> >
91 OpenHashTable(int32 minSize
, ElementVec
*elementVector
= 0,
92 float maxLoadFactor
= 0.8);
93 // it is up to the subclass of OpenHashTable to supply
97 bool InitCheck() const;
99 void SetElementVector(ElementVec
*elementVector
);
101 Element
*FindFirst(uint32 elementHash
) const;
102 Element
*Add(uint32 elementHash
);
104 void Remove(Element
*element
, bool dontRehash
= false);
107 // when calling Add, any outstanding element pointer may become
108 // invalid; to deal with this, get the element index and restore
110 int32
ElementIndex(const Element
*) const;
111 Element
*ElementAt(int32 index
) const;
113 int32
ArraySize() const;
114 int32
VectorSize() const;
115 int32
CountElements() const;
118 static int32
OptimalSize(int32 minSize
);
121 bool _RehashIfNeeded();
128 ElementVec
*fElementVector
;
129 float fMaxLoadFactor
;
132 template <class Element
>
133 class OpenHashElementArray
: public ElementVector
<Element
> {
134 // this is a straightforward implementation of an element vector
135 // deleting is handled by linking deleted elements into a free list
136 // the vector never shrinks
138 OpenHashElementArray(int32 initialSize
);
139 ~OpenHashElementArray();
141 bool InitCheck() const;
143 Element
&At(int32 index
);
144 const Element
&At(int32 index
) const;
145 Element
*Add(const Element
&);
147 void Remove(int32 index
);
148 int32
IndexOf(const Element
&) const;
159 //-----------------------------------
161 template<class Element
, class ElementVec
>
162 OpenHashTable
<Element
, ElementVec
>::OpenHashTable(int32 minSize
,
163 ElementVec
*elementVector
, float maxLoadFactor
)
164 : fArraySize(OptimalSize(minSize
)),
165 fInitialSize(fArraySize
),
167 fElementVector(elementVector
),
168 fMaxLoadFactor(maxLoadFactor
)
170 // sanity check the maximal load factor
171 if (fMaxLoadFactor
< 0.5)
172 fMaxLoadFactor
= 0.5;
173 // allocate and init the array
174 fHashArray
= (int32
*)calloc(fArraySize
, sizeof(int32
));
176 for (int32 index
= 0; index
< fArraySize
; index
++)
177 fHashArray
[index
] = -1;
181 template<class Element
, class ElementVec
>
182 OpenHashTable
<Element
, ElementVec
>::~OpenHashTable()
188 template<class Element
, class ElementVec
>
190 OpenHashTable
<Element
, ElementVec
>::InitCheck() const
192 return (fHashArray
&& fElementVector
);
195 template<class Element
, class ElementVec
>
197 OpenHashTable
<Element
, ElementVec
>::OptimalSize(int32 minSize
)
199 for (int32 index
= 0; ; index
++)
200 if (!kPrimes
[index
] || kPrimes
[index
] >= (uint32
)minSize
)
201 return (int32
)kPrimes
[index
];
206 template<class Element
, class ElementVec
>
208 OpenHashTable
<Element
, ElementVec
>::FindFirst(uint32 hash
) const
210 _OPEN_HASH_TABLE_ASSERT(fElementVector
);
212 if (fHashArray
[hash
] < 0)
215 return &fElementVector
->At(fHashArray
[hash
]);
218 template<class Element
, class ElementVec
>
220 OpenHashTable
<Element
, ElementVec
>::ElementIndex(const Element
*element
) const
222 return fElementVector
->IndexOf(*element
);
225 template<class Element
, class ElementVec
>
227 OpenHashTable
<Element
, ElementVec
>::ElementAt(int32 index
) const
229 return &fElementVector
->At(index
);
232 template<class Element
, class ElementVec
>
234 OpenHashTable
<Element
, ElementVec
>::ArraySize() const
239 template<class Element
, class ElementVec
>
241 OpenHashTable
<Element
, ElementVec
>::VectorSize() const
243 return fElementVector
->Size();
246 template<class Element
, class ElementVec
>
248 OpenHashTable
<Element
, ElementVec
>::CountElements() const
250 return fElementCount
;
254 template<class Element
, class ElementVec
>
256 OpenHashTable
<Element
, ElementVec
>::Add(uint32 hash
)
258 _OPEN_HASH_TABLE_ASSERT(fElementVector
);
261 Element
*result
= fElementVector
->Add();
263 result
->fNext
= fHashArray
[hash
];
264 fHashArray
[hash
] = fElementVector
->IndexOf(*result
);
270 template<class Element
, class ElementVec
>
272 OpenHashTable
<Element
, ElementVec
>::Remove(Element
*element
, bool dontRehash
)
276 uint32 hash
= element
->Hash() % fArraySize
;
277 int32 next
= fHashArray
[hash
];
278 _OPEN_HASH_TABLE_ASSERT(next
>= 0);
280 if (&fElementVector
->At(next
) == element
) {
281 fHashArray
[hash
] = element
->fNext
;
282 fElementVector
->Remove(next
);
287 for (int32 index
= next
; index
>= 0; ) {
288 // look for an existing match in table
289 next
= fElementVector
->At(index
).fNext
;
291 _OPEN_HASH_TABLE_TRESPASS();
295 if (&fElementVector
->At(next
) == element
) {
296 fElementVector
->At(index
).fNext
= element
->fNext
;
297 fElementVector
->Remove(next
);
305 template<class Element
, class ElementVec
>
307 OpenHashTable
<Element
, ElementVec
>::RemoveAll()
309 for (int32 i
= 0; fElementCount
> 0 && i
< fArraySize
; i
++) {
310 int32 index
= fHashArray
[i
];
312 Element
* element
= &fElementVector
->At(index
);
313 int32 next
= element
->fNext
;
314 fElementVector
->Remove(index
);
323 template<class Element
, class ElementVec
>
325 OpenHashTable
<Element
, ElementVec
>::SetElementVector(ElementVec
*elementVector
)
327 fElementVector
= elementVector
;
331 template<class Element
, class ElementVec
>
333 OpenHashTable
<Element
, ElementVec
>::_RehashIfNeeded()
335 // The load factor range [fMaxLoadFactor / 3, fMaxLoadFactor] is fine,
336 // I think. After rehashing the load factor will be about
337 // fMaxLoadFactor * 2 / 3, respectively fMaxLoadFactor / 2.
338 float loadFactor
= (float)fElementCount
/ (float)fArraySize
;
339 if (loadFactor
> fMaxLoadFactor
340 || (fArraySize
> fInitialSize
&& loadFactor
< fMaxLoadFactor
/ 3)) {
347 template<class Element
, class ElementVec
>
349 OpenHashTable
<Element
, ElementVec
>::_Rehash()
352 int32 newSize
= int32(fElementCount
* 1.73 * fMaxLoadFactor
);
353 newSize
= (fInitialSize
> newSize
? fInitialSize
: newSize
);
354 if (newSize
!= fArraySize
) {
355 // allocate a new array
356 int32
*newHashArray
= (int32
*)calloc(newSize
, sizeof(int32
));
358 // init the new hash array
359 for (int32 index
= 0; index
< newSize
; index
++)
360 newHashArray
[index
] = -1;
361 // iterate through all elements and put them into the new
363 for (int i
= 0; i
< fArraySize
; i
++) {
364 int32 index
= fHashArray
[i
];
366 // insert the element in the new array
367 Element
&element
= fElementVector
->At(index
);
368 int32 next
= element
.fNext
;
369 uint32 hash
= (element
.Hash() % newSize
);
370 element
.fNext
= newHashArray
[hash
];
371 newHashArray
[hash
] = index
;
372 // next element in old list
376 // delete the old array and set the new one
378 fHashArray
= newHashArray
;
379 fArraySize
= newSize
;
387 template<class Element
>
388 OpenHashElementArray
<Element
>::OpenHashElementArray(int32 initialSize
)
389 : fSize(initialSize
),
393 fData
= (Element
*)calloc((size_t)initialSize
, sizeof(Element
));
396 template<class Element
>
397 OpenHashElementArray
<Element
>::~OpenHashElementArray()
402 template<class Element
>
404 OpenHashElementArray
<Element
>::InitCheck() const
409 template<class Element
>
411 OpenHashElementArray
<Element
>::At(int32 index
)
413 _OPEN_HASH_TABLE_ASSERT(index
< fSize
);
417 template<class Element
>
419 OpenHashElementArray
<Element
>::At(int32 index
) const
421 _OPEN_HASH_TABLE_ASSERT(index
< fSize
);
425 template<class Element
>
427 OpenHashElementArray
<Element
>::IndexOf(const Element
&element
) const
429 int32 result
= &element
- fData
;
430 if (result
< 0 || result
> fSize
)
436 template<class Element
>
438 OpenHashElementArray
<Element
>::Size() const
444 template<class Element
>
446 OpenHashElementArray
<Element
>::Add(const Element
&newElement
)
448 Element
*element
= Add();
450 element
->Adopt(newElement
);
455 const int32 kGrowChunk
= 10;
457 const int32 kGrowChunk
= 1024;
460 template<class Element
>
462 OpenHashElementArray
<Element
>::Add()
464 int32 index
= fNextFree
;
465 if (fNextDeleted
>= 0) {
466 index
= fNextDeleted
;
467 fNextDeleted
= At(index
).fNext
;
468 } else if (fNextFree
>= fSize
- 1) {
469 int32 newSize
= fSize
+ kGrowChunk
;
471 Element *newData = (Element *)calloc((size_t)newSize , sizeof(Element));
474 memcpy(newData, fData, fSize * sizeof(Element));
477 Element
*newData
= (Element
*)realloc(fData
,
478 (size_t)newSize
* sizeof(Element
));
489 new (&At(index
)) Element
;
490 // call placement new to initialize the element properly
491 _OPEN_HASH_TABLE_ASSERT(At(index
).fNext
== -1);
496 template<class Element
>
498 OpenHashElementArray
<Element
>::Remove(int32 index
)
500 // delete by chaining empty elements in a single linked
501 // list, reusing the next field
502 _OPEN_HASH_TABLE_ASSERT(index
< fSize
);
503 At(index
).~Element();
504 // call the destructor explicitly to destroy the element
506 At(index
).fNext
= fNextDeleted
;
507 fNextDeleted
= index
;
510 } // namespace BPrivate
512 using BPrivate::OpenHashTable
;
514 #endif // __OPEN_HASH_TABLE__