📄 table.h
字号:
Iterator(const Table<Key, Value>* table, size_t numBuckets, Node** bucket) :
table(const_cast<Table<Key, Value>*>(table)),
numBuckets(numBuckets),
bucket(bucket) {
if (numBuckets == 0) {
// Empty table
isDone = true;
return;
}
index = 0;
node = bucket[index];
isDone = false;
findNext();
}
/**
Finds the next element, setting isDone if one can't be found.
Looks at the current element first.
*/
void findNext() {
while (node == NULL) {
index++;
if (index >= numBuckets) {
isDone = true;
break;
} else {
node = bucket[index];
}
}
}
public:
inline bool operator!=(const Iterator& other) const {
return !(*this == other);
}
bool operator==(const Iterator& other) const {
if (other.isDone || isDone) {
// Common case; check against isDone.
return (isDone == other.isDone) && (other.table == table);
} else {
return
(table == other.table) &&
(node == other.node) &&
(index == other.index);
}
}
/**
Pre increment.
*/
Iterator& operator++() {
node = node->next;
findNext();
return *this;
}
/**
Post increment (slower than preincrement).
*/
Iterator operator++(int) {
Iterator old = *this;
++(*this);
return old;
}
const Entry& operator*() const {
return node->entry;
}
Entry* operator->() const {
return &(node->entry);
}
operator Entry*() const {
return &(node->entry);
}
};
/**
C++ STL style iterator method. Returns the first Entry, which
contains a key and value. Use preincrement (++entry) to get to
the next element. Do not modify the table while iterating.
*/
Iterator begin() const {
return Iterator(this, numBuckets, bucket);
}
/**
C++ STL style iterator method. Returns one after the last iterator
element.
*/
const Iterator end() const {
return Iterator(this);
}
/**
Removes all elements
*/
void clear() {
freeMemory();
numBuckets = 20;
_size = 0;
bucket = (Node**)System::alignedMalloc(sizeof(Node*) * numBuckets, 16);
System::memset(bucket, 0, sizeof(Node*) * numBuckets);
}
/**
Returns the number of keys.
*/
inline size_t size() const {
return _size;
}
/**
If you insert a pointer into the key or value of a table, you are
responsible for deallocating the object eventually. Inserting
key into a table is O(1), but may cause a potentially slow rehashing.
*/
void set(const Key& key, const Value& value) {
size_t code = ::hashCode(key);
size_t b = code % numBuckets;
// Go to the bucket
Node* n = bucket[b];
// No bucket, so this must be the first
if (n == NULL) {
bucket[b] = new Node(key, value, code, NULL);
++_size;
return;
}
size_t bucketLength = 1;
// Sometimes a bad hash code will cause all elements
// to collide. Detect this case and don't rehash when
// it occurs; nothing good will come from the rehashing.
bool allSameCode = true;
// Try to find the node
do {
allSameCode = allSameCode && (code == n->hashCode);
if ((code == n->hashCode) && (n->entry.key == key)) {
// Replace the existing node.
n->entry.value = value;
return;
}
n = n->next;
++bucketLength;
} while (n != NULL);
const size_t maxBucketLength = 5;
if ((bucketLength > maxBucketLength) & ! allSameCode && (numBuckets < _size * 20)) {
// This bucket was really large; rehash if all elements
// don't have the same hashcode the number of buckets is reasonable.
resize(numBuckets * 2 + 1);
}
// Not found; insert at the head.
b = code % numBuckets;
bucket[b] = new Node(key, value, code, bucket[b]);
++_size;
}
/**
Removes an element from the table if it is present. It is an error
to remove an element that isn't present.
*/
void remove(const Key& key) {
size_t code = ::hashCode(key);
size_t b = code % numBuckets;
// Go to the bucket
Node* n = bucket[b];
// Make sure it was found
alwaysAssertM(n != NULL, "Tried to remove a key that was not in the table.");
Node* previous = NULL;
// Try to find the node
do {
if ((code == n->hashCode) && (n->entry.key == key)) {
// This is the node; remove it
if (previous == NULL) {
bucket[b] = n->next;
} else {
previous->next = n->next;
}
// Delete the node
delete n;
--_size;
return;
}
previous = n;
n = n->next;
} while (n != NULL);
alwaysAssertM(false, "Tried to remove a key that was not in the table.");
}
/**
Returns the value associated with key.
@deprecated Use get(key, val) or
*/
Value& get(const Key& key) const {
size_t code = ::hashCode(key);
size_t b = code % numBuckets;
Node* node = bucket[b];
while (node != NULL) {
if ((node->hashCode == code) && (node->entry.key == key)) {
return node->entry.value;
}
node = node->next;
}
debugAssertM(false, "Key not found");
// The next line is here just to make
// a compiler warning go away.
return node->entry.value;
}
/**
If the key is present in the table, val is set to the associated value and returns true.
If the key is not present, returns false.
*/
bool get(const Key& key, Value& val) const {
size_t code = ::hashCode(key);
size_t b = code % numBuckets;
Node* node = bucket[b];
while (node != NULL) {
if ((node->hashCode == code) && (node->entry.key == key)) {
// found key
val = node->entry.value;
return true;
}
node = node->next;
}
// Failed to find key
return false;
}
/**
Returns true if key is in the table.
*/
bool containsKey(const Key& key) const {
size_t code = ::hashCode(key);
size_t b = code % numBuckets;
Node* node = bucket[b];
while (node != NULL) {
if ((node->hashCode == code) && (node->entry.key == key)) {
return true;
}
node = node->next;
} while (node != NULL);
return false;
}
/**
Short syntax for get.
*/
inline Value& operator[](const Key &key) const {
return get(key);
}
/**
Returns an array of all of the keys in the table.
You can iterate over the keys to get the values.
*/
Array<Key> getKeys() const {
Array<Key> keyArray;
getKeys(keyArray);
return keyArray;
}
void getKeys(Array<Key>& keyArray) const {
keyArray.resize(0, DONT_SHRINK_UNDERLYING_ARRAY);
for (size_t i = 0; i < numBuckets; i++) {
Node* node = bucket[i];
while (node != NULL) {
keyArray.append(node->entry.key);
node = node->next;
}
}
}
/**
Calls delete on all of the keys. Does not clear the table,
however, so you are left with a table of dangling pointers.
Same as <CODE>getKeys().deleteAll();</CODE>
To delete all of the values, you may want something like
<PRE>
Array<Key> keys = table.getKeys();
Set<Value> value;
for (size_t k = 0; k < keys.length(); k++) {
value.insert(keys[k]);
}
value.getMembers().deleteAll();
keys.deleteAll();
</PRE>
*/
void deleteKeys() {
getKeys().deleteAll();
}
/**
Calls delete on all of the values. This is unsafe--
do not call unless you know that each value appears
at most once.
Does not clear the table, so you are left with a table
of dangling pointers.
*/
void deleteValues() {
for (size_t i = 0; i < numBuckets; i++) {
Node* node = bucket[i];
while (node != NULL) {
delete node->entry.value;
node = node->next;
}
}
}
};
} // namespace
#endif
#ifdef G3D_WIN32
# pragma warning (pop)
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -