jmap.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. #ifndef CCAN_JMAP_H
  2. #define CCAN_JMAP_H
  3. #include <stddef.h>
  4. #include <Judy.h>
  5. #include <stdbool.h>
  6. #include <string.h>
  7. #include <ccan/compiler/compiler.h>
  8. #include <assert.h>
  9. #ifdef CCAN_JMAP_DEBUG
  10. #include <stdio.h>
  11. #endif
  12. /**
  13. * jmap_new - create a new, empty jmap.
  14. *
  15. * See Also:
  16. * JMAP_DEFINE_TYPE()
  17. *
  18. * Example:
  19. * struct jmap *map = jmap_new();
  20. * if (!map)
  21. * errx(1, "Failed to allocate jmap");
  22. */
  23. struct jmap *jmap_new(void);
  24. /**
  25. * jmap_free - destroy a jmap.
  26. * @map: the map returned from jmap_new.
  27. *
  28. * Example:
  29. * jmap_free(map);
  30. */
  31. void jmap_free(const struct jmap *map);
  32. /* This is exposed in the header so we can inline. Treat it as private! */
  33. struct jmap {
  34. Pvoid_t judy;
  35. JError_t err;
  36. const char *errstr;
  37. /* Used if !NDEBUG */
  38. int num_accesses;
  39. /* Used if CCAN_JMAP_DEBUG */
  40. unsigned long *acc_value;
  41. unsigned long acc_index;
  42. const char *funcname;
  43. };
  44. const char *COLD jmap_error_(struct jmap *map);
  45. /* Debugging checks. */
  46. static inline void jmap_debug_add_access(const struct jmap *map,
  47. unsigned long index,
  48. unsigned long *val,
  49. const char *funcname)
  50. {
  51. #ifdef CCAN_JMAP_DEBUG
  52. if (!map->acc_value) {
  53. ((struct jmap *)map)->acc_value = val;
  54. ((struct jmap *)map)->acc_index = index;
  55. ((struct jmap *)map)->funcname = funcname;
  56. }
  57. #endif
  58. if (val)
  59. assert(++((struct jmap *)map)->num_accesses);
  60. }
  61. static inline void jmap_debug_del_access(struct jmap *map, unsigned long **val)
  62. {
  63. assert(--map->num_accesses >= 0);
  64. #ifdef CCAN_JMAP_DEBUG
  65. if (map->acc_value == *val)
  66. map->acc_value = NULL;
  67. #endif
  68. /* Set it to some invalid value. Not NULL, they might rely on that! */
  69. assert(memset(val, 0x42, sizeof(*val)));
  70. }
  71. static inline void jmap_debug_access(struct jmap *map)
  72. {
  73. #ifdef CCAN_JMAP_DEBUG
  74. if (map->num_accesses && map->acc_value)
  75. fprintf(stderr,
  76. "jmap: still got index %lu, val %lu (%p) from %s\n",
  77. map->acc_index, *map->acc_value, map->acc_value,
  78. map->funcname);
  79. #endif
  80. assert(!map->num_accesses);
  81. }
  82. /**
  83. * jmap_error - test for an error in the a previous jmap_ operation.
  84. * @map: the map to test.
  85. *
  86. * Under normal circumstances, return NULL to indicate no error has occurred.
  87. * Otherwise, it will return a string containing the error. This string
  88. * can only be freed by jmap_free() on the map.
  89. *
  90. * Other than out-of-memory, errors are caused by memory corruption or
  91. * interface misuse.
  92. *
  93. * Example:
  94. * struct jmap *map = jmap_new();
  95. * const char *errstr;
  96. *
  97. * if (!map)
  98. * err(1, "allocating jmap");
  99. * errstr = jmap_error(map);
  100. * if (errstr)
  101. * errx(1, "Woah, error on newly created map?! %s", errstr);
  102. */
  103. static inline const char *jmap_error(struct jmap *map)
  104. {
  105. if (JU_ERRNO(&map->err) <= JU_ERRNO_NFMAX)
  106. return NULL;
  107. return jmap_error_(map);
  108. }
  109. /**
  110. * jmap_add - add or replace a value for a given index in the map.
  111. * @map: map from jmap_new
  112. * @index: the index to map
  113. * @value: the value to associate with the index
  114. *
  115. * Adds index into the map; replaces value if it's already there.
  116. * Returns false on error (out of memory).
  117. *
  118. * Example:
  119. * if (!jmap_add(map, 0, 1))
  120. * err(1, "jmap_add failed!");
  121. */
  122. static inline bool jmap_add(struct jmap *map,
  123. unsigned long index, unsigned long value)
  124. {
  125. unsigned long *val;
  126. jmap_debug_access(map);
  127. val = (unsigned long *)JudyLIns(&map->judy, index, &map->err);
  128. if (val == PJERR)
  129. return false;
  130. *val = value;
  131. return true;
  132. }
  133. /**
  134. * jmap_set - change a value for an existing index in the map.
  135. * @map: map from jmap_new
  136. * @index: the index to map
  137. * @value: the value to associate with the index
  138. *
  139. * This sets the value of an index if it already exists, and return true,
  140. * otherwise returns false and does nothing.
  141. *
  142. * Example:
  143. * if (!jmap_set(map, 0, 2))
  144. * err(1, "jmap_set: index 0 not found");
  145. */
  146. static inline bool jmap_set(const struct jmap *map,
  147. unsigned long index, unsigned long value)
  148. {
  149. unsigned long *val;
  150. val = (unsigned long *)JudyLGet(map->judy, index,
  151. (JError_t *)&map->err);
  152. if (val && val != PJERR) {
  153. *val = value;
  154. return true;
  155. }
  156. return false;
  157. }
  158. /**
  159. * jmap_del - remove an index from the map.
  160. * @map: map from jmap_new
  161. * @index: the index to map
  162. *
  163. * Example:
  164. * if (!jmap_del(map, 0))
  165. * err(1, "jmap_del failed!");
  166. */
  167. static inline bool jmap_del(struct jmap *map, unsigned long index)
  168. {
  169. jmap_debug_access(map);
  170. return JudyLDel(&map->judy, index, &map->err) == 1;
  171. }
  172. /**
  173. * jmap_test - test if a given index is defined.
  174. * @map: map from jmap_new
  175. * @index: the index to find
  176. *
  177. * Example:
  178. * jmap_add(map, 0, 1);
  179. * assert(jmap_test(map, 0));
  180. */
  181. static inline bool jmap_test(const struct jmap *map, unsigned long index)
  182. {
  183. return JudyLGet(map->judy, index, (JError_t *)&map->err) != NULL;
  184. }
  185. /**
  186. * jmap_get - get a value for a given index.
  187. * @map: map from jmap_new
  188. * @index: the index to find
  189. * @invalid: the value to return if the index isn't found.
  190. *
  191. * Example:
  192. * jmap_add(map, 0, 1);
  193. * assert(jmap_get(map, 0, -1) == 1);
  194. *
  195. * See Also:
  196. * jmap_getval()
  197. */
  198. static inline unsigned long jmap_get(const struct jmap *map,
  199. unsigned long index,
  200. unsigned long invalid)
  201. {
  202. unsigned long *val;
  203. val = (unsigned long *)JudyLGet(map->judy, index,
  204. (JError_t *)&map->err);
  205. if (!val || val == PJERR)
  206. return invalid;
  207. return *val;
  208. }
  209. /**
  210. * jmap_popcount - get population of (some part of) the map.
  211. * @map: map from jmap_new
  212. * @start: first index to count
  213. * @end_incl: last index to count (use -1 for end).
  214. *
  215. * Example:
  216. * assert(jmap_popcount(map, 0, 1000) <= jmap_popcount(map, 0, 2000));
  217. */
  218. static inline unsigned long jmap_popcount(const struct jmap *map,
  219. unsigned long start,
  220. unsigned long end_incl)
  221. {
  222. return JudyLCount(map->judy, start, end_incl, (JError_t *)&map->err);
  223. }
  224. /**
  225. * jmap_nth - return the index of the nth value in the map.
  226. * @map: map from jmap_new
  227. * @n: which index we are interested in (0-based)
  228. * @invalid: what to return if n >= map population
  229. *
  230. * This normally returns the nth index in the map, and often there is a
  231. * convenient known-invalid value (ie. something which is never in the
  232. * map). Otherwise you can use jmap_nthval().
  233. *
  234. * Example:
  235. * unsigned long i, index;
  236. *
  237. * // We know 0 isn't in map.
  238. * assert(!jmap_test(map, 0));
  239. * for (i = 0; (index = jmap_nth(map, i, 0)) != 0; i++) {
  240. * assert(jmap_popcount(map, 0, index) == i);
  241. * printf("Index %lu = %lu\n", i, index);
  242. * }
  243. *
  244. * See Also:
  245. * jmap_nthval();
  246. */
  247. static inline unsigned long jmap_nth(const struct jmap *map,
  248. unsigned long n, unsigned long invalid)
  249. {
  250. unsigned long index;
  251. if (!JudyLByCount(map->judy, n+1, &index, (JError_t *)&map->err))
  252. index = invalid;
  253. return index;
  254. }
  255. /**
  256. * jmap_first - return the first index in the map.
  257. * @map: map from jmap_new
  258. * @invalid: return value if jmap is empty.
  259. *
  260. * This is equivalent to jmap_nth(map, 0, invalid).
  261. *
  262. * Example:
  263. * assert(!jmap_test(map, 0));
  264. * printf("Map indices (increasing order):");
  265. * for (i = jmap_first(map, 0); i; i = jmap_next(map, i, 0))
  266. * printf(" %lu", i);
  267. * printf("\n");
  268. *
  269. * See Also:
  270. * jmap_firstval()
  271. */
  272. static inline unsigned long jmap_first(const struct jmap *map,
  273. unsigned long invalid)
  274. {
  275. unsigned long index = 0;
  276. if (!JudyLFirst(map->judy, &index, (JError_t *)&map->err))
  277. index = invalid;
  278. else
  279. assert(index != invalid);
  280. return index;
  281. }
  282. /**
  283. * jmap_next - return the next index in the map.
  284. * @map: map from jmap_new
  285. * @prev: previous index
  286. * @invalid: return value if there prev was final index in map.
  287. *
  288. * This is usually used to find an adjacent index after jmap_first.
  289. * See Also:
  290. * jmap_nextval()
  291. */
  292. static inline unsigned long jmap_next(const struct jmap *map,
  293. unsigned long prev,
  294. unsigned long invalid)
  295. {
  296. if (!JudyLNext(map->judy, &prev, (JError_t *)&map->err))
  297. prev = invalid;
  298. else
  299. assert(prev != invalid);
  300. return prev;
  301. }
  302. /**
  303. * jmap_last - return the last index in the map.
  304. * @map: map from jmap_new
  305. * @invalid: return value if map is empty.
  306. *
  307. * Example:
  308. * assert(!jmap_test(map, 0));
  309. * printf("Map indices (increasing order):");
  310. * for (i = jmap_last(map, 0); i; i = jmap_prev(map, i, 0))
  311. * printf(" %lu", i);
  312. * printf("\n");
  313. * See Also:
  314. * jmap_lastval()
  315. */
  316. static inline unsigned long jmap_last(const struct jmap *map,
  317. unsigned long invalid)
  318. {
  319. unsigned long index = -1;
  320. if (!JudyLLast(map->judy, &index, (JError_t *)&map->err))
  321. index = invalid;
  322. else
  323. assert(index != invalid);
  324. return index;
  325. }
  326. /**
  327. * jmap_prev - return the previous index in the map.
  328. * @map: map from jmap_new
  329. * @prev: previous index
  330. * @invalid: return value if no previous indices are in the map.
  331. *
  332. * This is usually used to find an prior adjacent index after jmap_last.
  333. * See Also:
  334. * jmap_prevval()
  335. */
  336. static inline unsigned long jmap_prev(const struct jmap *map,
  337. unsigned long prev,
  338. unsigned long invalid)
  339. {
  340. if (!JudyLPrev(map->judy, &prev, (JError_t *)&map->err))
  341. prev = invalid;
  342. else
  343. assert(prev != invalid);
  344. return prev;
  345. }
  346. /**
  347. * jmap_getval - access a value in-place for a given index.
  348. * @map: map from jmap_new
  349. * @index: the index to find
  350. *
  351. * Returns a pointer into the map, or NULL if the index isn't in the
  352. * map. Like the other val functions (jmap_nthval, jmap_firstval
  353. * etc), this pointer cannot be used after a jmap_add or jmap_del
  354. * call, and you must call jmap_putval() once you are finished.
  355. *
  356. * Unless you define NDEBUG, jmap_add and kmap_del will check that you
  357. * have called jmap_putval().
  358. *
  359. * Example:
  360. * unsigned long *p;
  361. * jmap_add(map, 0, 1);
  362. * p = jmap_getval(map, 0);
  363. * if (!p)
  364. * errx(1, "Could not find 0 in map!");
  365. * if (*p != 1)
  366. * errx(1, "Value in map was not 0?!");
  367. * *p = 7;
  368. * jmap_putval(map, &p);
  369. * // Accessing p now would probably crash.
  370. *
  371. * See Also:
  372. * jmap_putval(), jmap_firstval()
  373. */
  374. static inline unsigned long *jmap_getval(struct jmap *map, unsigned long index)
  375. {
  376. unsigned long *val;
  377. val = (unsigned long *)JudyLGet(map->judy, index,
  378. (JError_t *)&map->err);
  379. jmap_debug_add_access(map, index, val, "jmap_getval");
  380. return val;
  381. }
  382. /**
  383. * jmap_putval - revoke access to a value.
  384. * @map: map from jmap_new
  385. * @p: the pointer to a pointer to the value
  386. *
  387. * @p is a pointer to the (successful) value retuned from one of the
  388. * jmap_*val functions (listed below). After this, it will be invalid.
  389. *
  390. * Unless NDEBUG is defined, this will actually alter the value of p
  391. * to point to garbage to help avoid accidental use.
  392. *
  393. * See Also:
  394. * jmap_getval(), jmap_nthval(), jmap_firstval(), jmap_nextval(),
  395. * jmap_lastval(), jmap_prevval().
  396. */
  397. static inline void jmap_putval(struct jmap *map, unsigned long **p)
  398. {
  399. jmap_debug_del_access(map, p);
  400. }
  401. /**
  402. * jmap_nthval - access the value of the nth value in the map.
  403. * @map: map from jmap_new
  404. * @n: which index we are interested in (0-based)
  405. *
  406. * This returns a pointer to the value at the nth index in the map,
  407. * or NULL if there are n is greater than the population of the map.
  408. * You must use jmap_putval() on the pointer once you are done with it.
  409. *
  410. * Example:
  411. * unsigned long *val;
  412. *
  413. * // We know 0 isn't in map.
  414. * assert(!jmap_test(map, 0));
  415. * for (i = 0; (val = jmap_nthval(map, i, &index)) != NULL; i++) {
  416. * assert(jmap_popcount(map, 0, index) == i);
  417. * printf("Index %lu = %lu, value = %lu\n", i, index, *val);
  418. * jmap_putval(map, &val);
  419. * }
  420. *
  421. * See Also:
  422. * jmap_nth();
  423. */
  424. static inline unsigned long *jmap_nthval(const struct jmap *map,
  425. unsigned long n, unsigned long *index)
  426. {
  427. unsigned long *val;
  428. val = (unsigned long *)JudyLByCount(map->judy, n+1, index,
  429. (JError_t *)&map->err);
  430. jmap_debug_add_access(map, *index, val, "jmap_nthval");
  431. return val;
  432. }
  433. /**
  434. * jmap_firstval - access the first value in the map.
  435. * @map: map from jmap_new
  436. * @index: set to the first index in the map.
  437. *
  438. * Returns NULL if the map is empty; otherwise this returns a pointer to
  439. * the first value, which you must call jmap_putval() on!
  440. *
  441. * Example:
  442. * // Add one to every value.
  443. * for (val = jmap_firstval(map, &i); val; val = jmap_nextval(map, &i)) {
  444. * (*val)++;
  445. * jmap_putval(map, &val);
  446. * }
  447. * printf("\n");
  448. *
  449. * See Also:
  450. * jmap_first, jmap_nextval()
  451. */
  452. static inline unsigned long *jmap_firstval(const struct jmap *map,
  453. unsigned long *index)
  454. {
  455. unsigned long *val;
  456. *index = 0;
  457. val = (unsigned long *)JudyLFirst(map->judy, index,
  458. (JError_t *)&map->err);
  459. jmap_debug_add_access(map, *index, val, "jmap_firstval");
  460. return val;
  461. }
  462. /**
  463. * jmap_nextval - access the next value in the map.
  464. * @map: map from jmap_new
  465. * @index: previous index, updated with the new index.
  466. *
  467. * This returns a pointer to a value (which you must call jmap_putval on)
  468. * or NULL. This usually used to find an adjacent value after jmap_firstval.
  469. *
  470. * See Also:
  471. * jmap_firstval(), jmap_putval()
  472. */
  473. static inline unsigned long *jmap_nextval(const struct jmap *map,
  474. unsigned long *index)
  475. {
  476. unsigned long *val;
  477. val = (unsigned long *)JudyLNext(map->judy, index,
  478. (JError_t *)&map->err);
  479. jmap_debug_add_access(map, *index, val, "jmap_nextval");
  480. return val;
  481. }
  482. /**
  483. * jmap_lastval - access the last value in the map.
  484. * @map: map from jmap_new
  485. * @index: set to the last index in the map.
  486. *
  487. * See Also:
  488. * jmap_last(), jmap_putval()
  489. */
  490. static inline unsigned long *jmap_lastval(const struct jmap *map,
  491. unsigned long *index)
  492. {
  493. unsigned long *val;
  494. *index = -1;
  495. val = (unsigned long *)JudyLLast(map->judy, index,
  496. (JError_t *)&map->err);
  497. jmap_debug_add_access(map, *index, val, "jmap_lastval");
  498. return val;
  499. }
  500. /**
  501. * jmap_prevval - access the previous value in the map.
  502. * @map: map from jmap_new
  503. * @index: previous index, updated with the new index.
  504. *
  505. * This returns a pointer to a value (which you must call jmap_putval on)
  506. * or NULL. This usually used to find an adjacent value after jmap_lastval.
  507. *
  508. * See Also:
  509. * jmap_lastval(), jmap_putval()
  510. */
  511. static inline unsigned long *jmap_prevval(const struct jmap *map,
  512. unsigned long *index)
  513. {
  514. unsigned long *val;
  515. val = (unsigned long *)JudyLPrev(map->judy, index,
  516. (JError_t *)&map->err);
  517. jmap_debug_add_access(map, *index, val, "jmap_prevval");
  518. return val;
  519. }
  520. #endif /* CCAN_JMAP_H */