VirtualBox

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

Last change on this file since 76553 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

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