]> git.ozlabs.org Git - ccan/blobdiff - ccan/list/list.h
container_of: don't put member_ptr in container_off.
[ccan] / ccan / list / list.h
index bda2922bc37b7b8dc22ec5482b5e6d75513c1eb7..5c9aa2a689ca38af5a03c5c7c928381bf7b3c443 100644 (file)
@@ -4,6 +4,7 @@
 #include <stdbool.h>
 #include <assert.h>
 #include <ccan/container_of/container_of.h>
+#include <ccan/check_type/check_type.h>
 
 /**
  * struct list_node - an entry in a doubly-linked list
@@ -279,8 +280,15 @@ static inline void list_del_from(struct list_head *h, struct list_node *n)
  *     struct child *first;
  *     first = list_top(&parent->children, struct child, list);
  */
-#define list_top(h, type, member) \
-       (list_empty(h) ? NULL : list_entry((h)->n.next, type, member))
+#define list_top(h, type, member)                                      \
+       ((type *)list_top_((h), list_off_(type, member)))
+
+static inline const void *list_top_(const struct list_head *h, size_t off)
+{
+       if (list_empty(h))
+               return NULL;
+       return (const char *)h->n.next - off;
+}
 
 /**
  * list_tail - get the last entry in a list
@@ -295,11 +303,18 @@ static inline void list_del_from(struct list_head *h, struct list_node *n)
  *     last = list_tail(&parent->children, struct child, list);
  */
 #define list_tail(h, type, member) \
-       (list_empty(h) ? NULL : list_entry((h)->n.prev, type, member))
+       ((type *)list_tail_((h), list_off_(type, member)))
+
+static inline const void *list_tail_(const struct list_head *h, size_t off)
+{
+       if (list_empty(h))
+               return NULL;
+       return (const char *)h->n.prev - off;
+}
 
 /**
  * list_for_each - iterate through a list.
- * @h: the list_head
+ * @h: the list_head (warning: evaluated multiple times!)
  * @i: the structure containing the list_node
  * @member: the list_node member of the structure
  *
@@ -356,4 +371,10 @@ static inline void list_del_from(struct list_head *h, struct list_node *n)
                nxt = container_of_var(i->member.next, i, member);      \
             &i->member != &(h)->n;                                     \
             i = nxt, nxt = container_of_var(i->member.next, i, member))
+
+/* Get the offset of the member, but make sure it's a list_node. */
+#define list_off_(type, member)                                        \
+       (container_off(type, member) +                          \
+        check_type(((type *)0)->member, struct list_node))
+
 #endif /* CCAN_LIST_H */