blob: 709eddf3b6d8b6a15e332e592b001f6eb139a1fc [file] [log] [blame]
/* -*- mode: c -*-
* $Id$
* http://www.bagley.org/~doug/shootout/
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 100
#define inline static
/* a simple Double Linked List
the head node is special, it's val is length of list */
typedef struct DLL {
int val;
struct DLL *next; /* points to next or head (if at tail) */
struct DLL *prev; /* points to prev or tail (if at head) */
} DLL;
inline int list_length(DLL *head) { return(head->val); }
inline int list_empty(DLL *head) { return(list_length(head) == 0); }
inline DLL *list_first(DLL *head) { return(head->next); }
inline DLL *list_last(DLL *head) { return(head->prev); }
void list_push_tail(DLL *head, DLL *item) {
DLL *tail = head->prev;
tail->next = item;
item->next = head;
head->prev = item;
item->prev = tail;
head->val++;
}
DLL *list_pop_tail(DLL *head) {
DLL *prev, *tail;
if (list_empty(head)) return(NULL);
tail = head->prev;
prev = tail->prev;
prev->next = head;
head->prev = prev;
head->val--;
return(tail);
}
void list_push_head(DLL *head, DLL *item) {
DLL *next = head->next;
head->next = item;
next->prev = item;
item->next = next;
item->prev = head;
head->val++;
}
DLL *list_pop_head(DLL *head) {
DLL *next;
if (list_empty(head)) return(NULL);
next = head->next;
head->next = next->next;
next->next->prev = head;
head->val--;
return(next);
}
int list_equal(DLL *x, DLL *y) {
DLL *xp, *yp;
/* first val's checked will be list lengths */
for (xp=x, yp=y; xp->next != x; xp=xp->next, yp=yp->next) {
if (xp->val != yp->val) return(0);
}
if (xp->val != yp->val) return(0);
return(yp->next == y);
}
void list_print(char *msg, DLL *x) {
DLL *xp, *first = x->next;
int i = 0;
puts(msg);
printf("length: %d\n", list_length(x));
for (xp=x->next; xp->next != first; xp=xp->next) {
printf("i:%3d v:%3d n:%3d p:%3d\n", ++i,
xp->val, xp->next->val, xp->prev->val);
}
printf("[last entry points to list head]\n");
printf("[val of next of tail is: %d]\n", xp->next->val);
}
DLL *list_new() {
DLL *l = (DLL *)malloc(sizeof(DLL));
l->next = l;
l->prev = l;
l->val = 0;
return(l);
}
/* inclusive sequence 'from' <-> 'to' */
DLL *list_sequence(int from, int to) {
int size, tmp, i, j;
DLL *l;
if (from > to) {
tmp = from; from = to; to = tmp;
}
size = to - from + 1;
l = (DLL *)malloc((size+1) * sizeof(DLL));
from--;
for (i=0, j=1; i<size; ++i, ++j) {
l[i].next = &l[i+1];
l[j].prev = &l[j-1];
l[i].val = from++;
}
l[0].prev = &l[size];
l[size].next = &l[0];
l[size].prev = &l[size-1];
l[size].val = from;
l[0].val = size;
return(l);
}
DLL *list_copy(DLL *x) {
int i, j, size = list_length(x);
DLL *xp, *l = (DLL *)malloc((size+1) * sizeof(DLL));
for (i=0, j=1, xp=x; i<size; i++, j++, xp=xp->next) {
l[i].next = &l[j];
l[j].prev = &l[i];
l[i].val = xp->val;
}
l[0].prev = &l[size];
l[size].next = &l[0];
l[size].val = list_last(x)->val;
return(l);
}
void list_reverse (DLL *head) {
DLL *tmp, *p = head;
do {
tmp = p->next;
p->next = p->prev;
p->prev = tmp;
p = tmp;
} while (p != head);
}
int test_lists() {
int len = 0;
/* create a list of integers (li1) from 1 to SIZE */
DLL *li1 = list_sequence(1, SIZE);
/* copy the list to li2*/
DLL *li2 = list_copy(li1);
/* remove each individual item from left side of li2 and
append to right side of li3 (preserving order) */
DLL *li3 = list_new();
/* compare li2 and li1 for equality */
if (!list_equal(li2, li1)) {
printf("li2 and li1 are not equal\n");
exit(1);
}
while (!list_empty(li2)) {
list_push_tail(li3, list_pop_head(li2));
}
/* li2 must now be empty */
if (!list_empty(li2)) {
printf("li2 should be empty now\n");
exit(1);
}
/* remove each individual item from right side of li3 and
append to right side of li2 (reversing list) */
while (!list_empty(li3)) {
list_push_tail(li2, list_pop_tail(li3));
}
/* li3 must now be empty */
if (!list_empty(li3)) {
printf("li3 should be empty now\n");
exit(1);
}
/* reverse li1 in place */
list_reverse(li1);
/* check that li1's first item is now SIZE */
if (list_first(li1)->val != SIZE) {
printf("li1 first value wrong, wanted %d, got %d\n",
SIZE, list_first(li1)->val);
exit(1);
}
/* check that li1's last item is now 1 */
if (list_last(li1)->val != 1) {
printf("last value wrong, wanted %d, got %d\n",
SIZE, list_last(li1)->val);
exit(1);
}
/* check that li2's first item is now SIZE */
if (list_first(li2)->val != SIZE) {
printf("li2 first value wrong, wanted %d, got %d\n",
SIZE, list_first(li2)->val);
exit(1);
}
/* check that li2's last item is now 1 */
if (list_last(li2)->val != 1) {
printf("last value wrong, wanted %d, got %d\n",
SIZE, list_last(li2)->val);
exit(1);
}
/* check that li1's length is still SIZE */
if (list_length(li1) != SIZE) {
printf("li1 size wrong, wanted %d, got %d\n",
SIZE, list_length(li1));
exit(1);
}
/* compare li1 and li2 for equality */
if (!list_equal(li1, li2)) {
printf("li1 and li2 are not equal\n");
exit(1);
}
len = list_length(li1);
free(li1);
free(li2);
free(li3);
/* return the length of the list */
return(len);
}
int main(int argc, char *argv[]) {
#ifdef SMALL_PROBLEM_SIZE
#define LENGTH 300000
#else
#define LENGTH 3000000
#endif
int n = ((argc == 2) ? atoi(argv[1]) : LENGTH);
int result = 0;
while(n--) result = test_lists();
printf("%d\n", result);
return 0;
}