Merge branch 'master' of gnunet.org:gnunet
[oweals/gnunet.git] / src / util / container_multipeermap.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_multipeermap.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-multipeermap", __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_PeerIdentity 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_PeerIdentity *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_MultiPeerMap
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 multipeermap.
130  * Allows to enumerate elements asynchronously.
131  */
132 struct GNUNET_CONTAINER_MultiPeerMapIterator
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_MultiPeerMap *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_MultiPeerMap *
173 GNUNET_CONTAINER_multipeermap_create (unsigned int len,
174                                       int do_not_copy_keys)
175 {
176   struct GNUNET_CONTAINER_MultiPeerMap *map;
177
178   GNUNET_assert (len > 0);
179   map = GNUNET_new (struct GNUNET_CONTAINER_MultiPeerMap);
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_multipeermap_destroy (struct GNUNET_CONTAINER_MultiPeerMap
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_MultiPeerMap *map,
244         const struct GNUNET_PeerIdentity *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_multipeermap_size (const struct GNUNET_CONTAINER_MultiPeerMap
262                                     *map)
263 {
264   return map->size;
265 }
266
267
268 /**
269  * Given a key find a value in the map matching the key.
270  *
271  * @param map the map
272  * @param key what to look for
273  * @return NULL if no value was found; note that
274  *   this is indistinguishable from values that just
275  *   happen to be NULL; use "contains" to test for
276  *   key-value pairs with value NULL
277  */
278 void *
279 GNUNET_CONTAINER_multipeermap_get (const struct GNUNET_CONTAINER_MultiPeerMap
280                                    *map, const struct GNUNET_PeerIdentity *key)
281 {
282   union MapEntry me;
283
284   me = map->map[idx_of (map, key)];
285   if (map->use_small_entries)
286   {
287     struct SmallMapEntry *sme;
288
289     for (sme = me.sme; NULL != sme; sme = sme->next)
290       if (0 == memcmp (key, sme->key, sizeof (struct GNUNET_PeerIdentity)))
291         return sme->value;
292   }
293   else
294   {
295     struct BigMapEntry *bme;
296
297     for (bme = me.bme; NULL != bme; bme = bme->next)
298       if (0 == memcmp (key, &bme->key, sizeof (struct GNUNET_PeerIdentity)))
299         return bme->value;
300   }
301   return NULL;
302 }
303
304
305 /**
306  * Iterate over all entries in the map.
307  *
308  * @param map the map
309  * @param it function to call on each entry
310  * @param it_cls extra argument to @a it
311  * @return the number of key value pairs processed,
312  *         #GNUNET_SYSERR if it aborted iteration
313  */
314 int
315 GNUNET_CONTAINER_multipeermap_iterate (const struct
316                                        GNUNET_CONTAINER_MultiPeerMap *map,
317                                        GNUNET_CONTAINER_PeerMapIterator it,
318                                        void *it_cls)
319 {
320   int count;
321   unsigned int i;
322   union MapEntry me;
323   struct GNUNET_PeerIdentity kc;
324
325   count = 0;
326   GNUNET_assert (NULL != map);
327   for (i = 0; i < map->map_length; i++)
328   {
329     me = map->map[i];
330     if (map->use_small_entries)
331     {
332       struct SmallMapEntry *sme;
333       struct SmallMapEntry *nxt;
334
335       nxt = me.sme;
336       while (NULL != (sme = nxt))
337       {
338         nxt = sme->next;
339         if (NULL != it)
340         {
341           if (GNUNET_OK != it (it_cls, sme->key, sme->value))
342             return GNUNET_SYSERR;
343         }
344         count++;
345       }
346     }
347     else
348     {
349       struct BigMapEntry *bme;
350       struct BigMapEntry *nxt;
351
352       nxt = me.bme;
353       while (NULL != (bme = nxt))
354       {
355         nxt = bme->next;
356         if (NULL != it)
357         {
358           kc = bme->key;
359           if (GNUNET_OK != it (it_cls, &kc, bme->value))
360             return GNUNET_SYSERR;
361         }
362         count++;
363       }
364     }
365   }
366   return count;
367 }
368
369
370 /**
371  * Remove the given key-value pair from the map.  Note that if the
372  * key-value pair is in the map multiple times, only one of the pairs
373  * will be removed.
374  *
375  * @param map the map
376  * @param key key of the key-value pair
377  * @param value value of the key-value pair
378  * @return GNUNET_YES on success, GNUNET_NO if the key-value pair
379  *  is not in the map
380  */
381 int
382 GNUNET_CONTAINER_multipeermap_remove (struct GNUNET_CONTAINER_MultiPeerMap *map,
383                                       const struct GNUNET_PeerIdentity *key,
384                                       const void *value)
385 {
386   union MapEntry me;
387   unsigned int i;
388
389   map->modification_counter++;
390
391   i = idx_of (map, key);
392   me = map->map[i];
393   if (map->use_small_entries)
394   {
395     struct SmallMapEntry *sme;
396     struct SmallMapEntry *p;
397
398     p = NULL;
399     for (sme = me.sme; NULL != sme; sme = sme->next)
400     {
401       if ((0 == memcmp (key, sme->key, sizeof (struct GNUNET_PeerIdentity))) &&
402           (value == sme->value))
403       {
404         if (NULL == p)
405           map->map[i].sme = sme->next;
406         else
407           p->next = sme->next;
408         GNUNET_free (sme);
409         map->size--;
410         return GNUNET_YES;
411       }
412       p = sme;
413     }
414   }
415   else
416   {
417     struct BigMapEntry *bme;
418     struct BigMapEntry *p;
419
420     p = NULL;
421     for (bme = me.bme; NULL != bme; bme = bme->next)
422     {
423       if ((0 == memcmp (key, &bme->key, sizeof (struct GNUNET_PeerIdentity))) &&
424           (value == bme->value))
425       {
426         if (NULL == p)
427           map->map[i].bme = bme->next;
428         else
429           p->next = bme->next;
430         GNUNET_free (bme);
431         map->size--;
432         return GNUNET_YES;
433       }
434       p = bme;
435     }
436   }
437   return GNUNET_NO;
438 }
439
440
441 /**
442  * Remove all entries for the given key from the map.
443  * Note that the values would not be "freed".
444  *
445  * @param map the map
446  * @param key identifies values to be removed
447  * @return number of values removed
448  */
449 int
450 GNUNET_CONTAINER_multipeermap_remove_all (struct GNUNET_CONTAINER_MultiPeerMap
451                                           *map, const struct GNUNET_PeerIdentity *key)
452 {
453   union MapEntry me;
454   unsigned int i;
455   int ret;
456
457   map->modification_counter++;
458
459   ret = 0;
460   i = idx_of (map, key);
461   me = map->map[i];
462   if (map->use_small_entries)
463   {
464     struct SmallMapEntry *sme;
465     struct SmallMapEntry *p;
466
467     p = NULL;
468     sme = me.sme;
469     while (NULL != sme)
470     {
471       if (0 == memcmp (key, sme->key, sizeof (struct GNUNET_PeerIdentity)))
472       {
473         if (NULL == p)
474           map->map[i].sme = sme->next;
475         else
476           p->next = sme->next;
477         GNUNET_free (sme);
478         map->size--;
479         if (NULL == p)
480           sme = map->map[i].sme;
481         else
482           sme = p->next;
483         ret++;
484       }
485       else
486       {
487         p = sme;
488         sme = sme->next;
489       }
490     }
491   }
492   else
493   {
494     struct BigMapEntry *bme;
495     struct BigMapEntry *p;
496
497     p = NULL;
498     bme = me.bme;
499     while (NULL != bme)
500     {
501       if (0 == memcmp (key, &bme->key, sizeof (struct GNUNET_PeerIdentity)))
502       {
503         if (NULL == p)
504           map->map[i].bme = bme->next;
505         else
506           p->next = bme->next;
507         GNUNET_free (bme);
508         map->size--;
509         if (NULL == p)
510           bme = map->map[i].bme;
511         else
512           bme = p->next;
513         ret++;
514       }
515       else
516       {
517         p = bme;
518         bme = bme->next;
519       }
520     }
521   }
522   return ret;
523 }
524
525
526 /**
527  * Check if the map contains any value under the given
528  * key (including values that are NULL).
529  *
530  * @param map the map
531  * @param key the key to test if a value exists for it
532  * @return GNUNET_YES if such a value exists,
533  *         GNUNET_NO if not
534  */
535 int
536 GNUNET_CONTAINER_multipeermap_contains (const struct
537                                         GNUNET_CONTAINER_MultiPeerMap *map,
538                                         const struct GNUNET_PeerIdentity *key)
539 {
540   union MapEntry me;
541
542   me = map->map[idx_of (map, key)];
543   if (map->use_small_entries)
544   {
545     struct SmallMapEntry *sme;
546
547     for (sme = me.sme; NULL != sme; sme = sme->next)
548       if (0 == memcmp (key, sme->key, sizeof (struct GNUNET_PeerIdentity)))
549         return GNUNET_YES;
550   }
551   else
552   {
553     struct BigMapEntry *bme;
554
555     for (bme = me.bme; NULL != bme; bme = bme->next)
556       if (0 == memcmp (key, &bme->key, sizeof (struct GNUNET_PeerIdentity)))
557         return GNUNET_YES;
558   }
559   return GNUNET_NO;
560 }
561
562
563 /**
564  * Check if the map contains the given value under the given
565  * key.
566  *
567  * @param map the map
568  * @param key the key to test if a value exists for it
569  * @param value value to test for
570  * @return GNUNET_YES if such a value exists,
571  *         GNUNET_NO if not
572  */
573 int
574 GNUNET_CONTAINER_multipeermap_contains_value (const struct
575                                               GNUNET_CONTAINER_MultiPeerMap
576                                               *map, const struct GNUNET_PeerIdentity *key,
577                                               const void *value)
578 {
579   union MapEntry me;
580
581   me = map->map[idx_of (map, key)];
582   if (map->use_small_entries)
583   {
584     struct SmallMapEntry *sme;
585
586     for (sme = me.sme; NULL != sme; sme = sme->next)
587       if ( (0 == memcmp (key, sme->key, sizeof (struct GNUNET_PeerIdentity))) &&
588            (sme->value == value) )
589         return GNUNET_YES;
590   }
591   else
592   {
593     struct BigMapEntry *bme;
594
595     for (bme = me.bme; NULL != bme; bme = bme->next)
596       if ( (0 == memcmp (key, &bme->key, sizeof (struct GNUNET_PeerIdentity))) &&
597            (bme->value == value) )
598         return GNUNET_YES;
599   }
600   return GNUNET_NO;
601 }
602
603
604 /**
605  * Grow the given map to a more appropriate size.
606  *
607  * @param map the hash map to grow
608  */
609 static void
610 grow (struct GNUNET_CONTAINER_MultiPeerMap *map)
611 {
612   union MapEntry *old_map;
613   union MapEntry *new_map;
614   unsigned int old_len;
615   unsigned int new_len;
616   unsigned int idx;
617   unsigned int i;
618
619   map->modification_counter++;
620
621   old_map = map->map;
622   old_len = map->map_length;
623   new_len = old_len * 2;
624   new_map = GNUNET_malloc (sizeof (union MapEntry) * new_len);
625   map->map_length = new_len;
626   map->map = new_map;
627   for (i = 0; i < old_len; i++)
628   {
629     if (map->use_small_entries)
630     {
631       struct SmallMapEntry *sme;
632
633       while (NULL != (sme = old_map[i].sme))
634       {
635         old_map[i].sme = sme->next;
636         idx = idx_of (map, sme->key);
637         sme->next = new_map[idx].sme;
638         new_map[idx].sme = sme;
639       }
640     }
641     else
642     {
643       struct BigMapEntry *bme;
644
645       while (NULL != (bme = old_map[i].bme))
646       {
647         old_map[i].bme = bme->next;
648         idx = idx_of (map, &bme->key);
649         bme->next = new_map[idx].bme;
650         new_map[idx].bme = bme;
651       }
652     }
653   }
654   GNUNET_free (old_map);
655 }
656
657
658 /**
659  * Store a key-value pair in the map.
660  *
661  * @param map the map
662  * @param key key to use
663  * @param value value to use
664  * @param opt options for put
665  * @return #GNUNET_OK on success,
666  *         #GNUNET_NO if a value was replaced (with REPLACE)
667  *         #GNUNET_SYSERR if GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY was the option and the
668  *                       value already exists
669  */
670 int
671 GNUNET_CONTAINER_multipeermap_put (struct GNUNET_CONTAINER_MultiPeerMap *map,
672                                    const struct GNUNET_PeerIdentity *key,
673                                    void *value,
674                                    enum GNUNET_CONTAINER_MultiHashMapOption opt)
675 {
676   union MapEntry me;
677   unsigned int i;
678
679   i = idx_of (map, key);
680   if ((opt != GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE) &&
681       (opt != GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
682   {
683     me = map->map[i];
684     if (map->use_small_entries)
685     {
686       struct SmallMapEntry *sme;
687
688       for (sme = me.sme; NULL != sme; sme = sme->next)
689         if (0 == memcmp (key, sme->key, sizeof (struct GNUNET_PeerIdentity)))
690         {
691           if (opt == GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)
692             return GNUNET_SYSERR;
693           sme->value = value;
694           return GNUNET_NO;
695         }
696     }
697     else
698     {
699       struct BigMapEntry *bme;
700
701       for (bme = me.bme; NULL != bme; bme = bme->next)
702         if (0 == memcmp (key, &bme->key, sizeof (struct GNUNET_PeerIdentity)))
703         {
704           if (opt == GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)
705             return GNUNET_SYSERR;
706           bme->value = value;
707           return GNUNET_NO;
708         }
709     }
710   }
711   if (map->size / 3 >= map->map_length / 4)
712   {
713     grow (map);
714     i = idx_of (map, key);
715   }
716   if (map->use_small_entries)
717   {
718     struct SmallMapEntry *sme;
719
720     sme = GNUNET_new (struct SmallMapEntry);
721     sme->key = key;
722     sme->value = value;
723     sme->next = map->map[i].sme;
724     map->map[i].sme = sme;
725   }
726   else
727   {
728     struct BigMapEntry *bme;
729
730     bme = GNUNET_new (struct BigMapEntry);
731     bme->key = *key;
732     bme->value = value;
733     bme->next = map->map[i].bme;
734     map->map[i].bme = bme;
735   }
736   map->size++;
737   return GNUNET_OK;
738 }
739
740
741 /**
742  * Iterate over all entries in the map that match a particular key.
743  *
744  * @param map the map
745  * @param key key that the entries must correspond to
746  * @param it function to call on each entry
747  * @param it_cls extra argument to @a it
748  * @return the number of key value pairs processed,
749  *         #GNUNET_SYSERR if it aborted iteration
750  */
751 int
752 GNUNET_CONTAINER_multipeermap_get_multiple (const struct GNUNET_CONTAINER_MultiPeerMap *map,
753                                             const struct GNUNET_PeerIdentity *key,
754                                             GNUNET_CONTAINER_PeerMapIterator it,
755                                             void *it_cls)
756 {
757   int count;
758   union MapEntry me;
759
760   count = 0;
761   me = map->map[idx_of (map, key)];
762   if (map->use_small_entries)
763   {
764     struct SmallMapEntry *sme;
765     struct SmallMapEntry *nxt;
766
767     nxt = me.sme;
768     while (NULL != (sme = nxt))
769     {
770       nxt = sme->next;
771       if (0 != memcmp (key, sme->key, sizeof (struct GNUNET_PeerIdentity)))
772         continue;
773       if ((it != NULL) && (GNUNET_OK != it (it_cls, key, sme->value)))
774         return GNUNET_SYSERR;
775       count++;
776     }
777   }
778   else
779   {
780     struct BigMapEntry *bme;
781     struct BigMapEntry *nxt;
782
783     nxt = me.bme;
784     while (NULL != (bme = nxt))
785     {
786       nxt = bme->next;
787       if (0 != memcmp (key, &bme->key, sizeof (struct GNUNET_PeerIdentity)))
788         continue;
789       if ((it != NULL) && (GNUNET_OK != it (it_cls, key, bme->value)))
790         return GNUNET_SYSERR;
791       count++;
792     }
793   }
794   return count;
795 }
796
797
798 /**
799  * @ingroup hashmap
800  * Call @a it on a random value from the map, or not at all
801  * if the map is empty.  Note that this function has linear
802  * complexity (in the size of the map).
803  *
804  * @param map the map
805  * @param it function to call on a random entry
806  * @param it_cls extra argument to @a it
807  * @return the number of key value pairs processed, zero or one.
808  */
809 unsigned int
810 GNUNET_CONTAINER_multipeermap_get_random (const struct GNUNET_CONTAINER_MultiPeerMap *map,
811                                           GNUNET_CONTAINER_PeerMapIterator it,
812                                           void *it_cls)
813 {
814   unsigned int off;
815   unsigned int idx;
816   union MapEntry me;
817
818   if (0 == map->size)
819     return 0;
820   if (NULL == it)
821     return 1;
822   off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
823                                   map->size);
824   for (idx = 0; idx < map->map_length; idx++)
825   {
826     me = map->map[idx];
827     if (map->use_small_entries)
828     {
829       struct SmallMapEntry *sme;
830       struct SmallMapEntry *nxt;
831
832       nxt = me.sme;
833       while (NULL != (sme = nxt))
834       {
835         nxt = sme->next;
836         if (0 == off)
837         {
838           if (GNUNET_OK != it (it_cls,
839                                sme->key,
840                                sme->value))
841             return GNUNET_SYSERR;
842           return 1;
843         }
844         off--;
845       }
846     }
847     else
848     {
849       struct BigMapEntry *bme;
850       struct BigMapEntry *nxt;
851
852       nxt = me.bme;
853       while (NULL != (bme = nxt))
854       {
855         nxt = bme->next;
856         if (0 == off)
857         {
858           if (GNUNET_OK != it (it_cls,
859                                &bme->key, bme->value))
860             return GNUNET_SYSERR;
861           return 1;
862         }
863         off--;
864       }
865     }
866   }
867   GNUNET_break (0);
868   return GNUNET_SYSERR;
869 }
870
871
872 /**
873  * Create an iterator for a multipeermap.
874  * The iterator can be used to retrieve all the elements in the multipeermap
875  * one by one, without having to handle all elements at once (in contrast to
876  * #GNUNET_CONTAINER_multipeermap_iterate).  Note that the iterator can not be
877  * used anymore if elements have been removed from 'map' after the creation of
878  * the iterator, or 'map' has been destroyed.  Adding elements to 'map' may
879  * result in skipped or repeated elements.
880  *
881  * @param map the map to create an iterator for
882  * @return an iterator over the given multipeermap 'map'
883  */
884 struct GNUNET_CONTAINER_MultiPeerMapIterator *
885 GNUNET_CONTAINER_multipeermap_iterator_create (const struct GNUNET_CONTAINER_MultiPeerMap *map)
886 {
887   struct GNUNET_CONTAINER_MultiPeerMapIterator *iter;
888
889   iter = GNUNET_new (struct GNUNET_CONTAINER_MultiPeerMapIterator);
890   iter->map = map;
891   iter->modification_counter = map->modification_counter;
892   iter->me = map->map[0];
893   return iter;
894 }
895
896
897 /**
898  * Retrieve the next element from the hash map at the iterator's position.
899  * If there are no elements left, GNUNET_NO is returned, and 'key' and 'value'
900  * are not modified.
901  * This operation is only allowed if no elements have been removed from the
902  * multipeermap since the creation of 'iter', and the map has not been destroyed.
903  * Adding elements may result in repeating or skipping elements.
904  *
905  * @param iter the iterator to get the next element from
906  * @param key pointer to store the key in, can be NULL
907  * @param value pointer to store the value in, can be NULL
908  * @return #GNUNET_YES we returned an element,
909  *         #GNUNET_NO if we are out of elements
910  */
911 int
912 GNUNET_CONTAINER_multipeermap_iterator_next (struct GNUNET_CONTAINER_MultiPeerMapIterator *iter,
913                                              struct GNUNET_PeerIdentity *key, const void **value)
914 {
915   /* make sure the map has not been modified */
916   GNUNET_assert (iter->modification_counter == iter->map->modification_counter);
917
918   /* look for the next entry, skipping empty buckets */
919   while (1)
920   {
921     if (iter->idx >= iter->map->map_length)
922       return GNUNET_NO;
923     if (GNUNET_YES == iter->map->use_small_entries)
924     {
925       if (NULL != iter->me.sme)
926       {
927         if (NULL != key)
928           *key = *iter->me.sme->key;
929         if (NULL != value)
930           *value = iter->me.sme->value;
931         iter->me.sme = iter->me.sme->next;
932         return GNUNET_YES;
933       }
934     }
935     else
936     {
937       if (NULL != iter->me.bme)
938       {
939         if (NULL != key)
940           *key = iter->me.bme->key;
941         if (NULL != value)
942           *value = iter->me.bme->value;
943         iter->me.bme = iter->me.bme->next;
944         return GNUNET_YES;
945       }
946     }
947     iter->idx += 1;
948     if (iter->idx < iter->map->map_length)
949       iter->me = iter->map->map[iter->idx];
950   }
951 }
952
953
954 /**
955  * Destroy a multipeermap iterator.
956  *
957  * @param iter the iterator to destroy
958  */
959 void
960 GNUNET_CONTAINER_multipeermap_iterator_destroy (struct GNUNET_CONTAINER_MultiPeerMapIterator *iter)
961 {
962   GNUNET_free (iter);
963 }
964
965
966 /* end of container_multipeermap.c */