]> git.ozlabs.org Git - ccan/blob - ccan/tcon/tcon.h
tcon: Encode integer values into "type" canaries
[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 /**
7  * TCON - declare a _tcon type containing canary variables.
8  * @decls: the semi-colon separated list of type canaries.
9  *
10  * This declares a _tcon member for a structure.  It should be the
11  * last element in your structure; with sufficient compiler support it
12  * will not use any actual storage.  tcon_check() will compare
13  * expressions with one of these "type canaries" to cause warnings if
14  * the container is misused.
15  *
16  * A type of "void *" will allow tcon_check() to pass on any (pointer) type.
17  *
18  * Example:
19  *      // Simply typesafe linked list.
20  *      struct list_head {
21  *              struct list_head *prev, *next;
22  *      };
23  *
24  *      struct string_list {
25  *              struct list_head raw;
26  *              TCON(char *canary);
27  *      };
28  *
29  *      // More complex: mapping from one type to another.
30  *      struct map {
31  *              void *contents;
32  *      };
33  *
34  *      struct int_to_string_map {
35  *              struct map raw;
36  *              TCON(char *charp_canary; int int_canary);
37  *      };
38  */
39 #if HAVE_FLEXIBLE_ARRAY_MEMBER
40 #define TCON(decls) struct { decls; } _tcon[]
41 #else
42 #define TCON(decls) struct { decls; } _tcon[1]
43 #endif
44
45 /**
46  * TCON_WRAP - declare a wrapper type containing a base type and type canaries
47  * @basetype: the base type to wrap
48  * @decls: the semi-colon separated list of type canaries.
49  *
50  * This expands to a new type which includes the given base type, and
51  * also type canaries, similar to those created with TCON.
52  *
53  * The embedded base type value can be accessed using tcon_unwrap().
54  *
55  * Differences from using TCON()
56  * - The wrapper type will take either the size of the base type, or
57  *   the size of a single pointer, whichever is greater (regardless of
58  *   compiler)
59  * - A TCON_WRAP type may be included in another structure, and need
60  *   not be the last element.
61  *
62  * A type of "void *" will allow tcon_check() to pass on any (pointer) type.
63  *
64  * Example:
65  *      // Simply typesafe linked list.
66  *      struct list_head {
67  *              struct list_head *prev, *next;
68  *      };
69  *
70  *      typedef TCON_WRAP(struct list_head, char *canary) string_list_t;
71  *
72  *      // More complex: mapping from one type to another.
73  *      struct map {
74  *              void *contents;
75  *      };
76  *
77  *      typedef TCON_WRAP(struct map, char *charp_canary; int int_canary)
78  *              int_to_string_map_t;
79  */
80 #define TCON_WRAP(basetype, decls) \
81         union {                    \
82                 basetype _base;    \
83                 struct {           \
84                         decls;     \
85                 } *_tcon;          \
86         }
87
88 /**
89  * TCON_WRAP_INIT - an initializer for a variable declared with TCON_WRAP
90  * @...: Initializer for the base type (treated as variadic so commas
91  *       can be included)
92  *
93  * Converts converts an initializer suitable for a base type into one
94  * suitable for that type wrapped with TCON_WRAP.
95  *
96  * Example:
97  *      TCON_WRAP(int, char *canary) canaried_int = TCON_WRAP_INIT(17);
98  */
99 #define TCON_WRAP_INIT(...)                     \
100         { ._base = __VA_ARGS__, }
101
102 /**
103  * tcon_unwrap - Access the base type of a TCON_WRAP
104  * @ptr: pointer to an object declared with TCON_WRAP
105  *
106  * tcon_unwrap() returns a pointer to the base type of the TCON_WRAP()
107  * object pointer to by @ptr.
108  *
109  * Example:
110  *      TCON_WRAP(int, char *canary) canaried_int;
111  *
112  *      *tcon_unwrap(&canaried_int) = 17;
113  */
114 #define tcon_unwrap(ptr) (&((ptr)->_base))
115
116 /**
117  * tcon_check - typecheck a typed container
118  * @x: the structure containing the TCON.
119  * @canary: which canary to check against.
120  * @expr: the expression whose type must match the TCON (not evaluated)
121  *
122  * This macro is used to check that the expression is the type
123  * expected for this structure (note the "useless" sizeof() argument
124  * which contains this comparison with the type canary).
125  *
126  * It evaluates to @x so you can chain it.
127  *
128  * Example:
129  *      #define tlist_add(h, n, member) \
130  *              list_add(&tcon_check((h), canary, (n))->raw, &(n)->member)
131  */
132 #define tcon_check(x, canary, expr)                             \
133         (sizeof((x)->_tcon[0].canary == (expr)) ? (x) : (x))
134
135 /**
136  * tcon_check_ptr - typecheck a typed container
137  * @x: the structure containing the TCON.
138  * @canary: which canary to check against.
139  * @expr: the expression whose type must match &TCON (not evaluated)
140  *
141  * This macro is used to check that the expression is a pointer to the type
142  * expected for this structure (note the "useless" sizeof() argument
143  * which contains this comparison with the type canary), or NULL.
144  *
145  * It evaluates to @x so you can chain it.
146  */
147 #define tcon_check_ptr(x, canary, expr)                         \
148         (sizeof(&(x)->_tcon[0].canary == (expr)) ? (x) : (x))
149
150
151 /**
152  * tcon_type - the type within a container (or void *)
153  * @x: the structure containing the TCON.
154  * @canary: which canary to check against.
155  */
156 #if HAVE_TYPEOF
157 #define tcon_type(x, canary) __typeof__((x)->_tcon[0].canary)
158 #else
159 #define tcon_type(x, canary) void *
160 #endif
161
162 /**
163  * tcon_sizeof - the size of type within a container
164  * @x: the structure containing the TCON.
165  * @canary: which canary to check against.
166  */
167 #define tcon_sizeof(x, canary) sizeof((x)->_tcon[0].canary)
168
169 /**
170  * TCON_VALUE - encode an integer value in a type canary
171  * @canary: name of the value canary
172  * @val: positive integer compile time constant value
173  *
174  * This macro can be included inside the declarations in a TCON() or
175  * TCON_WRAP(), constructing a special "type" canary which encodes the
176  * integer value @val (which must be a compile time constant, and a
177  * positive integer in the range of size_t).
178  */
179 #define TCON_VALUE(canary, val) char _value_##canary[val]
180
181 /**
182  * tcon_value - retrieve the value of a TCON_VALUE canary
183  * @x: the structure containing the TCON
184  * @canary: name of the value canary
185  *
186  * This macros expands to the value previously encoded into a TCON
187  * using TCON_VALUE().
188  */
189 #define tcon_value(x, canary)   tcon_sizeof(x, _value_##canary)
190
191 /**
192  * tcon_ptr_type - pointer to the type within a container (or void *)
193  * @x: the structure containing the TCON.
194  * @canary: which canary to check against.
195  */
196 #if HAVE_TYPEOF
197 #define tcon_ptr_type(x, canary) __typeof__(&(x)->_tcon[0].canary)
198 #else
199 #define tcon_ptr_type(x, canary) void *
200 #endif
201
202 /**
203  * tcon_cast - cast to a canary type for this container (or void *)
204  * @x: a structure containing the TCON.
205  * @canary: which canary to cast to.
206  * @expr: the value to cast
207  *
208  * This is used to cast to the correct type for this container.  If the
209  * platform doesn't HAVE_TYPEOF, then it casts to void * (which will
210  * cause a warning if the user doesn't expect a pointer type).
211  */
212 #define tcon_cast(x, canary, expr) ((tcon_type((x), canary))(expr))
213 #define tcon_cast_ptr(x, canary, expr) ((tcon_ptr_type((x), canary))(expr))
214
215 #endif /* CCAN_TCON_H */