| /* -*- Mode: C; tab-width: 4 -*- |
| * |
| * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. |
| * |
| * Licensed 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. |
| |
| File: GenLinkedList.c |
| |
| Contains: implementation of generic linked lists. |
| |
| Version: 1.0 |
| Tabs: 4 spaces |
| */ |
| |
| #include "GenLinkedList.h" |
| |
| |
| // Return the link pointer contained within element e at offset o. |
| #define GETLINK( e, o) ( *(void**)((char*) (e) + (o)) ) |
| |
| // Assign the link pointer l to element e at offset o. |
| #define ASSIGNLINK( e, l, o) ( *((void**)((char*) (e) + (o))) = (l)) |
| |
| |
| // GenLinkedList ///////////////////////////////////////////////////////////// |
| |
| void InitLinkedList( GenLinkedList *pList, size_t linkOffset) |
| /* Initialize the block of memory pointed to by pList as a linked list. */ |
| { |
| pList->Head = NULL; |
| pList->Tail = NULL; |
| pList->LinkOffset = linkOffset; |
| } |
| |
| |
| void AddToTail( GenLinkedList *pList, void *elem) |
| /* Add a linked list element to the tail of the list. */ |
| { |
| if ( pList->Tail) { |
| ASSIGNLINK( pList->Tail, elem, pList->LinkOffset); |
| } else |
| pList->Head = elem; |
| ASSIGNLINK( elem, NULL, pList->LinkOffset); |
| |
| pList->Tail = elem; |
| } |
| |
| |
| void AddToHead( GenLinkedList *pList, void *elem) |
| /* Add a linked list element to the head of the list. */ |
| { |
| ASSIGNLINK( elem, pList->Head, pList->LinkOffset); |
| if ( pList->Tail == NULL) |
| pList->Tail = elem; |
| |
| pList->Head = elem; |
| } |
| |
| |
| int RemoveFromList( GenLinkedList *pList, void *elem) |
| /* Remove a linked list element from the list. Return 0 if it was not found. */ |
| /* If the element is removed, its link will be set to NULL. */ |
| { |
| void *iElem, *lastElem; |
| |
| for ( iElem = pList->Head, lastElem = NULL; iElem; iElem = GETLINK( iElem, pList->LinkOffset)) { |
| if ( iElem == elem) { |
| if ( lastElem) { // somewhere past the head |
| ASSIGNLINK( lastElem, GETLINK( elem, pList->LinkOffset), pList->LinkOffset); |
| } else { // at the head |
| pList->Head = GETLINK( elem, pList->LinkOffset); |
| } |
| if ( pList->Tail == elem) |
| pList->Tail = lastElem ? lastElem : NULL; |
| ASSIGNLINK( elem, NULL, pList->LinkOffset); // maybe catch a stale reference bug. |
| return 1; |
| } |
| lastElem = iElem; |
| } |
| |
| return 0; |
| } |
| |
| |
| int ReplaceElem( GenLinkedList *pList, void *elemInList, void *newElem) |
| /* Replace an element in the list with a new element, in the same position. */ |
| { |
| void *iElem, *lastElem; |
| |
| if ( elemInList == NULL || newElem == NULL) |
| return 0; |
| |
| for ( iElem = pList->Head, lastElem = NULL; iElem; iElem = GETLINK( iElem, pList->LinkOffset)) |
| { |
| if ( iElem == elemInList) |
| { |
| ASSIGNLINK( newElem, GETLINK( elemInList, pList->LinkOffset), pList->LinkOffset); |
| if ( lastElem) // somewhere past the head |
| { |
| ASSIGNLINK( lastElem, newElem, pList->LinkOffset); |
| } |
| else // at the head |
| { |
| pList->Head = newElem; |
| } |
| if ( pList->Tail == elemInList) |
| pList->Tail = newElem; |
| return 1; |
| } |
| lastElem = iElem; |
| } |
| |
| return 0; |
| } |
| |
| |
| // GenDoubleLinkedList ///////////////////////////////////////////////////////// |
| |
| void InitDoubleLinkedList( GenDoubleLinkedList *pList, size_t fwdLinkOffset, |
| size_t backLinkOffset) |
| /* Initialize the block of memory pointed to by pList as a double linked list. */ |
| { |
| pList->Head = NULL; |
| pList->Tail = NULL; |
| pList->FwdLinkOffset = fwdLinkOffset; |
| pList->BackLinkOffset = backLinkOffset; |
| } |
| |
| |
| void DLLAddToHead( GenDoubleLinkedList *pList, void *elem) |
| /* Add a linked list element to the head of the list. */ |
| { |
| void *pNext; |
| |
| pNext = pList->Head; |
| |
| // fix up the forward links |
| ASSIGNLINK( elem, pList->Head, pList->FwdLinkOffset); |
| pList->Head = elem; |
| |
| // fix up the backward links |
| if ( pNext) { |
| ASSIGNLINK( pNext, elem, pList->BackLinkOffset); |
| } else |
| pList->Tail = elem; |
| ASSIGNLINK( elem, NULL, pList->BackLinkOffset); |
| } |
| |
| |
| void DLLRemoveFromList( GenDoubleLinkedList *pList, void *elem) |
| /* Remove a linked list element from the list. */ |
| /* When the element is removed, its link will be set to NULL. */ |
| { |
| void *pNext, *pPrev; |
| |
| pNext = GETLINK( elem, pList->FwdLinkOffset); |
| pPrev = GETLINK( elem, pList->BackLinkOffset); |
| |
| // fix up the forward links |
| if ( pPrev) |
| ASSIGNLINK( pPrev, pNext, pList->FwdLinkOffset); |
| else |
| pList->Head = pNext; |
| |
| // fix up the backward links |
| if ( pNext) |
| ASSIGNLINK( pNext, pPrev, pList->BackLinkOffset); |
| else |
| pList->Tail = pPrev; |
| |
| ASSIGNLINK( elem, NULL, pList->FwdLinkOffset); |
| ASSIGNLINK( elem, NULL, pList->BackLinkOffset); |
| } |
| |
| |
| // GenLinkedOffsetList ///////////////////////////////////////////////////// |
| |
| // Extract the Next offset from element |
| #define GETOFFSET( e, o) ( *(size_t*)((char*) (e) + (o)) ) |
| |
| static void AssignOffsetLink( void *elem, void *link, size_t linkOffset); |
| |
| |
| static void AssignOffsetLink( void *elem, void *link, size_t linkOffset) |
| // Assign link to elem as an offset from elem. Assign 0 to elem if link is NULL. |
| { |
| GETOFFSET( elem, linkOffset) = link ? (size_t) link - (size_t) elem : 0; |
| } |
| |
| |
| void *GetHeadPtr( GenLinkedOffsetList *pList) |
| /* Return a pointer to the head element of a list, or NULL if none. */ |
| { |
| return pList->Head ? ( (char*) (pList) + pList->Head) : NULL; |
| } |
| |
| |
| void *GetTailPtr( GenLinkedOffsetList *pList) |
| /* Return a pointer to the tail element of a list, or NULL if none. */ |
| { |
| return pList->Tail ? ( (char*) (pList) + pList->Tail) : NULL; |
| } |
| |
| |
| void *GetOffsetLink( GenLinkedOffsetList *pList, void *elem) |
| /* Return the link pointer contained within element e for pList, or NULL if it is 0. */ |
| { |
| size_t nextOffset; |
| |
| nextOffset = GETOFFSET( elem, pList->LinkOffset); |
| |
| return nextOffset ? (char*) elem + nextOffset : NULL; |
| } |
| |
| |
| void InitLinkedOffsetList( GenLinkedOffsetList *pList, size_t linkOffset) |
| /* Initialize the block of memory pointed to by pList as a linked list. */ |
| { |
| pList->Head = 0; |
| pList->Tail = 0; |
| pList->LinkOffset = linkOffset; |
| } |
| |
| |
| void OffsetAddToTail( GenLinkedOffsetList *pList, void *elem) |
| /* Add a linked list element to the tail of the list. */ |
| { |
| if ( pList->Tail) { |
| AssignOffsetLink( GetTailPtr( pList), elem, pList->LinkOffset); |
| } else |
| pList->Head = (size_t) elem - (size_t) pList; |
| AssignOffsetLink( elem, NULL, pList->LinkOffset); |
| |
| pList->Tail = (size_t) elem - (size_t) pList; |
| } |
| |
| |
| void OffsetAddToHead( GenLinkedOffsetList *pList, void *elem) |
| /* Add a linked list element to the head of the list. */ |
| { |
| AssignOffsetLink( elem, GetHeadPtr( pList), pList->LinkOffset); |
| if ( pList->Tail == 0) |
| pList->Tail = (size_t) elem - (size_t) pList; |
| |
| pList->Head = (size_t) elem - (size_t) pList; |
| } |
| |
| |
| int OffsetRemoveFromList( GenLinkedOffsetList *pList, void *elem) |
| /* Remove a linked list element from the list. Return 0 if it was not found. */ |
| /* If the element is removed, its link will be set to NULL. */ |
| { |
| void *iElem, *lastElem; |
| |
| for ( iElem = GetHeadPtr( pList), lastElem = NULL; iElem; |
| iElem = GetOffsetLink( pList, iElem)) |
| { |
| if ( iElem == elem) { |
| if ( lastElem) { // somewhere past the head |
| AssignOffsetLink( lastElem, GetOffsetLink( pList, elem), pList->LinkOffset); |
| } else { // at the head |
| iElem = GetOffsetLink( pList, elem); |
| pList->Head = iElem ? (size_t) iElem - (size_t) pList : 0; |
| } |
| if ( GetTailPtr( pList) == elem) |
| pList->Tail = lastElem ? (size_t) lastElem - (size_t) pList : 0; |
| AssignOffsetLink( elem, NULL, pList->LinkOffset); // maybe catch a stale reference bug. |
| return 1; |
| } |
| lastElem = iElem; |
| } |
| |
| return 0; |
| } |
| |
| |
| int OffsetReplaceElem( GenLinkedOffsetList *pList, void *elemInList, void *newElem) |
| /* Replace an element in the list with a new element, in the same position. */ |
| { |
| void *iElem, *lastElem; |
| |
| if ( elemInList == NULL || newElem == NULL) |
| return 0; |
| |
| for ( iElem = GetHeadPtr( pList), lastElem = NULL; iElem; |
| iElem = GetOffsetLink( pList, iElem)) |
| { |
| if ( iElem == elemInList) |
| { |
| AssignOffsetLink( newElem, GetOffsetLink( pList, elemInList), pList->LinkOffset); |
| if ( lastElem) // somewhere past the head |
| { |
| AssignOffsetLink( lastElem, newElem, pList->LinkOffset); |
| } |
| else // at the head |
| { |
| pList->Head = (size_t) newElem - (size_t) pList; |
| } |
| if ( GetTailPtr( pList) == elemInList) |
| pList->Tail = (size_t) newElem - (size_t) pList; |
| return 1; |
| } |
| lastElem = iElem; |
| } |
| |
| return 0; |
| } |
| |
| |