container_multiuuidmap.c 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013
  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_multiuuidmap.c
  18. * @brief hash map for UUIDs 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-multiuuidmap", __VA_ARGS__)
  25. /**
  26. * Maximum recursion depth for callbacks of
  27. * #GNUNET_CONTAINER_multihashmap_get_multiple() themselve 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_Uuid 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_Uuid *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_MultiUuidmap
  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 multiuuidmap.
  123. * Allows to enumerate elements asynchronously.
  124. */
  125. struct GNUNET_CONTAINER_MultiUuidmapIterator
  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_MultiUuidmap *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 recipie 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_MultiUuidmap *
  161. GNUNET_CONTAINER_multiuuidmap_create (unsigned int len, int do_not_copy_keys)
  162. {
  163. struct GNUNET_CONTAINER_MultiUuidmap *map;
  164. GNUNET_assert (len > 0);
  165. map = GNUNET_new (struct GNUNET_CONTAINER_MultiUuidmap);
  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_multiuuidmap_destroy (
  184. struct GNUNET_CONTAINER_MultiUuidmap *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_MultiUuidmap *map,
  228. const struct GNUNET_Uuid *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_multiuuidmap_size (
  243. const struct GNUNET_CONTAINER_MultiUuidmap *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_multiuuidmap_get (
  259. const struct GNUNET_CONTAINER_MultiUuidmap *map,
  260. const struct GNUNET_Uuid *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_multiuuidmap_iterate (
  289. struct GNUNET_CONTAINER_MultiUuidmap *map,
  290. GNUNET_CONTAINER_MultiUuidmapIteratorCallback it,
  291. void *it_cls)
  292. {
  293. int count;
  294. union MapEntry me;
  295. union MapEntry *ce;
  296. struct GNUNET_Uuid 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_MultiUuidmap *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_MultiUuidmap *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_multiuuidmap_remove (struct GNUNET_CONTAINER_MultiUuidmap *map,
  385. const struct GNUNET_Uuid *key,
  386. const void *value)
  387. {
  388. union MapEntry me;
  389. unsigned int i;
  390. map->modification_counter++;
  391. i = idx_of (map, key);
  392. me = map->map[i];
  393. if (map->use_small_entries)
  394. {
  395. struct SmallMapEntry *p = NULL;
  396. for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
  397. {
  398. if ((0 == GNUNET_memcmp (key, sme->key)) && (value == sme->value))
  399. {
  400. if (NULL == p)
  401. map->map[i].sme = sme->next;
  402. else
  403. p->next = sme->next;
  404. update_next_cache_sme (map, sme);
  405. GNUNET_free (sme);
  406. map->size--;
  407. return GNUNET_YES;
  408. }
  409. p = sme;
  410. }
  411. }
  412. else
  413. {
  414. struct BigMapEntry *p = NULL;
  415. for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
  416. {
  417. if ((0 == GNUNET_memcmp (key, &bme->key)) && (value == bme->value))
  418. {
  419. if (NULL == p)
  420. map->map[i].bme = bme->next;
  421. else
  422. p->next = bme->next;
  423. update_next_cache_bme (map, bme);
  424. GNUNET_free (bme);
  425. map->size--;
  426. return GNUNET_YES;
  427. }
  428. p = bme;
  429. }
  430. }
  431. return GNUNET_NO;
  432. }
  433. /**
  434. * Remove all entries for the given key from the map.
  435. * Note that the values would not be "freed".
  436. *
  437. * @param map the map
  438. * @param key identifies values to be removed
  439. * @return number of values removed
  440. */
  441. int
  442. GNUNET_CONTAINER_multiuuidmap_remove_all (
  443. struct GNUNET_CONTAINER_MultiUuidmap *map,
  444. const struct GNUNET_Uuid *key)
  445. {
  446. union MapEntry me;
  447. unsigned int i;
  448. int ret;
  449. map->modification_counter++;
  450. ret = 0;
  451. i = idx_of (map, key);
  452. me = map->map[i];
  453. if (map->use_small_entries)
  454. {
  455. struct SmallMapEntry *sme;
  456. struct SmallMapEntry *p;
  457. p = NULL;
  458. sme = me.sme;
  459. while (NULL != sme)
  460. {
  461. if (0 == GNUNET_memcmp (key, sme->key))
  462. {
  463. if (NULL == p)
  464. map->map[i].sme = sme->next;
  465. else
  466. p->next = sme->next;
  467. update_next_cache_sme (map, sme);
  468. GNUNET_free (sme);
  469. map->size--;
  470. if (NULL == p)
  471. sme = map->map[i].sme;
  472. else
  473. sme = p->next;
  474. ret++;
  475. }
  476. else
  477. {
  478. p = sme;
  479. sme = sme->next;
  480. }
  481. }
  482. }
  483. else
  484. {
  485. struct BigMapEntry *bme;
  486. struct BigMapEntry *p;
  487. p = NULL;
  488. bme = me.bme;
  489. while (NULL != bme)
  490. {
  491. if (0 == GNUNET_memcmp (key, &bme->key))
  492. {
  493. if (NULL == p)
  494. map->map[i].bme = bme->next;
  495. else
  496. p->next = bme->next;
  497. update_next_cache_bme (map, bme);
  498. GNUNET_free (bme);
  499. map->size--;
  500. if (NULL == p)
  501. bme = map->map[i].bme;
  502. else
  503. bme = p->next;
  504. ret++;
  505. }
  506. else
  507. {
  508. p = bme;
  509. bme = bme->next;
  510. }
  511. }
  512. }
  513. return ret;
  514. }
  515. /**
  516. * Check if the map contains any value under the given
  517. * key (including values that are NULL).
  518. *
  519. * @param map the map
  520. * @param key the key to test if a value exists for it
  521. * @return #GNUNET_YES if such a value exists,
  522. * #GNUNET_NO if not
  523. */
  524. int
  525. GNUNET_CONTAINER_multiuuidmap_contains (
  526. const struct GNUNET_CONTAINER_MultiUuidmap *map,
  527. const struct GNUNET_Uuid *key)
  528. {
  529. union MapEntry me;
  530. me = map->map[idx_of (map, key)];
  531. if (map->use_small_entries)
  532. {
  533. for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
  534. if (0 == GNUNET_memcmp (key, sme->key))
  535. return GNUNET_YES;
  536. }
  537. else
  538. {
  539. for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
  540. if (0 == GNUNET_memcmp (key, &bme->key))
  541. return GNUNET_YES;
  542. }
  543. return GNUNET_NO;
  544. }
  545. /**
  546. * Check if the map contains the given value under the given
  547. * key.
  548. *
  549. * @param map the map
  550. * @param key the key to test if a value exists for it
  551. * @param value value to test for
  552. * @return #GNUNET_YES if such a value exists,
  553. * #GNUNET_NO if not
  554. */
  555. int
  556. GNUNET_CONTAINER_multiuuidmap_contains_value (
  557. const struct GNUNET_CONTAINER_MultiUuidmap *map,
  558. const struct GNUNET_Uuid *key,
  559. const void *value)
  560. {
  561. union MapEntry me;
  562. me = map->map[idx_of (map, key)];
  563. if (map->use_small_entries)
  564. {
  565. for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
  566. if ((0 == GNUNET_memcmp (key, sme->key)) && (sme->value == value))
  567. return GNUNET_YES;
  568. }
  569. else
  570. {
  571. for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
  572. if ((0 == GNUNET_memcmp (key, &bme->key)) && (bme->value == value))
  573. return GNUNET_YES;
  574. }
  575. return GNUNET_NO;
  576. }
  577. /**
  578. * Grow the given map to a more appropriate size.
  579. *
  580. * @param map the hash map to grow
  581. */
  582. static void
  583. grow (struct GNUNET_CONTAINER_MultiUuidmap *map)
  584. {
  585. union MapEntry *old_map;
  586. union MapEntry *new_map;
  587. unsigned int old_len;
  588. unsigned int new_len;
  589. unsigned int idx;
  590. old_map = map->map;
  591. old_len = map->map_length;
  592. new_len = old_len * 2;
  593. if (0 == new_len) /* 2^31 * 2 == 0 */
  594. new_len = old_len; /* never use 0 */
  595. if (new_len == old_len)
  596. return; /* nothing changed */
  597. new_map = GNUNET_malloc_large (new_len * sizeof(union MapEntry));
  598. if (NULL == new_map)
  599. return; /* grow not possible */
  600. map->modification_counter++;
  601. map->map_length = new_len;
  602. map->map = new_map;
  603. for (unsigned int i = 0; i < old_len; i++)
  604. {
  605. if (map->use_small_entries)
  606. {
  607. struct SmallMapEntry *sme;
  608. while (NULL != (sme = old_map[i].sme))
  609. {
  610. old_map[i].sme = sme->next;
  611. idx = idx_of (map, sme->key);
  612. sme->next = new_map[idx].sme;
  613. new_map[idx].sme = sme;
  614. }
  615. }
  616. else
  617. {
  618. struct BigMapEntry *bme;
  619. while (NULL != (bme = old_map[i].bme))
  620. {
  621. old_map[i].bme = bme->next;
  622. idx = idx_of (map, &bme->key);
  623. bme->next = new_map[idx].bme;
  624. new_map[idx].bme = bme;
  625. }
  626. }
  627. }
  628. GNUNET_free (old_map);
  629. }
  630. /**
  631. * Store a key-value pair in the map.
  632. *
  633. * @param map the map
  634. * @param key key to use
  635. * @param value value to use
  636. * @param opt options for put
  637. * @return #GNUNET_OK on success,
  638. * #GNUNET_NO if a value was replaced (with REPLACE)
  639. * #GNUNET_SYSERR if #GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY was the option and the
  640. * value already exists
  641. */
  642. int
  643. GNUNET_CONTAINER_multiuuidmap_put (struct GNUNET_CONTAINER_MultiUuidmap *map,
  644. const struct GNUNET_Uuid *key,
  645. void *value,
  646. enum GNUNET_CONTAINER_MultiHashMapOption opt)
  647. {
  648. union MapEntry me;
  649. unsigned int i;
  650. i = idx_of (map, key);
  651. if ((opt != GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE) &&
  652. (opt != GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
  653. {
  654. me = map->map[i];
  655. if (map->use_small_entries)
  656. {
  657. for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
  658. if (0 == GNUNET_memcmp (key, sme->key))
  659. {
  660. if (opt == GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)
  661. return GNUNET_SYSERR;
  662. sme->value = value;
  663. return GNUNET_NO;
  664. }
  665. }
  666. else
  667. {
  668. for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
  669. if (0 == GNUNET_memcmp (key, &bme->key))
  670. {
  671. if (opt == GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)
  672. return GNUNET_SYSERR;
  673. bme->value = value;
  674. return GNUNET_NO;
  675. }
  676. }
  677. }
  678. if (map->size / 3 >= map->map_length / 4)
  679. {
  680. grow (map);
  681. i = idx_of (map, key);
  682. }
  683. if (map->use_small_entries)
  684. {
  685. struct SmallMapEntry *sme;
  686. sme = GNUNET_new (struct SmallMapEntry);
  687. sme->key = key;
  688. sme->value = value;
  689. sme->next = map->map[i].sme;
  690. map->map[i].sme = sme;
  691. }
  692. else
  693. {
  694. struct BigMapEntry *bme;
  695. bme = GNUNET_new (struct BigMapEntry);
  696. bme->key = *key;
  697. bme->value = value;
  698. bme->next = map->map[i].bme;
  699. map->map[i].bme = bme;
  700. }
  701. map->size++;
  702. return GNUNET_OK;
  703. }
  704. /**
  705. * Iterate over all entries in the map that match a particular key.
  706. *
  707. * @param map the map
  708. * @param key key that the entries must correspond to
  709. * @param it function to call on each entry
  710. * @param it_cls extra argument to @a it
  711. * @return the number of key value pairs processed,
  712. * #GNUNET_SYSERR if it aborted iteration
  713. */
  714. int
  715. GNUNET_CONTAINER_multiuuidmap_get_multiple (
  716. struct GNUNET_CONTAINER_MultiUuidmap *map,
  717. const struct GNUNET_Uuid *key,
  718. GNUNET_CONTAINER_MultiUuidmapIteratorCallback it,
  719. void *it_cls)
  720. {
  721. int count;
  722. union MapEntry me;
  723. union MapEntry *ce;
  724. ce = &map->next_cache[map->next_cache_off];
  725. GNUNET_assert (++map->next_cache_off < NEXT_CACHE_SIZE);
  726. count = 0;
  727. me = map->map[idx_of (map, key)];
  728. if (map->use_small_entries)
  729. {
  730. struct SmallMapEntry *sme;
  731. ce->sme = me.sme;
  732. while (NULL != (sme = ce->sme))
  733. {
  734. ce->sme = sme->next;
  735. if (0 != GNUNET_memcmp (key, sme->key))
  736. continue;
  737. if ((NULL != it) && (GNUNET_OK != it (it_cls, key, sme->value)))
  738. {
  739. GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
  740. return GNUNET_SYSERR;
  741. }
  742. count++;
  743. }
  744. }
  745. else
  746. {
  747. struct BigMapEntry *bme;
  748. ce->bme = me.bme;
  749. while (NULL != (bme = ce->bme))
  750. {
  751. ce->bme = bme->next;
  752. if (0 != GNUNET_memcmp (key, &bme->key))
  753. continue;
  754. if ((NULL != it) && (GNUNET_OK != it (it_cls, key, bme->value)))
  755. {
  756. GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
  757. return GNUNET_SYSERR;
  758. }
  759. count++;
  760. }
  761. }
  762. GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
  763. return count;
  764. }
  765. /**
  766. * @ingroup hashmap
  767. * Call @a it on a random value from the map, or not at all
  768. * if the map is empty. Note that this function has linear
  769. * complexity (in the size of the map).
  770. *
  771. * @param map the map
  772. * @param it function to call on a random entry
  773. * @param it_cls extra argument to @a it
  774. * @return the number of key value pairs processed, zero or one.
  775. */
  776. unsigned int
  777. GNUNET_CONTAINER_multiuuidmap_get_random (
  778. const struct GNUNET_CONTAINER_MultiUuidmap *map,
  779. GNUNET_CONTAINER_MultiUuidmapIteratorCallback it,
  780. void *it_cls)
  781. {
  782. unsigned int off;
  783. union MapEntry me;
  784. if (0 == map->size)
  785. return 0;
  786. if (NULL == it)
  787. return 1;
  788. off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, map->size);
  789. for (unsigned int idx = 0; idx < map->map_length; idx++)
  790. {
  791. me = map->map[idx];
  792. if (map->use_small_entries)
  793. {
  794. for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
  795. {
  796. if (0 == off)
  797. {
  798. if (GNUNET_OK != it (it_cls, sme->key, sme->value))
  799. return GNUNET_SYSERR;
  800. return 1;
  801. }
  802. off--;
  803. }
  804. }
  805. else
  806. {
  807. for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
  808. {
  809. if (0 == off)
  810. {
  811. if (GNUNET_OK != it (it_cls, &bme->key, bme->value))
  812. return GNUNET_SYSERR;
  813. return 1;
  814. }
  815. off--;
  816. }
  817. }
  818. }
  819. GNUNET_break (0);
  820. return GNUNET_SYSERR;
  821. }
  822. /**
  823. * Create an iterator for a multiuuidmap.
  824. * The iterator can be used to retrieve all the elements in the multiuuidmap
  825. * one by one, without having to handle all elements at once (in contrast to
  826. * #GNUNET_CONTAINER_multiuuidmap_iterate). Note that the iterator can not be
  827. * used anymore if elements have been removed from 'map' after the creation of
  828. * the iterator, or 'map' has been destroyed. Adding elements to 'map' may
  829. * result in skipped or repeated elements.
  830. *
  831. * @param map the map to create an iterator for
  832. * @return an iterator over the given multiuuidmap 'map'
  833. */
  834. struct GNUNET_CONTAINER_MultiUuidmapIterator *
  835. GNUNET_CONTAINER_multiuuidmap_iterator_create (
  836. const struct GNUNET_CONTAINER_MultiUuidmap *map)
  837. {
  838. struct GNUNET_CONTAINER_MultiUuidmapIterator *iter;
  839. iter = GNUNET_new (struct GNUNET_CONTAINER_MultiUuidmapIterator);
  840. iter->map = map;
  841. iter->modification_counter = map->modification_counter;
  842. iter->me = map->map[0];
  843. return iter;
  844. }
  845. /**
  846. * Retrieve the next element from the hash map at the iterator's position.
  847. * If there are no elements left, GNUNET_NO is returned, and 'key' and 'value'
  848. * are not modified.
  849. * This operation is only allowed if no elements have been removed from the
  850. * multiuuidmap since the creation of 'iter', and the map has not been destroyed.
  851. * Adding elements may result in repeating or skipping elements.
  852. *
  853. * @param iter the iterator to get the next element from
  854. * @param key pointer to store the key in, can be NULL
  855. * @param value pointer to store the value in, can be NULL
  856. * @return #GNUNET_YES we returned an element,
  857. * #GNUNET_NO if we are out of elements
  858. */
  859. int
  860. GNUNET_CONTAINER_multiuuidmap_iterator_next (
  861. struct GNUNET_CONTAINER_MultiUuidmapIterator *iter,
  862. struct GNUNET_Uuid *key,
  863. const void **value)
  864. {
  865. /* make sure the map has not been modified */
  866. GNUNET_assert (iter->modification_counter == iter->map->modification_counter);
  867. /* look for the next entry, skipping empty buckets */
  868. while (1)
  869. {
  870. if (iter->idx >= iter->map->map_length)
  871. return GNUNET_NO;
  872. if (GNUNET_YES == iter->map->use_small_entries)
  873. {
  874. if (NULL != iter->me.sme)
  875. {
  876. if (NULL != key)
  877. *key = *iter->me.sme->key;
  878. if (NULL != value)
  879. *value = iter->me.sme->value;
  880. iter->me.sme = iter->me.sme->next;
  881. return GNUNET_YES;
  882. }
  883. }
  884. else
  885. {
  886. if (NULL != iter->me.bme)
  887. {
  888. if (NULL != key)
  889. *key = iter->me.bme->key;
  890. if (NULL != value)
  891. *value = iter->me.bme->value;
  892. iter->me.bme = iter->me.bme->next;
  893. return GNUNET_YES;
  894. }
  895. }
  896. iter->idx += 1;
  897. if (iter->idx < iter->map->map_length)
  898. iter->me = iter->map->map[iter->idx];
  899. }
  900. }
  901. /**
  902. * Destroy a multiuuidmap iterator.
  903. *
  904. * @param iter the iterator to destroy
  905. */
  906. void
  907. GNUNET_CONTAINER_multiuuidmap_iterator_destroy (
  908. struct GNUNET_CONTAINER_MultiUuidmapIterator *iter)
  909. {
  910. GNUNET_free (iter);
  911. }
  912. /* end of container_multiuuidmap.c */