linkedlist.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /****************************************************************************\
  19. * 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 *
  20. ******************************************************************************
  21. Project Name:
  22. File Name : linkedlist.h
  23. Author : Neal Kettler
  24. Start Date : June 19, 1997
  25. Last Update : June 19, 1997
  26. Linked list template. This is a fairly standard doubly linked list that
  27. allows insertion and removal at any point in the list. A current pointer
  28. is used to quickly access items when they are examined sequentially.
  29. Copies of the data are stored instead of a pointer to the original.
  30. If you want to store pointers then the template should be of a pointer type.
  31. \****************************************************************************/
  32. #ifndef LINKEDLIST_HEADER
  33. #define LINKEDLIST_HEADER
  34. #include <stdio.h>
  35. #include <stdlib.h>
  36. #include <string.h>
  37. #include <assert.h>
  38. #include "wstypes.h"
  39. template <class T>
  40. class LNode
  41. {
  42. public:
  43. T Node;
  44. LNode<T> *Next;
  45. LNode<T> *Prev;
  46. };
  47. template <class T>
  48. class LinkedList
  49. {
  50. public:
  51. LinkedList();
  52. LinkedList(LinkedList<T> &other);
  53. ~LinkedList();
  54. // Remove all entries from the lsit
  55. void clear(void);
  56. // Add a node after the zero based 'pos'
  57. bit8 add(IN T &node,sint32 pos, OUT T **newnodeptr=NULL);
  58. bit8 addTail(IN T &node, OUT T **newnodeptr=NULL);
  59. bit8 addHead(IN T &node, OUT T **newnodeptr=NULL);
  60. // Remove a node
  61. bit8 remove(OUT T &node,sint32 pos);
  62. bit8 remove(sint32 pos);
  63. bit8 removeHead(OUT T &node);
  64. bit8 removeTail(OUT T &node);
  65. // Get a node without removing from the list
  66. bit8 get(OUT T &node,sint32 pos);
  67. bit8 getHead(OUT T &node);
  68. bit8 getTail(OUT T &node);
  69. // Get a pointer to the internally managed data (careful!)
  70. bit8 getPointer(OUT T **node, sint32 pos);
  71. // Get the number of entries in the list
  72. sint32 length(void);
  73. // Print information on the list
  74. void print(IN FILE *out);
  75. // assignment operator
  76. LinkedList<T> &operator=(LinkedList<T> &other);
  77. private:
  78. sint32 Entries; // Number of entries
  79. LNode<T> *Head; // Head of the list
  80. LNode<T> *Tail; // Tail of the list
  81. LNode<T> *Current; // Current pointer & index for speed only
  82. sint32 CurIndex;
  83. };
  84. //Create the empty list
  85. template <class T>
  86. LinkedList<T>::LinkedList()
  87. {
  88. Entries=0;
  89. Head=Tail=Current=NULL;
  90. CurIndex=-1; // Not valid when 0 entries
  91. }
  92. // copy constructor
  93. template <class T>
  94. LinkedList<T>::LinkedList(LinkedList<T> &other)
  95. {
  96. Entries=0;
  97. Head=Tail=Current=NULL;
  98. CurIndex=-1; // Not valid when 0 entries
  99. (*this)=other;
  100. }
  101. //Free all the memory...
  102. template <class T>
  103. LinkedList<T>::~LinkedList()
  104. {
  105. clear(); // Remove the entries
  106. }
  107. // assignment operator
  108. template <class T>
  109. LinkedList<T> &LinkedList<T>::operator=(LinkedList<T> &other)
  110. {
  111. T node;
  112. clear();
  113. for (int i=0; i<other.length(); i++)
  114. {
  115. other.get(node,i);
  116. addTail(node);
  117. }
  118. return(*this);
  119. }
  120. // Remove all the entries and free the memory
  121. template <class T>
  122. void LinkedList<T>::clear()
  123. {
  124. LNode<T> *temp,*del;
  125. temp=Head;
  126. while (temp) {
  127. del=temp;
  128. temp=temp->Next;
  129. delete(del);
  130. }
  131. Entries=0;
  132. CurIndex=-1;
  133. Head=Tail=Current=NULL;
  134. }
  135. // When adding into a position, the new node goes at the zero based slot
  136. // specified by pos. All other nodes get moved one slot down.
  137. template <class T>
  138. bit8 LinkedList<T>::add(IN T &node,sint32 pos, OUT T **newnodeptr)
  139. {
  140. LNode<T> *temp;
  141. LNode<T> *item;
  142. if (pos<0)
  143. pos=0;
  144. if (pos>Entries)
  145. pos=Entries;
  146. item=(LNode<T> *)new LNode<T>;
  147. assert(item!=NULL);
  148. item->Node=node; // copy the passed in object
  149. item->Prev=NULL;
  150. item->Next=NULL;
  151. if (newnodeptr)
  152. *newnodeptr=&(item->Node);
  153. if ((pos==0)||(pos==Entries)) { // Both cases can be true for a new list!
  154. if (pos==0) {
  155. item->Next=Head;
  156. if (Head)
  157. Head->Prev=item;
  158. Head=item;
  159. }
  160. if (pos==Entries) {
  161. item->Prev=Tail;
  162. if (Tail)
  163. Tail->Next=item;
  164. Tail=item;
  165. }
  166. Entries++;
  167. Current=item;
  168. CurIndex=pos;
  169. return(TRUE);
  170. }
  171. // If control is here, we know the new node is not an endpoint
  172. // Check for possible speedup, so we don't have to scan the list
  173. if (pos==CurIndex) {
  174. item->Next=Current;
  175. item->Prev=Current->Prev;
  176. Current->Prev=item;
  177. item->Prev->Next=item;
  178. Current=item;
  179. Entries++;
  180. return(TRUE);
  181. }
  182. // Check the other possible speedup (adding after CurIndex)
  183. if (pos==CurIndex+1) {
  184. item->Next=Current->Next;
  185. item->Prev=Current;
  186. Current->Next=item;
  187. item->Next->Prev=item;
  188. Current=item;
  189. CurIndex++;
  190. Entries++;
  191. return(TRUE);
  192. }
  193. // If control reaches here we have to scan the whole thing
  194. temp=Head->Next; // Can start at node '1' because head was special cased
  195. for (int i=1; i<pos; i++) {
  196. temp=temp->Next;
  197. assert(temp!=NULL);
  198. }
  199. item->Next=temp;
  200. item->Prev=temp->Prev;
  201. temp->Prev=item;
  202. item->Prev->Next=item;
  203. Current=item;
  204. CurIndex=pos;
  205. Entries++;
  206. return(TRUE);
  207. }
  208. // Add to the first node, all others get shifted down one slot
  209. template <class T>
  210. bit8 LinkedList<T>::addHead(IN T &node, OUT T **newnodeptr)
  211. {
  212. return(add(node,0,newnodeptr));
  213. }
  214. // Append to the end of the list
  215. template <class T>
  216. bit8 LinkedList<T>::addTail(IN T &node, OUT T **newnodeptr)
  217. {
  218. return(add(node,length(),newnodeptr));
  219. }
  220. // Remove at the zero based index specified by 'pos'. When removing from
  221. // a slot, all others get shifted up by one.
  222. template <class T>
  223. bit8 LinkedList<T>::remove(OUT T &node, sint32 pos)
  224. {
  225. ////////LNode<T> *temp;
  226. LNode<T> *item;
  227. if (Entries==0)
  228. return(FALSE);
  229. if (pos<0)
  230. pos=0;
  231. if (pos>=Entries)
  232. pos=Entries-1;
  233. if ((pos==0)||(pos==Entries-1)) { // Both can be true for a 1 item list
  234. if (pos==0) {
  235. item=Head;
  236. if (item->Next)
  237. item->Next->Prev=NULL;
  238. Head=item->Next;
  239. node=item->Node;
  240. Current=Head;
  241. CurIndex=0;
  242. }
  243. if (pos==Entries-1) {
  244. item=Tail;
  245. if (item->Prev)
  246. item->Prev->Next=NULL;
  247. Tail=item->Prev;
  248. node=item->Node;
  249. Current=Tail;
  250. CurIndex=Entries-2;
  251. }
  252. delete(item);
  253. Entries--;
  254. if (Entries==0) { // Super paranoia check
  255. assert(Current==NULL);
  256. assert(CurIndex==-1);
  257. assert(Head==NULL);
  258. assert(Tail==NULL);
  259. }
  260. return(TRUE);
  261. }
  262. // If control is here, we know the target node is not an endpoint
  263. // Check for possible speedup, so we don't have to scan the list
  264. if (pos==CurIndex) {
  265. item=Current;
  266. item->Prev->Next=item->Next;
  267. item->Next->Prev=item->Prev;
  268. Current=item->Next;
  269. // CurIndex stays the same
  270. node=item->Node;
  271. delete(item);
  272. Entries--;
  273. return(TRUE);
  274. }
  275. // Check the other possible speedup (removing after CurIndex)
  276. if (pos==CurIndex+1) {
  277. item=Current->Next;
  278. item->Prev->Next=item->Next;
  279. item->Next->Prev=item->Prev;
  280. Current=item->Next;
  281. CurIndex++;
  282. node=item->Node;
  283. delete(item);
  284. Entries--;
  285. return(TRUE);
  286. }
  287. // If control reaches here we have to scan the whole thing
  288. item=Head->Next; // Can start at node '1' because head was special cased
  289. for (int i=1; i<pos; i++) {
  290. item=item->Next;
  291. assert(item!=NULL);
  292. }
  293. item->Prev->Next=item->Next;
  294. item->Next->Prev=item->Prev;
  295. Current=item->Next;
  296. CurIndex=pos;
  297. node=item->Node;
  298. delete(item);
  299. Entries--;
  300. return(TRUE);
  301. }
  302. // Remove at the zero based index specified by 'pos'. When removing from
  303. // a slot, all others get shifted up by one.
  304. template <class T>
  305. bit8 LinkedList<T>::remove(sint32 pos)
  306. {
  307. T temp_node;
  308. return(remove(temp_node,pos));
  309. }
  310. // Remove the first node of the list
  311. template <class T>
  312. bit8 LinkedList<T>::removeHead(OUT T &node)
  313. {
  314. return(remove(node,0));
  315. }
  316. // Remove the last node of the list
  317. template <class T>
  318. bit8 LinkedList<T>::removeTail(OUT T &node)
  319. {
  320. return(remove(node,Entries-1));
  321. }
  322. template <class T>
  323. bit8 LinkedList<T>::get(OUT T &node, sint32 pos)
  324. {
  325. T *objptr;
  326. bool retval=getPointer(&objptr,pos);
  327. if (retval && objptr)
  328. node=*objptr;
  329. return(retval);
  330. }
  331. template <class T>
  332. bit8 LinkedList<T>::getPointer(OUT T **node,sint32 pos)
  333. {
  334. if ((node==0)||(Entries==0))
  335. return(FALSE);
  336. LNode<T> *item;
  337. if (pos<0)
  338. {
  339. //pos=0;
  340. return(FALSE);
  341. }
  342. if (pos>=Entries)
  343. {
  344. //pos=Entries-1;
  345. return(FALSE);
  346. }
  347. if (pos==0) {
  348. *node=&(Head->Node);
  349. return(TRUE);
  350. } else if (pos==Entries-1) {
  351. *node=&(Tail->Node);
  352. return(TRUE);
  353. }
  354. // If control reaches here, we know target is not an endpoint
  355. // Check for possible speedup, so we don't have to scan the list
  356. if (pos==CurIndex) {
  357. *node=&(Current->Node);
  358. return(TRUE);
  359. } else if (pos==CurIndex+1) {
  360. *node=&(Current->Next->Node);
  361. CurIndex++;
  362. Current=Current->Next;
  363. return(TRUE);
  364. } else if (pos==CurIndex-1) {
  365. *node=&(Current->Prev->Node);
  366. CurIndex--;
  367. Current=Current->Prev;
  368. return(TRUE);
  369. }
  370. // If control reaches here we have to scan the whole thing
  371. item=Head->Next; // Can start at node '1' because head was special cased
  372. for (int i=1; i<pos; i++) {
  373. item=item->Next;
  374. assert(item!=NULL);
  375. }
  376. *node=&(item->Node);
  377. CurIndex=pos;
  378. Current=item;
  379. return(TRUE);
  380. }
  381. // Remove the first node of the list
  382. template <class T>
  383. bit8 LinkedList<T>::getHead(OUT T &node)
  384. {
  385. return(get(node,0));
  386. }
  387. // Remove the last node of the list
  388. template <class T>
  389. bit8 LinkedList<T>::getTail(OUT T &node)
  390. {
  391. return(get(node,Entries-1));
  392. }
  393. template <class T>
  394. void LinkedList<T>::print(IN FILE *out)
  395. {
  396. LNode<T> *temp;
  397. fprintf(out,"--------------------\n");
  398. fprintf(out,"Entries = %d\n",length());
  399. fprintf(out,"H = %8p C = %8p (%d) T = %8p\n",Head,Current,CurIndex,Tail);
  400. temp=Head;
  401. while (temp) {
  402. fprintf(out," %8p<-((%8p))->%8p \n",temp->Prev,temp,temp->Next);
  403. temp=temp->Next;
  404. }
  405. fprintf(out,"--------------------\n");
  406. }
  407. // Return the current length of the list
  408. template <class T>
  409. sint32 LinkedList<T>::length(void) {
  410. return(Entries);
  411. }
  412. #endif