VirtualBox

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

Last change on this file since 96407 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

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