diff options
Diffstat (limited to 'lib/ccan/tlist')
-rw-r--r-- | lib/ccan/tlist/LICENSE | 165 | ||||
-rw-r--r-- | lib/ccan/tlist/_info | 74 | ||||
-rw-r--r-- | lib/ccan/tlist/test/compile_fail-tlist_add.c | 35 | ||||
-rw-r--r-- | lib/ccan/tlist/test/compile_fail-tlist_add_tail.c | 35 | ||||
-rw-r--r-- | lib/ccan/tlist/test/compile_fail-tlist_del_from.c | 34 | ||||
-rw-r--r-- | lib/ccan/tlist/test/compile_fail-tlist_for_each.c | 34 | ||||
-rw-r--r-- | lib/ccan/tlist/test/compile_fail-tlist_for_each_safe.c | 33 | ||||
-rw-r--r-- | lib/ccan/tlist/test/compile_fail-tlist_tail.c | 31 | ||||
-rw-r--r-- | lib/ccan/tlist/test/compile_fail-tlist_top.c | 31 | ||||
-rw-r--r-- | lib/ccan/tlist/test/run.c | 147 | ||||
-rw-r--r-- | lib/ccan/tlist/tlist.h | 265 |
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 */ |