f62d3b77aa
Or use the C++ list implementation where possible. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17901 a95241bf-73f2-0310-859d-f6bbb57e9c96
251 lines
4.8 KiB
C
251 lines
4.8 KiB
C
/*
|
|
* Copyright 2003-2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
|
* Distributed under the terms of the MIT License.
|
|
*/
|
|
|
|
|
|
#include <util/list.h>
|
|
|
|
|
|
#define GET_ITEM(list, item) ((void *)((uint8 *)item - list->offset))
|
|
#define GET_LINK(list, item) ((list_link *)((uint8 *)item + list->offset))
|
|
|
|
|
|
/** Initializes the list with a specified offset to the link
|
|
* structure in the items that will be part of the list.
|
|
*/
|
|
|
|
void
|
|
list_init_etc(struct list *list, int32 offset)
|
|
{
|
|
list->link.next = list->link.prev = &list->link;
|
|
list->offset = offset;
|
|
}
|
|
|
|
|
|
void
|
|
list_init(struct list *list)
|
|
{
|
|
list_init_etc(list, 0);
|
|
}
|
|
|
|
|
|
/** Adds a link to the head of the list
|
|
*/
|
|
|
|
void
|
|
list_add_link_to_head(struct list *list, void *_link)
|
|
{
|
|
list_link *link = (list_link *)_link;
|
|
|
|
link->next = list->link.next;
|
|
link->prev = &list->link;
|
|
|
|
list->link.next->prev = link;
|
|
list->link.next = link;
|
|
}
|
|
|
|
|
|
/** Adds a link to the tail of the list
|
|
*/
|
|
|
|
void
|
|
list_add_link_to_tail(struct list *list, void *_link)
|
|
{
|
|
list_link *link = (list_link *)_link;
|
|
|
|
link->next = &list->link;
|
|
link->prev = list->link.prev;
|
|
|
|
list->link.prev->next = link;
|
|
list->link.prev = link;
|
|
}
|
|
|
|
|
|
/** Removes a link from the list it's currently in.
|
|
* Note: the link has to be in a list when you call this function.
|
|
*/
|
|
|
|
void
|
|
list_remove_link(void *_link)
|
|
{
|
|
list_link *link = (list_link *)_link;
|
|
|
|
link->next->prev = link->prev;
|
|
link->prev->next = link->next;
|
|
}
|
|
|
|
|
|
static inline list_link *
|
|
get_next_link(struct list *list, list_link *link)
|
|
{
|
|
if (link->next == &list->link)
|
|
return NULL;
|
|
|
|
return link->next;
|
|
}
|
|
|
|
|
|
static inline list_link *
|
|
get_prev_link(struct list *list, list_link *link)
|
|
{
|
|
if (link->prev == &list->link)
|
|
return NULL;
|
|
|
|
return link->prev;
|
|
}
|
|
|
|
|
|
/** Gets the successor for the current item. If the passed
|
|
* item is NULL, it returns the first entry in the list,
|
|
* if there is one.
|
|
* Returns NULL if there aren't any more items in this list.
|
|
*/
|
|
|
|
void *
|
|
list_get_next_item(struct list *list, void *item)
|
|
{
|
|
list_link *link;
|
|
|
|
if (item == NULL)
|
|
return list_is_empty(list) ? NULL : GET_ITEM(list, list->link.next);
|
|
|
|
link = get_next_link(list, GET_LINK(list, item));
|
|
return link != NULL ? GET_ITEM(list, link) : NULL;
|
|
}
|
|
|
|
|
|
/** Gets the predecessor for the current item. If the passed
|
|
* item is NULL, it returns the last entry in the list,
|
|
* if there is one.
|
|
* Returns NULL if there aren't any previous items in this list.
|
|
*/
|
|
|
|
void *
|
|
list_get_prev_item(struct list *list, void *item)
|
|
{
|
|
list_link *link;
|
|
|
|
if (item == NULL)
|
|
return list_is_empty(list) ? NULL : GET_ITEM(list, list->link.prev);
|
|
|
|
link = get_prev_link(list, GET_LINK(list, item));
|
|
return link != NULL ? GET_ITEM(list, link) : NULL;
|
|
}
|
|
|
|
|
|
void *
|
|
list_get_last_item(struct list *list)
|
|
{
|
|
return list_is_empty(list) ? NULL : GET_ITEM(list, list->link.prev);
|
|
}
|
|
|
|
|
|
/** Adds an item to the end of the list.
|
|
* Similar to list_add_link_to_tail() but works on the item, not the link.
|
|
*/
|
|
|
|
void
|
|
list_add_item(struct list *list, void *item)
|
|
{
|
|
list_add_link_to_tail(list, GET_LINK(list, item));
|
|
}
|
|
|
|
|
|
/** Removes an item from the list.
|
|
* Similar to list_remove_link() but works on the item, not the link.
|
|
*/
|
|
|
|
void
|
|
list_remove_item(struct list *list, void *item)
|
|
{
|
|
list_remove_link(GET_LINK(list, item));
|
|
}
|
|
|
|
|
|
/** Inserts an item before another item in the list.
|
|
* If you pass NULL as \a before item, the item is added at the end of
|
|
* the list.
|
|
*/
|
|
|
|
void
|
|
list_insert_item_before(struct list *list, void *before, void *item)
|
|
{
|
|
list_link *beforeLink;
|
|
list_link *link;
|
|
|
|
if (before == NULL) {
|
|
list_add_item(list, item);
|
|
return;
|
|
}
|
|
|
|
beforeLink = GET_LINK(list, before);
|
|
link = GET_LINK(list, item);
|
|
|
|
link->prev = beforeLink->prev;
|
|
link->next = beforeLink;
|
|
|
|
beforeLink->prev->next = link;
|
|
beforeLink->prev = link;
|
|
}
|
|
|
|
|
|
/** Removes the first item in the list and returns it.
|
|
* Returns NULL if the list is empty.
|
|
*/
|
|
|
|
void *
|
|
list_remove_head_item(struct list *list)
|
|
{
|
|
list_link *link;
|
|
|
|
if (list_is_empty(list))
|
|
return NULL;
|
|
|
|
list_remove_link(link = list->link.next);
|
|
return GET_ITEM(list, link);
|
|
}
|
|
|
|
|
|
/** Removes the last item in the list and returns it.
|
|
* Returns NULL if the list is empty.
|
|
*/
|
|
|
|
void *
|
|
list_remove_tail_item(struct list *list)
|
|
{
|
|
list_link *link;
|
|
|
|
if (list_is_empty(list))
|
|
return NULL;
|
|
|
|
list_remove_link(link = list->link.prev);
|
|
return GET_ITEM(list, link);
|
|
}
|
|
|
|
|
|
/** Moves the contents of the source list to the target list.
|
|
* The target list will be emptied before the items are moved;
|
|
* this is a very fast operation.
|
|
*/
|
|
|
|
void
|
|
list_move_to_list(struct list *sourceList, struct list *targetList)
|
|
{
|
|
if (list_is_empty(sourceList)) {
|
|
targetList->link.next = targetList->link.prev = &targetList->link;
|
|
return;
|
|
}
|
|
|
|
*targetList = *sourceList;
|
|
|
|
// correct link pointers to this list
|
|
targetList->link.next->prev = &targetList->link;
|
|
targetList->link.prev->next = &targetList->link;
|
|
|
|
// empty source list
|
|
sourceList->link.next = sourceList->link.prev = &sourceList->link;
|
|
}
|
|
|
|
|