summaryrefslogtreecommitdiff
path: root/ccan/strmap/strmap.h
blob: 8fabc359acc64e2d4a4603e7097cfe93b3b2be17 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
#ifndef CCAN_STRMAP_H
#define CCAN_STRMAP_H
#include "config.h"
#include <ccan/tcon/tcon.h>
#include <ccan/typesafe_cb/typesafe_cb.h>
#include <stdlib.h>
#include <stdbool.h>

/**
 * struct strmap - representation of a string map
 *
 * It's exposed here to allow you to embed it and so we can inline the
 * trivial functions.
 */
struct strmap {
	union {
		struct node *n;
		const char *s;
	} u;
	void *v;
};

/**
 * STRMAP_MEMBERS - declare members for a type-specific strmap.
 * @type: type for this map's values, or void * for any pointer.
 *
 * You use this to create your own typed strmap for a particular type.
 * You can use an integer type, *but* remember you can't use "0" as a
 * value!
 *
 * Example:
 *	struct strmap_intp {
 *		STRMAP_MEMBERS(int *);
 *	};
 */
#define STRMAP_MEMBERS(type)			\
	struct strmap raw;			\
	TCON(type canary)


/**
 * strmap_init - initialize a string map (empty)
 * @map: the typed strmap to initialize.
 *
 * For completeness; if you've arranged for it to be NULL already you don't
 * need this.
 *
 * Example:
 *	struct strmap_intp map;
 *
 *	strmap_init(&map);
 */
#define strmap_init(map) strmap_init_(&(map)->raw)

static inline void strmap_init_(struct strmap *map)
{
	map->u.n = NULL;
}

/**
 * strmap_empty - is this string map empty?
 * @map: the typed strmap to check.
 *
 * Example:
 *	if (!strmap_empty(&map))
 *		abort();
 */
#define strmap_empty(map) strmap_empty_(&(map)->raw)

static inline bool strmap_empty_(const struct strmap *map)
{
	return map->u.n == NULL;
}

/**
 * strmap_get - get a value from a string map
 * @map: the typed strmap to search.
 * @member: the string to search for.
 *
 * Returns the value, or NULL if it isn't in the map (and sets errno = ENOENT).
 *
 * Example:
 *	int *val = strmap_get(&map, "hello");
 *	if (val)
 *		printf("hello => %i\n", *val);
 */
#define strmap_get(map, member) \
	tcon_cast((map), canary, strmap_get_(&(map)->raw, (member)))
void *strmap_get_(const struct strmap *map, const char *member);

/**
 * strmap_add - place a member in the string map.
 * @map: the typed strmap to add to.
 * @member: the string to place in the map.
 * @v: the (non-NULL) value.
 *
 * This returns false if we run out of memory (errno = ENOMEM), or
 * (more normally) if that string already appears in the map (EEXIST).
 *
 * Note that the pointer is placed in the map, the string is not copied.  If
 * you want a copy in the map, use strdup().  Similarly for the value.
 *
 * Example:
 *	val = malloc(sizeof *val);
 *	*val = 17;
 *	if (!strmap_add(&map, "goodbye", val))
 *		printf("goodbye was already in the map\n");
 */
#define strmap_add(map, member, value)				\
	strmap_add_(&tcon_check((map), canary, (value))->raw,	\
		    (member), (void *)(value))

bool strmap_add_(struct strmap *map, const char *member, const void *value);

/**
 * strmap_del - remove a member from the string map.
 * @map: the typed strmap to delete from.
 * @member: the string to remove from the map.
 * @valuep: the value (if non-NULL)
 *
 * This returns the string which was passed to strmap_map(), or NULL if
 * it was not in the map (and sets errno = ENOENT).
 *
 * This means that if you allocated a string (eg. using strdup()), you
 * can free it here.  Similarly, the value is returned in @valuep if
 * @valuep is not NULL.
 *
 * Example:
 *	if (!strmap_del(&map, "goodbye", NULL))
 *		printf("goodbye was not in the map?\n");
 */
#define strmap_del(map, member, valuep)					\
	strmap_del_(&tcon_check_ptr((map), canary, valuep)->raw,	\
		    (member), (void **)valuep)
char *strmap_del_(struct strmap *map, const char *member, void **valuep);

/**
 * strmap_clear - remove every member from the map.
 * @map: the typed strmap to clear.
 *
 * The map will be empty after this.
 *
 * Example:
 *	strmap_clear(&map);
 */
#define strmap_clear(map) strmap_clear_(&(map)->raw)

void strmap_clear_(struct strmap *map);

/**
 * strmap_iterate - ordered iteration over a map
 * @map: the typed strmap to iterate through.
 * @handle: the function to call.
 * @arg: the argument for the function (types should match).
 *
 * @handle's prototype should be:
 *	bool @handle(const char *member, type value, typeof(arg) arg)
 *
 * If @handle returns false, the iteration will stop.
 * You should not alter the map within the @handle function!
 *
 * Example:
 *	struct strmap_intp {
 *		STRMAP_MEMBERS(int *);
 *	};
 *	static bool dump_some(const char *member, int *value, int *num)
 *	{
 *		// Only dump out num nodes.
 *		if (*(num--) == 0)
 *			return false;
 *		printf("%s=>%i\n", member, *value);
 *		return true;
 *	}
 *
 *	static void dump_map(const struct strmap_intp *map)
 *	{
 *		int max = 100;
 *		strmap_iterate(map, dump_some, &max);
 *		if (max < 0)
 *			printf("... (truncated to 100 entries)\n");
 *	}
 */
#define strmap_iterate(map, handle, arg)				\
	strmap_iterate_(&(map)->raw,					\
			typesafe_cb_cast(bool (*)(const char *,		\
						  void *, void *),	\
					 bool (*)(const char *,		\
						  tcon_type((map), canary), \
						  __typeof__(arg)), (handle)), \
			(arg))
void strmap_iterate_(const struct strmap *map,
		     bool (*handle)(const char *, void *, void *),
		     const void *data);

/**
 * strmap_prefix - return a submap matching a prefix
 * @map: the map.
 * @prefix: the prefix.
 *
 * This returns a pointer into @map, so don't alter @map while using
 * the return value.  You can use strmap_iterate(), strmap_get() or
 * strmap_empty() on the returned pointer.
 *
 * Example:
 *	static void dump_prefix(const struct strmap_intp *map,
 *				const char *prefix)
 *	{
 *		int max = 100;
 *		printf("Nodes with prefix %s:\n", prefix);
 *		strmap_iterate(strmap_prefix(map, prefix), dump_some, &max);
 *		if (max < 0)
 *			printf("... (truncated to 100 entries)\n");
 *	}
 */
#if HAVE_TYPEOF
#define strmap_prefix(map, prefix) \
	((const __typeof__(map))strmap_prefix_(&(map)->raw, (prefix)))
#else
#define strmap_prefix(map, prefix) \
	((const void *)strmap_prefix_(&(map)->raw, (prefix)))
#endif

const struct strmap *strmap_prefix_(const struct strmap *map,
				    const char *prefix);

#endif /* CCAN_STRMAP_H */