static void RebuildTable(HashTable *tablePtr) { unsigned int oldSize, count, idx; HashEntry **oldBuckets; HashEntry **oldChainPtr, **newChainPtr; HashEntry *hPtr; oldSize = tablePtr->numBuckets; oldBuckets = tablePtr->buckets; /* * Allocate and initialize the new bucket array, and set up * hashing constants for new array size. */ tablePtr->numBuckets *= 4; tablePtr->buckets = (HashEntry **)malloc(tablePtr->numBuckets * sizeof(HashEntry *)); for (count = tablePtr->numBuckets, newChainPtr = tablePtr->buckets; count > 0; count--, newChainPtr++) { *newChainPtr = NULL; } tablePtr->rebuildSize *= 4; tablePtr->downShift -= 2; tablePtr->mask = (tablePtr->mask << 2) + 3; /* * Rehash all of the existing entries into the new bucket array. */ for (oldChainPtr = oldBuckets; oldSize > 0; oldSize--, oldChainPtr++) { for (hPtr = *oldChainPtr; hPtr != NULL; hPtr = *oldChainPtr) { *oldChainPtr = hPtr->nextPtr; if (tablePtr->keyLen == HASH_STRING_KEYS) { idx = HashString(hPtr->key.string) & tablePtr->mask; } else if (tablePtr->keyLen == HASH_ONE_WORD_KEYS) { idx = RANDOM_INDEX(tablePtr, hPtr->key.oneWordKey); } else { idx = HashArray(tablePtr, (const void *)hPtr->key.bytes); idx = RANDOM_INDEX(tablePtr, idx); } hPtr->bucketPtr = &(tablePtr->buckets[idx]); hPtr->nextPtr = *hPtr->bucketPtr; *hPtr->bucketPtr = hPtr; } } /* * Free up the old bucket array, if it was dynamically allocated. */ if (oldBuckets != tablePtr->staticBuckets) { free((char *) oldBuckets); } }
void Tcl_DeleteHashEntry( Tcl_HashEntry *entryPtr) { register Tcl_HashEntry *prevPtr; const Tcl_HashKeyType *typePtr; Tcl_HashTable *tablePtr; Tcl_HashEntry **bucketPtr; #if TCL_HASH_KEY_STORE_HASH int index; #endif tablePtr = entryPtr->tablePtr; if (tablePtr->keyType == TCL_STRING_KEYS) { typePtr = &tclStringHashKeyType; } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) { typePtr = &tclOneWordHashKeyType; } else if (tablePtr->keyType == TCL_CUSTOM_TYPE_KEYS || tablePtr->keyType == TCL_CUSTOM_PTR_KEYS) { typePtr = tablePtr->typePtr; } else { typePtr = &tclArrayHashKeyType; } #if TCL_HASH_KEY_STORE_HASH if (typePtr->hashKeyProc == NULL || typePtr->flags & TCL_HASH_KEY_RANDOMIZE_HASH) { index = RANDOM_INDEX (tablePtr, entryPtr->hash); } else { index = PTR2UINT(entryPtr->hash) & tablePtr->mask; } bucketPtr = &(tablePtr->buckets[index]); #else bucketPtr = entryPtr->bucketPtr; #endif if (*bucketPtr == entryPtr) { *bucketPtr = entryPtr->nextPtr; } else { for (prevPtr = *bucketPtr; ; prevPtr = prevPtr->nextPtr) { if (prevPtr == NULL) { Tcl_Panic("malformed bucket chain in Tcl_DeleteHashEntry"); } if (prevPtr->nextPtr == entryPtr) { prevPtr->nextPtr = entryPtr->nextPtr; break; } } } tablePtr->numEntries--; if (typePtr->freeEntryProc) { typePtr->freeEntryProc (entryPtr); } else { ckfree((char *) entryPtr); } }
static HashEntry * ArrayCreate(HashTable *tablePtr, const void *key, int *newPtr) { #if 0 HashTable *tablePtr; /* Table in which to lookup entry. */ const void *key; /* Key to use to find or create matching * entry. */ int *newPtr; /* Store info here telling whether a new * entry was created. */ #endif HashEntry *hPtr = NULL; unsigned int idx = HashArray(tablePtr, key); idx = RANDOM_INDEX(tablePtr, idx); /* * Search all of the entries in the appropriate bucket. */ for (hPtr = tablePtr->buckets[idx]; hPtr != NULL; hPtr = hPtr->nextPtr) { if (memcmp(key, (void *)hPtr->key.bytes, tablePtr->keyLen) == 0) { *newPtr = 0; return hPtr; } } /* * Entry not found. Add a new one to the bucket. */ hPtr = (HashEntry *)malloc(sizeof(HashEntry) - sizeof(hPtr->key) + tablePtr->keyLen); if (hPtr != NULL) { *newPtr = 1; hPtr->tablePtr = tablePtr; hPtr->bucketPtr = &(tablePtr->buckets[idx]); hPtr->nextPtr = *hPtr->bucketPtr; hPtr->clientData = 0; (void)memcpy((void *)hPtr->key.bytes, key, tablePtr->keyLen); *hPtr->bucketPtr = hPtr; tablePtr->numEntries++; /* * If the table has exceeded a decent size, rebuild it with many * more buckets. */ if (tablePtr->numEntries >= tablePtr->rebuildSize) { RebuildTable(tablePtr); } } else { *newPtr = 0; } return hPtr; }
static HashEntry * OneWordCreate(HashTable *tablePtr, const void *key, int *newPtr) { #if 0 HashTable *tablePtr; /* Table in which to lookup entry. */ const void *key; /* Key to use to find or create matching * entry. */ int *newPtr; /* Store info here telling whether a new * entry was created. */ #endif HashEntry *hPtr; unsigned int idx; idx = RANDOM_INDEX(tablePtr, key); /* * Search all of the entries in this bucket. */ for (hPtr = tablePtr->buckets[idx]; hPtr != NULL; hPtr = hPtr->nextPtr) { if (hPtr->key.oneWordKey == key) { *newPtr = 0; return hPtr; } } /* * Entry not found. Add a new one to the bucket. */ hPtr = (HashEntry *)malloc(sizeof(HashEntry)); if (hPtr != NULL) { *newPtr = 1; hPtr->tablePtr = tablePtr; hPtr->bucketPtr = &(tablePtr->buckets[idx]); hPtr->nextPtr = *hPtr->bucketPtr; hPtr->clientData = 0; hPtr->key.oneWordKey = key; *hPtr->bucketPtr = hPtr; tablePtr->numEntries++; /* * If the table has exceeded a decent size, rebuild it with * many more buckets. */ if (tablePtr->numEntries >= tablePtr->rebuildSize) { RebuildTable(tablePtr); } } else { *newPtr = 0; } return hPtr; }
static hash_entry_t * hash_lookup_internal(hash_t * tablePtr, void *key) { hash_entry_t *hPtr; unsigned int hash; int i; if (tablePtr->hashKeyFn) { hash = tablePtr->hashKeyFn(key); i = hash & tablePtr->mask; } else { hash = (unsigned int) key; i = RANDOM_INDEX(tablePtr, hash); } /* * Search all of the entries in the appropriate bucket. */ if (tablePtr->compareKeysFn) { compare_hash_keys_fn compareKeysFn = tablePtr->compareKeysFn; for (hPtr = tablePtr->buckets[i]; hPtr != NULL; hPtr = hPtr->nextPtr) { if (hash != (unsigned int) hPtr->hash) { continue; } if (compareKeysFn(key, hPtr->key) == 0) { return hPtr; } } } else { for (hPtr = tablePtr->buckets[i]; hPtr != NULL; hPtr = hPtr->nextPtr) { if (hash != (unsigned int) hPtr->hash) { continue; } if (key == hPtr->key) { return hPtr; } } } return NULL; }
static int hash_remove_internal(hash_t * tablePtr, void *key) { hash_entry_t *entryPtr; hash_entry_t **bucketPtr; int i; entryPtr = hash_lookup_internal(tablePtr, key); if (entryPtr == NULL) return 0; if (tablePtr->hashKeyFn) { i = ((unsigned int) entryPtr->hash) & tablePtr->mask; } else { i = RANDOM_INDEX(tablePtr, entryPtr->hash); } bucketPtr = &(tablePtr->buckets[i]); return hash_remove_entry_internal(tablePtr, bucketPtr, entryPtr); }
static HashEntry * ArrayFind(HashTable *tablePtr, const void *key) { #if 0 HashTable *tablePtr; /* Table in which to lookup entry. */ const void *key; /* Key to use to find matching entry. */ #endif HashEntry *hPtr; unsigned int idx = HashArray(tablePtr, key); idx = RANDOM_INDEX(tablePtr, idx); /* * Search all of the entries in the appropriate bucket. */ for (hPtr = tablePtr->buckets[idx]; hPtr != NULL; hPtr = hPtr->nextPtr) { if (memcmp(key, (void *)hPtr->key.bytes, tablePtr->keyLen) == 0) { return hPtr; } } return NULL; }
static HashEntry * OneWordFind(HashTable *tablePtr, const void *key) { #if 0 HashTable *tablePtr; /* Table in which to lookup entry. */ const void *key; /* Key to use to find matching entry. */ #endif HashEntry *hPtr; unsigned int idx; idx = RANDOM_INDEX(tablePtr, key); /* * Search all of the entries in the appropriate bucket. */ for (hPtr = tablePtr->buckets[idx]; hPtr != NULL; hPtr = hPtr->nextPtr) { if (hPtr->key.oneWordKey == key) { return hPtr; } } return NULL; }
static void RebuildTable( register Tcl_HashTable *tablePtr) /* Table to enlarge. */ { int oldSize, count, index; Tcl_HashEntry **oldBuckets; register Tcl_HashEntry **oldChainPtr, **newChainPtr; register Tcl_HashEntry *hPtr; const Tcl_HashKeyType *typePtr; if (tablePtr->keyType == TCL_STRING_KEYS) { typePtr = &tclStringHashKeyType; } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) { typePtr = &tclOneWordHashKeyType; } else if (tablePtr->keyType == TCL_CUSTOM_TYPE_KEYS || tablePtr->keyType == TCL_CUSTOM_PTR_KEYS) { typePtr = tablePtr->typePtr; } else { typePtr = &tclArrayHashKeyType; } oldSize = tablePtr->numBuckets; oldBuckets = tablePtr->buckets; /* * Allocate and initialize the new bucket array, and set up hashing * constants for new array size. */ tablePtr->numBuckets *= 4; if (typePtr->flags & TCL_HASH_KEY_SYSTEM_HASH) { tablePtr->buckets = (Tcl_HashEntry **) TclpSysAlloc((unsigned) (tablePtr->numBuckets * sizeof(Tcl_HashEntry *)), 0); } else { tablePtr->buckets = (Tcl_HashEntry **) ckalloc((unsigned) (tablePtr->numBuckets * sizeof(Tcl_HashEntry *))); } for (count = tablePtr->numBuckets, newChainPtr = tablePtr->buckets; count > 0; count--, newChainPtr++) { *newChainPtr = NULL; } tablePtr->rebuildSize *= 4; tablePtr->downShift -= 2; tablePtr->mask = (tablePtr->mask << 2) + 3; /* * Rehash all of the existing entries into the new bucket array. */ for (oldChainPtr = oldBuckets; oldSize > 0; oldSize--, oldChainPtr++) { for (hPtr = *oldChainPtr; hPtr != NULL; hPtr = *oldChainPtr) { *oldChainPtr = hPtr->nextPtr; #if TCL_HASH_KEY_STORE_HASH if (typePtr->hashKeyProc == NULL || typePtr->flags & TCL_HASH_KEY_RANDOMIZE_HASH) { index = RANDOM_INDEX (tablePtr, hPtr->hash); } else { index = PTR2UINT(hPtr->hash) & tablePtr->mask; } hPtr->nextPtr = tablePtr->buckets[index]; tablePtr->buckets[index] = hPtr; #else void *key = Tcl_GetHashKey(tablePtr, hPtr); if (typePtr->hashKeyProc) { unsigned int hash; hash = typePtr->hashKeyProc(tablePtr, key); if (typePtr->flags & TCL_HASH_KEY_RANDOMIZE_HASH) { index = RANDOM_INDEX (tablePtr, hash); } else { index = hash & tablePtr->mask; } } else { index = RANDOM_INDEX (tablePtr, key); } hPtr->bucketPtr = &(tablePtr->buckets[index]); hPtr->nextPtr = *hPtr->bucketPtr; *hPtr->bucketPtr = hPtr; #endif } } /* * Free up the old bucket array, if it was dynamically allocated. */ if (oldBuckets != tablePtr->staticBuckets) { if (typePtr->flags & TCL_HASH_KEY_SYSTEM_HASH) { TclpSysFree((char *) oldBuckets); } else { ckfree((char *) oldBuckets); } } }
Tcl_HashEntry * Tcl_CreateHashEntry( Tcl_HashTable *tablePtr, /* Table in which to lookup entry. */ const char *key, /* Key to use to find or create matching * entry. */ int *newPtr) /* Store info here telling whether a new entry * was created. */ { register Tcl_HashEntry *hPtr; const Tcl_HashKeyType *typePtr; unsigned int hash; int index; if (tablePtr->keyType == TCL_STRING_KEYS) { typePtr = &tclStringHashKeyType; } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) { typePtr = &tclOneWordHashKeyType; } else if (tablePtr->keyType == TCL_CUSTOM_TYPE_KEYS || tablePtr->keyType == TCL_CUSTOM_PTR_KEYS) { typePtr = tablePtr->typePtr; } else { typePtr = &tclArrayHashKeyType; } if (typePtr->hashKeyProc) { hash = typePtr->hashKeyProc(tablePtr, (void *) key); if (typePtr->flags & TCL_HASH_KEY_RANDOMIZE_HASH) { index = RANDOM_INDEX (tablePtr, hash); } else { index = hash & tablePtr->mask; } } else { hash = PTR2UINT(key); index = RANDOM_INDEX (tablePtr, hash); } /* * Search all of the entries in the appropriate bucket. */ if (typePtr->compareKeysProc) { Tcl_CompareHashKeysProc *compareKeysProc = typePtr->compareKeysProc; for (hPtr = tablePtr->buckets[index]; hPtr != NULL; hPtr = hPtr->nextPtr) { #if TCL_HASH_KEY_STORE_HASH if (hash != PTR2UINT(hPtr->hash)) { continue; } #endif if (compareKeysProc((void *) key, hPtr)) { if (newPtr) { *newPtr = 0; } return hPtr; } } } else { for (hPtr = tablePtr->buckets[index]; hPtr != NULL; hPtr = hPtr->nextPtr) { #if TCL_HASH_KEY_STORE_HASH if (hash != PTR2UINT(hPtr->hash)) { continue; } #endif if (key == hPtr->key.oneWordValue) { if (newPtr) { *newPtr = 0; } return hPtr; } } } if (!newPtr) { return NULL; } /* * Entry not found. Add a new one to the bucket. */ *newPtr = 1; if (typePtr->allocEntryProc) { hPtr = typePtr->allocEntryProc(tablePtr, (void *) key); } else { hPtr = (Tcl_HashEntry *) ckalloc((unsigned) sizeof(Tcl_HashEntry)); hPtr->key.oneWordValue = (char *) key; hPtr->clientData = 0; } hPtr->tablePtr = tablePtr; #if TCL_HASH_KEY_STORE_HASH hPtr->hash = UINT2PTR(hash); hPtr->nextPtr = tablePtr->buckets[index]; tablePtr->buckets[index] = hPtr; #else hPtr->bucketPtr = &(tablePtr->buckets[index]); hPtr->nextPtr = *hPtr->bucketPtr; *hPtr->bucketPtr = hPtr; #endif tablePtr->numEntries++; /* * If the table has exceeded a decent size, rebuild it with many more * buckets. */ if (tablePtr->numEntries >= tablePtr->rebuildSize) { RebuildTable(tablePtr); } return hPtr; }
static int hash_insert_internal(hash_t * tablePtr, void *key, void *value) { hash_entry_t *hPtr; unsigned int hash; int i; if (tablePtr->hashKeyFn) { hash = tablePtr->hashKeyFn(key); i = hash & tablePtr->mask; } else { hash = (unsigned int) key; i = RANDOM_INDEX(tablePtr, hash); } /* * Search all of the entries in the appropriate bucket. */ if (tablePtr->compareKeysFn) { compare_hash_keys_fn compareKeysFn = tablePtr->compareKeysFn; for (hPtr = tablePtr->buckets[i]; hPtr != NULL; hPtr = hPtr->nextPtr) { if (hash != (unsigned int) hPtr->hash) { continue; } if (compareKeysFn(key, hPtr->key) == 0) { if (tablePtr->valueDestroyFn && value != hPtr->value) tablePtr->valueDestroyFn(hPtr->value); hPtr->value = value; return 0; } } } else { for (hPtr = tablePtr->buckets[i]; hPtr != NULL; hPtr = hPtr->nextPtr) { if (hash != (unsigned int) hPtr->hash) { continue; } if (key == hPtr->key) { if (tablePtr->valueDestroyFn && value != hPtr->value) tablePtr->valueDestroyFn(hPtr->value); hPtr->value = value; return 0; } } } /* * Entry not found. Add a new one to the bucket. */ hPtr = alc_calloc(tablePtr->alc, 1, sizeof(hash_entry_t)); hPtr->key = key; hPtr->value = value; hPtr->tablePtr = tablePtr; hPtr->hash = hash; hPtr->nextPtr = tablePtr->buckets[i]; tablePtr->buckets[i] = hPtr; tablePtr->numEntries++; /* * If the table has exceeded a decent size, rebuild it with many * more buckets. */ if (tablePtr->numEntries >= tablePtr->rebuildSize) { rebuild_table(tablePtr); } return 1; }