]> git.ozlabs.org Git - ccan/blobdiff - ccan/tlist/tlist.h
tlist: Use TCON_WRAP instead of TCON
[ccan] / ccan / tlist / tlist.h
index 7e43fe29ee8a8ed664374ec8b59ca82376f988f1..37882ee7bbdcc62f0eaa38097a3c9b66eacc05fa 100644 (file)
@@ -2,24 +2,25 @@
 #ifndef CCAN_TLIST_H
 #define CCAN_TLIST_H
 #include <ccan/list/list.h>
+#include <ccan/tcon/tcon.h>
 
-#if HAVE_FLEXIBLE_ARRAY_MEMBER
 /**
  * TLIST_TYPE - declare a typed list type (struct tlist)
  * @suffix: the name to use (struct tlist_@suffix)
  * @type: the type the list will contain (void for any type)
  *
- * This declares a structure "struct tlist_@suffix" to use for
- * lists containing this type.  The actual list can be accessed using
- * ".raw" or tlist_raw().
+ * This declares a structure "struct tlist_@suffix" to use for lists
+ * containing this type.  The actual list can be accessed using
+ * tlist_raw().  For maximum portability, place tlists embedded in
+ * structures as the last member.
  *
  * Example:
  *     // Defines struct tlist_children
  *     TLIST_TYPE(children, struct child);
  *     struct parent {
  *             const char *name;
- *             struct tlist_children children;
  *             unsigned int num_children;
+ *             struct tlist_children children;
  *     };
  *
  *     struct child {
  *             struct list_node list;
  *     };
  */
-#define TLIST_TYPE(suffix, type)                                       \
-       struct tlist_##suffix {                                         \
-               struct list_head raw;                                   \
-               const type *tcheck[];                                   \
+#define TLIST_TYPE(suffix, type)                       \
+       struct tlist_##suffix {                         \
+               TCON_WRAP(struct list_head, type *canary);      \
        }
 
-/**
- * tlist_raw - access the raw list inside a typed list head.
- * @h: the head of the typed list (struct tlist_@suffix)
- * @test_var: a pointer to the expected element type.
- *
- * This elaborate macro usually causes the compiler to emit a warning
- * if the variable is of an unexpected type.  It is used internally
- * where we need to access the raw underlying list.
- */
-#define tlist_raw(h, test_var) \
-       (sizeof((h)->tcheck[0] == (test_var)) ? &(h)->raw : &(h)->raw)
-#else
-#define TLIST_TYPE(suffix, type)                                       \
-       struct tlist_##suffix {                                         \
-               struct list_head raw;                                   \
-       }
-#define tlist_raw(h, test_var) (&(h)->raw)
-#endif
-
 /**
  * TLIST_INIT - initalizer for an empty tlist
  * @name: the name of the list.
@@ -64,7 +45,7 @@
  * Example:
  *     static struct tlist_children my_list = TLIST_INIT(my_list);
  */
-#define TLIST_INIT(name) { LIST_HEAD_INIT(name.raw) }
+#define TLIST_INIT(name) TCON_WRAP_INIT(LIST_HEAD_INIT(*tcon_unwrap(&name)))
 
 /**
  * tlist_check - check head of a list for consistency
@@ -93,7 +74,7 @@
  *     }
  */
 #define tlist_check(h, abortstr) \
-       list_check(&(h)->raw, (abortstr))
+       list_check(tcon_unwrap(h), (abortstr))
 
 /**
  * tlist_init - initialize a tlist
  *     tlist_init(&parent->children);
  *     parent->num_children = 0;
  */
