From 361f3ea9ee577c5a3e2fed687a0b417b257c31de Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 22 Feb 2012 14:59:32 +1030 Subject: lib/ccan: import failtest and required ccan modules for TDB2 unit tests. New modules: failtest, list, time, read_write_all and tlist. Signed-off-by: Rusty Russell --- lib/ccan/tcon/_info | 74 ++++++++++++++++++ lib/ccan/tcon/tcon.h | 115 ++++++++++++++++++++++++++++ lib/ccan/tcon/test/compile_fail-tcon_cast.c | 29 +++++++ lib/ccan/tcon/test/compile_fail.c | 25 ++++++ lib/ccan/tcon/test/compile_ok-void.c | 21 +++++ lib/ccan/tcon/test/compile_ok.c | 27 +++++++ 6 files changed, 291 insertions(+) create mode 100644 lib/ccan/tcon/_info create mode 100644 lib/ccan/tcon/tcon.h create mode 100644 lib/ccan/tcon/test/compile_fail-tcon_cast.c create mode 100644 lib/ccan/tcon/test/compile_fail.c create mode 100644 lib/ccan/tcon/test/compile_ok-void.c create mode 100644 lib/ccan/tcon/test/compile_ok.c (limited to 'lib/ccan/tcon') diff --git a/lib/ccan/tcon/_info b/lib/ccan/tcon/_info new file mode 100644 index 0000000000..02c0dd8add --- /dev/null +++ b/lib/ccan/tcon/_info @@ -0,0 +1,74 @@ +#include "config.h" +#include + +/** + * tcon - routines for creating typesafe generic containers + * + * This code lets users create a structure with a typecanary; your API + * is then a set of macros which check the type canary before calling + * the generic routines. + * + * Example: + * #include + * #include + * + * // A simple container class. Can only contain one thing though! + * struct container { + * void *contents; + * }; + * static inline void container_add_raw(struct container *c, void *p) + * { + * c->contents = p; + * } + * static inline void *container_get_raw(struct container *c) + * { + * return c->contents; + * } + * + * // This lets the user define their container type; includes a + * // "type canary" to check types against. + * #define DEFINE_TYPED_CONTAINER_STRUCT(name, type) \ + * struct name { struct container raw; TCON(type canary); } + * + * // These macros make sure the container type and pointer match. + * #define container_add(c, p) \ + * container_add_raw(&tcon_check((c), canary, (p))->raw, (p)) + * #define container_get(c) \ + * tcon_cast((c), canary, container_get_raw(&(c)->raw)) + * + * // Now, let's define two different containers. + * DEFINE_TYPED_CONTAINER_STRUCT(int_container, int *); + * DEFINE_TYPED_CONTAINER_STRUCT(string_container, char *); + * + * int main(int argc, char *argv[]) + * { + * struct int_container ic; + * struct string_container sc; + * + * // We would get a warning if we used the wrong types... + * container_add(&ic, &argc); + * container_add(&sc, argv[argc-1]); + * + * printf("Last arg is %s of %i arguments\n", + * container_get(&sc), *container_get(&ic) - 1); + * return 0; + * } + * // Given "foo" outputs "Last arg is foo of 1 arguments" + * // Given "foo bar" outputs "Last arg is bar of 2 arguments" + * + * License: Public domain + * + * Author: Rusty Russell + */ +int main(int argc, char *argv[]) +{ + /* Expect exactly one argument */ + if (argc != 2) + return 1; + + if (strcmp(argv[1], "depends") == 0) { + return 0; + } + + return 1; +} diff --git a/lib/ccan/tcon/tcon.h b/lib/ccan/tcon/tcon.h new file mode 100644 index 0000000000..93c3ea6b9f --- /dev/null +++ b/lib/ccan/tcon/tcon.h @@ -0,0 +1,115 @@ +/* Placed into the public domain */ +#ifndef CCAN_TCON_H +#define CCAN_TCON_H +#include "config.h" + +/** + * TCON - declare a _tcon type containing canary variables. + * @decls: the semi-colon separated list of type canaries. + * + * This declares a _tcon member for a structure. It should be the + * last element in your structure; with sufficient compiler support it + * will not use any actual storage. tcon_check() will compare + * expressions with one of these "type canaries" to cause warnings if + * the container is misused. + * + * A type of "void *" will allow tcon_check() to pass on any (pointer) type. + * + * Example: + * // Simply typesafe linked list. + * struct list_head { + * struct list_head *prev, *next; + * }; + * + * struct string_list { + * struct list_head raw; + * TCON(char *canary); + * }; + * + * // More complex: mapping from one type to another. + * struct map { + * void *contents; + * }; + * + * struct int_to_string_map { + * struct map raw; + * TCON(char *charp_canary; int int_canary); + * }; + */ +#if HAVE_FLEXIBLE_ARRAY_MEMBER +#define TCON(decls) struct { decls; } _tcon[] +#else +#define TCON(decls) struct { decls; } _tcon[1] +#endif + +/** + * tcon_check - typecheck a typed container + * @x: the structure containing the TCON. + * @canary: which canary to check against. + * @expr: the expression whose type must match the TCON (not evaluated) + * + * This macro is used to check that the expression is the type + * expected for this structure (note the "useless" sizeof() argument + * which contains this comparison with the type canary). + * + * It evaluates to @x so you can chain it. + * + * Example: + * #define tlist_add(h, n, member) \ + * list_add(&tcon_check((h), canary, (n))->raw, &(n)->member) + */ +#define tcon_check(x, canary, expr) \ + (sizeof((x)->_tcon[0].canary == (expr)) ? (x) : (x)) + +/** + * tcon_check_ptr - typecheck a typed container + * @x: the structure containing the TCON. + * @canary: which canary to check against. + * @expr: the expression whose type must match &TCON (not evaluated) + * + * This macro is used to check that the expression is a pointer to the type + * expected for this structure (note the "useless" sizeof() argument + * which contains this comparison with the type canary), or NULL. + * + * It evaluates to @x so you can chain it. + */ +#define tcon_check_ptr(x, canary, expr) \ + (sizeof(&(x)->_tcon[0].canary == (expr)) ? (x) : (x)) + + +/** + * tcon_type - the type within a container (or void *) + * @x: the structure containing the TCON. + * @canary: which canary to check against. + */ +#if HAVE_TYPEOF +#define tcon_type(x, canary) __typeof__((x)->_tcon[0].canary) +#else +#define tcon_type(x, canary) void * +#endif + +/** + * tcon_ptr_type - pointer to the type within a container (or void *) + * @x: the structure containing the TCON. + * @canary: which canary to check against. + */ +#if HAVE_TYPEOF +#define tcon_ptr_type(x, canary) __typeof__(&(x)->_tcon[0].canary) +#else +#define tcon_ptr_type(x, canary) void * +#endif + +/** + * tcon_cast - cast to a canary type for this container (or void *) + * @x: a structure containing the TCON. + * @canary: which canary to cast to. + * @expr: the value to cast + * + * This is used to cast to the correct type for this container. If the + * platform doesn't HAVE_TYPEOF, then it casts to void * (which will + * cause a warning if the user doesn't expect a pointer type). + */ +#define tcon_cast(x, canary, expr) ((tcon_type((x), canary))(expr)) +#define tcon_cast_ptr(x, canary, expr) ((tcon_ptr_type((x), canary))(expr)) + +#endif /* CCAN_TCON_H */ diff --git a/lib/ccan/tcon/test/compile_fail-tcon_cast.c b/lib/ccan/tcon/test/compile_fail-tcon_cast.c new file mode 100644 index 0000000000..f80ef42c09 --- /dev/null +++ b/lib/ccan/tcon/test/compile_fail-tcon_cast.c @@ -0,0 +1,29 @@ +#include +#include + +struct container { + void *p; +}; + +struct int_and_charp_container { + struct container raw; + TCON(int *tc1; char *tc2); +}; + +int main(int argc, char *argv[]) +{ + struct int_and_charp_container icon; +#ifdef FAIL +#if !HAVE_TYPEOF +#error We cannot detect type problems without HAVE_TYPEOF +#endif + char * +#else + int * +#endif + x; + + icon.raw.p = NULL; + x = tcon_cast(&icon, tc1, icon.raw.p); + return 0; +} diff --git a/lib/ccan/tcon/test/compile_fail.c b/lib/ccan/tcon/test/compile_fail.c new file mode 100644 index 0000000000..683bbd62ff --- /dev/null +++ b/lib/ccan/tcon/test/compile_fail.c @@ -0,0 +1,25 @@ +#include +#include + +struct container { + void *p; +}; + +struct int_container { + struct container raw; + TCON(int *canary); +}; + +int main(int argc, char *argv[]) +{ + struct int_container icon; +#ifdef FAIL + char * +#else + int * +#endif + x = NULL; + + tcon_check(&icon, canary, x)->raw.p = x; + return 0; +} diff --git a/lib/ccan/tcon/test/compile_ok-void.c b/lib/ccan/tcon/test/compile_ok-void.c new file mode 100644 index 0000000000..26b712f6b2 --- /dev/null +++ b/lib/ccan/tcon/test/compile_ok-void.c @@ -0,0 +1,21 @@ +#include +#include + +struct container { + void *p; +}; + +struct void_container { + struct container raw; + TCON(void *canary); +}; + +int main(int argc, char *argv[]) +{ + struct void_container vcon; + + tcon_check(&vcon, canary, NULL)->raw.p = NULL; + tcon_check(&vcon, canary, argv[0])->raw.p = NULL; + tcon_check(&vcon, canary, main)->raw.p = NULL; + return 0; +} diff --git a/lib/ccan/tcon/test/compile_ok.c b/lib/ccan/tcon/test/compile_ok.c new file mode 100644 index 0000000000..447f0ee50a --- /dev/null +++ b/lib/ccan/tcon/test/compile_ok.c @@ -0,0 +1,27 @@ +#include +#include + +struct container { + void *p; +}; + +struct int_container { + struct container raw; + TCON(int tc); +}; + +struct charp_and_int_container { + struct container raw; + TCON(int tc1; char *tc2); +}; + +int main(int argc, char *argv[]) +{ + struct int_container icon; + struct charp_and_int_container cicon; + + tcon_check(&icon, tc, 7)->raw.p = NULL; + tcon_check(&cicon, tc1, 7)->raw.p = argv[0]; + tcon_check(&cicon, tc2, argv[0])->raw.p = argv[0]; + return 0; +} -- cgit