summaryrefslogtreecommitdiffstats
path: root/lib/ccan/tlist
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ccan/tlist')
-rw-r--r--lib/ccan/tlist/LICENSE165
-rw-r--r--lib/ccan/tlist/_info74
-rw-r--r--lib/ccan/tlist/test/compile_fail-tlist_add.c35
-rw-r--r--lib/ccan/tlist/test/compile_fail-tlist_add_tail.c35
-rw-r--r--lib/ccan/tlist/test/compile_fail-tlist_del_from.c34
-rw-r--r--lib/ccan/tlist/test/compile_fail-tlist_for_each.c34
-rw-r--r--lib/ccan/tlist/test/compile_fail-tlist_for_each_safe.c33
-rw-r--r--lib/ccan/tlist/test/compile_fail-tlist_tail.c31
-rw-r--r--lib/ccan/tlist/test/compile_fail-tlist_top.c31
-rw-r--r--lib/ccan/tlist/test/run.c147
-rw-r--r--lib/ccan/tlist/tlist.h265
11 files changed, 884 insertions, 0 deletions
diff --git a/lib/ccan/tlist/LICENSE b/lib/ccan/tlist/LICENSE
new file mode 100644
index 0000000000..cca7fc278f
--- /dev/null
+++ b/lib/ccan/tlist/LICENSE
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/lib/ccan/tlist/_info b/lib/ccan/tlist/_info
new file mode 100644
index 0000000000..e18e2efb23
--- /dev/null
+++ b/lib/ccan/tlist/_info
@@ -0,0 +1,74 @@
+#include <stdio.h>
+#include <string.h>
+#include "config.h"
+
+/**
+ * tlist - typesafe double linked list routines
+ *
+ * The list header contains routines for manipulating double linked lists;
+ * this extends it so you can create list head types which only accomodate
+ * a specific entry type.
+ *
+ * Example:
+ * #include <err.h>
+ * #include <stdio.h>
+ * #include <stdlib.h>
+ * #include <ccan/tlist/tlist.h>
+ *
+ * // We could use TLIST_TYPE(children, struct child) to define this.
+ * struct tlist_children {
+ * struct list_head raw;
+ * TCON(struct child *canary);
+ * };
+ * struct parent {
+ * const char *name;
+ * struct tlist_children children;
+ * unsigned int num_children;
+ * };
+ *
+ * struct child {
+ * const char *name;
+ * struct list_node list;
+ * };
+ *
+ * int main(int argc, char *argv[])
+ * {
+ * struct parent p;
+ * struct child *c;
+ * unsigned int i;
+ *
+ * if (argc < 2)
+ * errx(1, "Usage: %s parent children...", argv[0]);
+ *
+ * p.name = argv[1];
+ * tlist_init(&p.children);
+ * for (i = 2; i < argc; i++) {
+ * c = malloc(sizeof(*c));
+ * c->name = argv[i];
+ * tlist_add(&p.children, c, list);
+ * p.num_children++;
+ * }
+ *
+ * printf("%s has %u children:", p.name, p.num_children);
+ * tlist_for_each(&p.children, c, list)
+ * printf("%s ", c->name);
+ * printf("\n");
+ * return 0;
+ * }
+ *
+ * License: LGPL
+ * 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/list\n");
+ printf("ccan/tcon\n");
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/lib/ccan/tlist/test/compile_fail-tlist_add.c b/lib/ccan/tlist/test/compile_fail-tlist_add.c
new file mode 100644
index 0000000000..1b87bfd119
--- /dev/null
+++ b/lib/ccan/tlist/test/compile_fail-tlist_add.c
@@ -0,0 +1,35 @@
+#include <ccan/tlist/tlist.h>
+
+TLIST_TYPE(children, struct child);
+TLIST_TYPE(cousins, struct cousin);
+
+struct child {
+ const char *name;
+ struct list_node list;
+};
+
+struct cousin {
+ const char *name;
+ struct list_node list;
+};
+
+int main(int argc, char *argv[])
+{
+ struct tlist_children children;
+ struct tlist_cousins cousins;
+ struct child child = { "child" };
+ struct cousin cousin = { "cousin" };
+
+ tlist_init(&children);
+ tlist_init(&cousins);
+ tlist_add(&children, &child, list);
+ tlist_add(&cousins, &cousin, list);
+ tlist_del_from(&cousins, &cousin, list);
+#ifdef FAIL
+#if !HAVE_FLEXIBLE_ARRAY_MEMBER
+#error Need flexible array members to check type
+#endif
+ tlist_add(&children, &cousin, list);
+#endif
+ return 0;
+}
diff --git a/lib/ccan/tlist/test/compile_fail-tlist_add_tail.c b/lib/ccan/tlist/test/compile_fail-tlist_add_tail.c
new file mode 100644
index 0000000000..33dff3d8eb
--- /dev/null
+++ b/lib/ccan/tlist/test/compile_fail-tlist_add_tail.c
@@ -0,0 +1,35 @@
+#include <ccan/tlist/tlist.h>
+
+TLIST_TYPE(children, struct child);
+TLIST_TYPE(cousins, struct cousin);
+
+struct child {
+ const char *name;
+ struct list_node list;
+};
+
+struct cousin {
+ const char *name;
+ struct list_node list;
+};
+
+int main(int argc, char *argv[])
+{
+ struct tlist_children children;
+ struct tlist_cousins cousins;
+ struct child child = { "child" };
+ struct cousin cousin = { "cousin" };
+
+ tlist_init(&children);
+ tlist_init(&cousins);
+ tlist_add(&children, &child, list);
+ tlist_add(&cousins, &cousin, list);
+ tlist_del_from(&cousins, &cousin, list);
+#ifdef FAIL
+#if !HAVE_FLEXIBLE_ARRAY_MEMBER
+#error Need flexible array members to check type
+#endif
+ tlist_add_tail(&children, &cousin, list);
+#endif
+ return 0;
+}
diff --git a/lib/ccan/tlist/test/compile_fail-tlist_del_from.c b/lib/ccan/tlist/test/compile_fail-tlist_del_from.c
new file mode 100644
index 0000000000..d06a72fbfa
--- /dev/null
+++ b/lib/ccan/tlist/test/compile_fail-tlist_del_from.c
@@ -0,0 +1,34 @@
+#include <ccan/tlist/tlist.h>
+
+TLIST_TYPE(children, struct child);
+TLIST_TYPE(cousins, struct cousin);
+
+struct child {
+ const char *name;
+ struct list_node list;
+};
+
+struct cousin {
+ const char *name;
+ struct list_node list;
+};
+
+int main(int argc, char *argv[])
+{
+ struct tlist_children children;
+ struct tlist_cousins cousins;
+ struct child child = { "child" };
+ struct cousin cousin = { "cousin" };
+
+ tlist_init(&children);
+ tlist_init(&cousins);
+ tlist_add(&children, &child, list);
+ tlist_add(&cousins, &cousin, list);
+#ifdef FAIL
+#if !HAVE_FLEXIBLE_ARRAY_MEMBER
+#error Need flexible array members to check type
+#endif
+ tlist_del_from(&children, &cousin, list);
+#endif
+ return 0;
+}
diff --git a/lib/ccan/tlist/test/compile_fail-tlist_for_each.c b/lib/ccan/tlist/test/compile_fail-tlist_for_each.c
new file mode 100644
index 0000000000..1b2fb6882f
--- /dev/null
+++ b/lib/ccan/tlist/test/compile_fail-tlist_for_each.c
@@ -0,0 +1,34 @@
+#include <ccan/tlist/tlist.h>
+
+TLIST_TYPE(children, struct child);
+
+struct child {
+ const char *name;
+ struct list_node list;
+};
+
+struct cousin {
+ const char *name;
+ struct list_node list;
+};
+
+int main(int argc, char *argv[])
+{
+ struct tlist_children children;
+ struct child child = { "child" };
+#ifdef FAIL
+#if !HAVE_FLEXIBLE_ARRAY_MEMBER
+#error Need flexible array members to check type
+#endif
+ struct cousin *c;
+#else
+ struct child *c;
+#endif
+
+ tlist_init(&children);
+ tlist_add(&children, &child, list);
+
+ tlist_for_each(&children, c, list)
+ (void) c; /* Suppress unused-but-set-variable warning. */
+ return 0;
+}
diff --git a/lib/ccan/tlist/test/compile_fail-tlist_for_each_safe.c b/lib/ccan/tlist/test/compile_fail-tlist_for_each_safe.c
new file mode 100644
index 0000000000..651c6cefd6
--- /dev/null
+++ b/lib/ccan/tlist/test/compile_fail-tlist_for_each_safe.c
@@ -0,0 +1,33 @@
+#include <ccan/tlist/tlist.h>
+
+TLIST_TYPE(children, struct child);
+
+struct child {
+ const char *name;
+ struct list_node list;
+};
+
+struct cousin {
+ const char *name;
+ struct list_node list;
+};
+
+int main(int argc, char *argv[])
+{
+ struct tlist_children children;
+ struct child child = { "child" };
+#ifdef FAIL
+#if !HAVE_FLEXIBLE_ARRAY_MEMBER
+#error Need flexible array members to check type
+#endif
+ struct cousin *c, *n;
+#else
+ struct child *c, *n;
+#endif
+
+ tlist_init(&children);
+ tlist_add(&children, &child, list);
+
+ tlist_for_each_safe(&children, c, n, list);
+ return 0;
+}
diff --git a/lib/ccan/tlist/test/compile_fail-tlist_tail.c b/lib/ccan/tlist/test/compile_fail-tlist_tail.c
new file mode 100644
index 0000000000..48f394446e
--- /dev/null
+++ b/lib/ccan/tlist/test/compile_fail-tlist_tail.c
@@ -0,0 +1,31 @@
+#include <ccan/tlist/tlist.h>
+
+TLIST_TYPE(children, struct child);
+
+struct child {
+ const char *name;
+ struct list_node list;
+};
+
+struct cousin {
+ const char *name;
+ struct list_node list;
+};
+
+int main(int argc, char *argv[])
+{
+ struct tlist_children children;
+ struct child child = { "child" };
+#ifdef FAIL
+ struct cousin *c;
+#else
+ struct child *c;
+#endif
+
+ tlist_init(&children);
+ tlist_add(&children, &child, list);
+
+ c = tlist_tail(&children, list);
+ (void) c; /* Suppress unused-but-set-variable warning. */
+ return 0;
+}
diff --git a/lib/ccan/tlist/test/compile_fail-tlist_top.c b/lib/ccan/tlist/test/compile_fail-tlist_top.c
new file mode 100644
index 0000000000..21651400ef
--- /dev/null
+++ b/lib/ccan/tlist/test/compile_fail-tlist_top.c
@@ -0,0 +1,31 @@
+#include <ccan/tlist/tlist.h>
+
+TLIST_TYPE(children, struct child);
+
+struct child {
+ const char *name;
+ struct list_node list;
+};
+
+struct cousin {
+ const char *name;
+ struct list_node list;
+};
+
+int main(int argc, char *argv[])
+{
+ struct tlist_children children;
+ struct child child = { "child" };
+#ifdef FAIL
+ struct cousin *c;
+#else
+ struct child *c;
+#endif
+
+ tlist_init(&children);
+ tlist_add(&children, &child, list);
+
+ c = tlist_top(&children, list);
+ (void) c; /* Suppress unused-but-set-variable warning. */
+ return 0;
+}
diff --git a/lib/ccan/tlist/test/run.c b/lib/ccan/tlist/test/run.c
new file mode 100644
index 0000000000..95b02ebe21
--- /dev/null
+++ b/lib/ccan/tlist/test/run.c
@@ -0,0 +1,147 @@
+#define CCAN_LIST_DEBUG 1
+#include <ccan/tlist/tlist.h>
+#include <ccan/tap/tap.h>
+
+TLIST_TYPE(children, struct child);
+
+struct parent {
+ const char *name;
+ struct tlist_children children;
+ unsigned int num_children;
+};
+
+struct child {
+ const char *name;
+ struct list_node list;
+};
+
+int main(int argc, char *argv[])
+{
+ struct parent parent;
+ struct child c1, c2, c3, *c, *n;
+ unsigned int i;
+ struct tlist_children tlist = TLIST_INIT(tlist);
+
+ plan_tests(48);
+ /* Test TLIST_INIT, and tlist_empty */
+ ok1(tlist_empty(&tlist));
+ ok1(tlist_check(&tlist, NULL));
+
+ parent.num_children = 0;
+ tlist_init(&parent.children);
+ /* Test tlist_init */
+ ok1(tlist_empty(&parent.children));
+ ok1(tlist_check(&parent.children, NULL));
+
+ c2.name = "c2";
+ tlist_add(&parent.children, &c2, list);
+ /* Test tlist_add and !tlist_empty. */
+ ok1(!tlist_empty(&parent.children));
+ ok1(c2.list.next == &parent.children.raw.n);
+ ok1(c2.list.prev == &parent.children.raw.n);
+ ok1(parent.children.raw.n.next == &c2.list);
+ ok1(parent.children.raw.n.prev == &c2.list);
+ /* Test tlist_check */
+ ok1(tlist_check(&parent.children, NULL));
+
+ c1.name = "c1";
+ tlist_add(&parent.children, &c1, list);
+ /* Test list_add and !list_empty. */
+ ok1(!tlist_empty(&parent.children));
+ ok1(c2.list.next == &parent.children.raw.n);
+ ok1(c2.list.prev == &c1.list);
+ ok1(parent.children.raw.n.next == &c1.list);
+ ok1(parent.children.raw.n.prev == &c2.list);
+ ok1(c1.list.next == &c2.list);
+ ok1(c1.list.prev == &parent.children.raw.n);
+ /* Test tlist_check */
+ ok1(tlist_check(&parent.children, NULL));
+
+ c3.name = "c3";
+ tlist_add_tail(&parent.children, &c3, list);
+ /* Test list_add_tail and !list_empty. */
+ ok1(!tlist_empty(&parent.children));
+ ok1(parent.children.raw.n.next == &c1.list);
+ ok1(parent.children.raw.n.prev == &c3.list);
+ ok1(c1.list.next == &c2.list);
+ ok1(c1.list.prev == &parent.children.raw.n);
+ ok1(c2.list.next == &c3.list);
+ ok1(c2.list.prev == &c1.list);
+ ok1(c3.list.next == &parent.children.raw.n);
+ ok1(c3.list.prev == &c2.list);
+ /* Test tlist_check */
+ ok1(tlist_check(&parent.children, NULL));
+
+ /* Test tlist_top */
+ ok1(tlist_top(&parent.children, list) == &c1);
+
+ /* Test list_tail */
+ ok1(tlist_tail(&parent.children, list) == &c3);
+
+ /* Test tlist_for_each. */
+ i = 0;
+ tlist_for_each(&parent.children, c, list) {
+ switch (i++) {
+ case 0:
+ ok1(c == &c1);
+ break;
+ case 1:
+ ok1(c == &c2);
+ break;
+ case 2:
+ ok1(c == &c3);
+ break;
+ }
+ if (i > 2)
+ break;
+ }
+ ok1(i == 3);
+
+ /* Test tlist_for_each_rev. */
+ i = 0;
+ tlist_for_each_rev(&parent.children, c, list) {
+ switch (i++) {
+ case 0:
+ ok1(c == &c3);
+ break;
+ case 1:
+ ok1(c == &c2);
+ break;
+ case 2:
+ ok1(c == &c1);
+ break;
+ }
+ if (i > 2)
+ break;
+ }
+ ok1(i == 3);
+
+ /* Test tlist_for_each_safe, tlist_del and tlist_del_from. */
+ i = 0;
+ tlist_for_each_safe(&parent.children, c, n, list) {
+ switch (i++) {
+ case 0:
+ ok1(c == &c1);
+ tlist_del(c, list);
+ break;
+ case 1:
+ ok1(c == &c2);
+ tlist_del_from(&parent.children, c, list);
+ break;
+ case 2:
+ ok1(c == &c3);
+ tlist_del_from(&parent.children, c, list);
+ break;
+ }
+ ok1(tlist_check(&parent.children, NULL));
+ if (i > 2)
+ break;
+ }
+ ok1(i == 3);
+ ok1(tlist_empty(&parent.children));
+
+ /* Test list_top/list_tail on empty list. */
+ ok1(tlist_top(&parent.children, list) == (struct child *)NULL);
+ ok1(tlist_tail(&parent.children, list) == (struct child *)NULL);
+ return exit_status();
+}
diff --git a/lib/ccan/tlist/tlist.h b/lib/ccan/tlist/tlist.h
new file mode 100644
index 0000000000..1ce0b85ed9
--- /dev/null
+++ b/lib/ccan/tlist/tlist.h
@@ -0,0 +1,265 @@
+/* Licensed under LGPL - see LICENSE file for details */
+#ifndef CCAN_TLIST_H
+#define CCAN_TLIST_H
+#include <ccan/list/list.h>
+#include <ccan/tcon/tcon.h>
+
+/**
+ * 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().
+ *
+ * Example:
+ * // Defines struct tlist_children
+ * TLIST_TYPE(children, struct child);
+ * struct parent {
+ * const char *name;
+ * struct tlist_children children;
+ * unsigned int num_children;
+ * };
+ *
+ * struct child {
+ * const char *name;
+ * struct list_node list;
+ * };
+ */
+#define TLIST_TYPE(suffix, type) \
+ struct tlist_##suffix { \
+ struct list_head raw; \
+ TCON(type *canary); \
+ }
+
+/**
+ * TLIST_INIT - initalizer for an empty tlist
+ * @name: the name of the list.
+ *
+ * Explicit initializer for an empty list.
+ *
+ * See also:
+ * tlist_init()
+ *
+ * Example:
+ * static struct tlist_children my_list = TLIST_INIT(my_list);
+ */
+#define TLIST_INIT(name) { LIST_HEAD_INIT(name.raw) }
+
+/**
+ * tlist_check - check head of a list for consistency
+ * @h: the tlist_head
+ * @abortstr: the location to print on aborting, or NULL.
+ *
+ * Because list_nodes have redundant information, consistency checking between
+ * the back and forward links can be done. This is useful as a debugging check.
+ * If @abortstr is non-NULL, that will be printed in a diagnostic if the list
+ * is inconsistent, and the function will abort.
+ *
+ * Returns non-NULL if the list is consistent, NULL otherwise (it
+ * can never return NULL if @abortstr is set).
+ *
+ * See also: list_check()
+ *
+ * Example:
+ * static void dump_parent(struct parent *p)
+ * {
+ * struct child *c;
+ *
+ * printf("%s (%u children):\n", p->name, p->num_children);
+ * tlist_check(&p->children, "bad child list");
+ * tlist_for_each(&p->children, c, list)
+ * printf(" -> %s\n", c->name);
+ * }
+ */
+#define tlist_check(h, abortstr) \
+ list_check(&(h)->raw, (abortstr))
+
+/**
+ * tlist_init - initialize a tlist
+ * @h: the tlist to set to the empty list
+ *
+ * Example:
+ * ...
+ * struct parent *parent = malloc(sizeof(*parent));
+ *
+ * tlist_init(&parent->children);
+ * parent->num_children = 0;
+ */
+#define tlist_init(h) list_head_init(&(h)->raw)
+
+/**
+ * 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_check((h), canary, (expr))->raw)
+
+/**
+ * tlist_add - add an entry at the start of a linked list.
+ * @h: the tlist to add the node to
+ * @n: the entry to add to the list.
+ * @member: the member of n to add to the list.
+ *
+ * The entry's list_node does not need to be initialized; it will be
+ * overwritten.
+ * Example:
+ * struct child *child = malloc(sizeof(*child));
+ *
+ * child->name = "marvin";
+ * tlist_add(&parent->children, child, list);
+ * parent->num_children++;
+ */
+#define tlist_add(h, n, member) list_add(tlist_raw((h), (n)), &(n)->member)
+
+/**
+ * tlist_add_tail - add an entry at the end of a linked list.
+ * @h: the tlist to add the node to
+ * @n: the entry to add to the list.
+ * @member: the member of n to add to the list.
+ *
+ * The list_node does not need to be initialized; it will be overwritten.
+ * Example:
+ * tlist_add_tail(&parent->children, child, list);
+ * parent->num_children++;
+ */
+#define tlist_add_tail(h, n, member) \
+ list_add_tail(tlist_raw((h), (n)), &(n)->member)
+
+/**
+ * tlist_del_from - delete an entry from a linked list.
+ * @h: the tlist @n is in
+ * @n: the entry to delete
+ * @member: the member of n to remove from the list.
+ *
+ * This explicitly indicates which list a node is expected to be in,
+ * which is better documentation and can catch more bugs.
+ *
+ * Note that this leaves @n->@member in an undefined state; it
+ * can be added to another list, but not deleted again.
+ *
+ * See also: tlist_del()
+ *
+ * Example:
+ * tlist_del_from(&parent->children, child, list);
+ * parent->num_children--;
+ */
+#define tlist_del_from(h, n, member) \
+ list_del_from(tlist_raw((h), (n)), &(n)->member)
+
+/**
+ * tlist_del - delete an entry from an unknown linked list.
+ * @n: the entry to delete from the list.
+ * @member: the member of @n which is in the list.
+ *
+ * Example:
+ * tlist_del(child, list);
+ * parent->num_children--;
+ */
+#define tlist_del(n, member) \
+ list_del(&(n)->member)
+
+/**
+ * tlist_empty - is a list empty?
+ * @h: the tlist
+ *
+ * If the list is empty, returns true.
+ *
+ * Example:
+ * assert(tlist_empty(&parent->children) == (parent->num_children == 0));
+ */
+#define tlist_empty(h) list_empty(&(h)->raw)
+
+/**
+ * tlist_top - get the first entry in a list
+ * @h: the tlist
+ * @member: the list_node member of the type
+ *
+ * If the list is empty, returns NULL.
+ *
+ * Example:
+ * struct child *first;
+ * first = tlist_top(&parent->children, list);
+ */
+#define tlist_top(h, member) \
+ ((tcon_type((h), canary)) \
+ list_top_(&(h)->raw, \
+ (char *)(&(h)->_tcon[0].canary->member) - \
+ (char *)((h)->_tcon[0].canary)))
+
+/**
+ * tlist_tail - get the last entry in a list
+ * @h: the tlist
+ * @member: the list_node member of the type
+ *
+ * If the list is empty, returns NULL.
+ *
+ * Example:
+ * struct child *last;
+ * last = tlist_tail(&parent->children, list);
+ */
+#define tlist_tail(h, member) \
+ ((tcon_type((h), canary)) \
+ list_tail_(&(h)->raw, \
+ (char *)(&(h)->_tcon[0].canary->member) - \
+ (char *)((h)->_tcon[0].canary)))
+
+/**
+ * tlist_for_each - iterate through a list.
+ * @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(&parent->children, child, list)
+ * printf("Name: %s\n", child->name);
+ */
+#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
+ * @i: an iterator of suitable type for this list.
+ * @nxt: another iterator to store the next entry.
+ * @member: the list_node member of the structure
+ *
+ * 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. The extra variable
+ * @nxt is used to hold the next element, so you can delete @i from the list.
+ *
+ * Example:
+ * struct child *next;
+ * tlist_for_each_safe(&parent->children, child, next, list) {
+ * tlist_del(child, list);
+ * parent->num_children--;
+ * }
+ */
+#define tlist_for_each_safe(h, i, nxt, member) \
+ list_for_each_safe(tlist_raw((h), (i)), (i), (nxt), member)
+
+#endif /* CCAN_TLIST_H */