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