]> git.ozlabs.org Git - ccan/blob - ccan/jmap/jmap.h
base64: fix for unsigned chars (e.g. ARM).
[ccan] / ccan / jmap / jmap.h
1 /* Licensed under LGPLv2.1+ - see LICENSE file for details */
2 #ifndef CCAN_JMAP_H
3 #define CCAN_JMAP_H
4 #include <ccan/compiler/compiler.h>
5 #include <ccan/tcon/tcon.h>
6 #include <stddef.h>
7 #include <Judy.h>
8 #include <stdbool.h>
9 #include <string.h>
10 #include <assert.h>
11 #ifdef CCAN_JMAP_DEBUG
12 #include <stdio.h>
13 #endif
14
15 /**
16  * struct map - private definition of a jmap.
17  *
18  * It's exposed here so you can put it in your structures and so we can
19  * supply inline functions.
20  */
21 struct jmap {
22         Pvoid_t judy;
23         JError_t err;
24         const char *errstr;
25         /* Used if !NDEBUG */
26         int num_accesses;
27         /* Used if CCAN_JMAP_DEBUG */
28         unsigned long *acc_value;
29         unsigned long acc_index;
30         const char *funcname;
31 };
32
33 /**
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.
37  *
38  * Example:
39  *      struct jmap_long_to_charp {
40  *              JMAP_MEMBERS(long, char *);
41  *      };
42  */
43 #define JMAP_MEMBERS(itype, ctype)              \
44         TCON_WRAP(struct jmap, itype icanary; ctype ccanary) jmap_
45
46 /**
47  * jmap_new - create a new, empty jmap.
48  *
49  * See Also:
50  *      JMAP_MEMBERS()
51  *
52  * Example:
53  *      struct jmap_long_to_charp {
54  *              JMAP_MEMBERS(long, char *);
55  *      };
56  *
57  *      struct jmap_long_to_charp *map = jmap_new(struct jmap_long_to_charp);
58  *      if (!map)
59  *              errx(1, "Failed to allocate jmap");
60  */
61 #define jmap_new(type) ((type *)jmap_new_(sizeof(type)))
62
63 /**
64  * jmap_raw_ - unwrap the typed map (no type checking)
65  * @map: the typed jmap
66  */
67 #define jmap_raw_(map)  tcon_unwrap(&(map)->jmap_)
68
69 /**
70  * jmap_free - destroy a jmap.
71  * @map: the map returned from jmap_new.
72  *
73  * Example:
74  *      jmap_free(map);
75  */
76 #define jmap_free(map) jmap_free_(jmap_raw_(map))
77
78 /**
79  * jmap_error - test for an error in the a previous jmap_ operation.
80  * @map: the map to test.
81  *
82  * Under normal circumstances, return NULL to indicate no error has occurred.
83  * Otherwise, it will return a string containing the error.  This string
84  * can only be freed by jmap_free() on the map.
85  *
86  * Other than out-of-memory, errors are caused by memory corruption or
87  * interface misuse.
88  *
89  * Example:
90  *      const char *errstr;
91  *
92  *      errstr = jmap_error(map);
93  *      if (errstr)
94  *              errx(1, "Woah, error on newly created map?! %s", errstr);
95  */
96 #define jmap_error(map) jmap_error_(jmap_raw_(map))
97
98 /**
99  * jmap_rawi - unwrap the typed map and check the index type
100  * @map: the typed jmap
101  * @expr: the expression to check the index type against (not evaluated)
102  *
103  * This macro usually causes the compiler to emit a warning if the
104  * variable is of an unexpected type.  It is used internally where we
105  * need to access the raw underlying jmap.
106  */
107 #define jmap_rawi(map, expr) \
108         tcon_unwrap(tcon_check(&(map)->jmap_, icanary, (expr)))
109
110 /**
111  * jmap_rawc - unwrap the typed map and check the contents type
112  * @map: the typed jmap
113  * @expr: the expression to check the content type against (not evaluated)
114  *
115  * This macro usually causes the compiler to emit a warning if the
116  * variable is of an unexpected type.  It is used internally where we
117  * need to access the raw underlying jmap.
118  */
119 #define jmap_rawc(map, expr) \
120         tcon_unwrap(tcon_check(&(map)->jmap_, ccanary, (expr)))
121
122 /**
123  * jmap_rawci - unwrap the typed map and check the index and contents types
124  * @map: the typed jmap
125  * @iexpr: the expression to check the index type against (not evaluated)
126  * @cexpr: the expression to check the contents type against (not evaluated)
127  *
128  * This macro usually causes the compiler to emit a warning if the
129  * variable is of an unexpected type.  It is used internally where we
130  * need to access the raw underlying jmap.
131  */
132 #define jmap_rawci(map, iexpr, cexpr)                           \
133         tcon_unwrap(tcon_check(tcon_check(&(map)->jmap_,\
134                                           ccanary, (cexpr)), icanary, (iexpr)))
135
136 /**
137  * jmap_add - add or replace a value for a given index in the map.
138  * @map: map from jmap_new
139  * @index: the index to map
140  * @value: the value to associate with the index
141  *
142  * Adds index into the map; replaces value if it's already there.
143  * Returns false on error (out of memory).
144  *
145  * Example:
146  *      if (!jmap_add(map, 0, "hello"))
147  *              err(1, "jmap_add failed!");
148  */
149 #define jmap_add(map, index, value)                             \
150         jmap_add_(jmap_rawci((map), (index), (value)),          \
151                   (unsigned long)(index), (unsigned long)value)
152
153 /**
154  * jmap_set - change a value for an existing index in the map.
155  * @map: map from jmap_new
156  * @index: the index to map
157  * @value: the value to associate with the index
158  *
159  * This sets the value of an index if it already exists, and return true,
160  * otherwise returns false and does nothing.
161  *
162  * Example:
163  *      if (!jmap_set(map, 0, "goodbye"))
164  *              err(1, "jmap_set: index 0 not found");
165  */
166 #define jmap_set(map, index, value)                             \
167         jmap_set_(jmap_rawci((map), (index), (value)),          \
168                   (unsigned long)(index), (unsigned long)value)
169
170 /**
171  * jmap_del - remove an index from the map.
172  * @map: map from jmap_new
173  * @index: the index to map
174  *
175  * Example:
176  *      if (!jmap_del(map, 0))
177  *              err(1, "jmap_del failed!");
178  */
179 #define jmap_del(map, index)                                            \
180         jmap_del_(jmap_rawi((map), (index)), (unsigned long)(index))
181
182 /**
183  * jmap_test - test if a given index is defined.
184  * @map: map from jmap_new
185  * @index: the index to find
186  *
187  * Example:
188  *      jmap_add(map, 1, "hello");
189  *      assert(jmap_test(map, 1));
190  */
191 #define jmap_test(map, index)                           \
192         jmap_test_(jmap_rawi((map), (index)), (unsigned long)(index))
193
194 /**
195  * jmap_get - get a value for a given index.
196  * @map: map from jmap_new
197  * @index: the index to find
198  *
199  * Returns 0 if !jmap_test(map, index).
200  *
201  * Example:
202  *      const char *str = "hello";
203  *      jmap_add(map, 2, str);
204  *      assert(jmap_get(map, 0) == str);
205  *
206  * See Also:
207  *      jmap_getval()
208  */
209 #define jmap_get(map, index)                                            \
210         tcon_cast(&(map)->jmap_, ccanary,                               \
211                   jmap_get_(jmap_rawi((map), (index)), (unsigned long)(index)))
212
213 /**
214  * jmap_count - get population of the map.
215  * @map: map from jmap_new
216  *
217  * Example:
218  *      assert(jmap_count(map) < 1000);
219  */
220 #define jmap_count(map)                         \
221         jmap_popcount_(jmap_raw_(map), 0, -1UL)
222
223 /**
224  * jmap_popcount - get population of (some part of) the map.
225  * @map: map from jmap_new
226  * @start: first index to count
227  * @end_incl: last index to count (use -1 for end).
228  *
229  * Example:
230  *      assert(jmap_popcount(map, 0, 1000) <= jmap_popcount(map, 0, 2000));
231  */
232 #define jmap_popcount(map, start, end_incl)                             \
233         jmap_popcount_(jmap_rawi((map), (start) ? (start) : (end_incl)), \
234                        (unsigned long)(start), (unsigned long)(end_incl))
235
236 /**
237  * jmap_nth - return the index of the nth value in the map.
238  * @map: map from jmap_new
239  * @n: which index we are interested in (0-based)
240  * @invalid: what to return if n >= map population
241  *
242  * This normally returns the nth index in the map, and often there is a
243  * convenient known-invalid value (ie. something which is never in the
244  * map).  Otherwise you can use jmap_nthval().
245  *
246  * Example:
247  *      unsigned long i, index;
248  *
249  *      // We know 0 isn't in map.
250  *      assert(!jmap_test(map, 0));
251  *      for (i = 0; (index = jmap_nth(map, i, 0)) != 0; i++) {
252  *              assert(jmap_popcount(map, 0, index) == i);
253  *              printf("Index %lu = %lu\n", i, index);
254  *      }
255  *
256  * See Also:
257  *      jmap_nthval();
258  */
259 #define jmap_nth(map, n, invalid)                                       \
260         tcon_cast(&(map)->jmap_, icanary,                               \
261                   jmap_nth_(jmap_rawi((map), (invalid)),                \
262                             (n), (unsigned long)(invalid)))
263
264 /**
265  * jmap_first - return the first index in the map (must not contain 0).
266  * @map: map from jmap_new
267  *
268  * This is equivalent to jmap_nth(map, 0, 0).
269  *
270  * Example:
271  *      assert(!jmap_test(map, 0));
272  *      printf("Map indices (increasing order):");
273  *      for (i = jmap_first(map); i; i = jmap_next(map, i))
274  *              printf(" %lu", i);
275  *      printf("\n");
276  *
277  * See Also:
278  *      jmap_firstval()
279  */
280 #define jmap_first(map)                                         \
281         tcon_cast(&(map)->jmap_, icanary, jmap_first_(jmap_raw_(map)))
282
283 /**
284  * jmap_next - return the next index in the map.
285  * @map: map from jmap_new
286  * @prev: previous index
287  *
288  * This is usually used to find an adjacent index after jmap_first.
289  * See Also:
290  *      jmap_nextval()
291  */
292 #define jmap_next(map, prev)                                            \
293         tcon_cast(&(map)->jmap_, icanary, jmap_next_(jmap_rawi((map), (prev)),  \
294                                                      (unsigned long)(prev)))
295
296 /**
297  * jmap_last - return the last index in the map.
298  * @map: map from jmap_new
299  *
300  * Returns 0 if map is empty.
301  *
302  * Example:
303  *      assert(!jmap_test(map, 0));
304  *      printf("Map indices (increasing order):");
305  *      for (i = jmap_last(map); i; i = jmap_prev(map, i))
306  *              printf(" %lu", i);
307  *      printf("\n");
308  * See Also:
309  *      jmap_lastval()
310  */
311 #define jmap_last(map)                                          \
312         tcon_cast(&(map)->jmap_, icanary, jmap_last_(jmap_raw_(map)))
313
314 /**
315  * jmap_prev - return the previous index in the map (must not contain 0)
316  * @map: map from jmap_new
317  * @prev: previous index
318  *
319  * This is usually used to find an prior adjacent index after jmap_last.
320  * Returns 0 if no previous indices in map.
321  *
322  * See Also:
323  *      jmap_prevval()
324  */
325 #define jmap_prev(map, prev)                                            \
326         tcon_cast(&(map)->jmap_, icanary,                               \
327                   jmap_prev_(jmap_rawi((map), (prev)), (prev)))
328
329 /**
330  * jmap_getval - access a value in-place for a given index.
331  * @map: map from jmap_new
332  * @index: the index to find
333  *
334  * Returns a pointer into the map, or NULL if the index isn't in the
335  * map.  Like the other val functions (jmap_nthval, jmap_firstval
336  * etc), this pointer cannot be used after a jmap_add or jmap_del
337  * call, and you must call jmap_putval() once you are finished.
338  *
339  * Unless you define NDEBUG, jmap_add and kmap_del will check that you
340  * have called jmap_putval().
341  *
342  * Example:
343  *      char **p;
344  *      jmap_add(map, 0, "hello");
345  *      p = jmap_getval(map, 0);
346  *      if (!p)
347  *              errx(1, "Could not find 0 in map!");
348  *      if (strcmp(*p, "hello") != 0)
349  *              errx(1, "Value in map was not correct?!");
350  *      *p = (char *)"goodbye";
351  *      jmap_putval(map, &p);
352  *      // Accessing p now would probably crash.
353  *
354  * See Also:
355  *      jmap_putval(), jmap_firstval()
356  */
357 #define jmap_getval(map, index)                                         \
358         tcon_cast_ptr(&(map)->jmap_, ccanary,                           \
359                       jmap_getval_(jmap_rawi((map), (index)),           \
360                                    (unsigned long)(index)))
361
362 /**
363  * jmap_putval - revoke access to a value.
364  * @map: map from jmap_new
365  * @p: the pointer to a pointer to the value
366  *
367  * @p is a pointer to the (successful) value retuned from one of the
368  * jmap_*val functions (listed below).  After this, it will be invalid.
369  *
370  * Unless NDEBUG is defined, this will actually alter the value of p
371  * to point to garbage to help avoid accidental use.
372  *
373  * See Also:
374  *      jmap_getval(), jmap_nthval(), jmap_firstval(), jmap_nextval(),
375  *              jmap_lastval(), jmap_prevval().
376  */
377 #define jmap_putval(map, p)                                             \
378         jmap_putval_(jmap_rawc((map), **(p)), (p))
379
380 /**
381  * jmap_nthval - access the value of the nth value in the map.
382  * @map: map from jmap_new
383  * @n: which index we are interested in (0-based)
384  * @index: set to the nth index in the map.
385  *
386  * This returns a pointer to the value at the nth index in the map,
387  * or NULL if there are n is greater than the population of the map.
388  * You must use jmap_putval() on the pointer once you are done with it.
389  *
390  * Example:
391  *      char **val;
392  *
393  *      // We know 0 isn't in map.
394  *      assert(!jmap_test(map, 0));
395  *      for (i = 0; (val = jmap_nthval(map, i, &index)) != NULL; i++) {
396  *              assert(jmap_popcount(map, 0, index) == i);
397  *              printf("Index %lu = %lu, value = %s\n", i, index, *val);
398  *              jmap_putval(map, &val);
399  *      }
400  *
401  * See Also:
402  *      jmap_nth();
403  */
404 #define jmap_nthval(map, n, index)                                      \
405         tcon_cast_ptr(&(map)->jmap_, ccanary,                           \
406                       jmap_nthval_(jmap_rawi((map), *(index)), (n), (index)))
407
408 /**
409  * jmap_firstval - access the first value in the map.
410  * @map: map from jmap_new
411  * @index: set to the first index in the map.
412  *
413  * Returns NULL if the map is empty; otherwise this returns a pointer to
414  * the first value, which you must call jmap_putval() on!
415  *
416  * Example:
417  *      // Add one to every value (ie. make it point into second char of string)
418  *      for (val = jmap_firstval(map, &i); val; val = jmap_nextval(map, &i)) {
419  *              (*val)++;
420  *              jmap_putval(map, &val);
421  *      }
422  *      printf("\n");
423  *
424  * See Also:
425  *      jmap_first, jmap_nextval()
426  */
427 #define jmap_firstval(map, index)                                       \
428         tcon_cast_ptr(&(map)->jmap_, ccanary,                           \
429                       jmap_firstval_(jmap_rawi((map), *(index)),        \
430                                      (unsigned long *)(index)))
431
432 /**
433  * jmap_nextval - access the next value in the map.
434  * @map: map from jmap_new
435  * @index: previous index, updated with the new index.
436  *
437  * This returns a pointer to a value (which you must call jmap_putval on)
438  * or NULL.  This usually used to find an adjacent value after jmap_firstval.
439  *
440  * See Also:
441  *      jmap_firstval(), jmap_putval()
442  */
443 #define jmap_nextval(map, index)                                \
444         tcon_cast_ptr(&(map)->jmap_, ccanary,                   \
445                       jmap_nextval_(jmap_rawi((map), *(index)), \
446                                     (unsigned long *)(index)))
447
448
449 /**
450  * jmap_lastval - access the last value in the map.
451  * @map: map from jmap_new
452  * @index: set to the last index in the map.
453  *
454  * See Also:
455  *      jmap_last(), jmap_putval()
456  */
457 #define jmap_lastval(map, index)                                \
458         tcon_cast_ptr(&(map)->jmap_, ccanary,                   \
459                       jmap_lastval_(jmap_rawi((map), *(index)), \
460                                     (unsigned long *)(index)))
461
462
463 /**
464  * jmap_prevval - access the previous value in the map.
465  * @map: map from jmap_new
466  * @index: previous index, updated with the new index.
467  *
468  * This returns a pointer to a value (which you must call jmap_putval on)
469  * or NULL.  This usually used to find an adjacent value after jmap_lastval.
470  *
471  * See Also:
472  *      jmap_lastval(), jmap_putval()
473  */
474 #define jmap_prevval(map, index)                                \
475         tcon_cast_ptr(&(map)->jmap_, ccanary,                   \
476                       jmap_prevval_(jmap_rawi((map), *(index)), \
477                                     (unsigned long *)(index)))
478
479
480
481 /* Debugging checks. */
482 static inline void jmap_debug_add_access(const struct jmap *map,
483                                          unsigned long index,
484                                          unsigned long *val,
485                                          const char *funcname)
486 {
487 #ifdef CCAN_JMAP_DEBUG
488         if (!map->acc_value) {
489                 ((struct jmap *)map)->acc_value = val;
490                 ((struct jmap *)map)->acc_index = index;
491                 ((struct jmap *)map)->funcname = funcname;
492         }
493 #endif
494         if (val)
495                 assert(++((struct jmap *)map)->num_accesses);
496 }
497
498 static inline void jmap_debug_del_access(struct jmap *map, unsigned long **val)
499 {
500         assert(--map->num_accesses >= 0);
501 #ifdef CCAN_JMAP_DEBUG
502         if (map->acc_value == *val)
503                 map->acc_value = NULL;
504 #endif
505         /* Set it to some invalid value.  Not NULL, they might rely on that! */
506         assert(memset(val, 0x42, sizeof(void *)));
507 }
508
509 static inline void jmap_debug_access(struct jmap *map)
510 {
511 #ifdef CCAN_JMAP_DEBUG
512         if (map->num_accesses && map->acc_value)
513                 fprintf(stderr,
514                         "jmap: still got index %lu, val %lu (%p) from %s\n",
515                         map->acc_index, *map->acc_value, map->acc_value,
516                         map->funcname);
517 #endif
518         assert(!map->num_accesses);
519 }
520
521 /* Private functions */
522 struct jmap *jmap_new_(size_t size);
523 void jmap_free_(const struct jmap *map);
524 const char *COLD jmap_error_str_(struct jmap *map);
525 static inline const char *jmap_error_(struct jmap *map)
526 {
527         if (JU_ERRNO(&map->err) <= JU_ERRNO_NFMAX)
528                 return NULL;
529         return jmap_error_str_(map);
530 }
531 static inline bool jmap_add_(struct jmap *map,
532                              unsigned long index, unsigned long value)
533 {
534         unsigned long *val;
535         jmap_debug_access(map);
536         val = (unsigned long *)JudyLIns(&map->judy, index, &map->err);
537         if (val == PJERR)
538                 return false;
539         *val = value;
540         return true;
541 }
542 static inline bool jmap_set_(const struct jmap *map,
543                              unsigned long index, unsigned long value)
544 {
545         unsigned long *val;
546         val = (unsigned long *)JudyLGet(map->judy, index,
547                                         (JError_t *)&map->err);
548         if (val && val != PJERR) {
549                 *val = value;
550                 return true;
551         }
552         return false;
553 }
554 static inline bool jmap_del_(struct jmap *map, unsigned long index)
555 {
556         jmap_debug_access(map);
557         return JudyLDel(&map->judy, index, &map->err) == 1;
558 }
559 static inline bool jmap_test_(const struct jmap *map, unsigned long index)
560 {
561         return JudyLGet(map->judy, index, (JError_t *)&map->err) != NULL;
562 }
563 static inline unsigned long jmap_get_(const struct jmap *map,
564                                       unsigned long index)
565 {
566         unsigned long *val;
567         val = (unsigned long *)JudyLGet(map->judy, index,
568                                         (JError_t *)&map->err);
569         if (!val || val == PJERR)
570                 return 0;
571         return *val;
572 }
573 static inline unsigned long jmap_popcount_(const struct jmap *map,
574                                            unsigned long start,
575                                            unsigned long end_incl)
576 {
577         return JudyLCount(map->judy, start, end_incl, (JError_t *)&map->err);
578 }
579 static inline unsigned long jmap_nth_(const struct jmap *map,
580                                       unsigned long n, unsigned long invalid)
581 {
582         unsigned long index;
583         if (!JudyLByCount(map->judy, n+1, &index, (JError_t *)&map->err))
584                 index = invalid;
585         return index;
586 }
587 static inline unsigned long jmap_first_(const struct jmap *map)
588 {
589         unsigned long index = 0;
590         if (!JudyLFirst(map->judy, &index, (JError_t *)&map->err))
591                 index = 0;
592         else
593                 assert(index != 0);
594         return index;
595 }
596 static inline unsigned long jmap_next_(const struct jmap *map,
597                                        unsigned long prev)
598 {
599         if (!JudyLNext(map->judy, &prev, (JError_t *)&map->err))
600                 prev = 0;
601         else
602                 assert(prev != 0);
603         return prev;
604 }
605 static inline unsigned long jmap_last_(const struct jmap *map)
606 {
607         unsigned long index = -1;
608         if (!JudyLLast(map->judy, &index, (JError_t *)&map->err))
609                 index = 0;
610         else
611                 assert(index != 0);
612         return index;
613 }
614 static inline unsigned long jmap_prev_(const struct jmap *map,
615                                        unsigned long prev)
616 {
617         if (!JudyLPrev(map->judy, &prev, (JError_t *)&map->err))
618                 prev = 0;
619         else
620                 assert(prev != 0);
621         return prev;
622 }
623 static inline void *jmap_getval_(struct jmap *map, unsigned long index)
624 {
625         unsigned long *val;
626         val = (unsigned long *)JudyLGet(map->judy, index,
627                                         (JError_t *)&map->err);
628         jmap_debug_add_access(map, index, val, "jmap_getval");
629         return val;
630 }
631 static inline void jmap_putval_(struct jmap *map, void *p)
632 {
633         jmap_debug_del_access(map, p);
634 }
635 static inline unsigned long *jmap_nthval_(const struct jmap *map, unsigned long n,
636                                           unsigned long *index)
637 {
638         unsigned long *val;
639         val = (unsigned long *)JudyLByCount(map->judy, n+1, index,
640                                      (JError_t *)&map->err);
641         jmap_debug_add_access(map, *index, val, "jmap_nthval");
642         return val;
643 }
644 static inline unsigned long *jmap_firstval_(const struct jmap *map,
645                                             unsigned long *index)
646 {
647         unsigned long *val;
648         *index = 0;
649         val = (unsigned long *)JudyLFirst(map->judy, index,
650                                           (JError_t *)&map->err);
651         jmap_debug_add_access(map, *index, val, "jmap_firstval");
652         return val;
653 }
654 static inline unsigned long *jmap_nextval_(const struct jmap *map,
655                                            unsigned long *index)
656 {
657         unsigned long *val;
658         val = (unsigned long *)JudyLNext(map->judy, index,
659                                          (JError_t *)&map->err);
660         jmap_debug_add_access(map, *index, val, "jmap_nextval");
661         return val;
662 }
663 static inline unsigned long *jmap_lastval_(const struct jmap *map,
664                                            unsigned long *index)
665 {
666         unsigned long *val;
667         *index = -1;
668         val = (unsigned long *)JudyLLast(map->judy, index,
669                                          (JError_t *)&map->err);
670         jmap_debug_add_access(map, *index, val, "jmap_lastval");
671         return val;
672 }
673 static inline unsigned long *jmap_prevval_(const struct jmap *map,
674                                            unsigned long *index)
675 {
676         unsigned long *val;
677         val = (unsigned long *)JudyLPrev(map->judy, index,
678                                          (JError_t *)&map->err);
679         jmap_debug_add_access(map, *index, val, "jmap_prevval");
680         return val;
681 }
682 #endif /* CCAN_JMAP_H */