/* * Copyright (c) 2003-2019 Apple 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. */ #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; if (elem == NULL) { return 0; } 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; }