MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
genhash.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <math.h>
4 #include <assert.h>
5 
6 #include <memcached/genhash.h>
7 #include "genhash_int.h"
8 
9 /* Table of 32 primes by their distance from the nearest power of two */
10 static int prime_size_table[]={
11  3, 7, 13, 23, 47, 97, 193, 383, 769, 1531, 3067, 6143, 12289, 24571, 49157,
12  98299, 196613, 393209, 786433, 1572869, 3145721, 6291449, 12582917,
13  25165813, 50331653, 100663291, 201326611, 402653189, 805306357,
14  1610612741
15 };
16 
17 static inline void*
18 dup_key(genhash_t *h, const void *key, size_t klen)
19 {
20  if (h->ops.dupKey != NULL) {
21  return h->ops.dupKey(key, klen);
22  } else {
23  return (void*)key;
24  }
25 }
26 
27 static inline void*
28 dup_value(genhash_t *h, const void *value, size_t vlen)
29 {
30  if (h->ops.dupValue != NULL) {
31  return h->ops.dupValue(value, vlen);
32  } else {
33  return (void*)value;
34  }
35 }
36 
37 static inline void
38 free_key(genhash_t *h, void *key)
39 {
40  if (h->ops.freeKey != NULL) {
41  h->ops.freeKey(key);
42  }
43 }
44 
45 static inline void
46 free_value(genhash_t *h, void *value)
47 {
48  if (h->ops.freeValue != NULL) {
49  h->ops.freeValue(value);
50  }
51 }
52 
53 static int
54 estimate_table_size(int est)
55 {
56  int rv=0;
57  int magn=0;
58  assert(est > 0);
59  magn=(int)log((double)est)/log(2);
60  magn--;
61  magn = (magn < 0) ? 0 : magn;
62  assert(magn < (sizeof(prime_size_table) / sizeof(int)));
63  rv=prime_size_table[magn];
64  return rv;
65 }
66 
67 genhash_t* genhash_init(int est, struct hash_ops ops)
68 {
69  genhash_t* rv=NULL;
70  int size=0;
71  if (est < 1) {
72  return NULL;
73  }
74 
75  assert(ops.hashfunc != NULL);
76  assert(ops.hasheq != NULL);
77  assert((ops.dupKey != NULL && ops.freeKey != NULL) || ops.freeKey == NULL);
78  assert((ops.dupValue != NULL && ops.freeValue != NULL) || ops.freeValue == NULL);
79 
80  size=estimate_table_size(est);
81  rv=calloc(1, sizeof(genhash_t)
82  + (size * sizeof(struct genhash_entry_t *)));
83  assert(rv != NULL);
84  rv->size=size;
85  rv->ops=ops;
86 
87  return rv;
88 }
89 
90 void
92 {
93  if(h != NULL) {
94  genhash_clear(h);
95  free(h);
96  }
97 }
98 
99 void
100 genhash_store(genhash_t *h, const void* k, size_t klen,
101  const void* v, size_t vlen)
102 {
103  int n=0;
104  struct genhash_entry_t *p;
105 
106  assert(h != NULL);
107 
108  n=h->ops.hashfunc(k, klen) % h->size;
109  assert(n >= 0);
110  assert(n < h->size);
111 
112  p=calloc(1, sizeof(struct genhash_entry_t));
113  assert(p);
114 
115  p->key=dup_key(h, k, klen);
116  p->nkey = klen;
117  p->value=dup_value(h, v, vlen);
118  p->nvalue = vlen;
119 
120  p->next=h->buckets[n];
121  h->buckets[n]=p;
122 }
123 
124 static struct genhash_entry_t *
125 genhash_find_entry(genhash_t *h, const void* k, size_t klen)
126 {
127  int n=0;
128  struct genhash_entry_t *p;
129 
130  assert(h != NULL);
131  n=h->ops.hashfunc(k, klen) % h->size;
132  assert(n >= 0);
133  assert(n < h->size);
134 
135  p=h->buckets[n];
136  for(p=h->buckets[n]; p && !h->ops.hasheq(k, klen, p->key, p->nkey); p=p->next);
137  return p;
138 }
139 
140 void*
141 genhash_find(genhash_t *h, const void* k, size_t klen)
142 {
143  struct genhash_entry_t *p;
144  void *rv=NULL;
145 
146  p=genhash_find_entry(h, k, klen);
147 
148  if(p) {
149  rv=p->value;
150  }
151  return rv;
152 }
153 
154 enum update_type
155 genhash_update(genhash_t* h, const void* k, size_t klen,
156  const void* v, size_t vlen)
157 {
158  struct genhash_entry_t *p;
159  enum update_type rv=0;
160 
161  p=genhash_find_entry(h, k, klen);
162 
163  if(p) {
164  free_value(h, p->value);
165  p->value=dup_value(h, v, vlen);
166  rv=MODIFICATION;
167  } else {
168  genhash_store(h, k, klen, v, vlen);
169  rv=NEW;
170  }
171 
172  return rv;
173 }
174 
175 enum update_type
176 genhash_fun_update(genhash_t* h, const void* k, size_t klen,
177  void *(*upd)(const void *, const void *, size_t *, void *),
178  void (*fr)(void*),
179  void *arg,
180  const void *def, size_t deflen)
181 {
182  struct genhash_entry_t *p;
183  enum update_type rv=0;
184  size_t newSize = 0;
185 
186  p=genhash_find_entry(h, k, klen);
187 
188  if(p) {
189  void *newValue=upd(k, p->value, &newSize, arg);
190  free_value(h, p->value);
191  p->value=dup_value(h, newValue, newSize);
192  fr(newValue);
193  rv=MODIFICATION;
194  } else {
195  void *newValue=upd(k, def, &newSize, arg);
196  genhash_store(h, k, klen, newValue, newSize);
197  fr(newValue);
198  rv=NEW;
199  }
200 
201  return rv;
202 }
203 
204 static void
205 free_item(genhash_t *h, struct genhash_entry_t *i)
206 {
207  assert(i);
208  free_key(h, i->key);
209  free_value(h, i->value);
210  free(i);
211 }
212 
213 int
214 genhash_delete(genhash_t* h, const void* k, size_t klen)
215 {
216  struct genhash_entry_t *deleteme=NULL;
217  int n=0;
218  int rv=0;
219 
220  assert(h != NULL);
221  n=h->ops.hashfunc(k, klen) % h->size;
222  assert(n >= 0);
223  assert(n < h->size);
224 
225  if(h->buckets[n] != NULL) {
226  /* Special case the first one */
227  if(h->ops.hasheq(h->buckets[n]->key, h->buckets[n]->nkey, k, klen)) {
228  deleteme=h->buckets[n];
229  h->buckets[n]=deleteme->next;
230  } else {
231  struct genhash_entry_t *p=NULL;
232  for(p=h->buckets[n]; deleteme==NULL && p->next != NULL; p=p->next) {
233  if(h->ops.hasheq(p->next->key, p->next->nkey, k, klen)) {
234  deleteme=p->next;
235  p->next=deleteme->next;
236  }
237  }
238  }
239  }
240  if(deleteme != NULL) {
241  free_item(h, deleteme);
242  rv++;
243  }
244 
245  return rv;
246 }
247 
248 int
249 genhash_delete_all(genhash_t* h, const void* k, size_t klen)
250 {
251  int rv=0;
252  while(genhash_delete(h, k, klen) == 1) {
253  rv++;
254  }
255  return rv;
256 }
257 
258 void
260  void (*iterfunc)(const void* key, size_t nkey,
261  const void* val, size_t nval,
262  void *arg), void *arg)
263 {
264  int i=0;
265  struct genhash_entry_t *p=NULL;
266  assert(h != NULL);
267 
268  for(i=0; i<h->size; i++) {
269  for(p=h->buckets[i]; p!=NULL; p=p->next) {
270  iterfunc(p->key, p->nkey, p->value, p->nvalue, arg);
271  }
272  }
273 }
274 
275 int
277 {
278  int i = 0, rv = 0;
279  assert(h != NULL);
280 
281  for(i = 0; i < h->size; i++) {
282  while(h->buckets[i]) {
283  struct genhash_entry_t *p = NULL;
284  p = h->buckets[i];
285  h->buckets[i] = p->next;
286  free_item(h, p);
287  }
288  }
289 
290  return rv;
291 }
292 
293 static void
294 count_entries(const void *key, size_t klen,
295  const void *val, size_t vlen, void *arg)
296 {
297  int *count=(int *)arg;
298  (*count)++;
299 }
300 
301 int
303  int rv=0;
304  assert(h != NULL);
305  genhash_iter(h, count_entries, &rv);
306  return rv;
307 }
308 
309 int
310 genhash_size_for_key(genhash_t* h, const void* k, size_t klen)
311 {
312  int rv=0;
313  assert(h != NULL);
314  genhash_iter_key(h, k, klen, count_entries, &rv);
315  return rv;
316 }
317 
318 void
319 genhash_iter_key(genhash_t* h, const void* key, size_t klen,
320  void (*iterfunc)(const void* key, size_t klen,
321  const void* val, size_t vlen,
322  void *arg), void *arg)
323 {
324  int n=0;
325  struct genhash_entry_t *p=NULL;
326 
327  assert(h != NULL);
328  n=h->ops.hashfunc(key, klen) % h->size;
329  assert(n >= 0);
330  assert(n < h->size);
331 
332  for(p=h->buckets[n]; p!=NULL; p=p->next) {
333  if(h->ops.hasheq(key, klen, p->key, p->nkey)) {
334  iterfunc(p->key, p->nkey, p->value, p->nvalue, arg);
335  }
336  }
337 }
338 
339 int
340 genhash_string_hash(const void* p, size_t nkey)
341 {
342  int rv=5381;
343  int i=0;
344  char *str=(char *)p;
345 
346  for(i=0; i < nkey; i++) {
347  rv = ((rv << 5) + rv) ^ str[i];
348  }
349 
350  return rv;
351 }