dthash.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. #include <cdt/dthdr.h>
  2. #include <stdlib.h>
  3. /* Hash table.
  4. ** dt: dictionary
  5. ** obj: what to look for
  6. ** type: type of search
  7. **
  8. ** Written by Kiem-Phong Vo (05/25/96)
  9. */
  10. /* resize the hash table */
  11. static void dthtab(Dt_t* dt)
  12. {
  13. Dtlink_t *t, *r, *p, **s, **hs, **is, **olds;
  14. int n;
  15. /* compute new table size */
  16. if((n = dt->data->ntab) == 0)
  17. n = HSLOT;
  18. while(dt->data->size > HLOAD(n))
  19. n = HRESIZE(n);
  20. if(n == dt->data->ntab)
  21. return;
  22. /* allocate new table */
  23. olds = dt->data->ntab == 0 ? NULL : dt->data->htab;
  24. if (!(s = realloc(olds, n * sizeof(Dtlink_t*))))
  25. return;
  26. olds = s + dt->data->ntab;
  27. dt->data->htab = s;
  28. dt->data->ntab = n;
  29. /* rehash elements */
  30. for(hs = s+n-1; hs >= olds; --hs)
  31. *hs = NULL;
  32. for(hs = s; hs < olds; ++hs)
  33. { for(p = NULL, t = *hs; t; t = r)
  34. { r = t->right;
  35. if((is = s + HINDEX(n,t->hash)) == hs)
  36. p = t;
  37. else /* move to a new chain */
  38. { if(p)
  39. p->right = r;
  40. else *hs = r;
  41. t->right = *is; *is = t;
  42. }
  43. }
  44. }
  45. }
  46. static void* dthash(Dt_t* dt, void* obj, int type)
  47. {
  48. Dtlink_t *t, *r = NULL, *p;
  49. void *k, *key;
  50. unsigned hsh;
  51. int lk, sz, ky;
  52. Dtcompar_f cmpf;
  53. Dtdisc_t* disc;
  54. Dtlink_t **s = NULL, **ends;
  55. UNFLATTEN(dt);
  56. /* initialize discipline data */
  57. disc = dt->disc; _DTDSC(disc,ky,sz,lk,cmpf);
  58. if(!obj)
  59. { if(type&(DT_NEXT|DT_PREV))
  60. goto end_walk;
  61. if(dt->data->size <= 0 || !(type&(DT_CLEAR|DT_FIRST|DT_LAST)) )
  62. return NULL;
  63. ends = (s = dt->data->htab) + dt->data->ntab;
  64. if(type&DT_CLEAR)
  65. { /* clean out all objects */
  66. for(; s < ends; ++s)
  67. { t = *s;
  68. *s = NULL;
  69. if(!disc->freef && disc->link >= 0)
  70. continue;
  71. while(t)
  72. { r = t->right;
  73. if(disc->freef)
  74. disc->freef(_DTOBJ(t, lk));
  75. if(disc->link < 0)
  76. free(t);
  77. t = r;
  78. }
  79. }
  80. dt->data->here = NULL;
  81. dt->data->size = 0;
  82. dt->data->loop = 0;
  83. return NULL;
  84. }
  85. else /* computing the first/last object */
  86. { t = NULL;
  87. while(s < ends && !t )
  88. t = (type&DT_LAST) ? *--ends : *s++;
  89. if(t && (type&DT_LAST))
  90. for(; t->right; t = t->right)
  91. ;
  92. dt->data->loop += 1;
  93. dt->data->here = t;
  94. return t ? _DTOBJ(t,lk) : NULL;
  95. }
  96. }
  97. if(type&(DT_MATCH|DT_SEARCH|DT_INSERT) )
  98. { key = (type&DT_MATCH) ? obj : _DTKEY(obj,ky,sz);
  99. hsh = dtstrhash(key, sz);
  100. goto do_search;
  101. }
  102. else if(type&(DT_RENEW|DT_VSEARCH) )
  103. { r = obj;
  104. obj = _DTOBJ(r,lk);
  105. key = _DTKEY(obj,ky,sz);
  106. hsh = r->hash;
  107. goto do_search;
  108. }
  109. else /*if(type&(DT_DELETE|DT_DETACH|DT_NEXT|DT_PREV))*/
  110. { if((t = dt->data->here) && _DTOBJ(t,lk) == obj)
  111. { hsh = t->hash;
  112. s = dt->data->htab + HINDEX(dt->data->ntab,hsh);
  113. p = NULL;
  114. }
  115. else
  116. { key = _DTKEY(obj,ky,sz);
  117. hsh = dtstrhash(key, sz);
  118. do_search:
  119. t = dt->data->ntab <= 0 ? NULL :
  120. *(s = dt->data->htab + HINDEX(dt->data->ntab,hsh));
  121. for(p = NULL; t; p = t, t = t->right)
  122. { if(hsh == t->hash)
  123. { k = _DTOBJ(t,lk); k = _DTKEY(k,ky,sz);
  124. if(_DTCMP(key, k, cmpf, sz) == 0)
  125. break;
  126. }
  127. }
  128. }
  129. }
  130. if(type&(DT_MATCH|DT_SEARCH|DT_VSEARCH))
  131. { if(!t)
  132. return NULL;
  133. if(p && (dt->data->type&DT_SET) && dt->data->loop <= 0)
  134. { /* move-to-front heuristic */
  135. p->right = t->right;
  136. t->right = *s;
  137. *s = t;
  138. }
  139. dt->data->here = t;
  140. return _DTOBJ(t,lk);
  141. }
  142. else if(type&DT_INSERT)
  143. { if(t && (dt->data->type&DT_SET) )
  144. { dt->data->here = t;
  145. return _DTOBJ(t,lk);
  146. }
  147. if (disc->makef && (type&DT_INSERT) && !(obj = disc->makef(obj, disc)))
  148. return NULL;
  149. if(lk >= 0)
  150. r = _DTLNK(obj,lk);
  151. else
  152. { r = malloc(sizeof(Dthold_t));
  153. if(r)
  154. ((Dthold_t*)r)->obj = obj;
  155. else
  156. { if(disc->makef && disc->freef && (type&DT_INSERT))
  157. disc->freef(obj);
  158. return NULL;
  159. }
  160. }
  161. r->hash = hsh;
  162. /* insert object */
  163. do_insert:
  164. if((dt->data->size += 1) > HLOAD(dt->data->ntab) && dt->data->loop <= 0 )
  165. dthtab(dt);
  166. if(dt->data->ntab == 0)
  167. { dt->data->size -= 1;
  168. if(disc->freef && (type&DT_INSERT))
  169. disc->freef(obj);
  170. if(disc->link < 0)
  171. free(r);
  172. return NULL;
  173. }
  174. s = dt->data->htab + HINDEX(dt->data->ntab,hsh);
  175. if(t)
  176. { r->right = t->right;
  177. t->right = r;
  178. }
  179. else
  180. { r->right = *s;
  181. *s = r;
  182. }
  183. dt->data->here = r;
  184. return obj;
  185. }
  186. else if(type&DT_NEXT)
  187. { if(t && !(p = t->right) )
  188. { for(ends = dt->data->htab+dt->data->ntab, s += 1; s < ends; ++s)
  189. if((p = *s) )
  190. break;
  191. }
  192. goto done_adj;
  193. }
  194. else if(type&DT_PREV)
  195. { if(t && !p)
  196. { if((p = *s) != t)
  197. { while(p->right != t)
  198. p = p->right;
  199. }
  200. else
  201. { p = NULL;
  202. for(s -= 1, ends = dt->data->htab; s >= ends; --s)
  203. { if((p = *s) )
  204. { while(p->right)
  205. p = p->right;
  206. break;
  207. }
  208. }
  209. }
  210. }
  211. done_adj:
  212. if(!(dt->data->here = p) )
  213. { end_walk:
  214. if((dt->data->loop -= 1) < 0)
  215. dt->data->loop = 0;
  216. if(dt->data->size > HLOAD(dt->data->ntab) && dt->data->loop <= 0)
  217. dthtab(dt);
  218. return NULL;
  219. }
  220. else
  221. { dt->data->type |= DT_WALK;
  222. return _DTOBJ(p,lk);
  223. }
  224. }
  225. else if(type&DT_RENEW)
  226. { if(!t)
  227. goto do_insert;
  228. else
  229. { if(disc->freef)
  230. disc->freef(obj);
  231. if(disc->link < 0)
  232. free(r);
  233. return t ? _DTOBJ(t,lk) : NULL;
  234. }
  235. }
  236. else /*if(type&(DT_DELETE|DT_DETACH))*/
  237. { /* take an element out of the dictionary */
  238. if(!t)
  239. return NULL;
  240. else if(p)
  241. p->right = t->right;
  242. else if((p = *s) == t)
  243. p = *s = t->right;
  244. else
  245. { while(p->right != t)
  246. p = p->right;
  247. p->right = t->right;
  248. }
  249. obj = _DTOBJ(t,lk);
  250. dt->data->size -= 1;
  251. dt->data->here = p;
  252. if(disc->freef && (type&DT_DELETE))
  253. disc->freef(obj);
  254. if(disc->link < 0)
  255. free(t);
  256. return obj;
  257. }
  258. }
  259. static Dtmethod_t _Dtset = { dthash, DT_SET };
  260. Dtmethod_t* Dtset = &_Dtset;