Tcl_Hash(3)
okay bestie, welcome to Tcl_Hash(3) from the Tcl Library Procedures β it's the hash-table friend group, and they're all here to manage hash tables. π β¨
πΈ NAME πΈ
the whole squad is:
Tcl_InitHashTableTcl_InitCustomHashTableTcl_InitObjHashTableTcl_DeleteHashTableTcl_CreateHashEntryTcl_AttemptCreateHashEntryTcl_DeleteHashEntryTcl_FindHashEntryTcl_GetHashValueTcl_SetHashValueTcl_GetHashKeyTcl_FirstHashEntryTcl_NextHashEntryTcl_HashStats
and together they're the procedures to manage hash tables. Lowkey iconic. π«Ά
β¨ SYNOPSIS β¨
#include <tcl.h>
Tcl_InitHashTable(tablePtr, keyType)
Tcl_InitCustomHashTable(tablePtr, keyType, typePtr)
Tcl_InitObjHashTable(tablePtr)
Tcl_DeleteHashTable(tablePtr)
Tcl_HashEntry *
Tcl_CreateHashEntry(tablePtr, key, newPtr)
Tcl_HashEntry *
Tcl_AttemptCreateHashEntry(tablePtr, key, newPtr)
Tcl_DeleteHashEntry(entryPtr)
Tcl_HashEntry *
Tcl_FindHashEntry(tablePtr, key)
void *
Tcl_GetHashValue(entryPtr)
Tcl_SetHashValue(entryPtr, value)
void *
Tcl_GetHashKey(tablePtr, entryPtr)
Tcl_HashEntry *
Tcl_FirstHashEntry(tablePtr, searchPtr)
Tcl_HashEntry *
Tcl_NextHashEntry(searchPtr)
char *
Tcl_HashStats(tablePtr)
π ARGUMENTS π
Tcl_HashTable *tablePtr(in) β address of hash table structure. For all procedures butTcl_InitHashTable, this must have been initialized by previous call toTcl_InitHashTable.int keyType(in) β kind of keys to use for new hash table. Must be eitherTCL_STRING_KEYS,TCL_ONE_WORD_KEYS,TCL_CUSTOM_TYPE_KEYS,TCL_CUSTOM_PTR_KEYS, or an integer value greater than 1.Tcl_HashKeyType *typePtr(in) β address of structure which defines the behavior of the hash table.const void *key(in) β key to use for probe into table. Exact form depends onkeyTypeused to create table.int *newPtr(out) β the word at*newPtris set to1if a new entry was created and0if there was already an entry forkey.Tcl_HashEntry *entryPtr(in) β pointer to hash table entry.void *value(in) β new value to assign to hash table entry.Tcl_HashSearch *searchPtr(in) β pointer to record to use to keep track of progress in enumerating all the entries in a hash table.
β¨ DESCRIPTION β¨
Okay bestie, buckle up, because this is the whole vibe of what a hash table is π
A hash table is literally just zero or more entries, and each entry is a lil duo of a key and a value. Give the hashing routines the key and they'll zoom straight to the entry β and obvi to its value β so fast. There can be at most one entry in a hash table with any particular key, but bestie, many entries can totally have the same value. No drama there. π«Ά
Keys come in one of four forms:
- strings
- one-word values
- integer arrays
- custom keys defined by a
Tcl_HashKeyTypestructure (peep the section THE TCL_HASHKEYTYPE STRUCTURE below π)
And here's the rule: all the keys in a given table have the same form. You pick that form when the table is initialized. Periodt. β¨
The value of a hash table entry can be literally anything that fits in the same space as a char * pointer. Values for hash table entries are managed entirely by clients β not by the hash module itself. Typically each entry's value is a pointer to some data structure that the client code is managing. Main character energy for the client, honestly. π
Hash tables grow gracefully as the number of entries goes up, so there are always less than three entries per hash bucket, on average. That means fast lookups no matter how many entries are in the table. Slay. π₯
The core provides three functions for initializing hash tables:
Tcl_InitHashTableTcl_InitObjHashTableTcl_InitCustomHashTable
Tcl_InitHashTable initializes a structure that describes a new hash table. The space for the structure is provided by the caller, not by the hash module β so you gotta bring your own storage, bestie. π The value of keyType tells it what kinds of keys will be used for all entries in the table. All of the key types described later are allowed, with the exception of TCL_CUSTOM_TYPE_KEYS and TCL_CUSTOM_PTR_KEYS. Those two are a no-go here, fr fr. π
Tcl_InitObjHashTable is a wrapper around Tcl_InitCustomHashTable and initializes a hash table whose keys are Tcl_Obj *. Cute little shortcut. π
Tcl_InitCustomHashTable initializes a structure that describes a new hash table. Again: the space for the structure is provided by the caller, not by the hash module. The value of keyType indicates what kinds of keys will be used for all entries in the table. KeyType must have one of the following values:
TCL_STRING_KEYSβ Keys are null-terminated strings. They get passed to hashing routines using the address of the first character of the string. Easy peasy. πΈTCL_ONE_WORD_KEYSβ Keys are single-word values; they're passed to hashing routines and stored in hash table entries aschar *values. The pointer value is the key; it need not (and usually does not) actually point to a string. Like, don't assume it's a string, bestie, it's just a word. πTCL_CUSTOM_TYPE_KEYSβ Keys are of arbitrary type, and are stored in the entry. Hashing and comparison are determined by typePtr. TheTcl_HashKeyTypestructure is described in the section THE TCL_HASHKEYTYPE STRUCTURE below. π¦TCL_CUSTOM_PTR_KEYSβ Keys are pointers to an arbitrary type, and are stored in the entry. Hashing and comparison are determined by typePtr. TheTcl_HashKeyTypestructure is described in the section THE TCL_HASHKEYTYPE STRUCTURE below. π¦- other β If keyType is not one of the above, then it must be an integer value greater than 1. In this case the keys will be arrays of
intvalues, where keyType gives the number of ints in each key. This lets you use structures as keys. All keys must have the same size. Array keys are passed into hashing functions using the address of the first int in the array. Iconic β¨
Tcl_DeleteHashTable deletes all of the entries in a hash table and frees up the memory associated with the table's bucket array and entries. Important caveat though: it does not free the actual table structure (pointed to by tablePtr), because that memory is assumed to be managed by the client. Same energy with values: Tcl_DeleteHashTable also does not free or otherwise manipulate the values of the hash table entries. So if the entry values point to dynamically-allocated memory, it is the client's responsibility to free those structures before deleting the table. Don't forget, or that's a leak, and leaks are not the vibe. π
Tcl_CreateHashEntry locates the entry corresponding to a particular key, creating a new entry in the table if there wasn't already one with the given key. If an entry already existed with the given key, then *newPtr is set to zero. If a new entry was created, then *newPtr is set to a non-zero value and the value of the new entry will be set to zero. *newPtr is allowed to be NULL. The return value from Tcl_CreateHashEntry is a pointer to the entry, which you can use to retrieve and modify the entry's value or to delete the entry from the table. π
Tcl_AttemptCreateHashEntry does the same as Tcl_CreateHashEntry, except in case of a memory overflow. Tcl_AttemptCreateHashEntry returns NULL in that case while Tcl_CreateHashEntry panics. So, y'know, pick your fighter. π
Tcl_DeleteHashEntry will remove an existing entry from a table. The memory associated with the entry itself will be freed, but the client is responsible for any cleanup associated with the entry's value β such as freeing a structure that it points to. Yes, again, cleanup is on you, bestie π«Ά
Tcl_FindHashEntry is similar to Tcl_CreateHashEntry except that it does not create a new entry if the key doesn't exist; instead, it returns NULL as result. Lookup only, no surprises. π
Tcl_GetHashValue and Tcl_SetHashValue are used to read and write an entry's value, respectively. Simple as that. β¨
Tcl_GetHashKey returns the key for a given hash table entry, either as a pointer to a string, a one-word (char *) key, or as a pointer to the first word of an array of integers β depending on the keyType used to create the hash table. In all cases Tcl_GetHashKey returns a result with type char *. When the key is a string or array, the result of Tcl_GetHashKey points to information in the table entry; this information will remain valid until the entry is deleted or its table is deleted. So don't go deleting stuff and then using it, okay? π
Tcl_FirstHashEntry and Tcl_NextHashEntry may be used to scan all of the entries in a hash table. A structure of type Tcl_HashSearch, provided by the client, is used to keep track of progress through the table. Tcl_FirstHashEntry initializes the search record and returns the first entry in the table (or NULL if the table is empty). Each subsequent call to Tcl_NextHashEntry returns the next entry in the table or NULL if the end of the table has been reached. A call to Tcl_FirstHashEntry followed by calls to Tcl_NextHashEntry will return each of the entries in the table exactly once, in an arbitrary order (so don't expect a specific order, bestie, it's giving chaos π). It is inadvisable to modify the structure of the table β e.g. by creating or deleting entries β while the search is in progress, with the exception of deleting the entry returned by Tcl_FirstHashEntry or Tcl_NextHashEntry. That one's allowed. Everything else? Don't. π
Tcl_HashStats returns a dynamically-allocated string with overall information about a hash table, such as the number of entries it contains, the number of buckets in its hash array, and the utilization of the buckets. It is the caller's responsibility to free the result string by passing it to Tcl_Free. Free your strings, bestie, it's self-care. π
One last thing: the header file tcl.h defines the actual data structures used to implement hash tables. This is necessary so that clients can allocate Tcl_HashTable structures and so that macros can be used to read and write the values of entries. However, users of the hashing routines should never refer directly to any of the fields of any of the hash-related data structures; use the procedures and macros defined here instead. Like, don't peek behind the curtain, okay? The API is right there, use it. πβ¨
β¨ THE TCL_HASHKEYTYPE STRUCTURE β¨
Okay bestie, this is the part where you get to invent your own key type, which is honestly kind of iconic π. Extension writers can define new hash key types by defining four procedures, initializing a Tcl_HashKeyType structure to describe the type, and calling Tcl_InitCustomHashTable. The Tcl_HashKeyType structure is defined as follows:
typedef struct {
int version;
int flags;
Tcl_HashKeyProc *hashKeyProc;
Tcl_CompareHashKeysProc *compareKeysProc;
Tcl_AllocHashEntryProc *allocEntryProc;
Tcl_FreeHashEntryProc *freeEntryProc;
} Tcl_HashKeyType;
The version member is the version of the table π. If this structure is extended in future then the version can be used to distinguish between different structures. It should be set to TCL_HASH_KEY_TYPE_VERSION. Like, that's the whole vibe check for forward compatibility, no cap.
The flags member is 0 or one or more of the following values OR'ed together:
TCL_HASH_KEY_RANDOMIZE_HASHβ there are some things, pointers for example, which do not hash well because they do not use the lower bits π« . If this flag is set then the hash table will attempt to rectify this by randomizing the bits and then using the upper N bits as the index into the table. Fixing the bit situation, honestly so real of it.TCL_HASH_KEY_SYSTEM_HASHβ this flag forces Tcl to use the memory allocation procedures provided by the operating system when allocating and freeing memory used to store the hash table data structures, and not any of Tcl's own customized memory allocation routines π . This is important if the hash table is to be used in the implementation of a custom set of allocation routines, or something that a custom set of allocation routines might depend on, in order to avoid any circular dependency. Circular dependency is giving toxic relationship, so we're not doing that π ββοΈ.
The hashKeyProc member contains the address of a function called to calculate a hash value for the key:
typedef size_t Tcl_HashKeyProc(
Tcl_HashTable *tablePtr,
void *keyPtr);
If this is NULL then keyPtr is used and TCL_HASH_KEY_RANDOMIZE_HASH is assumed. Default behavior said what it said β¨.
The compareKeysProc member contains the address of a function called to compare two keys:
typedef int Tcl_CompareHashKeysProc(
void *keyPtr,
Tcl_HashEntry *hPtr);
If this is NULL then the keyPtr pointers are compared π. If the keys do not match then the function returns 0, otherwise it returns 1. Binary queen β it's giving either/or, no in between.
The allocEntryProc member contains the address of a function called to allocate space for an entry and initialize the key and clientData:
typedef Tcl_HashEntry *Tcl_AllocHashEntryProc(
Tcl_HashTable *tablePtr,
void *keyPtr);
If this is NULL then Tcl_Alloc is used to allocate enough space for a Tcl_HashEntry, the key pointer is assigned to key.oneWordValue and the clientData is set to NULL π. String keys and array keys use this function to allocate enough space for the entry and the key in one block, rather than doing it in two blocks. This saves space for a pointer to the key from the entry and another memory allocation β efficiency slay π
. Tcl_Obj * keys use this function to allocate enough space for an entry and increment the reference count on the value.
The freeEntryProc member contains the address of a function called to free space for an entry:
typedef void Tcl_FreeHashEntryProc(
Tcl_HashEntry *hPtr);
If this is NULL then Tcl_Free is used to free the space for the entry. Tcl_Obj * keys use this function to decrement the reference count on the value. Symmetry! We love a matching alloc/free moment π«Ά.
π REFERENCE COUNT MANAGEMENT π
Okay this bit is lowkey important so lock in π. When a hash table is created with Tcl_InitCustomHashTable, the Tcl_CreateHashEntry function will increment the reference count of its key argument when it creates a key (but not if there is an existing matching key). The reference count of the key will be decremented when the corresponding hash entry is deleted, whether with Tcl_DeleteHashEntry or with Tcl_DeleteHashTable. The Tcl_GetHashKey function will return the key without further modifying its reference count. So like, it hands you the key and just... does not touch the count. Respect.
Custom hash tables that use a Tcl_Obj * as key will generally need to do something similar in their allocEntryProc. Fr fr, don't forget this part or the refcounts will get messy π.
π SEE ALSO π
Go read it, it's a whole vibe π¦.
π KEYWORDS π
hash table, key, lookup, search, value
That's the whole page, bestie! π This was Tcl_Hash(3) from the Tcl manual set β source/version: the Tcl documentation, page Tcl_Hash(3) β mwah π, go forth and hash responsibly. π
π¦ where this page comes from
- nixpkgs unstable: tcl 9.1.0
- Copyright (c) 1989-1993 The Regents of the University of California
- Copyright (c) 1994-1996 Sun Microsystems, Inc
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms