VirtualBox

source: vbox/trunk/src/VBox/Additions/haiku/SharedFolders/OpenHashTable.h@ 43363

最後變更 在這個檔案從43363是 43363,由 vboxsync 提交於 13 年 前

Haiku Additions.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 9.6 KB
 
1/* $Id: OpenHashTable.h 43363 2012-09-20 09:56:07Z vboxsync $ */
2/** @file
3 * OpenHashTable, Haiku Guest Additions.
4 */
5
6/*
7 * Copyright (C) 2012 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*
19 * This code is based on:
20 *
21 * VirtualBox Guest Additions for Haiku.
22 *
23 * Copyright 2007, Hugo Santos. All Rights Reserved.
24 * Distributed under the terms of the MIT License.
25 */
26
27#ifndef _KERNEL_UTIL_OPEN_HASH_TABLE_H
28#define _KERNEL_UTIL_OPEN_HASH_TABLE_H
29
30
31#include <OS.h>
32#include <stdlib.h>
33#include <string.h>
34
35#ifdef _KERNEL_MODE
36# include <KernelExport.h>
37# include "kernel_cpp.h"
38#endif
39
40/*!
41 The Definition template must have four methods: `HashKey', `Hash',
42 `Compare' and `GetLink;. It must also define several types as shown in the
43 following example:
44
45 struct Foo {
46 int bar;
47
48 Foo* fNext;
49 };
50
51 struct HashTableDefinition {
52 typedef int KeyType;
53 typedef Foo ValueType;
54
55 size_t HashKey(int key) const
56 {
57 return key >> 1;
58 }
59
60 size_t Hash(Foo* value) const
61 {
62 return HashKey(value->bar);
63 }
64
65 bool Compare(int key, Foo* value) const
66 {
67 return value->bar == key;
68 }
69
70 Foo*& GetLink(Foo* value) const
71 {
72 return value->fNext;
73 }
74 };
75*/
76
77
78struct MallocAllocator {
79 void* Allocate(size_t size) const
80 {
81 return malloc(size);
82 }
83
84 void Free(void* memory) const
85 {
86 free(memory);
87 }
88};
89
90
91template<typename Definition, bool AutoExpand = true,
92 bool CheckDuplicates = false, typename Allocator = MallocAllocator>
93class BOpenHashTable {
94public:
95 typedef BOpenHashTable<Definition, AutoExpand, CheckDuplicates> HashTable;
96 typedef typename Definition::KeyType KeyType;
97 typedef typename Definition::ValueType ValueType;
98
99 static const size_t kMinimumSize = 8;
100
101 // All allocations are of power of 2 lengths.
102
103 // regrowth factor: 200 / 256 = 78.125%
104 // 50 / 256 = 19.53125%
105
106 BOpenHashTable()
107 :
108 fTableSize(0),
109 fItemCount(0),
110 fTable(NULL)
111 {
112 }
113
114 BOpenHashTable(const Definition& definition)
115 :
116 fDefinition(definition),
117 fTableSize(0),
118 fItemCount(0),
119 fTable(NULL)
120 {
121 }
122
123 BOpenHashTable(const Definition& definition, const Allocator& allocator)
124 :
125 fDefinition(definition),
126 fAllocator(allocator),
127 fTableSize(0),
128 fItemCount(0),
129 fTable(NULL)
130 {
131 }
132
133 ~BOpenHashTable()
134 {
135 fAllocator.Free(fTable);
136 }
137
138 status_t Init(size_t initialSize = kMinimumSize)
139 {
140 if (initialSize > 0 && !_Resize(initialSize))
141 return B_NO_MEMORY;
142 return B_OK;
143 }
144
145 size_t TableSize() const
146 {
147 return fTableSize;
148 }
149
150 size_t CountElements() const
151 {
152 return fItemCount;
153 }
154
155 ValueType* Lookup(const KeyType& key) const
156 {
157 if (fTableSize == 0)
158 return NULL;
159
160 size_t index = fDefinition.HashKey(key) & (fTableSize - 1);
161 ValueType* slot = fTable[index];
162
163 while (slot) {
164 if (fDefinition.Compare(key, slot))
165 break;
166 slot = _Link(slot);
167 }
168
169 return slot;
170 }
171
172 status_t Insert(ValueType* value)
173 {
174 if (fTableSize == 0) {
175 if (!_Resize(kMinimumSize))
176 return B_NO_MEMORY;
177 } else if (AutoExpand && fItemCount >= (fTableSize * 200 / 256))
178 _Resize(fTableSize * 2);
179
180 InsertUnchecked(value);
181 return B_OK;
182 }
183
184 void InsertUnchecked(ValueType* value)
185 {
186 if (CheckDuplicates && _ExhaustiveSearch(value)) {
187#ifdef _KERNEL_MODE
188 panic("Hash Table: value already in table.");
189#else
190 debugger("Hash Table: value already in table.");
191#endif
192 }
193
194 _Insert(fTable, fTableSize, value);
195 fItemCount++;
196 }
197
198 // TODO: a ValueType* Remove(const KeyType& key) method is missing
199
200 bool Remove(ValueType* value)
201 {
202 if (!RemoveUnchecked(value))
203 return false;
204
205 if (AutoExpand && fTableSize > kMinimumSize
206 && fItemCount < (fTableSize * 50 / 256))
207 _Resize(fTableSize / 2);
208
209 return true;
210 }
211
212 bool RemoveUnchecked(ValueType* value)
213 {
214 size_t index = fDefinition.Hash(value) & (fTableSize - 1);
215 ValueType* previous = NULL;
216 ValueType* slot = fTable[index];
217
218 while (slot) {
219 ValueType* next = _Link(slot);
220
221 if (value == slot) {
222 if (previous)
223 _Link(previous) = next;
224 else
225 fTable[index] = next;
226 break;
227 }
228
229 previous = slot;
230 slot = next;
231 }
232
233 if (slot == NULL)
234 return false;
235
236 if (CheckDuplicates && _ExhaustiveSearch(value)) {
237#ifdef _KERNEL_MODE
238 panic("Hash Table: duplicate detected.");
239#else
240 debugger("Hash Table: duplicate detected.");
241#endif
242 }
243
244 fItemCount--;
245 return true;
246 }
247
248 /*! Removes all elements from the hash table. No resizing happens. The
249 elements are not deleted. If \a returnElements is \c true, the method
250 returns all elements chained via their hash table link.
251 */
252 ValueType* Clear(bool returnElements = false)
253 {
254 if (this->fItemCount == 0)
255 return NULL;
256
257 ValueType* result = NULL;
258
259 if (returnElements) {
260 ValueType** nextPointer = &result;
261
262 // iterate through all buckets
263 for (size_t i = 0; i < fTableSize; i++) {
264 ValueType* element = fTable[i];
265 if (element != NULL) {
266 // add the bucket to the list
267 *nextPointer = element;
268
269 // update nextPointer to point to the fNext of the last
270 // element in the bucket
271 while (element != NULL) {
272 nextPointer = &_Link(element);
273 element = *nextPointer;
274 }
275 }
276 }
277 }
278
279 memset(this->fTable, 0, sizeof(ValueType*) * this->fTableSize);
280
281 return result;
282 }
283
284 /*! If the table needs resizing, the number of bytes for the required
285 allocation is returned. If no resizing is needed, 0 is returned.
286 */
287 size_t ResizeNeeded() const
288 {
289 size_t size = fTableSize;
290 if (size == 0 || fItemCount >= (size * 200 / 256)) {
291 // grow table
292 if (size == 0)
293 size = kMinimumSize;
294 while (fItemCount >= size * 200 / 256)
295 size <<= 1;
296 } else if (size > kMinimumSize && fItemCount < size * 50 / 256) {
297 // shrink table
298 while (fItemCount < size * 50 / 256)
299 size >>= 1;
300 if (size < kMinimumSize)
301 size = kMinimumSize;
302 }
303
304 if (size == fTableSize)
305 return 0;
306
307 return size * sizeof(ValueType*);
308 }
309
310 /*! Resizes the table using the given allocation. The allocation must not
311 be \c NULL. It must be of size \a size, which must a value returned
312 earlier by ResizeNeeded(). If the size requirements have changed in the
313 meantime, the method free()s the given allocation and returns \c false,
314 unless \a force is \c true, in which case the supplied allocation is
315 used in any event.
316 Otherwise \c true is returned.
317 If \a oldTable is non-null and resizing is successful, the old table
318 will not be freed, but will be returned via this parameter instead.
319 */
320 bool Resize(void* allocation, size_t size, bool force = false,
321 void** oldTable = NULL)
322 {
323 if (!force && size != ResizeNeeded()) {
324 fAllocator.Free(allocation);
325 return false;
326 }
327
328 _Resize((ValueType**)allocation, size / sizeof(ValueType*), oldTable);
329 return true;
330 }
331
332 class Iterator {
333 public:
334 Iterator(const HashTable* table)
335 : fTable(table)
336 {
337 Rewind();
338 }
339
340 Iterator(const HashTable* table, size_t index, ValueType* value)
341 : fTable(table), fIndex(index), fNext(value) {}
342
343 bool HasNext() const { return fNext != NULL; }
344
345 ValueType* Next()
346 {
347 ValueType* current = fNext;
348 _GetNext();
349 return current;
350 }
351
352 void Rewind()
353 {
354 // get the first one
355 fIndex = 0;
356 fNext = NULL;
357 _GetNext();
358 }
359
360 protected:
361 Iterator() {}
362
363 void _GetNext()
364 {
365 if (fNext)
366 fNext = fTable->_Link(fNext);
367
368 while (fNext == NULL && fIndex < fTable->fTableSize)
369 fNext = fTable->fTable[fIndex++];
370 }
371
372 const HashTable* fTable;
373 size_t fIndex;
374 ValueType* fNext;
375 };
376
377 Iterator GetIterator() const
378 {
379 return Iterator(this);
380 }
381
382 Iterator GetIterator(const KeyType& key) const
383 {
384 if (fTableSize == 0)
385 return Iterator(this, fTableSize, NULL);
386
387 size_t index = fDefinition.HashKey(key) & (fTableSize - 1);
388 ValueType* slot = fTable[index];
389
390 while (slot) {
391 if (fDefinition.Compare(key, slot))
392 break;
393 slot = _Link(slot);
394 }
395
396 if (slot == NULL)
397 return Iterator(this, fTableSize, NULL);
398
399 return Iterator(this, index + 1, slot);
400 }
401
402protected:
403 // for g++ 2.95
404 friend class Iterator;
405
406 void _Insert(ValueType** table, size_t tableSize, ValueType* value)
407 {
408 size_t index = fDefinition.Hash(value) & (tableSize - 1);
409
410 _Link(value) = table[index];
411 table[index] = value;
412 }
413
414 bool _Resize(size_t newSize)
415 {
416 ValueType** newTable
417 = (ValueType**)fAllocator.Allocate(sizeof(ValueType*) * newSize);
418 if (newTable == NULL)
419 return false;
420
421 _Resize(newTable, newSize);
422 return true;
423 }
424
425 void _Resize(ValueType** newTable, size_t newSize, void** _oldTable = NULL)
426 {
427 for (size_t i = 0; i < newSize; i++)
428 newTable[i] = NULL;
429
430 if (fTable) {
431 for (size_t i = 0; i < fTableSize; i++) {
432 ValueType* bucket = fTable[i];
433 while (bucket) {
434 ValueType* next = _Link(bucket);
435 _Insert(newTable, newSize, bucket);
436 bucket = next;
437 }
438 }
439
440 if (_oldTable != NULL)
441 *_oldTable = fTable;
442 else
443 fAllocator.Free(fTable);
444 } else if (_oldTable != NULL)
445 *_oldTable = NULL;
446
447 fTableSize = newSize;
448 fTable = newTable;
449 }
450
451 ValueType*& _Link(ValueType* bucket) const
452 {
453 return fDefinition.GetLink(bucket);
454 }
455
456 bool _ExhaustiveSearch(ValueType* value) const
457 {
458 for (size_t i = 0; i < fTableSize; i++) {
459 ValueType* bucket = fTable[i];
460 while (bucket) {
461 if (bucket == value)
462 return true;
463 bucket = _Link(bucket);
464 }
465 }
466
467 return false;
468 }
469
470 Definition fDefinition;
471 Allocator fAllocator;
472 size_t fTableSize;
473 size_t fItemCount;
474 ValueType** fTable;
475};
476
477#endif // _KERNEL_UTIL_OPEN_HASH_TABLE_H
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette