mirror of
https://github.com/electronicarts/CnC_Renegade.git
synced 2025-12-16 23:51:41 -05:00
Initial commit of Command & Conquer Renegade source code.
This commit is contained in:
495
Code/Tools/wlib/linkedlist.h
Normal file
495
Code/Tools/wlib/linkedlist.h
Normal file
@@ -0,0 +1,495 @@
|
||||
/*
|
||||
** 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/****************************************************************************\
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "wstypes.h"
|
||||
|
||||
template <class T>
|
||||
class LNode
|
||||
{
|
||||
public:
|
||||
T Node;
|
||||
LNode<T> *Next;
|
||||
LNode<T> *Prev;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class LinkedList
|
||||
{
|
||||
public:
|
||||
LinkedList();
|
||||
LinkedList(LinkedList<T> &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<T> &operator=(LinkedList<T> &other);
|
||||
|
||||
private:
|
||||
sint32 Entries; // Number of entries
|
||||
LNode<T> *Head; // Head of the list
|
||||
LNode<T> *Tail; // Tail of the list
|
||||
|
||||
LNode<T> *Current; // Current pointer & index for speed only
|
||||
sint32 CurIndex;
|
||||
};
|
||||
|
||||
|
||||
//Create the empty list
|
||||
template <class T>
|
||||
LinkedList<T>::LinkedList()
|
||||
{
|
||||
Entries=0;
|
||||
Head=Tail=Current=NULL;
|
||||
CurIndex=-1; // Not valid when 0 entries
|
||||
}
|
||||
|
||||
// copy constructor
|
||||
template <class T>
|
||||
LinkedList<T>::LinkedList(LinkedList<T> &other)
|
||||
{
|
||||
Entries=0;
|
||||
Head=Tail=Current=NULL;
|
||||
CurIndex=-1; // Not valid when 0 entries
|
||||
(*this)=other;
|
||||
}
|
||||
|
||||
//Free all the memory...
|
||||
template <class T>
|
||||
LinkedList<T>::~LinkedList()
|
||||
{
|
||||
clear(); // Remove the entries
|
||||
}
|
||||
|
||||
// assignment operator
|
||||
template <class T>
|
||||
LinkedList<T> &LinkedList<T>::operator=(LinkedList<T> &other)
|
||||
{
|
||||
T node;
|
||||
clear();
|
||||
for (int i=0; i<other.length(); i++)
|
||||
{
|
||||
other.get(node,i);
|
||||
addTail(node);
|
||||
}
|
||||
return(*this);
|
||||
}
|
||||
|
||||
|
||||
// Remove all the entries and free the memory
|
||||
template <class T>
|
||||
void LinkedList<T>::clear()
|
||||
{
|
||||
LNode<T> *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 <class T>
|
||||
bit8 LinkedList<T>::add(IN T &node,sint32 pos, OUT T **newnodeptr)
|
||||
{
|
||||
LNode<T> *temp;
|
||||
LNode<T> *item;
|
||||
|
||||
if (pos<0)
|
||||
pos=0;
|
||||
if (pos>Entries)
|
||||
pos=Entries;
|
||||
|
||||
item=(LNode<T> *)new LNode<T>;
|
||||
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; i<pos; i++) {
|
||||
temp=temp->Next;
|
||||
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 <class T>
|
||||
bit8 LinkedList<T>::addHead(IN T &node, OUT T **newnodeptr)
|
||||
{
|
||||
return(add(node,0,newnodeptr));
|
||||
}
|
||||
|
||||
|
||||
// Append to the end of the list
|
||||
template <class T>
|
||||
bit8 LinkedList<T>::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 <class T>
|
||||
bit8 LinkedList<T>::remove(OUT T &node, sint32 pos)
|
||||
{
|
||||
////////LNode<T> *temp;
|
||||
LNode<T> *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; i<pos; i++) {
|
||||
item=item->Next;
|
||||
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 <class T>
|
||||
bit8 LinkedList<T>::remove(sint32 pos)
|
||||
{
|
||||
T temp_node;
|
||||
return(remove(temp_node,pos));
|
||||
}
|
||||
|
||||
|
||||
// Remove the first node of the list
|
||||
template <class T>
|
||||
bit8 LinkedList<T>::removeHead(OUT T &node)
|
||||
{
|
||||
return(remove(node,0));
|
||||
}
|
||||
|
||||
|
||||
// Remove the last node of the list
|
||||
template <class T>
|
||||
bit8 LinkedList<T>::removeTail(OUT T &node)
|
||||
{
|
||||
return(remove(node,Entries-1));
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <class T>
|
||||
bit8 LinkedList<T>::get(OUT T &node, sint32 pos)
|
||||
{
|
||||
T *objptr;
|
||||
bool retval=getPointer(&objptr,pos);
|
||||
if (retval && objptr)
|
||||
node=*objptr;
|
||||
|
||||
return(retval);
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
bit8 LinkedList<T>::getPointer(OUT T **node,sint32 pos)
|
||||
{
|
||||
if ((node==0)||(Entries==0))
|
||||
return(FALSE);
|
||||
|
||||
LNode<T> *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; i<pos; i++) {
|
||||
item=item->Next;
|
||||
assert(item!=NULL);
|
||||
}
|
||||
*node=&(item->Node);
|
||||
CurIndex=pos;
|
||||
Current=item;
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
// Remove the first node of the list
|
||||
template <class T>
|
||||
bit8 LinkedList<T>::getHead(OUT T &node)
|
||||
{
|
||||
return(get(node,0));
|
||||
}
|
||||
|
||||
|
||||
// Remove the last node of the list
|
||||
template <class T>
|
||||
bit8 LinkedList<T>::getTail(OUT T &node)
|
||||
{
|
||||
return(get(node,Entries-1));
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
void LinkedList<T>::print(IN FILE *out)
|
||||
{
|
||||
LNode<T> *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 <class T>
|
||||
sint32 LinkedList<T>::length(void) {
|
||||
return(Entries);
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user