/* $Id: alist.c,v 1.1 2001/07/13 19:09:55 sandro Exp $ */ /* * Copyright (c) 2001 Sandro Sigala. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifdef TEST #undef NDEBUG #endif #include #include #include #include #include "config.h" #include "alist.h" static aentry aentry_new(void *p) { aentry ae; ae = (aentry)xmalloc(sizeof *ae); ae->p = p; ae->prev = ae->next = NULL; return ae; } static void aentry_delete(aentry ae) { ae->p = NULL; /* Useful for debugging. */ ae->prev = ae->next = NULL; free(ae); } static aentry find_aentry(alist al, unsigned int i) { aentry ae; unsigned int count; for (ae = al->head, count = 0; ae != NULL; ae = ae->next, ++count) if (count == i) return ae; return NULL; } static aentry find_aentry_ptr(alist al, void *p) { aentry ae; for (ae = al->head; ae != NULL; ae = ae->next) if (ae->p == p) return ae; return NULL; } alist alist_new(void) { alist al; al = (alist)xmalloc(sizeof *al); al->head = al->tail = al->current = NULL; al->idx = 0; al->size = 0; return al; } alist alist_copy(alist src) { alist al; aentry ae; assert(src != NULL); al = alist_new(); for (ae = src->head; ae != NULL; ae = ae->next) alist_append(al, ae->p); return al; } void alist_delete(alist al) { assert(al != NULL); alist_clear(al); free(al); } void alist_clear(alist al) { aentry ae, next; assert(al != NULL); for (ae = al->head; ae != NULL; ae = next) { next = ae->next; aentry_delete(ae); } al->head = al->tail = al->current = NULL; al->idx = 0; al->size = 0; } int (alist_count)(alist al) { return al->size; } int (alist_isempty)(alist al) { return al->size == 0; } void *(alist_first)(alist al) { assert(al != NULL); al->current = al->head; al->idx = 0; if (al->current != NULL) return al->current->p; return NULL; } void *(alist_last)(alist al) { assert(al != NULL); al->current = al->tail; if (al->current != NULL) { al->idx = al->size - 1; return al->current->p; } return NULL; } void *(alist_prev)(alist al) { assert(al != NULL); if (al->current != NULL) { al->current = al->current->prev; if (al->current != NULL) { --al->idx; return al->current->p; } else return NULL; } return NULL; } void *(alist_next)(alist al) { assert(al != NULL); if (al->current != NULL) { al->current = al->current->next; if (al->current != NULL) { ++al->idx; return al->current->p; } else return NULL; } return NULL; } void *(alist_current)(alist al) { assert(al != NULL); if (al->current != NULL) return al->current->p; return NULL; } int (alist_current_idx)(alist al) { if (al->current != NULL) return al->idx; return -1; } void alist_insert(alist al, unsigned int i, void *p) { if (i >= al->size) { i = al->size; alist_append(al, p); } else if (i == 0) alist_prepend(al, p); else { aentry oldae = find_aentry(al, i); aentry ae = aentry_new(p); ae->next = oldae; if (oldae->prev != NULL) { ae->prev = oldae->prev; ae->prev->next = ae; } oldae->prev = ae; al->current = ae; al->idx = i; ++al->size; } } void alist_prepend(alist al, void *p) { aentry ae; assert(al != NULL); ae = aentry_new(p); if (al->head != NULL) { al->head->prev = ae; ae->next = al->head; al->head = ae; } else al->head = al->tail = ae; al->current = ae; al->idx = 0; ++al->size; } void alist_append(alist al, void *p) { aentry ae; assert(al != NULL); ae = aentry_new(p); if (al->tail != NULL) { al->tail->next = ae; ae->prev = al->tail; al->tail = ae; } else al->head = al->tail = ae; al->current = ae; ++al->size; al->idx = al->size - 1; } static void take_off(alist al, aentry ae) { if (ae->prev != NULL) ae->prev->next = ae->next; if (ae->next != NULL) ae->next->prev = ae->prev; if (al->head == ae) al->head = ae->next; if (al->tail == ae) al->tail = ae->prev; al->current = NULL; al->idx = 0; --al->size; } int alist_remove(alist al) { aentry ae; assert(al != NULL); if ((ae = al->current) == NULL) return -1; take_off(al, ae); aentry_delete(ae); return 0; } int alist_remove_ptr(alist al, void *p) { aentry ae; assert(al != NULL); if ((ae = find_aentry_ptr(al, p)) != NULL) { take_off(al, ae); aentry_delete(ae); return 0; } return -1; } int alist_remove_idx(alist al, unsigned int i) { aentry ae; assert(al != NULL); if (i >= al->size) return -1; ae = find_aentry(al, i); take_off(al, ae); aentry_delete(ae); return 0; } void *alist_take(alist al) { aentry ae; void *p; assert(al != NULL); if ((ae = al->current) == NULL) return NULL; take_off(al, ae); p = ae->p; aentry_delete(ae); return p; } void *alist_take_idx(alist al, unsigned int i) { aentry ae; void *p; assert(al != NULL); if (i >= al->size) return NULL; ae = find_aentry(al, i); take_off(al, ae); p = ae->p; aentry_delete(ae); return p; } void alist_sort(alist al, int (*cmp)(const void *p1, const void *p2)) { void **vec; aentry ae; int i; assert(al != NULL && cmp != NULL); if (al->size == 0) return; vec = (void **)xmalloc(sizeof(void *) * al->size); for (ae = al->head, i = 0; ae != NULL; ae = ae->next, ++i) vec[i] = ae->p; qsort(vec, al->size, sizeof(void *), cmp); for (ae = al->head, i = 0; ae != NULL; ae = ae->next, ++i) ae->p = vec[i]; free(vec); } void *alist_at(alist al, unsigned int i) { aentry ae; assert(al != NULL); if (i >= al->size) return NULL; ae = find_aentry(al, i); return ae->p; } int alist_find(alist al, void *p) { aentry ae; unsigned int count; assert(al != NULL); for (ae = al->head, count = 0; ae != NULL; ae = ae->next, ++count) if (ae->p == p) return count; return -1; } #ifdef TEST int sorter(const void *p1, const void *p2) { return strcmp(*(char **)p1, *(char **)p2); } int main(void) { alist al; char *t1 = "def", *t2 = "abc", *t3 = "xyz"; char *s; al = alist_new(); assert(alist_count(al) == 0); assert(alist_current(al) == NULL); assert(alist_current_idx(al) == -1); alist_append(al, t1); assert(alist_count(al) == 1); assert(alist_current(al) == t1); assert(alist_current_idx(al) == 0); alist_append(al, t2); assert(alist_count(al) == 2); assert(alist_current(al) == t2); assert(alist_current_idx(al) == 1); s = alist_first(al); assert(s == t1); assert(alist_current(al) == t1); assert(alist_current_idx(al) == 0); s = alist_next(al); assert(s == t2); assert(alist_current(al) == t2); assert(alist_current_idx(al) == 1); s = alist_next(al); assert(s == NULL); assert(alist_current(al) == NULL); assert(alist_current_idx(al) == -1); alist_prepend(al, t3); assert(alist_count(al) == 3); assert(alist_current(al) == t3); assert(alist_current_idx(al) == 0); printf("elements:\n"); for (s = alist_first(al); s != NULL; s = alist_next(al)) printf("element %d: %s\n", alist_current_idx(al), s); alist_sort(al, sorter); printf("sorted elements:\n"); for (s = alist_first(al); s != NULL; s = alist_next(al)) printf("element %d: %s\n", alist_current_idx(al), s) ; assert(alist_at(al, 0) == t2); assert(alist_at(al, 1) == t1); assert(alist_at(al, 2) == t3); alist_clear(al); assert(alist_count(al) == 0); assert(alist_current(al) == NULL); assert(alist_current_idx(al) == -1); alist_insert(al, 5, t1); assert(alist_count(al) == 1); assert(alist_current(al) == t1); assert(alist_current_idx(al) == 0); alist_insert(al, 0, t2); assert(alist_count(al) == 2); assert(alist_current(al) == t2); assert(alist_current_idx(al) == 0); alist_insert(al, 1, t3); assert(alist_count(al) == 3); assert(alist_at(al, 0) == t2); assert(alist_at(al, 1) == t3); assert(alist_at(al, 2) == t1); assert(alist_current(al) == t3); assert(alist_current_idx(al) == 1); alist_delete(al); printf("alist test successful.\n"); return 0; } #endif /* TEST */