1 /* Licensed under LGPLv2.1+ - see LICENSE file for details */
4 #include <ccan/compiler/compiler.h>
5 #include <ccan/tcon/tcon.h>
11 #ifdef CCAN_JMAP_DEBUG
16 * struct map - private definition of a jmap.
18 * It's exposed here so you can put it in your structures and so we can
19 * supply inline functions.
27 /* Used if CCAN_JMAP_DEBUG */
28 unsigned long *acc_value;
29 unsigned long acc_index;
34 * JMAP_MEMBERS - declare members for a type-specific jmap.
35 * @itype: index type for this map, or void * for any pointer.
36 * @ctype: contents type for this map, or void * for any pointer.
39 * struct jmap_long_to_charp {
40 * JMAP_MEMBERS(long, char *);
43 #define JMAP_MEMBERS(itype, ctype) \
45 TCON(itype icanary; ctype ccanary)
48 * jmap_new - create a new, empty jmap.
54 * struct jmap_long_to_charp {
55 * JMAP_MEMBERS(long, char *);
58 * struct jmap_long_to_charp *map = jmap_new(struct jmap_long_to_charp);
60 * errx(1, "Failed to allocate jmap");
62 #define jmap_new(type) ((type *)jmap_new_(sizeof(type)))
65 * jmap_free - destroy a jmap.
66 * @map: the map returned from jmap_new.
71 #define jmap_free(map) jmap_free_(&(map)->raw)
74 * jmap_error - test for an error in the a previous jmap_ operation.
75 * @map: the map to test.
77 * Under normal circumstances, return NULL to indicate no error has occurred.
78 * Otherwise, it will return a string containing the error. This string
79 * can only be freed by jmap_free() on the map.
81 * Other than out-of-memory, errors are caused by memory corruption or
87 * errstr = jmap_error(map);
89 * errx(1, "Woah, error on newly created map?! %s", errstr);
91 #define jmap_error(map) jmap_error_(&(map)->raw)
94 * jmap_rawi - unwrap the typed map and check the index type
95 * @map: the typed jmap
96 * @expr: the expression to check the index type against (not evaluated)
98 * This macro usually causes the compiler to emit a warning if the
99 * variable is of an unexpected type. It is used internally where we
100 * need to access the raw underlying jmap.
102 #define jmap_rawi(map, expr) (&tcon_check((map), icanary, (expr))->raw)
105 * jmap_rawc - unwrap the typed map and check the contents type
106 * @map: the typed jmap
107 * @expr: the expression to check the content type against (not evaluated)
109 * This macro usually causes the compiler to emit a warning if the
110 * variable is of an unexpected type. It is used internally where we
111 * need to access the raw underlying jmap.
113 #define jmap_rawc(map, expr) (&tcon_check((map), ccanary, (expr))->raw)
116 * jmap_rawci - unwrap the typed map and check the index and contents types
117 * @map: the typed jmap
118 * @iexpr: the expression to check the index type against (not evaluated)
119 * @cexpr: the expression to check the contents type against (not evaluated)
121 * This macro usually causes the compiler to emit a warning if the
122 * variable is of an unexpected type. It is used internally where we
123 * need to access the raw underlying jmap.
125 #define jmap_rawci(map, iexpr, cexpr) \
126 (&tcon_check(tcon_check((map), ccanary, (cexpr)), icanary, (iexpr))->raw)
129 * jmap_add - add or replace a value for a given index in the map.
130 * @map: map from jmap_new
131 * @index: the index to map
132 * @value: the value to associate with the index
134 * Adds index into the map; replaces value if it's already there.
135 * Returns false on error (out of memory).
138 * if (!jmap_add(map, 0, "hello"))
139 * err(1, "jmap_add failed!");
141 #define jmap_add(map, index, value) \
142 jmap_add_(jmap_rawci((map), (index), (value)), \
143 (unsigned long)(index), (unsigned long)value)
146 * jmap_set - change a value for an existing index in the map.
147 * @map: map from jmap_new
148 * @index: the index to map
149 * @value: the value to associate with the index
151 * This sets the value of an index if it already exists, and return true,
152 * otherwise returns false and does nothing.
155 * if (!jmap_set(map, 0, "goodbye"))
156 * err(1, "jmap_set: index 0 not found");
158 #define jmap_set(map, index, value) \
159 jmap_set_(jmap_rawci((map), (index), (value)), \
160 (unsigned long)(index), (unsigned long)value)
163 * jmap_del - remove an index from the map.
164 * @map: map from jmap_new
165 * @index: the index to map
168 * if (!jmap_del(map, 0))
169 * err(1, "jmap_del failed!");
171 #define jmap_del(map, index) \
172 jmap_del_(jmap_rawi((map), (index)), (unsigned long)(index))
175 * jmap_test - test if a given index is defined.
176 * @map: map from jmap_new
177 * @index: the index to find
180 * jmap_add(map, 1, "hello");
181 * assert(jmap_test(map, 1));
183 #define jmap_test(map, index) \
184 jmap_test_(jmap_rawi((map), (index)), (unsigned long)(index))
187 * jmap_get - get a value for a given index.
188 * @map: map from jmap_new
189 * @index: the index to find
191 * Returns 0 if !jmap_test(map, index).
194 * const char *str = "hello";
195 * jmap_add(map, 2, str);
196 * assert(jmap_get(map, 0) == str);
201 #define jmap_get(map, index) \
202 tcon_cast((map), ccanary, \
203 jmap_get_(jmap_rawi((map), (index)), (unsigned long)(index)))
206 * jmap_count - get population of the map.
207 * @map: map from jmap_new
210 * assert(jmap_count(map) < 1000);
212 #define jmap_count(map) \
213 jmap_popcount_(&(map)->raw, 0, -1UL)
216 * jmap_popcount - get population of (some part of) the map.
217 * @map: map from jmap_new
218 * @start: first index to count
219 * @end_incl: last index to count (use -1 for end).
222 * assert(jmap_popcount(map, 0, 1000) <= jmap_popcount(map, 0, 2000));
224 #define jmap_popcount(map, start, end_incl) \
225 jmap_popcount_(jmap_rawi((map), (start) ? (start) : (end_incl)), \
226 (unsigned long)(start), (unsigned long)(end_incl))
229 * jmap_nth - return the index of the nth value in the map.
230 * @map: map from jmap_new
231 * @n: which index we are interested in (0-based)
232 * @invalid: what to return if n >= map population
234 * This normally returns the nth index in the map, and often there is a
235 * convenient known-invalid value (ie. something which is never in the
236 * map). Otherwise you can use jmap_nthval().
239 * unsigned long i, index;
241 * // We know 0 isn't in map.
242 * assert(!jmap_test(map, 0));
243 * for (i = 0; (index = jmap_nth(map, i, 0)) != 0; i++) {
244 * assert(jmap_popcount(map, 0, index) == i);
245 * printf("Index %lu = %lu\n", i, index);
251 #define jmap_nth(map, n, invalid) \
252 tcon_cast((map), icanary, \
253 jmap_nth_(jmap_rawi((map), (invalid)), \
254 (n), (unsigned long)(invalid)))
257 * jmap_first - return the first index in the map (must not contain 0).
258 * @map: map from jmap_new
260 * This is equivalent to jmap_nth(map, 0, 0).
263 * assert(!jmap_test(map, 0));
264 * printf("Map indices (increasing order):");
265 * for (i = jmap_first(map); i; i = jmap_next(map, i))
272 #define jmap_first(map) \
273 tcon_cast((map), icanary, jmap_first_(&(map)->raw))
276 * jmap_next - return the next index in the map.
277 * @map: map from jmap_new
278 * @prev: previous index
280 * This is usually used to find an adjacent index after jmap_first.
284 #define jmap_next(map, prev) \
285 tcon_cast((map), icanary, jmap_next_(jmap_rawi((map), (prev)), \
286 (unsigned long)(prev)))
289 * jmap_last - return the last index in the map.
290 * @map: map from jmap_new
292 * Returns 0 if map is empty.
295 * assert(!jmap_test(map, 0));
296 * printf("Map indices (increasing order):");
297 * for (i = jmap_last(map); i; i = jmap_prev(map, i))
303 #define jmap_last(map) \
304 tcon_cast((map), icanary, jmap_last_(&(map)->raw))
307 * jmap_prev - return the previous index in the map (must not contain 0)
308 * @map: map from jmap_new
309 * @prev: previous index
311 * This is usually used to find an prior adjacent index after jmap_last.
312 * Returns 0 if no previous indices in map.
317 #define jmap_prev(map, prev) \
318 tcon_cast((map), icanary, jmap_prev_(jmap_rawi((map), (prev)), (prev)))
321 * jmap_getval - access a value in-place for a given index.
322 * @map: map from jmap_new
323 * @index: the index to find
325 * Returns a pointer into the map, or NULL if the index isn't in the
326 * map. Like the other val functions (jmap_nthval, jmap_firstval
327 * etc), this pointer cannot be used after a jmap_add or jmap_del
328 * call, and you must call jmap_putval() once you are finished.
330 * Unless you define NDEBUG, jmap_add and kmap_del will check that you
331 * have called jmap_putval().
335 * jmap_add(map, 0, "hello");
336 * p = jmap_getval(map, 0);
338 * errx(1, "Could not find 0 in map!");
339 * if (strcmp(*p, "hello") != 0)
340 * errx(1, "Value in map was not correct?!");
341 * *p = (char *)"goodbye";
342 * jmap_putval(map, &p);
343 * // Accessing p now would probably crash.
346 * jmap_putval(), jmap_firstval()
348 #define jmap_getval(map, index) \
349 tcon_cast_ptr((map), ccanary, \
350 jmap_getval_(jmap_rawi((map), (index)), \
351 (unsigned long)(index)))
354 * jmap_putval - revoke access to a value.
355 * @map: map from jmap_new
356 * @p: the pointer to a pointer to the value
358 * @p is a pointer to the (successful) value retuned from one of the
359 * jmap_*val functions (listed below). After this, it will be invalid.
361 * Unless NDEBUG is defined, this will actually alter the value of p
362 * to point to garbage to help avoid accidental use.
365 * jmap_getval(), jmap_nthval(), jmap_firstval(), jmap_nextval(),
366 * jmap_lastval(), jmap_prevval().
368 #define jmap_putval(map, p) \
369 jmap_putval_(jmap_rawc((map), **(p)), (p))
372 * jmap_nthval - access the value of the nth value in the map.
373 * @map: map from jmap_new
374 * @n: which index we are interested in (0-based)
375 * @index: set to the nth index in the map.
377 * This returns a pointer to the value at the nth index in the map,
378 * or NULL if there are n is greater than the population of the map.
379 * You must use jmap_putval() on the pointer once you are done with it.
384 * // We know 0 isn't in map.
385 * assert(!jmap_test(map, 0));
386 * for (i = 0; (val = jmap_nthval(map, i, &index)) != NULL; i++) {
387 * assert(jmap_popcount(map, 0, index) == i);
388 * printf("Index %lu = %lu, value = %s\n", i, index, *val);
389 * jmap_putval(map, &val);
395 #define jmap_nthval(map, n, index) \
396 tcon_cast_ptr((map), ccanary, \
397 jmap_nthval_(jmap_rawi((map), *(index)), (n), (index)))
400 * jmap_firstval - access the first value in the map.
401 * @map: map from jmap_new
402 * @index: set to the first index in the map.
404 * Returns NULL if the map is empty; otherwise this returns a pointer to
405 * the first value, which you must call jmap_putval() on!
408 * // Add one to every value (ie. make it point into second char of string)
409 * for (val = jmap_firstval(map, &i); val; val = jmap_nextval(map, &i)) {
411 * jmap_putval(map, &val);
416 * jmap_first, jmap_nextval()
418 #define jmap_firstval(map, index) \
419 tcon_cast_ptr((map), ccanary, \
420 jmap_firstval_(jmap_rawi((map), *(index)), \
421 (unsigned long *)(index)))
424 * jmap_nextval - access the next value in the map.
425 * @map: map from jmap_new
426 * @index: previous index, updated with the new index.
428 * This returns a pointer to a value (which you must call jmap_putval on)
429 * or NULL. This usually used to find an adjacent value after jmap_firstval.
432 * jmap_firstval(), jmap_putval()
434 #define jmap_nextval(map, index) \
435 tcon_cast_ptr((map), ccanary, \
436 jmap_nextval_(jmap_rawi((map), *(index)), \
437 (unsigned long *)(index)))
441 * jmap_lastval - access the last value in the map.
442 * @map: map from jmap_new
443 * @index: set to the last index in the map.
446 * jmap_last(), jmap_putval()
448 #define jmap_lastval(map, index) \
449 tcon_cast_ptr((map), ccanary, \
450 jmap_lastval_(jmap_rawi((map), *(index)), \
451 (unsigned long *)(index)))
455 * jmap_prevval - access the previous value in the map.
456 * @map: map from jmap_new
457 * @index: previous index, updated with the new index.
459 * This returns a pointer to a value (which you must call jmap_putval on)
460 * or NULL. This usually used to find an adjacent value after jmap_lastval.
463 * jmap_lastval(), jmap_putval()
465 #define jmap_prevval(map, index) \
466 tcon_cast_ptr((map), ccanary, \
467 jmap_prevval_(jmap_rawi((map), *(index)), \
468 (unsigned long *)(index)))
472 /* Debugging checks. */
473 static inline void jmap_debug_add_access(const struct jmap *map,
476 const char *funcname)
478 #ifdef CCAN_JMAP_DEBUG
479 if (!map->acc_value) {
480 ((struct jmap *)map)->acc_value = val;
481 ((struct jmap *)map)->acc_index = index;
482 ((struct jmap *)map)->funcname = funcname;
486 assert(++((struct jmap *)map)->num_accesses);
489 static inline void jmap_debug_del_access(struct jmap *map, unsigned long **val)
491 assert(--map->num_accesses >= 0);
492 #ifdef CCAN_JMAP_DEBUG
493 if (map->acc_value == *val)
494 map->acc_value = NULL;
496 /* Set it to some invalid value. Not NULL, they might rely on that! */
497 assert(memset(val, 0x42, sizeof(void *)));
500 static inline void jmap_debug_access(struct jmap *map)
502 #ifdef CCAN_JMAP_DEBUG
503 if (map->num_accesses && map->acc_value)
505 "jmap: still got index %lu, val %lu (%p) from %s\n",
506 map->acc_index, *map->acc_value, map->acc_value,
509 assert(!map->num_accesses);
512 /* Private functions */
513 struct jmap *jmap_new_(size_t size);
514 void jmap_free_(const struct jmap *map);
515 const char *COLD jmap_error_str_(struct jmap *map);
516 static inline const char *jmap_error_(struct jmap *map)
518 if (JU_ERRNO(&map->err) <= JU_ERRNO_NFMAX)
520 return jmap_error_str_(map);
522 static inline bool jmap_add_(struct jmap *map,
523 unsigned long index, unsigned long value)
526 jmap_debug_access(map);
527 val = (unsigned long *)JudyLIns(&map->judy, index, &map->err);
533 static inline bool jmap_set_(const struct jmap *map,
534 unsigned long index, unsigned long value)
537 val = (unsigned long *)JudyLGet(map->judy, index,
538 (JError_t *)&map->err);
539 if (val && val != PJERR) {
545 static inline bool jmap_del_(struct jmap *map, unsigned long index)
547 jmap_debug_access(map);
548 return JudyLDel(&map->judy, index, &map->err) == 1;
550 static inline bool jmap_test_(const struct jmap *map, unsigned long index)
552 return JudyLGet(map->judy, index, (JError_t *)&map->err) != NULL;
554 static inline unsigned long jmap_get_(const struct jmap *map,
558 val = (unsigned long *)JudyLGet(map->judy, index,
559 (JError_t *)&map->err);
560 if (!val || val == PJERR)
564 static inline unsigned long jmap_popcount_(const struct jmap *map,
566 unsigned long end_incl)
568 return JudyLCount(map->judy, start, end_incl, (JError_t *)&map->err);
570 static inline unsigned long jmap_nth_(const struct jmap *map,
571 unsigned long n, unsigned long invalid)
574 if (!JudyLByCount(map->judy, n+1, &index, (JError_t *)&map->err))
578 static inline unsigned long jmap_first_(const struct jmap *map)
580 unsigned long index = 0;
581 if (!JudyLFirst(map->judy, &index, (JError_t *)&map->err))
587 static inline unsigned long jmap_next_(const struct jmap *map,
590 if (!JudyLNext(map->judy, &prev, (JError_t *)&map->err))
596 static inline unsigned long jmap_last_(const struct jmap *map)
598 unsigned long index = -1;
599 if (!JudyLLast(map->judy, &index, (JError_t *)&map->err))
605 static inline unsigned long jmap_prev_(const struct jmap *map,
608 if (!JudyLPrev(map->judy, &prev, (JError_t *)&map->err))
614 static inline void *jmap_getval_(struct jmap *map, unsigned long index)
617 val = (unsigned long *)JudyLGet(map->judy, index,
618 (JError_t *)&map->err);
619 jmap_debug_add_access(map, index, val, "jmap_getval");
622 static inline void jmap_putval_(struct jmap *map, void *p)
624 jmap_debug_del_access(map, p);
626 static inline unsigned long *jmap_nthval_(const struct jmap *map, unsigned long n,
627 unsigned long *index)
630 val = (unsigned long *)JudyLByCount(map->judy, n+1, index,
631 (JError_t *)&map->err);
632 jmap_debug_add_access(map, *index, val, "jmap_nthval");
635 static inline unsigned long *jmap_firstval_(const struct jmap *map,
636 unsigned long *index)
640 val = (unsigned long *)JudyLFirst(map->judy, index,
641 (JError_t *)&map->err);
642 jmap_debug_add_access(map, *index, val, "jmap_firstval");
645 static inline unsigned long *jmap_nextval_(const struct jmap *map,
646 unsigned long *index)
649 val = (unsigned long *)JudyLNext(map->judy, index,
650 (JError_t *)&map->err);
651 jmap_debug_add_access(map, *index, val, "jmap_nextval");
654 static inline unsigned long *jmap_lastval_(const struct jmap *map,
655 unsigned long *index)
659 val = (unsigned long *)JudyLLast(map->judy, index,
660 (JError_t *)&map->err);
661 jmap_debug_add_access(map, *index, val, "jmap_lastval");
664 static inline unsigned long *jmap_prevval_(const struct jmap *map,
665 unsigned long *index)
668 val = (unsigned long *)JudyLPrev(map->judy, index,
669 (JError_t *)&map->err);
670 jmap_debug_add_access(map, *index, val, "jmap_prevval");
673 #endif /* CCAN_JMAP_H */