-#define tlist_init(h) list_head_init(&(h)->raw)
+#define tlist_init(h) list_head_init(tcon_unwrap(h))
+
+/**
+ * tlist_raw - unwrap the typed list and check the type
+ * @h: the tlist
+ * @expr: the expression to check the type against (not evaluated)
+ *
+ * This macro usually causes the compiler to emit a warning if the
+ * variable is of an unexpected type.  It is used internally where we
+ * need to access the raw underlying list.
+ */
+#define tlist_raw(h, expr) tcon_unwrap(tcon_check((h), canary, (expr)))
 
 /**
  * tlist_add - add an entry at the start of a linked list.
  * Example:
  *     assert(tlist_empty(&parent->children) == (parent->num_children == 0));
  */
-#define tlist_empty(h) list_empty(&(h)->raw)
+#define tlist_empty(h) list_empty(tcon_unwrap(h))
 
 /**
  * tlist_top - get the first entry in a list
  * @h: the tlist
- * @type: the type of the entry
  * @member: the list_node member of the type
  *
  * If the list is empty, returns NULL.
  *
  * Example:
  *     struct child *first;
- *     first = tlist_top(&parent->children, struct child, list);
+ *     first = tlist_top(&parent->children, list);
+ *     if (!first)
+ *             printf("Empty list!\n");
  */
-#define tlist_top(h, type, member) \
-       list_top(tlist_raw((h), (type *)NULL), type, member)
+#define tlist_top(h, member)                                           \
+       ((tcon_type((h), canary))                                       \
+        list_top_(tcon_unwrap((h)),                                    \
+                  (char *)(&(h)->_tcon[0].canary->member) -            \
+                  (char *)((h)->_tcon[0].canary)))
 
 /**
  * tlist_tail - get the last entry in a list
  * @h: the tlist
- * @type: the type of the entry
  * @member: the list_node member of the type
  *
  * If the list is empty, returns NULL.
  *
  * Example:
  *     struct child *last;
- *     last = tlist_tail(&parent->children, struct child, list);
+ *     last = tlist_tail(&parent->children, list);
+ *     if (!last)
+ *             printf("Empty list!\n");
+ */
+#define tlist_tail(h, member)                                          \
+       ((tcon_type((h), canary))                                       \
+        list_tail_(tcon_unwrap(h),                                     \
+                   (char *)(&(h)->_tcon[0].canary->member) -           \
+                   (char *)((h)->_tcon[0].canary)))
+
+/**
+ * tlist_next - get the next entry in a list
+ * @h: the tlist
+ * @n: the list element
+ * @member: the list_node member of the type
+ *
+ * Returns the element of list @h immediately after @n, or NULL, if @n
+ * is the last element in the list.
  */
-#define tlist_tail(h, type, member) \
-       list_tail(tlist_raw((h), (type *)NULL), type, member)
+#define tlist_next(h, n, member)                                       \
+       list_next(tlist_raw((h), (n)), (n), member)
+
+/**
+ * tlist_prev - get the previous entry in a list
+ * @h: the tlist
+ * @n: the list element
+ * @member: the list_node member of the type
+ *
+ * Returns the element of list @h immediately before @n, or NULL, if
+ * @n is the first element in the list.
+ */
+#define tlist_prev(h, n, member)                                       \
+       list_prev(tlist_raw((h), (n)), (n), member)
 
 /**
  * tlist_for_each - iterate through a list.
 #define tlist_for_each(h, i, member)                                   \
        list_for_each(tlist_raw((h), (i)), (i), member)
 
+/**
+ * tlist_for_each - iterate through a list backwards.
+ * @h: the tlist
+ * @i: an iterator of suitable type for this list.
+ * @member: the list_node member of @i
+ *
+ * This is a convenient wrapper to iterate @i over the entire list.  It's
+ * a for loop, so you can break and continue as normal.
+ *
+ * Example:
+ *     tlist_for_each_rev(&parent->children, child, list)
+ *             printf("Name: %s\n", child->name);
+ */
+#define tlist_for_each_rev(h, i, member)                                       \
+       list_for_each_rev(tlist_raw((h), (i)), (i), member)
+
 /**
  * tlist_for_each_safe - iterate through a list, maybe during deletion
  * @h: the tlist