-remove trailing whitespace
[oweals/gnunet.git] / src / util / container_multipeermap.c
1 /*
2      This file is part of GNUnet.
3      (C) 2008, 2012 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20 /**
21  * @file util/container_multipeermap.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_util_lib.h"
28
29 #define LOG(kind,...) GNUNET_log_from (kind, "util", __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_PeerIdentity 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_PeerIdentity *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_MultiPeerMap
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 multipeermap.
132  * Allows to enumerate elements asynchronously.
133  */
134 struct GNUNET_CONTAINER_MultiPeerMapIterator
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_MultiPeerMap *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_MultiPeerMap *
175 GNUNET_CONTAINER_multipeermap_create (unsigned int len,
176                                       int do_not_copy_keys)
177 {
178   struct GNUNET_CONTAINER_MultiPeerMap *map;
179
180   GNUNET_assert (len > 0);
181   map = GNUNET_new (struct GNUNET_CONTAINER_MultiPeerMap);
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_multipeermap_destroy (struct GNUNET_CONTAINER_MultiPeerMap
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_MultiPeerMap *map,
246         const struct GNUNET_PeerIdentity *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_multipeermap_size (const struct GNUNET_CONTAINER_MultiPeerMap
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_multipeermap_get (const struct GNUNET_CONTAINER_MultiPeerMap
279                                    *map, const struct GNUNET_PeerIdentity *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_PeerIdentity)))
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_PeerIdentity)))
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_multipeermap_iterate (const struct
315                                        GNUNET_CONTAINER_MultiPeerMap *map,
316                                        GNUNET_CONTAINER_PeerMapIterator it,
317                                        void *it_cls)
318 {
319   int count;
320   unsigned int i;
321   union MapEntry me;
322   struct GNUNET_PeerIdentity 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_multipeermap_remove (struct GNUNET_CONTAINER_MultiPeerMap *map,
382                                       const struct GNUNET_PeerIdentity *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_PeerIdentity))) &&
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_PeerIdentity))) &&
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_multipeermap_remove_all (struct GNUNET_CONTAINER_MultiPeerMap
450                                           *map, const struct GNUNET_PeerIdentity *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_PeerIdentity)))
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_PeerIdentity)))
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  * Check if the map contains any value under the given
527  * key (including values that are NULL).
528  *
529  * @param map the map
530  * @param key the key to test if a value exists for it
531  * @return GNUNET_YES if such a value exists,
532  *         GNUNET_NO if not
533  */
534 int
535 GNUNET_CONTAINER_multipeermap_contains (const struct
536                                         GNUNET_CONTAINER_MultiPeerMap *map,
537                                         const struct GNUNET_PeerIdentity *key)
538 {
539   union MapEntry me;
540
541   me = map->map[idx_of (map, key)];
542   if (map->use_small_entries)
543   {
544     struct SmallMapEntry *sme;
545
546     for (sme = me.sme; NULL != sme; sme = sme->next)
547       if (0 == memcmp (key, sme->key, sizeof (struct GNUNET_PeerIdentity)))
548         return GNUNET_YES;
549   }
550   else
551   {
552     struct BigMapEntry *bme;
553
554     for (bme = me.bme; NULL != bme; bme = bme->next)
555       if (0 == memcmp (key, &bme->key, sizeof (struct GNUNET_PeerIdentity)))
556         return GNUNET_YES;
557   }
558   return GNUNET_NO;
559 }
560
561
562 /**
563  * Check if the map contains the given value under the given
564  * key.
565  *
566  * @param map the map
567  * @param key the key to test if a value exists for it
568  * @param value value to test for
569  * @return GNUNET_YES if such a value exists,
570  *         GNUNET_NO if not
571  */
572 int
573 GNUNET_CONTAINER_multipeermap_contains_value (const struct
574                                               GNUNET_CONTAINER_MultiPeerMap
575                                               *map, const struct GNUNET_PeerIdentity *key,
576                                               const void *value)
577 {
578   union MapEntry me;
579
580   me = map->map[idx_of (map, key)];
581   if (map->use_small_entries)
582   {
583     struct SmallMapEntry *sme;
584
585     for (sme = me.sme; NULL != sme; sme = sme->next)
586       if ( (0 == memcmp (key, sme->key, sizeof (struct GNUNET_PeerIdentity))) &&
587            (sme->value == value) )
588         return GNUNET_YES;
589   }
590   else
591   {
592     struct BigMapEntry *bme;
593
594     for (bme = me.bme; NULL != bme; bme = bme->next)
595       if ( (0 == memcmp (key, &bme->key, sizeof (struct GNUNET_PeerIdentity))) &&
596            (bme->value == value) )
597         return GNUNET_YES;
598   }
599   return GNUNET_NO;
600 }
601
602
603 /**
604  * Grow the given map to a more appropriate size.
605  *
606  * @param map the hash map to grow
607  */
608 static void
609 grow (struct GNUNET_CONTAINER_MultiPeerMap *map)
610 {
611   union MapEntry *old_map;
612   union MapEntry *new_map;
613   unsigned int old_len;
614   unsigned int new_len;
615   unsigned int idx;
616   unsigned int i;
617
618   map->modification_counter++;
619
620   old_map = map->map;
621   old_len = map->map_length;
622   new_len = old_len * 2;
623   new_map = GNUNET_malloc (sizeof (union MapEntry) * new_len);
624   map->map_length = new_len;
625   map->map = new_map;
626   for (i = 0; i < old_len; i++)
627   {
628     if (map->use_small_entries)
629     {
630       struct SmallMapEntry *sme;
631
632       while (NULL != (sme = old_map[i].sme))
633       {
634         old_map[i].sme = sme->next;
635         idx = idx_of (map, sme->key);
636         sme->next = new_map[idx].sme;
637         new_map[idx].sme = sme;
638       }
639     }
640     else
641     {
642       struct BigMapEntry *bme;
643
644       while (NULL != (bme = old_map[i].bme))
645       { 
646         old_map[i].bme = bme->next;
647         idx = idx_of (map, &bme->key);
648         bme->next = new_map[idx].bme;
649         new_map[idx].bme = bme;
650       }
651     }
652   }
653   GNUNET_free (old_map);
654 }
655
656
657 /**
658  * Store a key-value pair in the map.
659  *
660  * @param map the map
661  * @param key key to use
662  * @param value value to use
663  * @param opt options for put
664  * @return #GNUNET_OK on success,
665  *         #GNUNET_NO if a value was replaced (with REPLACE)
666  *         #GNUNET_SYSERR if GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY was the option and the
667  *                       value already exists
668  */
669 int
670 GNUNET_CONTAINER_multipeermap_put (struct GNUNET_CONTAINER_MultiPeerMap *map,
671                                    const struct GNUNET_PeerIdentity *key,
672                                    void *value,
673                                    enum GNUNET_CONTAINER_MultiHashMapOption opt)
674 {
675   union MapEntry me;
676   unsigned int i;
677
678   i = idx_of (map, key);
679   if ((opt != GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE) &&
680       (opt != GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
681   {
682     me = map->map[i];
683     if (map->use_small_entries)
684     {
685       struct SmallMapEntry *sme;
686
687       for (sme = me.sme; NULL != sme; sme = sme->next)
688         if (0 == memcmp (key, sme->key, sizeof (struct GNUNET_PeerIdentity)))
689         {
690           if (opt == GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)
691             return GNUNET_SYSERR;
692           sme->value = value;
693           return GNUNET_NO;
694         }
695     }
696     else
697     {
698       struct BigMapEntry *bme;
699
700       for (bme = me.bme; NULL != bme; bme = bme->next)
701         if (0 == memcmp (key, &bme->key, sizeof (struct GNUNET_PeerIdentity)))
702         {
703           if (opt == GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)
704             return GNUNET_SYSERR;
705           bme->value = value;
706           return GNUNET_NO;
707         }
708     }
709   }
710   if (map->size / 3 >= map->map_length / 4)
711   {
712     grow (map);
713     i = idx_of (map, key);
714   }
715   if (map->use_small_entries)
716   {
717     struct SmallMapEntry *sme;
718
719     sme = GNUNET_new (struct SmallMapEntry);
720     sme->key = key;
721     sme->value = value;
722     sme->next = map->map[i].sme;
723     map->map[i].sme = sme;
724   }
725   else
726   {
727     struct BigMapEntry *bme;
728
729     bme = GNUNET_new (struct BigMapEntry);
730     bme->key = *key;
731     bme->value = value;
732     bme->next = map->map[i].bme;
733     map->map[i].bme = bme;
734   }
735   map->size++;
736   return GNUNET_OK;
737 }
738
739
740 /**
741  * Iterate over all entries in the map that match a particular key.
742  *
743  * @param map the map
744  * @param key key that the entries must correspond to
745  * @param it function to call on each entry
746  * @param it_cls extra argument to @a it
747  * @return the number of key value pairs processed,
748  *         #GNUNET_SYSERR if it aborted iteration
749  */
750 int
751 GNUNET_CONTAINER_multipeermap_get_multiple (const struct GNUNET_CONTAINER_MultiPeerMap *map,
752                                             const struct GNUNET_PeerIdentity *key,
753                                             GNUNET_CONTAINER_PeerMapIterator it,
754                                             void *it_cls)
755 {
756   int count;
757   union MapEntry me;
758
759   count = 0;
760   me = map->map[idx_of (map, key)];
761   if (map->use_small_entries)
762   {
763     struct SmallMapEntry *sme;
764     struct SmallMapEntry *nxt;
765
766     nxt = me.sme;
767     while (NULL != (sme = nxt))
768     {
769       nxt = sme->next;
770       if (0 != memcmp (key, sme->key, sizeof (struct GNUNET_PeerIdentity)))
771         continue;
772       if ((it != NULL) && (GNUNET_OK != it (it_cls, key, sme->value)))
773         return GNUNET_SYSERR;
774       count++;
775     }
776   }
777   else
778   {
779     struct BigMapEntry *bme;
780     struct BigMapEntry *nxt;
781
782     nxt = me.bme;
783     while (NULL != (bme = nxt))
784     {
785       nxt = bme->next;
786       if (0 != memcmp (key, &bme->key, sizeof (struct GNUNET_PeerIdentity)))
787         continue;
788       if ((it != NULL) && (GNUNET_OK != it (it_cls, key, bme->value)))
789         return GNUNET_SYSERR;
790       count++;
791     }
792   }
793   return count;
794 }
795
796
797 /**
798  * Create an iterator for a multipeermap.
799  * The iterator can be used to retrieve all the elements in the multipeermap
800  * one by one, without having to handle all elements at once (in contrast to
801  * #GNUNET_CONTAINER_multipeermap_iterate).  Note that the iterator can not be
802  * used anymore if elements have been removed from 'map' after the creation of
803  * the iterator, or 'map' has been destroyed.  Adding elements to 'map' may
804  * result in skipped or repeated elements.
805  *
806  * @param map the map to create an iterator for
807  * @return an iterator over the given multipeermap 'map'
808  */
809 struct GNUNET_CONTAINER_MultiPeerMapIterator *
810 GNUNET_CONTAINER_multipeermap_iterator_create (const struct GNUNET_CONTAINER_MultiPeerMap *map)
811 {
812   struct GNUNET_CONTAINER_MultiPeerMapIterator *iter;
813
814   iter = GNUNET_new (struct GNUNET_CONTAINER_MultiPeerMapIterator);
815   iter->map = map;
816   iter->modification_counter = map->modification_counter;
817   iter->me = map->map[0];
818   return iter;
819 }
820
821
822 /**
823  * Retrieve the next element from the hash map at the iterator's position.
824  * If there are no elements left, GNUNET_NO is returned, and 'key' and 'value'
825  * are not modified.
826  * This operation is only allowed if no elements have been removed from the
827  * multipeermap since the creation of 'iter', and the map has not been destroyed.
828  * Adding elements may result in repeating or skipping elements.
829  *
830  * @param iter the iterator to get the next element from
831  * @param key pointer to store the key in, can be NULL
832  * @param value pointer to store the value in, can be NULL
833  * @return #GNUNET_YES we returned an element,
834  *         #GNUNET_NO if we are out of elements
835  */
836 int
837 GNUNET_CONTAINER_multipeermap_iterator_next (struct GNUNET_CONTAINER_MultiPeerMapIterator *iter,
838                                              struct GNUNET_PeerIdentity *key, const void **value)
839 {
840   /* make sure the map has not been modified */
841   GNUNET_assert (iter->modification_counter == iter->map->modification_counter);
842
843   /* look for the next entry, skipping empty buckets */
844   while (1)
845   {
846     if (iter->idx >= iter->map->map_length)
847       return GNUNET_NO;
848     if (GNUNET_YES == iter->map->use_small_entries)
849     {
850       if (NULL != iter->me.sme)
851       {
852         if (NULL != key)
853           *key = *iter->me.sme->key;
854         if (NULL != value)
855           *value = iter->me.sme->value;
856         iter->me.sme = iter->me.sme->next;
857         return GNUNET_YES;
858       }
859     }
860     else
861     {
862       if (NULL != iter->me.bme)
863       {
864         if (NULL != key)
865           *key = iter->me.bme->key;
866         if (NULL != value)
867           *value = iter->me.bme->value;
868         iter->me.bme = iter->me.bme->next;
869         return GNUNET_YES;
870       }
871     }
872     iter->idx += 1;
873     if (iter->idx < iter->map->map_length)
874       iter->me = iter->map->map[iter->idx];
875   }
876 }
877
878
879 /**
880  * Destroy a multipeermap iterator.
881  *
882  * @param iter the iterator to destroy
883  */
884 void
885 GNUNET_CONTAINER_multipeermap_iterator_destroy (struct GNUNET_CONTAINER_MultiPeerMapIterator *iter)
886 {
887   GNUNET_free (iter);
888 }
889
890
891 /* end of container_multipeermap.c */