/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ /*[]---------------------------------------------------[]*/ /*| |*/ /*| list.c - bidirectional list class |*/ /*| |*/ /*| |*/ /*| Author: Alexander Gelfenbain |*/ /*[]---------------------------------------------------[]*/ #include #if OSL_DEBUG_LEVEL == 0 # ifndef NDEBUG # define NDEBUG # endif #endif #include /* #define TEST */ #include "list.h" /*- private data types */ typedef struct _lnode { struct _lnode *next; struct _lnode *prev; void *value; } lnode; struct _list { lnode *head, *tail, *cptr; size_t aCount; list_destructor eDtor; }; /*- private methods */ static lnode *newNode(void *el) { lnode *ptr = (lnode*)rtl_allocateMemory(sizeof(lnode)); assert(ptr != 0); ptr->value = el; return ptr; } static lnode *appendPrim(list pThis, void *el) { lnode *ptr = newNode(el); lnode **flink, *blink; if (pThis->tail != 0) { flink = &(pThis->tail->next); blink = pThis->tail; } else { flink = &pThis->head; blink = 0; pThis->cptr = ptr; /*- list was empty - set current to pThis element */ } *flink = ptr; pThis->tail = ptr; ptr->prev = blink; ptr->next = 0; pThis->aCount++; return ptr; } #ifdef TEST static lnode *prependPrim(list pThis, void *el) { lnode *ptr = newNode(el); lnode *flink, **blink; if (pThis->head != 0) { blink = &(pThis->head->prev); flink = pThis->head; } else { blink = &pThis->tail; flink = 0; pThis->cptr = ptr; /*- list was empty - set current to pThis element */ } *blink = ptr; pThis->head = ptr; ptr->next = flink; ptr->prev = 0; pThis->aCount++; return ptr; } #endif /*- public methods */ list listNewEmpty(void) /*- default ctor */ { list pThis = (list)rtl_allocateMemory(sizeof(struct _list)); assert(pThis != 0); pThis->aCount = 0; pThis->eDtor = 0; pThis->head = pThis->tail = pThis->cptr = 0; return pThis; } #ifdef TEST list listNewCopy(list l) /*- copy ctor */ { lnode *ptr, *c; list pThis; assert(l != 0); pThis = rtl_allocateMemory(sizeof(struct _list)); assert(pThis != 0); ptr = l->head; pThis->aCount = 0; pThis->eDtor = 0; pThis->head = pThis->tail = pThis->cptr = 0; while (ptr) { c = appendPrim(pThis, ptr->value); if (ptr == l->cptr) pThis->cptr = c; ptr = ptr->next; } return pThis; } #endif void listDispose(list pThis) /*- dtor */ { assert(pThis != 0); listClear(pThis); rtl_freeMemory(pThis); } void listSetElementDtor(list pThis, list_destructor f) { assert(pThis != 0); pThis->eDtor = f; } /* calling this function on an empty list is a run-time error */ void *listCurrent(list pThis) { assert(pThis != 0); assert(pThis->cptr != 0); return pThis->cptr->value; } int listCount(list pThis) { assert(pThis != 0); return pThis->aCount; } int listIsEmpty(list pThis) { assert(pThis != 0); return pThis->aCount == 0; } #ifdef TEST int listAtFirst(list pThis) { assert(pThis != 0); return pThis->cptr == pThis->head; } int listAtLast(list pThis) { assert(pThis != 0); return pThis->cptr == pThis->tail; } int listPosition(list pThis) { int res = 0; lnode *ptr; assert(pThis != 0); ptr = pThis->head; while (ptr != pThis->cptr) { ptr = ptr->next; res++; } return res; } #endif int listFind(list pThis, void *el) { lnode *ptr; assert(pThis != 0); ptr = pThis->head; while (ptr) { if (ptr->value == el) { pThis->cptr = ptr; return 1; } ptr = ptr->next; } return 0; } int listNext(list pThis) { return listSkipForward(pThis, 1); } int listSkipForward(list pThis, int n) { int m = 0; assert(pThis != 0); if (pThis->cptr == 0) return 0; while (n != 0) { if (pThis->cptr->next == 0) break; pThis->cptr = pThis->cptr->next; n--; m++; } return m; } int listToFirst(list pThis) { assert(pThis != 0); if (pThis->cptr != pThis->head) { pThis->cptr = pThis->head; return 1; } return 0; } int listToLast(list pThis) { assert(pThis != 0); if (pThis->cptr != pThis->tail) { pThis->cptr = pThis->tail; return 1; } return 0; } int listPositionAt(list pThis, int n) /*- returns the actual position number */ { int m = 0; assert(pThis != 0); pThis->cptr = pThis->head; while (n != 0) { if (pThis->cptr->next == 0) break; pThis->cptr = pThis->cptr->next; n--; m++; } return m; } list listAppend(list pThis, void *el) { assert(pThis != 0); appendPrim(pThis, el); return pThis; } #ifdef TEST list listPrepend(list pThis, void *el) { assert(pThis != 0); prependPrim(pThis, el); return pThis; } list listInsertAfter(list pThis, void *el) { lnode *ptr; assert(pThis != 0); if (pThis->cptr == 0) return listAppend(pThis, el); ptr = newNode(el); ptr->prev = pThis->cptr; ptr->next = pThis->cptr->next; pThis->cptr->next = ptr; if (ptr->next != 0) { ptr->next->prev = ptr; } else { pThis->tail = ptr; } pThis->aCount++; return pThis; } list listInsertBefore(list pThis, void *el) { lnode *ptr; assert(pThis != 0); if (pThis->cptr == 0) return listAppend(pThis, el); ptr = newNode(el); ptr->prev = pThis->cptr->prev; ptr->next = pThis->cptr; pThis->cptr->prev = ptr; if (ptr->prev != 0) { ptr->prev->next = ptr; } else { pThis->head = ptr; } pThis->aCount++; return pThis; } #endif list listRemove(list pThis) { lnode *ptr = 0; if (pThis->cptr == 0) return pThis; if (pThis->cptr->next != 0) { ptr = pThis->cptr->next; pThis->cptr->next->prev = pThis->cptr->prev; } else { pThis->tail = pThis->cptr->prev; } if (pThis->cptr->prev != 0) { if (ptr == 0) ptr = pThis->cptr->prev; pThis->cptr->prev->next = pThis->cptr->next; } else { pThis->head = pThis->cptr->next; } if (pThis->eDtor) pThis->eDtor(pThis->cptr->value); /* call the dtor callback */ rtl_freeMemory(pThis->cptr); pThis->aCount--; pThis->cptr = ptr; return pThis; } list listClear(list pThis) { lnode *node = pThis->head, *ptr; while (node) { ptr = node->next; if (pThis->eDtor) pThis->eDtor(node->value); /* call the dtor callback */ rtl_freeMemory(node); pThis->aCount--; node = ptr; } pThis->head = pThis->tail = pThis->cptr = 0; assert(pThis->aCount == 0); return pThis; } #ifdef TEST void listForAll(list pThis, void (*f)(void *)) { lnode *ptr = pThis->head; while (ptr) { f(ptr->value); ptr = ptr->next; } } #include void printlist(list l) { int saved; assert(l != 0); saved = listPosition(l); printf("[ "); if (!listIsEmpty(l)) { listToFirst(l); do { printf("%d ", (int) listCurrent(l)); } while (listNext(l)); } printf("]\n"); listPositionAt(l, saved); } void printstringlist(list l) { int saved; assert(l != 0); saved = listPosition(l); printf("[ "); if (!listIsEmpty(l)) { listToFirst(l); do { printf("'%s' ", (char *) listCurrent(l)); } while (listNext(l)); } printf("]\n"); listPositionAt(l, saved); } void printstat(list l) { printf("count: %d, position: %d, isEmpty: %d, atFirst: %d, atLast: %d.\n", listCount(l), listPosition(l), listIsEmpty(l), listAtFirst(l), listAtLast(l)); } void allfunc(void *e) { printf("%d ", e); } void edtor(void *ptr) { printf("element dtor: 0x%08x\n", ptr); rtl_freeMemory(ptr); } int main() { list l1, l2; char *ptr; int i; l1 = listNewEmpty(); printstat(l1); listAppend(l1, 1); printstat(l1); listAppend(l1, 2); printstat(l1); listAppend(l1, 3); printstat(l1); printlist(l1); listToFirst(l1); listInsertBefore(l1, -5); printlist(l1); l2 = listNewCopy(l1); printlist(l2); listForAll(l2, allfunc); printf("\n"); listClear(l1); listSetElementDtor(l1, edtor); for(i=0; i<10; i++) { ptr = rtl_allocateMemory(20); snprintf(ptr, 20, "element # %d", i); listAppend(l1, ptr); } printstringlist(l1); listDispose(l1); listDispose(l2); return 0; } #endif /* vim: set noet sw=4 ts=4: */