container_multishortmap.c 24 KB

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