Exemple #1
0
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);
  }
}
Exemple #2
0
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);
    }
}
Exemple #3
0
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;
}
Exemple #4
0
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;
}
Exemple #5
0
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;
}
Exemple #6
0
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);
}
Exemple #7
0
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;
}
Exemple #8
0
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;
}
Exemple #9
0
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);
	}
    }
}
Exemple #10
0
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;
}
Exemple #11
0
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;
}