diff options
author | Ian Moffett <ian@osmora.org> | 2024-12-16 01:04:26 -0500 |
---|---|---|
committer | Ian Moffett <ian@osmora.org> | 2024-12-16 01:04:26 -0500 |
commit | 9f5dae52cc66fbae16781fd73174c9d220e83560 (patch) | |
tree | 16323582d2540ccb9a0ebfea903ea5766a51f31a /share | |
parent | 4ce9517c4b7675991c969702ba306004b9bb8353 (diff) |
docs: man: Add queue(3) and tree(3)
Signed-off-by: Ian Moffett <ian@osmora.org>
Diffstat (limited to 'share')
-rw-r--r-- | share/man/man3/queue.3 | 1195 | ||||
-rw-r--r-- | share/man/man3/tree.3 | 582 |
2 files changed, 1777 insertions, 0 deletions
diff --git a/share/man/man3/queue.3 b/share/man/man3/queue.3 new file mode 100644 index 0000000..dd3fe53 --- /dev/null +++ b/share/man/man3/queue.3 @@ -0,0 +1,1195 @@ +.\" $NetBSD: queue.3,v 1.4 1995/07/03 00:25:36 mycroft Exp $ +.\" +.\" Copyright (c) 1993 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)queue.3 8.1 (Berkeley) 12/13/93 +.\" +.Dd $Mdocdate: Dec 16 2024 $ +.Dt SLIST_INIT 3 +.Os +.Sh NAME +.Nm SLIST_ENTRY , +.Nm SLIST_HEAD , +.Nm SLIST_HEAD_INITIALIZER , +.Nm SLIST_FIRST , +.Nm SLIST_NEXT , +.Nm SLIST_EMPTY , +.Nm SLIST_FOREACH , +.Nm SLIST_FOREACH_SAFE , +.Nm SLIST_INIT , +.Nm SLIST_INSERT_AFTER , +.Nm SLIST_INSERT_HEAD , +.Nm SLIST_REMOVE_AFTER , +.Nm SLIST_REMOVE_HEAD , +.Nm SLIST_REMOVE , +.Nm LIST_ENTRY , +.Nm LIST_HEAD , +.Nm LIST_HEAD_INITIALIZER , +.Nm LIST_FIRST , +.Nm LIST_NEXT , +.Nm LIST_EMPTY , +.Nm LIST_FOREACH , +.Nm LIST_FOREACH_SAFE , +.Nm LIST_INIT , +.Nm LIST_INSERT_AFTER , +.Nm LIST_INSERT_BEFORE , +.Nm LIST_INSERT_HEAD , +.Nm LIST_REMOVE , +.Nm LIST_REPLACE , +.Nm SIMPLEQ_ENTRY , +.Nm SIMPLEQ_HEAD , +.Nm SIMPLEQ_HEAD_INITIALIZER , +.Nm SIMPLEQ_FIRST , +.Nm SIMPLEQ_NEXT , +.Nm SIMPLEQ_EMPTY , +.Nm SIMPLEQ_FOREACH , +.Nm SIMPLEQ_FOREACH_SAFE , +.Nm SIMPLEQ_INIT , +.Nm SIMPLEQ_INSERT_AFTER , +.Nm SIMPLEQ_INSERT_HEAD , +.Nm SIMPLEQ_INSERT_TAIL , +.Nm SIMPLEQ_REMOVE_AFTER , +.Nm SIMPLEQ_REMOVE_HEAD , +.Nm SIMPLEQ_CONCAT , +.Nm STAILQ_ENTRY , +.Nm STAILQ_HEAD , +.Nm STAILQ_HEAD_INITIALIZER , +.Nm STAILQ_FIRST , +.Nm STAILQ_NEXT , +.Nm STAILQ_LAST , +.Nm STAILQ_EMPTY , +.Nm STAILQ_FOREACH , +.Nm STAILQ_FOREACH_SAFE , +.Nm STAILQ_INIT , +.Nm STAILQ_INSERT_AFTER , +.Nm STAILQ_INSERT_HEAD , +.Nm STAILQ_INSERT_TAIL , +.Nm STAILQ_REMOVE , +.Nm STAILQ_REMOVE_AFTER , +.Nm STAILQ_REMOVE_HEAD , +.Nm STAILQ_CONCAT , +.Nm TAILQ_ENTRY , +.Nm TAILQ_HEAD , +.Nm TAILQ_HEAD_INITIALIZER , +.Nm TAILQ_FIRST , +.Nm TAILQ_NEXT , +.Nm TAILQ_LAST , +.Nm TAILQ_PREV , +.Nm TAILQ_EMPTY , +.Nm TAILQ_FOREACH , +.Nm TAILQ_FOREACH_SAFE , +.Nm TAILQ_FOREACH_REVERSE , +.Nm TAILQ_FOREACH_REVERSE_SAFE , +.Nm TAILQ_INIT , +.Nm TAILQ_INSERT_AFTER , +.Nm TAILQ_INSERT_BEFORE , +.Nm TAILQ_INSERT_HEAD , +.Nm TAILQ_INSERT_TAIL , +.Nm TAILQ_REMOVE , +.Nm TAILQ_REPLACE , +.Nm TAILQ_CONCAT +.Nd intrusive singly-linked and doubly-linked lists, simple queues, singly-linked and doubly-linked tail queues +.Sh SYNOPSIS +.In sys/queue.h +.Pp +.Fn SLIST_ENTRY "TYPE" +.Fn SLIST_HEAD "HEADNAME" "TYPE" +.Fn SLIST_HEAD_INITIALIZER "SLIST_HEAD head" +.Ft "struct TYPE *" +.Fn SLIST_FIRST "SLIST_HEAD *head" +.Ft "struct TYPE *" +.Fn SLIST_NEXT "struct TYPE *listelm" "FIELDNAME" +.Ft int +.Fn SLIST_EMPTY "SLIST_HEAD *head" +.Fn SLIST_FOREACH "VARNAME" "SLIST_HEAD *head" "FIELDNAME" +.Fn SLIST_FOREACH_SAFE "VARNAME" "SLIST_HEAD *head" "FIELDNAME" "TEMP_VARNAME" +.Ft void +.Fn SLIST_INIT "SLIST_HEAD *head" +.Ft void +.Fn SLIST_INSERT_AFTER "struct TYPE *listelm" "struct TYPE *elm" "FIELDNAME" +.Ft void +.Fn SLIST_INSERT_HEAD "SLIST_HEAD *head" "struct TYPE *elm" "FIELDNAME" +.Ft void +.Fn SLIST_REMOVE_AFTER "struct TYPE *elm" "FIELDNAME" +.Ft void +.Fn SLIST_REMOVE_HEAD "SLIST_HEAD *head" "FIELDNAME" +.Ft void +.Fn SLIST_REMOVE "SLIST_HEAD *head" "struct TYPE *elm" "TYPE" "FIELDNAME" +.Pp +.Fn LIST_ENTRY "TYPE" +.Fn LIST_HEAD "HEADNAME" "TYPE" +.Fn LIST_HEAD_INITIALIZER "LIST_HEAD head" +.Ft "struct TYPE *" +.Fn LIST_FIRST "LIST_HEAD *head" +.Ft "struct TYPE *" +.Fn LIST_NEXT "struct TYPE *listelm" "FIELDNAME" +.Ft int +.Fn LIST_EMPTY "LIST_HEAD *head" +.Fn LIST_FOREACH "VARNAME" "LIST_HEAD *head" "FIELDNAME" +.Fn LIST_FOREACH_SAFE "VARNAME" "LIST_HEAD *head" "FIELDNAME" "TEMP_VARNAME" +.Ft void +.Fn LIST_INIT "LIST_HEAD *head" +.Ft void +.Fn LIST_INSERT_AFTER "struct TYPE *listelm" "struct TYPE *elm" "FIELDNAME" +.Ft void +.Fn LIST_INSERT_BEFORE "struct TYPE *listelm" "struct TYPE *elm" "FIELDNAME" +.Ft void +.Fn LIST_INSERT_HEAD "LIST_HEAD *head" "struct TYPE *elm" "FIELDNAME" +.Ft void +.Fn LIST_REMOVE "struct TYPE *elm" "FIELDNAME" +.Ft void +.Fn LIST_REPLACE "struct TYPE *elm" "struct TYPE *elm2" "FIELDNAME" +.Pp +.Fn SIMPLEQ_ENTRY "TYPE" +.Fn SIMPLEQ_HEAD "HEADNAME" "TYPE" +.Fn SIMPLEQ_HEAD_INITIALIZER "SIMPLEQ_HEAD head" +.Ft "struct TYPE *" +.Fn SIMPLEQ_FIRST "SIMPLEQ_HEAD *head" +.Ft "struct TYPE *" +.Fn SIMPLEQ_NEXT "struct TYPE *listelm" "FIELDNAME" +.Ft int +.Fn SIMPLEQ_EMPTY "SIMPLEQ_HEAD *head" +.Fn SIMPLEQ_FOREACH "VARNAME" "SIMPLEQ_HEAD *head" "FIELDNAME" +.Fn SIMPLEQ_FOREACH_SAFE "VARNAME" "SIMPLEQ_HEAD *head" "FIELDNAME" "TEMP_VARNAME" +.Ft void +.Fn SIMPLEQ_INIT "SIMPLEQ_HEAD *head" +.Ft void +.Fn SIMPLEQ_INSERT_AFTER "SIMPLEQ_HEAD *head" "struct TYPE *listelm" "struct TYPE *elm" "FIELDNAME" +.Ft void +.Fn SIMPLEQ_INSERT_HEAD "SIMPLEQ_HEAD *head" "struct TYPE *elm" "FIELDNAME" +.Ft void +.Fn SIMPLEQ_INSERT_TAIL "SIMPLEQ_HEAD *head" "struct TYPE *elm" "FIELDNAME" +.Ft void +.Fn SIMPLEQ_REMOVE_AFTER "SIMPLEQ_HEAD *head" "struct TYPE *elm" "FIELDNAME" +.Ft void +.Fn SIMPLEQ_REMOVE_HEAD "SIMPLEQ_HEAD *head" "FIELDNAME" +.Fn SIMPLEQ_CONCAT "SIMPLEQ_HEAD *head1" "SIMPLEQ_HEAD *head2" +.Pp +.Fn STAILQ_ENTRY "TYPE" +.Fn STAILQ_HEAD "HEADNAME" "TYPE" +.Fn STAILQ_HEAD_INITIALIZER "STAILQ_HEAD head" +.Fn STAILQ_FIRST "STAILQ_HEAD *head" +.Fn STAILQ_NEXT "TYPE *elm" "STAILQ_ENTRY NAME" +.Fn STAILQ_LAST "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME" +.Fn STAILQ_EMPTY "STAILQ_HEAD *head" +.Fn STAILQ_FOREACH "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME" +.Fn STAILQ_FOREACH_SAFE "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME" "TYPE *temp_var" +.Fn STAILQ_INIT "STAILQ_HEAD *head" +.Fn STAILQ_INSERT_AFTER "STAILQ_HEAD *head" "TYPE *listelm" "TYPE *elm" "STAILQ_ENTRY NAME" +.Fn STAILQ_INSERT_HEAD "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME" +.Fn STAILQ_INSERT_TAIL "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME" +.Fn STAILQ_REMOVE "STAILQ_HEAD *head" "TYPE *elm" "TYPE" "STAILQ_ENTRY NAME" +.Fn STAILQ_REMOVE_AFTER "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME" +.Fn STAILQ_REMOVE_HEAD "STAILQ_HEAD *head" "STAILQ_ENTRY NAME" +.Fn STAILQ_CONCAT "STAILQ_HEAD *head1" "STAILQ_HEAD *head2" +.Pp +.Fn TAILQ_ENTRY "TYPE" +.Fn TAILQ_HEAD "HEADNAME" "TYPE" +.Fn TAILQ_HEAD_INITIALIZER "TAILQ_HEAD head" +.Ft "struct TYPE *" +.Fn TAILQ_FIRST "TAILQ_HEAD *head" +.Ft "struct TYPE *" +.Fn TAILQ_NEXT "struct TYPE *listelm" "FIELDNAME" +.Ft "struct TYPE *" +.Fn TAILQ_LAST "TAILQ_HEAD *head" "HEADNAME" +.Ft "struct TYPE *" +.Fn TAILQ_PREV "struct TYPE *listelm" "HEADNAME" "FIELDNAME" +.Ft int +.Fn TAILQ_EMPTY "TAILQ_HEAD *head" +.Fn TAILQ_FOREACH "VARNAME" "TAILQ_HEAD *head" "FIELDNAME" +.Fn TAILQ_FOREACH_SAFE "VARNAME" "TAILQ_HEAD *head" "FIELDNAME" "TEMP_VARNAME" +.Fn TAILQ_FOREACH_REVERSE "VARNAME" "TAILQ_HEAD *head" "HEADNAME" "FIELDNAME" +.Fn TAILQ_FOREACH_REVERSE_SAFE "VARNAME" "TAILQ_HEAD *head" "HEADNAME" "FIELDNAME" "TEMP_VARNAME" +.Ft void +.Fn TAILQ_INIT "TAILQ_HEAD *head" +.Ft void +.Fn TAILQ_INSERT_AFTER "TAILQ_HEAD *head" "struct TYPE *listelm" "struct TYPE *elm" "FIELDNAME" +.Ft void +.Fn TAILQ_INSERT_BEFORE "struct TYPE *listelm" "struct TYPE *elm" "FIELDNAME" +.Ft void +.Fn TAILQ_INSERT_HEAD "TAILQ_HEAD *head" "struct TYPE *elm" "FIELDNAME" +.Ft void +.Fn TAILQ_INSERT_TAIL "TAILQ_HEAD *head" "struct TYPE *elm" "FIELDNAME" +.Ft void +.Fn TAILQ_REMOVE "TAILQ_HEAD *head" "struct TYPE *elm" "FIELDNAME" +.Ft void +.Fn TAILQ_REPLACE "TAILQ_HEAD *head" "struct TYPE *elm" "struct TYPE *elm2" "FIELDNAME" +.Fn TAILQ_CONCAT "TAILQ_HEAD *head1" "TAILQ_HEAD *head2" "FIELDNAME" +.Sh DESCRIPTION +These macros define and operate on five types of data structures: +singly-linked lists, simple queues, lists, singly-linked tail queues, +and tail queues. +All five structures support the following functionality: +.Pp +.Bl -enum -compact -offset indent +.It +Insertion of a new entry at the head of the list. +.It +Insertion of a new entry after any element in the list. +.It +Removal of an entry from the head of the list. +.It +Forward traversal through the list. +.El +.Pp +The following table provides a quick overview +of which types support which additional macros: +.Bl -column -offset 6n "LAST, PREV, FOREACH_REVERSE" SLIST LIST SIMPLEQ STAILQ TAILQ +.It LAST, PREV, FOREACH_REVERSE Ta - Ta - Ta - Ta - Ta TAILQ +.It INSERT_BEFORE, REPLACE Ta - Ta LIST Ta - Ta - Ta TAILQ +.It INSERT_TAIL, CONCAT Ta - Ta - Ta SIMPLEQ Ta STAILQ Ta TAILQ +.It REMOVE_AFTER, REMOVE_HEAD Ta SLIST Ta - Ta SIMPLEQ Ta STAILQ Ta - +.It REMOVE Ta SLIST Ta LIST Ta - Ta STAILQ Ta TAILQ +.El +.Pp +Singly-linked lists are the simplest of the five data structures +and support only the above functionality. +Singly-linked lists are ideal for applications with large datasets +and few or no removals, or for implementing a LIFO queue. +.Pp +Simple queues and singly-linked tail queues add the following functionality: +.Pp +.Bl -enum -compact -offset indent +.It +Entries can be added at the end of a list. +.El +.Pp +However: +.Pp +.Bl -enum -compact -offset indent +.It +All list insertions must specify the head of the list. +.It +Each head entry requires two pointers rather than one. +.It +Code size is about 15% greater and operations run about 20% slower +than singly-linked lists. +.El +.Pp +Simple queues and singly-linked tail queues are ideal for applications with +large datasets and few or no removals, or for implementing a FIFO queue. +.Pp +All doubly linked types of data structures (lists and tail queues) +additionally allow: +.Pp +.Bl -enum -compact -offset indent +.It +Insertion of a new entry before any element in the list. +.It +Removal of any entry in the list. +.El +.Pp +However: +.Pp +.Bl -enum -compact -offset indent +.It +Each element requires two pointers rather than one. +.It +Code size and execution time of operations (except for removal) is about +twice that of the singly-linked data-structures. +.El +.Pp +Lists are the simplest of the doubly linked data structures and support +only the above functionality over singly-linked lists. +.Pp +Tail queues add the following functionality: +.Pp +.Bl -enum -compact -offset indent +.It +Entries can be added at the end of a list. +.It +They may be traversed backwards, at a cost. +.El +.Pp +However: +.Pp +.Bl -enum -compact -offset indent +.It +All list insertions and removals must specify the head of the list. +.It +Each head entry requires two pointers rather than one. +.It +Code size is about 15% greater and operations run about 20% slower +than singly-linked lists. +.El +.Pp +An additional type of data structure, circular queues, violated the C +language aliasing rules and were miscompiled as a result. +All code using them should be converted to another structure; +tail queues are usually the easiest to convert to. +.Pp +All these lists and queues are intrusive: they link together user +defined structures containing a field of type +.Li SLIST_ENTRY , +.Li LIST_ENTRY , +.Li SIMPLEQ_ENTRY , +.Li STAILQ_ENTRY , +or +.Li TAILQ_ENTRY . +In the macro definitions, +.Fa TYPE +is the name tag of the user defined structure and +.Fa FIELDNAME +is the name of the +.Li *_ENTRY +field. +If an instance of the user defined structure needs to be a member of +multiple lists at the same time, the structure requires multiple +.Li *_ENTRY +fields, one for each list. +.Pp +The argument +.Fa HEADNAME +is the name tag of a user defined structure that must be declared +using the macros +.Fn SLIST_HEAD , +.Fn LIST_HEAD , +.Fn SIMPLEQ_HEAD , +.Fn STAILQ_HEAD , +or +.Fn TAILQ_HEAD . +See the examples below for further explanation of how these macros are used. +.Sh SINGLY-LINKED LISTS +A singly-linked list is headed by a structure defined by the +.Fn SLIST_HEAD +macro. +This structure contains a single pointer to the first element on the list. +The elements are singly linked for minimum space and pointer manipulation +overhead at the expense of O(n) removal for arbitrary elements. +New elements can be added to the list after an existing element or +at the head of the list. +A +.Fa SLIST_HEAD +structure is declared as follows: +.Bd -literal -offset indent +SLIST_HEAD(HEADNAME, TYPE) head; +.Ed +.Pp +where +.Fa HEADNAME +is the name of the structure to be defined, and struct +.Fa TYPE +is the type of the elements to be linked into the list. +A pointer to the head of the list can later be declared as: +.Bd -literal -offset indent +struct HEADNAME *headp; +.Ed +.Pp +(The names +.Li head +and +.Li headp +are user selectable.) +.Pp +The +.Fa HEADNAME +facility is often not used, leading to the following bizarre code: +.Bd -literal -offset indent +SLIST_HEAD(, TYPE) head, *headp; +.Ed +.Pp +The +.Fn SLIST_ENTRY +macro declares a structure that connects the elements in the list. +.Pp +The +.Fn SLIST_INIT +macro initializes the list referenced by +.Fa head . +.Pp +The list can also be initialized statically by using the +.Fn SLIST_HEAD_INITIALIZER +macro like this: +.Bd -literal -offset indent +SLIST_HEAD(HEADNAME, TYPE) head = SLIST_HEAD_INITIALIZER(head); +.Ed +.Pp +The +.Fn SLIST_INSERT_HEAD +macro inserts the new element +.Fa elm +at the head of the list. +.Pp +The +.Fn SLIST_INSERT_AFTER +macro inserts the new element +.Fa elm +after the element +.Fa listelm . +.Pp +The +.Fn SLIST_REMOVE_HEAD +macro removes the first element of the list pointed by +.Fa head . +.Pp +The +.Fn SLIST_REMOVE_AFTER +macro removes the list element immediately following +.Fa elm . +.Pp +The +.Fn SLIST_REMOVE +macro removes the element +.Fa elm +of the list pointed by +.Fa head . +.Pp +The +.Fn SLIST_FIRST +and +.Fn SLIST_NEXT +macros can be used to traverse the list: +.Bd -literal -offset indent +for (np = SLIST_FIRST(&head); np != NULL; np = SLIST_NEXT(np, FIELDNAME)) +.Ed +.Pp +Or, for simplicity, one can use the +.Fn SLIST_FOREACH +macro: +.Bd -literal -offset indent +SLIST_FOREACH(np, head, FIELDNAME) +.Ed +.Pp +The macro +.Fn SLIST_FOREACH_SAFE +traverses the list referenced by head in a +forward direction, assigning each element in turn to var. +However, unlike +.Fn SLIST_FOREACH +it is permitted to remove var as well +as free it from within the loop safely without interfering with the traversal. +.Pp +The +.Fn SLIST_EMPTY +macro should be used to check whether a simple list is empty. +.Sh SINGLY-LINKED LIST EXAMPLE +.Bd -literal +SLIST_HEAD(listhead, entry) head; +struct entry { + ... + SLIST_ENTRY(entry) entries; /* Simple list. */ + ... +} *n1, *n2, *np; + +SLIST_INIT(&head); /* Initialize simple list. */ + +n1 = malloc(sizeof(struct entry)); /* Insert at the head. */ +SLIST_INSERT_HEAD(&head, n1, entries); + +n2 = malloc(sizeof(struct entry)); /* Insert after. */ +SLIST_INSERT_AFTER(n1, n2, entries); + +SLIST_FOREACH(np, &head, entries) /* Forward traversal. */ + np-> ... + +while (!SLIST_EMPTY(&head)) { /* Delete. */ + n1 = SLIST_FIRST(&head); + SLIST_REMOVE_HEAD(&head, entries); + free(n1); +} + +.Ed +.Sh LISTS +A list is headed by a structure defined by the +.Fn LIST_HEAD +macro. +This structure contains a single pointer to the first element on the list. +The elements are doubly linked so that an arbitrary element can be +removed without traversing the list. +New elements can be added to the list after an existing element, +before an existing element, or at the head of the list. +A +.Fa LIST_HEAD +structure is declared as follows: +.Bd -literal -offset indent +LIST_HEAD(HEADNAME, TYPE) head; +.Ed +.Pp +where +.Fa HEADNAME +is the name of the structure to be defined, and struct +.Fa TYPE +is the type of the elements to be linked into the list. +A pointer to the head of the list can later be declared as: +.Bd -literal -offset indent +struct HEADNAME *headp; +.Ed +.Pp +(The names +.Li head +and +.Li headp +are user selectable.) +.Pp +The +.Fa HEADNAME +facility is often not used, leading to the following bizarre code: +.Bd -literal -offset indent +LIST_HEAD(, TYPE) head, *headp; +.Ed +.Pp +The +.Fn LIST_ENTRY +macro declares a structure that connects the elements in the list. +.Pp +The +.Fn LIST_INIT +macro initializes the list referenced by +.Fa head . +.Pp +The list can also be initialized statically by using the +.Fn LIST_HEAD_INITIALIZER +macro like this: +.Bd -literal -offset indent +LIST_HEAD(HEADNAME, TYPE) head = LIST_HEAD_INITIALIZER(head); +.Ed +.Pp +The +.Fn LIST_INSERT_HEAD +macro inserts the new element +.Fa elm +at the head of the list. +.Pp +The +.Fn LIST_INSERT_AFTER +macro inserts the new element +.Fa elm +after the element +.Fa listelm . +.Pp +The +.Fn LIST_INSERT_BEFORE +macro inserts the new element +.Fa elm +before the element +.Fa listelm . +.Pp +The +.Fn LIST_REMOVE +macro removes the element +.Fa elm +from the list. +.Pp +The +.Fn LIST_REPLACE +macro replaces the list element +.Fa elm +with the new element +.Fa elm2 . +.Pp +The +.Fn LIST_FIRST +and +.Fn LIST_NEXT +macros can be used to traverse the list: +.Bd -literal -offset indent +for (np = LIST_FIRST(&head); np != NULL; np = LIST_NEXT(np, FIELDNAME)) +.Ed +.Pp +Or, for simplicity, one can use the +.Fn LIST_FOREACH +macro: +.Bd -literal -offset indent +LIST_FOREACH(np, head, FIELDNAME) +.Ed +.Pp +The macro +.Fn LIST_FOREACH_SAFE +traverses the list referenced by head in a +forward direction, assigning each element in turn to var. +However, unlike +.Fn LIST_FOREACH +it is permitted to remove var as well +as free it from within the loop safely without interfering with the traversal. +.Pp +The +.Fn LIST_EMPTY +macro should be used to check whether a list is empty. +.Sh LIST EXAMPLE +.Bd -literal +LIST_HEAD(listhead, entry) head; +struct entry { + ... + LIST_ENTRY(entry) entries; /* List. */ + ... +} *n1, *n2, *np; + +LIST_INIT(&head); /* Initialize list. */ + +n1 = malloc(sizeof(struct entry)); /* Insert at the head. */ +LIST_INSERT_HEAD(&head, n1, entries); + +n2 = malloc(sizeof(struct entry)); /* Insert after. */ +LIST_INSERT_AFTER(n1, n2, entries); + +n2 = malloc(sizeof(struct entry)); /* Insert before. */ +LIST_INSERT_BEFORE(n1, n2, entries); + /* Forward traversal. */ +LIST_FOREACH(np, &head, entries) + np-> ... + +while (!LIST_EMPTY(&head)) { /* Delete. */ + n1 = LIST_FIRST(&head); + LIST_REMOVE(n1, entries); + free(n1); +} +.Ed +.Sh SIMPLE QUEUES +A simple queue is headed by a structure defined by the +.Fn SIMPLEQ_HEAD +macro. +This structure contains a pair of pointers, one to the first element in the +simple queue and the other to the last element in the simple queue. +The elements are singly linked. +New elements can be added to the queue after an existing element, +at the head of the queue or at the tail of the queue. +A +.Fa SIMPLEQ_HEAD +structure is declared as follows: +.Bd -literal -offset indent +SIMPLEQ_HEAD(HEADNAME, TYPE) head; +.Ed +.Pp +where +.Fa HEADNAME +is the name of the structure to be defined, and struct +.Fa TYPE +is the type of the elements to be linked into the queue. +A pointer to the head of the queue can later be declared as: +.Bd -literal -offset indent +struct HEADNAME *headp; +.Ed +.Pp +(The names +.Li head +and +.Li headp +are user selectable.) +.Pp +The +.Fn SIMPLEQ_ENTRY +macro declares a structure that connects the elements in +the queue. +.Pp +The +.Fn SIMPLEQ_INIT +macro initializes the queue referenced by +.Fa head . +.Pp +The queue can also be initialized statically by using the +.Fn SIMPLEQ_HEAD_INITIALIZER +macro like this: +.Bd -literal -offset indent +SIMPLEQ_HEAD(HEADNAME, TYPE) head = SIMPLEQ_HEAD_INITIALIZER(head); +.Ed +.Pp +The +.Fn SIMPLEQ_INSERT_AFTER +macro inserts the new element +.Fa elm +after the element +.Fa listelm . +.Pp +The +.Fn SIMPLEQ_INSERT_HEAD +macro inserts the new element +.Fa elm +at the head of the queue. +.Pp +The +.Fn SIMPLEQ_INSERT_TAIL +macro inserts the new element +.Fa elm +at the end of the queue. +.Pp +The +.Fn SIMPLEQ_REMOVE_AFTER +macro removes the queue element immediately following +.Fa elm . +.Pp +The +.Fn SIMPLEQ_REMOVE_HEAD +macro removes the first element +from the queue. +.Pp +The +.Fn SIMPLEQ_CONCAT +macro concatenates all the elements of the queue referenced by +.Fa head2 +to the end of the queue referenced by +.Fa head1 , +emptying +.Fa head2 +in the process. +This is more efficient than removing and inserting the individual elements +as it does not actually traverse +.Fa head2 . +.Pp +The +.Fn SIMPLEQ_FIRST +and +.Fn SIMPLEQ_NEXT +macros can be used to traverse the queue. +The +.Fn SIMPLEQ_FOREACH +macro is used for queue traversal: +.Bd -literal -offset indent +SIMPLEQ_FOREACH(np, head, FIELDNAME) +.Ed +.Pp +The macro +.Fn SIMPLEQ_FOREACH_SAFE +traverses the queue referenced by head in a +forward direction, assigning each element in turn to var. +However, unlike +.Fn SIMPLEQ_FOREACH +it is permitted to remove var as well +as free it from within the loop safely without interfering with the traversal. +.Pp +The +.Fn SIMPLEQ_EMPTY +macro should be used to check whether a list is empty. +.Sh SIMPLE QUEUE EXAMPLE +.Bd -literal +SIMPLEQ_HEAD(listhead, entry) head = SIMPLEQ_HEAD_INITIALIZER(head); +struct entry { + ... + SIMPLEQ_ENTRY(entry) entries; /* Simple queue. */ + ... +} *n1, *n2, *np; + +n1 = malloc(sizeof(struct entry)); /* Insert at the head. */ +SIMPLEQ_INSERT_HEAD(&head, n1, entries); + +n2 = malloc(sizeof(struct entry)); /* Insert after. */ +SIMPLEQ_INSERT_AFTER(&head, n1, n2, entries); + +n2 = malloc(sizeof(struct entry)); /* Insert at the tail. */ +SIMPLEQ_INSERT_TAIL(&head, n2, entries); + /* Forward traversal. */ +SIMPLEQ_FOREACH(np, &head, entries) + np-> ... + /* Delete. */ +while (!SIMPLEQ_EMPTY(&head)) { + n1 = SIMPLEQ_FIRST(&head); + SIMPLEQ_REMOVE_HEAD(&head, entries); + free(n1); +} +.Ed +.Sh SINGLY-LINKED TAIL QUEUES +A singly-linked tail queue is headed by a structure defined by the +.Fn STAILQ_HEAD +macro. +This structure contains a pair of pointers, one to the first element in +the tail queue and the other to the last element in the tail queue. +The elements are singly linked for minimum space and pointer manipulation +overhead at the expense of O(n) removal for arbitrary elements. +New elements can be added to the tail queue after an existing element, +at the head of the tail queue or at the end of the tail queue. +A +.Fa STAILQ_HEAD +structure is declared as follows: +.Bd -literal -offset indent +STAILQ_HEAD(HEADNAME, TYPE) head; +.Ed +.Pp +where +.Fa HEADNAME +is the name of the structure to be defined, and struct +.Fa TYPE +is the type of the elements to be linked into the tail queue. +A pointer to the head of the tail queue can later be declared as: +.Bd -literal -offset indent +struct HEADNAME *headp; +.Ed +.Pp +(The names +.Li head +and +.Li headp +are user selectable.) +.Pp +The +.Fn STAILQ_ENTRY +macro declares a structure that connects the elements in +the tail queue. +.Pp +The +.Fn STAILQ_INIT +macro initializes the tail queue referenced by +.Fa head . +.Pp +The tail queue can also be initialized statically by using the +.Fn STAILQ_HEAD_INITIALIZER +macro like this: +.Bd -literal -offset indent +STAILQ_HEAD(HEADNAME, TYPE) head = STAILQ_HEAD_INITIALIZER(head); +.Ed +.Pp +The +.Fn STAILQ_INSERT_AFTER +macro inserts the new element +.Fa elm +after the element +.Fa listelm . +.Pp +The +.Fn STAILQ_INSERT_HEAD +macro inserts the new element +.Fa elm +at the head of the tail queue. +.Pp +The +.Fn STAILQ_INSERT_TAIL +macro inserts the new element +.Fa elm +at the end of the tail queue. +.Pp +The +.Fn STAILQ_REMOVE_AFTER +macro removes the queue element immediately following +.Fa elm . +Unlike +.Fa STAILQ_REMOVE , +this macro does not traverse the entire tail queue. +.Pp +The +.Fn STAILQ_REMOVE_HEAD +macro removes the first element +from the tail queue. +For optimum efficiency, +elements being removed from the head of the tail queue should +use this macro explicitly rather than the generic +.Fa STAILQ_REMOVE +macro. +.Pp +The +.Fn STAILQ_REMOVE +macro removes the element +.Fa elm +from the tail queue. +Use of this macro should be avoided as it traverses the entire list. +A doubly-linked tail queue should be used if this macro is needed in +high-usage code paths or to operate on long tail queues. +.Pp +The +.Fn STAILQ_CONCAT +macro concatenates all the elements of the tail queue referenced by +.Fa head2 +to the end of the tail queue referenced by +.Fa head1 , +emptying +.Fa head2 +in the process. +This is more efficient than removing and inserting the individual elements +as it does not actually traverse +.Fa head2 . +.Pp +The +.Fn STAILQ_FOREACH +macro is used for queue traversal: +.Bd -literal -offset indent +STAILQ_FOREACH(np, head, FIELDNAME) +.Ed +.Pp +The macro +.Fn STAILQ_FOREACH_SAFE +traverses the queue referenced by head in a +forward direction, assigning each element in turn to var. +However, unlike +.Fn STAILQ_FOREACH +it is permitted to remove var as well +as free it from within the loop safely without interfering with the traversal. +.Pp +The +.Fn STAILQ_FIRST , +.Fn STAILQ_NEXT , +and +.Fn STAILQ_LAST +macros can be used to manually traverse a tail queue or an arbitrary part of +one. +The +.Fn STAILQ_EMPTY +macro should be used to check whether a tail queue is empty. +.Sh SINGLY-LINKED TAIL QUEUE EXAMPLE +.Bd -literal +STAILQ_HEAD(listhead, entry) head = STAILQ_HEAD_INITIALIZER(head); +struct entry { + ... + STAILQ_ENTRY(entry) entries; /* Singly-linked tail queue. */ + ... +} *n1, *n2, *np; + +n1 = malloc(sizeof(struct entry)); /* Insert at the head. */ +STAILQ_INSERT_HEAD(&head, n1, entries); + +n2 = malloc(sizeof(struct entry)); /* Insert at the tail. */ +STAILQ_INSERT_TAIL(&head, n2, entries); + +n2 = malloc(sizeof(struct entry)); /* Insert after. */ +STAILQ_INSERT_AFTER(&head, n1, n2, entries); + + /* Deletion. */ +STAILQ_REMOVE(&head, n2, entry, entries); +free(n2); + /* Deletion from the head. */ +n3 = STAILQ_FIRST(&head); +STAILQ_REMOVE_HEAD(&head, entries); +free(n3); + /* Forward traversal. */ +STAILQ_FOREACH(np, &head, entries) + np-> ... + /* Safe forward traversal. */ +STAILQ_FOREACH_SAFE(np, &head, entries, np_temp) { + np-> ... + STAILQ_REMOVE(&head, np, entry, entries); + free(np); +} + /* Delete. */ +while (!STAILQ_EMPTY(&head)) { + n1 = STAILQ_FIRST(&head); + STAILQ_REMOVE_HEAD(&head, entries); + free(n1); +} +.Ed +.Sh TAIL QUEUES +A tail queue is headed by a structure defined by the +.Fn TAILQ_HEAD +macro. +This structure contains a pair of pointers, +one to the first element in the tail queue and the other to +the last element in the tail queue. +The elements are doubly linked so that an arbitrary element can be +removed without traversing the tail queue. +New elements can be added to the queue after an existing element, +before an existing element, at the head of the queue, or at the end +of the queue. +A +.Fa TAILQ_HEAD +structure is declared as follows: +.Bd -literal -offset indent +TAILQ_HEAD(HEADNAME, TYPE) head; +.Ed +.Pp +where +.Fa HEADNAME +is the name of the structure to be defined, and struct +.Fa TYPE +is the type of the elements to be linked into the tail queue. +A pointer to the head of the tail queue can later be declared as: +.Bd -literal -offset indent +struct HEADNAME *headp; +.Ed +.Pp +(The names +.Li head +and +.Li headp +are user selectable.) +.Pp +The +.Fn TAILQ_ENTRY +macro declares a structure that connects the elements in +the tail queue. +.Pp +The +.Fn TAILQ_INIT +macro initializes the tail queue referenced by +.Fa head . +.Pp +The tail queue can also be initialized statically by using the +.Fn TAILQ_HEAD_INITIALIZER +macro. +.Pp +The +.Fn TAILQ_INSERT_HEAD +macro inserts the new element +.Fa elm +at the head of the tail queue. +.Pp +The +.Fn TAILQ_INSERT_TAIL +macro inserts the new element +.Fa elm +at the end of the tail queue. +.Pp +The +.Fn TAILQ_INSERT_AFTER +macro inserts the new element +.Fa elm +after the element +.Fa listelm . +.Pp +The +.Fn TAILQ_INSERT_BEFORE +macro inserts the new element +.Fa elm +before the element +.Fa listelm . +.Pp +The +.Fn TAILQ_REMOVE +macro removes the element +.Fa elm +from the tail queue. +.Pp +The +.Fn TAILQ_REPLACE +macro replaces the list element +.Fa elm +with the new element +.Fa elm2 . +.Pp +The +.Fn TAILQ_CONCAT +macro concatenates all the elements of the tail queue referenced by +.Fa head2 +to the end of the tail queue referenced by +.Fa head1 , +emptying +.Fa head2 +in the process. +This is more efficient than removing and inserting the individual elements +as it does not actually traverse +.Fa head2 . +.Pp +.Fn TAILQ_FOREACH +and +.Fn TAILQ_FOREACH_REVERSE +are used for traversing a tail queue. +.Fn TAILQ_FOREACH +starts at the first element and proceeds towards the last. +.Fn TAILQ_FOREACH_REVERSE +starts at the last element and proceeds towards the first. +.Bd -literal -offset indent +TAILQ_FOREACH(np, &head, FIELDNAME) +TAILQ_FOREACH_REVERSE(np, &head, HEADNAME, FIELDNAME) +.Ed +.Pp +The macros +.Fn TAILQ_FOREACH_SAFE +and +.Fn TAILQ_FOREACH_REVERSE_SAFE +traverse the list referenced by head +in a forward or reverse direction respectively, +assigning each element in turn to var. +However, unlike their unsafe counterparts, +they permit both the removal of var +as well as freeing it from within the loop safely +without interfering with the traversal. +.Pp +The +.Fn TAILQ_FIRST , +.Fn TAILQ_NEXT , +.Fn TAILQ_LAST +and +.Fn TAILQ_PREV +macros can be used to manually traverse a tail queue or an arbitrary part of +one. +.Pp +The +.Fn TAILQ_EMPTY +macro should be used to check whether a tail queue is empty. +.Sh TAIL QUEUE EXAMPLE +.Bd -literal +TAILQ_HEAD(tailhead, entry) head; +struct entry { + ... + TAILQ_ENTRY(entry) entries; /* Tail queue. */ + ... +} *n1, *n2, *np; + +TAILQ_INIT(&head); /* Initialize queue. */ + +n1 = malloc(sizeof(struct entry)); /* Insert at the head. */ +TAILQ_INSERT_HEAD(&head, n1, entries); + +n1 = malloc(sizeof(struct entry)); /* Insert at the tail. */ +TAILQ_INSERT_TAIL(&head, n1, entries); + +n2 = malloc(sizeof(struct entry)); /* Insert after. */ +TAILQ_INSERT_AFTER(&head, n1, n2, entries); + +n2 = malloc(sizeof(struct entry)); /* Insert before. */ +TAILQ_INSERT_BEFORE(n1, n2, entries); + /* Forward traversal. */ +TAILQ_FOREACH(np, &head, entries) + np-> ... + /* Manual forward traversal. */ +for (np = n2; np != NULL; np = TAILQ_NEXT(np, entries)) + np-> ... + /* Delete. */ +while ((np = TAILQ_FIRST(&head))) { + TAILQ_REMOVE(&head, np, entries); + free(np); +} + +.Ed +.Sh SEE ALSO +.Xr tree 3 +.Sh NOTES +It is an error to assume the next and previous fields are preserved +after an element has been removed from a list or queue. +Using any macro (except the various forms of insertion) on an element +removed from a list or queue is incorrect. +An example of erroneous usage is removing the same element twice. +.Pp +The +.Fn SLIST_END , +.Fn LIST_END , +.Fn SIMPLEQ_END , +.Fn STAILQ_END +and +.Fn TAILQ_END +macros are deprecated; they provided symmetry with the historical +.Fn CIRCLEQ_END +and just expand to +.Dv NULL . +.Pp +Trying to free a list in the following way is a common error: +.Bd -literal -offset indent +LIST_FOREACH(var, head, entry) + free(var); +free(head); +.Ed +.Pp +Since +.Va var +is free'd, the FOREACH macros refer to a pointer that may have been +reallocated already. +A similar situation occurs when the current element is deleted +from the list. +In cases like these the data structure's FOREACH_SAFE macros should be used +instead. +.Sh HISTORY +The +.Nm queue +functions first appeared in +.Bx 4.4 . +The historical circle queue macros were deprecated in +.Ox 5.5 . diff --git a/share/man/man3/tree.3 b/share/man/man3/tree.3 new file mode 100644 index 0000000..7fa1f31 --- /dev/null +++ b/share/man/man3/tree.3 @@ -0,0 +1,582 @@ +.\"/* +.\" * Copyright 2002 Niels Provos <provos@citi.umich.edu> +.\" * All rights reserved. +.\" * +.\" * Redistribution and use in source and binary forms, with or without +.\" * modification, are permitted provided that the following conditions +.\" * are met: +.\" * 1. Redistributions of source code must retain the above copyright +.\" * notice, this list of conditions and the following disclaimer. +.\" * 2. Redistributions in binary form must reproduce the above copyright +.\" * notice, this list of conditions and the following disclaimer in the +.\" * documentation and/or other materials provided with the distribution. +.\" * +.\" * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" */ +.Dd $Mdocdate: Dec 16 2024 $ +.Dt SPLAY_INIT 3 +.Os +.Sh NAME +.Nm SPLAY_PROTOTYPE , +.Nm SPLAY_GENERATE , +.Nm SPLAY_ENTRY , +.Nm SPLAY_HEAD , +.Nm SPLAY_INITIALIZER , +.Nm SPLAY_ROOT , +.Nm SPLAY_EMPTY , +.Nm SPLAY_NEXT , +.Nm SPLAY_MIN , +.Nm SPLAY_MAX , +.Nm SPLAY_FIND , +.Nm SPLAY_LEFT , +.Nm SPLAY_RIGHT , +.Nm SPLAY_FOREACH , +.Nm SPLAY_INIT , +.Nm SPLAY_INSERT , +.Nm SPLAY_REMOVE , +.Nm RB_PROTOTYPE , +.Nm RB_PROTOTYPE_STATIC , +.Nm RB_GENERATE , +.Nm RB_GENERATE_STATIC , +.Nm RB_ENTRY , +.Nm RB_HEAD , +.Nm RB_INITIALIZER , +.Nm RB_ROOT , +.Nm RB_EMPTY , +.Nm RB_NEXT , +.Nm RB_PREV , +.Nm RB_MIN , +.Nm RB_MAX , +.Nm RB_FIND , +.Nm RB_NFIND , +.Nm RB_LEFT , +.Nm RB_RIGHT , +.Nm RB_PARENT , +.Nm RB_FOREACH , +.Nm RB_FOREACH_SAFE , +.Nm RB_FOREACH_REVERSE , +.Nm RB_FOREACH_REVERSE_SAFE , +.Nm RB_INIT , +.Nm RB_INSERT , +.Nm RB_REMOVE +.Nd implementations of splay and red-black trees +.Sh SYNOPSIS +.In sys/tree.h +.Pp +.Fn SPLAY_PROTOTYPE "NAME" "TYPE" "FIELD" "CMP" +.Fn SPLAY_GENERATE "NAME" "TYPE" "FIELD" "CMP" +.Fn SPLAY_ENTRY "TYPE" +.Fn SPLAY_HEAD "HEADNAME" "TYPE" +.Ft "struct TYPE *" +.Fn SPLAY_INITIALIZER "SPLAY_HEAD *head" +.Fn SPLAY_ROOT "SPLAY_HEAD *head" +.Ft "int" +.Fn SPLAY_EMPTY "SPLAY_HEAD *head" +.Ft "struct TYPE *" +.Fn SPLAY_NEXT "NAME" "SPLAY_HEAD *head" "struct TYPE *elm" +.Ft "struct TYPE *" +.Fn SPLAY_MIN "NAME" "SPLAY_HEAD *head" +.Ft "struct TYPE *" +.Fn SPLAY_MAX "NAME" "SPLAY_HEAD *head" +.Ft "struct TYPE *" +.Fn SPLAY_FIND "NAME" "SPLAY_HEAD *head" "struct TYPE *elm" +.Ft "struct TYPE *" +.Fn SPLAY_LEFT "struct TYPE *elm" "SPLAY_ENTRY NAME" +.Ft "struct TYPE *" +.Fn SPLAY_RIGHT "struct TYPE *elm" "SPLAY_ENTRY NAME" +.Fn SPLAY_FOREACH "VARNAME" "NAME" "SPLAY_HEAD *head" +.Ft void +.Fn SPLAY_INIT "SPLAY_HEAD *head" +.Ft "struct TYPE *" +.Fn SPLAY_INSERT "NAME" "SPLAY_HEAD *head" "struct TYPE *elm" +.Ft "struct TYPE *" +.Fn SPLAY_REMOVE "NAME" "SPLAY_HEAD *head" "struct TYPE *elm" +.Pp +.Fn RB_PROTOTYPE "NAME" "TYPE" "FIELD" "CMP" +.Fn RB_PROTOTYPE_STATIC "NAME" "TYPE" "FIELD" "CMP" +.Fn RB_GENERATE "NAME" "TYPE" "FIELD" "CMP" +.Fn RB_GENERATE_STATIC "NAME" "TYPE" "FIELD" "CMP" +.Fn RB_ENTRY "TYPE" +.Fn RB_HEAD "HEADNAME" "TYPE" +.Fn RB_INITIALIZER "RB_HEAD *head" +.Ft "struct TYPE *" +.Fn RB_ROOT "RB_HEAD *head" +.Ft "int" +.Fn RB_EMPTY "RB_HEAD *head" +.Ft "struct TYPE *" +.Fn RB_NEXT "NAME" "RB_HEAD *head" "struct TYPE *elm" +.Ft "struct TYPE *" +.Fn RB_PREV "NAME" "RB_HEAD *head" "struct TYPE *elm" +.Ft "struct TYPE *" +.Fn RB_MIN "NAME" "RB_HEAD *head" +.Ft "struct TYPE *" +.Fn RB_MAX "NAME" "RB_HEAD *head" +.Ft "struct TYPE *" +.Fn RB_FIND "NAME" "RB_HEAD *head" "struct TYPE *elm" +.Ft "struct TYPE *" +.Fn RB_NFIND "NAME" "RB_HEAD *head" "struct TYPE *elm" +.Ft "struct TYPE *" +.Fn RB_LEFT "struct TYPE *elm" "RB_ENTRY NAME" +.Ft "struct TYPE *" +.Fn RB_RIGHT "struct TYPE *elm" "RB_ENTRY NAME" +.Ft "struct TYPE *" +.Fn RB_PARENT "struct TYPE *elm" "RB_ENTRY NAME" +.Fn RB_FOREACH "VARNAME" "NAME" "RB_HEAD *head" +.Fn RB_FOREACH_SAFE "VARNAME" "NAME" "RB_HEAD *head" "TEMP_VARNAME" +.Fn RB_FOREACH_REVERSE "VARNAME" "NAME" "RB_HEAD *head" +.Fn RB_FOREACH_REVERSE_SAFE "VARNAME" "NAME" "RB_HEAD *head" "TEMP_VARNAME" +.Ft void +.Fn RB_INIT "RB_HEAD *head" +.Ft "struct TYPE *" +.Fn RB_INSERT "NAME" "RB_HEAD *head" "struct TYPE *elm" +.Ft "struct TYPE *" +.Fn RB_REMOVE "NAME" "RB_HEAD *head" "struct TYPE *elm" +.Sh DESCRIPTION +These macros define data structures for different types of trees: +splay trees and red-black trees. +.Pp +In the macro definitions, +.Fa TYPE +is the name tag of a user defined structure that must contain a field named +.Fa FIELD , +of type +.Li SPLAY_ENTRY +or +.Li RB_ENTRY . +The argument +.Fa HEADNAME +is the name tag of a user defined structure that must be declared +using the macros +.Fn SPLAY_HEAD +or +.Fn RB_HEAD . +The argument +.Fa NAME +has to be a unique name prefix for every tree that is defined. +.Pp +The function prototypes are declared with +.Li SPLAY_PROTOTYPE , +.Li RB_PROTOTYPE , +or +.Li RB_PROTOTYPE_STATIC . +The function bodies are generated with +.Li SPLAY_GENERATE , +.Li RB_GENERATE , +or +.Li RB_GENERATE_STATIC . +See the examples below for further explanation of how these macros are used. +.Sh SPLAY TREES +A splay tree is a self-organizing data structure. +Every operation on the tree causes a splay to happen. +The splay moves the requested node to the root of the tree and partly +rebalances it. +.Pp +This has the benefit that request locality causes faster lookups as +the requested nodes move to the top of the tree. +On the other hand, every lookup causes memory writes. +.Pp +The Balance Theorem bounds the total access time for m operations +and n inserts on an initially empty tree as O((m + n)lg n). +The amortized cost for a sequence of m accesses to a splay tree is O(lg n). +.Pp +A splay tree is headed by a structure defined by the +.Fn SPLAY_HEAD +macro. +A +.Fa SPLAY_HEAD +structure is declared as follows: +.Bd -literal -offset indent +SPLAY_HEAD(HEADNAME, TYPE) head; +.Ed +.Pp +where +.Fa HEADNAME +is the name of the structure to be defined, and struct +.Fa TYPE +is the type of the elements to be inserted into the tree. +.Pp +The +.Fn SPLAY_ENTRY +macro declares a structure that allows elements to be connected in the tree. +.Pp +In order to use the functions that manipulate the tree structure, +their prototypes need to be declared with the +.Fn SPLAY_PROTOTYPE +macro, +where +.Fa NAME +is a unique identifier for this particular tree. +The +.Fa TYPE +argument is the type of the structure that is being managed +by the tree. +The +.Fa FIELD +argument is the name of the element defined by +.Fn SPLAY_ENTRY . +.Pp +The function bodies are generated with the +.Fn SPLAY_GENERATE +macro. +It takes the same arguments as the +.Fn SPLAY_PROTOTYPE +macro, but should be used only once. +.Pp +Finally, +the +.Fa CMP +argument is the name of a function used to compare trees' nodes +with each other. +The function takes two arguments of type +.Fa "struct TYPE *" . +If the first argument is smaller than the second, the function returns a +value smaller than zero. +If they are equal, the function returns zero. +Otherwise, it should return a value greater than zero. +The compare function defines the order of the tree elements. +.Pp +The +.Fn SPLAY_INIT +macro initializes the tree referenced by +.Fa head . +.Pp +The splay tree can also be initialized statically by using the +.Fn SPLAY_INITIALIZER +macro like this: +.Bd -literal -offset indent +SPLAY_HEAD(HEADNAME, TYPE) head = SPLAY_INITIALIZER(&head); +.Ed +.Pp +The +.Fn SPLAY_INSERT +macro inserts the new element +.Fa elm +into the tree. +Upon success, +.Va NULL +is returned. +If a matching element already exists in the tree, the insertion is +aborted, and a pointer to the existing element is returned. +.Pp +The +.Fn SPLAY_REMOVE +macro removes the element +.Fa elm +from the tree pointed by +.Fa head . +Upon success, a pointer to the removed element is returned. +.Va NULL +is returned if +.Fa elm +is not present in the tree. +.Pp +The +.Fn SPLAY_FIND +macro can be used to find a particular element in the tree. +.Bd -literal -offset indent +struct TYPE find, *res; +find.key = 30; +res = SPLAY_FIND(NAME, &head, &find); +.Ed +.Pp +The +.Fn SPLAY_ROOT , +.Fn SPLAY_MIN , +.Fn SPLAY_MAX , +and +.Fn SPLAY_NEXT +macros can be used to traverse the tree: +.Bd -literal -offset indent +for (np = SPLAY_MIN(NAME, &head); np != NULL; np = SPLAY_NEXT(NAME, &head, np)) +.Ed +.Pp +Or, for simplicity, one can use the +.Fn SPLAY_FOREACH +macro: +.Bd -literal -offset indent +SPLAY_FOREACH(np, NAME, &head) +.Ed +.Pp +The +.Fn SPLAY_EMPTY +macro should be used to check whether a splay tree is empty. +.Sh RED-BLACK TREES +A red-black tree is a binary search tree with the node color as an +extra attribute. +It fulfills a set of conditions: +.Pp +.Bl -enum -compact -offset indent +.It +every search path from the root to a leaf consists of the same number of +black nodes, +.It +each red node (except for the root) has a black parent, +.It +each leaf node is black. +.El +.Pp +Every operation on a red-black tree is bounded as O(lg n). +The maximum height of a red-black tree is 2lg (n+1). +.Pp +A red-black tree is headed by a structure defined by the +.Fn RB_HEAD +macro. +A +.Fa RB_HEAD +structure is declared as follows: +.Bd -literal -offset indent +RB_HEAD(HEADNAME, TYPE) head; +.Ed +.Pp +where +.Fa HEADNAME +is the name of the structure to be defined, and struct +.Fa TYPE +is the type of the elements to be inserted into the tree. +.Pp +The +.Fn RB_ENTRY +macro declares a structure that allows elements to be connected in the tree. +.Pp +In order to use the functions that manipulate the tree structure, +their prototypes need to be declared with the +.Fn RB_PROTOTYPE +or +.Fn RB_PROTOTYPE_STATIC +macros, +where +.Fa NAME +is a unique identifier for this particular tree. +The +.Fa TYPE +argument is the type of the structure that is being managed +by the tree. +The +.Fa FIELD +argument is the name of the element defined by +.Fn RB_ENTRY . +.Pp +The function bodies are generated with the +.Fn RB_GENERATE +or +.Fn RB_GENERATE_STATIC +macros. +These macros take the same arguments as the +.Fn RB_PROTOTYPE +and +.Fn RB_PROTOTYPE_STATIC +macros, but should be used only once. +.Pp +Finally, +the +.Fa CMP +argument is the name of a function used to compare trees' nodes +with each other. +The function takes two arguments of type +.Fa "struct TYPE *" . +If the first argument is smaller than the second, the function returns a +value smaller than zero. +If they are equal, the function returns zero. +Otherwise, it should return a value greater than zero. +The compare function defines the order of the tree elements. +.Pp +The +.Fn RB_INIT +macro initializes the tree referenced by +.Fa head . +.Pp +The red-black tree can also be initialized statically by using the +.Fn RB_INITIALIZER +macro like this: +.Bd -literal -offset indent +RB_HEAD(HEADNAME, TYPE) head = RB_INITIALIZER(&head); +.Ed +.Pp +The +.Fn RB_INSERT +macro inserts the new element +.Fa elm +into the tree. +Upon success, +.Va NULL +is returned. +If a matching element already exists in the tree, the insertion is +aborted, and a pointer to the existing element is returned. +.Pp +The +.Fn RB_REMOVE +macro removes the element +.Fa elm +from the tree pointed by +.Fa head . +.Fn RB_REMOVE +returns +.Fa elm . +.Pp +The +.Fn RB_FIND +and +.Fn RB_NFIND +macros can be used to find a particular element in the tree. +.Fn RB_FIND +finds the node with the same key as +.Fa elm . +.Fn RB_NFIND +finds the first node greater than or equal to the search key. +.Bd -literal -offset indent +struct TYPE find, *res; +find.key = 30; +res = RB_FIND(NAME, &head, &find); +.Ed +.Pp +The +.Fn RB_ROOT , +.Fn RB_MIN , +.Fn RB_MAX , +.Fn RB_NEXT , +and +.Fn RB_PREV +macros can be used to traverse the tree: +.Bd -literal -offset indent +for (np = RB_MIN(NAME, &head); np != NULL; np = RB_NEXT(NAME, &head, np)) +.Ed +.Pp +Or, for simplicity, one can use the +.Fn RB_FOREACH +or +.Fn RB_FOREACH_REVERSE +macros: +.Bd -literal -offset indent +RB_FOREACH(np, NAME, &head) +.Ed +.Pp +The macros +.Fn RB_FOREACH_SAFE +and +.Fn RB_FOREACH_REVERSE_SAFE +traverse the tree referenced by head +in a forward or reverse direction respectively, +assigning each element in turn to np. +However, unlike their unsafe counterparts, +they permit both the removal of np +as well as freeing it from within the loop safely +without interfering with the traversal. +.Pp +The +.Fn RB_EMPTY +macro should be used to check whether a red-black tree is empty. +.Sh EXAMPLES +The following example demonstrates how to declare a red-black tree +holding integers. +Values are inserted into it and the contents of the tree are printed +in order. +Lastly, the internal structure of the tree is printed. +.Bd -literal -offset 3n +#include <sys/tree.h> +#include <err.h> +#include <stdio.h> +#include <stdlib.h> + +struct node { + RB_ENTRY(node) entry; + int i; +}; + +int intcmp(struct node *, struct node *); +void print_tree(struct node *); + +int +intcmp(struct node *e1, struct node *e2) +{ + return (e1->i < e2->i ? -1 : e1->i > e2->i); +} + +RB_HEAD(inttree, node) head = RB_INITIALIZER(&head); +RB_PROTOTYPE(inttree, node, entry, intcmp) +RB_GENERATE(inttree, node, entry, intcmp) + +int testdata[] = { + 20, 16, 17, 13, 3, 6, 1, 8, 2, 4, 10, 19, 5, 9, 12, 15, 18, + 7, 11, 14 +}; + +void +print_tree(struct node *n) +{ + struct node *left, *right; + + if (n == NULL) { + printf("nil"); + return; + } + left = RB_LEFT(n, entry); + right = RB_RIGHT(n, entry); + if (left == NULL && right == NULL) + printf("%d", n->i); + else { + printf("%d(", n->i); + print_tree(left); + printf(","); + print_tree(right); + printf(")"); + } +} + +int +main(void) +{ + int i; + struct node *n; + + for (i = 0; i < sizeof(testdata) / sizeof(testdata[0]); i++) { + if ((n = malloc(sizeof(struct node))) == NULL) + err(1, NULL); + n->i = testdata[i]; + RB_INSERT(inttree, &head, n); + } + + RB_FOREACH(n, inttree, &head) { + printf("%d\en", n->i); + } + print_tree(RB_ROOT(&head)); + printf("\en"); + return (0); +} +.Ed +.Sh SEE ALSO +.Xr queue 3 +.Sh NOTES +Trying to free a tree in the following way is a common error: +.Bd -literal -offset indent +SPLAY_FOREACH(var, NAME, &head) { + SPLAY_REMOVE(NAME, &head, var); + free(var); +} +free(head); +.Ed +.Pp +Since +.Va var +is free'd, the +.Fn FOREACH +macro refers to a pointer that may have been reallocated already. +Proper code needs a second variable. +.Bd -literal -offset indent +for (var = SPLAY_MIN(NAME, &head); var != NULL; var = nxt) { + nxt = SPLAY_NEXT(NAME, &head, var); + SPLAY_REMOVE(NAME, &head, var); + free(var); +} +.Ed +.Sh AUTHORS +The author of the tree macros is +.An Niels Provos . |