2
0

hash.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /* $XConsortium: hash.c /main/1 1996/04/21 19:23:21 drk $ */
  24. /*
  25. * (c) Copyright 1993, 1994 Hewlett-Packard Company
  26. * (c) Copyright 1993, 1994 International Business Machines Corp.
  27. * (c) Copyright 1993, 1994 Novell, Inc.
  28. * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
  29. */
  30. /*
  31. Synopsis:
  32. #include "hash.h"
  33. void * _DtCmMakeHash(int size)
  34. void * _DtCmMakeIHash(int size)
  35. void ** _DtCmGetHash(void * tbl, unsigned char * key)
  36. void ** _DtCmFindHash(void * tbl,unsigned char * key)
  37. void ** _DtCmDelHash(void * tbl, unsigned char * key)
  38. int _DtCmOperateHash(void * tbl, void (*op_func)(), void * usr_arg)
  39. void _DtCmDestroyHash(void * tbl, int (*des_func)(), void * usr_arg)
  40. Description:
  41. These routines provide a general purpose hash table facility that
  42. supports multiple open hash tables. Each entry in the table consists of a
  43. key and a data ptr. The key is a null terminated character string, while
  44. the data ptr is opaque. Since all the entries are maintained in a doubly
  45. linked lists, deletions and operations on entire table execute very quickly.
  46. This make these routines suitable for use when the tables may be very ephemeral.
  47. _DtCmMakeHash returns a pointer to the created table. The size argument
  48. indicate the number of buckets the routine is to allocate. This should be ~
  49. the max number of items expected in the table for maximum performance....
  50. but /2 or /3 should still be ok. Note that for maximum efficiency the hash
  51. table size should be a prime number (a side effect of the hash alorithm).
  52. _DtCmMakeIHash performs the same function as _DtCmMakeHash, except that the hash
  53. routines will use the key arguments as arbitrary integers rather than strings.
  54. _DtCmGetHash searches the specified hash table tbl for an entry with the
  55. specified key. If the entry does not exist, it is created with a NULL data
  56. ptr. The routine returns a ptr to the area where the data ptr is (can be)
  57. stored.
  58. _DtCmFindHash searchs the table for an entry with the specified key. If the
  59. entry is found, the address of the data pointer associated with the key is
  60. returned. If no such entry exists, the routine returns NULL.
  61. _DtCmDelHash deletes the specified table entry and returns the associated data
  62. ptr. If the entry did not exist ( or the data ptr was NULL), the routine
  63. returns NULL.
  64. _DtCmOperateHash calls the routine pointed to by op_func once for each entry
  65. in tbl, with three arguments: the data ptr, the usr_arg ptr and a ptr to the
  66. key for that entry (which should NOT be altered). This is useful for
  67. transversing a hash table quickly and operating on the entries. Note that
  68. the order of the traversal of the hash table is the reverse order of
  69. insertion.
  70. _DtCmDestroyHash destroys the specified hash table after operating on it
  71. with the specified des_func function as described for _DtCmOperateHash. All storage
  72. allocated by the hash routines is reclaimed.
  73. Author: Bart Smaalders 1/89
  74. */
  75. #include <EUSCompat.h>
  76. #include <stdio.h> /* grab NULL define */
  77. #include <stdlib.h>
  78. #include <string.h>
  79. #include "hash.h"
  80. static int hash_string(const char *s, int modulo);
  81. typedef struct hash_entry {
  82. struct hash_entry
  83. * next_entry,
  84. * right_entry,
  85. * left_entry;
  86. unsigned char * key;
  87. void * data;
  88. } hash_entry;
  89. typedef struct hash {
  90. int size;
  91. hash_entry ** table;
  92. hash_entry * start;
  93. enum hash_type { String_Key = 0 , Integer_Key = 1} hash_type;
  94. } hash;
  95. void * _DtCmMakeHash(int size)
  96. {
  97. hash * ptr;
  98. ptr = (hash *) malloc(sizeof(*ptr));
  99. ptr->size = size;
  100. ptr->table = (hash_entry **) malloc( (unsigned) (sizeof(hash_entry *) * size) );
  101. (void)memset((char *) ptr->table, (char) 0, sizeof(hash_entry *)*size);
  102. ptr->start = NULL;
  103. ptr->hash_type = String_Key;
  104. return((void*)ptr);
  105. }
  106. void ** _DtCmGetHash(void * t, const unsigned char * key)
  107. {
  108. hash * tbl = (hash *) t;
  109. int bucket;
  110. hash_entry * tmp;
  111. hash_entry * new;
  112. if(tbl->hash_type == String_Key)
  113. tmp = tbl->table[bucket = hash_string(key, tbl->size)];
  114. else
  115. tmp = tbl->table[bucket = abs((long)key) % tbl->size];
  116. if(tbl->hash_type == String_Key)
  117. while(tmp!=NULL)
  118. {
  119. if(strcmp((char *)tmp->key, (char *)key)==0)
  120. return(&tmp->data);
  121. tmp = tmp->next_entry;
  122. }
  123. else
  124. while(tmp!=NULL)
  125. {
  126. if(tmp->key == key)
  127. return(&tmp->data);
  128. tmp = tmp->next_entry;
  129. }
  130. /*
  131. not found....
  132. insert new entry into bucket...
  133. */
  134. new = (hash_entry *) malloc(sizeof(*new));
  135. new->key = (unsigned char *)((tbl->hash_type == String_Key)?(unsigned char *)strdup((char *)key):key);
  136. /*
  137. hook into chain from tbl...
  138. */
  139. new->right_entry = NULL;
  140. new->left_entry = tbl->start;
  141. tbl->start = new;
  142. /*
  143. hook into bucket chain
  144. */
  145. new->next_entry = tbl->table[bucket];
  146. tbl->table[bucket] = new;
  147. new->data = NULL; /* so we know that it is new */
  148. return((void*)& new->data);
  149. }
  150. void ** _DtCmFindHash(void * t, const unsigned char * key)
  151. {
  152. hash * tbl = (hash *) t;
  153. hash_entry * tmp;
  154. if(tbl->hash_type == String_Key)
  155. {
  156. tmp = tbl->table[hash_string(key, tbl->size)];
  157. for(;tmp!=NULL; tmp = tmp->next_entry)
  158. if(!strcmp((char *)tmp->key, (char *)key))
  159. return((void *)&tmp->data);
  160. }
  161. else
  162. {
  163. tmp = tbl->table[abs((long)key) % tbl->size];
  164. for(;tmp!=NULL; tmp = tmp->next_entry)
  165. if(tmp->key == key)
  166. return((void *)&tmp->data);
  167. }
  168. return(NULL);
  169. }
  170. void _DtCmDestroyHash(void * t, int (*ptr)(void *, void *, unsigned char *), void * usr_arg)
  171. {
  172. hash * tbl = (hash *) t;
  173. hash_entry * tmp = tbl->start, * prev;
  174. while(tmp)
  175. {
  176. if(ptr)
  177. (*ptr)(tmp->data,usr_arg, tmp->key);
  178. if(tbl->hash_type == String_Key)
  179. free(tmp->key);
  180. prev = tmp;
  181. tmp = tmp->left_entry;
  182. free((char *)prev);
  183. }
  184. free((char *)tbl->table);
  185. free(tbl);
  186. }
  187. static int hash_string(const char *s, int modulo)
  188. {
  189. unsigned result = 0;
  190. int i=1;
  191. while(*s!=0)
  192. result += (*s++ << i++);
  193. return(result % modulo);
  194. }