* [PATCHv2 0/6] tcon extensions for easier typesafe wrapping
@ 2015-10-22 6:47 David Gibson
2015-10-22 6:47 ` [PATCHv2 1/6] tcon: Add an alternate way of building type canaries David Gibson
` (5 more replies)
0 siblings, 6 replies; 9+ messages in thread
From: David Gibson @ 2015-10-22 6:47 UTC (permalink / raw)
To: ccan
ccan includes many modules which use macro wrappers to make typesafe
pseudo-templated versions of a basic algorithm or data structure.
This series implements several extensions to the tcon module to enable
yet another approach to this. The advantage of this new method is
that it's able to store a variety of "template" information into a
type or variable declaration. That means that a module using this
technique can implement typesafe wrappers which can obtain the type
information they need from that initial declaration avoiding the need
to respecify types or field members in multiple places.
The last two patches in the series apply this approach to the lstack
and lqueue modules, giving them a nicer typesafe interface.
Changes since v1:
* More macros to access the normal tcon options for the type
canaries built into TCON_CONTAINER
* Macro ti directly access to the offset stored in a TCON_CONTAINER
* TCON_CONTAINER stores the type canaries as the type itself, rather
than a pointer to it. That matches the rest of tcon better, and
plays nicer in conjuction with total_order_cast() from the order
module.
* Fixed the problem that broke ccanlint. It was a ": " where there
should have been a " - ". Really.
David Gibson (6):
tcon: Add an alternate way of building type canaries
tcon: Add tcon_sizeof() helper
tcon: Encode integer values into "type" canaries
tcon: Encode information on container members in "type" canaries
lstack: Streamline interface with TCON_CONTAINER
lqueue: Streamline interface with TCON_CONTAINER
ccan/aga/bfs.c | 18 +-
ccan/aga/dfs.c | 18 +-
ccan/lqueue/_info | 8 +-
ccan/lqueue/lqueue.h | 154 ++++++++--------
ccan/lqueue/test/run.c | 44 ++---
ccan/lstack/_info | 8 +-
ccan/lstack/lstack.h | 141 ++++++++-------
ccan/lstack/test/run.c | 31 ++--
ccan/tcon/_info | 5 +
ccan/tcon/tcon.h | 252 +++++++++++++++++++++++++++
ccan/tcon/test/compile_fail-container1.c | 39 +++++
ccan/tcon/test/compile_fail-container1w.c | 35 ++++
ccan/tcon/test/compile_fail-container2.c | 39 +++++
ccan/tcon/test/compile_fail-container2w.c | 35 ++++
ccan/tcon/test/compile_fail-container3.c | 40 +++++
ccan/tcon/test/compile_fail-container3w.c | 36 ++++
ccan/tcon/test/compile_fail-container4.c | 40 +++++
ccan/tcon/test/compile_fail-container4w.c | 36 ++++
ccan/tcon/test/compile_fail-tcon_cast_wrap.c | 25 +++
ccan/tcon/test/compile_fail-wrap.c | 20 +++
ccan/tcon/test/compile_ok-sizeof.c | 35 ++++
ccan/tcon/test/compile_ok-value.c | 51 ++++++
ccan/tcon/test/compile_ok-void.c | 6 +
ccan/tcon/test/compile_ok.c | 11 ++
ccan/tcon/test/run-container.c | 59 +++++++
ccan/tcon/test/run-wrap.c | 18 ++
26 files changed, 1015 insertions(+), 189 deletions(-)
create mode 100644 ccan/tcon/test/compile_fail-container1.c
create mode 100644 ccan/tcon/test/compile_fail-container1w.c
create mode 100644 ccan/tcon/test/compile_fail-container2.c
create mode 100644 ccan/tcon/test/compile_fail-container2w.c
create mode 100644 ccan/tcon/test/compile_fail-container3.c
create mode 100644 ccan/tcon/test/compile_fail-container3w.c
create mode 100644 ccan/tcon/test/compile_fail-container4.c
create mode 100644 ccan/tcon/test/compile_fail-container4w.c
create mode 100644 ccan/tcon/test/compile_fail-tcon_cast_wrap.c
create mode 100644 ccan/tcon/test/compile_fail-wrap.c
create mode 100644 ccan/tcon/test/compile_ok-sizeof.c
create mode 100644 ccan/tcon/test/compile_ok-value.c
create mode 100644 ccan/tcon/test/run-container.c
create mode 100644 ccan/tcon/test/run-wrap.c
--
2.4.3
_______________________________________________
ccan mailing list
ccan@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/ccan
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCHv2 1/6] tcon: Add an alternate way of building type canaries
2015-10-22 6:47 [PATCHv2 0/6] tcon extensions for easier typesafe wrapping David Gibson
@ 2015-10-22 6:47 ` David Gibson
2015-10-22 6:47 ` [PATCHv2 2/6] tcon: Add tcon_sizeof() helper David Gibson
` (4 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: David Gibson @ 2015-10-22 6:47 UTC (permalink / raw)
To: ccan
The tcon module allows you to add "type canaries" to a structures, which
can be used for later typechecks. The canaries are implemented using
a flexible array member, to avoid them taking any actual space at runtime.
That means the canaries must go at the end of your structure.
That doesn't seem like a big limitation, except that it also means the
structure containing the canaries must be at the end of any structure it
is embedded in in turn, which is a rather more serious limitation.
This patch adds a TCON_WRAP() macro which wraps a given type in a new type
which also contains type canaries, and doesn't suffer the last member
limitation. The drawback is that if the wrapped type has smaller size than
a pointer, the type canaries will pad the wrapped type out to the size of a
pointer.
By constructing the wrappers carefully, the existing tcon macros will work
on both wrapper types constructed with TCON_WRAP and on structures
explicitly including TCON type canaries.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
ccan/tcon/_info | 5 ++
ccan/tcon/tcon.h | 71 ++++++++++++++++++++++++++++
ccan/tcon/test/compile_fail-tcon_cast_wrap.c | 25 ++++++++++
ccan/tcon/test/compile_fail-wrap.c | 20 ++++++++
ccan/tcon/test/compile_ok-void.c | 6 +++
ccan/tcon/test/compile_ok.c | 11 +++++
ccan/tcon/test/run-wrap.c | 18 +++++++
7 files changed, 156 insertions(+)
create mode 100644 ccan/tcon/test/compile_fail-tcon_cast_wrap.c
create mode 100644 ccan/tcon/test/compile_fail-wrap.c
create mode 100644 ccan/tcon/test/run-wrap.c
diff --git a/ccan/tcon/_info b/ccan/tcon/_info
index f6a6f0f..50dc0a5 100644
--- a/ccan/tcon/_info
+++ b/ccan/tcon/_info
@@ -71,5 +71,10 @@ int main(int argc, char *argv[])
return 0;
}
+ if (strcmp(argv[1], "testdepends") == 0) {
+ printf("ccan/build_assert\n");
+ return 0;
+ }
+
return 1;
}
diff --git a/ccan/tcon/tcon.h b/ccan/tcon/tcon.h
index cf82f3e..a256f10 100644
--- a/ccan/tcon/tcon.h
+++ b/ccan/tcon/tcon.h
@@ -43,6 +43,77 @@
#endif
/**
+ * TCON_WRAP - declare a wrapper type containing a base type and type canaries
+ * @basetype: the base type to wrap
+ * @decls: the semi-colon separated list of type canaries.
+ *
+ * This expands to a new type which includes the given base type, and
+ * also type canaries, similar to those created with TCON.
+ *
+ * The embedded base type value can be accessed using tcon_unwrap().
+ *
+ * Differences from using TCON()
+ * - The wrapper type will take either the size of the base type, or
+ * the size of a single pointer, whichever is greater (regardless of
+ * compiler)
+ * - A TCON_WRAP type may be included in another structure, and need
+ * not be the last element.
+ *
+ * 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;
+ * };
+ *
+ * typedef TCON_WRAP(struct list_head, char *canary) string_list_t;
+ *
+ * // More complex: mapping from one type to another.
+ * struct map {
+ * void *contents;
+ * };
+ *
+ * typedef TCON_WRAP(struct map, char *charp_canary; int int_canary)
+ * int_to_string_map_t;
+ */
+#define TCON_WRAP(basetype, decls) \
+ union { \
+ basetype _base; \
+ struct { \
+ decls; \
+ } *_tcon; \
+ }
+
+/**
+ * TCON_WRAP_INIT - an initializer for a variable declared with TCON_WRAP
+ * @...: Initializer for the base type (treated as variadic so commas
+ * can be included)
+ *
+ * Converts converts an initializer suitable for a base type into one
+ * suitable for that type wrapped with TCON_WRAP.
+ *
+ * Example:
+ * TCON_WRAP(int, char *canary) canaried_int = TCON_WRAP_INIT(17);
+ */
+#define TCON_WRAP_INIT(...) \
+ { ._base = __VA_ARGS__, }
+
+/**
+ * tcon_unwrap - Access the base type of a TCON_WRAP
+ * @ptr: pointer to an object declared with TCON_WRAP
+ *
+ * tcon_unwrap() returns a pointer to the base type of the TCON_WRAP()
+ * object pointer to by @ptr.
+ *
+ * Example:
+ * TCON_WRAP(int, char *canary) canaried_int;
+ *
+ * *tcon_unwrap(&canaried_int) = 17;
+ */
+#define tcon_unwrap(ptr) (&((ptr)->_base))
+
+/**
* tcon_check - typecheck a typed container
* @x: the structure containing the TCON.
* @canary: which canary to check against.
diff --git a/ccan/tcon/test/compile_fail-tcon_cast_wrap.c b/ccan/tcon/test/compile_fail-tcon_cast_wrap.c
new file mode 100644
index 0000000..f24cb01
--- /dev/null
+++ b/ccan/tcon/test/compile_fail-tcon_cast_wrap.c
@@ -0,0 +1,25 @@
+#include <ccan/tcon/tcon.h>
+#include <stdlib.h>
+
+struct container {
+ void *p;
+};
+
+int main(int argc, char *argv[])
+{
+ TCON_WRAP(struct container,
+ int *tc1; char *tc2) icon;
+#ifdef FAIL
+#if !HAVE_TYPEOF
+#error We cannot detect type problems without HAVE_TYPEOF
+#endif
+ char *
+#else
+ int *
+#endif
+ x;
+
+ tcon_unwrap(&icon)->p = NULL;
+ x = tcon_cast(&icon, tc1, tcon_unwrap(&icon)->p);
+ return x != NULL ? 0 : 1;
+}
diff --git a/ccan/tcon/test/compile_fail-wrap.c b/ccan/tcon/test/compile_fail-wrap.c
new file mode 100644
index 0000000..26da13c
--- /dev/null
+++ b/ccan/tcon/test/compile_fail-wrap.c
@@ -0,0 +1,20 @@
+#include <ccan/tcon/tcon.h>
+#include <stdlib.h>
+
+struct container {
+ void *p;
+};
+
+int main(int argc, char *argv[])
+{
+ TCON_WRAP(struct container, int *canary) icon;
+#ifdef FAIL
+ char *
+#else
+ int *
+#endif
+ x = NULL;
+
+ tcon_unwrap(tcon_check(&icon, canary, x))->p = x;
+ return 0;
+}
diff --git a/ccan/tcon/test/compile_ok-void.c b/ccan/tcon/test/compile_ok-void.c
index 26b712f..694a53b 100644
--- a/ccan/tcon/test/compile_ok-void.c
+++ b/ccan/tcon/test/compile_ok-void.c
@@ -13,9 +13,15 @@ struct void_container {
int main(int argc, char *argv[])
{
struct void_container vcon;
+ TCON_WRAP(struct container, void *canary) vconw;
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;
+
+ tcon_unwrap(tcon_check(&vconw, canary, NULL))->p = NULL;
+ tcon_unwrap(tcon_check(&vconw, canary, argv[0]))->p = NULL;
+ tcon_unwrap(tcon_check(&vconw, canary, main))->p = NULL;
+
return 0;
}
diff --git a/ccan/tcon/test/compile_ok.c b/ccan/tcon/test/compile_ok.c
index 447f0ee..f3fe2c6 100644
--- a/ccan/tcon/test/compile_ok.c
+++ b/ccan/tcon/test/compile_ok.c
@@ -1,4 +1,5 @@
#include <ccan/tcon/tcon.h>
+#include <ccan/build_assert/build_assert.h>
#include <stdlib.h>
struct container {
@@ -19,9 +20,19 @@ int main(int argc, char *argv[])
{
struct int_container icon;
struct charp_and_int_container cicon;
+ TCON_WRAP(struct container, int tc) iconw;
+ TCON_WRAP(struct container, int tc1; char *tc2) ciconw;
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];
+
+ tcon_unwrap(tcon_check(&iconw, tc, 7))->p = NULL;
+ tcon_unwrap(tcon_check(&ciconw, tc1, 7))->p = argv[0];
+ tcon_unwrap(tcon_check(&ciconw, tc2, argv[0]))->p = argv[0];
+
+ BUILD_ASSERT(sizeof(iconw) == sizeof(struct container));
+ BUILD_ASSERT(sizeof(ciconw) == sizeof(struct container));
+
return 0;
}
diff --git a/ccan/tcon/test/run-wrap.c b/ccan/tcon/test/run-wrap.c
new file mode 100644
index 0000000..0d5cfef
--- /dev/null
+++ b/ccan/tcon/test/run-wrap.c
@@ -0,0 +1,18 @@
+#include <ccan/tcon/tcon.h>
+#include <ccan/tap/tap.h>
+#include <stdlib.h>
+
+typedef TCON_WRAP(int, char *canary) canaried_int;
+
+int main(int argc, char *argv[])
+{
+ canaried_int ci = TCON_WRAP_INIT(0);
+
+ plan_tests(2);
+
+ ok1(*tcon_unwrap(&ci) == 0);
+ *tcon_unwrap(&ci) = 17;
+ ok1(*tcon_unwrap(&ci) == 17);
+
+ return exit_status();
+}
--
2.4.3
_______________________________________________
ccan mailing list
ccan@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/ccan
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCHv2 2/6] tcon: Add tcon_sizeof() helper
2015-10-22 6:47 [PATCHv2 0/6] tcon extensions for easier typesafe wrapping David Gibson
2015-10-22 6:47 ` [PATCHv2 1/6] tcon: Add an alternate way of building type canaries David Gibson
@ 2015-10-22 6:47 ` David Gibson
2015-10-22 6:47 ` [PATCHv2 3/6] tcon: Encode integer values into "type" canaries David Gibson
` (3 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: David Gibson @ 2015-10-22 6:47 UTC (permalink / raw)
To: ccan
Add a new tcon_sizeof() helper macro which returns the size of a type for
which a canary has been constructed with TCON or TCON_WRAP.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
ccan/tcon/tcon.h | 7 +++++++
ccan/tcon/test/compile_ok-sizeof.c | 35 +++++++++++++++++++++++++++++++++++
2 files changed, 42 insertions(+)
create mode 100644 ccan/tcon/test/compile_ok-sizeof.c
diff --git a/ccan/tcon/tcon.h b/ccan/tcon/tcon.h
index a256f10..62bacf5 100644
--- a/ccan/tcon/tcon.h
+++ b/ccan/tcon/tcon.h
@@ -160,6 +160,13 @@
#endif
/**
+ * tcon_sizeof - the size of type within a container
+ * @x: the structure containing the TCON.
+ * @canary: which canary to check against.
+ */
+#define tcon_sizeof(x, canary) sizeof((x)->_tcon[0].canary)
+
+/**
* tcon_ptr_type - pointer to the type within a container (or void *)
* @x: the structure containing the TCON.
* @canary: which canary to check against.
diff --git a/ccan/tcon/test/compile_ok-sizeof.c b/ccan/tcon/test/compile_ok-sizeof.c
new file mode 100644
index 0000000..64ccc13
--- /dev/null
+++ b/ccan/tcon/test/compile_ok-sizeof.c
@@ -0,0 +1,35 @@
+#include <ccan/tcon/tcon.h>
+#include <ccan/build_assert/build_assert.h>
+#include <stdlib.h>
+
+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_WRAP(struct container, int tc) iconw;
+ TCON_WRAP(struct container, int tc1; char *tc2) ciconw;
+
+ BUILD_ASSERT(tcon_sizeof(&icon, tc) == sizeof(int));
+ BUILD_ASSERT(tcon_sizeof(&cicon, tc1) == sizeof(int));
+ BUILD_ASSERT(tcon_sizeof(&cicon, tc2) == sizeof(char *));
+
+ BUILD_ASSERT(tcon_sizeof(&iconw, tc) == sizeof(int));
+ BUILD_ASSERT(tcon_sizeof(&ciconw, tc1) == sizeof(int));
+ BUILD_ASSERT(tcon_sizeof(&ciconw, tc2) == sizeof(char *));
+
+ return 0;
+}
--
2.4.3
_______________________________________________
ccan mailing list
ccan@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/ccan
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCHv2 3/6] tcon: Encode integer values into "type" canaries
2015-10-22 6:47 [PATCHv2 0/6] tcon extensions for easier typesafe wrapping David Gibson
2015-10-22 6:47 ` [PATCHv2 1/6] tcon: Add an alternate way of building type canaries David Gibson
2015-10-22 6:47 ` [PATCHv2 2/6] tcon: Add tcon_sizeof() helper David Gibson
@ 2015-10-22 6:47 ` David Gibson
2015-10-27 3:11 ` Rusty Russell
2015-10-22 6:47 ` [PATCHv2 4/6] tcon: Encode information on container members in " David Gibson
` (2 subsequent siblings)
5 siblings, 1 reply; 9+ messages in thread
From: David Gibson @ 2015-10-22 6:47 UTC (permalink / raw)
To: ccan
Add the ability to encode, as well as types, integer values (must be
positive, compile time constant and in the range of size_t) into TCON
constructed "type" canaries.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
ccan/tcon/tcon.h | 22 +++++++++++++++++
ccan/tcon/test/compile_ok-value.c | 51 +++++++++++++++++++++++++++++++++++++++
2 files changed, 73 insertions(+)
create mode 100644 ccan/tcon/test/compile_ok-value.c
diff --git a/ccan/tcon/tcon.h b/ccan/tcon/tcon.h
index 62bacf5..c33070d 100644
--- a/ccan/tcon/tcon.h
+++ b/ccan/tcon/tcon.h
@@ -167,6 +167,28 @@
#define tcon_sizeof(x, canary) sizeof((x)->_tcon[0].canary)
/**
+ * TCON_VALUE - encode an integer value in a type canary
+ * @canary: name of the value canary
+ * @val: positive integer compile time constant value
+ *
+ * This macro can be included inside the declarations in a TCON() or
+ * TCON_WRAP(), constructing a special "type" canary which encodes the
+ * integer value @val (which must be a compile time constant, and a
+ * positive integer in the range of size_t).
+ */
+#define TCON_VALUE(canary, val) char _value_##canary[val]
+
+/**
+ * tcon_value - retrieve the value of a TCON_VALUE canary
+ * @x: the structure containing the TCON
+ * @canary: name of the value canary
+ *
+ * This macros expands to the value previously encoded into a TCON
+ * using TCON_VALUE().
+ */
+#define tcon_value(x, canary) tcon_sizeof(x, _value_##canary)
+
+/**
* tcon_ptr_type - pointer to the type within a container (or void *)
* @x: the structure containing the TCON.
* @canary: which canary to check against.
diff --git a/ccan/tcon/test/compile_ok-value.c b/ccan/tcon/test/compile_ok-value.c
new file mode 100644
index 0000000..d9c911e
--- /dev/null
+++ b/ccan/tcon/test/compile_ok-value.c
@@ -0,0 +1,51 @@
+#include <ccan/tcon/tcon.h>
+#include <ccan/build_assert/build_assert.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+struct container {
+ void *p;
+};
+
+struct val_container {
+ struct container raw;
+ TCON(TCON_VALUE(fixed_val, 17));
+};
+
+struct other_struct {
+ char junk1;
+ int x1;
+ long junk2;
+ char *x2;
+ short junk3;
+};
+
+struct offs_container {
+ struct container raw;
+ TCON(TCON_VALUE(off1, offsetof(struct other_struct, x1));
+ TCON_VALUE(off2, offsetof(struct other_struct, x2)));
+};
+
+int main(int argc, char *argv[])
+{
+ struct val_container valcon;
+ struct offs_container offscon;
+ TCON_WRAP(struct container, TCON_VALUE(fixed_val, 17)) valconw;
+ TCON_WRAP(struct container,
+ TCON_VALUE(off1, offsetof(struct other_struct, x1));
+ TCON_VALUE(off2, offsetof(struct other_struct, x2))) offsconw;
+
+ BUILD_ASSERT(tcon_value(&valcon, fixed_val) == 17);
+ BUILD_ASSERT(tcon_value(&valconw, fixed_val) == 17);
+
+ BUILD_ASSERT(tcon_value(&offscon, off1)
+ == offsetof(struct other_struct, x1));
+ BUILD_ASSERT(tcon_value(&offscon, off2)
+ == offsetof(struct other_struct, x2));
+ BUILD_ASSERT(tcon_value(&offsconw, off1)
+ == offsetof(struct other_struct, x1));
+ BUILD_ASSERT(tcon_value(&offsconw, off2)
+ == offsetof(struct other_struct, x2));
+
+ return 0;
+}
--
2.4.3
_______________________________________________
ccan mailing list
ccan@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/ccan
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCHv2 4/6] tcon: Encode information on container members in "type" canaries
2015-10-22 6:47 [PATCHv2 0/6] tcon extensions for easier typesafe wrapping David Gibson
` (2 preceding siblings ...)
2015-10-22 6:47 ` [PATCHv2 3/6] tcon: Encode integer values into "type" canaries David Gibson
@ 2015-10-22 6:47 ` David Gibson
2015-10-22 6:47 ` [PATCHv2 5/6] lstack: Streamline interface with TCON_CONTAINER David Gibson
2015-10-22 6:47 ` [PATCHv2 6/6] lqueue: " David Gibson
5 siblings, 0 replies; 9+ messages in thread
From: David Gibson @ 2015-10-22 6:47 UTC (permalink / raw)
To: ccan
Add "container canaries" to tcon. This allows information about a specific
member of a container structure to be encoded with TCON or TCON_WRAP. Once
that's done, tcon_container_of() and tcon_member_of() can be used to
translate between member and container pointers based on the canary
information, without having to repeat the type and member details.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
ccan/tcon/tcon.h | 152 ++++++++++++++++++++++++++++++
ccan/tcon/test/compile_fail-container1.c | 39 ++++++++
ccan/tcon/test/compile_fail-container1w.c | 35 +++++++
ccan/tcon/test/compile_fail-container2.c | 39 ++++++++
ccan/tcon/test/compile_fail-container2w.c | 35 +++++++
ccan/tcon/test/compile_fail-container3.c | 40 ++++++++
ccan/tcon/test/compile_fail-container3w.c | 36 +++++++
ccan/tcon/test/compile_fail-container4.c | 40 ++++++++
ccan/tcon/test/compile_fail-container4w.c | 36 +++++++
ccan/tcon/test/run-container.c | 59 ++++++++++++
10 files changed, 511 insertions(+)
create mode 100644 ccan/tcon/test/compile_fail-container1.c
create mode 100644 ccan/tcon/test/compile_fail-container1w.c
create mode 100644 ccan/tcon/test/compile_fail-container2.c
create mode 100644 ccan/tcon/test/compile_fail-container2w.c
create mode 100644 ccan/tcon/test/compile_fail-container3.c
create mode 100644 ccan/tcon/test/compile_fail-container3w.c
create mode 100644 ccan/tcon/test/compile_fail-container4.c
create mode 100644 ccan/tcon/test/compile_fail-container4w.c
create mode 100644 ccan/tcon/test/run-container.c
diff --git a/ccan/tcon/tcon.h b/ccan/tcon/tcon.h
index c33070d..1dbadaf 100644
--- a/ccan/tcon/tcon.h
+++ b/ccan/tcon/tcon.h
@@ -3,6 +3,8 @@
#define CCAN_TCON_H
#include "config.h"
+#include <stddef.h>
+
/**
* TCON - declare a _tcon type containing canary variables.
* @decls: the semi-colon separated list of type canaries.
@@ -212,4 +214,154 @@
#define tcon_cast(x, canary, expr) ((tcon_type((x), canary))(expr))
#define tcon_cast_ptr(x, canary, expr) ((tcon_ptr_type((x), canary))(expr))
+/**
+ * TCON_CONTAINER - encode information on a specific member of a
+ * containing structure into a "type" canary
+ * @canary: name of the container canary
+ * @container: type of the container structure
+ * @member: name of the member
+ *
+ * Used in the declarations in TCON() or TCON_WRAP(), encode a
+ * "container canary". This encodes the type of @container, the type
+ * of @member within it (with sufficient compiler support) and the
+ * offset of @member within @container.
+ */
+#if HAVE_TYPEOF
+#define TCON_CONTAINER(canary, container, member) \
+ container _container_##canary; \
+ typeof(((container *)0)->member) _member_##canary; \
+ TCON_VALUE(_offset_##canary, offsetof(container, member))
+#else
+#define TCON_CONTAINER(canary, container, member) \
+ container _container_##canary; \
+ TCON_VALUE(_offset_##canary, offsetof(container, member))
+#endif
+
+/**
+ * tcon_container_check
+ * tcon_container_check_ptr
+ * tcon_container_type
+ * tcon_container_ptr_type
+ * tcon_container_sizeof
+ * tcon_container_cast
+ * tcon_container_cast_ptr
+ * @x: the structure containing the TCON.
+ * @canary: which container canary to check against.
+ *
+ * As tcon_check / tcon_check_ptr / tcon_type / tcon_ptr_type /
+ * tcon_sizeof / tcon_cast / tcon_cast_ptr, but use the type of the
+ * "container" type declared with TCON_CONTAINER, instead of a simple
+ * canary.
+ */
+#define tcon_container_check(x, canary, expr) \
+ tcon_check(x, _container_##canary, expr)
+#define tcon_container_check_ptr(x, canary, expr) \
+ tcon_check_ptr(x, _container_##canary, expr)
+#define tcon_container_type(x, canary) \
+ tcon_type(x, _container_##canary)
+#define tcon_container_ptr_type(x, canary) \
+ tcon_ptr_type(x, _container_##canary)
+#define tcon_container_sizeof(x, canary) \
+ tcon_sizeof(x, _container_##canary)
+#define tcon_container_cast(x, canary, expr) \
+ tcon_cast(x, _container_##canary, expr)
+#define tcon_container_cast_ptr(x, canary, expr) \
+ tcon_cast_ptr(x, _container_##canary, expr)
+
+/**
+ * tcon_member_check
+ * tcon_member_check_ptr
+ * tcon_member_type
+ * tcon_member_ptr_type
+ * tcon_member_sizeof
+ * tcon_member_cast
+ * tcon_member_cast_ptr
+ * @x: the structure containing the TCON.
+ * @canary: which container canary to check against.
+ *
+ * As tcon_check / tcon_check_ptr / tcon_type / tcon_ptr_type /
+ * tcon_sizeof / tcon_cast / tcon_cast_ptr, but use the type of the
+ * "member" type declared with TCON_CONTAINER, instead of a simple
+ * canary.
+ */
+#define tcon_member_check(x, canary, expr) \
+ tcon_check(x, _member_##canary, expr)
+#define tcon_member_check_ptr(x, canary, expr) \
+ tcon_check_ptr(x, _member_##canary, expr)
+#define tcon_member_type(x, canary) \
+ tcon_type(x, _member_##canary)
+#define tcon_member_ptr_type(x, canary) \
+ tcon_ptr_type(x, _member_##canary)
+#define tcon_member_sizeof(x, canary) \
+ tcon_sizeof(x, _member_##canary)
+#define tcon_member_cast(x, canary, expr) \
+ tcon_cast(x, _member_##canary, expr)
+#define tcon_member_cast_ptr(x, canary, expr) \
+ tcon_cast_ptr(x, _member_##canary, expr)
+
+/**
+ * tcon_offset - the offset of a member within a container, as
+ * declared with TCON_CONTAINER
+ * @x: the structure containing the TCON.
+ * @canary: which container canary to check against.
+ */
+#define tcon_offset(x, canary) \
+ tcon_value((x), _offset_##canary)
+
+/**
+ * tcon_container_of - get pointer to enclosing structure based on a
+ * container canary
+ * @x: the structure containing the TCON
+ * @canary: the name of the container canary
+ * @member_ptr: pointer to a member of the container
+ *
+ * @member_ptr must be a pointer to the member of a container
+ * structure previously recorded in @canary with TCON_CONTAINER.
+ *
+ * tcon_container_of() evaluates to a pointer to the container
+ * structure. With sufficient compiler support, the pointer will be
+ * correctly typed, and the type of @member_ptr will be verified.
+ *
+ * Returns NULL if @member_ptr is NULL.
+ */
+#define tcon_container_of(x, canary, member_ptr) \
+ tcon_container_cast_ptr( \
+ tcon_member_check_ptr((x), canary, (member_ptr)), \
+ canary, tcon_container_of_((member_ptr), \
+ tcon_offset((x), canary)))
+
+static inline void *tcon_container_of_(void *member_ptr, size_t offset)
+{
+ return member_ptr ? (char *)member_ptr - offset : NULL;
+}
+
+
+/**
+ * tcon_member_of - get pointer to enclosed member structure based on a
+ * container canary
+ * @x: the structure containing the TCON
+ * @canary: the name of the container canary
+ * @container_ptr: pointer to a container
+ *
+ * @container_ptr must be a pointer to a container structure
+ * previously recorded in @canary with TCON_CONTAINER.
+ *
+ * tcon_member_of() evaluates to a pointer to the member of the
+ * container recorded in @canary. With sufficient compiler support,
+ * the pointer will be correctly typed, and the type of @container_ptr
+ * will be verified.
+ *
+ * Returns NULL if @container_ptr is NULL.
+ */
+#define tcon_member_of(x, canary, container_ptr) \
+ tcon_member_cast_ptr( \
+ tcon_container_check_ptr((x), canary, (container_ptr)), \
+ canary, tcon_member_of_((container_ptr), \
+ tcon_offset((x), canary)))
+static inline void *tcon_member_of_(void *container_ptr, size_t offset)
+{
+ return container_ptr ? (char *)container_ptr + offset : NULL;
+}
+
+
#endif /* CCAN_TCON_H */
diff --git a/ccan/tcon/test/compile_fail-container1.c b/ccan/tcon/test/compile_fail-container1.c
new file mode 100644
index 0000000..a67e209
--- /dev/null
+++ b/ccan/tcon/test/compile_fail-container1.c
@@ -0,0 +1,39 @@
+#include <stdlib.h>
+
+#include <ccan/tcon/tcon.h>
+#include <ccan/build_assert/build_assert.h>
+#include <ccan/tap/tap.h>
+
+struct inner {
+ int inner_val;
+};
+
+struct outer {
+ int outer_val;
+ struct inner inner;
+};
+
+struct info_base {
+ char *infop;
+};
+
+struct info_tcon {
+ struct info_base base;
+ TCON(TCON_CONTAINER(concan, struct outer, inner));
+};
+
+int main(int argc, char *argv[])
+{
+ struct info_tcon info;
+ struct outer ovar;
+#ifdef FAIL
+#if !HAVE_TYPEOF
+#error We cannot detect type problems without HAVE_TYPEOF
+#endif
+ int *innerp = &ovar.outer_val;
+#else
+ struct inner *innerp = &ovar.inner;
+#endif
+
+ return tcon_container_of(&info, concan, innerp) == &ovar;
+}
diff --git a/ccan/tcon/test/compile_fail-container1w.c b/ccan/tcon/test/compile_fail-container1w.c
new file mode 100644
index 0000000..0226b68
--- /dev/null
+++ b/ccan/tcon/test/compile_fail-container1w.c
@@ -0,0 +1,35 @@
+#include <stdlib.h>
+
+#include <ccan/tcon/tcon.h>
+#include <ccan/build_assert/build_assert.h>
+#include <ccan/tap/tap.h>
+
+struct inner {
+ int inner_val;
+};
+
+struct outer {
+ int outer_val;
+ struct inner inner;
+};
+
+struct info_base {
+ char *infop;
+};
+
+int main(int argc, char *argv[])
+{
+ TCON_WRAP(struct info_base,
+ TCON_CONTAINER(concan, struct outer, inner)) info;
+ struct outer ovar;
+#ifdef FAIL
+#if !HAVE_TYPEOF
+#error We cannot detect type problems without HAVE_TYPEOF
+#endif
+ int *innerp = &ovar.outer_val;
+#else
+ struct inner *innerp = &ovar.inner;
+#endif
+
+ return tcon_container_of(&info, concan, innerp) == &ovar;
+}
diff --git a/ccan/tcon/test/compile_fail-container2.c b/ccan/tcon/test/compile_fail-container2.c
new file mode 100644
index 0000000..6cad734
--- /dev/null
+++ b/ccan/tcon/test/compile_fail-container2.c
@@ -0,0 +1,39 @@
+#include <stdlib.h>
+
+#include <ccan/tcon/tcon.h>
+#include <ccan/build_assert/build_assert.h>
+#include <ccan/tap/tap.h>
+
+struct inner {
+ int inner_val;
+};
+
+struct outer {
+ int outer_val;
+ struct inner inner;
+};
+
+struct info_base {
+ char *infop;
+};
+
+struct info_tcon {
+ struct info_base base;
+ TCON(TCON_CONTAINER(concan, struct outer, inner));
+};
+
+int main(int argc, char *argv[])
+{
+ struct info_tcon info;
+ struct outer ovar;
+#ifdef FAIL
+#if !HAVE_TYPEOF
+#error We cannot detect type problems without HAVE_TYPEOF
+#endif
+ char *outerp = NULL;
+#else
+ struct outer *outerp = &ovar;
+#endif
+
+ return tcon_member_of(&info, concan, outerp) == &ovar.inner;
+}
diff --git a/ccan/tcon/test/compile_fail-container2w.c b/ccan/tcon/test/compile_fail-container2w.c
new file mode 100644
index 0000000..c73123c
--- /dev/null
+++ b/ccan/tcon/test/compile_fail-container2w.c
@@ -0,0 +1,35 @@
+#include <stdlib.h>
+
+#include <ccan/tcon/tcon.h>
+#include <ccan/build_assert/build_assert.h>
+#include <ccan/tap/tap.h>
+
+struct inner {
+ int inner_val;
+};
+
+struct outer {
+ int outer_val;
+ struct inner inner;
+};
+
+struct info_base {
+ char *infop;
+};
+
+int main(int argc, char *argv[])
+{
+ TCON_WRAP(struct info_base,
+ TCON_CONTAINER(concan, struct outer, inner)) info;
+ struct outer ovar;
+#ifdef FAIL
+#if !HAVE_TYPEOF
+#error We cannot detect type problems without HAVE_TYPEOF
+#endif
+ char *outerp = NULL;
+#else
+ struct outer *outerp = &ovar;
+#endif
+
+ return tcon_member_of(&info, concan, outerp) == &ovar.inner;
+}
diff --git a/ccan/tcon/test/compile_fail-container3.c b/ccan/tcon/test/compile_fail-container3.c
new file mode 100644
index 0000000..97473c8
--- /dev/null
+++ b/ccan/tcon/test/compile_fail-container3.c
@@ -0,0 +1,40 @@
+#include <stdlib.h>
+
+#include <ccan/tcon/tcon.h>
+#include <ccan/build_assert/build_assert.h>
+#include <ccan/tap/tap.h>
+
+struct inner {
+ int inner_val;
+};
+
+struct outer {
+ int outer_val;
+ struct inner inner;
+};
+
+struct info_base {
+ char *infop;
+};
+
+struct info_tcon {
+ struct info_base base;
+ TCON(TCON_CONTAINER(concan, struct outer, inner));
+};
+
+int main(int argc, char *argv[])
+{
+ struct info_tcon info;
+ struct outer ovar;
+#ifdef FAIL
+#if !HAVE_TYPEOF
+#error We cannot detect type problems without HAVE_TYPEOF
+#endif
+ int *outerp;
+#else
+ struct outer *outerp;
+#endif
+
+ outerp = tcon_container_of(&info, concan, &ovar.inner);
+ return outerp != NULL;
+}
diff --git a/ccan/tcon/test/compile_fail-container3w.c b/ccan/tcon/test/compile_fail-container3w.c
new file mode 100644
index 0000000..6930b43
--- /dev/null
+++ b/ccan/tcon/test/compile_fail-container3w.c
@@ -0,0 +1,36 @@
+#include <stdlib.h>
+
+#include <ccan/tcon/tcon.h>
+#include <ccan/build_assert/build_assert.h>
+#include <ccan/tap/tap.h>
+
+struct inner {
+ int inner_val;
+};
+
+struct outer {
+ int outer_val;
+ struct inner inner;
+};
+
+struct info_base {
+ char *infop;
+};
+
+int main(int argc, char *argv[])
+{
+ TCON_WRAP(struct info_base,
+ TCON_CONTAINER(concan, struct outer, inner)) info;
+ struct outer ovar;
+#ifdef FAIL
+#if !HAVE_TYPEOF
+#error We cannot detect type problems without HAVE_TYPEOF
+#endif
+ int *outerp;
+#else
+ struct outer *outerp;
+#endif
+
+ outerp = tcon_container_of(&info, concan, &ovar.inner);
+ return outerp != NULL;
+}
diff --git a/ccan/tcon/test/compile_fail-container4.c b/ccan/tcon/test/compile_fail-container4.c
new file mode 100644
index 0000000..838ce9b
--- /dev/null
+++ b/ccan/tcon/test/compile_fail-container4.c
@@ -0,0 +1,40 @@
+#include <stdlib.h>
+
+#include <ccan/tcon/tcon.h>
+#include <ccan/build_assert/build_assert.h>
+#include <ccan/tap/tap.h>
+
+struct inner {
+ int inner_val;
+};
+
+struct outer {
+ int outer_val;
+ struct inner inner;
+};
+
+struct info_base {
+ char *infop;
+};
+
+struct info_tcon {
+ struct info_base base;
+ TCON(TCON_CONTAINER(concan, struct outer, inner));
+};
+
+int main(int argc, char *argv[])
+{
+ struct info_tcon info;
+ struct outer ovar;
+#ifdef FAIL
+#if !HAVE_TYPEOF
+#error We cannot detect type problems without HAVE_TYPEOF
+#endif
+ int *innerp;
+#else
+ struct inner *innerp;
+#endif
+
+ innerp = tcon_member_of(&info, concan, &ovar);
+ return innerp != NULL;
+}
diff --git a/ccan/tcon/test/compile_fail-container4w.c b/ccan/tcon/test/compile_fail-container4w.c
new file mode 100644
index 0000000..0d7b367
--- /dev/null
+++ b/ccan/tcon/test/compile_fail-container4w.c
@@ -0,0 +1,36 @@
+#include <stdlib.h>
+
+#include <ccan/tcon/tcon.h>
+#include <ccan/build_assert/build_assert.h>
+#include <ccan/tap/tap.h>
+
+struct inner {
+ int inner_val;
+};
+
+struct outer {
+ int outer_val;
+ struct inner inner;
+};
+
+struct info_base {
+ char *infop;
+};
+
+int main(int argc, char *argv[])
+{
+ TCON_WRAP(struct info_base,
+ TCON_CONTAINER(concan, struct outer, inner)) info;
+ struct outer ovar;
+#ifdef FAIL
+#if !HAVE_TYPEOF
+#error We cannot detect type problems without HAVE_TYPEOF
+#endif
+ int *innerp;
+#else
+ struct inner *innerp;
+#endif
+
+ innerp = tcon_member_of(&info, concan, &ovar);
+ return innerp != NULL;
+}
diff --git a/ccan/tcon/test/run-container.c b/ccan/tcon/test/run-container.c
new file mode 100644
index 0000000..88bb2a1
--- /dev/null
+++ b/ccan/tcon/test/run-container.c
@@ -0,0 +1,59 @@
+#include <stdlib.h>
+
+#include <ccan/tcon/tcon.h>
+#include <ccan/build_assert/build_assert.h>
+#include <ccan/tap/tap.h>
+
+struct inner {
+ int inner_val;
+};
+
+struct outer {
+ int outer_val;
+ struct inner inner;
+};
+
+struct outer0 {
+ struct inner inner;
+ int outer0_val;
+};
+
+struct info_base {
+ char *infop;
+};
+
+struct info_tcon {
+ struct info_base base;
+ TCON(TCON_CONTAINER(fi, struct outer, inner);
+ TCON_CONTAINER(fi2, struct outer0, inner));
+};
+
+int main(int argc, char *argv[])
+{
+ struct info_tcon info;
+ TCON_WRAP(struct info_base,
+ TCON_CONTAINER(fi, struct outer, inner);
+ TCON_CONTAINER(fi2, struct outer0, inner)) infow;
+ struct outer ovar;
+ struct outer0 ovar2;
+
+ plan_tests(12);
+
+ ok1(tcon_container_of(&info, fi, &ovar.inner) == &ovar);
+ ok1(tcon_member_of(&info, fi, &ovar) == &ovar.inner);
+ ok1(tcon_container_of(&infow, fi, &ovar.inner) == &ovar);
+ ok1(tcon_member_of(&infow, fi, &ovar) == &ovar.inner);
+
+ ok1(tcon_container_of(&info, fi2, &ovar2.inner) == &ovar2);
+ ok1(tcon_member_of(&info, fi2, &ovar2) == &ovar2.inner);
+ ok1(tcon_container_of(&infow, fi2, &ovar2.inner) == &ovar2);
+ ok1(tcon_member_of(&infow, fi2, &ovar2) == &ovar2.inner);
+
+ /* Check handling of NULLs */
+ ok1(tcon_container_of(&info, fi, NULL) == NULL);
+ ok1(tcon_member_of(&info, fi, NULL) == NULL);
+ ok1(tcon_container_of(&infow, fi, NULL) == NULL);
+ ok1(tcon_member_of(&infow, fi, NULL) == NULL);
+
+ return 0;
+}
--
2.4.3
_______________________________________________
ccan mailing list
ccan@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/ccan
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCHv2 5/6] lstack: Streamline interface with TCON_CONTAINER
2015-10-22 6:47 [PATCHv2 0/6] tcon extensions for easier typesafe wrapping David Gibson
` (3 preceding siblings ...)
2015-10-22 6:47 ` [PATCHv2 4/6] tcon: Encode information on container members in " David Gibson
@ 2015-10-22 6:47 ` David Gibson
2015-10-22 6:47 ` [PATCHv2 6/6] lqueue: " David Gibson
5 siblings, 0 replies; 9+ messages in thread
From: David Gibson @ 2015-10-22 6:47 UTC (permalink / raw)
To: ccan
The interfaces the lstack module currently has implement (partial) type
safety in a somewhat clunk way - types and member names need to be passed
to a number of entry points.
This patch uses the new TCON_CONTAINER magic to stash the typing
information into the declaration of the stack object, so it no longer needs
to be explicitly passed to later calls.
This does alter the lstack interface incompatibly. I think the module
is young enough that we can reasonably do that. One other module,
'aga', was using lstack, and this also includes fixes so that it still
works.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
ccan/aga/dfs.c | 18 ++++---
ccan/lstack/_info | 8 +--
ccan/lstack/lstack.h | 141 ++++++++++++++++++++++++++++---------------------
ccan/lstack/test/run.c | 31 +++++------
4 files changed, 111 insertions(+), 87 deletions(-)
diff --git a/ccan/aga/dfs.c b/ccan/aga/dfs.c
index 638481c..5f836ec 100644
--- a/ccan/aga/dfs.c
+++ b/ccan/aga/dfs.c
@@ -12,25 +12,27 @@
* Depth first search
*/
-static bool dfs_push(struct aga_graph *g, struct lstack *stack,
+typedef LSTACK(struct aga_node, u.dfs.parent) dfs_stack;
+
+static bool dfs_push(struct aga_graph *g, dfs_stack *stack,
struct aga_node *n)
{
if (!aga_update_node(g, n))
return false;
- lstack_push(stack, n, u.dfs.parent);
+ lstack_push(stack, n);
n->u.dfs.edge = aga_first_edge(g, n);
return true;
}
-static void dfs_pop(struct lstack *stack)
+static void dfs_pop(dfs_stack *stack)
{
- lstack_pop(stack, struct aga_node, u.dfs.parent);
+ lstack_pop(stack);
}
-static struct aga_node *dfs_top(struct lstack *stack)
+static struct aga_node *dfs_top(dfs_stack *stack)
{
- return lstack_top(stack, struct aga_node, u.dfs.parent);
+ return lstack_top(stack);
}
int aga_dfs_start(struct aga_graph *g)
@@ -46,7 +48,7 @@ int aga_dfs_start(struct aga_graph *g)
struct aga_node *aga_dfs_explore(struct aga_graph *g, struct aga_node *n)
{
- LSTACK(stack);
+ dfs_stack stack = LSTACK_INIT;
if (!aga_check_state(g))
return NULL;
@@ -57,7 +59,7 @@ struct aga_node *aga_dfs_explore(struct aga_graph *g, struct aga_node *n)
if (dfs_push(g, &stack, n))
return n;
- lstack_init_from_top(&stack, n, u.dfs.parent);
+ lstack_init_from_top(&stack, n);
while ((n = dfs_top(&stack))) {
const void *e = n->u.dfs.edge;
diff --git a/ccan/lstack/_info b/ccan/lstack/_info
index 5b270bc..21fe3c7 100644
--- a/ccan/lstack/_info
+++ b/ccan/lstack/_info
@@ -23,18 +23,18 @@
* {
* int i;
* struct arg *a;
- * LSTACK(argstack);
+ * LSTACK(struct arg, sl) argstack;
*
* for (i = 0; i < argc; i++) {
* a = malloc(sizeof(*a));
* a->arg = argv[i];
- * lstack_push(&argstack, a, sl);
+ * lstack_push(&argstack, a);
* }
*
* printf("Command line arguments in reverse:\n");
*
* while (!lstack_empty(&argstack)) {
- * a = lstack_pop(&argstack, struct arg, sl);
+ * a = lstack_pop(&argstack);
* printf("Argument: %s\n", a->arg);
* free(a);
* }
@@ -49,7 +49,7 @@ int main(int argc, char *argv[])
return 1;
if (strcmp(argv[1], "depends") == 0) {
- printf("ccan/container_of\n");
+ printf("ccan/tcon\n");
return 0;
}
diff --git a/ccan/lstack/lstack.h b/ccan/lstack/lstack.h
index 7eb880a..ef910bd 100644
--- a/ccan/lstack/lstack.h
+++ b/ccan/lstack/lstack.h
@@ -6,7 +6,7 @@
#include <stdio.h>
#include <assert.h>
-#include <ccan/container_of/container_of.h>
+#include <ccan/tcon/tcon.h>
/**
* struct lstack_link - a stack link
@@ -25,36 +25,75 @@ struct lstack_link {
};
/**
- * struct lstack - a stack
+ * struct lstack_ - a stack (internal type)
* @b: the top of the stack (NULL if empty)
*/
-struct lstack {
+struct lstack_ {
struct lstack_link *top;
};
/**
- * LSTACK - define and initialize an empty stack
- * @name: the name of the lstack.
+ * LSTACK - declare a stack
+ * @type: the type of elements in the stack
+ * @link: the field containing the lstack_link in @type
*
- * The LSTACK macro defines an lstack and initializes it to an empty
- * stack. It can be prepended by "static" to define a static lstack.
+ * The LSTACK macro declares an lstack. It can be prepended by
+ * "static" to define a static lstack. The stack begins in undefined
+ * state, you must either initialize with LSTACK_INIT, or call
+ * lstack_init() before using it.
*
* See also:
* lstack_init()
*
* Example:
- * LSTACK(my_stack);
+ * struct element {
+ * int value;
+ * struct lstack_link link;
+ * };
+ * LSTACK(struct element, link) my_stack;
+ */
+#define LSTACK(etype, link) \
+ TCON_WRAP(struct lstack_, \
+ TCON_CONTAINER(canary, etype, link))
+
+/**
+ * LSTACK_INIT - initializer for an empty stack
+ *
+ * The LSTACK_INIT macro returns a suitable initializer for a stack
+ * defined with LSTACK.
+ *
+ * Example:
+ * struct element {
+ * int value;
+ * struct lstack_link link;
+ * };
+ * LSTACK(struct element, link) my_stack = LSTACK_INIT;
*
* assert(lstack_empty(&my_stack));
*/
-#define LSTACK(name) \
- struct lstack name = { NULL, }
+#define LSTACK_INIT \
+ TCON_WRAP_INIT({ NULL, })
+
+/**
+ * lstack_entry - convert an lstack_link back into the structure containing it.
+ * @s: the stack
+ * @l: the lstack_link
+ *
+ * Example:
+ * struct element {
+ * int value;
+ * struct lstack_link link;
+ * } e;
+ * LSTACK(struct element, link) my_stack;
+ * assert(lstack_entry(&my_stack, &e.link) == &e);
+ */
+#define lstack_entry(s_, l_) tcon_container_of((s_), canary, (l_))
+
/**
* lstack_init_from_top - initialize a stack with a given top element
* @s: the lstack to initialize
* @e: pointer to the top element of the new stack
- * @member: member of the element containing the lstack_link
*
* USE WITH CAUTION: This is for handling unusual cases where you have
* a pointer to an element in a previously constructed stack but can't
@@ -62,32 +101,35 @@ struct lstack {
* should use lstack_init().
*
* Example:
- * LSTACK(stack1);
- * struct lstack stack2;
* struct element {
* int value;
* struct lstack_link link;
- * } el;
+ * } e;
+ * LSTACK(struct element, link) stack1 = LSTACK_INIT;
+ * LSTACK(struct element, link) stack2;
*
- * lstack_push(&stack1, &el, link);
+ * lstack_push(&stack1, &e);
*
- * lstack_init_from_top(&stack2,
- * lstack_top(&stack1, struct element, link), link);
+ * lstack_init_from_top(&stack2, lstack_top(&stack1));
*/
-#define lstack_init_from_top(s, e, member) \
- (lstack_init_((s), &(e)->member))
+#define lstack_init_from_top(s_, e_) \
+ (lstack_init_(tcon_unwrap(s_), tcon_member_of((s_), canary, (e_))))
/**
* lstack_init - initialize a stack
* @h: the lstack to set to an empty stack
*
* Example:
- * struct lstack *sp = malloc(sizeof(*sp));
+ * struct element {
+ * int value;
+ * struct lstack_link link;
+ * };
+ * LSTACK(struct element, link) *sp = malloc(sizeof(*sp));
* lstack_init(sp);
*/
-#define lstack_init(s) \
- (lstack_init_((s), NULL))
-static inline void lstack_init_(struct lstack *s, struct lstack_link *top)
+#define lstack_init(s_) \
+ (lstack_init_(tcon_unwrap(s_), NULL))
+static inline void lstack_init_(struct lstack_ *s, struct lstack_link *top)
{
s->top = top;
}
@@ -97,47 +139,29 @@ static inline void lstack_init_(struct lstack *s, struct lstack_link *top)
* @s: the stack
*
* If the stack is empty, returns true.
- *
- * Example:
- * assert(lstack_empty(sp));
*/
-static inline bool lstack_empty(const struct lstack *s)
+#define lstack_empty(s_) \
+ lstack_empty_(tcon_unwrap(s_))
+static inline bool lstack_empty_(const struct lstack_ *s)
{
return (s->top == NULL);
}
/**
- * lstack_entry - convert an lstack_link back into the structure containing it.
- * @e: the lstack_link
- * @type: the type of the entry
- * @member: the lstack_link member of the type
- *
- * Example:
- * struct stacker {
- * char *name;
- * struct lstack_link sl;
- * } st;
- * assert(lstack_entry(&st.sl, struct stacker, sl) == &st);
- */
-#define lstack_entry(n, type, member) container_of_or_null(n, type, member)
-
-/**
* lstack_top - get top entry in a stack
* @s: the stack
- * @type: the type of stack entries
- * @member: the lstack_link entry
*
* If the stack is empty, returns NULL.
*
* Example:
- * struct stacker *t;
+ * struct element *t;
*
- * t = lstack_top(sp, struct stacker, sl);
- * assert(lstack_pop(sp, struct stacker, sl) == t);
+ * t = lstack_top(sp);
+ * assert(lstack_pop(sp) == t);
*/
-#define lstack_top(s, type, member) \
- lstack_entry(lstack_top_((s)), type, member)
-static inline struct lstack_link *lstack_top_(const struct lstack *s)
+#define lstack_top(s_) \
+ lstack_entry((s_), lstack_top_(tcon_unwrap(s_)))
+static inline struct lstack_link *lstack_top_(const struct lstack_ *s)
{
return s->top;
}
@@ -146,13 +170,12 @@ static inline struct lstack_link *lstack_top_(const struct lstack *s)
* lstack_push - add an entry to the top of the stack
* @s: the stack to add the node to
* @e: the item to push
- * @member: the lstack_link field of *e
*
* The lstack_link does not need to be initialized; it will be overwritten.
*/
-#define lstack_push(s, e, member) \
- lstack_push_((s), &((e)->member))
-static inline void lstack_push_(struct lstack *s, struct lstack_link *e)
+#define lstack_push(s_, e_) \
+ lstack_push_(tcon_unwrap(s_), tcon_member_of((s_), canary, (e_)))
+static inline void lstack_push_(struct lstack_ *s, struct lstack_link *e)
{
e->down = lstack_top_(s);
s->top = e;
@@ -161,19 +184,17 @@ static inline void lstack_push_(struct lstack *s, struct lstack_link *e)
/**
* lstack_pop - remove and return the entry from the top of the stack
* @s: the stack
- * @type: the type of stack entries
- * @member: the lstack_link field of @type
*
* Note that this leaves the returned entry's link in an undefined
* state; it can be added to another stack, but not deleted again.
*/
-#define lstack_pop(s, type, member) \
- lstack_entry(lstack_pop_((s)), type, member)
-static inline struct lstack_link *lstack_pop_(struct lstack *s)
+#define lstack_pop(s_) \
+ lstack_entry((s_), lstack_pop_(tcon_unwrap((s_))))
+static inline struct lstack_link *lstack_pop_(struct lstack_ *s)
{
struct lstack_link *top;
- if (lstack_empty(s))
+ if (lstack_empty_(s))
return NULL;
top = lstack_top_(s);
diff --git a/ccan/lstack/test/run.c b/ccan/lstack/test/run.c
index d67ba32..1bc7175 100644
--- a/ccan/lstack/test/run.c
+++ b/ccan/lstack/test/run.c
@@ -10,7 +10,7 @@ struct stacker {
int main(void)
{
- LSTACK(s);
+ LSTACK(struct stacker, sl) s = LSTACK_INIT;
struct stacker a = { "Alice" };
struct stacker b = { "Bob" };
struct stacker c = { "Carol" };
@@ -20,42 +20,43 @@ int main(void)
plan_tests(18);
ok1(lstack_empty(&s));
- ok1(lstack_top(&s, struct stacker, sl) == NULL);
+ diag("top = %p\n", lstack_top(&s));
+ ok1(lstack_top(&s) == NULL);
- lstack_push(&s, &a, sl);
+ lstack_push(&s, &a);
ok1(!lstack_empty(&s));
- ok1(lstack_top(&s, struct stacker, sl) == &a);
+ ok1(lstack_top(&s) == &a);
- lstack_push(&s, &b, sl);
+ lstack_push(&s, &b);
ok1(!lstack_empty(&s));
- ok1(lstack_top(&s, struct stacker, sl) == &b);
+ ok1(lstack_top(&s) == &b);
- lstack_push(&s, &c, sl);
+ lstack_push(&s, &c);
ok1(!lstack_empty(&s));
- ok1(lstack_top(&s, struct stacker, sl) == &c);
+ ok1(lstack_top(&s) == &c);
- stacker = lstack_pop(&s, struct stacker, sl);
+ stacker = lstack_pop(&s);
ok1(stacker == &c);
ok1(!lstack_empty(&s));
- ok1(lstack_top(&s, struct stacker, sl) == &b);
+ ok1(lstack_top(&s) == &b);
- stacker = lstack_pop(&s, struct stacker, sl);
+ stacker = lstack_pop(&s);
ok1(stacker == &b);
ok1(!lstack_empty(&s));
- ok1(lstack_top(&s, struct stacker, sl) == &a);
+ ok1(lstack_top(&s) == &a);
- stacker = lstack_pop(&s, struct stacker, sl);
+ stacker = lstack_pop(&s);
ok1(stacker == &a);
ok1(lstack_empty(&s));
- ok1(lstack_top(&s, struct stacker, sl) == NULL);
+ ok1(lstack_top(&s) == NULL);
- ok1(lstack_pop(&s, struct stacker, sl) == NULL);
+ ok1(lstack_pop(&s) == NULL);
/* This exits depending on whether all tests passed */
return exit_status();
--
2.4.3
_______________________________________________
ccan mailing list
ccan@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/ccan
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCHv2 6/6] lqueue: Streamline interface with TCON_CONTAINER
2015-10-22 6:47 [PATCHv2 0/6] tcon extensions for easier typesafe wrapping David Gibson
` (4 preceding siblings ...)
2015-10-22 6:47 ` [PATCHv2 5/6] lstack: Streamline interface with TCON_CONTAINER David Gibson
@ 2015-10-22 6:47 ` David Gibson
5 siblings, 0 replies; 9+ messages in thread
From: David Gibson @ 2015-10-22 6:47 UTC (permalink / raw)
To: ccan
The interfaces the lqueue module currently has implement (partial) type
safety in a somewhat clunky way - types and member names need to be passed
to a number of entry points.
This patch uses the new TCON_CONTAINER magic to stash the typing
information into the declaration of the queue object, so it no longer needs
to be explicitly passed to later calls.
This does alter the lqueue interface incompatibly. I think the module
is young enough that we can reasonably do that. One other module,
'aga', was using lqueue, and this also includes fixes so that it still
works.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
ccan/aga/bfs.c | 18 +++---
ccan/lqueue/_info | 8 +--
ccan/lqueue/lqueue.h | 154 +++++++++++++++++++++++++++----------------------
ccan/lqueue/test/run.c | 44 +++++++-------
4 files changed, 122 insertions(+), 102 deletions(-)
diff --git a/ccan/aga/bfs.c b/ccan/aga/bfs.c
index 01eb851..64fdd48 100644
--- a/ccan/aga/bfs.c
+++ b/ccan/aga/bfs.c
@@ -12,25 +12,27 @@
* Breadth first search
*/
-static bool bfs_enqueue(struct aga_graph *g, struct lqueue *queue,
+typedef LQUEUE(struct aga_node, u.bfs.next) bfs_queue;
+
+static bool bfs_enqueue(struct aga_graph *g, bfs_queue *queue,
struct aga_node *n)
{
if (!aga_update_node(g, n))
return false;
- lqueue_enqueue(queue, n, u.bfs.next);
+ lqueue_enqueue(queue, n);
n->u.bfs.edge = aga_first_edge(g, n);
return true;
}
-static struct aga_node *bfs_front(struct lqueue *queue)
+static struct aga_node *bfs_front(bfs_queue *queue)
{
- return lqueue_front(queue, struct aga_node, u.bfs.next);
+ return lqueue_front(queue);
}
-static void bfs_dequeue(struct lqueue *queue)
+static void bfs_dequeue(bfs_queue *queue)
{
- lqueue_dequeue(queue, struct aga_node, u.bfs.next);
+ lqueue_dequeue(queue);
}
int aga_bfs_start(struct aga_graph *g)
@@ -46,7 +48,7 @@ int aga_bfs_start(struct aga_graph *g)
struct aga_node *aga_bfs_explore(struct aga_graph *g, struct aga_node *n)
{
- LQUEUE(queue);
+ bfs_queue queue = LQUEUE_INIT;
if (!aga_check_state(g))
return NULL;
@@ -57,7 +59,7 @@ struct aga_node *aga_bfs_explore(struct aga_graph *g, struct aga_node *n)
if (bfs_enqueue(g, &queue, n))
return n;
- lqueue_init_from_back(&queue, n, u.bfs.next);
+ lqueue_init_from_back(&queue, n);
while ((n = bfs_front(&queue))) {
const void *e = n->u.bfs.edge;
diff --git a/ccan/lqueue/_info b/ccan/lqueue/_info
index 4d7c6a4..d6b6232 100644
--- a/ccan/lqueue/_info
+++ b/ccan/lqueue/_info
@@ -23,18 +23,18 @@
* {
* int i;
* struct arg *a;
- * LQUEUE(argq);
+ * LQUEUE(struct arg, ql) argq = LQUEUE_INIT;
*
* for (i = 0; i < argc; i++) {
* a = malloc(sizeof(*a));
* a->arg = argv[i];
- * lqueue_enqueue(&argq, a, ql);
+ * lqueue_enqueue(&argq, a);
* }
*
* printf("Command line arguments in order:\n");
*
* while (!lqueue_empty(&argq)) {
- * a = lqueue_dequeue(&argq, struct arg, ql);
+ * a = lqueue_dequeue(&argq);
* printf("Argument: %s\n", a->arg);
* free(a);
* }
@@ -49,7 +49,7 @@ int main(int argc, char *argv[])
return 1;
if (strcmp(argv[1], "depends") == 0) {
- printf("ccan/container_of\n");
+ printf("ccan/tcon\n");
return 0;
}
diff --git a/ccan/lqueue/lqueue.h b/ccan/lqueue/lqueue.h
index 1af5847..cff51bb 100644
--- a/ccan/lqueue/lqueue.h
+++ b/ccan/lqueue/lqueue.h
@@ -6,7 +6,7 @@
#include <stdio.h>
#include <assert.h>
-#include <ccan/container_of/container_of.h>
+#include <ccan/tcon/tcon.h>
/**
* struct lqueue_link - a queue link
@@ -25,36 +25,74 @@ struct lqueue_link {
};
/**
- * struct lqueue - the head of a queue
+ * struct lqueue_ - a queue (internal type)
* @b: the back of the queue (NULL if empty)
*/
-struct lqueue {
+struct lqueue_ {
struct lqueue_link *back;
};
/**
- * LQUEUE - define and initialize an empty queue
- * @name: the name of the lqueue.
+ * LQUEUE - declare a queue
+ * @type: the type of elements in the queue
+ * @link: the field containing the lqueue_link in @type
*
- * The LQUEUE macro defines an lqueue and initializes it to an empty
- * queue. It can be prepended by "static" to define a static lqueue.
+ * The LQUEUE macro declares an lqueue. It can be prepended by
+ * "static" to define a static lqueue. The queue begins in undefined
+ * state, you must either initialize with LQUEUE_INIT, or call
+ * lqueue_init() before using it.
*
* See also:
* lqueue_init()
*
* Example:
- * LQUEUE(my_queue);
+ * struct element {
+ * int value;
+ * struct lqueue_link link;
+ * };
+ * LQUEUE(struct element, link) my_queue;
+ */
+#define LQUEUE(etype, link) \
+ TCON_WRAP(struct lqueue_, \
+ TCON_CONTAINER(canary, etype, link))
+
+/**
+ * LQUEUE_INIT - initializer for an empty queue
+ *
+ * The LQUEUE_INIT macro returns a suitable initializer for a queue
+ * defined with LQUEUE.
+ *
+ * Example:
+ * struct element {
+ * int value;
+ * struct lqueue_link link;
+ * };
+ * LQUEUE(struct element, link) my_queue = LQUEUE_INIT;
*
* assert(lqueue_empty(&my_queue));
*/
-#define LQUEUE(name) \
- struct lqueue name = { NULL, }
+#define LQUEUE_INIT \
+ TCON_WRAP_INIT({ NULL, })
+
+/**
+ * lqueue_entry - convert an lqueue_link back into the structure containing it.
+ * @q: the queue
+ * @l: the lqueue_link
+ *
+ * Example:
+ * struct waiter {
+ * char *name;
+ * struct lqueue_link ql;
+ * } w;
+ * LQUEUE(struct waiter, ql) my_queue;
+ * assert(lqueue_entry(&my_queue, &w.ql) == &w);
+ */
+#define lqueue_entry(q_, l_) tcon_container_of((q_), canary, (l_))
/**
* lqueue_init_from_back - initialize a queue with a specific back element
* @s: the lqueue to initialize
* @e: pointer to the back element of the new queue
- * @member: member of the element containing the lqueue_link
*
* USE WITH CAUTION: This is for handling unusual cases where you have
* a pointer to an element in a previously constructed queue but can't
@@ -62,32 +100,35 @@ struct lqueue {
* should use lqueue_init().
*
* Example:
- * LQUEUE(queue1);
- * struct lqueue queue2;
* struct element {
* int value;
* struct lqueue_link link;
* } el;
+ * LQUEUE(struct element, link) queue1;
+ * LQUEUE(struct element, link) queue2;
*
- * lqueue_enqueue(&queue1, &el, link);
+ * lqueue_enqueue(&queue1, &el);
*
- * lqueue_init_from_back(&queue2,
- * lqueue_back(&queue1, struct element, link), link);
+ * lqueue_init_from_back(&queue2, lqueue_back(&queue1));
*/
-#define lqueue_init_from_back(s, e, member) \
- (lqueue_init_((s), &(e)->member))
+#define lqueue_init_from_back(q_, e_) \
+ (lqueue_init_(tcon_unwrap(q_), tcon_member_of((q_), canary, (e_))))
/**
* lqueue_init - initialize a queue
* @h: the lqueue to set to an empty queue
*
* Example:
- * struct lqueue *qp = malloc(sizeof(*qp));
+ * struct element {
+ * int value;
+ * struct lqueue_link link;
+ * };
+ * LQUEUE(struct element, link) *qp = malloc(sizeof(*qp));
* lqueue_init(qp);
*/
-#define lqueue_init(s) \
- (lqueue_init_((s), NULL))
-static inline void lqueue_init_(struct lqueue *q, struct lqueue_link *back)
+#define lqueue_init(q_) \
+ (lqueue_init_(tcon_unwrap(q_), NULL))
+static inline void lqueue_init_(struct lqueue_ *q, struct lqueue_link *back)
{
q->back = back;
}
@@ -97,47 +138,29 @@ static inline void lqueue_init_(struct lqueue *q, struct lqueue_link *back)
* @q: the queue
*
* If the queue is empty, returns true.
- *
- * Example:
- * assert(lqueue_empty(qp));
*/
-static inline bool lqueue_empty(const struct lqueue *q)
+#define lqueue_empty(q_) \
+ lqueue_empty_(tcon_unwrap(q_))
+static inline bool lqueue_empty_(const struct lqueue_ *q)
{
return (q->back == NULL);
}
/**
- * lqueue_entry - convert an lqueue_link back into the structure containing it.
- * @e: the lqueue_link
- * @type: the type of the entry
- * @member: the lqueue_link member of the type
- *
- * Example:
- * struct waiter {
- * char *name;
- * struct lqueue_link ql;
- * } w;
- * assert(lqueue_entry(&w.ql, struct waiter, ql) == &w);
- */
-#define lqueue_entry(n, type, member) container_of_or_null(n, type, member)
-
-/**
* lqueue_front - get front entry in a queue
* @q: the queue
- * @type: the type of queue entries
- * @member: the lqueue_link entry
*
* If the queue is empty, returns NULL.
*
* Example:
- * struct waiter *f;
+ * struct element *f;
*
- * f = lqueue_front(qp, struct waiter, ql);
- * assert(lqueue_dequeue(qp, struct waiter, ql) == f);
+ * f = lqueue_front(qp);
+ * assert(lqueue_dequeue(qp) == f);
*/
-#define lqueue_front(q, type, member) \
- lqueue_entry(lqueue_front_((q)), type, member)
-static inline struct lqueue_link *lqueue_front_(const struct lqueue *q)
+#define lqueue_front(q_) \
+ lqueue_entry((q_), lqueue_front_(tcon_unwrap(q_)))
+static inline struct lqueue_link *lqueue_front_(const struct lqueue_ *q)
{
if (!q->back)
return NULL;
@@ -148,20 +171,18 @@ static inline struct lqueue_link *lqueue_front_(const struct lqueue *q)
/**
* lqueue_back - get back entry in a queue
* @q: the queue
- * @type: the type of queue entries
- * @member: the lqueue_link entry
*
* If the queue is empty, returns NULL.
*
* Example:
- * struct waiter b;
+ * struct element b;
*
- * lqueue_enqueue(qp, &b, ql);
- * assert(lqueue_back(qp, struct waiter, ql) == &b);
+ * lqueue_enqueue(qp, &b);
+ * assert(lqueue_back(qp) == &b);
*/
-#define lqueue_back(q, type, member) \
- lqueue_entry(lqueue_back_((q)), type, member)
-static inline struct lqueue_link *lqueue_back_(const struct lqueue *q)
+#define lqueue_back(q_) \
+ lqueue_entry((q_), lqueue_back_(tcon_unwrap(q_)))
+static inline struct lqueue_link *lqueue_back_(const struct lqueue_ *q)
{
return q->back;
}
@@ -170,15 +191,14 @@ static inline struct lqueue_link *lqueue_back_(const struct lqueue *q)
* lqueue_enqueue - add an entry to the back of a queue
* @q: the queue to add the node to
* @e: the item to enqueue
- * @member: the lqueue_link field of *e
*
* The lqueue_link does not need to be initialized; it will be overwritten.
*/
-#define lqueue_enqueue(q, e, member) \
- lqueue_enqueue_((q), &((e)->member))
-static inline void lqueue_enqueue_(struct lqueue *q, struct lqueue_link *e)
+#define lqueue_enqueue(q_, e_) \
+ lqueue_enqueue_(tcon_unwrap(q_), tcon_member_of((q_), canary, (e_)))
+static inline void lqueue_enqueue_(struct lqueue_ *q, struct lqueue_link *e)
{
- if (lqueue_empty(q)) {
+ if (lqueue_empty_(q)) {
/* New entry will be both front and back of queue */
e->next = e;
q->back = e;
@@ -192,19 +212,17 @@ static inline void lqueue_enqueue_(struct lqueue *q, struct lqueue_link *e)
/**
* lqueue_dequeue - remove and return the entry from the front of the queue
* @q: the queue
- * @type: the type of queue entries
- * @member: the lqueue_link field of @type
*
* Note that this leaves the returned entry's link in an undefined
* state; it can be added to another queue, but not deleted again.
*/
-#define lqueue_dequeue(q, type, member) \
- lqueue_entry(lqueue_dequeue_((q)), type, member)
-static inline struct lqueue_link *lqueue_dequeue_(struct lqueue *q)
+#define lqueue_dequeue(q_) \
+ lqueue_entry((q_), lqueue_dequeue_(tcon_unwrap(q_)))
+static inline struct lqueue_link *lqueue_dequeue_(struct lqueue_ *q)
{
struct lqueue_link *front;
- if (lqueue_empty(q))
+ if (lqueue_empty_(q))
return NULL;
front = lqueue_front_(q);
diff --git a/ccan/lqueue/test/run.c b/ccan/lqueue/test/run.c
index b10b4cd..6791d25 100644
--- a/ccan/lqueue/test/run.c
+++ b/ccan/lqueue/test/run.c
@@ -10,7 +10,7 @@ struct waiter {
int main(void)
{
- LQUEUE(q);
+ LQUEUE(struct waiter, ql) q = LQUEUE_INIT;
struct waiter a = { "Alice" };
struct waiter b = { "Bob" };
struct waiter c = { "Carol" };
@@ -20,49 +20,49 @@ int main(void)
plan_tests(25);
ok1(lqueue_empty(&q));
- ok1(lqueue_front(&q, struct waiter, ql) == NULL);
- ok1(lqueue_back(&q, struct waiter, ql) == NULL);
+ ok1(lqueue_front(&q) == NULL);
+ ok1(lqueue_back(&q) == NULL);
- lqueue_enqueue(&q, &a, ql);
+ lqueue_enqueue(&q, &a);
ok1(!lqueue_empty(&q));
- ok1(lqueue_front(&q, struct waiter, ql) == &a);
- ok1(lqueue_back(&q, struct waiter, ql) == &a);
+ ok1(lqueue_front(&q) == &a);
+ ok1(lqueue_back(&q) == &a);
- lqueue_enqueue(&q, &b, ql);
+ lqueue_enqueue(&q, &b);
ok1(!lqueue_empty(&q));
- ok1(lqueue_front(&q, struct waiter, ql) == &a);
- ok1(lqueue_back(&q, struct waiter, ql) == &b);
+ ok1(lqueue_front(&q) == &a);
+ ok1(lqueue_back(&q) == &b);
- lqueue_enqueue(&q, &c, ql);
+ lqueue_enqueue(&q, &c);
ok1(!lqueue_empty(&q));
- ok1(lqueue_front(&q, struct waiter, ql) == &a);
- ok1(lqueue_back(&q, struct waiter, ql) == &c);
+ ok1(lqueue_front(&q) == &a);
+ ok1(lqueue_back(&q) == &c);
- waiter = lqueue_dequeue(&q, struct waiter, ql);
+ waiter = lqueue_dequeue(&q);
ok1(waiter == &a);
ok1(!lqueue_empty(&q));
- ok1(lqueue_front(&q, struct waiter, ql) == &b);
- ok1(lqueue_back(&q, struct waiter, ql) == &c);
+ ok1(lqueue_front(&q) == &b);
+ ok1(lqueue_back(&q) == &c);
- waiter = lqueue_dequeue(&q, struct waiter, ql);
+ waiter = lqueue_dequeue(&q);
ok1(waiter == &b);
ok1(!lqueue_empty(&q));
- ok1(lqueue_front(&q, struct waiter, ql) == &c);
- ok1(lqueue_back(&q, struct waiter, ql) == &c);
+ ok1(lqueue_front(&q) == &c);
+ ok1(lqueue_back(&q) == &c);
- waiter = lqueue_dequeue(&q, struct waiter, ql);
+ waiter = lqueue_dequeue(&q);
ok1(waiter == &c);
ok1(lqueue_empty(&q));
- ok1(lqueue_front(&q, struct waiter, ql) == NULL);
- ok1(lqueue_back(&q, struct waiter, ql) == NULL);
+ ok1(lqueue_front(&q) == NULL);
+ ok1(lqueue_back(&q) == NULL);
- ok1(lqueue_dequeue(&q, struct waiter, ql) == NULL);
+ ok1(lqueue_dequeue(&q) == NULL);
/* This exits depending on whether all tests passed */
return exit_status();
--
2.4.3
_______________________________________________
ccan mailing list
ccan@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/ccan
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCHv2 3/6] tcon: Encode integer values into "type" canaries
2015-10-22 6:47 ` [PATCHv2 3/6] tcon: Encode integer values into "type" canaries David Gibson
@ 2015-10-27 3:11 ` Rusty Russell
2015-10-27 6:17 ` David Gibson
0 siblings, 1 reply; 9+ messages in thread
From: Rusty Russell @ 2015-10-27 3:11 UTC (permalink / raw)
To: David Gibson, ccan
David Gibson <david@gibson.dropbear.id.au> writes:
> Add the ability to encode, as well as types, integer values (must be
> positive, compile time constant and in the range of size_t) into TCON
> constructed "type" canaries.
Oh, wow.
That is clever!
Please apply this series.
Thanks!
Rusty.
_______________________________________________
ccan mailing list
ccan@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/ccan
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCHv2 3/6] tcon: Encode integer values into "type" canaries
2015-10-27 3:11 ` Rusty Russell
@ 2015-10-27 6:17 ` David Gibson
0 siblings, 0 replies; 9+ messages in thread
From: David Gibson @ 2015-10-27 6:17 UTC (permalink / raw)
To: Rusty Russell; +Cc: ccan
[-- Attachment #1.1: Type: text/plain, Size: 619 bytes --]
On Tue, Oct 27, 2015 at 01:41:38PM +1030, Paul 'Rusty' Russell wrote:
> David Gibson <david@gibson.dropbear.id.au> writes:
> > Add the ability to encode, as well as types, integer values (must be
> > positive, compile time constant and in the range of size_t) into TCON
> > constructed "type" canaries.
>
> Oh, wow.
>
> That is clever!
>
> Please apply this series.
I thought you'd like it :).
Applied.
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
[-- Attachment #2: Type: text/plain, Size: 127 bytes --]
_______________________________________________
ccan mailing list
ccan@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/ccan
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2015-10-27 6:47 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-10-22 6:47 [PATCHv2 0/6] tcon extensions for easier typesafe wrapping David Gibson
2015-10-22 6:47 ` [PATCHv2 1/6] tcon: Add an alternate way of building type canaries David Gibson
2015-10-22 6:47 ` [PATCHv2 2/6] tcon: Add tcon_sizeof() helper David Gibson
2015-10-22 6:47 ` [PATCHv2 3/6] tcon: Encode integer values into "type" canaries David Gibson
2015-10-27 3:11 ` Rusty Russell
2015-10-27 6:17 ` David Gibson
2015-10-22 6:47 ` [PATCHv2 4/6] tcon: Encode information on container members in " David Gibson
2015-10-22 6:47 ` [PATCHv2 5/6] lstack: Streamline interface with TCON_CONTAINER David Gibson
2015-10-22 6:47 ` [PATCHv2 6/6] lqueue: " David Gibson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox