mirror of
https://github.com/samba-team/samba.git
synced 2025-03-24 10:50:22 +03:00
util: rewrite dlinklist.h so that DLIST_ADD_END() is O(1)
This changes the meaning of the ->prev pointer in our doubly linked lists to point at the end of the list from the front of the list. That allows us to implement DLIST_ADD_END() and related functions in O(1) time, which can be a huge saving in many places in Samba. This also means that the 'type' argument to various DLIST_*() macros is no longer needed, but I have left it in for now to keep the patchset small, which will make it easier to revert if any problems are found. In the future we should remove the 'type' arguments. (jra. Move the one use of DLIST_TAIL over to the new macros).
This commit is contained in:
parent
13ac4ad521
commit
32809bd8c1
@ -1,7 +1,8 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
some simple double linked list macros
|
||||
Copyright (C) Andrew Tridgell 1998
|
||||
|
||||
Copyright (C) Andrew Tridgell 1998-2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -23,71 +24,94 @@
|
||||
#ifndef _DLINKLIST_H
|
||||
#define _DLINKLIST_H
|
||||
|
||||
/*
|
||||
February 2010 - changed list format to have a prev pointer from the
|
||||
list head. This makes DLIST_ADD_END() O(1) even though we only have
|
||||
one list pointer.
|
||||
|
||||
/* hook into the front of the list */
|
||||
The scheme is as follows:
|
||||
|
||||
1) with no entries in the list:
|
||||
list_head == NULL
|
||||
|
||||
2) with 1 entry in the list:
|
||||
list_head->next == NULL
|
||||
list_head->prev == list_head
|
||||
|
||||
3) with 2 entries in the list:
|
||||
list_head->next == element2
|
||||
list_head->prev == element2
|
||||
element2->prev == list_head
|
||||
element2->next == NULL
|
||||
|
||||
4) with N entries in the list:
|
||||
list_head->next == element2
|
||||
list_head->prev == elementN
|
||||
elementN->prev == element{N-1}
|
||||
elementN->next == NULL
|
||||
|
||||
This allows us to find the tail of the list by using
|
||||
list_head->prev, which means we can add to the end of the list in
|
||||
O(1) time
|
||||
|
||||
|
||||
Note that the 'type' arguments below are no longer needed, but
|
||||
are kept for now to prevent an incompatible argument change
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
add an element at the front of a list
|
||||
*/
|
||||
#define DLIST_ADD(list, p) \
|
||||
do { \
|
||||
if (!(list)) { \
|
||||
(list) = (p); \
|
||||
(p)->next = (p)->prev = NULL; \
|
||||
(p)->prev = (list) = (p); \
|
||||
(p)->next = NULL; \
|
||||
} else { \
|
||||
(p)->prev = (list)->prev; \
|
||||
(list)->prev = (p); \
|
||||
(p)->next = (list); \
|
||||
(p)->prev = NULL; \
|
||||
(list) = (p); \
|
||||
}\
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* remove an element from a list - element doesn't have to be in list. */
|
||||
/*
|
||||
remove an element from a list
|
||||
Note that the element doesn't have to be in the list. If it
|
||||
isn't then this is a no-op
|
||||
*/
|
||||
#define DLIST_REMOVE(list, p) \
|
||||
do { \
|
||||
if ((p) == (list)) { \
|
||||
if ((p)->next) (p)->next->prev = (p)->prev; \
|
||||
(list) = (p)->next; \
|
||||
if (list) (list)->prev = NULL; \
|
||||
} else if ((list) && (p) == (list)->prev) { \
|
||||
(p)->prev->next = NULL; \
|
||||
(list)->prev = (p)->prev; \
|
||||
} else { \
|
||||
if ((p)->prev) (p)->prev->next = (p)->next; \
|
||||
if ((p)->next) (p)->next->prev = (p)->prev; \
|
||||
} \
|
||||
if ((p) != (list)) (p)->next = (p)->prev = NULL; \
|
||||
if ((p) != (list)) (p)->next = (p)->prev = NULL; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
find the head of the list given any element in it.
|
||||
Note that this costs O(N), so you should avoid this macro
|
||||
if at all possible!
|
||||
*/
|
||||
#define DLIST_HEAD(p, result_head) \
|
||||
do { \
|
||||
(result_head) = (p); \
|
||||
while (DLIST_PREV(result_head)) (result_head) = (result_head)->prev; \
|
||||
(result_head) = (p); \
|
||||
while (DLIST_PREV(result_head)) (result_head) = (result_head)->prev; \
|
||||
} while(0)
|
||||
|
||||
/* return the last element in the list */
|
||||
#define DLIST_TAIL(list, result_tail) \
|
||||
do { \
|
||||
(result_tail) = (list); \
|
||||
while ((result_tail) && (result_tail)->next) (result_tail) = (result_tail)->next; \
|
||||
} while (0);
|
||||
#define DLIST_TAIL(list) ((list)?(list)->prev:NULL)
|
||||
|
||||
/* return the previous element in the list. */
|
||||
#define DLIST_PREV(p) ((p)?(p)->prev:NULL)
|
||||
|
||||
/* promote an element to the top of the list */
|
||||
#define DLIST_PROMOTE(list, p) \
|
||||
do { \
|
||||
DLIST_REMOVE(list, p); \
|
||||
DLIST_ADD(list, p); \
|
||||
} while (0)
|
||||
|
||||
/* hook into the end of the list - needs the entry type */
|
||||
#define DLIST_ADD_END(list, p, type) \
|
||||
do { \
|
||||
if (!(list)) { \
|
||||
(list) = (p); \
|
||||
(p)->next = (p)->prev = NULL; \
|
||||
} else { \
|
||||
type tmp; \
|
||||
for (tmp = (list); tmp->next; tmp = tmp->next) ; \
|
||||
tmp->next = (p); \
|
||||
(p)->next = NULL; \
|
||||
(p)->prev = tmp; \
|
||||
} \
|
||||
} while (0)
|
||||
#define DLIST_PREV(p) (((p)->prev && (p)->prev->next != NULL)?(p)->prev:NULL)
|
||||
|
||||
/* insert 'p' after the given element 'el' in a list. If el is NULL then
|
||||
this is the same as a DLIST_ADD() */
|
||||
@ -96,34 +120,62 @@ do { \
|
||||
if (!(list) || !(el)) { \
|
||||
DLIST_ADD(list, p); \
|
||||
} else { \
|
||||
p->prev = el; \
|
||||
p->next = el->next; \
|
||||
el->next = p; \
|
||||
if (p->next) p->next->prev = p; \
|
||||
(p)->prev = (el); \
|
||||
(p)->next = (el)->next; \
|
||||
(el)->next = (p); \
|
||||
if ((p)->next) (p)->next->prev = (p); \
|
||||
if ((list)->prev == (el)) (list)->prev = (p); \
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
/* demote an element to the end of the list, needs the entry type */
|
||||
#define DLIST_DEMOTE(list, p, type) \
|
||||
|
||||
/*
|
||||
add to the end of a list.
|
||||
Note that 'type' is ignored
|
||||
*/
|
||||
#define DLIST_ADD_END(list, p, type) \
|
||||
do { \
|
||||
DLIST_REMOVE(list, p); \
|
||||
DLIST_ADD_END(list, p, type); \
|
||||
if (!(list)) { \
|
||||
DLIST_ADD(list, p); \
|
||||
} else { \
|
||||
DLIST_ADD_AFTER(list, p, (list)->prev); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* concatenate two lists - putting all elements of the 2nd list at the
|
||||
end of the first list */
|
||||
#define DLIST_CONCATENATE(list1, list2, type) \
|
||||
/* promote an element to the from of a list */
|
||||
#define DLIST_PROMOTE(list, p) \
|
||||
do { \
|
||||
if (!(list1)) { \
|
||||
(list1) = (list2); \
|
||||
} else { \
|
||||
type tmp; \
|
||||
for (tmp = (list1); tmp->next; tmp = tmp->next) ; \
|
||||
tmp->next = (list2); \
|
||||
if (list2) { \
|
||||
(list2)->prev = tmp; \
|
||||
} \
|
||||
DLIST_REMOVE(list, p); \
|
||||
DLIST_ADD(list, p); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
demote an element to the end of a list.
|
||||
Note that 'type' is ignored
|
||||
*/
|
||||
#define DLIST_DEMOTE(list, p, type) \
|
||||
do { \
|
||||
DLIST_REMOVE(list, p); \
|
||||
DLIST_ADD_END(list, p, NULL); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
concatenate two lists - putting all elements of the 2nd list at the
|
||||
end of the first list.
|
||||
Note that 'type' is ignored
|
||||
*/
|
||||
#define DLIST_CONCATENATE(list1, list2, type) \
|
||||
do { \
|
||||
if (!(list1)) { \
|
||||
(list1) = (list2); \
|
||||
} else { \
|
||||
(list1)->prev->next = (list2); \
|
||||
if (list2) { \
|
||||
void *_tmplist = (void *)(list1)->prev; \
|
||||
(list1)->prev = (list2)->prev; \
|
||||
(list2)->prev = _tmplist; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif /* _DLINKLIST_H */
|
||||
|
@ -1,7 +1,8 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
some simple double linked list macros
|
||||
Copyright (C) Andrew Tridgell 1998
|
||||
|
||||
Copyright (C) Andrew Tridgell 1998-2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -23,71 +24,94 @@
|
||||
#ifndef _DLINKLIST_H
|
||||
#define _DLINKLIST_H
|
||||
|
||||
/*
|
||||
February 2010 - changed list format to have a prev pointer from the
|
||||
list head. This makes DLIST_ADD_END() O(1) even though we only have
|
||||
one list pointer.
|
||||
|
||||
/* hook into the front of the list */
|
||||
The scheme is as follows:
|
||||
|
||||
1) with no entries in the list:
|
||||
list_head == NULL
|
||||
|
||||
2) with 1 entry in the list:
|
||||
list_head->next == NULL
|
||||
list_head->prev == list_head
|
||||
|
||||
3) with 2 entries in the list:
|
||||
list_head->next == element2
|
||||
list_head->prev == element2
|
||||
element2->prev == list_head
|
||||
element2->next == NULL
|
||||
|
||||
4) with N entries in the list:
|
||||
list_head->next == element2
|
||||
list_head->prev == elementN
|
||||
elementN->prev == element{N-1}
|
||||
elementN->next == NULL
|
||||
|
||||
This allows us to find the tail of the list by using
|
||||
list_head->prev, which means we can add to the end of the list in
|
||||
O(1) time
|
||||
|
||||
|
||||
Note that the 'type' arguments below are no longer needed, but
|
||||
are kept for now to prevent an incompatible argument change
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
add an element at the front of a list
|
||||
*/
|
||||
#define DLIST_ADD(list, p) \
|
||||
do { \
|
||||
if (!(list)) { \
|
||||
(list) = (p); \
|
||||
(p)->next = (p)->prev = NULL; \
|
||||
(p)->prev = (list) = (p); \
|
||||
(p)->next = NULL; \
|
||||
} else { \
|
||||
(p)->prev = (list)->prev; \
|
||||
(list)->prev = (p); \
|
||||
(p)->next = (list); \
|
||||
(p)->prev = NULL; \
|
||||
(list) = (p); \
|
||||
}\
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* remove an element from a list - element doesn't have to be in list. */
|
||||
/*
|
||||
remove an element from a list
|
||||
Note that the element doesn't have to be in the list. If it
|
||||
isn't then this is a no-op
|
||||
*/
|
||||
#define DLIST_REMOVE(list, p) \
|
||||
do { \
|
||||
if ((p) == (list)) { \
|
||||
if ((p)->next) (p)->next->prev = (p)->prev; \
|
||||
(list) = (p)->next; \
|
||||
if (list) (list)->prev = NULL; \
|
||||
} else if ((list) && (p) == (list)->prev) { \
|
||||
(p)->prev->next = NULL; \
|
||||
(list)->prev = (p)->prev; \
|
||||
} else { \
|
||||
if ((p)->prev) (p)->prev->next = (p)->next; \
|
||||
if ((p)->next) (p)->next->prev = (p)->prev; \
|
||||
} \
|
||||
if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \
|
||||
if ((p) != (list)) (p)->next = (p)->prev = NULL; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
find the head of the list given any element in it.
|
||||
Note that this costs O(N), so you should avoid this macro
|
||||
if at all possible!
|
||||
*/
|
||||
#define DLIST_HEAD(p, result_head) \
|
||||
do { \
|
||||
(result_head) = (p); \
|
||||
while (DLIST_PREV(result_head)) (result_head) = (result_head)->prev; \
|
||||
(result_head) = (p); \
|
||||
while (DLIST_PREV(result_head)) (result_head) = (result_head)->prev; \
|
||||
} while(0)
|
||||
|
||||
/* return the last element in the list */
|
||||
#define DLIST_TAIL(list, result_tail) \
|
||||
do { \
|
||||
(result_tail) = (list); \
|
||||
while ((result_tail) && (result_tail)->next) (result_tail) = (result_tail)->next; \
|
||||
} while (0);
|
||||
#define DLIST_TAIL(list) ((list)?(list)->prev:NULL)
|
||||
|
||||
/* return the previous element in the list. */
|
||||
#define DLIST_PREV(p) ((p)?(p)->prev:NULL)
|
||||
|
||||
/* promote an element to the top of the list */
|
||||
#define DLIST_PROMOTE(list, p) \
|
||||
do { \
|
||||
DLIST_REMOVE(list, p); \
|
||||
DLIST_ADD(list, p); \
|
||||
} while (0)
|
||||
|
||||
/* hook into the end of the list - needs the entry type */
|
||||
#define DLIST_ADD_END(list, p, type) \
|
||||
do { \
|
||||
if (!(list)) { \
|
||||
(list) = (p); \
|
||||
(p)->next = (p)->prev = NULL; \
|
||||
} else { \
|
||||
type tmp; \
|
||||
for (tmp = (list); tmp->next; tmp = tmp->next) ; \
|
||||
tmp->next = (p); \
|
||||
(p)->next = NULL; \
|
||||
(p)->prev = tmp; \
|
||||
} \
|
||||
} while (0)
|
||||
#define DLIST_PREV(p) (((p)->prev && (p)->prev->next != NULL)?(p)->prev:NULL)
|
||||
|
||||
/* insert 'p' after the given element 'el' in a list. If el is NULL then
|
||||
this is the same as a DLIST_ADD() */
|
||||
@ -96,34 +120,62 @@ do { \
|
||||
if (!(list) || !(el)) { \
|
||||
DLIST_ADD(list, p); \
|
||||
} else { \
|
||||
p->prev = el; \
|
||||
p->next = el->next; \
|
||||
el->next = p; \
|
||||
if (p->next) p->next->prev = p; \
|
||||
(p)->prev = (el); \
|
||||
(p)->next = (el)->next; \
|
||||
(el)->next = (p); \
|
||||
if ((p)->next) (p)->next->prev = (p); \
|
||||
if ((list)->prev == (el)) (list)->prev = (p); \
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
/* demote an element to the end of the list, needs the entry type */
|
||||
#define DLIST_DEMOTE(list, p, type) \
|
||||
|
||||
/*
|
||||
add to the end of a list.
|
||||
Note that 'type' is ignored
|
||||
*/
|
||||
#define DLIST_ADD_END(list, p, type) \
|
||||
do { \
|
||||
DLIST_REMOVE(list, p); \
|
||||
DLIST_ADD_END(list, p, type); \
|
||||
if (!(list)) { \
|
||||
DLIST_ADD(list, p); \
|
||||
} else { \
|
||||
DLIST_ADD_AFTER(list, p, (list)->prev); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* concatenate two lists - putting all elements of the 2nd list at the
|
||||
end of the first list */
|
||||
#define DLIST_CONCATENATE(list1, list2, type) \
|
||||
/* promote an element to the from of a list */
|
||||
#define DLIST_PROMOTE(list, p) \
|
||||
do { \
|
||||
if (!(list1)) { \
|
||||
(list1) = (list2); \
|
||||
} else { \
|
||||
type tmp; \
|
||||
for (tmp = (list1); tmp->next; tmp = tmp->next) ; \
|
||||
tmp->next = (list2); \
|
||||
if (list2) { \
|
||||
(list2)->prev = tmp; \
|
||||
} \
|
||||
DLIST_REMOVE(list, p); \
|
||||
DLIST_ADD(list, p); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
demote an element to the end of a list.
|
||||
Note that 'type' is ignored
|
||||
*/
|
||||
#define DLIST_DEMOTE(list, p, type) \
|
||||
do { \
|
||||
DLIST_REMOVE(list, p); \
|
||||
DLIST_ADD_END(list, p, NULL); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
concatenate two lists - putting all elements of the 2nd list at the
|
||||
end of the first list.
|
||||
Note that 'type' is ignored
|
||||
*/
|
||||
#define DLIST_CONCATENATE(list1, list2, type) \
|
||||
do { \
|
||||
if (!(list1)) { \
|
||||
(list1) = (list2); \
|
||||
} else { \
|
||||
(list1)->prev->next = (list2); \
|
||||
if (list2) { \
|
||||
void *_tmplist = (void *)(list1)->prev; \
|
||||
(list1)->prev = (list2)->prev; \
|
||||
(list2)->prev = _tmplist; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif /* _DLINKLIST_H */
|
||||
|
@ -3783,8 +3783,7 @@ static int replmd_prepare_commit(struct ldb_module *module)
|
||||
/* walk the list backwards, to do the first entry first, as we
|
||||
* added the entries with DLIST_ADD() which puts them at the
|
||||
* start of the list */
|
||||
DLIST_TAIL(replmd_private->la_list,la);
|
||||
for (; la; la=prev) {
|
||||
for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
|
||||
prev = DLIST_PREV(la);
|
||||
DLIST_REMOVE(replmd_private->la_list, la);
|
||||
ret = replmd_process_linked_attribute(module, la);
|
||||
|
@ -1,7 +1,8 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
some simple double linked list macros
|
||||
Copyright (C) Andrew Tridgell 1998
|
||||
|
||||
Copyright (C) Andrew Tridgell 1998-2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -23,71 +24,94 @@
|
||||
#ifndef _DLINKLIST_H
|
||||
#define _DLINKLIST_H
|
||||
|
||||
/*
|
||||
February 2010 - changed list format to have a prev pointer from the
|
||||
list head. This makes DLIST_ADD_END() O(1) even though we only have
|
||||
one list pointer.
|
||||
|
||||
/* hook into the front of the list */
|
||||
The scheme is as follows:
|
||||
|
||||
1) with no entries in the list:
|
||||
list_head == NULL
|
||||
|
||||
2) with 1 entry in the list:
|
||||
list_head->next == NULL
|
||||
list_head->prev == list_head
|
||||
|
||||
3) with 2 entries in the list:
|
||||
list_head->next == element2
|
||||
list_head->prev == element2
|
||||
element2->prev == list_head
|
||||
element2->next == NULL
|
||||
|
||||
4) with N entries in the list:
|
||||
list_head->next == element2
|
||||
list_head->prev == elementN
|
||||
elementN->prev == element{N-1}
|
||||
elementN->next == NULL
|
||||
|
||||
This allows us to find the tail of the list by using
|
||||
list_head->prev, which means we can add to the end of the list in
|
||||
O(1) time
|
||||
|
||||
|
||||
Note that the 'type' arguments below are no longer needed, but
|
||||
are kept for now to prevent an incompatible argument change
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
add an element at the front of a list
|
||||
*/
|
||||
#define DLIST_ADD(list, p) \
|
||||
do { \
|
||||
if (!(list)) { \
|
||||
(list) = (p); \
|
||||
(p)->next = (p)->prev = NULL; \
|
||||
(p)->prev = (list) = (p); \
|
||||
(p)->next = NULL; \
|
||||
} else { \
|
||||
(p)->prev = (list)->prev; \
|
||||
(list)->prev = (p); \
|
||||
(p)->next = (list); \
|
||||
(p)->prev = NULL; \
|
||||
(list) = (p); \
|
||||
}\
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* remove an element from a list - element doesn't have to be in list. */
|
||||
/*
|
||||
remove an element from a list
|
||||
Note that the element doesn't have to be in the list. If it
|
||||
isn't then this is a no-op
|
||||
*/
|
||||
#define DLIST_REMOVE(list, p) \
|
||||
do { \
|
||||
if ((p) == (list)) { \
|
||||
if ((p)->next) (p)->next->prev = (p)->prev; \
|
||||
(list) = (p)->next; \
|
||||
if (list) (list)->prev = NULL; \
|
||||
} else if ((list) && (p) == (list)->prev) { \
|
||||
(p)->prev->next = NULL; \
|
||||
(list)->prev = (p)->prev; \
|
||||
} else { \
|
||||
if ((p)->prev) (p)->prev->next = (p)->next; \
|
||||
if ((p)->next) (p)->next->prev = (p)->prev; \
|
||||
} \
|
||||
if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \
|
||||
if ((p) != (list)) (p)->next = (p)->prev = NULL; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
find the head of the list given any element in it.
|
||||
Note that this costs O(N), so you should avoid this macro
|
||||
if at all possible!
|
||||
*/
|
||||
#define DLIST_HEAD(p, result_head) \
|
||||
do { \
|
||||
(result_head) = (p); \
|
||||
while (DLIST_PREV(result_head)) (result_head) = (result_head)->prev; \
|
||||
(result_head) = (p); \
|
||||
while (DLIST_PREV(result_head)) (result_head) = (result_head)->prev; \
|
||||
} while(0)
|
||||
|
||||
/* return the last element in the list */
|
||||
#define DLIST_TAIL(list, result_tail) \
|
||||
do { \
|
||||
(result_tail) = (list); \
|
||||
while ((result_tail) && (result_tail)->next) (result_tail) = (result_tail)->next; \
|
||||
} while (0);
|
||||
#define DLIST_TAIL(list) ((list)?(list)->prev:NULL)
|
||||
|
||||
/* return the previous element in the list. */
|
||||
#define DLIST_PREV(p) ((p)?(p)->prev:NULL)
|
||||
|
||||
/* promote an element to the top of the list */
|
||||
#define DLIST_PROMOTE(list, p) \
|
||||
do { \
|
||||
DLIST_REMOVE(list, p); \
|
||||
DLIST_ADD(list, p); \
|
||||
} while (0)
|
||||
|
||||
/* hook into the end of the list - needs the entry type */
|
||||
#define DLIST_ADD_END(list, p, type) \
|
||||
do { \
|
||||
if (!(list)) { \
|
||||
(list) = (p); \
|
||||
(p)->next = (p)->prev = NULL; \
|
||||
} else { \
|
||||
type tmp; \
|
||||
for (tmp = (list); tmp->next; tmp = tmp->next) ; \
|
||||
tmp->next = (p); \
|
||||
(p)->next = NULL; \
|
||||
(p)->prev = tmp; \
|
||||
} \
|
||||
} while (0)
|
||||
#define DLIST_PREV(p) (((p)->prev && (p)->prev->next != NULL)?(p)->prev:NULL)
|
||||
|
||||
/* insert 'p' after the given element 'el' in a list. If el is NULL then
|
||||
this is the same as a DLIST_ADD() */
|
||||
@ -96,34 +120,62 @@ do { \
|
||||
if (!(list) || !(el)) { \
|
||||
DLIST_ADD(list, p); \
|
||||
} else { \
|
||||
p->prev = el; \
|
||||
p->next = el->next; \
|
||||
el->next = p; \
|
||||
if (p->next) p->next->prev = p; \
|
||||
(p)->prev = (el); \
|
||||
(p)->next = (el)->next; \
|
||||
(el)->next = (p); \
|
||||
if ((p)->next) (p)->next->prev = (p); \
|
||||
if ((list)->prev == (el)) (list)->prev = (p); \
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
/* demote an element to the end of the list, needs the entry type */
|
||||
#define DLIST_DEMOTE(list, p, type) \
|
||||
|
||||
/*
|
||||
add to the end of a list.
|
||||
Note that 'type' is ignored
|
||||
*/
|
||||
#define DLIST_ADD_END(list, p, type) \
|
||||
do { \
|
||||
DLIST_REMOVE(list, p); \
|
||||
DLIST_ADD_END(list, p, type); \
|
||||
if (!(list)) { \
|
||||
DLIST_ADD(list, p); \
|
||||
} else { \
|
||||
DLIST_ADD_AFTER(list, p, (list)->prev); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* concatenate two lists - putting all elements of the 2nd list at the
|
||||
end of the first list */
|
||||
#define DLIST_CONCATENATE(list1, list2, type) \
|
||||
/* promote an element to the from of a list */
|
||||
#define DLIST_PROMOTE(list, p) \
|
||||
do { \
|
||||
if (!(list1)) { \
|
||||
(list1) = (list2); \
|
||||
} else { \
|
||||
type tmp; \
|
||||
for (tmp = (list1); tmp->next; tmp = tmp->next) ; \
|
||||
tmp->next = (list2); \
|
||||
if (list2) { \
|
||||
(list2)->prev = tmp; \
|
||||
} \
|
||||
DLIST_REMOVE(list, p); \
|
||||
DLIST_ADD(list, p); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
demote an element to the end of a list.
|
||||
Note that 'type' is ignored
|
||||
*/
|
||||
#define DLIST_DEMOTE(list, p, type) \
|
||||
do { \
|
||||
DLIST_REMOVE(list, p); \
|
||||
DLIST_ADD_END(list, p, NULL); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
concatenate two lists - putting all elements of the 2nd list at the
|
||||
end of the first list.
|
||||
Note that 'type' is ignored
|
||||
*/
|
||||
#define DLIST_CONCATENATE(list1, list2, type) \
|
||||
do { \
|
||||
if (!(list1)) { \
|
||||
(list1) = (list2); \
|
||||
} else { \
|
||||
(list1)->prev->next = (list2); \
|
||||
if (list2) { \
|
||||
void *_tmplist = (void *)(list1)->prev; \
|
||||
(list1)->prev = (list2)->prev; \
|
||||
(list2)->prev = _tmplist; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif /* _DLINKLIST_H */
|
||||
|
Loading…
x
Reference in New Issue
Block a user