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