Add two new macros, SLIST_CONCAT and LIST_CONCAT. Note in both the
queue.h header file and in the queue.3 manual page that they are O(n) so should be used only in low-usage paths with short lists (otherwise an STAILQ or TAILQ should be used). Reviewed by: kib
This commit is contained in:
parent
39f7cbe9ab
commit
65d3199746
@ -28,12 +28,13 @@
|
|||||||
.\" @(#)queue.3 8.2 (Berkeley) 1/24/94
|
.\" @(#)queue.3 8.2 (Berkeley) 1/24/94
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd June 24, 2015
|
.Dd August 15, 2016
|
||||||
.Dt QUEUE 3
|
.Dt QUEUE 3
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
.Nm SLIST_CLASS_ENTRY ,
|
.Nm SLIST_CLASS_ENTRY ,
|
||||||
.Nm SLIST_CLASS_HEAD ,
|
.Nm SLIST_CLASS_HEAD ,
|
||||||
|
.Nm SLIST_CONCAT ,
|
||||||
.Nm SLIST_EMPTY ,
|
.Nm SLIST_EMPTY ,
|
||||||
.Nm SLIST_ENTRY ,
|
.Nm SLIST_ENTRY ,
|
||||||
.Nm SLIST_FIRST ,
|
.Nm SLIST_FIRST ,
|
||||||
@ -75,6 +76,7 @@
|
|||||||
.Nm STAILQ_SWAP ,
|
.Nm STAILQ_SWAP ,
|
||||||
.Nm LIST_CLASS_ENTRY ,
|
.Nm LIST_CLASS_ENTRY ,
|
||||||
.Nm LIST_CLASS_HEAD ,
|
.Nm LIST_CLASS_HEAD ,
|
||||||
|
.Nm LIST_CONCAT ,
|
||||||
.Nm LIST_EMPTY ,
|
.Nm LIST_EMPTY ,
|
||||||
.Nm LIST_ENTRY ,
|
.Nm LIST_ENTRY ,
|
||||||
.Nm LIST_FIRST ,
|
.Nm LIST_FIRST ,
|
||||||
@ -125,6 +127,7 @@ lists and tail queues
|
|||||||
.\"
|
.\"
|
||||||
.Fn SLIST_CLASS_ENTRY "CLASSTYPE"
|
.Fn SLIST_CLASS_ENTRY "CLASSTYPE"
|
||||||
.Fn SLIST_CLASS_HEAD "HEADNAME" "CLASSTYPE"
|
.Fn SLIST_CLASS_HEAD "HEADNAME" "CLASSTYPE"
|
||||||
|
.Fn SLIST_CONCAT "SLIST_HEAD *head1" "SLIST_HEAD *head2" "TYPE" "SLIST_ENTRY NAME"
|
||||||
.Fn SLIST_EMPTY "SLIST_HEAD *head"
|
.Fn SLIST_EMPTY "SLIST_HEAD *head"
|
||||||
.Fn SLIST_ENTRY "TYPE"
|
.Fn SLIST_ENTRY "TYPE"
|
||||||
.Fn SLIST_FIRST "SLIST_HEAD *head"
|
.Fn SLIST_FIRST "SLIST_HEAD *head"
|
||||||
@ -168,6 +171,7 @@ lists and tail queues
|
|||||||
.\"
|
.\"
|
||||||
.Fn LIST_CLASS_ENTRY "CLASSTYPE"
|
.Fn LIST_CLASS_ENTRY "CLASSTYPE"
|
||||||
.Fn LIST_CLASS_HEAD "HEADNAME" "CLASSTYPE"
|
.Fn LIST_CLASS_HEAD "HEADNAME" "CLASSTYPE"
|
||||||
|
.Fn LIST_CONCAT "LIST_HEAD *head1" "LIST_HEAD *head2" "TYPE" "LIST_ENTRY NAME"
|
||||||
.Fn LIST_EMPTY "LIST_HEAD *head"
|
.Fn LIST_EMPTY "LIST_HEAD *head"
|
||||||
.Fn LIST_ENTRY "TYPE"
|
.Fn LIST_ENTRY "TYPE"
|
||||||
.Fn LIST_FIRST "LIST_HEAD *head"
|
.Fn LIST_FIRST "LIST_HEAD *head"
|
||||||
@ -249,6 +253,8 @@ Singly-linked lists add the following functionality:
|
|||||||
.Bl -enum -compact -offset indent
|
.Bl -enum -compact -offset indent
|
||||||
.It
|
.It
|
||||||
O(n) removal of any entry in the list.
|
O(n) removal of any entry in the list.
|
||||||
|
.It
|
||||||
|
O(n) concatenation of two lists.
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
Singly-linked tail queues add the following functionality:
|
Singly-linked tail queues add the following functionality:
|
||||||
@ -296,6 +302,8 @@ Linked lists are the simplest of the doubly linked data structures.
|
|||||||
They add the following functionality over the above:
|
They add the following functionality over the above:
|
||||||
.Bl -enum -compact -offset indent
|
.Bl -enum -compact -offset indent
|
||||||
.It
|
.It
|
||||||
|
O(n) concatenation of two lists.
|
||||||
|
.It
|
||||||
They may be traversed backwards.
|
They may be traversed backwards.
|
||||||
.El
|
.El
|
||||||
However:
|
However:
|
||||||
@ -401,6 +409,19 @@ evaluates to an initializer for the list
|
|||||||
.Fa head .
|
.Fa head .
|
||||||
.Pp
|
.Pp
|
||||||
The macro
|
The macro
|
||||||
|
.Nm SLIST_CONCAT
|
||||||
|
concatenates the list headed by
|
||||||
|
.Fa head2
|
||||||
|
onto the end of the one headed by
|
||||||
|
.Fa head1
|
||||||
|
removing all entries from the former.
|
||||||
|
Use of this macro should be avoided as it traverses the entirety of the
|
||||||
|
.Fa head1
|
||||||
|
list.
|
||||||
|
A singly-linked tail queue should be used if this macro is needed in
|
||||||
|
high-usage code paths or to operate on long lists.
|
||||||
|
.Pp
|
||||||
|
The macro
|
||||||
.Nm SLIST_EMPTY
|
.Nm SLIST_EMPTY
|
||||||
evaluates to true if there are no elements in the list.
|
evaluates to true if there are no elements in the list.
|
||||||
.Pp
|
.Pp
|
||||||
@ -508,6 +529,9 @@ The macro
|
|||||||
removes the element
|
removes the element
|
||||||
.Fa elm
|
.Fa elm
|
||||||
from the list.
|
from the list.
|
||||||
|
Use of this macro should be avoided as it traverses the entire list.
|
||||||
|
A doubly-linked list should be used if this macro is needed in
|
||||||
|
high-usage code paths or to operate on long lists.
|
||||||
.Pp
|
.Pp
|
||||||
The macro
|
The macro
|
||||||
.Nm SLIST_SWAP
|
.Nm SLIST_SWAP
|
||||||
@ -724,6 +748,9 @@ The macro
|
|||||||
removes the element
|
removes the element
|
||||||
.Fa elm
|
.Fa elm
|
||||||
from the tail queue.
|
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
|
.Pp
|
||||||
The macro
|
The macro
|
||||||
.Nm STAILQ_SWAP
|
.Nm STAILQ_SWAP
|
||||||
@ -823,6 +850,19 @@ evaluates to an initializer for the list
|
|||||||
.Fa head .
|
.Fa head .
|
||||||
.Pp
|
.Pp
|
||||||
The macro
|
The macro
|
||||||
|
.Nm LIST_CONCAT
|
||||||
|
concatenates the list headed by
|
||||||
|
.Fa head2
|
||||||
|
onto the end of the one headed by
|
||||||
|
.Fa head1
|
||||||
|
removing all entries from the former.
|
||||||
|
Use of this macro should be avoided as it traverses the entirety of the
|
||||||
|
.Fa head1
|
||||||
|
list.
|
||||||
|
A tail queue should be used if this macro is needed in
|
||||||
|
high-usage code paths or to operate on long lists.
|
||||||
|
.Pp
|
||||||
|
The macro
|
||||||
.Nm LIST_EMPTY
|
.Nm LIST_EMPTY
|
||||||
evaluates to true if there are no elements in the list.
|
evaluates to true if there are no elements in the list.
|
||||||
.Pp
|
.Pp
|
||||||
|
@ -76,6 +76,10 @@
|
|||||||
*
|
*
|
||||||
* For details on the use of these macros, see the queue(3) manual page.
|
* For details on the use of these macros, see the queue(3) manual page.
|
||||||
*
|
*
|
||||||
|
* Below is a summary of implemented functions where:
|
||||||
|
* + means the macro is available
|
||||||
|
* - means the macro is not available
|
||||||
|
* s means the macro is available but is slow (runs in O(n) time)
|
||||||
*
|
*
|
||||||
* SLIST LIST STAILQ TAILQ
|
* SLIST LIST STAILQ TAILQ
|
||||||
* _HEAD + + + +
|
* _HEAD + + + +
|
||||||
@ -101,10 +105,10 @@
|
|||||||
* _INSERT_BEFORE - + - +
|
* _INSERT_BEFORE - + - +
|
||||||
* _INSERT_AFTER + + + +
|
* _INSERT_AFTER + + + +
|
||||||
* _INSERT_TAIL - - + +
|
* _INSERT_TAIL - - + +
|
||||||
* _CONCAT - - + +
|
* _CONCAT s s + +
|
||||||
* _REMOVE_AFTER + - + -
|
* _REMOVE_AFTER + - + -
|
||||||
* _REMOVE_HEAD + - + -
|
* _REMOVE_HEAD + - + -
|
||||||
* _REMOVE + + + +
|
* _REMOVE s + s +
|
||||||
* _SWAP + + + +
|
* _SWAP + + + +
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -183,6 +187,19 @@ struct { \
|
|||||||
/*
|
/*
|
||||||
* Singly-linked List functions.
|
* Singly-linked List functions.
|
||||||
*/
|
*/
|
||||||
|
#define SLIST_CONCAT(head1, head2, type, field) do { \
|
||||||
|
QUEUE_TYPEOF(type) *curelm = SLIST_FIRST(head1); \
|
||||||
|
if (curelm == NULL) { \
|
||||||
|
if ((SLIST_FIRST(head1) = SLIST_FIRST(head2)) != NULL) \
|
||||||
|
SLIST_INIT(head2); \
|
||||||
|
} else if (SLIST_FIRST(head2) != NULL) { \
|
||||||
|
while (SLIST_NEXT(curelm, field) != NULL) \
|
||||||
|
curelm = SLIST_NEXT(curelm, field); \
|
||||||
|
SLIST_NEXT(curelm, field) = SLIST_FIRST(head2); \
|
||||||
|
SLIST_INIT(head2); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
|
#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
|
||||||
|
|
||||||
#define SLIST_FIRST(head) ((head)->slh_first)
|
#define SLIST_FIRST(head) ((head)->slh_first)
|
||||||
@ -447,6 +464,23 @@ struct { \
|
|||||||
#define QMD_LIST_CHECK_PREV(elm, field)
|
#define QMD_LIST_CHECK_PREV(elm, field)
|
||||||
#endif /* (_KERNEL && INVARIANTS) */
|
#endif /* (_KERNEL && INVARIANTS) */
|
||||||
|
|
||||||
|
#define LIST_CONCAT(head1, head2, type, field) do { \
|
||||||
|
QUEUE_TYPEOF(type) *curelm = LIST_FIRST(head1); \
|
||||||
|
if (curelm == NULL) { \
|
||||||
|
if ((LIST_FIRST(head1) = LIST_FIRST(head2)) != NULL) { \
|
||||||
|
LIST_FIRST(head2)->field.le_prev = \
|
||||||
|
&LIST_FIRST((head1)); \
|
||||||
|
LIST_INIT(head2); \
|
||||||
|
} \
|
||||||
|
} else if (LIST_FIRST(head2) != NULL) { \
|
||||||
|
while (LIST_NEXT(curelm, field) != NULL) \
|
||||||
|
curelm = LIST_NEXT(curelm, field); \
|
||||||
|
LIST_NEXT(curelm, field) = LIST_FIRST(head2); \
|
||||||
|
LIST_FIRST(head2)->field.le_prev = &LIST_NEXT(curelm, field); \
|
||||||
|
LIST_INIT(head2); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define LIST_EMPTY(head) ((head)->lh_first == NULL)
|
#define LIST_EMPTY(head) ((head)->lh_first == NULL)
|
||||||
|
|
||||||
#define LIST_FIRST(head) ((head)->lh_first)
|
#define LIST_FIRST(head) ((head)->lh_first)
|
||||||
|
Loading…
Reference in New Issue
Block a user