tclhash.c
来自「tcl是工具命令语言」· C语言 代码 · 共 1,204 行 · 第 1/3 页
C
1,204 行
/* * tclHash.c -- * * Implementation of in-memory hash tables for Tcl and Tcl-based * applications. * * Copyright (c) 1991-1993 The Regents of the University of California. * Copyright (c) 1994 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * RCS: @(#) $Id: tclHash.c,v 1.12 2002/11/12 02:23:18 hobbs Exp $ */#include "tclInt.h"/* * Prevent macros from clashing with function definitions. */#if TCL_PRESERVE_BINARY_COMPATABILITY# undef Tcl_FindHashEntry# undef Tcl_CreateHashEntry#endif/* * When there are this many entries per bucket, on average, rebuild * the hash table to make it larger. */#define REBUILD_MULTIPLIER 3/* * The following macro takes a preliminary integer hash value and * produces an index into a hash tables bucket list. The idea is * to make it so that preliminary values that are arbitrarily similar * will end up in different buckets. The hash function was taken * from a random-number generator. */#define RANDOM_INDEX(tablePtr, i) \ (((((long) (i))*1103515245) >> (tablePtr)->downShift) & (tablePtr)->mask)/* * Prototypes for the array hash key methods. */static Tcl_HashEntry * AllocArrayEntry _ANSI_ARGS_(( Tcl_HashTable *tablePtr, VOID *keyPtr));static int CompareArrayKeys _ANSI_ARGS_(( VOID *keyPtr, Tcl_HashEntry *hPtr));static unsigned int HashArrayKey _ANSI_ARGS_(( Tcl_HashTable *tablePtr, VOID *keyPtr));/* * Prototypes for the one word hash key methods. */#if 0static Tcl_HashEntry * AllocOneWordEntry _ANSI_ARGS_(( Tcl_HashTable *tablePtr, VOID *keyPtr));static int CompareOneWordKeys _ANSI_ARGS_(( VOID *keyPtr, Tcl_HashEntry *hPtr));static unsigned int HashOneWordKey _ANSI_ARGS_(( Tcl_HashTable *tablePtr, VOID *keyPtr));#endif/* * Prototypes for the string hash key methods. */static Tcl_HashEntry * AllocStringEntry _ANSI_ARGS_(( Tcl_HashTable *tablePtr, VOID *keyPtr));static int CompareStringKeys _ANSI_ARGS_(( VOID *keyPtr, Tcl_HashEntry *hPtr));static unsigned int HashStringKey _ANSI_ARGS_(( Tcl_HashTable *tablePtr, VOID *keyPtr));/* * Procedure prototypes for static procedures in this file: */#if TCL_PRESERVE_BINARY_COMPATABILITYstatic Tcl_HashEntry * BogusFind _ANSI_ARGS_((Tcl_HashTable *tablePtr, CONST char *key));static Tcl_HashEntry * BogusCreate _ANSI_ARGS_((Tcl_HashTable *tablePtr, CONST char *key, int *newPtr));#endifstatic void RebuildTable _ANSI_ARGS_((Tcl_HashTable *tablePtr));Tcl_HashKeyType tclArrayHashKeyType = { TCL_HASH_KEY_TYPE_VERSION, /* version */ TCL_HASH_KEY_RANDOMIZE_HASH, /* flags */ HashArrayKey, /* hashKeyProc */ CompareArrayKeys, /* compareKeysProc */ AllocArrayEntry, /* allocEntryProc */ NULL /* freeEntryProc */};Tcl_HashKeyType tclOneWordHashKeyType = { TCL_HASH_KEY_TYPE_VERSION, /* version */ 0, /* flags */ NULL, /* HashOneWordKey, */ /* hashProc */ NULL, /* CompareOneWordKey, */ /* compareProc */ NULL, /* AllocOneWordKey, */ /* allocEntryProc */ NULL /* FreeOneWordKey, */ /* freeEntryProc */};Tcl_HashKeyType tclStringHashKeyType = { TCL_HASH_KEY_TYPE_VERSION, /* version */ 0, /* flags */ HashStringKey, /* hashKeyProc */ CompareStringKeys, /* compareKeysProc */ AllocStringEntry, /* allocEntryProc */ NULL /* freeEntryProc */};/* *---------------------------------------------------------------------- * * Tcl_InitHashTable -- * * Given storage for a hash table, set up the fields to prepare * the hash table for use. * * Results: * None. * * Side effects: * TablePtr is now ready to be passed to Tcl_FindHashEntry and * Tcl_CreateHashEntry. * *---------------------------------------------------------------------- */#undef Tcl_InitHashTablevoidTcl_InitHashTable(tablePtr, keyType) register Tcl_HashTable *tablePtr; /* Pointer to table record, which * is supplied by the caller. */ int keyType; /* Type of keys to use in table: * TCL_STRING_KEYS, TCL_ONE_WORD_KEYS, * or an integer >= 2. */{ /* * Use a special value to inform the extended version that it must * not access any of the new fields in the Tcl_HashTable. If an * extension is rebuilt then any calls to this function will be * redirected to the extended version by a macro. */ Tcl_InitCustomHashTable(tablePtr, keyType, (Tcl_HashKeyType *) -1);}/* *---------------------------------------------------------------------- * * Tcl_InitCustomHashTable -- * * Given storage for a hash table, set up the fields to prepare * the hash table for use. This is an extended version of * Tcl_InitHashTable which supports user defined keys. * * Results: * None. * * Side effects: * TablePtr is now ready to be passed to Tcl_FindHashEntry and * Tcl_CreateHashEntry. * *---------------------------------------------------------------------- */voidTcl_InitCustomHashTable(tablePtr, keyType, typePtr) register Tcl_HashTable *tablePtr; /* Pointer to table record, which * is supplied by the caller. */ int keyType; /* Type of keys to use in table: * TCL_STRING_KEYS, TCL_ONE_WORD_KEYS, * TCL_CUSTOM_TYPE_KEYS, * TCL_CUSTOM_PTR_KEYS, or an * integer >= 2. */ Tcl_HashKeyType *typePtr; /* Pointer to structure which defines * the behaviour of this table. */{#if (TCL_SMALL_HASH_TABLE != 4) panic("Tcl_InitCustomHashTable: TCL_SMALL_HASH_TABLE is %d, not 4\n", TCL_SMALL_HASH_TABLE);#endif tablePtr->buckets = tablePtr->staticBuckets; tablePtr->staticBuckets[0] = tablePtr->staticBuckets[1] = 0; tablePtr->staticBuckets[2] = tablePtr->staticBuckets[3] = 0; tablePtr->numBuckets = TCL_SMALL_HASH_TABLE; tablePtr->numEntries = 0; tablePtr->rebuildSize = TCL_SMALL_HASH_TABLE*REBUILD_MULTIPLIER; tablePtr->downShift = 28; tablePtr->mask = 3; tablePtr->keyType = keyType;#if TCL_PRESERVE_BINARY_COMPATABILITY tablePtr->findProc = Tcl_FindHashEntry; tablePtr->createProc = Tcl_CreateHashEntry; if (typePtr == NULL) { /* * The caller has been rebuilt so the hash table is an extended * version. */ } else if (typePtr != (Tcl_HashKeyType *) -1) { /* * The caller is requesting a customized hash table so it must be * an extended version. */ tablePtr->typePtr = typePtr; } else { /* * The caller has not been rebuilt so the hash table is not * extended. */ }#else if (typePtr == NULL) { /* * Use the key type to decide which key type is needed. */ if (keyType == TCL_STRING_KEYS) { typePtr = &tclStringHashKeyType; } else if (keyType == TCL_ONE_WORD_KEYS) { typePtr = &tclOneWordHashKeyType; } else if (keyType == TCL_CUSTOM_TYPE_KEYS) { Tcl_Panic ("No type structure specified for TCL_CUSTOM_TYPE_KEYS"); } else if (keyType == TCL_CUSTOM_PTR_KEYS) { Tcl_Panic ("No type structure specified for TCL_CUSTOM_PTR_KEYS"); } else { typePtr = &tclArrayHashKeyType; } } else if (typePtr == (Tcl_HashKeyType *) -1) { /* * If the caller has not been rebuilt then we cannot continue as * the hash table is not an extended version. */ Tcl_Panic ("Hash table is not compatible"); } tablePtr->typePtr = typePtr;#endif}/* *---------------------------------------------------------------------- * * Tcl_FindHashEntry -- * * Given a hash table find the entry with a matching key. * * Results: * The return value is a token for the matching entry in the * hash table, or NULL if there was no matching entry. * * Side effects: * None. * *---------------------------------------------------------------------- */Tcl_HashEntry *Tcl_FindHashEntry(tablePtr, key) Tcl_HashTable *tablePtr; /* Table in which to lookup entry. */ CONST char *key; /* Key to use to find matching entry. */{ register Tcl_HashEntry *hPtr; Tcl_HashKeyType *typePtr; unsigned int hash; int index;#if TCL_PRESERVE_BINARY_COMPATABILITY 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; }#else typePtr = tablePtr->typePtr; if (typePtr == NULL) { Tcl_Panic("called Tcl_FindHashEntry on deleted table"); return NULL; }#endif 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 = (unsigned int) key; index = RANDOM_INDEX (tablePtr, hash); } /* * Search all of the entries in the appropriate bucket. */ if (typePtr->compareKeysProc) { for (hPtr = tablePtr->buckets[index]; hPtr != NULL; hPtr = hPtr->nextPtr) {#if TCL_HASH_KEY_STORE_HASH if (hash != (unsigned int) hPtr->hash) { continue; }#endif if (typePtr->compareKeysProc ((VOID *) key, hPtr)) { return hPtr; } } } else { for (hPtr = tablePtr->buckets[index]; hPtr != NULL; hPtr = hPtr->nextPtr) {#if TCL_HASH_KEY_STORE_HASH if (hash != (unsigned int) hPtr->hash) { continue; }#endif if (key == hPtr->key.oneWordValue) { return hPtr; } } } return NULL;}/* *---------------------------------------------------------------------- * * Tcl_CreateHashEntry -- * * Given a hash table with string keys, and a string key, find * the entry with a matching key. If there is no matching entry, * then create a new entry that does match. * * Results: * The return value is a pointer to the matching entry. If this * is a newly-created entry, then *newPtr will be set to a non-zero * value; otherwise *newPtr will be set to 0. If this is a new * entry the value stored in the entry will initially be 0. * * Side effects: * A new entry may be added to the hash table. * *---------------------------------------------------------------------- */Tcl_HashEntry *Tcl_CreateHashEntry(tablePtr, key, newPtr) 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; Tcl_HashKeyType *typePtr; unsigned int hash; int index;#if TCL_PRESERVE_BINARY_COMPATABILITY 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; }#else typePtr = tablePtr->typePtr; if (typePtr == NULL) { Tcl_Panic("called Tcl_CreateHashEntry on deleted table"); return NULL; }#endif if (typePtr->hashKeyProc) { hash = typePtr->hashKeyProc (tablePtr, (VOID *) key); if (typePtr->flags & TCL_HASH_KEY_RANDOMIZE_HASH) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?