lib-of-vs-libs-free-type-2.1.4-include-freetype2-freetype-internal-fthash.h / h
**************************************************************** fthash.h - fast dynamic hash tables Copyright 2002 by David Turner, Robert Wilhelm, and Werner Lemberg This file is part of the FreeType project, and may only be used, modified, and distributed under the terms of the FreeType project license, LICENSE.TXT. By continuing to use, modify, or distribute this file you indicate that you have read the license and understand and accept it fully. This header is used to define dynamic hash tables as described by the article "Main-Memory Linear Hashing - Some Enhancements of Larson's Algorithm" by Mikael Petterson. Basically, linear hashing prevents big "stalls" during resizes of the buckets array by only splitting one bucket at a time. This ensures excellent response time even when the table is frequently resized.. Note that the use of the FT_Hash type is rather unusual in order to be as generic and efficient as possible. See the comments in the following definitions for more details.
********************************************************* @type: FT_Hash @description: handle to a @FT_HashRec structure used to model a dynamic hash table
********************************************************* @type: FT_HashNode @description: handle to a @FT_HashNodeRec structure used to model a single node of a hash table
********************************************************* @type: FT_HashLookup @description: handle to a @FT_HashNode pointer. This is returned by the @ft_hash_lookup function and can later be used by @ft_hash_add or @ft_hash_remove
********************************************************* @type: FT_Hash_EqualFunc @description: a function used to compare two nodes of the hash table @input: node1 :: handle to first node node2 :: handle to second node @return: 1 iff the 'keys' in 'node1' and 'node2' are identical. 0 otherwise.
********************************************************* @struct: FT_HashRec @description: a structure used to model a dynamic hash table. @fields: memory :: memory manager used to allocate the buckets array and the hash nodes buckets :: array of hash buckets node_size :: size of node in bytes node_compare :: a function used to compare two nodes node_hash :: a function used to compute the hash value of a given node p :: mask :: slack :: @note: 'p', 'mask' and 'slack' are control values managed by the hash table. Do not try to interpret them directly. You can grab the hash table size by calling '@ft_hash_get_size'.
********************************************************* @struct: FT_HashNodeRec @description: a structure used to model the root fields of a dynamic hash table node. it's up to client applications to "sub-class" this structure to add relevant (key,value) definitions @fields: link :: pointer to next node in bucket's collision list hash :: 32-bit hash value for this node @note: it's up to client applications to "sub-class" this structure to add relevant (key,value) type definitions. For example, if we want to build a "string -> int" mapping, we could use something like: { typedef struct MyNodeRec_ { FT_HashNodeRec hnode; const char* key; int value; } MyNodeRec, *MyNode; }
************************************************************** @function: ft_hash_init @description: initialize a dynamic hash table @input: table :: handle to target hash table structure node_equal :: node comparison function memory :: memory manager handle used to allocate the buckets array within the hash table @return: error code. 0 means success @note: the node comparison function should only compare node _keys_ and ignore values !! with good hashing computation (which the user must perform itself), the comparison function should be pretty seldom called. here is a simple example: { static int my_equal( MyNode node1, MyNode node2 ) { // compare keys of 'node1' and 'node2' return (strcmp( node1->key, node2->key ) == 0); } .... ft_hash_init( &hash, (FT_Hash_EqualFunc) my_compare, memory ); .... }
************************************************************** @function: ft_hash_lookup @description: search a hash table to find a node corresponding to a given key. @input: table :: handle to target hash table structure keynode :: handle to a reference hash node that will be only used for key comparisons with the table's elements @return: a pointer-to-hash-node value, which must be used as followed: - if '*result' is NULL, the key wasn't found in the hash table. The value of 'result' can be used to add new elements through @ft_hash_add however.. - if '*result' is not NULL, it's a handle to the first table node that corresponds to the search key. The value of 'result' can be used to remove this element through @ft_hash_remove @note: here is an example: { // maps a string to an integer with a hash table // returns -1 in case of failure // int my_lookup( FT_Hash table, const char* key ) { MyNode* pnode; MyNodeRec noderec; // set-up key node. It's 'hash' and 'key' fields must // be set correctly.. we ignore 'link' and 'value' // noderec.hnode.hash = strhash( key ); noderec.key = key; // perform search - return value // pnode = (MyNode) ft_hash_lookup( table, &noderec ); if ( *pnode ) { // we found it return (*pnode)->value; } return -1; } }
************************************************************** @function: ft_hash_add @description: add a new node to a dynamic hash table. the user must call @ft_hash_lookup and allocate a new node before calling this function. @input: table :: hash table handle lookup :: pointer-to-hash-node value returned by @ft_hash_lookup new_node :: handle to new hash node. All its fields must be correctly set, including 'hash'. @return: error code. 0 means success @note: this function should always be used _after_ a call to @ft_hash_lookup that returns a pointer to a NULL handle. Here's an example: { // sets the value corresponding to a given string key // void my_set( FT_Hash table, const char* key, int value ) { MyNode* pnode; MyNodeRec noderec; MyNode node; // set-up key node. It's 'hash' and 'key' fields must // be set correctly.. noderec.hnode.hash = strhash( key ); noderec.key = key; // perform search - return value pnode = (MyNode) ft_hash_lookup( table, &noderec ); if ( *pnode ) { // we found it, simply replace the value in the node (*pnode)->value = value; return; } // allocate a new node - and set it up node = (MyNode) malloc( sizeof(*node) ); if ( node == NULL ) ..... node->hnode.hash = noderec.hnode.hash; node->key = key; node->value = value; // add it to the hash table error = ft_hash_add( table, pnode, node ); if (error) .... }
************************************************************** @function: ft_hash_remove @description: try to remove the node corresponding to a given key from a hash table. This must be called after @ft_hash_lookup @input: table :: hash table handle lookup :: pointer-to-hash-node value returned by @ft_hash_lookup @note: this function doesn't free the node itself !! Here's an example: { // sets the value corresponding to a given string key // void my_remove( FT_Hash table, const char* key ) { MyNodeRec noderec; MyNode node; noderec.hnode.hash = strhash(key); noderec.key = key; node = &noderec; pnode = ft_hash_lookup( table, &noderec ); node = *pnode; if ( node != NULL ) { error = ft_hash_remove( table, pnode ); if ( !error ) free( node ); } } }
************************************************************** @function: ft_hash_get_size @description: return the number of elements in a given hash table @input: table :: handle to target hash table structure @return: number of elements. 0 if empty
************************************************************** @functype: FT_Hash_ForeachFunc @description: a function used to iterate over all elements of a given hash table @input: node :: handle to target @FT_HashNodeRec node structure data :: optional argument to iteration routine @also: @ft_hash_foreach
************************************************************** @function: ft_hash_foreach @description: parse over all elements in a hash table @input: table :: handle to target hash table structure foreach_func :: iteration routine called for each element foreach_data :: optional argument to the iteration routine @note: this function is often used to release all elements from a hash table. See the example given for @ft_hash_done
************************************************************** @function: ft_hash_done @description: finalize a given hash table @input: table :: handle to target hash table structure node_func :: optional iteration function pointer. this can be used to destroy all nodes explicitely node_data :: optional argument to the node iterator @note: this function simply frees the hash table's buckets. you probably will need to call @ft_hash_foreach to destroy all its elements before @ft_hash_done, as in the following example: { static void my_node_clear( const MyNode node ) { free( node ); } static void my_done( FT_Hash table ) { ft_hash_done( table, (FT_Hash_ForeachFunc) my_node_clear, NULL ); } }
(C) Æliens 04/09/2009
You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.