hashlist.h 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  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. /* $Header: /Commando/Code/wwlib/hashlist.h 13 4/30/01 3:05p Joe_b $ */
  19. /***********************************************************************************************
  20. *** 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 ***
  21. ***********************************************************************************************
  22. * *
  23. * Project Name : G *
  24. * *
  25. * $Archive:: /Commando/Code/wwlib/hashlist.h $*
  26. * *
  27. * Creator::Scott K. Bowen - 5/4/99 *
  28. * *
  29. * $Author:: Joe_b $*
  30. * *
  31. * $Modtime:: 4/30/01 2:41p $*
  32. * *
  33. * $Revision:: 13 $*
  34. * *
  35. *---------------------------------------------------------------------------------------------*
  36. * Functions: *
  37. * HashListClass::Find -- Find record in hash table. *
  38. * HashListClass::Remove -- Remove record from hash table. *
  39. * HashListClass::Add -- Add record to hash list. *
  40. * HashListClass::Add -- Add record to list, list creates node for user. *
  41. * HashListClass::Move_To -- Move nodes from one list to another. *
  42. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  43. #if defined(_MSC_VER)
  44. #pragma once
  45. #endif
  46. #ifndef HASHLIST_H
  47. #define HASHLIST_H
  48. #pragma warning (push)
  49. #pragma warning (disable: 4786)
  50. #include "listnode.h"
  51. #include <memory.h>
  52. #ifndef NULL
  53. #define NULL (0L)
  54. #endif
  55. #define A_LARGE_PRIME_NUMBER 257
  56. // HashListClass<> and HashNodeClass<>:
  57. // The purpose of these templates is to allow a user to insert records into
  58. // a hash table that also contains a double linked list that includes every
  59. // record in the hash table. The functionality of the hash list mirrors
  60. // very closely that of the DataNode<> and List<> templates. The differences
  61. // between them are:
  62. // -User calls Add(?) to add to list instead of Add_Head() or others.
  63. // -A key must be set to hash off of.
  64. //
  65. // Additional features of the HashList<> over List<> are:
  66. // -Quick searching as long as key's are well hashed..
  67. // -Node can inherit user class so additional data can be put in node.
  68. // For example a timestamp to be set by user. Default is
  69. // HashDefaluatUserClass that has no data.
  70. // -If class T is actually a class (not a pointer), user may get a ptr
  71. // to class with Get_Ptr() instead of Get() that returns an INSTANCE
  72. // of the class.
  73. // -Flags to tell user if record was just created or record was just put
  74. // into a list (user must clear flags if desired.)
  75. // -HashListClass<> can create and destroy nodes so that the nodes do not
  76. // need to be put as members in classes. This allows an object to be
  77. // put into an infinite (subject to memory constraints) lists.
  78. // -User may specify number of hash node slots (default is A_LARGE_PRIME_NUMBER).
  79. // You can typedef these templates with the the following:
  80. // typedef HashListClass<TestHashClass *> HashTableClass;
  81. // typedef HashNodeClass<TestHashClass *> HashTableNodeClass;
  82. // or if using a UserClass
  83. // typedef HashListClass<TestHashClass *, 4, UserClass> HashTableClass;
  84. // typedef HashNodeClass<TestHashClass *, UserClass> HashTableNodeClass;
  85. template<class T, class U> class HashNodeClass;
  86. template<class T, class U> class HashNodeFriendClass;
  87. template<class T, class U, int NumHashValues> class HashListClass;
  88. ////////////////////////////////////////////////////////////////////////////////////////////////
  89. ////////////////////////////////////////////////////////////////////////////////////////////////
  90. ////////////////////////////////////////////////////////////////////////////////////////////////
  91. // This is a default class that is stored in HashNodeClass. It's purpose is
  92. // to allow the user to override it with his/her own class so that additional
  93. // data may be stored in the node about the object.
  94. // Since the object might be in various lists, this data is specific to
  95. // the list that it in.
  96. class HashDefaultUserClass {};
  97. ////////////////////////////////////////////////////////////////////////////////////////////////
  98. ////////////////////////////////////////////////////////////////////////////////////////////////
  99. ////////////////////////////////////////////////////////////////////////////////////////////////
  100. template<class T, class U = class HashDefaultUserClass>
  101. class HashNodeClass : public DataNode<HashNodeClass<T,U> *>, public U
  102. {
  103. public:
  104. // Creation when key and record are known.
  105. HashNodeClass(T record, unsigned key) :
  106. Flags(0),
  107. Record(record),
  108. Key(key)
  109. {
  110. DataNode<HashNodeClass<T,U> *>::Set(this);
  111. Flag.NewRecord = true;
  112. Flag.KeySet = true;
  113. }
  114. // Creation when key and record are to be set later.
  115. // node may not be put into list until the key is set.
  116. HashNodeClass() :
  117. Flags(0),
  118. Key(-1)
  119. {
  120. DataNode<HashNodeClass<T,U> *>::Set(this);
  121. Flag.NewRecord = true;
  122. }
  123. virtual ~HashNodeClass() {
  124. // Assert is raised when user tries to delete HashNodeClass still in a list
  125. // NOTE: This might be raised because user expected node to clean
  126. // itself up when deleted. Currently, this feature is not available
  127. // because it would require an additional pointer to the HashListClass
  128. // that the node is a member of.
  129. assert(!Flag.InList);
  130. }
  131. // Get next and prev record given a node.
  132. // A node may be retrieved from: HashListClass::Find();
  133. HashNodeClass<T,U> *Next() {
  134. return((HashNodeClass<T,U> *) DataNode<HashNodeClass<T,U> *>::Next());
  135. }
  136. HashNodeClass<T,U> *Prev() {
  137. return((HashNodeClass<T,U> *) DataNode<HashNodeClass<T,U> *>::Prev());
  138. }
  139. // User may use these if he desires not to have to check for valid.
  140. HashNodeClass<T,U> *Next_Valid() {
  141. HashNodeClass<T,U> *next = Next();
  142. if (next && next->Is_Valid()) {
  143. return(next);
  144. }
  145. return(NULL);
  146. }
  147. HashNodeClass<T,U> *Prev_Valid() {
  148. HashNodeClass<T,U> *prev = Prev();
  149. if (prev && prev->Is_Valid()) {
  150. return(prev);
  151. }
  152. return(NULL);
  153. }
  154. // Get record that is in hash table.
  155. T Get_Record() {return(Record);}
  156. T Get_Record_Ptr() {return(&Record);}
  157. // Overload DataNode::Get() to get the record we are pointing to so
  158. // that it behaves how people expect List to operate.
  159. // To Get HashNodeClass - it is this.
  160. T Get() {return(Record);}
  161. // Get a pointer to Record to avoid a copy construction of Record if
  162. // it is an instance of a class that does not want to be copied all
  163. // over the place.
  164. T *Get_Ptr() {return(&Record);}
  165. // To mirror usage of DataNode().
  166. void Set(T record) {Record = record;}
  167. void Set_Key(unsigned key) {
  168. // Can't change key once in a list, we would never find it.
  169. assert(!Flag.InList);
  170. Flag.KeySet = true;
  171. Key = key;
  172. }
  173. // Get key of record for has table.
  174. unsigned Get_Key() {
  175. assert(Flag.KeySet);
  176. return (Key);
  177. }
  178. // Enable user to know if a record has just been added to the list.
  179. // It stays set until user clears it - not required.
  180. int Is_New_Record() {return(Flag.NewRecord);}
  181. void Clear_New_Record() {Flag.NewRecord = false;}
  182. // Each time object gets put into a list NewInList is set.
  183. // Stays set until user clears - not required.
  184. int Is_New_In_List() {return(Flag.NewInList);}
  185. void Clear_New_In_List() {Flag.NewInList = false;}
  186. bool Is_In_List() {return(Flag.InList);}
  187. bool Is_Key_Set() {return(Flag.KeySet);}
  188. protected:
  189. // Record that we are keeping in hash table.
  190. // This is commonly a pointer to the actual record.
  191. T Record;
  192. // Key that user gives to identify record.
  193. // WARNING: Duplicate keys are undefined behavior.
  194. unsigned Key;
  195. // Unioned flags so Flags can be initialized to 0.
  196. union {
  197. struct {
  198. // When record collides in hash list, these ?InTable
  199. // tell when to stop looking for object in hash entry.
  200. unsigned FirstInTable:1;
  201. unsigned LastInTable:1;
  202. // This is set when record is first created. It is up to user
  203. // to clear if he uses flag.
  204. unsigned NewRecord:1;
  205. // This is set when record is first put in list. It is up to user
  206. // to clear if he uses flag.
  207. unsigned NewInList:1;
  208. // Certain functions may not happen if node is InList (in hash table)
  209. // These include delete, Set_Key(), and possibly others.
  210. unsigned InList:1;
  211. // This is set so HashListClass knows if it should delete the
  212. // node when removed from it's list.
  213. unsigned ListCreated:1;
  214. // Make sure someone does not insert a node into a list
  215. // without setting it's key.
  216. unsigned KeySet:1;
  217. } Flag;
  218. unsigned Flags;
  219. };
  220. private:
  221. // Not something the casual user can call.
  222. void Unlink(void) {
  223. DataNode<HashNodeClass<T,U> *>::Unlink();
  224. }
  225. friend class HashNodeFriendClass<T,U>;
  226. };
  227. ////////////////////////////////////////////////////////////////////////////////////////////////
  228. ////////////////////////////////////////////////////////////////////////////////////////////////
  229. ////////////////////////////////////////////////////////////////////////////////////////////////
  230. // This class is created so that HashListClass can access HashNodeClass.
  231. // HashListClass cannot access directly because it is impossible
  232. // (I could not figure out how) to tell HashNodeClass to be a friend
  233. // to all creations of HashListClass<T,N> since HashNodeClass
  234. // does not need the NumHashValues parameter.
  235. #pragma warning(push)
  236. #pragma warning(disable : 4786) // identifier was truncated to 255 chars in debug information.
  237. template<class T, class U>
  238. class HashNodeFriendClass
  239. {
  240. protected:
  241. void Set_In_List(HashNodeClass<T,U> *ptr) {ptr->Flag.InList = true; ptr->Flag.NewInList = true;}
  242. void Clear_In_List(HashNodeClass<T,U> *ptr) {ptr->Flag.InList = false; ptr->Flag.NewInList = false;}
  243. bool Is_First(HashNodeClass<T,U> *ptr) {return(ptr->Flag.FirstInTable);}
  244. bool Is_Last(HashNodeClass<T,U> *ptr) {return(ptr->Flag.LastInTable); }
  245. void Set_First(HashNodeClass<T,U> *ptr) {ptr->Flag.FirstInTable = true; }
  246. void Set_Last(HashNodeClass<T,U> *ptr) {ptr->Flag.LastInTable = true; }
  247. void Clear_First(HashNodeClass<T,U> *ptr) {ptr->Flag.FirstInTable = false;}
  248. void Clear_Last(HashNodeClass<T,U> *ptr) {ptr->Flag.LastInTable = false; }
  249. void Set_List_Created(HashNodeClass<T,U> *ptr) {ptr->Flag.ListCreated = true; }
  250. void Clear_List_Created(HashNodeClass<T,U> *ptr) {ptr->Flag.ListCreated = false; }
  251. bool Is_List_Created(HashNodeClass<T,U> *ptr) {return(ptr->Flag.ListCreated);}
  252. void Unlink(HashNodeClass<T,U> *ptr) {ptr->Unlink();}
  253. };
  254. #pragma warning(pop)
  255. // The sole purpose of using NumHashValues as a template is to make it easier to
  256. // view in a debugger. If it were an allocated array of pointers, the debugger does
  257. // not easily show each element in the array.
  258. template<class T, class U = class HashDefaultUserClass, int NumHashValues = A_LARGE_PRIME_NUMBER>
  259. class HashListClass : protected HashNodeFriendClass<T,U>
  260. {
  261. public:
  262. // Creation and destruction.
  263. HashListClass() :
  264. List(),NumRecords(0), UsedValues(0)
  265. {
  266. memset(HashTable, 0, sizeof(HashTable));
  267. }
  268. ~HashListClass() {Delete();}
  269. // Get first node in list so user can itterate through it.
  270. // CAUTION: Do not destroy pointer returned or itterated though -
  271. // you must call the Remove function on it.
  272. // An assert() will come up if you try.
  273. HashNodeClass<T,U> *First() {
  274. return((HashNodeClass<T,U> *)List.First());
  275. }
  276. HashNodeClass<T,U> *First_Valid() {
  277. return((HashNodeClass<T,U> *)List.First_Valid());
  278. }
  279. HashNodeClass<T,U> *Last() {
  280. return((HashNodeClass<T,U> *)List.Last());
  281. }
  282. HashNodeClass<T,U> *Last_Valid() {
  283. return((HashNodeClass<T,U> *)List.Last_Valid());
  284. }
  285. // Add a record to hash creating new HashNodeClass.
  286. HashNodeClass<T,U> *Add(T record, unsigned key);
  287. // Add an existing node not in a list to this list.
  288. // This allows closer behavior to List class.
  289. HashNodeClass<T,U> *Add(HashNodeClass<T,U> *node);
  290. // Search for record based off key in hash table.
  291. HashNodeClass<T,U> *Find(unsigned key);
  292. // Use this remove if you know the node * already. It is quicker.
  293. void Remove(HashNodeClass<T,U> *node);
  294. // Use this remove if you need to do a find to get the node.
  295. // OK if key does not exist in table.
  296. bool Remove(unsigned key);
  297. // Removes all nodes in list.
  298. void Delete(void) {while (First()->Is_Valid()) Remove(First());}
  299. // Move contents of one list to another (this becomes empty).
  300. void Move_To(HashListClass<T,U> *newlist);
  301. // So we always do it the same way.
  302. unsigned Hash_Value(unsigned key) {
  303. return(unsigned)(key % NumHashValues);
  304. }
  305. // Total number of records in hash table.
  306. int Num_Records() {
  307. return(NumRecords);
  308. }
  309. // how many hash values are used.
  310. // The closer this number is to NumRecords, the
  311. // better hashing going on.
  312. int Num_Used_Values() {
  313. return(UsedValues);
  314. }
  315. protected:
  316. // This list can be walked from start to end of all objects in the list.
  317. // User can use Get_First() to get first (valid) record in linked list.
  318. List<DataNode<T> *> List;
  319. // Points to first record in List that has the right 'value'.
  320. // Must check LaastInTable to see if end of records in has list.
  321. HashNodeClass<T,U> *HashTable[NumHashValues];
  322. // Number of records we have in class.
  323. int NumRecords;
  324. int UsedValues;
  325. };
  326. ////////////////////////////////////////////////////////////////////////////////////////////////
  327. ////////////////////////////////////////////////////////////////////////////////////////////////
  328. ////////////////////////////////////////////////////////////////////////////////////////////////
  329. /***********************************************************************************************
  330. * HashListClass::Add -- Add record to hash list. *
  331. * *
  332. * INPUT: *
  333. * *
  334. * OUTPUT: *
  335. * *
  336. * WARNINGS: *
  337. * *
  338. * HISTORY: *
  339. * 05/26/1999 SKB : Created. *
  340. *=============================================================================================*/
  341. template <class T, class U, int NumHashValues>
  342. HashNodeClass<T,U> *HashListClass<T, U, NumHashValues>::Add(HashNodeClass<T,U> *node)
  343. {
  344. // Get our index into the hash table.
  345. int hashidx = Hash_Value(node->Get_Key());
  346. assert(hashidx < NumHashValues);
  347. // Tell system we are being put in the list (and make sure we weren't already in one).
  348. assert(!node->Is_In_List());
  349. Set_In_List(node);
  350. // Get first hit in table.
  351. HashNodeClass<T,U> *first = HashTable[hashidx];
  352. if (first) {
  353. // This will add the new node right after the first node in the list.
  354. first->Link(node);
  355. // If we are the first one to collide, then we will be at end of list.
  356. // otherwise, we are at the end.
  357. if (Is_Last(first)) {
  358. Clear_Last(first);
  359. Set_Last(node);
  360. }
  361. } else {
  362. // We are first hit at hash index. Put ourselves at start of
  363. List.Add_Head(node);
  364. Set_First(node);
  365. Set_Last(node);
  366. HashTable[hashidx] = node;
  367. UsedValues++;
  368. }
  369. NumRecords++;
  370. return (node);
  371. }
  372. /***********************************************************************************************
  373. * HashListClass::Add -- Add record to list, list creates node for user. *
  374. * *
  375. * INPUT: *
  376. * *
  377. * OUTPUT: *
  378. * *
  379. * WARNINGS: *
  380. * *
  381. * HISTORY: *
  382. * 06/03/1999 SKB : Created. *
  383. *=============================================================================================*/
  384. template <class T, class U, int NumHashValues>
  385. HashNodeClass<T,U> *HashListClass<T, U, NumHashValues>::Add(T record, unsigned key)
  386. {
  387. // Create new node so we can add our record.
  388. HashNodeClass<T,U> *node = new HashNodeClass<T,U>(record, key);
  389. Set_List_Created(node);
  390. // Now let the other add do all the work.
  391. Add(node);
  392. return (node);
  393. }
  394. /***********************************************************************************************
  395. * HashListClass::Find -- Find record in hash table. *
  396. * *
  397. * INPUT: *
  398. * *
  399. * OUTPUT: *
  400. * *
  401. * WARNINGS: *
  402. * *
  403. * HISTORY: *
  404. * 05/26/1999 SKB : Created. *
  405. *=============================================================================================*/
  406. template <class T, class U, int NumHashValues>
  407. HashNodeClass<T,U> *HashListClass<T, U, NumHashValues>::Find(unsigned key)
  408. {
  409. int hashidx = Hash_Value(key);
  410. assert(hashidx < NumHashValues);
  411. HashNodeClass<T,U> *cur = HashTable[hashidx];
  412. if (cur) for(;;) {
  413. // Have we found our match?
  414. if (cur->Get_Key() == key) {
  415. return(cur);
  416. }
  417. // We have to find record before the end of the list.
  418. if (Is_Last(cur)) {
  419. break;
  420. }
  421. // Continue on because we appear to have some collisions.
  422. cur = cur->Next();
  423. // The end of a list should always be marked with Is_Last().
  424. assert(cur);
  425. assert(cur->Is_Valid());
  426. }
  427. return(NULL);
  428. }
  429. /***********************************************************************************************
  430. * HashListClass::Remove_Node -- Remove node from hash table. *
  431. * Protected function for usage by Remove() routines. *
  432. * *
  433. * INPUT: *
  434. * HashNodeClass<T,U> *node - node to remove. *
  435. * *
  436. * OUTPUT: *
  437. * *
  438. * WARNINGS: *
  439. * *
  440. * HISTORY: *
  441. * 06/02/1999 SKB : Created. *
  442. * 01/19/2000 SKB : Remove the node with Unlink. *
  443. *=============================================================================================*/
  444. template <class T, class U, int NumHashValues>
  445. void HashListClass<T, U, NumHashValues>::Remove(HashNodeClass<T,U> *node)
  446. {
  447. assert(node);
  448. assert(node->Is_In_List());
  449. // See if entry is first in list for hash value.
  450. if (Is_First(node)) {
  451. int hashidx = Hash_Value(node->Get_Key());
  452. assert(HashTable[hashidx]);
  453. // SKB: 2/20/01 - clear incase inserted in new list later.
  454. Clear_First(node);
  455. // is it only one in hash index?
  456. if (Is_Last(node)) {
  457. // SKB: 2/20/01 - clear incase inserted in new list later.
  458. Clear_Last(node);
  459. HashTable[hashidx] = NULL;
  460. UsedValues--;
  461. } else {
  462. HashTable[hashidx] = node->Next_Valid();
  463. Set_First(HashTable[hashidx]);
  464. }
  465. } else if (Is_Last(node)) {
  466. // SKB: 2/20/01 - clear incase inserted in new list later.
  467. Clear_Last(node);
  468. // There is one before us because it failed above.
  469. Set_Last(node->Prev());
  470. }
  471. // All done with you. Set flag to avoid assert.
  472. Clear_In_List(node);
  473. // Delete node if it was created by the this class instead of by the user.
  474. if (Is_List_Created(node)) {
  475. delete node;
  476. } else {
  477. // Remove it from the link list at least so it can be put in another.
  478. Unlink(node);
  479. }
  480. NumRecords--;
  481. }
  482. /***********************************************************************************************
  483. * HashListClass::Remove -- Remove record from hash table. *
  484. * *
  485. * INPUT: *
  486. * unsigned key - key to find node by. *
  487. * *
  488. * OUTPUT: *
  489. * *
  490. * WARNINGS: *
  491. * *
  492. * HISTORY: *
  493. * 05/26/1999 SKB : Created. *
  494. *=============================================================================================*/
  495. template <class T, class U, int NumHashValues>
  496. bool HashListClass<T, U, NumHashValues>::Remove(unsigned key)
  497. {
  498. int hashidx = Hash_Value(key);
  499. assert(hashidx < NumHashValues);
  500. HashNodeClass<T,U> *node = Find(key);
  501. if (node) {
  502. Remove(node);
  503. return(true);
  504. }
  505. return(false);
  506. }
  507. /***********************************************************************************************
  508. * HashListClass::Move_To -- Move nodes from one list to another. *
  509. * *
  510. * INPUT: *
  511. * *
  512. * OUTPUT: *
  513. * *
  514. * WARNINGS: *
  515. * *
  516. * HISTORY: *
  517. * 06/04/1999 SKB : Created. *
  518. *=============================================================================================*/
  519. template <class T, class U, int NumHashValues>
  520. void HashListClass<T, U, NumHashValues>::Move_To(HashListClass<T,U> *newlist)
  521. {
  522. HashNodeClass<T,U> *node = First_Valid();
  523. while (node) {
  524. HashNodeClass<T,U> *next = node->Next_Valid();
  525. // If list created node, clear that fact for a moment so it
  526. // will not get deleted in the remove.
  527. if (Is_List_Created(node)) {
  528. Clear_List_Created(node);
  529. Remove(node);
  530. newlist->Add(node);
  531. Set_List_Created(node);
  532. } else {
  533. Remove(node);
  534. newlist->Add(node);
  535. }
  536. node = next;
  537. }
  538. }
  539. #pragma warning (pop)
  540. #endif // HASHLIST_H