]> git.ozlabs.org Git - ccan/blob - ccan/strmap/strmap.h
strmap: add strmap_getn for non-terminated string search.
[ccan] / ccan / strmap / strmap.h
1 #ifndef CCAN_STRMAP_H
2 #define CCAN_STRMAP_H
3 #include "config.h"
4 #include <ccan/tcon/tcon.h>
5 #include <ccan/typesafe_cb/typesafe_cb.h>
6 #include <stdlib.h>
7 #include <stdbool.h>
8
9 /**
10  * struct strmap - representation of a string map
11  *
12  * It's exposed here to allow you to embed it and so we can inline the
13  * trivial functions.
14  */
15 struct strmap {
16         union {
17                 struct node *n;
18                 const char *s;
19         } u;
20         void *v;
21 };
22
23 /**
24  * STRMAP - declare a type-specific strmap
25  * @type: type for this map's values, or void * for any pointer.
26  *
27  * You use this to create your own typed strmap for a particular type.
28  * You can use an integer type, *but* remember you can't use "0" as a
29  * value!
30  *
31  * Example:
32  *      STRMAP(int *) int_strmap;
33  *      strmap_init(&int_strmap);
34  */
35 #define STRMAP(type)                            \
36         TCON_WRAP(struct strmap, type canary)
37
38 /**
39  * strmap_init - initialize a string map (empty)
40  * @map: the typed strmap to initialize.
41  *
42  * For completeness; if you've arranged for it to be NULL already you don't
43  * need this.
44  *
45  * Example:
46  *      STRMAP(int *) map;
47  *
48  *      strmap_init(&map);
49  */
50 #define strmap_init(map) strmap_init_(tcon_unwrap(map))
51
52 static inline void strmap_init_(struct strmap *map)
53 {
54         map->u.n = NULL;
55 }
56
57 /**
58  * strmap_empty - is this string map empty?
59  * @map: the typed strmap to check.
60  *
61  * Example:
62  *      if (!strmap_empty(&map))
63  *              abort();
64  */
65 #define strmap_empty(map) strmap_empty_(tcon_unwrap(map))
66
67 static inline bool strmap_empty_(const struct strmap *map)
68 {
69         return map->u.n == NULL;
70 }
71
72 /**
73  * strmap_get - get a value from a string map
74  * @map: the typed strmap to search.
75  * @member: the string to search for (nul terminated)
76  *
77  * Returns the value, or NULL if it isn't in the map (and sets errno = ENOENT).
78  *
79  * Example:
80  *      int *val = strmap_get(&map, "hello");
81  *      if (val)
82  *              printf("hello => %i\n", *val);
83  */
84 #define strmap_get(map, member) \
85         tcon_cast((map), canary, strmap_get_(tcon_unwrap(map), (member)))
86 void *strmap_get_(const struct strmap *map, const char *member);
87
88 /**
89  * strmap_getn - get a value from a string map
90  * @map: the typed strmap to search.
91  * @member: the string to search for.
92  * @memberlen: the length of @member.
93  *
94  * Returns the value, or NULL if it isn't in the map (and sets errno = ENOENT).
95  *
96  * Example:
97  *      val = strmap_getn(&map, "hello", 5);
98  *      if (val)
99  *              printf("hello => %i\n", *val);
100  */
101 #define strmap_getn(map, member, n)                                     \
102         tcon_cast((map), canary, strmap_getn_(tcon_unwrap(map), (member), (n)))
103 void *strmap_getn_(const struct strmap *map, const char *member, size_t n);
104
105 /**
106  * strmap_add - place a member in the string map.
107  * @map: the typed strmap to add to.
108  * @member: the string to place in the map.
109  * @v: the (non-NULL) value.
110  *
111  * This returns false if we run out of memory (errno = ENOMEM), or
112  * (more normally) if that string already appears in the map (EEXIST).
113  *
114  * Note that the pointer is placed in the map, the string is not copied.  If
115  * you want a copy in the map, use strdup().  Similarly for the value.
116  *
117  * Example:
118  *      val = malloc(sizeof *val);
119  *      *val = 17;
120  *      if (!strmap_add(&map, "goodbye", val))
121  *              printf("goodbye was already in the map\n");
122  */
123 #define strmap_add(map, member, value)                                  \
124         strmap_add_(tcon_unwrap(tcon_check((map), canary, (value))),    \
125                     (member), (void *)(value))
126
127 bool strmap_add_(struct strmap *map, const char *member, const void *value);
128
129 /**
130  * strmap_del - remove a member from the string map.
131  * @map: the typed strmap to delete from.
132  * @member: the string to remove from the map.
133  * @valuep: the value (if non-NULL)
134  *
135  * This returns the string which was passed to strmap_map(), or NULL if
136  * it was not in the map (and sets errno = ENOENT).
137  *
138  * This means that if you allocated a string (eg. using strdup()), you
139  * can free it here.  Similarly, the value is returned in @valuep if
140  * @valuep is not NULL.
141  *
142  * Example:
143  *      if (!strmap_del(&map, "goodbye", NULL))
144  *              printf("goodbye was not in the map?\n");
145  */
146 #define strmap_del(map, member, valuep)                                 \
147         strmap_del_(tcon_unwrap(tcon_check_ptr((map), canary, valuep)), \
148                     (member), (void **)valuep)
149 char *strmap_del_(struct strmap *map, const char *member, void **valuep);
150
151 /**
152  * strmap_clear - remove every member from the map.
153  * @map: the typed strmap to clear.
154  *
155  * The map will be empty after this.
156  *
157  * Example:
158  *      strmap_clear(&map);
159  */
160 #define strmap_clear(map) strmap_clear_(tcon_unwrap(map))
161
162 void strmap_clear_(struct strmap *map);
163
164 /**
165  * strmap_iterate - ordered iteration over a map
166  * @map: the typed strmap to iterate through.
167  * @handle: the function to call.
168  * @arg: the argument for the function (types should match).
169  *
170  * @handle's prototype should be:
171  *      bool @handle(const char *member, type value, typeof(arg) arg)
172  *
173  * If @handle returns false, the iteration will stop.
174  * You should not alter the map within the @handle function!
175  *
176  * Example:
177  *      typedef STRMAP(int *) strmap_intp;
178  *      static bool dump_some(const char *member, int *value, int *num)
179  *      {
180  *              // Only dump out num nodes.
181  *              if (*(num--) == 0)
182  *                      return false;
183  *              printf("%s=>%i\n", member, *value);
184  *              return true;
185  *      }
186  *
187  *      static void dump_map(const strmap_intp *map)
188  *      {
189  *              int max = 100;
190  *              strmap_iterate(map, dump_some, &max);
191  *              if (max < 0)
192  *                      printf("... (truncated to 100 entries)\n");
193  *      }
194  */
195 #define strmap_iterate(map, handle, arg)                                \
196         strmap_iterate_(tcon_unwrap(map),                               \
197                         typesafe_cb_cast(bool (*)(const char *,         \
198                                                   void *, void *),      \
199                                          bool (*)(const char *,         \
200                                                   tcon_type((map), canary), \
201                                                   __typeof__(arg)), (handle)), \
202                         (arg))
203 void strmap_iterate_(const struct strmap *map,
204                      bool (*handle)(const char *, void *, void *),
205                      const void *data);
206
207 /**
208  * strmap_prefix - return a submap matching a prefix
209  * @map: the map.
210  * @prefix: the prefix.
211  *
212  * This returns a pointer into @map, so don't alter @map while using
213  * the return value.  You can use strmap_iterate(), strmap_get() or
214  * strmap_empty() on the returned pointer.
215  *
216  * Example:
217  *      static void dump_prefix(const strmap_intp *map,
218  *                              const char *prefix)
219  *      {
220  *              int max = 100;
221  *              printf("Nodes with prefix %s:\n", prefix);
222  *              strmap_iterate(strmap_prefix(map, prefix), dump_some, &max);
223  *              if (max < 0)
224  *                      printf("... (truncated to 100 entries)\n");
225  *      }
226  */
227 #if HAVE_TYPEOF
228 #define strmap_prefix(map, prefix) \
229         ((const __typeof__(map))strmap_prefix_(tcon_unwrap(map), (prefix)))
230 #else
231 #define strmap_prefix(map, prefix) \
232         ((const void *)strmap_prefix_(tcon_unwrap(map), (prefix)))
233 #endif
234
235 const struct strmap *strmap_prefix_(const struct strmap *map,
236                                     const char *prefix);
237
238 #endif /* CCAN_STRMAP_H */