-fixes
[oweals/gnunet.git] / src / util / container_multihashmap32.c
1 /*
2      This file is part of GNUnet.
3      (C) 2008 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20 /**
21  * @file util/container_multihashmap32.c
22  * @brief a version of hash map implemented in container_multihashmap.c but with
23  *          uint32_t as keys
24  * @author Christian Grothoff
25  * @author Sree Harsha Totakura
26  */
27
28 #include "platform.h"
29 #include "gnunet_util_lib.h"
30
31 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
32
33 /**
34  * An entry in the hash map.
35  */
36 struct MapEntry
37 {
38
39   /**
40    * Key for the entry.
41    */
42   uint32_t key;
43
44   /**
45    * Value of the entry.
46    */
47   void *value;
48
49   /**
50    * If there is a hash collision, we create a linked list.
51    */
52   struct MapEntry *next;
53
54 };
55
56 /**
57  * Internal representation of the hash map.
58  */
59 struct GNUNET_CONTAINER_MultiHashMap32
60 {
61
62   /**
63    * All of our buckets.
64    */
65   struct MapEntry **map;
66
67   /**
68    * Number of entries in the map.
69    */
70   unsigned int size;
71
72   /**
73    * Length of the "map" array.
74    */
75   unsigned int map_length;
76 };
77
78
79 /**
80  * Create a multi hash map.
81  *
82  * @param len initial size (map will grow as needed)
83  * @return NULL on error
84  */
85 struct GNUNET_CONTAINER_MultiHashMap32 *
86 GNUNET_CONTAINER_multihashmap32_create (unsigned int len)
87 {
88   struct GNUNET_CONTAINER_MultiHashMap32 *ret;
89
90   GNUNET_assert (len > 0);
91   ret = GNUNET_new (struct GNUNET_CONTAINER_MultiHashMap32);
92   ret->map = GNUNET_malloc (len * sizeof (struct MapEntry *));
93   ret->map_length = len;
94   return ret;
95 }
96
97
98 /**
99  * Destroy a hash map.  Will not free any values
100  * stored in the hash map!
101  *
102  * @param map the map
103  */
104 void
105 GNUNET_CONTAINER_multihashmap32_destroy (struct GNUNET_CONTAINER_MultiHashMap32
106                                          *map)
107 {
108   unsigned int i;
109   struct MapEntry *e;
110
111   for (i = 0; i < map->map_length; i++)
112   {
113     while (NULL != (e = map->map[i]))
114     {
115       map->map[i] = e->next;
116       GNUNET_free (e);
117     }
118   }
119   GNUNET_free (map->map);
120   GNUNET_free (map);
121 }
122
123
124 /**
125  * Compute the index of the bucket for the given key.
126  *
127  * @param m hash map for which to compute the index
128  * @param key what key should the index be computed for
129  * @return offset into the "map" array of "m"
130  */
131 static unsigned int
132 idx_of (const struct GNUNET_CONTAINER_MultiHashMap32 *m,
133         const uint32_t key)
134 {
135   GNUNET_assert (m != NULL);
136   return ((unsigned int) key) % m->map_length;
137 }
138
139
140 /**
141  * Get the number of key-value pairs in the map.
142  *
143  * @param map the map
144  * @return the number of key value pairs
145  */
146 unsigned int
147 GNUNET_CONTAINER_multihashmap32_size (const struct
148                                       GNUNET_CONTAINER_MultiHashMap32 *map)
149 {
150   return map->size;
151 }
152
153
154 /**
155  * Given a key find a value in the map matching the key.
156  *
157  * @param map the map
158  * @param key what to look for
159  * @return NULL if no value was found; note that
160  *   this is indistinguishable from values that just
161  *   happen to be NULL; use "contains" to test for
162  *   key-value pairs with value NULL
163  */
164 void *
165 GNUNET_CONTAINER_multihashmap32_get (const struct
166                                      GNUNET_CONTAINER_MultiHashMap32 *map,
167                                      uint32_t key)
168 {
169   struct MapEntry *e;
170
171   e = map->map[idx_of (map, key)];
172   while (e != NULL)
173   {
174     if (key == e->key)
175       return e->value;
176     e = e->next;
177   }
178   return NULL;
179 }
180
181
182 /**
183  * Iterate over all entries in the map.
184  *
185  * @param map the map
186  * @param it function to call on each entry
187  * @param it_cls extra argument to it
188  * @return the number of key value pairs processed,
189  *         GNUNET_SYSERR if it aborted iteration
190  */
191 int
192 GNUNET_CONTAINER_multihashmap32_iterate (const struct
193                                          GNUNET_CONTAINER_MultiHashMap32 *map,
194                                          GNUNET_CONTAINER_HashMapIterator32 it,
195                                          void *it_cls)
196 {
197   int count;
198   unsigned int i;
199   struct MapEntry *e;
200   struct MapEntry *n;
201
202   count = 0;
203   GNUNET_assert (map != NULL);
204   for (i = 0; i < map->map_length; i++)
205   {
206     n = map->map[i];
207     while (NULL != (e = n))
208     {
209       n = e->next;
210       if (NULL != it)
211       {
212         if (GNUNET_OK != it (it_cls, e->key, e->value))
213           return GNUNET_SYSERR;
214       }
215       count++;
216     }
217   }
218   return count;
219 }
220
221
222 /**
223  * Remove the given key-value pair from the map.  Note that if the
224  * key-value pair is in the map multiple times, only one of the pairs
225  * will be removed.
226  *
227  * @param map the map
228  * @param key key of the key-value pair
229  * @param value value of the key-value pair
230  * @return GNUNET_YES on success, GNUNET_NO if the key-value pair
231  *  is not in the map
232  */
233 int
234 GNUNET_CONTAINER_multihashmap32_remove (struct GNUNET_CONTAINER_MultiHashMap32
235                                         *map,
236                                         uint32_t key, const void *value)
237 {
238   struct MapEntry *e;
239   struct MapEntry *p;
240   unsigned int i;
241
242   i = idx_of (map, key);
243   p = NULL;
244   e = map->map[i];
245   while (e != NULL)
246   {
247     if ( (key == e->key) && (value == e->value) )
248     {
249       if (p == NULL)
250         map->map[i] = e->next;
251       else
252         p->next = e->next;
253       GNUNET_free (e);
254       map->size--;
255       return GNUNET_YES;
256     }
257     p = e;
258     e = e->next;
259   }
260   return GNUNET_NO;
261 }
262
263
264 /**
265  * Remove all entries for the given key from the map.
266  * Note that the values would not be "freed".
267  *
268  * @param map the map
269  * @param key identifies values to be removed
270  * @return number of values removed
271  */
272 int
273 GNUNET_CONTAINER_multihashmap32_remove_all (struct
274                                             GNUNET_CONTAINER_MultiHashMap32
275                                             *map,
276                                             uint32_t key)
277 {
278   struct MapEntry *e;
279   struct MapEntry *p;
280   unsigned int i;
281   int ret;
282
283   ret = 0;
284   i = idx_of (map, key);
285   p = NULL;
286   e = map->map[i];
287   while (e != NULL)
288   {
289     if (key == e->key)
290     {
291       if (p == NULL)
292         map->map[i] = e->next;
293       else
294         p->next = e->next;
295       GNUNET_free (e);
296       map->size--;
297       if (p == NULL)
298         e = map->map[i];
299       else
300         e = p->next;
301       ret++;
302     }
303     else
304     {
305       p = e;
306       e = e->next;
307     }
308   }
309   return ret;
310 }
311
312
313 /**
314  * Check if the map contains any value under the given
315  * key (including values that are NULL).
316  *
317  * @param map the map
318  * @param key the key to test if a value exists for it
319  * @return GNUNET_YES if such a value exists,
320  *         GNUNET_NO if not
321  */
322 int
323 GNUNET_CONTAINER_multihashmap32_contains (const struct
324                                           GNUNET_CONTAINER_MultiHashMap32 *map,
325                                           uint32_t key)
326 {
327   struct MapEntry *e;
328
329   e = map->map[idx_of (map, key)];
330   while (e != NULL)
331   {
332     if (key == e->key)
333       return GNUNET_YES;
334     e = e->next;
335   }
336   return GNUNET_NO;
337 }
338
339
340 /**
341  * Check if the map contains the given value under the given
342  * key.
343  *
344  * @param map the map
345  * @param key the key to test if a value exists for it
346  * @param value value to test for
347  * @return GNUNET_YES if such a value exists,
348  *         GNUNET_NO if not
349  */
350 int
351 GNUNET_CONTAINER_multihashmap32_contains_value (const struct
352                                                 GNUNET_CONTAINER_MultiHashMap32
353                                                 *map,
354                                                 uint32_t key,
355                                                 const void *value)
356 {
357   struct MapEntry *e;
358
359   e = map->map[idx_of (map, key)];
360   while (e != NULL)
361   {
362     if ( (key == e->key) && (e->value == value) )
363       return GNUNET_YES;
364     e = e->next;
365   }
366   return GNUNET_NO;
367 }
368
369
370 /**
371  * Grow the given map to a more appropriate size.
372  *
373  * @param map the hash map to grow
374  */
375 static void
376 grow (struct GNUNET_CONTAINER_MultiHashMap32 *map)
377 {
378   struct MapEntry **old_map;
379   struct MapEntry **new_map;
380   struct MapEntry *e;
381   unsigned int old_len;
382   unsigned int new_len;
383   unsigned int idx;
384   unsigned int i;
385
386   old_map = map->map;
387   old_len = map->map_length;
388   new_len = old_len * 2;
389   new_map = GNUNET_malloc (sizeof (struct MapEntry *) * new_len);
390   map->map_length = new_len;
391   map->map = new_map;
392   for (i = 0; i < old_len; i++)
393   {
394     while (NULL != (e = old_map[i]))
395     {
396       old_map[i] = e->next;
397       idx = idx_of (map, e->key);
398       e->next = new_map[idx];
399       new_map[idx] = e;
400     }
401   }
402   GNUNET_free (old_map);
403 }
404
405
406 /**
407  * Store a key-value pair in the map.
408  *
409  * @param map the map
410  * @param key key to use
411  * @param value value to use
412  * @param opt options for put
413  * @return GNUNET_OK on success,
414  *         GNUNET_NO if a value was replaced (with REPLACE)
415  *         GNUNET_SYSERR if UNIQUE_ONLY was the option and the
416  *                       value already exists
417  */
418 int
419 GNUNET_CONTAINER_multihashmap32_put (struct GNUNET_CONTAINER_MultiHashMap32
420                                      *map, uint32_t key, void *value,
421                                      enum GNUNET_CONTAINER_MultiHashMapOption
422                                      opt)
423 {
424   struct MapEntry *e;
425   unsigned int i;
426
427   i = idx_of (map, key);
428   if ((opt != GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE) &&
429       (opt != GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
430   {
431     e = map->map[i];
432     while (e != NULL)
433     {
434       if (key == e->key)
435       {
436         if (opt == GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)
437           return GNUNET_SYSERR;
438         e->value = value;
439         return GNUNET_NO;
440       }
441       e = e->next;
442     }
443   }
444   if (map->size / 3 >= map->map_length / 4)
445   {
446     grow (map);
447     i = idx_of (map, key);
448   }
449   e = GNUNET_new (struct MapEntry);
450   e->key = key;
451   e->value = value;
452   e->next = map->map[i];
453   map->map[i] = e;
454   map->size++;
455   return GNUNET_OK;
456 }
457
458
459 /**
460  * Iterate over all entries in the map that match a particular key.
461  *
462  * @param map the map
463  * @param key key that the entries must correspond to
464  * @param it function to call on each entry
465  * @param it_cls extra argument to it
466  * @return the number of key value pairs processed,
467  *         GNUNET_SYSERR if it aborted iteration
468  */
469 int
470 GNUNET_CONTAINER_multihashmap32_get_multiple (const struct
471                                               GNUNET_CONTAINER_MultiHashMap32
472                                               *map, uint32_t key,
473                                               GNUNET_CONTAINER_HashMapIterator32
474                                               it, void *it_cls)
475 {
476   int count;
477   struct MapEntry *e;
478   struct MapEntry *n;
479
480   count = 0;
481   n = map->map[idx_of (map, key)];
482   while (NULL != (e = n))
483   {
484     n = e->next;
485     if (key != e->key)
486       continue;
487     if ((it != NULL) && (GNUNET_OK != it (it_cls, key, e->value)))
488       return GNUNET_SYSERR;
489     count++;
490   }
491   return count;
492 }
493
494
495 /* end of container_multihashmap.c */