os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclHash.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 /* 
     2  * tclHash.c --
     3  *
     4  *	Implementation of in-memory hash tables for Tcl and Tcl-based
     5  *	applications.
     6  *
     7  * Copyright (c) 1991-1993 The Regents of the University of California.
     8  * Copyright (c) 1994 Sun Microsystems, Inc.
     9  * Portions Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiaries. All rights reserved.  
    10  *
    11  * See the file "license.terms" for information on usage and redistribution
    12  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
    13  *
    14  * RCS: @(#) $Id: tclHash.c,v 1.12.2.1 2004/11/11 01:18:07 das Exp $
    15  */
    16 
    17 #include "tclInt.h"
    18 
    19 /*
    20  * Prevent macros from clashing with function definitions.
    21  */
    22 
    23 #if TCL_PRESERVE_BINARY_COMPATABILITY
    24 #   undef Tcl_FindHashEntry
    25 #   undef Tcl_CreateHashEntry
    26 #endif
    27 
    28 /*
    29  * When there are this many entries per bucket, on average, rebuild
    30  * the hash table to make it larger.
    31  */
    32 
    33 #define REBUILD_MULTIPLIER	3
    34 
    35 /*
    36  * The following macro takes a preliminary integer hash value and
    37  * produces an index into a hash tables bucket list.  The idea is
    38  * to make it so that preliminary values that are arbitrarily similar
    39  * will end up in different buckets.  The hash function was taken
    40  * from a random-number generator.
    41  */
    42 
    43 #define RANDOM_INDEX(tablePtr, i) \
    44     (((((long) (i))*1103515245) >> (tablePtr)->downShift) & (tablePtr)->mask)
    45 
    46 /*
    47  * Prototypes for the array hash key methods.
    48  */
    49 
    50 static Tcl_HashEntry *	AllocArrayEntry _ANSI_ARGS_((
    51 			    Tcl_HashTable *tablePtr,
    52 			    VOID *keyPtr));
    53 static int		CompareArrayKeys _ANSI_ARGS_((
    54 			    VOID *keyPtr, Tcl_HashEntry *hPtr));
    55 static unsigned int	HashArrayKey _ANSI_ARGS_((
    56 			    Tcl_HashTable *tablePtr,
    57 			    VOID *keyPtr));
    58 
    59 /*
    60  * Prototypes for the one word hash key methods.
    61  */
    62 
    63 #if 0
    64 static Tcl_HashEntry *	AllocOneWordEntry _ANSI_ARGS_((
    65 			    Tcl_HashTable *tablePtr,
    66 			    VOID *keyPtr));
    67 static int		CompareOneWordKeys _ANSI_ARGS_((
    68 			    VOID *keyPtr, Tcl_HashEntry *hPtr));
    69 static unsigned int	HashOneWordKey _ANSI_ARGS_((
    70 			    Tcl_HashTable *tablePtr,
    71 			    VOID *keyPtr));
    72 #endif
    73 
    74 /*
    75  * Prototypes for the string hash key methods.
    76  */
    77 
    78 static Tcl_HashEntry *	AllocStringEntry _ANSI_ARGS_((
    79 			    Tcl_HashTable *tablePtr,
    80 			    VOID *keyPtr));
    81 static int		CompareStringKeys _ANSI_ARGS_((
    82 			    VOID *keyPtr, Tcl_HashEntry *hPtr));
    83 static unsigned int	HashStringKey _ANSI_ARGS_((
    84 			    Tcl_HashTable *tablePtr,
    85 			    VOID *keyPtr));
    86 
    87 /*
    88  * Procedure prototypes for static procedures in this file:
    89  */
    90 
    91 #if TCL_PRESERVE_BINARY_COMPATABILITY
    92 static Tcl_HashEntry *	BogusFind _ANSI_ARGS_((Tcl_HashTable *tablePtr,
    93 			    CONST char *key));
    94 static Tcl_HashEntry *	BogusCreate _ANSI_ARGS_((Tcl_HashTable *tablePtr,
    95 			    CONST char *key, int *newPtr));
    96 #endif
    97 
    98 static void		RebuildTable _ANSI_ARGS_((Tcl_HashTable *tablePtr));
    99 
   100 Tcl_HashKeyType tclArrayHashKeyType = {
   101     TCL_HASH_KEY_TYPE_VERSION,		/* version */
   102     TCL_HASH_KEY_RANDOMIZE_HASH,	/* flags */
   103     HashArrayKey,			/* hashKeyProc */
   104     CompareArrayKeys,			/* compareKeysProc */
   105     AllocArrayEntry,			/* allocEntryProc */
   106     NULL				/* freeEntryProc */
   107 };
   108 
   109 Tcl_HashKeyType tclOneWordHashKeyType = {
   110     TCL_HASH_KEY_TYPE_VERSION,		/* version */
   111     0,					/* flags */
   112     NULL, /* HashOneWordKey, */		/* hashProc */
   113     NULL, /* CompareOneWordKey, */	/* compareProc */
   114     NULL, /* AllocOneWordKey, */	/* allocEntryProc */
   115     NULL  /* FreeOneWordKey, */		/* freeEntryProc */
   116 };
   117 
   118 Tcl_HashKeyType tclStringHashKeyType = {
   119     TCL_HASH_KEY_TYPE_VERSION,		/* version */
   120     0,					/* flags */
   121     HashStringKey,			/* hashKeyProc */
   122     CompareStringKeys,			/* compareKeysProc */
   123     AllocStringEntry,			/* allocEntryProc */
   124     NULL				/* freeEntryProc */
   125 };
   126 
   127 
   128 /*
   129  *----------------------------------------------------------------------
   130  *
   131  * Tcl_InitHashTable --
   132  *
   133  *	Given storage for a hash table, set up the fields to prepare
   134  *	the hash table for use.
   135  *
   136  * Results:
   137  *	None.
   138  *
   139  * Side effects:
   140  *	TablePtr is now ready to be passed to Tcl_FindHashEntry and
   141  *	Tcl_CreateHashEntry.
   142  *
   143  *----------------------------------------------------------------------
   144  */
   145 
   146 #undef Tcl_InitHashTable
   147 EXPORT_C void
   148 Tcl_InitHashTable(tablePtr, keyType)
   149     register Tcl_HashTable *tablePtr;	/* Pointer to table record, which
   150 					 * is supplied by the caller. */
   151     int keyType;			/* Type of keys to use in table:
   152 					 * TCL_STRING_KEYS, TCL_ONE_WORD_KEYS,
   153 					 * or an integer >= 2. */
   154 {
   155     /*
   156      * Use a special value to inform the extended version that it must
   157      * not access any of the new fields in the Tcl_HashTable. If an
   158      * extension is rebuilt then any calls to this function will be
   159      * redirected to the extended version by a macro.
   160      */
   161     Tcl_InitCustomHashTable(tablePtr, keyType, (Tcl_HashKeyType *) -1);
   162 }
   163 
   164 /*
   165  *----------------------------------------------------------------------
   166  *
   167  * Tcl_InitCustomHashTable --
   168  *
   169  *	Given storage for a hash table, set up the fields to prepare
   170  *	the hash table for use. This is an extended version of
   171  *	Tcl_InitHashTable which supports user defined keys.
   172  *
   173  * Results:
   174  *	None.
   175  *
   176  * Side effects:
   177  *	TablePtr is now ready to be passed to Tcl_FindHashEntry and
   178  *	Tcl_CreateHashEntry.
   179  *
   180  *----------------------------------------------------------------------
   181  */
   182 
   183 EXPORT_C void
   184 Tcl_InitCustomHashTable(tablePtr, keyType, typePtr)
   185     register Tcl_HashTable *tablePtr;	/* Pointer to table record, which
   186 					 * is supplied by the caller. */
   187     int keyType;			/* Type of keys to use in table:
   188 					 * TCL_STRING_KEYS, TCL_ONE_WORD_KEYS,
   189 					 * TCL_CUSTOM_TYPE_KEYS,
   190 					 * TCL_CUSTOM_PTR_KEYS,  or an
   191 					 * integer >= 2. */
   192     Tcl_HashKeyType *typePtr;		/* Pointer to structure which defines
   193 					 * the behaviour of this table. */
   194 {
   195 #if (TCL_SMALL_HASH_TABLE != 4) 
   196     panic("Tcl_InitCustomHashTable: TCL_SMALL_HASH_TABLE is %d, not 4\n",
   197 	    TCL_SMALL_HASH_TABLE);
   198 #endif
   199     
   200     tablePtr->buckets = tablePtr->staticBuckets;
   201     tablePtr->staticBuckets[0] = tablePtr->staticBuckets[1] = 0;
   202     tablePtr->staticBuckets[2] = tablePtr->staticBuckets[3] = 0;
   203     tablePtr->numBuckets = TCL_SMALL_HASH_TABLE;
   204     tablePtr->numEntries = 0;
   205     tablePtr->rebuildSize = TCL_SMALL_HASH_TABLE*REBUILD_MULTIPLIER;
   206     tablePtr->downShift = 28;
   207     tablePtr->mask = 3;
   208     tablePtr->keyType = keyType;
   209 #if TCL_PRESERVE_BINARY_COMPATABILITY
   210     tablePtr->findProc = Tcl_FindHashEntry;
   211     tablePtr->createProc = Tcl_CreateHashEntry;
   212 
   213     if (typePtr == NULL) {
   214 	/*
   215 	 * The caller has been rebuilt so the hash table is an extended
   216 	 * version.
   217 	 */
   218     } else if (typePtr != (Tcl_HashKeyType *) -1) {
   219 	/*
   220 	 * The caller is requesting a customized hash table so it must be
   221 	 * an extended version.
   222 	 */
   223 	tablePtr->typePtr = typePtr;
   224     } else {
   225 	/*
   226 	 * The caller has not been rebuilt so the hash table is not
   227 	 * extended.
   228 	 */
   229     }
   230 #else
   231     if (typePtr == NULL) {
   232 	/*
   233 	 * Use the key type to decide which key type is needed.
   234 	 */
   235 	if (keyType == TCL_STRING_KEYS) {
   236 	    typePtr = &tclStringHashKeyType;
   237 	} else if (keyType == TCL_ONE_WORD_KEYS) {
   238 	    typePtr = &tclOneWordHashKeyType;
   239 	} else if (keyType == TCL_CUSTOM_TYPE_KEYS) {
   240 	    Tcl_Panic ("No type structure specified for TCL_CUSTOM_TYPE_KEYS");
   241 	} else if (keyType == TCL_CUSTOM_PTR_KEYS) {
   242 	    Tcl_Panic ("No type structure specified for TCL_CUSTOM_PTR_KEYS");
   243 	} else {
   244 	    typePtr = &tclArrayHashKeyType;
   245 	}
   246     } else if (typePtr == (Tcl_HashKeyType *) -1) {
   247 	/*
   248 	 * If the caller has not been rebuilt then we cannot continue as
   249 	 * the hash table is not an extended version.
   250 	 */
   251 	Tcl_Panic ("Hash table is not compatible");
   252     }
   253     tablePtr->typePtr = typePtr;
   254 #endif
   255 }
   256 
   257 /*
   258  *----------------------------------------------------------------------
   259  *
   260  * Tcl_FindHashEntry --
   261  *
   262  *	Given a hash table find the entry with a matching key.
   263  *
   264  * Results:
   265  *	The return value is a token for the matching entry in the
   266  *	hash table, or NULL if there was no matching entry.
   267  *
   268  * Side effects:
   269  *	None.
   270  *
   271  *----------------------------------------------------------------------
   272  */
   273 
   274 EXPORT_C Tcl_HashEntry *
   275 Tcl_FindHashEntry(tablePtr, key)
   276     Tcl_HashTable *tablePtr;	/* Table in which to lookup entry. */
   277     CONST char *key;		/* Key to use to find matching entry. */
   278 {
   279     register Tcl_HashEntry *hPtr;
   280     Tcl_HashKeyType *typePtr;
   281     unsigned int hash;
   282     int index;
   283 
   284 #if TCL_PRESERVE_BINARY_COMPATABILITY
   285     if (tablePtr->keyType == TCL_STRING_KEYS) {
   286 	typePtr = &tclStringHashKeyType;
   287     } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) {
   288 	typePtr = &tclOneWordHashKeyType;
   289     } else if (tablePtr->keyType == TCL_CUSTOM_TYPE_KEYS
   290 	       || tablePtr->keyType == TCL_CUSTOM_PTR_KEYS) {
   291 	typePtr = tablePtr->typePtr;
   292     } else {
   293 	typePtr = &tclArrayHashKeyType;
   294     }
   295 #else
   296     typePtr = tablePtr->typePtr;
   297     if (typePtr == NULL) {
   298 	Tcl_Panic("called Tcl_FindHashEntry on deleted table");
   299 	return NULL;
   300     }
   301 #endif
   302 
   303     if (typePtr->hashKeyProc) {
   304 	hash = typePtr->hashKeyProc (tablePtr, (VOID *) key);
   305 	if (typePtr->flags & TCL_HASH_KEY_RANDOMIZE_HASH) {
   306 	    index = RANDOM_INDEX (tablePtr, hash);
   307 	} else {
   308 	    index = hash & tablePtr->mask;
   309 	}
   310     } else {
   311 	hash = (unsigned int) key;
   312 	index = RANDOM_INDEX (tablePtr, hash);
   313     }
   314 
   315     /*
   316      * Search all of the entries in the appropriate bucket.
   317      */
   318 
   319     if (typePtr->compareKeysProc) {
   320 	Tcl_CompareHashKeysProc *compareKeysProc = typePtr->compareKeysProc;
   321 	for (hPtr = tablePtr->buckets[index]; hPtr != NULL;
   322 	        hPtr = hPtr->nextPtr) {
   323 #if TCL_HASH_KEY_STORE_HASH
   324 	    if (hash != (unsigned int) hPtr->hash) {
   325 		continue;
   326 	    }
   327 #endif
   328 	    if (compareKeysProc ((VOID *) key, hPtr)) {
   329 		return hPtr;
   330 	    }
   331 	}
   332     } else {
   333 	for (hPtr = tablePtr->buckets[index]; hPtr != NULL;
   334 	        hPtr = hPtr->nextPtr) {
   335 #if TCL_HASH_KEY_STORE_HASH
   336 	    if (hash != (unsigned int) hPtr->hash) {
   337 		continue;
   338 	    }
   339 #endif
   340 	    if (key == hPtr->key.oneWordValue) {
   341 		return hPtr;
   342 	    }
   343 	}
   344     }
   345     
   346     return NULL;
   347 }
   348 
   349 /*
   350  *----------------------------------------------------------------------
   351  *
   352  * Tcl_CreateHashEntry --
   353  *
   354  *	Given a hash table with string keys, and a string key, find
   355  *	the entry with a matching key.  If there is no matching entry,
   356  *	then create a new entry that does match.
   357  *
   358  * Results:
   359  *	The return value is a pointer to the matching entry.  If this
   360  *	is a newly-created entry, then *newPtr will be set to a non-zero
   361  *	value;  otherwise *newPtr will be set to 0.  If this is a new
   362  *	entry the value stored in the entry will initially be 0.
   363  *
   364  * Side effects:
   365  *	A new entry may be added to the hash table.
   366  *
   367  *----------------------------------------------------------------------
   368  */
   369 
   370 EXPORT_C Tcl_HashEntry *
   371 Tcl_CreateHashEntry(tablePtr, key, newPtr)
   372     Tcl_HashTable *tablePtr;	/* Table in which to lookup entry. */
   373     CONST char *key;		/* Key to use to find or create matching
   374 				 * entry. */
   375     int *newPtr;		/* Store info here telling whether a new
   376 				 * entry was created. */
   377 {
   378     register Tcl_HashEntry *hPtr;
   379     Tcl_HashKeyType *typePtr;
   380     unsigned int hash;
   381     int index;
   382 
   383 #if TCL_PRESERVE_BINARY_COMPATABILITY
   384     if (tablePtr->keyType == TCL_STRING_KEYS) {
   385 	typePtr = &tclStringHashKeyType;
   386     } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) {
   387 	typePtr = &tclOneWordHashKeyType;
   388     } else if (tablePtr->keyType == TCL_CUSTOM_TYPE_KEYS
   389 	       || tablePtr->keyType == TCL_CUSTOM_PTR_KEYS) {
   390 	typePtr = tablePtr->typePtr;
   391     } else {
   392 	typePtr = &tclArrayHashKeyType;
   393     }
   394 #else
   395     typePtr = tablePtr->typePtr;
   396     if (typePtr == NULL) {
   397 	Tcl_Panic("called Tcl_CreateHashEntry on deleted table");
   398 	return NULL;
   399     }
   400 #endif
   401 
   402     if (typePtr->hashKeyProc) {
   403 	hash = typePtr->hashKeyProc (tablePtr, (VOID *) key);
   404 	if (typePtr->flags & TCL_HASH_KEY_RANDOMIZE_HASH) {
   405 	    index = RANDOM_INDEX (tablePtr, hash);
   406 	} else {
   407 	    index = hash & tablePtr->mask;
   408 	}
   409     } else {
   410 	hash = (unsigned int) key;
   411 	index = RANDOM_INDEX (tablePtr, hash);
   412     }
   413 
   414     /*
   415      * Search all of the entries in the appropriate bucket.
   416      */
   417 
   418     if (typePtr->compareKeysProc) {
   419 	Tcl_CompareHashKeysProc *compareKeysProc = typePtr->compareKeysProc;
   420 	for (hPtr = tablePtr->buckets[index]; hPtr != NULL;
   421 	        hPtr = hPtr->nextPtr) {
   422 #if TCL_HASH_KEY_STORE_HASH
   423 	    if (hash != (unsigned int) hPtr->hash) {
   424 		continue;
   425 	    }
   426 #endif
   427 	    if (compareKeysProc ((VOID *) key, hPtr)) {
   428 		*newPtr = 0;
   429 		return hPtr;
   430 	    }
   431 	}
   432     } else {
   433 	for (hPtr = tablePtr->buckets[index]; hPtr != NULL;
   434 	        hPtr = hPtr->nextPtr) {
   435 #if TCL_HASH_KEY_STORE_HASH
   436 	    if (hash != (unsigned int) hPtr->hash) {
   437 		continue;
   438 	    }
   439 #endif
   440 	    if (key == hPtr->key.oneWordValue) {
   441 		*newPtr = 0;
   442 		return hPtr;
   443 	    }
   444 	}
   445     }
   446 
   447     /*
   448      * Entry not found.  Add a new one to the bucket.
   449      */
   450 
   451     *newPtr = 1;
   452     if (typePtr->allocEntryProc) {
   453 	hPtr = typePtr->allocEntryProc (tablePtr, (VOID *) key);
   454     } else {
   455 	hPtr = (Tcl_HashEntry *) ckalloc((unsigned) sizeof(Tcl_HashEntry));
   456 	hPtr->key.oneWordValue = (char *) key;
   457     }
   458 					 
   459     hPtr->tablePtr = tablePtr;
   460 #if TCL_HASH_KEY_STORE_HASH
   461 #   if TCL_PRESERVE_BINARY_COMPATABILITY
   462     hPtr->hash = (VOID *) hash;
   463 #   else
   464     hPtr->hash = hash;
   465 #   endif
   466     hPtr->nextPtr = tablePtr->buckets[index];
   467     tablePtr->buckets[index] = hPtr;
   468 #else
   469     hPtr->bucketPtr = &(tablePtr->buckets[index]);
   470     hPtr->nextPtr = *hPtr->bucketPtr;
   471     *hPtr->bucketPtr = hPtr;
   472 #endif
   473     hPtr->clientData = 0;
   474     tablePtr->numEntries++;
   475 
   476     /*
   477      * If the table has exceeded a decent size, rebuild it with many
   478      * more buckets.
   479      */
   480 
   481     if (tablePtr->numEntries >= tablePtr->rebuildSize) {
   482 	RebuildTable(tablePtr);
   483     }
   484     return hPtr;
   485 }
   486 
   487 /*
   488  *----------------------------------------------------------------------
   489  *
   490  * Tcl_DeleteHashEntry --
   491  *
   492  *	Remove a single entry from a hash table.
   493  *
   494  * Results:
   495  *	None.
   496  *
   497  * Side effects:
   498  *	The entry given by entryPtr is deleted from its table and
   499  *	should never again be used by the caller.  It is up to the
   500  *	caller to free the clientData field of the entry, if that
   501  *	is relevant.
   502  *
   503  *----------------------------------------------------------------------
   504  */
   505 
   506 EXPORT_C void
   507 Tcl_DeleteHashEntry(entryPtr)
   508     Tcl_HashEntry *entryPtr;
   509 {
   510     register Tcl_HashEntry *prevPtr;
   511     Tcl_HashKeyType *typePtr;
   512     Tcl_HashTable *tablePtr;
   513     Tcl_HashEntry **bucketPtr;
   514 #if TCL_HASH_KEY_STORE_HASH
   515     int index;
   516 #endif
   517 
   518     tablePtr = entryPtr->tablePtr;
   519 
   520 #if TCL_PRESERVE_BINARY_COMPATABILITY
   521     if (tablePtr->keyType == TCL_STRING_KEYS) {
   522 	typePtr = &tclStringHashKeyType;
   523     } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) {
   524 	typePtr = &tclOneWordHashKeyType;
   525     } else if (tablePtr->keyType == TCL_CUSTOM_TYPE_KEYS
   526 	       || tablePtr->keyType == TCL_CUSTOM_PTR_KEYS) {
   527 	typePtr = tablePtr->typePtr;
   528     } else {
   529 	typePtr = &tclArrayHashKeyType;
   530     }
   531 #else
   532     typePtr = tablePtr->typePtr;
   533 #endif
   534     
   535 #if TCL_HASH_KEY_STORE_HASH
   536     if (typePtr->hashKeyProc == NULL
   537 	|| typePtr->flags & TCL_HASH_KEY_RANDOMIZE_HASH) {
   538 	index = RANDOM_INDEX (tablePtr, entryPtr->hash);
   539     } else {
   540 	index = ((unsigned int) entryPtr->hash) & tablePtr->mask;
   541     }
   542 
   543     bucketPtr = &(tablePtr->buckets[index]);
   544 #else
   545     bucketPtr = entryPtr->bucketPtr;
   546 #endif
   547     
   548     if (*bucketPtr == entryPtr) {
   549 	*bucketPtr = entryPtr->nextPtr;
   550     } else {
   551 	for (prevPtr = *bucketPtr; ; prevPtr = prevPtr->nextPtr) {
   552 	    if (prevPtr == NULL) {
   553 		panic("malformed bucket chain in Tcl_DeleteHashEntry");
   554 	    }
   555 	    if (prevPtr->nextPtr == entryPtr) {
   556 		prevPtr->nextPtr = entryPtr->nextPtr;
   557 		break;
   558 	    }
   559 	}
   560     }
   561 
   562     tablePtr->numEntries--;
   563     if (typePtr->freeEntryProc) {
   564 	typePtr->freeEntryProc (entryPtr);
   565     } else {
   566 	ckfree((char *) entryPtr);
   567     }
   568 }
   569 
   570 /*
   571  *----------------------------------------------------------------------
   572  *
   573  * Tcl_DeleteHashTable --
   574  *
   575  *	Free up everything associated with a hash table except for
   576  *	the record for the table itself.
   577  *
   578  * Results:
   579  *	None.
   580  *
   581  * Side effects:
   582  *	The hash table is no longer useable.
   583  *
   584  *----------------------------------------------------------------------
   585  */
   586 
   587 EXPORT_C void
   588 Tcl_DeleteHashTable(tablePtr)
   589     register Tcl_HashTable *tablePtr;		/* Table to delete. */
   590 {
   591     register Tcl_HashEntry *hPtr, *nextPtr;
   592     Tcl_HashKeyType *typePtr;
   593     int i;
   594 
   595 #if TCL_PRESERVE_BINARY_COMPATABILITY
   596     if (tablePtr->keyType == TCL_STRING_KEYS) {
   597 	typePtr = &tclStringHashKeyType;
   598     } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) {
   599 	typePtr = &tclOneWordHashKeyType;
   600     } else if (tablePtr->keyType == TCL_CUSTOM_TYPE_KEYS
   601 	       || tablePtr->keyType == TCL_CUSTOM_PTR_KEYS) {
   602 	typePtr = tablePtr->typePtr;
   603     } else {
   604 	typePtr = &tclArrayHashKeyType;
   605     }
   606 #else
   607     typePtr = tablePtr->typePtr;
   608 #endif
   609 
   610     /*
   611      * Free up all the entries in the table.
   612      */
   613 
   614     for (i = 0; i < tablePtr->numBuckets; i++) {
   615 	hPtr = tablePtr->buckets[i];
   616 	while (hPtr != NULL) {
   617 	    nextPtr = hPtr->nextPtr;
   618 	    if (typePtr->freeEntryProc) {
   619 		typePtr->freeEntryProc (hPtr);
   620 	    } else {
   621 		ckfree((char *) hPtr);
   622 	    }
   623 	    hPtr = nextPtr;
   624 	}
   625     }
   626 
   627     /*
   628      * Free up the bucket array, if it was dynamically allocated.
   629      */
   630 
   631     if (tablePtr->buckets != tablePtr->staticBuckets) {
   632 	ckfree((char *) tablePtr->buckets);
   633     }
   634 
   635     /*
   636      * Arrange for panics if the table is used again without
   637      * re-initialization.
   638      */
   639 
   640 #if TCL_PRESERVE_BINARY_COMPATABILITY
   641     tablePtr->findProc = BogusFind;
   642     tablePtr->createProc = BogusCreate;
   643 #else
   644     tablePtr->typePtr = NULL;
   645 #endif
   646 }
   647 
   648 /*
   649  *----------------------------------------------------------------------
   650  *
   651  * Tcl_FirstHashEntry --
   652  *
   653  *	Locate the first entry in a hash table and set up a record
   654  *	that can be used to step through all the remaining entries
   655  *	of the table.
   656  *
   657  * Results:
   658  *	The return value is a pointer to the first entry in tablePtr,
   659  *	or NULL if tablePtr has no entries in it.  The memory at
   660  *	*searchPtr is initialized so that subsequent calls to
   661  *	Tcl_NextHashEntry will return all of the entries in the table,
   662  *	one at a time.
   663  *
   664  * Side effects:
   665  *	None.
   666  *
   667  *----------------------------------------------------------------------
   668  */
   669 
   670 EXPORT_C Tcl_HashEntry *
   671 Tcl_FirstHashEntry(tablePtr, searchPtr)
   672     Tcl_HashTable *tablePtr;		/* Table to search. */
   673     Tcl_HashSearch *searchPtr;		/* Place to store information about
   674 					 * progress through the table. */
   675 {
   676     searchPtr->tablePtr = tablePtr;
   677     searchPtr->nextIndex = 0;
   678     searchPtr->nextEntryPtr = NULL;
   679     return Tcl_NextHashEntry(searchPtr);
   680 }
   681 
   682 /*
   683  *----------------------------------------------------------------------
   684  *
   685  * Tcl_NextHashEntry --
   686  *
   687  *	Once a hash table enumeration has been initiated by calling
   688  *	Tcl_FirstHashEntry, this procedure may be called to return
   689  *	successive elements of the table.
   690  *
   691  * Results:
   692  *	The return value is the next entry in the hash table being
   693  *	enumerated, or NULL if the end of the table is reached.
   694  *
   695  * Side effects:
   696  *	None.
   697  *
   698  *----------------------------------------------------------------------
   699  */
   700 
   701 EXPORT_C Tcl_HashEntry *
   702 Tcl_NextHashEntry(searchPtr)
   703     register Tcl_HashSearch *searchPtr;	/* Place to store information about
   704 					 * progress through the table.  Must
   705 					 * have been initialized by calling
   706 					 * Tcl_FirstHashEntry. */
   707 {
   708     Tcl_HashEntry *hPtr;
   709     Tcl_HashTable *tablePtr = searchPtr->tablePtr;
   710 
   711     while (searchPtr->nextEntryPtr == NULL) {
   712 	if (searchPtr->nextIndex >= tablePtr->numBuckets) {
   713 	    return NULL;
   714 	}
   715 	searchPtr->nextEntryPtr =
   716 		tablePtr->buckets[searchPtr->nextIndex];
   717 	searchPtr->nextIndex++;
   718     }
   719     hPtr = searchPtr->nextEntryPtr;
   720     searchPtr->nextEntryPtr = hPtr->nextPtr;
   721     return hPtr;
   722 }
   723 
   724 /*
   725  *----------------------------------------------------------------------
   726  *
   727  * Tcl_HashStats --
   728  *
   729  *	Return statistics describing the layout of the hash table
   730  *	in its hash buckets.
   731  *
   732  * Results:
   733  *	The return value is a malloc-ed string containing information
   734  *	about tablePtr.  It is the caller's responsibility to free
   735  *	this string.
   736  *
   737  * Side effects:
   738  *	None.
   739  *
   740  *----------------------------------------------------------------------
   741  */
   742 
   743 EXPORT_C CONST char *
   744 Tcl_HashStats(tablePtr)
   745     Tcl_HashTable *tablePtr;		/* Table for which to produce stats. */
   746 {
   747 #define NUM_COUNTERS 10
   748     int count[NUM_COUNTERS], overflow, i, j;
   749     double average, tmp;
   750     register Tcl_HashEntry *hPtr;
   751     char *result, *p;
   752 
   753     /*
   754      * Compute a histogram of bucket usage.
   755      */
   756 
   757     for (i = 0; i < NUM_COUNTERS; i++) {
   758 	count[i] = 0;
   759     }
   760     overflow = 0;
   761     average = 0.0;
   762     for (i = 0; i < tablePtr->numBuckets; i++) {
   763 	j = 0;
   764 	for (hPtr = tablePtr->buckets[i]; hPtr != NULL; hPtr = hPtr->nextPtr) {
   765 	    j++;
   766 	}
   767 	if (j < NUM_COUNTERS) {
   768 	    count[j]++;
   769 	} else {
   770 	    overflow++;
   771 	}
   772 	tmp = j;
   773 	average += (tmp+1.0)*(tmp/tablePtr->numEntries)/2.0;
   774     }
   775 
   776     /*
   777      * Print out the histogram and a few other pieces of information.
   778      */
   779 
   780     result = (char *) ckalloc((unsigned) ((NUM_COUNTERS*60) + 300));
   781     sprintf(result, "%d entries in table, %d buckets\n",
   782 	    tablePtr->numEntries, tablePtr->numBuckets);
   783     p = result + strlen(result);
   784     for (i = 0; i < NUM_COUNTERS; i++) {
   785 	sprintf(p, "number of buckets with %d entries: %d\n",
   786 		i, count[i]);
   787 	p += strlen(p);
   788     }
   789     sprintf(p, "number of buckets with %d or more entries: %d\n",
   790 	    NUM_COUNTERS, overflow);
   791     p += strlen(p);
   792     sprintf(p, "average search distance for entry: %.1f", average);
   793     return result;
   794 }
   795 
   796 /*
   797  *----------------------------------------------------------------------
   798  *
   799  * AllocArrayEntry --
   800  *
   801  *	Allocate space for a Tcl_HashEntry containing the array key.
   802  *
   803  * Results:
   804  *	The return value is a pointer to the created entry.
   805  *
   806  * Side effects:
   807  *	None.
   808  *
   809  *----------------------------------------------------------------------
   810  */
   811 
   812 static Tcl_HashEntry *
   813 AllocArrayEntry(tablePtr, keyPtr)
   814     Tcl_HashTable *tablePtr;	/* Hash table. */
   815     VOID *keyPtr;		/* Key to store in the hash table entry. */
   816 {
   817     int *array = (int *) keyPtr;
   818     register int *iPtr1, *iPtr2;
   819     Tcl_HashEntry *hPtr;
   820     int count;
   821     unsigned int size;
   822 
   823     count = tablePtr->keyType;
   824     
   825     size = sizeof(Tcl_HashEntry) + (count*sizeof(int)) - sizeof(hPtr->key);
   826     if (size < sizeof(Tcl_HashEntry))
   827 	size = sizeof(Tcl_HashEntry);
   828     hPtr = (Tcl_HashEntry *) ckalloc(size);
   829     
   830     for (iPtr1 = array, iPtr2 = hPtr->key.words;
   831 	    count > 0; count--, iPtr1++, iPtr2++) {
   832 	*iPtr2 = *iPtr1;
   833     }
   834 
   835     return hPtr;
   836 }
   837 
   838 /*
   839  *----------------------------------------------------------------------
   840  *
   841  * CompareArrayKeys --
   842  *
   843  *	Compares two array keys.
   844  *
   845  * Results:
   846  *	The return value is 0 if they are different and 1 if they are
   847  *	the same.
   848  *
   849  * Side effects:
   850  *	None.
   851  *
   852  *----------------------------------------------------------------------
   853  */
   854 
   855 static int
   856 CompareArrayKeys(keyPtr, hPtr)
   857     VOID *keyPtr;		/* New key to compare. */
   858     Tcl_HashEntry *hPtr;	/* Existing key to compare. */
   859 {
   860     register CONST int *iPtr1 = (CONST int *) keyPtr;
   861     register CONST int *iPtr2 = (CONST int *) hPtr->key.words;
   862     Tcl_HashTable *tablePtr = hPtr->tablePtr;
   863     int count;
   864 
   865     for (count = tablePtr->keyType; ; count--, iPtr1++, iPtr2++) {
   866 	if (count == 0) {
   867 	    return 1;
   868 	}
   869 	if (*iPtr1 != *iPtr2) {
   870 	    break;
   871 	}
   872     }
   873     return 0;
   874 }
   875 
   876 /*
   877  *----------------------------------------------------------------------
   878  *
   879  * HashArrayKey --
   880  *
   881  *	Compute a one-word summary of an array, which can be
   882  *	used to generate a hash index.
   883  *
   884  * Results:
   885  *	The return value is a one-word summary of the information in
   886  *	string.
   887  *
   888  * Side effects:
   889  *	None.
   890  *
   891  *----------------------------------------------------------------------
   892  */
   893 
   894 static unsigned int
   895 HashArrayKey(tablePtr, keyPtr)
   896     Tcl_HashTable *tablePtr;	/* Hash table. */
   897     VOID *keyPtr;		/* Key from which to compute hash value. */
   898 {
   899     register CONST int *array = (CONST int *) keyPtr;
   900     register unsigned int result;
   901     int count;
   902 
   903     for (result = 0, count = tablePtr->keyType; count > 0;
   904 	    count--, array++) {
   905 	result += *array;
   906     }
   907     return result;
   908 }
   909 
   910 /*
   911  *----------------------------------------------------------------------
   912  *
   913  * AllocStringEntry --
   914  *
   915  *	Allocate space for a Tcl_HashEntry containing the string key.
   916  *
   917  * Results:
   918  *	The return value is a pointer to the created entry.
   919  *
   920  * Side effects:
   921  *	None.
   922  *
   923  *----------------------------------------------------------------------
   924  */
   925 
   926 static Tcl_HashEntry *
   927 AllocStringEntry(tablePtr, keyPtr)
   928     Tcl_HashTable *tablePtr;	/* Hash table. */
   929     VOID *keyPtr;		/* Key to store in the hash table entry. */
   930 {
   931     CONST char *string = (CONST char *) keyPtr;
   932     Tcl_HashEntry *hPtr;
   933     unsigned int size;
   934 
   935     size = sizeof(Tcl_HashEntry) + strlen(string) + 1 - sizeof(hPtr->key);
   936     if (size < sizeof(Tcl_HashEntry))
   937 	size = sizeof(Tcl_HashEntry);
   938     hPtr = (Tcl_HashEntry *) ckalloc(size);
   939     strcpy(hPtr->key.string, string);
   940 
   941     return hPtr;
   942 }
   943 
   944 /*
   945  *----------------------------------------------------------------------
   946  *
   947  * CompareStringKeys --
   948  *
   949  *	Compares two string keys.
   950  *
   951  * Results:
   952  *	The return value is 0 if they are different and 1 if they are
   953  *	the same.
   954  *
   955  * Side effects:
   956  *	None.
   957  *
   958  *----------------------------------------------------------------------
   959  */
   960 
   961 static int
   962 CompareStringKeys(keyPtr, hPtr)
   963     VOID *keyPtr;		/* New key to compare. */
   964     Tcl_HashEntry *hPtr;		/* Existing key to compare. */
   965 {
   966     register CONST char *p1 = (CONST char *) keyPtr;
   967     register CONST char *p2 = (CONST char *) hPtr->key.string;
   968 
   969     for (;; p1++, p2++) {
   970 	if (*p1 != *p2) {
   971 	    break;
   972 	}
   973 	if (*p1 == '\0') {
   974 	    return 1;
   975 	}
   976     }
   977     return 0;
   978 }
   979 
   980 /*
   981  *----------------------------------------------------------------------
   982  *
   983  * HashStringKey --
   984  *
   985  *	Compute a one-word summary of a text string, which can be
   986  *	used to generate a hash index.
   987  *
   988  * Results:
   989  *	The return value is a one-word summary of the information in
   990  *	string.
   991  *
   992  * Side effects:
   993  *	None.
   994  *
   995  *----------------------------------------------------------------------
   996  */
   997 
   998 static unsigned int
   999 HashStringKey(tablePtr, keyPtr)
  1000     Tcl_HashTable *tablePtr;	/* Hash table. */
  1001     VOID *keyPtr;		/* Key from which to compute hash value. */
  1002 {
  1003     register CONST char *string = (CONST char *) keyPtr;
  1004     register unsigned int result;
  1005     register int c;
  1006 
  1007     /*
  1008      * I tried a zillion different hash functions and asked many other
  1009      * people for advice.  Many people had their own favorite functions,
  1010      * all different, but no-one had much idea why they were good ones.
  1011      * I chose the one below (multiply by 9 and add new character)
  1012      * because of the following reasons:
  1013      *
  1014      * 1. Multiplying by 10 is perfect for keys that are decimal strings,
  1015      *    and multiplying by 9 is just about as good.
  1016      * 2. Times-9 is (shift-left-3) plus (old).  This means that each
  1017      *    character's bits hang around in the low-order bits of the
  1018      *    hash value for ever, plus they spread fairly rapidly up to
  1019      *    the high-order bits to fill out the hash value.  This seems
  1020      *    works well both for decimal and non-decimal strings.
  1021      */
  1022 
  1023     result = 0;
  1024     while (1) {
  1025 	c = *string;
  1026 	if (c == 0) {
  1027 	    break;
  1028 	}
  1029 	result += (result<<3) + c;
  1030 	string++;
  1031     }
  1032     return result;
  1033 }
  1034 
  1035 #if TCL_PRESERVE_BINARY_COMPATABILITY
  1036 /*
  1037  *----------------------------------------------------------------------
  1038  *
  1039  * BogusFind --
  1040  *
  1041  *	This procedure is invoked when an Tcl_FindHashEntry is called
  1042  *	on a table that has been deleted.
  1043  *
  1044  * Results:
  1045  *	If panic returns (which it shouldn't) this procedure returns
  1046  *	NULL.
  1047  *
  1048  * Side effects:
  1049  *	Generates a panic.
  1050  *
  1051  *----------------------------------------------------------------------
  1052  */
  1053 
  1054 	/* ARGSUSED */
  1055 static Tcl_HashEntry *
  1056 BogusFind(tablePtr, key)
  1057     Tcl_HashTable *tablePtr;	/* Table in which to lookup entry. */
  1058     CONST char *key;		/* Key to use to find matching entry. */
  1059 {
  1060     panic("called Tcl_FindHashEntry on deleted table");
  1061     return NULL;
  1062 }
  1063 
  1064 /*
  1065  *----------------------------------------------------------------------
  1066  *
  1067  * BogusCreate --
  1068  *
  1069  *	This procedure is invoked when an Tcl_CreateHashEntry is called
  1070  *	on a table that has been deleted.
  1071  *
  1072  * Results:
  1073  *	If panic returns (which it shouldn't) this procedure returns
  1074  *	NULL.
  1075  *
  1076  * Side effects:
  1077  *	Generates a panic.
  1078  *
  1079  *----------------------------------------------------------------------
  1080  */
  1081 
  1082 	/* ARGSUSED */
  1083 static Tcl_HashEntry *
  1084 BogusCreate(tablePtr, key, newPtr)
  1085     Tcl_HashTable *tablePtr;	/* Table in which to lookup entry. */
  1086     CONST char *key;		/* Key to use to find or create matching
  1087 				 * entry. */
  1088     int *newPtr;		/* Store info here telling whether a new
  1089 				 * entry was created. */
  1090 {
  1091     panic("called Tcl_CreateHashEntry on deleted table");
  1092     return NULL;
  1093 }
  1094 #endif
  1095 
  1096 /*
  1097  *----------------------------------------------------------------------
  1098  *
  1099  * RebuildTable --
  1100  *
  1101  *	This procedure is invoked when the ratio of entries to hash
  1102  *	buckets becomes too large.  It creates a new table with a
  1103  *	larger bucket array and moves all of the entries into the
  1104  *	new table.
  1105  *
  1106  * Results:
  1107  *	None.
  1108  *
  1109  * Side effects:
  1110  *	Memory gets reallocated and entries get re-hashed to new
  1111  *	buckets.
  1112  *
  1113  *----------------------------------------------------------------------
  1114  */
  1115 
  1116 static void
  1117 RebuildTable(tablePtr)
  1118     register Tcl_HashTable *tablePtr;	/* Table to enlarge. */
  1119 {
  1120     int oldSize, count, index;
  1121     Tcl_HashEntry **oldBuckets;
  1122     register Tcl_HashEntry **oldChainPtr, **newChainPtr;
  1123     register Tcl_HashEntry *hPtr;
  1124     Tcl_HashKeyType *typePtr;
  1125     VOID *key;
  1126 
  1127     oldSize = tablePtr->numBuckets;
  1128     oldBuckets = tablePtr->buckets;
  1129 
  1130     /*
  1131      * Allocate and initialize the new bucket array, and set up
  1132      * hashing constants for new array size.
  1133      */
  1134 
  1135     tablePtr->numBuckets *= 4;
  1136     tablePtr->buckets = (Tcl_HashEntry **) ckalloc((unsigned)
  1137 	    (tablePtr->numBuckets * sizeof(Tcl_HashEntry *)));
  1138     for (count = tablePtr->numBuckets, newChainPtr = tablePtr->buckets;
  1139 	    count > 0; count--, newChainPtr++) {
  1140 	*newChainPtr = NULL;
  1141     }
  1142     tablePtr->rebuildSize *= 4;
  1143     tablePtr->downShift -= 2;
  1144     tablePtr->mask = (tablePtr->mask << 2) + 3;
  1145 
  1146 #if TCL_PRESERVE_BINARY_COMPATABILITY
  1147     if (tablePtr->keyType == TCL_STRING_KEYS) {
  1148 	typePtr = &tclStringHashKeyType;
  1149     } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) {
  1150 	typePtr = &tclOneWordHashKeyType;
  1151     } else if (tablePtr->keyType == TCL_CUSTOM_TYPE_KEYS
  1152 	       || tablePtr->keyType == TCL_CUSTOM_PTR_KEYS) {
  1153 	typePtr = tablePtr->typePtr;
  1154     } else {
  1155 	typePtr = &tclArrayHashKeyType;
  1156     }
  1157 #else
  1158     typePtr = tablePtr->typePtr;
  1159 #endif
  1160 
  1161     /*
  1162      * Rehash all of the existing entries into the new bucket array.
  1163      */
  1164 
  1165     for (oldChainPtr = oldBuckets; oldSize > 0; oldSize--, oldChainPtr++) {
  1166 	for (hPtr = *oldChainPtr; hPtr != NULL; hPtr = *oldChainPtr) {
  1167 	    *oldChainPtr = hPtr->nextPtr;
  1168 
  1169 	    key = (VOID *) Tcl_GetHashKey (tablePtr, hPtr);
  1170 
  1171 #if TCL_HASH_KEY_STORE_HASH
  1172 	    if (typePtr->hashKeyProc == NULL
  1173 		|| typePtr->flags & TCL_HASH_KEY_RANDOMIZE_HASH) {
  1174 		index = RANDOM_INDEX (tablePtr, hPtr->hash);
  1175 	    } else {
  1176 		index = ((unsigned int) hPtr->hash) & tablePtr->mask;
  1177 	    }
  1178 	    hPtr->nextPtr = tablePtr->buckets[index];
  1179 	    tablePtr->buckets[index] = hPtr;
  1180 #else
  1181 	    if (typePtr->hashKeyProc) {
  1182 		unsigned int hash;
  1183 		hash = typePtr->hashKeyProc (tablePtr, (VOID *) key);
  1184 		if (typePtr->flags & TCL_HASH_KEY_RANDOMIZE_HASH) {
  1185 		    index = RANDOM_INDEX (tablePtr, hash);
  1186 		} else {
  1187 		    index = hash & tablePtr->mask;
  1188 		}
  1189 	    } else {
  1190 		index = RANDOM_INDEX (tablePtr, key);
  1191 	    }
  1192 
  1193 	    hPtr->bucketPtr = &(tablePtr->buckets[index]);
  1194 	    hPtr->nextPtr = *hPtr->bucketPtr;
  1195 	    *hPtr->bucketPtr = hPtr;
  1196 #endif
  1197 	}
  1198     }
  1199 
  1200     /*
  1201      * Free up the old bucket array, if it was dynamically allocated.
  1202      */
  1203 
  1204     if (oldBuckets != tablePtr->staticBuckets) {
  1205 	ckfree((char *) oldBuckets);
  1206     }
  1207 }