diff options
Diffstat (limited to 'lib/ccan/container_of')
-rw-r--r-- | lib/ccan/container_of/_info | 63 | ||||
-rw-r--r-- | lib/ccan/container_of/container_of.h | 108 | ||||
-rw-r--r-- | lib/ccan/container_of/test/compile_fail-bad-type.c | 22 | ||||
-rw-r--r-- | lib/ccan/container_of/test/compile_fail-types.c | 22 | ||||
-rw-r--r-- | lib/ccan/container_of/test/compile_fail-var-types.c | 25 | ||||
-rw-r--r-- | lib/ccan/container_of/test/run.c | 26 |
6 files changed, 266 insertions, 0 deletions
diff --git a/lib/ccan/container_of/_info b/lib/ccan/container_of/_info new file mode 100644 index 0000000000..2f45ca7ccd --- /dev/null +++ b/lib/ccan/container_of/_info @@ -0,0 +1,63 @@ +#include <stdio.h> +#include <string.h> +#include "config.h" + +/** + * container_of - routine for upcasting + * + * It is often convenient to create code where the caller registers a pointer + * to a generic structure and a callback. The callback might know that the + * pointer points to within a larger structure, and container_of gives a + * convenient and fairly type-safe way of returning to the enclosing structure. + * + * This idiom is an alternative to providing a void * pointer for every + * callback. + * + * Example: + * #include <stdio.h> + * #include <ccan/container_of/container_of.h> + * + * struct timer { + * void *members; + * }; + * + * struct info { + * int my_stuff; + * struct timer timer; + * }; + * + * static void register_timer(struct timer *timer) + * { + * //... + * } + * + * static void my_timer_callback(struct timer *timer) + * { + * struct info *info = container_of(timer, struct info, timer); + * printf("my_stuff is %u\n", info->my_stuff); + * } + * + * int main(void) + * { + * struct info info = { .my_stuff = 1 }; + * + * register_timer(&info.timer); + * // ... + * return 0; + * } + * + * License: Public domain + * Author: Rusty Russell <rusty@rustcorp.com.au> + */ +int main(int argc, char *argv[]) +{ + if (argc != 2) + return 1; + + if (strcmp(argv[1], "depends") == 0) { + printf("ccan/check_type\n"); + return 0; + } + + return 1; +} diff --git a/lib/ccan/container_of/container_of.h b/lib/ccan/container_of/container_of.h new file mode 100644 index 0000000000..1c9d147ae0 --- /dev/null +++ b/lib/ccan/container_of/container_of.h @@ -0,0 +1,108 @@ +#ifndef CCAN_CONTAINER_OF_H +#define CCAN_CONTAINER_OF_H +#include <stddef.h> + +#include "config.h" +#include <ccan/check_type/check_type.h> + +/** + * container_of - get pointer to enclosing structure + * @member_ptr: pointer to the structure member + * @containing_type: the type this member is within + * @member: the name of this member within the structure. + * + * Given a pointer to a member of a structure, this macro does pointer + * subtraction to return the pointer to the enclosing type. + * + * Example: + * struct foo { + * int fielda, fieldb; + * // ... + * }; + * struct info { + * int some_other_field; + * struct foo my_foo; + * }; + * + * static struct info *foo_to_info(struct foo *foo) + * { + * return container_of(foo, struct info, my_foo); + * } + */ +#define container_of(member_ptr, containing_type, member) \ + ((containing_type *) \ + ((char *)(member_ptr) \ + - container_off(containing_type, member)) \ + + check_types_match(*(member_ptr), ((containing_type *)0)->member)) + +/** + * container_off - get offset to enclosing structure + * @containing_type: the type this member is within + * @member: the name of this member within the structure. + * + * Given a pointer to a member of a structure, this macro does + * typechecking and figures out the offset to the enclosing type. + * + * Example: + * struct foo { + * int fielda, fieldb; + * // ... + * }; + * struct info { + * int some_other_field; + * struct foo my_foo; + * }; + * + * static struct info *foo_to_info(struct foo *foo) + * { + * size_t off = container_off(struct info, my_foo); + * return (void *)((char *)foo - off); + * } + */ +#define container_off(containing_type, member) \ + offsetof(containing_type, member) + +/** + * container_of_var - get pointer to enclosing structure using a variable + * @member_ptr: pointer to the structure member + * @container_var: a pointer of same type as this member's container + * @member: the name of this member within the structure. + * + * Given a pointer to a member of a structure, this macro does pointer + * subtraction to return the pointer to the enclosing type. + * + * Example: + * static struct info *foo_to_i(struct foo *foo) + * { + * struct info *i = container_of_var(foo, i, my_foo); + * return i; + * } + */ +#if HAVE_TYPEOF +#define container_of_var(member_ptr, container_var, member) \ + container_of(member_ptr, typeof(*container_var), member) +#else +#define container_of_var(member_ptr, container_var, member) \ + ((void *)((char *)(member_ptr) - \ + container_off_var(container_var, member))) +#endif + +/** + * container_off_var - get offset of a field in enclosing structure + * @container_var: a pointer to a container structure + * @member: the name of a member within the structure. + * + * Given (any) pointer to a structure and a its member name, this + * macro does pointer subtraction to return offset of member in a + * structure memory layout. + * + */ +#if HAVE_TYPEOF +#define container_off_var(var, member) \ + container_off(typeof(*var), member) +#else +#define container_off_var(var, member) \ + ((char *)&(var)->member - (char *)(var)) +#endif + +#endif /* CCAN_CONTAINER_OF_H */ diff --git a/lib/ccan/container_of/test/compile_fail-bad-type.c b/lib/ccan/container_of/test/compile_fail-bad-type.c new file mode 100644 index 0000000000..b7a1459386 --- /dev/null +++ b/lib/ccan/container_of/test/compile_fail-bad-type.c @@ -0,0 +1,22 @@ +#include <ccan/container_of/container_of.h> +#include <stdlib.h> + +struct foo { + int a; + char b; +}; + +int main(int argc, char *argv[]) +{ + struct foo foo = { .a = 1, .b = 2 }; + int *intp = &foo.a; + char *p; + +#ifdef FAIL + /* p is a char *, but this gives a struct foo * */ + p = container_of(intp, struct foo, a); +#else + p = (char *)intp; +#endif + return p == NULL; +} diff --git a/lib/ccan/container_of/test/compile_fail-types.c b/lib/ccan/container_of/test/compile_fail-types.c new file mode 100644 index 0000000000..cae1c7abd2 --- /dev/null +++ b/lib/ccan/container_of/test/compile_fail-types.c @@ -0,0 +1,22 @@ +#include <ccan/container_of/container_of.h> +#include <stdlib.h> + +struct foo { + int a; + char b; +}; + +int main(int argc, char *argv[]) +{ + struct foo foo = { .a = 1, .b = 2 }, *foop; + int *intp = &foo.a; + +#ifdef FAIL + /* b is a char, but intp is an int * */ + foop = container_of(intp, struct foo, b); +#else + foop = NULL; +#endif + (void) foop; /* Suppress unused-but-set-variable warning. */ + return intp == NULL; +} diff --git a/lib/ccan/container_of/test/compile_fail-var-types.c b/lib/ccan/container_of/test/compile_fail-var-types.c new file mode 100644 index 0000000000..f254d92102 --- /dev/null +++ b/lib/ccan/container_of/test/compile_fail-var-types.c @@ -0,0 +1,25 @@ +#include <ccan/container_of/container_of.h> +#include <stdlib.h> + +struct foo { + int a; + char b; +}; + +int main(int argc, char *argv[]) +{ + struct foo foo = { .a = 1, .b = 2 }, *foop; + int *intp = &foo.a; + +#ifdef FAIL + /* b is a char, but intp is an int * */ + foop = container_of_var(intp, foop, b); +#if !HAVE_TYPEOF +#error "Unfortunately we don't fail if we don't have typeof." +#endif +#else + foop = NULL; +#endif + (void) foop; /* Suppress unused-but-set-variable warning. */ + return intp == NULL; +} diff --git a/lib/ccan/container_of/test/run.c b/lib/ccan/container_of/test/run.c new file mode 100644 index 0000000000..5da440a1e5 --- /dev/null +++ b/lib/ccan/container_of/test/run.c @@ -0,0 +1,26 @@ +#include <ccan/container_of/container_of.h> +#include <ccan/tap/tap.h> + +struct foo { + int a; + char b; +}; + +int main(int argc, char *argv[]) +{ + struct foo foo = { .a = 1, .b = 2 }; + int *intp = &foo.a; + char *charp = &foo.b; + + plan_tests(8); + ok1(container_of(intp, struct foo, a) == &foo); + ok1(container_of(charp, struct foo, b) == &foo); + ok1(container_of_var(intp, &foo, a) == &foo); + ok1(container_of_var(charp, &foo, b) == &foo); + + ok1(container_off(struct foo, a) == 0); + ok1(container_off(struct foo, b) == offsetof(struct foo, b)); + ok1(container_off_var(&foo, a) == 0); + ok1(container_off_var(&foo, b) == offsetof(struct foo, b)); + return exit_status(); +} |