1 /* Linear probe hash table.
2 * 2004 (C) Tor Andersson.
5 * Simple hashtable with open adressing linear probe.
6 * Unlike text book examples, removing entries works
7 * correctly in this implementation so it wont start
8 * exhibiting bad behaviour if entries are inserted
9 * and removed frequently.
12 #include "fitz-base.h"
14 enum { MAXKEYLEN
= 16 };
16 typedef struct fz_hashentry_s fz_hashentry
;
20 unsigned char key
[MAXKEYLEN
];
32 static unsigned hash(unsigned char *s
, int len
)
36 for (i
= 0; i
< len
; i
++)
49 fz_newhash(fz_hashtable
**tablep
, int initialsize
, int keylen
)
53 assert(keylen
<= MAXKEYLEN
);
55 table
= *tablep
= fz_malloc(sizeof(fz_hashtable
));
59 table
->keylen
= keylen
;
60 table
->size
= initialsize
;
63 table
->ents
= fz_malloc(sizeof(fz_hashentry
) * table
->size
);
71 memset(table
->ents
, 0, sizeof(fz_hashentry
) * table
->size
);
77 fz_emptyhash(fz_hashtable
*table
)
80 memset(table
->ents
, 0, sizeof(fz_hashentry
) * table
->size
);
84 fz_hashlen(fz_hashtable
*table
)
90 fz_hashgetkey(fz_hashtable
*table
, int idx
)
92 return table
->ents
[idx
].key
;
96 fz_hashgetval(fz_hashtable
*table
, int idx
)
98 return table
->ents
[idx
].val
;
102 fz_drophash(fz_hashtable
*table
)
104 fz_free(table
->ents
);
109 fz_resizehash(fz_hashtable
*table
, int newsize
)
112 fz_hashentry
*newents
;
113 fz_hashentry
*oldents
;
118 oldsize
= table
->size
;
119 oldload
= table
->load
;
120 oldents
= table
->ents
;
122 if (newsize
< oldload
* 8 / 10)
123 return fz_throw("rangecheck: resize hash too small");
125 newents
= fz_malloc(sizeof(fz_hashentry
) * newsize
);
129 table
->size
= newsize
;
131 table
->ents
= newents
;
132 memset(table
->ents
, 0, sizeof(fz_hashentry
) * table
->size
);
134 for (i
= 0; i
< oldsize
; i
++)
138 error
= fz_hashinsert(table
, oldents
[i
].key
, oldents
[i
].val
);
141 table
->size
= oldsize
;
142 table
->load
= oldload
;
143 table
->ents
= oldents
;
155 fz_hashfind(fz_hashtable
*table
, void *key
)
157 fz_hashentry
*ents
= table
->ents
;
158 unsigned size
= table
->size
;
159 unsigned pos
= hash(key
, table
->keylen
) % size
;
166 if (memcmp(key
, &ents
[pos
].key
, table
->keylen
) == 0)
167 return ents
[pos
].val
;
169 pos
= (pos
+ 1) % size
;
174 fz_hashinsert(fz_hashtable
*table
, void *key
, void *val
)
181 if (table
->load
> table
->size
* 8 / 10)
183 error
= fz_resizehash(table
, table
->size
* 2);
190 pos
= hash(key
, table
->keylen
) % size
;
196 memcpy(ents
[pos
].key
, key
, table
->keylen
);
202 if (memcmp(key
, &ents
[pos
].key
, table
->keylen
) == 0)
203 return fz_throw("rangecheck: overwrite hash slot");
205 pos
= (pos
+ 1) % size
;
212 fz_hashremove(fz_hashtable
*table
, void *key
)
214 fz_hashentry
*ents
= table
->ents
;
215 unsigned size
= table
->size
;
216 unsigned pos
= hash(key
, table
->keylen
) % size
;
217 unsigned hole
, look
, code
;
222 return fz_throw("rangecheck: remove inexistant hash entry");
224 if (memcmp(key
, &ents
[pos
].key
, table
->keylen
) == 0)
229 look
= (hole
+ 1) % size
;
231 while (ents
[look
].val
)
233 code
= hash(ents
[look
].key
, table
->keylen
) % size
;
234 if ((code
<= hole
&& hole
< look
) ||
235 (look
< code
&& code
<= hole
) ||
236 (hole
< look
&& look
< code
))
238 ents
[hole
] = ents
[look
];
239 ents
[look
].val
= nil
;
243 look
= (look
+ 1) % size
;
250 pos
= (pos
+ 1) % size
;
255 fz_debughash(fz_hashtable
*table
)
259 printf("cache load %d / %d\n", table
->load
, table
->size
);
261 for (i
= 0; i
< table
->size
; i
++)
263 if (!table
->ents
[i
].val
)
264 printf("table % 4d: empty\n", i
);
267 printf("table % 4d: key=", i
);
268 for (k
= 0; k
< MAXKEYLEN
; k
++)
269 printf("%02x", ((char*)table
->ents
[i
].key
)[k
]);
270 printf(" val=$%p\n", table
->ents
[i
].val
);