⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hash.c

📁 xorp源码hg
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 2000, 2001 by Martin C. Shepherd. *  * All rights reserved. *  * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, and/or sell copies of the Software, and to permit persons * to whom the Software is furnished to do so, provided that the above * copyright notice(s) and this permission notice appear in all copies of * the Software and that both the above copyright notice(s) and this * permission notice appear in supporting documentation. *  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *  * Except as contained in this notice, the name of a copyright holder * shall not be used in advertising or otherwise to promote the sale, use * or other dealings in this Software without prior written authorization * of the copyright holder. */#include <stdlib.h>#include <stdio.h>#include <string.h>#include <ctype.h>#include "hash.h"#include "strngmem.h"#include "freelist.h"/* * The following container object contains free-lists to be used * for allocation of HashTable containers and nodes. */struct HashMemory {  FreeList *hash_memory;    /* HashTable free-list */  FreeList *node_memory;    /* HashNode free-list */  StringMem *string_memory; /* Memory used to allocate hash strings */};/* * Define a hash symbol-table entry. * See symbol.h for the definition of the Symbol container type. */typedef struct HashNode HashNode;struct HashNode {  Symbol symbol;       /* The symbol stored in the hash-entry */  HashNode *next;      /* The next hash-table entry in a bucket list */};/* * Each hash-table bucket contains a linked list of entries that * hash to the same bucket. */typedef struct {  HashNode *head;   /* The head of the bucket hash-node list */  int count;        /* The number of entries in the list */} HashBucket;/* * Set the max length of the error-reporting string. There is no point * in this being longer than the width of a typical terminal window. * In composing error messages, I have assumed that this number is * at least 80, so you don't decrease it below this number. */#define ERRLEN 200/* * A hash-table consists of 'size' hash buckets. * Note that the HashTable typedef for this struct is contained in hash.h. */struct HashTable {  char errmsg[ERRLEN+1];/* Error-report buffer */  HashMemory *mem;      /* HashTable free-list */  int internal_mem;     /* True if 'mem' was allocated by _new_HashTable() */  int case_sensitive;   /* True if case is significant in lookup keys */  int size;             /* The number of hash buckets */  HashBucket *bucket;   /* An array of 'size' hash buckets */  int (*keycmp)(const char *, const char *); /* Key comparison function */  void *app_data;       /* Application-provided data */  HASH_DEL_FN(*del_fn); /* Application-provided 'app_data' destructor */};static HashNode *_del_HashNode(HashTable *hash, HashNode *node);static HashNode *_new_HashNode(HashTable *hash, const char *name, int code,		      void (*fn)(void), void *data, SYM_DEL_FN(*del_fn));static HashNode *_find_HashNode(HashTable *hash, HashBucket *bucket,				const char *name, HashNode **prev);static HashBucket *_find_HashBucket(HashTable *hash, const char *name);static int _ht_lower_strcmp(const char *node_key, const char *look_key);static int _ht_strcmp(const char *node_key, const char *look_key);/*....................................................................... * Allocate a free-list for use in allocating hash tables and their nodes. * * Input: *  list_count    int    The number of HashTable containers per free-list *                       block. *  node_count    int    The number of HashTable nodes per free-list block. * Output: *  return HashMemory *  The new free-list for use in allocating hash tables *                       and their nodes. */HashMemory *_new_HashMemory(int hash_count, int node_count){  HashMemory *mem;/* * Allocate the free-list container. */  mem = (HashMemory *) malloc(sizeof(HashMemory));  if(!mem) {    fprintf(stderr, "_new_HashMemory: Insufficient memory.\n");    return NULL;  };/* * Initialize the container at least up to the point at which it can * safely be passed to _del_HashMemory(). */  mem->hash_memory = NULL;  mem->node_memory = NULL;  mem->string_memory = NULL;/* * Allocate the two free-lists. */  mem->hash_memory = _new_FreeList("_new_HashMemory", sizeof(HashTable),				  hash_count);  if(!mem->hash_memory)    return _del_HashMemory(mem, 1);  mem->node_memory = _new_FreeList("_new_HashMemory", sizeof(HashNode),				  node_count);  if(!mem->node_memory)    return _del_HashMemory(mem, 1);  mem->string_memory = _new_StringMem("_new_HashMemory", 64);  if(!mem->string_memory)    return _del_HashMemory(mem, 1);/* * Return the free-list container. */  return mem;}/*....................................................................... * Delete a HashTable free-list. An error will be displayed if the list is * still in use and the deletion will be aborted. * * Input: *  mem    HashMemory *  The free-list container to be deleted. *  force         int    If force==0 then _del_HashMemory() will complain *                        and refuse to delete the free-list if any *                        of nodes have not been returned to the free-list. *                       If force!=0 then _del_HashMemory() will not check *                        whether any nodes are still in use and will *                        always delete the list. * Output: *  return HashMemory *  Always NULL (even if the memory could not be *                       deleted). */HashMemory *_del_HashMemory(HashMemory *mem, int force){  const char *caller = "_del_HashMemory";  if(mem) {    if(!force && (_busy_FreeListNodes(mem->hash_memory) > 0 ||		  _busy_FreeListNodes(mem->node_memory) > 0)) {      fprintf(stderr, "%s: Free-list in use.\n", caller);      return NULL;    };    mem->hash_memory = _del_FreeList(caller, mem->hash_memory, force);    mem->node_memory = _del_FreeList(caller, mem->node_memory, force);    mem->string_memory = _del_StringMem(caller, mem->string_memory, force);    free(mem);  };  return NULL;}/*....................................................................... * Create a new hash table. * * Input: *  mem       HashMemory *  An optional free-list for use in allocating *                          HashTable containers and nodes. See explanation *                          in hash.h. If you are going to allocate more *                          than one hash table, then it will be more *                          efficient to allocate a single free-list for *                          all of them than to force each hash table *                          to allocate its own private free-list. *  size             int    The size of the hash table. Best performance *                          will be acheived if this is a prime number. *  hcase       HashCase    Specify how symbol case is considered when *                          looking up symbols, from: *                           IGNORE_CASE - Upper and lower case versions *                                         of a letter are treated as *                                         being identical. *                           HONOUR_CASE - Upper and lower case versions *                                         of a letter are treated as *                                         being distinct. *                          characters in a lookup name is significant. *  app_data        void *  Optional application data to be registered *                          to the table. This is presented to user *                          provided SYM_DEL_FN() symbol destructors along *                          with the symbol data. *  del_fn() HASH_DEL_FN(*) If you want app_data to be free'd when the *                          hash-table is destroyed, register a suitable *                          destructor function here. * Output: *  return HashTable *  The new hash table, or NULL on error. */HashTable *_new_HashTable(HashMemory *mem, int size, HashCase hcase,			 void *app_data, HASH_DEL_FN(*del_fn)){  HashTable *hash;         /* The table to be returned */  int allocate_mem = !mem; /* True if mem should be internally allocated */  int i;/* * Check arguments. */  if(size <= 0) {    fprintf(stderr, "_new_HashTable: Illegal table size (%d).\n", size);    return NULL;  };/* * Allocate an internal free-list? */  if(allocate_mem) {    mem = _new_HashMemory(1, 100);    if(!mem)      return NULL;  };/* * Allocate the container. */  hash = (HashTable *) _new_FreeListNode(mem->hash_memory);  if(!hash) {    fprintf(stderr, "_new_HashTable: Insufficient memory.\n");    if(allocate_mem)      mem = _del_HashMemory(mem, 1);    return NULL;  };/* * Before attempting any operation that might fail, initialize * the container at least up to the point at which it can safely * be passed to _del_HashTable(). */  hash->errmsg[0] = '\0';  hash->mem = mem;  hash->internal_mem = allocate_mem;  hash->case_sensitive = hcase==HONOUR_CASE;  hash->size = size;  hash->bucket = NULL;  hash->keycmp = hash->case_sensitive ? _ht_strcmp : _ht_lower_strcmp;  hash->app_data = app_data;  hash->del_fn = del_fn;/* * Allocate the array of 'size' hash buckets. */  hash->bucket = (HashBucket *) malloc(sizeof(HashBucket) * size);  if(!hash->bucket) {    fprintf(stderr, "_new_HashTable: Insufficient memory for %d buckets.\n",	    size);    return _del_HashTable(hash);  };/* * Initialize the bucket array. */  for(i=0; i<size; i++) {    HashBucket *b = hash->bucket + i;    b->head = NULL;    b->count = 0;  };/* * The table is ready for use - albeit currently empty. */  return hash;}/*....................................................................... * Delete a hash-table. * * Input: *  hash   HashTable *  The hash table to be deleted. * Output: *  return HashTable *  The deleted hash table (always NULL). */HashTable *_del_HashTable(HashTable *hash){  if(hash) {/* * Clear and delete the bucket array. */    if(hash->bucket) {      _clear_HashTable(hash);      free(hash->bucket);      hash->bucket = NULL;    };/* * Delete application data. */    if(hash->del_fn)      hash->del_fn(hash->app_data);/* * If the hash table was allocated from an internal free-list, delete * it and the hash table by deleting the free-list. Otherwise just * return the hash-table to the external free-list. */    if(hash->internal_mem)      _del_HashMemory(hash->mem, 1);    else      hash = (HashTable *) _del_FreeListNode(hash->mem->hash_memory, hash);  };  return NULL;}/*....................................................................... * Create and install a new entry in a hash table. If an entry with the * same name already exists, replace its contents with the new data. * * Input: *  hash   HashTable *  The hash table to insert the symbol into. *  name  const char *  The name to tag the entry with. *  code         int    An application-specific code to be stored in *                      the entry. *  fn  void (*)(void)  An application-specific function to be stored *                      in the entry. *  data        void *  An application-specific pointer to data to be *                      associated with the entry, or NULL if not *                      relevant. *  del_fn SYM_DEL_FN(*) An optional destructor function. When the *                      symbol is deleted this function will be called *                      with the 'code' and 'data' arguments given *                      above. Any application data that was registered *                      to the table via the app_data argument of *                      _new_HashTable() will also be passed. * Output: *  return  HashNode *  The new entry, or NULL if there was insufficient *                      memory or the arguments were invalid. */Symbol *_new_HashSymbol(HashTable *hash, const char *name, int code,			void (*fn)(void), void *data, SYM_DEL_FN(*del_fn)){  HashBucket *bucket;  /* The hash-bucket associated with the name */  HashNode *node;      /* The new node *//* * Check arguments. */  if(!hash || !name)    return NULL;/* * Get the hash bucket of the specified name. */  bucket = _find_HashBucket(hash, name);/* * See if a node with the same name already exists. */  node = _find_HashNode(hash, bucket, name, NULL);/* * If found, delete its contents by calling the user-supplied * destructor function, if provided. */  if(node) {    if(node->symbol.data && node->symbol.del_fn) {      node->symbol.data = node->symbol.del_fn(hash->app_data, node->symbol.code,					      node->symbol.data);    };/* * Allocate a new node if necessary. */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -