📄 dict.h
字号:
/* dict.H * John Viega * * September 1995 * Converted to C++ somewhere along the line. */#ifndef __DICT_H__#define __DICT_H__#include "fatal.H"#include <stdlib.h>#include <stdio.h>#ifdef ITS_DEBUG#include <assert.h>#else#define assert(x)#endifvoid InitDummyBucket();extern unsigned long primes[];/* ** This constant is used to signify where a key was there but has been** deleted. */#define INVALID (char *)~0template<class T> struct dictBucket{ char *key; T *value;};template<class T> class Dictionary{public: /* ** Dictionary<T>::SetItem(char *key, T* value) ** ** Inserts the key : value pair into dicttable h. If such an ** insertation would make the hash table full enough to resize, ** as defined by rehashSize then the hash table is expanded. */ void SetItem(char *key, T* value) { unsigned int dictkey = 0; unsigned int dict2 = 0; unsigned int i = 0; assert(key != NULL); assert(key != INVALID); /* ** First check to see if the key is already there, ** and if it is, just replace the value. */ dictkey = Hash(key, numBuckets); dict2 = Hash(key, secondHash); if(!dict2) { dict2 = 1; } assert(dictkey < numBuckets); /* ** We don't want to do this forever, if the table is full, stop ** when we've checked all of the buckets. */ for(i=0;i<numBuckets;i++) { /* ** When we find an unused bucket, we can stop, we've never hashed ** this key before, or we would have found it by now. */ if(buckets[dictkey].key == NULL) { break; } /* ** We've found the key in the hashtable. Just replace the value ** and return. */ if(!strcmp(buckets[dictkey].key, key)) { buckets[dictkey].value = value; return; } dictkey += dict2; dictkey %= numBuckets; } if(((100.*(++numKeys))/numBuckets) >= rehashSize) { Expand(); /* Recompute the dict keys because we resized. */ dictkey = Hash(key, numBuckets); dict2 = Hash(key, secondHash); if(!dict2) { dict2 = 1; } } assert(dictkey < numBuckets); while((buckets[dictkey].key != NULL) && (buckets[dictkey].key != INVALID)) { dictkey += dict2; dictkey %= numBuckets; } buckets[dictkey].key = key; buckets[dictkey].value = value; } /* ** T* Dictionary<T>::GetItem(char *key, short& error) ** ** Returns the T* you passed in as a value, given the key. It sets ** error to 1 and returns null if the key isn't in the hash table. ** */ T* GetItem(char *key, short& error) { unsigned int dictkey, dict2, i; assert(key != NULL); assert(key != INVALID); error = 0; dictkey = Hash(key, numBuckets); dict2 = Hash(key, secondHash); if(!dict2) { dict2 = 1; } assert(dictkey < numBuckets); assert(dict2 < numBuckets); for(i=0;i<numBuckets;i++) { if(buckets[dictkey].key == NULL) { error = 1; return NULL; } if(!strcmp(buckets[dictkey].key, key)) { return buckets[dictkey].value; } dictkey += dict2; dictkey %= numBuckets; } /* Only get here if the table was full. */ error = 1; return NULL; } /* ** T* Dictionary<T>::DeleteItem(char *key, short& error) ** ** Deletes the key from the dict table h. Returns the value if the key ** was in the map, or else returns NULL and sets error. */ T* DeleteItem(char *key, short& error) { unsigned int dictkey, dict2, i; error = 0; assert(key != NULL); assert(key != INVALID); dictkey = Hash(key, numBuckets); dict2 = Hash(key, secondHash); if(!dict2) { dict2 = 1; } assert(dictkey < numBuckets); for(i=0;i<numBuckets;i++) { if(buckets[dictkey].key == NULL) { error = 1; return NULL; } if(!strcmp(buckets[dictkey].key,key)) { buckets[dictkey].key = INVALID; numKeys--; return buckets[dictkey].value; } dictkey += dict2; dictkey %= numBuckets; } error = 1; return NULL; } /* ** Dictionary<T>::Dictionary(int sizeIndex) ** ** Allocate a new Dictionary. The sizeIndex determines how many items ** the dict table will hold. Note that unless you make REHASH_SIZE 1, ** not all of these slots will be used before rehashing occurs. ** Here are the valid values: ** ** sizeIndex Size of Dict Table Rehashes At n Keys ** 1 7 6 ** 2 13 10 ** 3 31 24 ** 4 61 46 ** 5 127 96 ** 6 251 189 ** 7 509 382 ** 8 1021 766 ** 9 2017 1513 ** 10 4093 3070 ** 11 5987 4491 ** 12 9551 7164 ** 13 15683 11762 ** 14 19609 14707 ** 15 31397 23578 ** 16 65521 49141 ** 17 131071 98304 ** 18 262139 196605 ** 19 524287 393216 ** 20 1048573 786430 ** 21 2097143 1572858 ** 22 4194301 3145726 ** 23 8388593 6291445 ** 24 16777213 12582910 ** 25 33554393 25165795 ** 26 67108859 50331645 ** 27 134217689 100663267 ** 28 268435399 201326550 ** 29 536870909 402653182 ** 30 1073741789 none (805306342) */ Dictionary(int sizeIndex) { unsigned int i; InitDummyBucket(); assert(sizeIndex > 0); assert(sizeIndex < 30); rehashSize = 75.; numBuckets = primes[sizeIndex]; numKeys = 0; secondHash = primes[sizeIndex-1]; buckets = new dictBucket<T>[numBuckets]; if(!buckets) OutOfMemory(); for(i=0; i<numBuckets;i++) { buckets[i].key = NULL; } } Dictionary(int sizeIndex, double r) { assert(r>0 && r<=100); assert(sizeIndex > 0); assert(sizeIndex < 30); rehashSize = r; numBuckets = primes[sizeIndex]; numKeys = 0; secondHash = primes[sizeIndex-1]; buckets = new dictBucket<T>[numBuckets]; if(!buckets) OutOfMemory(); for(unsigned int i=0; i<numBuckets;i++) { buckets[i].key = NULL; } } unsigned int GetNumKeys() { return numKeys; } // Note: no bounds check. Use with caution! void GetKeys(char **outbuf) { int j = 0; for(unsigned int i=0;i<numBuckets;i++) { if(buckets[i].key != NULL && buckets[i].key != INVALID) { outbuf[j++] = buckets[i].key; } } }private: unsigned int Hash(char *str, int pri) { unsigned int hashval = 0; while(*str != '\0') { hashval = *str + 31 * hashval; str++; } return hashval % pri; } /* ** This is what actually expands the hash table, when you insert something ** and the table is too full, and needs to expand. ** Note that this needs to be atomic. */ void Expand() { dictBucket<T> *oldBuckets; unsigned int i; i = FindNextSize(); secondHash = numBuckets; numBuckets = primes[i]; oldBuckets = buckets; buckets = new dictBucket<T>[numBuckets]; if(!buckets) OutOfMemory(); for(i=0;i<numBuckets;i++) { buckets[i].key = NULL; } numKeys = 0; // We're about to add them back in. for(i = 0; i < secondHash; i++) { if(oldBuckets[i].key != NULL && oldBuckets[i].key != INVALID) { SetItem(oldBuckets[i].key, oldBuckets[i].value); } } delete[] oldBuckets; } /* ** Given the current size of the dict table, this scans the list ** of primes until it finds where in that list you are. Then ** it gives you the new index you should use for expanding your ** dict table. */ int FindNextSize() { int i = 0; while(1) { assert(primes[i]); if(primes[i] == numBuckets) { /* If this fails, you asked for too big of a dict table. */ assert(primes[i+1]); return i+1; } i++; } } dictBucket<T> *buckets; unsigned int numBuckets; unsigned int numKeys; unsigned int secondHash; double rehashSize;};// If you need it.struct DummyBucket{};extern DummyBucket *dummy_bucket;#endif /* __DICT_H__ */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -