/* ** Command & Conquer Renegade(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ /****************************************************************************\ * C O N F I D E N T I A L --- W E S T W O O D S T U D I O S * ****************************************************************************** Project Name: File Name : linkedlist.h Author : Neal Kettler Start Date : June 19, 1997 Last Update : June 19, 1997 Linked list template. This is a fairly standard doubly linked list that allows insertion and removal at any point in the list. A current pointer is used to quickly access items when they are examined sequentially. Copies of the data are stored instead of a pointer to the original. If you want to store pointers then the template should be of a pointer type. \****************************************************************************/ #ifndef LINKEDLIST_HEADER #define LINKEDLIST_HEADER #include #include #include #include #include "wstypes.h" template class LNode { public: T Node; LNode *Next; LNode *Prev; }; template class LinkedList { public: LinkedList(); LinkedList(LinkedList &other); ~LinkedList(); // Remove all entries from the lsit void clear(void); // Add a node after the zero based 'pos' bit8 add(IN T &node,sint32 pos, OUT T **newnodeptr=NULL); bit8 addTail(IN T &node, OUT T **newnodeptr=NULL); bit8 addHead(IN T &node, OUT T **newnodeptr=NULL); // Remove a node bit8 remove(OUT T &node,sint32 pos); bit8 remove(sint32 pos); bit8 removeHead(OUT T &node); bit8 removeTail(OUT T &node); // Get a node without removing from the list bit8 get(OUT T &node,sint32 pos); bit8 getHead(OUT T &node); bit8 getTail(OUT T &node); // Get a pointer to the internally managed data (careful!) bit8 getPointer(OUT T **node, sint32 pos); // Get the number of entries in the list sint32 length(void); // Print information on the list void print(IN FILE *out); // assignment operator LinkedList &operator=(LinkedList &other); private: sint32 Entries; // Number of entries LNode *Head; // Head of the list LNode *Tail; // Tail of the list LNode *Current; // Current pointer & index for speed only sint32 CurIndex; }; //Create the empty list template LinkedList::LinkedList() { Entries=0; Head=Tail=Current=NULL; CurIndex=-1; // Not valid when 0 entries } // copy constructor template LinkedList::LinkedList(LinkedList &other) { Entries=0; Head=Tail=Current=NULL; CurIndex=-1; // Not valid when 0 entries (*this)=other; } //Free all the memory... template LinkedList::~LinkedList() { clear(); // Remove the entries } // assignment operator template LinkedList &LinkedList::operator=(LinkedList &other) { T node; clear(); for (int i=0; i void LinkedList::clear() { LNode *temp,*del; temp=Head; while (temp) { del=temp; temp=temp->Next; delete(del); } Entries=0; CurIndex=-1; Head=Tail=Current=NULL; } // When adding into a position, the new node goes at the zero based slot // specified by pos. All other nodes get moved one slot down. template bit8 LinkedList::add(IN T &node,sint32 pos, OUT T **newnodeptr) { LNode *temp; LNode *item; if (pos<0) pos=0; if (pos>Entries) pos=Entries; item=(LNode *)new LNode; assert(item!=NULL); item->Node=node; // copy the passed in object item->Prev=NULL; item->Next=NULL; if (newnodeptr) *newnodeptr=&(item->Node); if ((pos==0)||(pos==Entries)) { // Both cases can be true for a new list! if (pos==0) { item->Next=Head; if (Head) Head->Prev=item; Head=item; } if (pos==Entries) { item->Prev=Tail; if (Tail) Tail->Next=item; Tail=item; } Entries++; Current=item; CurIndex=pos; return(TRUE); } // If control is here, we know the new node is not an endpoint // Check for possible speedup, so we don't have to scan the list if (pos==CurIndex) { item->Next=Current; item->Prev=Current->Prev; Current->Prev=item; item->Prev->Next=item; Current=item; Entries++; return(TRUE); } // Check the other possible speedup (adding after CurIndex) if (pos==CurIndex+1) { item->Next=Current->Next; item->Prev=Current; Current->Next=item; item->Next->Prev=item; Current=item; CurIndex++; Entries++; return(TRUE); } // If control reaches here we have to scan the whole thing temp=Head->Next; // Can start at node '1' because head was special cased for (int i=1; iNext; assert(temp!=NULL); } item->Next=temp; item->Prev=temp->Prev; temp->Prev=item; item->Prev->Next=item; Current=item; CurIndex=pos; Entries++; return(TRUE); } // Add to the first node, all others get shifted down one slot template bit8 LinkedList::addHead(IN T &node, OUT T **newnodeptr) { return(add(node,0,newnodeptr)); } // Append to the end of the list template bit8 LinkedList::addTail(IN T &node, OUT T **newnodeptr) { return(add(node,length(),newnodeptr)); } // Remove at the zero based index specified by 'pos'. When removing from // a slot, all others get shifted up by one. template bit8 LinkedList::remove(OUT T &node, sint32 pos) { ////////LNode *temp; LNode *item; if (Entries==0) return(FALSE); if (pos<0) pos=0; if (pos>=Entries) pos=Entries-1; if ((pos==0)||(pos==Entries-1)) { // Both can be true for a 1 item list if (pos==0) { item=Head; if (item->Next) item->Next->Prev=NULL; Head=item->Next; node=item->Node; Current=Head; CurIndex=0; } if (pos==Entries-1) { item=Tail; if (item->Prev) item->Prev->Next=NULL; Tail=item->Prev; node=item->Node; Current=Tail; CurIndex=Entries-2; } delete(item); Entries--; if (Entries==0) { // Super paranoia check assert(Current==NULL); assert(CurIndex==-1); assert(Head==NULL); assert(Tail==NULL); } return(TRUE); } // If control is here, we know the target node is not an endpoint // Check for possible speedup, so we don't have to scan the list if (pos==CurIndex) { item=Current; item->Prev->Next=item->Next; item->Next->Prev=item->Prev; Current=item->Next; // CurIndex stays the same node=item->Node; delete(item); Entries--; return(TRUE); } // Check the other possible speedup (removing after CurIndex) if (pos==CurIndex+1) { item=Current->Next; item->Prev->Next=item->Next; item->Next->Prev=item->Prev; Current=item->Next; CurIndex++; node=item->Node; delete(item); Entries--; return(TRUE); } // If control reaches here we have to scan the whole thing item=Head->Next; // Can start at node '1' because head was special cased for (int i=1; iNext; assert(item!=NULL); } item->Prev->Next=item->Next; item->Next->Prev=item->Prev; Current=item->Next; CurIndex=pos; node=item->Node; delete(item); Entries--; return(TRUE); } // Remove at the zero based index specified by 'pos'. When removing from // a slot, all others get shifted up by one. template bit8 LinkedList::remove(sint32 pos) { T temp_node; return(remove(temp_node,pos)); } // Remove the first node of the list template bit8 LinkedList::removeHead(OUT T &node) { return(remove(node,0)); } // Remove the last node of the list template bit8 LinkedList::removeTail(OUT T &node) { return(remove(node,Entries-1)); } template bit8 LinkedList::get(OUT T &node, sint32 pos) { T *objptr; bool retval=getPointer(&objptr,pos); if (retval && objptr) node=*objptr; return(retval); } template bit8 LinkedList::getPointer(OUT T **node,sint32 pos) { if ((node==0)||(Entries==0)) return(FALSE); LNode *item; if (pos<0) { //pos=0; return(FALSE); } if (pos>=Entries) { //pos=Entries-1; return(FALSE); } if (pos==0) { *node=&(Head->Node); return(TRUE); } else if (pos==Entries-1) { *node=&(Tail->Node); return(TRUE); } // If control reaches here, we know target is not an endpoint // Check for possible speedup, so we don't have to scan the list if (pos==CurIndex) { *node=&(Current->Node); return(TRUE); } else if (pos==CurIndex+1) { *node=&(Current->Next->Node); CurIndex++; Current=Current->Next; return(TRUE); } else if (pos==CurIndex-1) { *node=&(Current->Prev->Node); CurIndex--; Current=Current->Prev; return(TRUE); } // If control reaches here we have to scan the whole thing item=Head->Next; // Can start at node '1' because head was special cased for (int i=1; iNext; assert(item!=NULL); } *node=&(item->Node); CurIndex=pos; Current=item; return(TRUE); } // Remove the first node of the list template bit8 LinkedList::getHead(OUT T &node) { return(get(node,0)); } // Remove the last node of the list template bit8 LinkedList::getTail(OUT T &node) { return(get(node,Entries-1)); } template void LinkedList::print(IN FILE *out) { LNode *temp; fprintf(out,"--------------------\n"); fprintf(out,"Entries = %d\n",length()); fprintf(out,"H = %8p C = %8p (%d) T = %8p\n",Head,Current,CurIndex,Tail); temp=Head; while (temp) { fprintf(out," %8p<-((%8p))->%8p \n",temp->Prev,temp,temp->Next); temp=temp->Next; } fprintf(out,"--------------------\n"); } // Return the current length of the list template sint32 LinkedList::length(void) { return(Entries); } #endif