VirtualBox

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

Last change on this file since 65102 was 62526, checked in by vboxsync, 8 years ago

(C) 2016

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.1 KB
Line 
1/* $Id: OpenHashTable.h 62526 2016-07-22 19:18:03Z vboxsync $ */
2/** @file
3 * OpenHashTable, Haiku Guest Additions.
4 */
5
6/*
7 * Copyright (C) 2012-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.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{
80 void* Allocate(size_t size) const
81 {
82 return malloc(size);
83 }
84
85 void Free(void* memory) const
86 {
87 free(memory);
88 }
89};
90
91
92template<typename Definition, bool AutoExpand = true,
93 bool CheckDuplicates = false, typename Allocator = MallocAllocator>
94class BOpenHashTable
95{
96public:
97 typedef BOpenHashTable<Definition, AutoExpand, CheckDuplicates> HashTable;
98 typedef typename Definition::KeyType KeyType;
99 typedef typename Definition::ValueType ValueType;
100
101 static const size_t kMinimumSize = 8;
102
103 // All allocations are of power of 2 lengths.
104
105 // regrowth factor: 200 / 256 = 78.125%
106 // 50 / 256 = 19.53125%
107
108 BOpenHashTable()
109 :
110 fTableSize(0),
111 fItemCount(0),
112 fTable(NULL)
113 {
114 }
115
116 BOpenHashTable(const Definition& definition)
117 :
118 fDefinition(definition),
119 fTableSize(0),
120 fItemCount(0),
121 fTable(NULL)
122 {
123 }
124
125 BOpenHashTable(const Definition& definition, const Allocator& allocator)
126 :
127 fDefinition(definition),
128 fAllocator(allocator),
129 fTableSize(0),
130 fItemCount(0),
131 fTable(NULL)
132 {
133 }
134
135 ~BOpenHashTable()
136 {
137 fAllocator.Free(fTable);
138 }
139
140 status_t Init(size_t initialSize = kMinimumSize)
141 {
142 if (initialSize > 0 && !_Resize(initialSize))
143 return B_NO_MEMORY;
144 return B_OK;
145 }
146
147 size_t TableSize() const
148 {
149 return fTableSize;
150 }
151
152 size_t CountElements() const
153 {
154 return fItemCount;
155 }
156
157 ValueType* Lookup(const KeyType& key) const
158 {
159 if (fTableSize == 0)
160 return NULL;
161
162 size_t index = fDefinition.HashKey(key) & (fTableSize - 1);
163 ValueType* slot = fTable[index];
164
165 while (slot)
166 {
167 if (fDefinition.Compare(key, slot))
168 break;
169 slot = _Link(slot);
170 }
171
172 return slot;
173 }
174
175 status_t Insert(ValueType* value)
176 {
177 if (fTableSize == 0)
178 {
179 if (!_Resize(kMinimumSize))
180 return B_NO_MEMORY;
181 }
182 else if (AutoExpand && fItemCount >= (fTableSize * 200 / 256))
183 _Resize(fTableSize * 2);
184
185 InsertUnchecked(value);
186 return B_OK;
187 }
188
189 void InsertUnchecked(ValueType* value)
190 {
191 if (CheckDuplicates && _ExhaustiveSearch(value))
192 {
193#ifdef _KERNEL_MODE
194 panic("Hash Table: value already in table.");
195#else
196 debugger("Hash Table: value already in table.");
197#endif
198 }
199
200 _Insert(fTable, fTableSize, value);
201 fItemCount++;
202 }
203
204 // TODO: a ValueType* Remove(const KeyType& key) method is missing
205
206 bool Remove(ValueType* value)
207 {
208 if (!RemoveUnchecked(value))
209 return false;
210
211 if (AutoExpand && fTableSize > kMinimumSize
212 && fItemCount < (fTableSize * 50 / 256))
213 _Resize(fTableSize / 2);
214
215 return true;
216 }
217
218 bool RemoveUnchecked(ValueType* value)
219 {
220 size_t index = fDefinition.Hash(value) & (fTableSize - 1);
221 ValueType* previous = NULL;
222 ValueType* slot = fTable[index];
223
224 while (slot)
225 {
226 ValueType* next = _Link(slot);
227
228 if (value == slot)
229 {
230 if (previous)
231 _Link(previous) = next;
232 else
233 fTable[index] = next;
234 break;
235 }
236
237 previous = slot;
238 slot = next;
239 }
240
241 if (slot == NULL)
242 return false;
243
244 if (CheckDuplicates && _ExhaustiveSearch(value))
245 {
246#ifdef _KERNEL_MODE
247 panic("Hash Table: duplicate detected.");
248#else
249 debugger("Hash Table: duplicate detected.");
250#endif
251 }
252
253 fItemCount--;
254 return true;
255 }
256
257 /*! Removes all elements from the hash table. No resizing happens. The
258 elements are not deleted. If \a returnElements is \c true, the method
259 returns all elements chained via their hash table link.
260 */
261 ValueType* Clear(bool returnElements = false)
262 {
263 if (this->fItemCount == 0)
264 return NULL;
265
266 ValueType* result = NULL;
267
268 if (returnElements)
269 {
270 ValueType** nextPointer = &result;
271
272 // iterate through all buckets
273 for (size_t i = 0; i < fTableSize; i++)
274 {
275 ValueType* element = fTable[i];
276 if (element != NULL)
277 {
278 // add the bucket to the list
279 *nextPointer = element;
280
281 // update nextPointer to point to the fNext of the last
282 // element in the bucket
283 while (element != NULL)
284 {
285 nextPointer = &_Link(element);
286 element = *nextPointer;
287 }
288 }
289 }
290 }
291
292 memset(this->fTable, 0, sizeof(ValueType*) * this->fTableSize);
293
294 return result;
295 }
296
297 /*! If the table needs resizing, the number of bytes for the required
298 allocation is returned. If no resizing is needed, 0 is returned.
299 */
300 size_t ResizeNeeded() const
301 {
302 size_t size = fTableSize;
303 if (size == 0 || fItemCount >= (size * 200 / 256))
304 {
305 // grow table
306 if (size == 0)
307 size = kMinimumSize;
308 while (fItemCount >= size * 200 / 256)
309 size <<= 1;
310 }
311 else if (size > kMinimumSize && fItemCount < size * 50 / 256)
312 {
313 // shrink table
314 while (fItemCount < size * 50 / 256)
315 size >>= 1;
316 if (size < kMinimumSize)
317 size = kMinimumSize;
318 }
319
320 if (size == fTableSize)
321 return 0;
322
323 return size * sizeof(ValueType*);
324 }
325
326 /*! Resizes the table using the given allocation. The allocation must not
327 be \c NULL. It must be of size \a size, which must a value returned
328 earlier by ResizeNeeded(). If the size requirements have changed in the
329 meantime, the method free()s the given allocation and returns \c false,
330 unless \a force is \c true, in which case the supplied allocation is
331 used in any event.
332 Otherwise \c true is returned.
333 If \a oldTable is non-null and resizing is successful, the old table
334 will not be freed, but will be returned via this parameter instead.
335 */
336 bool Resize(void* allocation, size_t size, bool force = false,
337 void** oldTable = NULL)
338 {
339 if (!force && size != ResizeNeeded())
340 {
341 fAllocator.Free(allocation);
342 return false;
343 }
344
345 _Resize((ValueType**)allocation, size / sizeof(ValueType*), oldTable);
346 return true;
347 }
348
349 class Iterator
350 {
351 public:
352 Iterator(const HashTable* table)
353 : fTable(table)
354 {
355 Rewind();
356 }
357
358 Iterator(const HashTable* table, size_t index, ValueType* value)
359 : fTable(table), fIndex(index), fNext(value) {}
360
361 bool HasNext() const { return fNext != NULL; }
362
363 ValueType* Next()
364 {
365 ValueType* current = fNext;
366 _GetNext();
367 return current;
368 }
369
370 void Rewind()
371 {
372 // get the first one
373 fIndex = 0;
374 fNext = NULL;
375 _GetNext();
376 }
377
378 protected:
379 Iterator() {}
380
381 void _GetNext()
382 {
383 if (fNext)
384 fNext = fTable->_Link(fNext);
385
386 while (fNext == NULL && fIndex < fTable->fTableSize)
387 fNext = fTable->fTable[fIndex++];
388 }
389
390 const HashTable* fTable;
391 size_t fIndex;
392 ValueType* fNext;
393 };
394
395 Iterator GetIterator() const
396 {
397 return Iterator(this);
398 }
399
400 Iterator GetIterator(const KeyType& key) const
401 {
402 if (fTableSize == 0)
403 return Iterator(this, fTableSize, NULL);
404
405 size_t index = fDefinition.HashKey(key) & (fTableSize - 1);
406 ValueType* slot = fTable[index];
407
408 while (slot)
409 {
410 if (fDefinition.Compare(key, slot))
411 break;
412 slot = _Link(slot);
413 }
414
415 if (slot == NULL)
416 return Iterator(this, fTableSize, NULL);
417
418 return Iterator(this, index + 1, slot);
419 }
420
421protected:
422 // for g++ 2.95
423 friend class Iterator;
424
425 void _Insert(ValueType** table, size_t tableSize, ValueType* value)
426 {
427 size_t index = fDefinition.Hash(value) & (tableSize - 1);
428
429 _Link(value) = table[index];
430 table[index] = value;
431 }
432
433 bool _Resize(size_t newSize)
434 {
435 ValueType** newTable
436 = (ValueType**)fAllocator.Allocate(sizeof(ValueType*) * newSize);
437 if (newTable == NULL)
438 return false;
439
440 _Resize(newTable, newSize);
441 return true;
442 }
443
444 void _Resize(ValueType** newTable, size_t newSize, void** _oldTable = NULL)
445 {
446 for (size_t i = 0; i < newSize; i++)
447 newTable[i] = NULL;
448
449 if (fTable)
450 {
451 for (size_t i = 0; i < fTableSize; i++)
452 {
453 ValueType* bucket = fTable[i];
454 while (bucket)
455 {
456 ValueType* next = _Link(bucket);
457 _Insert(newTable, newSize, bucket);
458 bucket = next;
459 }
460 }
461
462 if (_oldTable != NULL)
463 *_oldTable = fTable;
464 else
465 fAllocator.Free(fTable);
466 }
467 else if (_oldTable != NULL)
468 *_oldTable = NULL;
469
470 fTableSize = newSize;
471 fTable = newTable;
472 }
473
474 ValueType*& _Link(ValueType* bucket) const
475 {
476 return fDefinition.GetLink(bucket);
477 }
478
479 bool _ExhaustiveSearch(ValueType* value) const
480 {
481 for (size_t i = 0; i < fTableSize; i++)
482 {
483 ValueType* bucket = fTable[i];
484 while (bucket) {
485 if (bucket == value)
486 return true;
487 bucket = _Link(bucket);
488 }
489 }
490
491 return false;
492 }
493
494 Definition fDefinition;
495 Allocator fAllocator;
496 size_t fTableSize;
497 size_t fItemCount;
498 ValueType** fTable;
499};
500
501#endif // _KERNEL_UTIL_OPEN_HASH_TABLE_H
502
Note: See TracBrowser for help on using the repository browser.

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