fix socket cmp, fix compiler warnings about unused args
[oweals/gnunet.git] / src / util / container_multiuuidmap.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2008, 2012 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19 */
20 /**
21  * @file util/container_multiuuidmap.c
22  * @brief hash map for UUIDs where the same key may be present multiple times
23  * @author Christian Grothoff
24  */
25
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28
29 #define LOG(kind, ...) \
30   GNUNET_log_from (kind, "util-container-multiuuidmap", __VA_ARGS__)
31
32 /**
33  * Maximum recursion depth for callbacks of
34  * #GNUNET_CONTAINER_multihashmap_get_multiple() themselve s
35  * again calling #GNUNET_CONTAINER_multihashmap_get_multiple().
36  * Should be totally excessive, but if violated we die.
37  */
38 #define NEXT_CACHE_SIZE 16
39
40
41 /**
42  * An entry in the hash map with the full key.
43  */
44 struct BigMapEntry
45 {
46
47   /**
48    * Value of the entry.
49    */
50   void *value;
51
52   /**
53    * If there is a hash collision, we create a linked list.
54    */
55   struct BigMapEntry *next;
56
57   /**
58    * Key for the entry.
59    */
60   struct GNUNET_Uuid key;
61 };
62
63
64 /**
65  * An entry in the hash map with just a pointer to the key.
66  */
67 struct SmallMapEntry
68 {
69
70   /**
71    * Value of the entry.
72    */
73   void *value;
74
75   /**
76    * If there is a hash collision, we create a linked list.
77    */
78   struct SmallMapEntry *next;
79
80   /**
81    * Key for the entry.
82    */
83   const struct GNUNET_Uuid *key;
84 };
85
86
87 /**
88  * Entry in the map.
89  */
90 union MapEntry
91 {
92   /**
93    * Variant used if map entries only contain a pointer to the key.
94    */
95   struct SmallMapEntry *sme;
96
97   /**
98    * Variant used if map entries contain the full key.
99    */
100   struct BigMapEntry *bme;
101 };
102
103
104 /**
105  * Internal representation of the hash map.
106  */
107 struct GNUNET_CONTAINER_MultiUuidmap
108 {
109   /**
110    * All of our buckets.
111    */
112   union MapEntry *map;
113
114   /**
115    * Number of entries in the map.
116    */
117   unsigned int size;
118
119   /**
120    * Length of the "map" array.
121    */
122   unsigned int map_length;
123
124   /**
125    * #GNUNET_NO if the map entries are of type 'struct BigMapEntry',
126    * #GNUNET_YES if the map entries are of type 'struct SmallMapEntry'.
127    */
128   int use_small_entries;
129
130   /**
131    * Counts the destructive modifications (grow, remove)
132    * to the map, so that iterators can check if they are still valid.
133    */
134   unsigned int modification_counter;
135
136   /**
137    * Map entries indicating iteration positions currently
138    * in use by #GNUNET_CONTAINER_multihashmap_get_multiple().
139    * Only used up to @e next_cache_off.
140    */
141   union MapEntry next_cache[NEXT_CACHE_SIZE];
142
143   /**
144    * Offset of @e next_cache entries in use, must be smaller
145    * than #NEXT_CACHE_SIZE.
146    */
147   unsigned int next_cache_off;
148 };
149
150
151 /**
152  * Cursor into a multiuuidmap.
153  * Allows to enumerate elements asynchronously.
154  */
155 struct GNUNET_CONTAINER_MultiUuidmapIterator
156 {
157   /**
158    * Position in the bucket 'idx'
159    */
160   union MapEntry me;
161
162   /**
163    * Current bucket index.
164    */
165   unsigned int idx;
166
167   /**
168    * Modification counter as observed on the map when the iterator
169    * was created.
170    */
171   unsigned int modification_counter;
172
173   /**
174    * Map that we are iterating over.
175    */
176   const struct GNUNET_CONTAINER_MultiUuidmap *map;
177 };
178
179
180 /**
181  * Create a multi hash map.
182  *
183  * @param len initial size (map will grow as needed)
184  * @param do_not_copy_keys #GNUNET_NO is always safe and should be used by default;
185  *                         #GNUNET_YES means that on 'put', the 'key' does not have
186  *                         to be copied as the destination of the pointer is
187  *                         guaranteed to be life as long as the value is stored in
188  *                         the hashmap.  This can significantly reduce memory
189  *                         consumption, but of course is also a recipie for
190  *                         heap corruption if the assumption is not true.  Only
191  *                         use this if (1) memory use is important in this case and
192  *                         (2) you have triple-checked that the invariant holds
193  * @return NULL on error
194  */
195 struct GNUNET_CONTAINER_MultiUuidmap *
196 GNUNET_CONTAINER_multiuuidmap_create (unsigned int len, int do_not_copy_keys)
197 {
198   struct GNUNET_CONTAINER_MultiUuidmap *map;
199
200   GNUNET_assert (len > 0);
201   map = GNUNET_new (struct GNUNET_CONTAINER_MultiUuidmap);
202   map->map = GNUNET_malloc_large (len * sizeof (union MapEntry));
203   if (NULL == map->map)
204   {
205     GNUNET_free (map);
206     return NULL;
207   }
208   map->map_length = len;
209   map->use_small_entries = do_not_copy_keys;
210   return map;
211 }
212
213
214 /**
215  * Destroy a hash map.  Will not free any values
216  * stored in the hash map!
217  *
218  * @param map the map
219  */
220 void
221 GNUNET_CONTAINER_multiuuidmap_destroy (
222   struct GNUNET_CONTAINER_MultiUuidmap *map)
223 {
224   GNUNET_assert (0 == map->next_cache_off);
225   for (unsigned int i = 0; i < map->map_length; i++)
226   {
227     union MapEntry me;
228
229     me = map->map[i];
230     if (map->use_small_entries)
231     {
232       struct SmallMapEntry *sme;
233       struct SmallMapEntry *nxt;
234
235       nxt = me.sme;
236       while (NULL != (sme = nxt))
237       {
238         nxt = sme->next;
239         GNUNET_free (sme);
240       }
241       me.sme = NULL;
242     }
243     else
244     {
245       struct BigMapEntry *bme;
246       struct BigMapEntry *nxt;
247
248       nxt = me.bme;
249       while (NULL != (bme = nxt))
250       {
251         nxt = bme->next;
252         GNUNET_free (bme);
253       }
254       me.bme = NULL;
255     }
256   }
257   GNUNET_free (map->map);
258   GNUNET_free (map);
259 }
260
261
262 /**
263  * Compute the index of the bucket for the given key.
264  *
265  * @param map hash map for which to compute the index
266  * @param key what key should the index be computed for
267  * @return offset into the "map" array of "map"
268  */
269 static unsigned int
270 idx_of (const struct GNUNET_CONTAINER_MultiUuidmap *map,
271         const struct GNUNET_Uuid *key)
272 {
273   unsigned int kx;
274
275   GNUNET_assert (NULL != map);
276   GNUNET_memcpy (&kx, key, sizeof (kx));
277   return kx % map->map_length;
278 }
279
280
281 /**
282  * Get the number of key-value pairs in the map.
283  *
284  * @param map the map
285  * @return the number of key value pairs
286  */
287 unsigned int
288 GNUNET_CONTAINER_multiuuidmap_size (
289   const struct GNUNET_CONTAINER_MultiUuidmap *map)
290 {
291   return map->size;
292 }
293
294
295 /**
296  * Given a key find a value in the map matching the key.
297  *
298  * @param map the map
299  * @param key what to look for
300  * @return NULL if no value was found; note that
301  *   this is indistinguishable from values that just
302  *   happen to be NULL; use "contains" to test for
303  *   key-value pairs with value NULL
304  */
305 void *
306 GNUNET_CONTAINER_multiuuidmap_get (
307   const struct GNUNET_CONTAINER_MultiUuidmap *map,
308   const struct GNUNET_Uuid *key)
309 {
310   union MapEntry me;
311
312   me = map->map[idx_of (map, key)];
313   if (map->use_small_entries)
314   {
315     for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
316       if (0 == GNUNET_memcmp (key, sme->key))
317         return sme->value;
318   }
319   else
320   {
321     for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
322       if (0 == GNUNET_memcmp (key, &bme->key))
323         return bme->value;
324   }
325   return NULL;
326 }
327
328
329 /**
330  * Iterate over all entries in the map.
331  *
332  * @param map the map
333  * @param it function to call on each entry
334  * @param it_cls extra argument to @a it
335  * @return the number of key value pairs processed,
336  *         #GNUNET_SYSERR if it aborted iteration
337  */
338 int
339 GNUNET_CONTAINER_multiuuidmap_iterate (
340   struct GNUNET_CONTAINER_MultiUuidmap *map,
341   GNUNET_CONTAINER_MultiUuidmapIterator it,
342   void *it_cls)
343 {
344   int count;
345   union MapEntry me;
346   union MapEntry *ce;
347   struct GNUNET_Uuid kc;
348
349   count = 0;
350   GNUNET_assert (NULL != map);
351   ce = &map->next_cache[map->next_cache_off];
352   GNUNET_assert (++map->next_cache_off < NEXT_CACHE_SIZE);
353   for (unsigned int i = 0; i < map->map_length; i++)
354   {
355     me = map->map[i];
356     if (map->use_small_entries)
357     {
358       struct SmallMapEntry *sme;
359
360       ce->sme = me.sme;
361       while (NULL != (sme = ce->sme))
362       {
363         ce->sme = sme->next;
364         if ((NULL != it) && (GNUNET_OK != it (it_cls, sme->key, sme->value)))
365         {
366           GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
367           return GNUNET_SYSERR;
368         }
369         count++;
370       }
371     }
372     else
373     {
374       struct BigMapEntry *bme;
375
376       ce->bme = me.bme;
377       while (NULL != (bme = ce->bme))
378       {
379         ce->bme = bme->next;
380         if (NULL != it)
381         {
382           kc = bme->key;
383           if (GNUNET_OK != it (it_cls, &kc, bme->value))
384           {
385             GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
386             return GNUNET_SYSERR;
387           }
388         }
389         count++;
390       }
391     }
392   }
393   GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
394   return count;
395 }
396
397
398 /**
399  * We are about to free() the @a bme, make sure it is not in
400  * the list of next values for any iterator in the @a map's next_cache.
401  *
402  * @param map the map to check
403  * @param bme the entry that is about to be free'd
404  */
405 static void
406 update_next_cache_bme (struct GNUNET_CONTAINER_MultiUuidmap *map,
407                        const struct BigMapEntry *bme)
408 {
409   for (unsigned int i = 0; i < map->next_cache_off; i++)
410     if (map->next_cache[i].bme == bme)
411       map->next_cache[i].bme = bme->next;
412 }
413
414
415 /**
416  * We are about to free() the @a sme, make sure it is not in
417  * the list of next values for any iterator in the @a map's next_cache.
418  *
419  * @param map the map to check
420  * @param sme the entry that is about to be free'd
421  */
422 static void
423 update_next_cache_sme (struct GNUNET_CONTAINER_MultiUuidmap *map,
424                        const struct SmallMapEntry *sme)
425 {
426   for (unsigned int i = 0; i < map->next_cache_off; i++)
427     if (map->next_cache[i].sme == sme)
428       map->next_cache[i].sme = sme->next;
429 }
430
431
432 /**
433  * Remove the given key-value pair from the map.  Note that if the
434  * key-value pair is in the map multiple times, only one of the pairs
435  * will be removed.
436  *
437  * @param map the map
438  * @param key key of the key-value pair
439  * @param value value of the key-value pair
440  * @return #GNUNET_YES on success, #GNUNET_NO if the key-value pair
441  *  is not in the map
442  */
443 int
444 GNUNET_CONTAINER_multiuuidmap_remove (struct GNUNET_CONTAINER_MultiUuidmap *map,
445                                       const struct GNUNET_Uuid *key,
446                                       const void *value)
447 {
448   union MapEntry me;
449   unsigned int i;
450
451   map->modification_counter++;
452   i = idx_of (map, key);
453   me = map->map[i];
454   if (map->use_small_entries)
455   {
456     struct SmallMapEntry *p = NULL;
457
458     for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
459     {
460       if ((0 == GNUNET_memcmp (key, sme->key)) && (value == sme->value))
461       {
462         if (NULL == p)
463           map->map[i].sme = sme->next;
464         else
465           p->next = sme->next;
466         update_next_cache_sme (map, sme);
467         GNUNET_free (sme);
468         map->size--;
469         return GNUNET_YES;
470       }
471       p = sme;
472     }
473   }
474   else
475   {
476     struct BigMapEntry *p = NULL;
477
478     for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
479     {
480       if ((0 == GNUNET_memcmp (key, &bme->key)) && (value == bme->value))
481       {
482         if (NULL == p)
483           map->map[i].bme = bme->next;
484         else
485           p->next = bme->next;
486         update_next_cache_bme (map, bme);
487         GNUNET_free (bme);
488         map->size--;
489         return GNUNET_YES;
490       }
491       p = bme;
492     }
493   }
494   return GNUNET_NO;
495 }
496
497
498 /**
499  * Remove all entries for the given key from the map.
500  * Note that the values would not be "freed".
501  *
502  * @param map the map
503  * @param key identifies values to be removed
504  * @return number of values removed
505  */
506 int
507 GNUNET_CONTAINER_multiuuidmap_remove_all (
508   struct GNUNET_CONTAINER_MultiUuidmap *map,
509   const struct GNUNET_Uuid *key)
510 {
511   union MapEntry me;
512   unsigned int i;
513   int ret;
514
515   map->modification_counter++;
516
517   ret = 0;
518   i = idx_of (map, key);
519   me = map->map[i];
520   if (map->use_small_entries)
521   {
522     struct SmallMapEntry *sme;
523     struct SmallMapEntry *p;
524
525     p = NULL;
526     sme = me.sme;
527     while (NULL != sme)
528     {
529       if (0 == GNUNET_memcmp (key, sme->key))
530       {
531         if (NULL == p)
532           map->map[i].sme = sme->next;
533         else
534           p->next = sme->next;
535         update_next_cache_sme (map, sme);
536         GNUNET_free (sme);
537         map->size--;
538         if (NULL == p)
539           sme = map->map[i].sme;
540         else
541           sme = p->next;
542         ret++;
543       }
544       else
545       {
546         p = sme;
547         sme = sme->next;
548       }
549     }
550   }
551   else
552   {
553     struct BigMapEntry *bme;
554     struct BigMapEntry *p;
555
556     p = NULL;
557     bme = me.bme;
558     while (NULL != bme)
559     {
560       if (0 == GNUNET_memcmp (key, &bme->key))
561       {
562         if (NULL == p)
563           map->map[i].bme = bme->next;
564         else
565           p->next = bme->next;
566         update_next_cache_bme (map, bme);
567         GNUNET_free (bme);
568         map->size--;
569         if (NULL == p)
570           bme = map->map[i].bme;
571         else
572           bme = p->next;
573         ret++;
574       }
575       else
576       {
577         p = bme;
578         bme = bme->next;
579       }
580     }
581   }
582   return ret;
583 }
584
585
586 /**
587  * Check if the map contains any value under the given
588  * key (including values that are NULL).
589  *
590  * @param map the map
591  * @param key the key to test if a value exists for it
592  * @return #GNUNET_YES if such a value exists,
593  *         #GNUNET_NO if not
594  */
595 int
596 GNUNET_CONTAINER_multiuuidmap_contains (
597   const struct GNUNET_CONTAINER_MultiUuidmap *map,
598   const struct GNUNET_Uuid *key)
599 {
600   union MapEntry me;
601
602   me = map->map[idx_of (map, key)];
603   if (map->use_small_entries)
604   {
605     for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
606       if (0 == GNUNET_memcmp (key, sme->key))
607         return GNUNET_YES;
608   }
609   else
610   {
611     for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
612       if (0 == GNUNET_memcmp (key, &bme->key))
613         return GNUNET_YES;
614   }
615   return GNUNET_NO;
616 }
617
618
619 /**
620  * Check if the map contains the given value under the given
621  * key.
622  *
623  * @param map the map
624  * @param key the key to test if a value exists for it
625  * @param value value to test for
626  * @return #GNUNET_YES if such a value exists,
627  *         #GNUNET_NO if not
628  */
629 int
630 GNUNET_CONTAINER_multiuuidmap_contains_value (
631   const struct GNUNET_CONTAINER_MultiUuidmap *map,
632   const struct GNUNET_Uuid *key,
633   const void *value)
634 {
635   union MapEntry me;
636
637   me = map->map[idx_of (map, key)];
638   if (map->use_small_entries)
639   {
640     for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
641       if ((0 == GNUNET_memcmp (key, sme->key)) && (sme->value == value))
642         return GNUNET_YES;
643   }
644   else
645   {
646     for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
647       if ((0 == GNUNET_memcmp (key, &bme->key)) && (bme->value == value))
648         return GNUNET_YES;
649   }
650   return GNUNET_NO;
651 }
652
653
654 /**
655  * Grow the given map to a more appropriate size.
656  *
657  * @param map the hash map to grow
658  */
659 static void
660 grow (struct GNUNET_CONTAINER_MultiUuidmap *map)
661 {
662   union MapEntry *old_map;
663   union MapEntry *new_map;
664   unsigned int old_len;
665   unsigned int new_len;
666   unsigned int idx;
667
668   old_map = map->map;
669   old_len = map->map_length;
670   new_len = old_len * 2;
671   if (0 == new_len) /* 2^31 * 2 == 0 */
672     new_len = old_len; /* never use 0 */
673   if (new_len == old_len)
674     return; /* nothing changed */
675   new_map = GNUNET_malloc_large (new_len * sizeof (union MapEntry));
676   if (NULL == new_map)
677     return; /* grow not possible */
678   map->modification_counter++;
679   map->map_length = new_len;
680   map->map = new_map;
681   for (unsigned int i = 0; i < old_len; i++)
682   {
683     if (map->use_small_entries)
684     {
685       struct SmallMapEntry *sme;
686
687       while (NULL != (sme = old_map[i].sme))
688       {
689         old_map[i].sme = sme->next;
690         idx = idx_of (map, sme->key);
691         sme->next = new_map[idx].sme;
692         new_map[idx].sme = sme;
693       }
694     }
695     else
696     {
697       struct BigMapEntry *bme;
698
699       while (NULL != (bme = old_map[i].bme))
700       {
701         old_map[i].bme = bme->next;
702         idx = idx_of (map, &bme->key);
703         bme->next = new_map[idx].bme;
704         new_map[idx].bme = bme;
705       }
706     }
707   }
708   GNUNET_free (old_map);
709 }
710
711
712 /**
713  * Store a key-value pair in the map.
714  *
715  * @param map the map
716  * @param key key to use
717  * @param value value to use
718  * @param opt options for put
719  * @return #GNUNET_OK on success,
720  *         #GNUNET_NO if a value was replaced (with REPLACE)
721  *         #GNUNET_SYSERR if #GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY was the option and the
722  *                       value already exists
723  */
724 int
725 GNUNET_CONTAINER_multiuuidmap_put (struct GNUNET_CONTAINER_MultiUuidmap *map,
726                                    const struct GNUNET_Uuid *key,
727                                    void *value,
728                                    enum GNUNET_CONTAINER_MultiHashMapOption opt)
729 {
730   union MapEntry me;
731   unsigned int i;
732
733   i = idx_of (map, key);
734   if ((opt != GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE) &&
735       (opt != GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
736   {
737     me = map->map[i];
738     if (map->use_small_entries)
739     {
740       for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
741         if (0 == GNUNET_memcmp (key, sme->key))
742         {
743           if (opt == GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)
744             return GNUNET_SYSERR;
745           sme->value = value;
746           return GNUNET_NO;
747         }
748     }
749     else
750     {
751       for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
752         if (0 == GNUNET_memcmp (key, &bme->key))
753         {
754           if (opt == GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)
755             return GNUNET_SYSERR;
756           bme->value = value;
757           return GNUNET_NO;
758         }
759     }
760   }
761   if (map->size / 3 >= map->map_length / 4)
762   {
763     grow (map);
764     i = idx_of (map, key);
765   }
766   if (map->use_small_entries)
767   {
768     struct SmallMapEntry *sme;
769
770     sme = GNUNET_new (struct SmallMapEntry);
771     sme->key = key;
772     sme->value = value;
773     sme->next = map->map[i].sme;
774     map->map[i].sme = sme;
775   }
776   else
777   {
778     struct BigMapEntry *bme;
779
780     bme = GNUNET_new (struct BigMapEntry);
781     bme->key = *key;
782     bme->value = value;
783     bme->next = map->map[i].bme;
784     map->map[i].bme = bme;
785   }
786   map->size++;
787   return GNUNET_OK;
788 }
789
790
791 /**
792  * Iterate over all entries in the map that match a particular key.
793  *
794  * @param map the map
795  * @param key key that the entries must correspond to
796  * @param it function to call on each entry
797  * @param it_cls extra argument to @a it
798  * @return the number of key value pairs processed,
799  *         #GNUNET_SYSERR if it aborted iteration
800  */
801 int
802 GNUNET_CONTAINER_multiuuidmap_get_multiple (
803   struct GNUNET_CONTAINER_MultiUuidmap *map,
804   const struct GNUNET_Uuid *key,
805   GNUNET_CONTAINER_MultiUuidmapIterator it,
806   void *it_cls)
807 {
808   int count;
809   union MapEntry me;
810   union MapEntry *ce;
811
812   ce = &map->next_cache[map->next_cache_off];
813   GNUNET_assert (++map->next_cache_off < NEXT_CACHE_SIZE);
814   count = 0;
815   me = map->map[idx_of (map, key)];
816   if (map->use_small_entries)
817   {
818     struct SmallMapEntry *sme;
819
820     ce->sme = me.sme;
821     while (NULL != (sme = ce->sme))
822     {
823       ce->sme = sme->next;
824       if (0 != GNUNET_memcmp (key, sme->key))
825         continue;
826       if ((NULL != it) && (GNUNET_OK != it (it_cls, key, sme->value)))
827       {
828         GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
829         return GNUNET_SYSERR;
830       }
831       count++;
832     }
833   }
834   else
835   {
836     struct BigMapEntry *bme;
837
838     ce->bme = me.bme;
839     while (NULL != (bme = ce->bme))
840     {
841       ce->bme = bme->next;
842       if (0 != GNUNET_memcmp (key, &bme->key))
843         continue;
844       if ((NULL != it) && (GNUNET_OK != it (it_cls, key, bme->value)))
845       {
846         GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
847         return GNUNET_SYSERR;
848       }
849       count++;
850     }
851   }
852   GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
853   return count;
854 }
855
856
857 /**
858  * @ingroup hashmap
859  * Call @a it on a random value from the map, or not at all
860  * if the map is empty.  Note that this function has linear
861  * complexity (in the size of the map).
862  *
863  * @param map the map
864  * @param it function to call on a random entry
865  * @param it_cls extra argument to @a it
866  * @return the number of key value pairs processed, zero or one.
867  */
868 unsigned int
869 GNUNET_CONTAINER_multiuuidmap_get_random (
870   const struct GNUNET_CONTAINER_MultiUuidmap *map,
871   GNUNET_CONTAINER_MultiUuidmapIterator it,
872   void *it_cls)
873 {
874   unsigned int off;
875   union MapEntry me;
876
877   if (0 == map->size)
878     return 0;
879   if (NULL == it)
880     return 1;
881   off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, map->size);
882   for (unsigned int idx = 0; idx < map->map_length; idx++)
883   {
884     me = map->map[idx];
885     if (map->use_small_entries)
886     {
887       for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
888       {
889         if (0 == off)
890         {
891           if (GNUNET_OK != it (it_cls, sme->key, sme->value))
892             return GNUNET_SYSERR;
893           return 1;
894         }
895         off--;
896       }
897     }
898     else
899     {
900       for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
901       {
902         if (0 == off)
903         {
904           if (GNUNET_OK != it (it_cls, &bme->key, bme->value))
905             return GNUNET_SYSERR;
906           return 1;
907         }
908         off--;
909       }
910     }
911   }
912   GNUNET_break (0);
913   return GNUNET_SYSERR;
914 }
915
916
917 /**
918  * Create an iterator for a multiuuidmap.
919  * The iterator can be used to retrieve all the elements in the multiuuidmap
920  * one by one, without having to handle all elements at once (in contrast to
921  * #GNUNET_CONTAINER_multiuuidmap_iterate).  Note that the iterator can not be
922  * used anymore if elements have been removed from 'map' after the creation of
923  * the iterator, or 'map' has been destroyed.  Adding elements to 'map' may
924  * result in skipped or repeated elements.
925  *
926  * @param map the map to create an iterator for
927  * @return an iterator over the given multiuuidmap 'map'
928  */
929 struct GNUNET_CONTAINER_MultiUuidmapIterator *
930 GNUNET_CONTAINER_multiuuidmap_iterator_create (
931   const struct GNUNET_CONTAINER_MultiUuidmap *map)
932 {
933   struct GNUNET_CONTAINER_MultiUuidmapIterator *iter;
934
935   iter = GNUNET_new (struct GNUNET_CONTAINER_MultiUuidmapIterator);
936   iter->map = map;
937   iter->modification_counter = map->modification_counter;
938   iter->me = map->map[0];
939   return iter;
940 }
941
942
943 /**
944  * Retrieve the next element from the hash map at the iterator's position.
945  * If there are no elements left, GNUNET_NO is returned, and 'key' and 'value'
946  * are not modified.
947  * This operation is only allowed if no elements have been removed from the
948  * multiuuidmap since the creation of 'iter', and the map has not been destroyed.
949  * Adding elements may result in repeating or skipping elements.
950  *
951  * @param iter the iterator to get the next element from
952  * @param key pointer to store the key in, can be NULL
953  * @param value pointer to store the value in, can be NULL
954  * @return #GNUNET_YES we returned an element,
955  *         #GNUNET_NO if we are out of elements
956  */
957 int
958 GNUNET_CONTAINER_multiuuidmap_iterator_next (
959   struct GNUNET_CONTAINER_MultiUuidmapIterator *iter,
960   struct GNUNET_Uuid *key,
961   const void **value)
962 {
963   /* make sure the map has not been modified */
964   GNUNET_assert (iter->modification_counter == iter->map->modification_counter);
965
966   /* look for the next entry, skipping empty buckets */
967   while (1)
968   {
969     if (iter->idx >= iter->map->map_length)
970       return GNUNET_NO;
971     if (GNUNET_YES == iter->map->use_small_entries)
972     {
973       if (NULL != iter->me.sme)
974       {
975         if (NULL != key)
976           *key = *iter->me.sme->key;
977         if (NULL != value)
978           *value = iter->me.sme->value;
979         iter->me.sme = iter->me.sme->next;
980         return GNUNET_YES;
981       }
982     }
983     else
984     {
985       if (NULL != iter->me.bme)
986       {
987         if (NULL != key)
988           *key = iter->me.bme->key;
989         if (NULL != value)
990           *value = iter->me.bme->value;
991         iter->me.bme = iter->me.bme->next;
992         return GNUNET_YES;
993       }
994     }
995     iter->idx += 1;
996     if (iter->idx < iter->map->map_length)
997       iter->me = iter->map->map[iter->idx];
998   }
999 }
1000
1001
1002 /**
1003  * Destroy a multiuuidmap iterator.
1004  *
1005  * @param iter the iterator to destroy
1006  */
1007 void
1008 GNUNET_CONTAINER_multiuuidmap_iterator_destroy (
1009   struct GNUNET_CONTAINER_MultiUuidmapIterator *iter)
1010 {
1011   GNUNET_free (iter);
1012 }
1013
1014
1015 /* end of container_multiuuidmap.c */