]> 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((expr) ? (expr) : &(x)->_tcon[0].canary) ? (x) : (x))
151
152 /**
153  * tcon_type - the type within a container (or void *)
154  * @x: the structure containing the TCON.
155  * @canary: which canary to check against.
156  */
157 #if HAVE_TYPEOF
158 #define tcon_type(x, canary) __typeof__((x)->_tcon[0].canary)
159 #else
160 #define tcon_type(x, canary) void *
161 #endif
162
163 /**
164  * tcon_sizeof - the size of type within a container
165  * @x: the structure containing the TCON.
166  * @canary: which canary to check against.
167  */
168 #define tcon_sizeof(x, canary) sizeof((x)->_tcon[0].canary)
169
170 /**
171  * TCON_VALUE - encode an integer value in a type canary
172  * @canary: name of the value canary
173  * @val: positive integer compile time constant value
174  *
175  * This macro can be included inside the declarations in a TCON() or
176  * TCON_WRAP(), constructing a special "type" canary which encodes the
177  * integer value @val (which must be a compile time constant, and a
178  * positive integer in the range of size_t).
179  */
180 #define TCON_VALUE(canary, val) char _value_##canary[val]
181
182 /**
183  * tcon_value - retrieve the value of a TCON_VALUE canary
184  * @x: the structure containing the TCON
185  * @canary: name of the value canary
186  *
187  * This macros expands to the value previously encoded into a TCON
188  * using TCON_VALUE().
189  */
190 #define tcon_value(x, canary)   tcon_sizeof(x, _value_##canary)
191
192 /**
193  * tcon_ptr_type - pointer to the type within a container (or void *)
194  * @x: the structure containing the TCON.
195  * @canary: which canary to check against.
196  */
197 #if HAVE_TYPEOF
198 #define tcon_ptr_type(x, canary) __typeof__(&(x)->_tcon[0].canary)
199 #else
200 #define tcon_ptr_type(x, canary) void *
201 #endif
202
203 /**
204  * tcon_cast - cast to a canary type for this container (or void *)
205  * @x: a structure containing the TCON.
206  * @canary: which canary to cast to.
207  * @expr: the value to cast
208  *
209  * This is used to cast to the correct type for this container.  If the
210  * platform doesn't HAVE_TYPEOF, then it casts to void * (which will
211  * cause a warning if the user doesn't expect a pointer type).
212  */
213 #define tcon_cast(x, canary, expr) ((tcon_type((x), canary))(expr))
214 #define tcon_cast_ptr(x, canary, expr) ((tcon_ptr_type((x), canary))(expr))
215
216 /**
217  * TCON_CONTAINER - encode information on a specific member of a
218  *                  containing structure into a "type" canary
219  * @canary: name of the container canary
220  * @container: type of the container structure
221  * @member: name of the member
222  *
223  * Used in the declarations in TCON() or TCON_WRAP(), encode a
224  * "container canary".  This encodes the type of @container, the type
225  * of @member within it (with sufficient compiler support) and the
226  * offset of @member within @container.
227  */
228 #if HAVE_TYPEOF
229 #define TCON_CONTAINER(canary, container, member)                       \
230         container _container_##canary;                                  \
231         typeof(((container *)0)->member) _member_##canary;              \
232         TCON_VALUE(_offset_##canary, offsetof(container, member))
233 #else
234 #define TCON_CONTAINER(canary, container, member)                       \
235         container _container_##canary;                                  \
236         TCON_VALUE(_offset_##canary, offsetof(container, member))
237 #endif
238
239 /**
240  * tcon_container_check
241  * tcon_container_check_ptr
242  * tcon_container_type
243  * tcon_container_ptr_type
244  * tcon_container_sizeof
245  * tcon_container_cast
246  * tcon_container_cast_ptr
247  * @x: the structure containing the TCON.
248  * @canary: which container canary to check against.
249  *
250  * As tcon_check / tcon_check_ptr / tcon_type / tcon_ptr_type /
251  * tcon_sizeof / tcon_cast / tcon_cast_ptr, but use the type of the
252  * "container" type declared with TCON_CONTAINER, instead of a simple
253  * canary.
254  */
255 #define tcon_container_check(x, canary, expr)           \
256         tcon_check(x, _container_##canary, expr)
257 #define tcon_container_check_ptr(x, canary, expr)       \
258         tcon_check_ptr(x, _container_##canary, expr)
259 #define tcon_container_type(x, canary)          \
260         tcon_type(x, _container_##canary)
261 #define tcon_container_ptr_type(x, canary)      \
262         tcon_ptr_type(x, _container_##canary)
263 #define tcon_container_sizeof(x, canary)        \
264         tcon_sizeof(x, _container_##canary)
265 #define tcon_container_cast(x, canary, expr)    \
266         tcon_cast(x, _container_##canary, expr)
267 #define tcon_container_cast_ptr(x, canary, expr)        \
268         tcon_cast_ptr(x, _container_##canary, expr)
269
270 /**
271  * tcon_member_check
272  * tcon_member_check_ptr
273  * tcon_member_type
274  * tcon_member_ptr_type
275  * tcon_member_sizeof
276  * tcon_member_cast
277  * tcon_member_cast_ptr
278  * @x: the structure containing the TCON.
279  * @canary: which container canary to check against.
280  *
281  * As tcon_check / tcon_check_ptr / tcon_type / tcon_ptr_type /
282  * tcon_sizeof / tcon_cast / tcon_cast_ptr, but use the type of the
283  * "member" type declared with TCON_CONTAINER, instead of a simple
284  * canary.
285  */
286 #define tcon_member_check(x, canary, expr)      \
287         tcon_check(x, _member_##canary, expr)
288 #define tcon_member_check_ptr(x, canary, expr)          \
289         tcon_check_ptr(x, _member_##canary, expr)
290 #define tcon_member_type(x, canary)             \
291         tcon_type(x, _member_##canary)
292 #define tcon_member_ptr_type(x, canary) \
293         tcon_ptr_type(x, _member_##canary)
294 #define tcon_member_sizeof(x, canary)   \
295         tcon_sizeof(x, _member_##canary)
296 #define tcon_member_cast(x, canary, expr)       \
297         tcon_cast(x, _member_##canary, expr)
298 #define tcon_member_cast_ptr(x, canary, expr)   \
299         tcon_cast_ptr(x, _member_##canary, expr)
300
301 /**
302  * tcon_offset - the offset of a member within a container, as
303  *               declared with TCON_CONTAINER
304  * @x: the structure containing the TCON.
305  * @canary: which container canary to check against.
306  */
307 #define tcon_offset(x, canary)                  \
308         tcon_value((x), _offset_##canary)
309
310 /**
311  * tcon_container_of - get pointer to enclosing structure based on a
312  *                     container canary
313  * @x: the structure containing the TCON
314  * @canary: the name of the container canary
315  * @member_ptr: pointer to a member of the container
316  *
317  * @member_ptr must be a pointer to the member of a container
318  * structure previously recorded in @canary with TCON_CONTAINER.
319  *
320  * tcon_container_of() evaluates to a pointer to the container
321  * structure.  With sufficient compiler support, the pointer will be
322  * correctly typed, and the type of @member_ptr will be verified.
323  * Note that const is discarded; a const @member_ptr still yields a
324  * non-const container (unless @canary is const).
325  *
326  * Returns NULL if @member_ptr is NULL.
327  */
328 #define tcon_container_of(x, canary, member_ptr)                        \
329         tcon_container_cast_ptr(                                        \
330                 tcon_member_check_ptr((x), canary, (member_ptr)),       \
331                 canary, tcon_container_of_((member_ptr),                \
332                                            tcon_offset((x), canary)))
333
334 static inline void *tcon_container_of_(const void *member_ptr, size_t offset)
335 {
336         return member_ptr ? (char *)member_ptr - offset : NULL;
337 }
338
339
340 /**
341  * tcon_member_of - get pointer to enclosed member structure based on a
342  *                  container canary
343  * @x: the structure containing the TCON
344  * @canary: the name of the container canary
345  * @container_ptr: pointer to a container
346  *
347  * @container_ptr must be a pointer to a container structure
348  * previously recorded in @canary with TCON_CONTAINER.
349  *
350  * tcon_member_of() evaluates to a pointer to the member of the
351  * container recorded in @canary. With sufficient compiler support,
352  * the pointer will be correctly typed, and the type of @container_ptr
353  * will be verified.
354  *
355  * Returns NULL if @container_ptr is NULL.
356  */
357 #define tcon_member_of(x, canary, container_ptr)                        \
358         tcon_member_cast_ptr(                                           \
359                 tcon_container_check_ptr((x), canary, (container_ptr)), \
360                 canary, tcon_member_of_((container_ptr),                \
361                                         tcon_offset((x), canary)))
362 static inline void *tcon_member_of_(void *container_ptr, size_t offset)
363 {
364         return container_ptr ? (char *)container_ptr + offset : NULL;
365 }
366
367
368 #endif /* CCAN_TCON_H */