]> git.ozlabs.org Git - ccan/blob - ccan/tcon/tcon.h
base64: fix for unsigned chars (e.g. ARM).
[ccan] / ccan / tcon / tcon.h
1 /* CC0 (Public domain) - see LICENSE file for details */
2 #ifndef CCAN_TCON_H
3 #define CCAN_TCON_H
4 #include "config.h"
5
6 #include <stddef.h>
7
8 /**
9  * TCON - declare a _tcon type containing canary variables.
10  * @decls: the semi-colon separated list of type canaries.
11  *
12  * This declares a _tcon member for a structure.  It should be the
13  * last element in your structure; with sufficient compiler support it
14  * will not use any actual storage.  tcon_check() will compare
15  * expressions with one of these "type canaries" to cause warnings if
16  * the container is misused.
17  *
18  * A type of "void *" will allow tcon_check() to pass on any (pointer) type.
19  *
20  * Example:
21  *      // Simply typesafe linked list.
22  *      struct list_head {
23  *              struct list_head *prev, *next;
24  *      };
25  *
26  *      struct string_list {
27  *              struct list_head raw;
28  *              TCON(char *canary);
29  *      };
30  *
31  *      // More complex: mapping from one type to another.
32  *      struct map {
33  *              void *contents;
34  *      };
35  *
36  *      struct int_to_string_map {
37  *              struct map raw;
38  *              TCON(char *charp_canary; int int_canary);
39  *      };
40  */
41 #if HAVE_FLEXIBLE_ARRAY_MEMBER
42 #define TCON(decls) struct { decls; } _tcon[]
43 #else
44 #define TCON(decls) struct { decls; } _tcon[1]
45 #endif
46
47 /**
48  * TCON_WRAP - declare a wrapper type containing a base type and type canaries
49  * @basetype: the base type to wrap
50  * @decls: the semi-colon separated list of type canaries.
51  *
52  * This expands to a new type which includes the given base type, and
53  * also type canaries, similar to those created with TCON.
54  *
55  * The embedded base type value can be accessed using tcon_unwrap().
56  *
57  * Differences from using TCON()
58  * - The wrapper type will take either the size of the base type, or
59  *   the size of a single pointer, whichever is greater (regardless of
60  *   compiler)
61  * - A TCON_WRAP type may be included in another structure, and need
62  *   not be the last element.
63  *
64  * A type of "void *" will allow tcon_check() to pass on any (pointer) type.
65  *
66  * Example:
67  *      // Simply typesafe linked list.
68  *      struct list_head {
69  *              struct list_head *prev, *next;
70  *      };
71  *
72  *      typedef TCON_WRAP(struct list_head, char *canary) string_list_t;
73  *
74  *      // More complex: mapping from one type to another.
75  *      struct map {
76  *              void *contents;
77  *      };
78  *
79  *      typedef TCON_WRAP(struct map, char *charp_canary; int int_canary)
80  *              int_to_string_map_t;
81  */
82 #define TCON_WRAP(basetype, decls) \
83         union {                    \
84                 basetype _base;    \
85                 struct {           \
86                         decls;     \
87                 } *_tcon;          \
88         }
89
90 /**
91  * TCON_WRAP_INIT - an initializer for a variable declared with TCON_WRAP
92  * @...: Initializer for the base type (treated as variadic so commas
93  *       can be included)
94  *
95  * Converts converts an initializer suitable for a base type into one
96  * suitable for that type wrapped with TCON_WRAP.
97  *
98  * Example:
99  *      TCON_WRAP(int, char *canary) canaried_int = TCON_WRAP_INIT(17);
100  */
101 #define TCON_WRAP_INIT(...)                     \
102         { ._base = __VA_ARGS__, }
103
104 /**
105  * tcon_unwrap - Access the base type of a TCON_WRAP
106  * @ptr: pointer to an object declared with TCON_WRAP
107  *
108  * tcon_unwrap() returns a pointer to the base type of the TCON_WRAP()
109  * object pointer to by @ptr.
110  *
111  * Example:
112  *      TCON_WRAP(int, char *canary) canaried_int;
113  *
114  *      *tcon_unwrap(&canaried_int) = 17;
115  */
116 #define tcon_unwrap(ptr) (&((ptr)->_base))
117
118 /**
119  * tcon_check - typecheck a typed container
120  * @x: the structure containing the TCON.
121  * @canary: which canary to check against.
122  * @expr: the expression whose type must match the TCON (not evaluated)
123  *
124  * This macro is used to check that the expression is the type
125  * expected for this structure (note the "useless" sizeof() argument
126  * which contains this comparison with the type canary).
127  *
128  * It evaluates to @x so you can chain it.
129  *
130  * Example:
131  *      #define tlist_add(h, n, member) \
132  *              list_add(&tcon_check((h), canary, (n))->raw, &(n)->member)
133  */
134 #define tcon_check(x, canary, expr)                             \
135         (sizeof((x)->_tcon[0].canary == (expr)) ? (x) : (x))
136
137 /**
138  * tcon_check_ptr - typecheck a typed container
139  * @x: the structure containing the TCON.
140  * @canary: which canary to check against.
141  * @expr: the expression whose type must match &TCON (not evaluated)
142  *
143  * This macro is used to check that the expression is a pointer to the type
144  * expected for this structure (note the "useless" sizeof() argument
145  * which contains this comparison with the type canary), or NULL.
146  *
147  * It evaluates to @x so you can chain it.
148  */
149 #define tcon_check_ptr(x, canary, expr)                         \
150         (sizeof(&(x)->_tcon[0].canary == (expr)) ? (x) : (x))
151
152
153 /**
154  * tcon_type - the type within a container (or void *)
155  * @x: the structure containing the TCON.
156  * @canary: which canary to check against.
157  */
158 #if HAVE_TYPEOF
159 #define tcon_type(x, canary) __typeof__((x)->_tcon[0].canary)
160 #else
161 #define tcon_type(x, canary) void *
162 #endif
163
164 /**
165  * tcon_sizeof - the size of type within a container
166  * @x: the structure containing the TCON.
167  * @canary: which canary to check against.
168  */
169 #define tcon_sizeof(x, canary) sizeof((x)->_tcon[0].canary)
170
171 /**
172  * TCON_VALUE - encode an integer value in a type canary
173  * @canary: name of the value canary
174  * @val: positive integer compile time constant value
175  *
176  * This macro can be included inside the declarations in a TCON() or
177  * TCON_WRAP(), constructing a special "type" canary which encodes the
178  * integer value @val (which must be a compile time constant, and a
179  * positive integer in the range of size_t).
180  */
181 #define TCON_VALUE(canary, val) char _value_##canary[val]
182
183 /**
184  * tcon_value - retrieve the value of a TCON_VALUE canary
185  * @x: the structure containing the TCON
186  * @canary: name of the value canary
187  *
188  * This macros expands to the value previously encoded into a TCON
189  * using TCON_VALUE().
190  */
191 #define tcon_value(x, canary)   tcon_sizeof(x, _value_##canary)
192
193 /**
194  * tcon_ptr_type - pointer to the type within a container (or void *)
195  * @x: the structure containing the TCON.
196  * @canary: which canary to check against.
197  */
198 #if HAVE_TYPEOF
199 #define tcon_ptr_type(x, canary) __typeof__(&(x)->_tcon[0].canary)
200 #else
201 #define tcon_ptr_type(x, canary) void *
202 #endif
203
204 /**
205  * tcon_cast - cast to a canary type for this container (or void *)
206  * @x: a structure containing the TCON.
207  * @canary: which canary to cast to.
208  * @expr: the value to cast
209  *
210  * This is used to cast to the correct type for this container.  If the
211  * platform doesn't HAVE_TYPEOF, then it casts to void * (which will
212  * cause a warning if the user doesn't expect a pointer type).
213  */
214 #define tcon_cast(x, canary, expr) ((tcon_type((x), canary))(expr))
215 #define tcon_cast_ptr(x, canary, expr) ((tcon_ptr_type((x), canary))(expr))
216
217 /**
218  * TCON_CONTAINER - encode information on a specific member of a
219  *                  containing structure into a "type" canary
220  * @canary: name of the container canary
221  * @container: type of the container structure
222  * @member: name of the member
223  *
224  * Used in the declarations in TCON() or TCON_WRAP(), encode a
225  * "container canary".  This encodes the type of @container, the type
226  * of @member within it (with sufficient compiler support) and the
227  * offset of @member within @container.
228  */
229 #if HAVE_TYPEOF
230 #define TCON_CONTAINER(canary, container, member)                       \
231         container _container_##canary;                                  \
232         typeof(((container *)0)->member) _member_##canary;              \
233         TCON_VALUE(_offset_##canary, offsetof(container, member))
234 #else
235 #define TCON_CONTAINER(canary, container, member)                       \
236         container _container_##canary;                                  \
237         TCON_VALUE(_offset_##canary, offsetof(container, member))
238 #endif
239
240 /**
241  * tcon_container_check
242  * tcon_container_check_ptr
243  * tcon_container_type
244  * tcon_container_ptr_type
245  * tcon_container_sizeof
246  * tcon_container_cast
247  * tcon_container_cast_ptr
248  * @x: the structure containing the TCON.
249  * @canary: which container canary to check against.
250  *
251  * As tcon_check / tcon_check_ptr / tcon_type / tcon_ptr_type /
252  * tcon_sizeof / tcon_cast / tcon_cast_ptr, but use the type of the
253  * "container" type declared with TCON_CONTAINER, instead of a simple
254  * canary.
255  */
256 #define tcon_container_check(x, canary, expr)           \
257         tcon_check(x, _container_##canary, expr)
258 #define tcon_container_check_ptr(x, canary, expr)       \
259         tcon_check_ptr(x, _container_##canary, expr)
260 #define tcon_container_type(x, canary)          \
261         tcon_type(x, _container_##canary)
262 #define tcon_container_ptr_type(x, canary)      \
263         tcon_ptr_type(x, _container_##canary)
264 #define tcon_container_sizeof(x, canary)        \
265         tcon_sizeof(x, _container_##canary)
266 #define tcon_container_cast(x, canary, expr)    \
267         tcon_cast(x, _container_##canary, expr)
268 #define tcon_container_cast_ptr(x, canary, expr)        \
269         tcon_cast_ptr(x, _container_##canary, expr)
270
271 /**
272  * tcon_member_check
273  * tcon_member_check_ptr
274  * tcon_member_type
275  * tcon_member_ptr_type
276  * tcon_member_sizeof
277  * tcon_member_cast
278  * tcon_member_cast_ptr
279  * @x: the structure containing the TCON.
280  * @canary: which container canary to check against.
281  *
282  * As tcon_check / tcon_check_ptr / tcon_type / tcon_ptr_type /
283  * tcon_sizeof / tcon_cast / tcon_cast_ptr, but use the type of the
284  * "member" type declared with TCON_CONTAINER, instead of a simple
285  * canary.
286  */
287 #define tcon_member_check(x, canary, expr)      \
288         tcon_check(x, _member_##canary, expr)
289 #define tcon_member_check_ptr(x, canary, expr)          \
290         tcon_check_ptr(x, _member_##canary, expr)
291 #define tcon_member_type(x, canary)             \
292         tcon_type(x, _member_##canary)
293 #define tcon_member_ptr_type(x, canary) \
294         tcon_ptr_type(x, _member_##canary)
295 #define tcon_member_sizeof(x, canary)   \
296         tcon_sizeof(x, _member_##canary)
297 #define tcon_member_cast(x, canary, expr)       \
298         tcon_cast(x, _member_##canary, expr)
299 #define tcon_member_cast_ptr(x, canary, expr)   \
300         tcon_cast_ptr(x, _member_##canary, expr)
301
302 /**
303  * tcon_offset - the offset of a member within a container, as
304  *               declared with TCON_CONTAINER
305  * @x: the structure containing the TCON.
306  * @canary: which container canary to check against.
307  */
308 #define tcon_offset(x, canary)                  \
309         tcon_value((x), _offset_##canary)
310
311 /**
312  * tcon_container_of - get pointer to enclosing structure based on a
313  *                     container canary
314  * @x: the structure containing the TCON
315  * @canary: the name of the container canary
316  * @member_ptr: pointer to a member of the container
317  *
318  * @member_ptr must be a pointer to the member of a container
319  * structure previously recorded in @canary with TCON_CONTAINER.
320  *
321  * tcon_container_of() evaluates to a pointer to the container
322  * structure.  With sufficient compiler support, the pointer will be
323  * correctly typed, and the type of @member_ptr will be verified.
324  * Note that const is discarded; a const @member_ptr still yields a
325  * non-const container (unless @canary is const).
326  *
327  * Returns NULL if @member_ptr is NULL.
328  */
329 #define tcon_container_of(x, canary, member_ptr)                        \
330         tcon_container_cast_ptr(                                        \
331                 tcon_member_check_ptr((x), canary, (member_ptr)),       \
332                 canary, tcon_container_of_((member_ptr),                \
333                                            tcon_offset((x), canary)))
334
335 static inline void *tcon_container_of_(const void *member_ptr, size_t offset)
336 {
337         return member_ptr ? (char *)member_ptr - offset : NULL;
338 }
339
340
341 /**
342  * tcon_member_of - get pointer to enclosed member structure based on a
343  *                  container canary
344  * @x: the structure containing the TCON
345  * @canary: the name of the container canary
346  * @container_ptr: pointer to a container
347  *
348  * @container_ptr must be a pointer to a container structure
349  * previously recorded in @canary with TCON_CONTAINER.
350  *
351  * tcon_member_of() evaluates to a pointer to the member of the
352  * container recorded in @canary. With sufficient compiler support,
353  * the pointer will be correctly typed, and the type of @container_ptr
354  * will be verified.
355  *
356  * Returns NULL if @container_ptr is NULL.
357  */
358 #define tcon_member_of(x, canary, container_ptr)                        \
359         tcon_member_cast_ptr(                                           \
360                 tcon_container_check_ptr((x), canary, (container_ptr)), \
361                 canary, tcon_member_of_((container_ptr),                \
362                                         tcon_offset((x), canary)))
363 static inline void *tcon_member_of_(void *container_ptr, size_t offset)
364 {
365         return container_ptr ? (char *)container_ptr + offset : NULL;
366 }
367
368
369 #endif /* CCAN_TCON_H */