rootfs: convert to BOpenHashTable.
* Add an fs-shell compatible version of BOpenHashTable in the fs_shell to keep it working. The header is renamed to KOpenHashTable to avoid a conflict with the OpenHashTable.h available in private/shared which is not API compatible.
This commit is contained in:
parent
9d053f5975
commit
bb3092b298
@ -8,9 +8,11 @@
|
||||
|
||||
|
||||
#if FS_SHELL
|
||||
# include <new>
|
||||
|
||||
# include "fssh_api_wrapper.h"
|
||||
|
||||
# include "hash.h"
|
||||
# include "KOpenHashTable.h"
|
||||
# include "list.h"
|
||||
#else
|
||||
# include <stdio.h>
|
||||
@ -23,14 +25,15 @@
|
||||
# include <NodeMonitor.h>
|
||||
|
||||
# include <debug.h>
|
||||
# include <khash.h>
|
||||
# include <lock.h>
|
||||
# include <OpenHashTable.h>
|
||||
# include <util/AutoLock.h>
|
||||
# include <vfs.h>
|
||||
# include <vm/vm.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if FS_SHELL
|
||||
using namespace FSShell;
|
||||
# define user_strlcpy(to, from, len) (strlcpy(to, from, len), FSSH_B_OK)
|
||||
@ -71,12 +74,39 @@ struct rootfs_vnode {
|
||||
struct rootfs_stream stream;
|
||||
};
|
||||
|
||||
struct VnodeHash {
|
||||
typedef ino_t KeyType;
|
||||
typedef rootfs_vnode ValueType;
|
||||
|
||||
size_t HashKey(KeyType key) const
|
||||
{
|
||||
return key;
|
||||
}
|
||||
|
||||
size_t Hash(ValueType* vnode) const
|
||||
{
|
||||
return vnode->id;
|
||||
}
|
||||
|
||||
bool Compare(KeyType key, ValueType* vnode) const
|
||||
{
|
||||
return vnode->id == key;
|
||||
}
|
||||
|
||||
ValueType*& GetLink(ValueType* value) const
|
||||
{
|
||||
return value->all_next;
|
||||
}
|
||||
};
|
||||
|
||||
typedef BOpenHashTable<VnodeHash> VnodeTable;
|
||||
|
||||
struct rootfs {
|
||||
fs_volume* volume;
|
||||
dev_t id;
|
||||
rw_lock lock;
|
||||
ino_t next_vnode_id;
|
||||
hash_table* vnode_list_hash;
|
||||
VnodeTable* vnode_list_hash;
|
||||
struct rootfs_vnode* root_vnode;
|
||||
};
|
||||
|
||||
@ -117,32 +147,6 @@ current_timespec()
|
||||
}
|
||||
|
||||
|
||||
static uint32
|
||||
rootfs_vnode_hash_func(void* _v, const void* _key, uint32 range)
|
||||
{
|
||||
struct rootfs_vnode* vnode = (rootfs_vnode*)_v;
|
||||
const ino_t* key = (const ino_t*)_key;
|
||||
|
||||
if (vnode != NULL)
|
||||
return vnode->id % range;
|
||||
|
||||
return (uint64)*key % range;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
rootfs_vnode_compare_func(void* _v, const void* _key)
|
||||
{
|
||||
struct rootfs_vnode* v = (rootfs_vnode*)_v;
|
||||
const ino_t* key = (const ino_t*)_key;
|
||||
|
||||
if (v->id == *key)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static struct rootfs_vnode*
|
||||
rootfs_create_vnode(struct rootfs* fs, struct rootfs_vnode* parent,
|
||||
const char* name, int type)
|
||||
@ -188,7 +192,7 @@ rootfs_delete_vnode(struct rootfs* fs, struct rootfs_vnode* v, bool force_delete
|
||||
return EPERM;
|
||||
|
||||
// remove it from the global hash table
|
||||
hash_remove(fs->vnode_list_hash, v);
|
||||
fs->vnode_list_hash->Remove(v);
|
||||
|
||||
if (S_ISDIR(v->stream.type))
|
||||
mutex_destroy(&v->stream.dir.cookie_lock);
|
||||
@ -376,10 +380,9 @@ rootfs_mount(fs_volume* volume, const char* device, uint32 flags,
|
||||
|
||||
rw_lock_init(&fs->lock, "rootfs");
|
||||
|
||||
fs->vnode_list_hash = hash_init(ROOTFS_HASH_SIZE,
|
||||
offsetof(rootfs_vnode, all_next), &rootfs_vnode_compare_func,
|
||||
&rootfs_vnode_hash_func);
|
||||
if (fs->vnode_list_hash == NULL) {
|
||||
fs->vnode_list_hash = new(std::nothrow) VnodeTable();
|
||||
if (fs->vnode_list_hash == NULL
|
||||
|| fs->vnode_list_hash->Init(ROOTFS_HASH_SIZE) != B_OK) {
|
||||
err = B_NO_MEMORY;
|
||||
goto err2;
|
||||
}
|
||||
@ -393,7 +396,7 @@ rootfs_mount(fs_volume* volume, const char* device, uint32 flags,
|
||||
vnode->parent = vnode;
|
||||
|
||||
fs->root_vnode = vnode;
|
||||
hash_insert(fs->vnode_list_hash, vnode);
|
||||
fs->vnode_list_hash->Insert(vnode);
|
||||
publish_vnode(volume, vnode->id, vnode, &sVnodeOps, vnode->stream.type, 0);
|
||||
|
||||
*_rootID = vnode->id;
|
||||
@ -401,7 +404,7 @@ rootfs_mount(fs_volume* volume, const char* device, uint32 flags,
|
||||
return B_OK;
|
||||
|
||||
err3:
|
||||
hash_uninit(fs->vnode_list_hash);
|
||||
delete fs->vnode_list_hash;
|
||||
err2:
|
||||
rw_lock_destroy(&fs->lock);
|
||||
free(fs);
|
||||
@ -421,17 +424,14 @@ rootfs_unmount(fs_volume* _volume)
|
||||
put_vnode(fs->volume, fs->root_vnode->id);
|
||||
|
||||
// delete all of the vnodes
|
||||
struct hash_iterator i;
|
||||
hash_open(fs->vnode_list_hash, &i);
|
||||
VnodeTable::Iterator i(fs->vnode_list_hash);
|
||||
|
||||
while (struct rootfs_vnode* vnode = (struct rootfs_vnode*)
|
||||
hash_next(fs->vnode_list_hash, &i)) {
|
||||
while (i.HasNext()) {
|
||||
struct rootfs_vnode* vnode = i.Next();
|
||||
rootfs_delete_vnode(fs, vnode, true);
|
||||
}
|
||||
|
||||
hash_close(fs->vnode_list_hash, &i, false);
|
||||
|
||||
hash_uninit(fs->vnode_list_hash);
|
||||
delete fs->vnode_list_hash;
|
||||
rw_lock_destroy(&fs->lock);
|
||||
free(fs);
|
||||
|
||||
@ -503,7 +503,7 @@ rootfs_get_vnode(fs_volume* _volume, ino_t id, fs_vnode* _vnode, int* _type,
|
||||
if (!reenter)
|
||||
rw_lock_read_lock(&fs->lock);
|
||||
|
||||
vnode = (rootfs_vnode*)hash_lookup(fs->vnode_list_hash, &id);
|
||||
vnode = fs->vnode_list_hash->Lookup(id);
|
||||
|
||||
if (!reenter)
|
||||
rw_lock_read_unlock(&fs->lock);
|
||||
@ -644,7 +644,7 @@ rootfs_create_dir(fs_volume* _volume, fs_vnode* _dir, const char* name,
|
||||
return B_NO_MEMORY;
|
||||
|
||||
rootfs_insert_in_dir(fs, dir, vnode);
|
||||
hash_insert(fs->vnode_list_hash, vnode);
|
||||
fs->vnode_list_hash->Insert(vnode);
|
||||
|
||||
entry_cache_add(fs->volume->id, dir->id, name, vnode->id);
|
||||
notify_entry_created(fs->id, dir->id, name, vnode->id);
|
||||
@ -877,7 +877,7 @@ rootfs_symlink(fs_volume* _volume, fs_vnode* _dir, const char* name,
|
||||
return B_NO_MEMORY;
|
||||
|
||||
rootfs_insert_in_dir(fs, dir, vnode);
|
||||
hash_insert(fs->vnode_list_hash, vnode);
|
||||
fs->vnode_list_hash->Insert(vnode);
|
||||
|
||||
vnode->stream.symlink.path = strdup(path);
|
||||
if (vnode->stream.symlink.path == NULL) {
|
||||
@ -1086,7 +1086,7 @@ rootfs_create_special_node(fs_volume* _volume, fs_vnode* _dir, const char* name,
|
||||
else
|
||||
flags |= B_VNODE_PUBLISH_REMOVED;
|
||||
|
||||
hash_insert(fs->vnode_list_hash, vnode);
|
||||
fs->vnode_list_hash->Insert(vnode);
|
||||
|
||||
_superVnode->private_node = vnode;
|
||||
_superVnode->ops = &sVnodeOps;
|
||||
|
497
src/tools/fs_shell/KOpenHashTable.h
Normal file
497
src/tools/fs_shell/KOpenHashTable.h
Normal file
@ -0,0 +1,497 @@
|
||||
/*
|
||||
* Copyright 2007, Hugo Santos. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _KERNEL_UTIL_OPEN_HASH_TABLE_H
|
||||
#define _KERNEL_UTIL_OPEN_HASH_TABLE_H
|
||||
|
||||
|
||||
#include "fssh_api_wrapper.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _KERNEL_MODE
|
||||
# include <KernelExport.h>
|
||||
# include <util/kernel_cpp.h>
|
||||
# include <util/TypeOperation.h>
|
||||
#else
|
||||
# include <TypeOperation.h>
|
||||
#endif
|
||||
|
||||
|
||||
/*!
|
||||
The Definition template must have four methods: `HashKey', `Hash',
|
||||
`Compare' and `GetLink;. It must also define several types as shown in the
|
||||
following example:
|
||||
|
||||
struct Foo {
|
||||
int bar;
|
||||
|
||||
Foo* fNext;
|
||||
};
|
||||
|
||||
struct HashTableDefinition {
|
||||
typedef int KeyType;
|
||||
typedef Foo ValueType;
|
||||
|
||||
size_t HashKey(KeyType key) const
|
||||
{
|
||||
return key >> 1;
|
||||
}
|
||||
|
||||
size_t Hash(ValueType* value) const
|
||||
{
|
||||
return HashKey(value->bar);
|
||||
}
|
||||
|
||||
bool Compare(KeyType key, ValueType* value) const
|
||||
{
|
||||
return value->bar == key;
|
||||
}
|
||||
|
||||
ValueType*& GetLink(ValueType* value) const
|
||||
{
|
||||
return value->fNext;
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
|
||||
struct MallocAllocator {
|
||||
void* Allocate(size_t size) const
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void Free(void* memory) const
|
||||
{
|
||||
free(memory);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Implements an hash table with open hashing, that is, colliding entries are
|
||||
* stored in a linked list. The table may be made to adjust its number of slots
|
||||
* depending on the load factor (this should be enabled unless the object is to
|
||||
* be used at times where memory allocations aren't possible, such as code
|
||||
* called byt he memory allocator).
|
||||
*
|
||||
* The link between entries is part of the ValueType stored items, which makes
|
||||
* sure the table can always accept new items and will never fail because it is
|
||||
* out of memory (except at Init time).
|
||||
*/
|
||||
template<typename Definition, bool AutoExpand = true,
|
||||
bool CheckDuplicates = false, typename Allocator = MallocAllocator>
|
||||
class BOpenHashTable {
|
||||
public:
|
||||
typedef BOpenHashTable<Definition, AutoExpand, CheckDuplicates> HashTable;
|
||||
typedef typename Definition::KeyType KeyType;
|
||||
typedef typename Definition::ValueType ValueType;
|
||||
|
||||
static const size_t kMinimumSize = 8;
|
||||
|
||||
// All allocations are of power of 2 lengths.
|
||||
|
||||
// regrowth factor: 200 / 256 = 78.125%
|
||||
// 50 / 256 = 19.53125%
|
||||
|
||||
BOpenHashTable()
|
||||
:
|
||||
fTableSize(0),
|
||||
fItemCount(0),
|
||||
fTable(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
BOpenHashTable(const Definition& definition)
|
||||
:
|
||||
fDefinition(definition),
|
||||
fTableSize(0),
|
||||
fItemCount(0),
|
||||
fTable(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
BOpenHashTable(const Definition& definition, const Allocator& allocator)
|
||||
:
|
||||
fDefinition(definition),
|
||||
fAllocator(allocator),
|
||||
fTableSize(0),
|
||||
fItemCount(0),
|
||||
fTable(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
~BOpenHashTable()
|
||||
{
|
||||
fAllocator.Free(fTable);
|
||||
}
|
||||
|
||||
status_t Init(size_t initialSize = kMinimumSize)
|
||||
{
|
||||
if (initialSize > 0 && !_Resize(initialSize))
|
||||
return B_NO_MEMORY;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
size_t TableSize() const
|
||||
{
|
||||
return fTableSize;
|
||||
}
|
||||
|
||||
bool IsEmpty() const
|
||||
{
|
||||
return fItemCount == 0;
|
||||
}
|
||||
|
||||
size_t CountElements() const
|
||||
{
|
||||
return fItemCount;
|
||||
}
|
||||
|
||||
ValueType* Lookup(typename TypeOperation<KeyType>::ConstRefT key) const
|
||||
{
|
||||
if (fTableSize == 0)
|
||||
return NULL;
|
||||
|
||||
size_t index = fDefinition.HashKey(key) & (fTableSize - 1);
|
||||
ValueType* slot = fTable[index];
|
||||
|
||||
while (slot) {
|
||||
if (fDefinition.Compare(key, slot))
|
||||
break;
|
||||
slot = _Link(slot);
|
||||
}
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
status_t Insert(ValueType* value)
|
||||
{
|
||||
if (fTableSize == 0) {
|
||||
if (!_Resize(kMinimumSize))
|
||||
return B_NO_MEMORY;
|
||||
} else if (AutoExpand && fItemCount >= (fTableSize * 200 / 256))
|
||||
_Resize(fTableSize * 2);
|
||||
|
||||
InsertUnchecked(value);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/*! \brief Inserts a value without resizing the table.
|
||||
|
||||
Use this method if you need to insert a value into the table while
|
||||
iterating it, as regular insertion can invalidate iterators.
|
||||
*/
|
||||
void InsertUnchecked(ValueType* value)
|
||||
{
|
||||
if (CheckDuplicates && _ExhaustiveSearch(value)) {
|
||||
#if defined(_KERNEL_MODE) || defined(FS_SHELL)
|
||||
panic("Hash Table: value already in table.");
|
||||
#else
|
||||
debugger("Hash Table: value already in table.");
|
||||
#endif
|
||||
}
|
||||
|
||||
_Insert(fTable, fTableSize, value);
|
||||
fItemCount++;
|
||||
}
|
||||
|
||||
// TODO: a ValueType* Remove(const KeyType& key) method is missing
|
||||
|
||||
bool Remove(ValueType* value)
|
||||
{
|
||||
if (!RemoveUnchecked(value))
|
||||
return false;
|
||||
|
||||
if (AutoExpand && fTableSize > kMinimumSize
|
||||
&& fItemCount < (fTableSize * 50 / 256))
|
||||
_Resize(fTableSize / 2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! \brief Removes a value without resizing the table.
|
||||
|
||||
Use this method if you need to remove a value from the table while
|
||||
iterating it, as Remove can invalidate iterators.
|
||||
|
||||
Also use this method if you know you are going to reinsert the item soon
|
||||
(possibly with a different hash) to avoid shrinking then growing the
|
||||
table again.
|
||||
*/
|
||||
bool RemoveUnchecked(ValueType* value)
|
||||
{
|
||||
size_t index = fDefinition.Hash(value) & (fTableSize - 1);
|
||||
ValueType* previous = NULL;
|
||||
ValueType* slot = fTable[index];
|
||||
|
||||
while (slot) {
|
||||
ValueType* next = _Link(slot);
|
||||
|
||||
if (value == slot) {
|
||||
if (previous)
|
||||
_Link(previous) = next;
|
||||
else
|
||||
fTable[index] = next;
|
||||
break;
|
||||
}
|
||||
|
||||
previous = slot;
|
||||
slot = next;
|
||||
}
|
||||
|
||||
if (slot == NULL)
|
||||
return false;
|
||||
|
||||
if (CheckDuplicates && _ExhaustiveSearch(value)) {
|
||||
#if defined(_KERNEL_MODE) || defined(FS_SHELL)
|
||||
panic("Hash Table: duplicate detected.");
|
||||
#else
|
||||
debugger("Hash Table: duplicate detected.");
|
||||
#endif
|
||||
}
|
||||
|
||||
fItemCount--;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! \brief Removes all elements from the hash table.
|
||||
|
||||
No resizing happens. The elements are not deleted. If \a returnElements
|
||||
is \c true, the method returns all elements chained via their hash table
|
||||
link.
|
||||
*/
|
||||
ValueType* Clear(bool returnElements = false)
|
||||
{
|
||||
if (fItemCount == 0)
|
||||
return NULL;
|
||||
|
||||
ValueType* result = NULL;
|
||||
|
||||
if (returnElements) {
|
||||
ValueType** nextPointer = &result;
|
||||
|
||||
// iterate through all buckets
|
||||
for (size_t i = 0; i < fTableSize; i++) {
|
||||
ValueType* element = fTable[i];
|
||||
if (element != NULL) {
|
||||
// add the bucket to the list
|
||||
*nextPointer = element;
|
||||
|
||||
// update nextPointer to point to the fNext of the last
|
||||
// element in the bucket
|
||||
while (element != NULL) {
|
||||
nextPointer = &_Link(element);
|
||||
element = *nextPointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memset(this->fTable, 0, sizeof(ValueType*) * this->fTableSize);
|
||||
fItemCount = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*! If the table needs resizing, the number of bytes for the required
|
||||
allocation is returned. If no resizing is needed, 0 is returned.
|
||||
*/
|
||||
size_t ResizeNeeded() const
|
||||
{
|
||||
size_t size = fTableSize;
|
||||
if (size == 0 || fItemCount >= (size * 200 / 256)) {
|
||||
// grow table
|
||||
if (size == 0)
|
||||
size = kMinimumSize;
|
||||
while (fItemCount >= size * 200 / 256)
|
||||
size <<= 1;
|
||||
} else if (size > kMinimumSize && fItemCount < size * 50 / 256) {
|
||||
// shrink table
|
||||
while (fItemCount < size * 50 / 256)
|
||||
size >>= 1;
|
||||
if (size < kMinimumSize)
|
||||
size = kMinimumSize;
|
||||
}
|
||||
|
||||
if (size == fTableSize)
|
||||
return 0;
|
||||
|
||||
return size * sizeof(ValueType*);
|
||||
}
|
||||
|
||||
/*! Resizes the table using the given allocation. The allocation must not
|
||||
be \c NULL. It must be of size \a size, which must be a value returned
|
||||
earlier by ResizeNeeded(). If the size requirements have changed in the
|
||||
meantime, the method free()s the given allocation and returns \c false,
|
||||
unless \a force is \c true, in which case the supplied allocation is
|
||||
used in any event.
|
||||
Otherwise \c true is returned.
|
||||
If \a oldTable is non-null and resizing is successful, the old table
|
||||
will not be freed, but will be returned via this parameter instead.
|
||||
*/
|
||||
bool Resize(void* allocation, size_t size, bool force = false,
|
||||
void** oldTable = NULL)
|
||||
{
|
||||
if (!force && size != ResizeNeeded()) {
|
||||
fAllocator.Free(allocation);
|
||||
return false;
|
||||
}
|
||||
|
||||
_Resize((ValueType**)allocation, size / sizeof(ValueType*), oldTable);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! \brief Iterator for BOpenHashMap
|
||||
|
||||
The iterator is not invalidated when removing the current element from
|
||||
the table, unless the removal triggers a resize.
|
||||
*/
|
||||
class Iterator {
|
||||
public:
|
||||
Iterator(const HashTable* table)
|
||||
: fTable(table)
|
||||
{
|
||||
Rewind();
|
||||
}
|
||||
|
||||
Iterator(const HashTable* table, size_t index, ValueType* value)
|
||||
: fTable(table), fIndex(index), fNext(value) {}
|
||||
|
||||
bool HasNext() const { return fNext != NULL; }
|
||||
|
||||
ValueType* Next()
|
||||
{
|
||||
ValueType* current = fNext;
|
||||
_GetNext();
|
||||
return current;
|
||||
}
|
||||
|
||||
void Rewind()
|
||||
{
|
||||
// get the first one
|
||||
fIndex = 0;
|
||||
fNext = NULL;
|
||||
_GetNext();
|
||||
}
|
||||
|
||||
protected:
|
||||
Iterator() {}
|
||||
|
||||
void _GetNext()
|
||||
{
|
||||
if (fNext)
|
||||
fNext = fTable->_Link(fNext);
|
||||
|
||||
while (fNext == NULL && fIndex < fTable->fTableSize)
|
||||
fNext = fTable->fTable[fIndex++];
|
||||
}
|
||||
|
||||
const HashTable* fTable;
|
||||
size_t fIndex;
|
||||
ValueType* fNext;
|
||||
};
|
||||
|
||||
Iterator GetIterator() const
|
||||
{
|
||||
return Iterator(this);
|
||||
}
|
||||
|
||||
Iterator GetIterator(typename TypeOperation<KeyType>::ConstRefT key) const
|
||||
{
|
||||
if (fTableSize == 0)
|
||||
return Iterator(this, fTableSize, NULL);
|
||||
|
||||
size_t index = fDefinition.HashKey(key) & (fTableSize - 1);
|
||||
ValueType* slot = fTable[index];
|
||||
|
||||
while (slot) {
|
||||
if (fDefinition.Compare(key, slot))
|
||||
break;
|
||||
slot = _Link(slot);
|
||||
}
|
||||
|
||||
if (slot == NULL)
|
||||
return Iterator(this, fTableSize, NULL);
|
||||
|
||||
return Iterator(this, index + 1, slot);
|
||||
}
|
||||
|
||||
protected:
|
||||
// for g++ 2.95
|
||||
friend class Iterator;
|
||||
|
||||
void _Insert(ValueType** table, size_t tableSize, ValueType* value)
|
||||
{
|
||||
size_t index = fDefinition.Hash(value) & (tableSize - 1);
|
||||
|
||||
_Link(value) = table[index];
|
||||
table[index] = value;
|
||||
}
|
||||
|
||||
bool _Resize(size_t newSize)
|
||||
{
|
||||
ValueType** newTable
|
||||
= (ValueType**)fAllocator.Allocate(sizeof(ValueType*) * newSize);
|
||||
if (newTable == NULL)
|
||||
return false;
|
||||
|
||||
_Resize(newTable, newSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
void _Resize(ValueType** newTable, size_t newSize, void** _oldTable = NULL)
|
||||
{
|
||||
for (size_t i = 0; i < newSize; i++)
|
||||
newTable[i] = NULL;
|
||||
|
||||
if (fTable) {
|
||||
for (size_t i = 0; i < fTableSize; i++) {
|
||||
ValueType* bucket = fTable[i];
|
||||
while (bucket) {
|
||||
ValueType* next = _Link(bucket);
|
||||
_Insert(newTable, newSize, bucket);
|
||||
bucket = next;
|
||||
}
|
||||
}
|
||||
|
||||
if (_oldTable != NULL)
|
||||
*_oldTable = fTable;
|
||||
else
|
||||
fAllocator.Free(fTable);
|
||||
} else if (_oldTable != NULL)
|
||||
*_oldTable = NULL;
|
||||
|
||||
fTableSize = newSize;
|
||||
fTable = newTable;
|
||||
}
|
||||
|
||||
ValueType*& _Link(ValueType* bucket) const
|
||||
{
|
||||
return fDefinition.GetLink(bucket);
|
||||
}
|
||||
|
||||
bool _ExhaustiveSearch(ValueType* value) const
|
||||
{
|
||||
for (size_t i = 0; i < fTableSize; i++) {
|
||||
ValueType* bucket = fTable[i];
|
||||
while (bucket) {
|
||||
if (bucket == value)
|
||||
return true;
|
||||
bucket = _Link(bucket);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Definition fDefinition;
|
||||
Allocator fAllocator;
|
||||
size_t fTableSize;
|
||||
size_t fItemCount;
|
||||
ValueType** fTable;
|
||||
};
|
||||
|
||||
#endif // _KERNEL_UTIL_OPEN_HASH_TABLE_H
|
Loading…
Reference in New Issue
Block a user