redream/src/core/list.c

133 lines
2.6 KiB
C

#include "core/list.h"
int list_empty(struct list *list) {
return !list->head;
}
void list_add(struct list *list, struct list_node *n) {
list_add_after(list, list->tail, n);
}
void list_add_after(struct list *list, struct list_node *after,
struct list_node *n) {
struct list_node *before = NULL;
if (after) {
before = after->next;
n->prev = after;
n->prev->next = n;
} else {
before = list->head;
list->head = n;
list->head->prev = NULL;
}
if (before) {
n->next = before;
n->next->prev = n;
} else {
list->tail = n;
list->tail->next = NULL;
}
}
void list_remove(struct list *list, struct list_node *n) {
if (n->prev) {
n->prev->next = n->next;
} else {
list->head = n->next;
}
if (n->next) {
n->next->prev = n->prev;
} else {
list->tail = n->prev;
}
n->prev = n->next = NULL;
}
void list_clear(struct list *list) {
list->head = list->tail = NULL;
}
/* implements the mergesort for linked lists as described at
http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html */
void list_sort(struct list *list, list_node_cmp cmp) {
struct list_node *head = list->head;
struct list_node *tail = NULL;
int k = 1;
while (1) {
int merges = 0;
struct list_node *p = head;
head = NULL;
tail = NULL;
while (p) {
/* track the number of lists merged this pass */
merges++;
/* step q forward k places, tracking the size of p */
int psize = 0;
int qsize = k;
struct list_node *q = p;
while (psize < k && q) {
psize++;
q = q->next;
}
/* merge the list starting at p of length psize with the list starting
at q of at most, length qsize */
while (psize || (qsize && q)) {
struct list_node *next;
if (!psize) {
next = q;
q = q->next;
qsize--;
} else if (!qsize || !q) {
next = p;
p = p->next;
psize--;
} else if (cmp(q, p) < 0) {
next = q;
q = q->next;
qsize--;
} else {
next = p;
p = p->next;
psize--;
}
/* move merged node to tail */
if (!tail) {
head = next;
} else {
tail->next = next;
}
next->prev = tail;
tail = next;
}
p = q;
}
if (tail) {
tail->next = NULL;
}
/* if only 1 pair of lists was merged, this is the end */
if (merges <= 1) {
break;
}
k *= 2;
}
/* update internal head and tail with sorted head and tail */
list->head = head;
list->tail = tail;
}