Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
dictionary.h
Go to the documentation of this file.
1/*
2** Command & Conquer Generals Zero Hour(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/****************************************************************************\
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******************************************************************************
22Project Name: Carpenter (The RedAlert ladder creator)
23File Name : dictionary.h
24Author : Neal Kettler
25Start Date : June 1, 1997
26Last Update : June 17, 1997
27
28This template file implements a hash dictionary. A hash dictionary is
29used to quickly match a value with a key. This works well for very
30large sets of data. A table is constructed that has some power of two
31number of pointers in it. Any value to be put in the table has a hashing
32function applied to the key. That key/value pair is then put in the
33linked list at the slot the hashing function specifies. If everything
34is working well, this is much faster than a linked list, but only if
35your hashing function is good.
36\****************************************************************************/
37
38
39#ifndef DICTIONARY_HEADER
40#define DICTIONARY_HEADER
41
42
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <assert.h>
47
48#include "wstypes.h"
49
50// Every entry in the hash dictionary must be an instance of the DNode
51// template. 'K' and 'V' denote Key and Value.
52template <class K,class V>
53class DNode
54{
55 public:
56 K key;
57 V value;
58 DNode<K,V> *hashNext;
59};
60
61template <class K,class V>
62class Dictionary
63{
64 public:
66
67
68// Note: I had to put this inside the class definition because VC5 sucks butt
69
70//Create the empty hash dictionary
71Dictionary(uint32 (*hashFn)(const K &key)) :
72 SHRINK_THRESHOLD(0.20), // When table is only 20% full shrink it
73 EXPAND_THRESHOLD(0.80), // When table is 80% full grow it
74 MIN_TABLE_SIZE(128) // must be a power of 2
75{
76 log2Size=MIN_TABLE_SIZE;
77 size=MIN_TABLE_SIZE;
78 assert(size>=4);
79 tableBits=0;
80 while(log2Size) { tableBits++; log2Size>>=1; }
81 tableBits--;
82 size=1<<tableBits; //Just in case MIN_TABLE_SIZE wasn't a power of 2
83 entries=0;
84 keepSize=FALSE;
85
86 //Table is a pointer to a list of pointers (the hash table)
87 table=(DNode<K,V> **)new DNode<K,V>* [size];
88 assert(table!=NULL);
89
90 memset((void *)table,0,size*sizeof(void *));
91 hashFunc=hashFn;
92}
93
94
96
97 void clear(void);
98 bit8 add(IN K &key,IN V &value);
99 bool getValue(IN K &key, OUT V &value) RO;
100 bool getPointer(IN K &key, OUT V **value) RO; // ptr to internal storage (Careful!)
101 void print(FILE *out) RO;
106 bit8 remove(IN K &key,OUT V &value);
107 bit8 remove(IN K &key);
109 bit8 iterate(INOUT int &index,INOUT int &offset, OUT V &value) RO;
110 bit8 iterate(INOUT int &index,INOUT int &offset, OUT K &key, OUT V &value) RO;
112
113 private:
114 void shrink(void); // halve the number of slots
115 void expand(void); // double the number of slots
116
117
118 DNode<K,V> **table; // This stores the lists at each slot
119
120 uint32 entries; // number of entries
121 uint32 size; // size of table
122 uint32 tableBits; // table is 2^tableBits big
123 uint32 log2Size; // Junk variable
124 bit8 keepSize; // If true don't shrink or expand
125
126 uint32 (* hashFunc)(IN K &key); // User provided hash function
127 uint32 keyHash(IN K &key) RO; // This will reduce to correct range
128
129
130 // See initilizer list of constructor for values
131 const double SHRINK_THRESHOLD; // When table is this % full shrink it
132 const double EXPAND_THRESHOLD; // When table is this % full grow it
133 const int MIN_TABLE_SIZE; // must be a power of 2
134};
135
136
137
138//Free all the memory...
139template <class K,class V>
141{
142 clear(); // Remove the entries
143 delete[](table); // And the table as well
144}
145
146// Remove all the entries and free the memory
147template <class K,class V>
149{
150 DNode<K,V> *temp,*del;
151 uint32 i;
152 //free all the data
153 for (i=0; i<size; i++)
154 {
155 temp=table[i];
156 while(temp!=NULL)
157 {
158 del=temp;
159 temp=temp->hashNext;
160 delete(del);
161 }
162 table[i]=NULL;
163 }
164 entries=0;
165
166 while ((getSize()>(uint32)MIN_TABLE_SIZE)&&(keepSize==FALSE))
167 shrink();
168}
169
170template <class K,class V>
171uint32 Dictionary<K,V>::keyHash(IN K &key) RO
172{
173 uint32 retval=hashFunc(key);
174 retval &= ((1<<tableBits)-1);
175 assert(retval<getSize());
176 return(retval);
177}
178
179
180template <class K,class V>
182{
183 DNode<K,V> *temp;
184 uint32 i;
185
186 fprintf(out,"--------------------\n");
187 for (i=0; i<getSize(); i++)
188 {
189 temp=table[i];
190
191 fprintf(out," |\n");
192 fprintf(out,"[ ]");
193
194 while (temp!=NULL)
195 {
196 fprintf(out,"--[ ]");
197 temp=temp->hashNext;
198 }
199 fprintf(out,"\n");
200 }
201 fprintf(out,"--------------------\n");
202}
203
204
205template <class K, class V>
210
211
212
213//
214// Iterate through all the records. Index is for the table, offset specifies the
215// element in the linked list. Set both to 0 and continue calling till false
216// is returned.
217template <class K,class V>
219 OUT V &value) RO
220{
221 DNode<K,V> *temp;
222
223 // index out of range
224 if ((index<0)||(index >= (int)getSize()))
225 return(FALSE);
226
227 temp=table[index];
228 while ((temp==NULL)&&((++index) < (int)getSize()))
229 {
230 temp=table[index];
231 offset=0;
232 }
233
234 if (temp==NULL) // no more slots with data
235 return(FALSE);
236
237 uint32 i=0;
238 while ((temp!=NULL) && ((int)i < offset))
239 {
240 temp=temp->hashNext;
241 i++;
242 }
243
244 if (temp==NULL) // should never happen
245 return(FALSE);
246
247 value=temp->value;
248 if (temp->hashNext==NULL)
249 {
250 index++;
251 offset=0;
252 }
253 else
254 offset++;
255
256 return(TRUE);
257}
258
259
260
261
262//
263// Iterate through all the records. Index is for the table, offset specifies the
264// element in the linked list. Set both to 0 and continue calling till false
265// is returned.
266template <class K,class V>
268 OUT K &key, OUT V &value) RO
269{
270 DNode<K,V> *temp;
271
272 // index out of range
273 if ((index<0)||(index >= (int)getSize()))
274 return(FALSE);
275
276 temp=table[index];
277 while ((temp==NULL)&&((++index) < (int)getSize()))
278 {
279 temp=table[index];
280 offset=0;
281 }
282
283 if (temp==NULL) // no more slots with data
284 return(FALSE);
285
286 uint32 i=0;
287 while ((temp!=NULL) && ((int)i < offset))
288 {
289 temp=temp->hashNext;
290 i++;
291 }
292
293 if (temp==NULL) // should never happen
294 return(FALSE);
295
296 value=temp->value;
297 key=temp->key;
298 if (temp->hashNext==NULL)
299 {
300 index++;
301 offset=0;
302 }
303 else
304 offset++;
305
306 return(TRUE);
307}
308
309
310
311
312// Return the current size of the hash table
313template <class K,class V>
315{ return(size); }
316
317
318// Return the current number of entries in the table
319template <class K,class V>
321{ return(entries); }
322
323
324// Does the Dictionary contain the key?
325template <class K,class V>
327{
328 int offset;
329 DNode<K,V> *node;
330
331 offset=keyHash(key);
332
333 node=table[offset];
334
335 if (node==NULL)
336 { return(FALSE); } // can't find it
337
338 while(node!=NULL)
339 {
340 if ((node->key)==key)
341 { return(TRUE); }
342 node=node->hashNext;
343 }
344 return(FALSE);
345}
346
347
348// Try and update the value of an already existing object
349template <class K,class V>
351{
352 sint32 retval;
353
354 retval=remove(key);
355 if (retval==FALSE)
356 return(FALSE);
357
358 add(key,value);
359 return(TRUE);
360}
361
362
363// Add to the dictionary (if key exists, value is updated with the new V)
364template <class K, class V>
366{
367 int offset;
368 DNode<K,V> *node,*item,*temp;
369 float percent;
370
371 item=(DNode<K,V> *)new DNode<K,V>;
372 assert(item!=NULL);
373
374 #ifdef KEY_MEM_OPS
375 memcpy(&(item->key),&key,sizeof(K));
376 #else
377 item->key=key;
378 #endif
379
380 #ifdef VALUE_MEM_OPS
381 memcpy(&(item->value),&value,sizeof(V));
382 #else
383 item->value=value;
384 #endif
385
386 item->hashNext=NULL;
387
388 //If key already exists, it will be overwritten
389 remove(key); // Hopefully this will be false...
390
391 offset=keyHash(key);
392
393 node=table[offset];
394
395 if (node==NULL)
396 { table[offset]=item; }
397 else
398 {
399 temp=table[offset];
400 table[offset]=item;
401 item->hashNext=temp;
402 }
403
404 entries++;
405 percent=(float)entries;
406 percent/=(float)getSize();
407 if (percent>= EXPAND_THRESHOLD ) expand();
408
409 return(TRUE);
410}
411
412// Remove an item from the dictionary
413template <class K,class V>
415{
416 int offset;
417 DNode<K,V> *node,*last,*temp;
418 float percent;
419
420 if (entries==0)
421 return(FALSE);
422
423 percent=(float)(entries-1);
424 percent/=(float)getSize();
425
426 offset=keyHash(key);
427 node=table[offset];
428
429 last=node;
430 if (node==NULL)
431 return(FALSE);
432
433 //special case table points to thing to delete
434
435 #ifdef KEY_MEM_OPS
436 if (0==memcmp(&(node->key),&key,sizeof(K)))
437 #else
438 if ((node->key)==key)
439 #endif
440 {
441 #ifdef VALUE_MEM_OPS
442 memcpy(&value,&(node->value),sizeof(V));
443 #else
444 value=node->value;
445 #endif
446 temp=table[offset]->hashNext;
447 delete(table[offset]);
448 table[offset]=temp;
449 entries--;
450 if (percent <= SHRINK_THRESHOLD)
451 shrink();
452 return(TRUE);
453 }
454 node=node->hashNext;
455
456 bit8 retval=FALSE; // wow, didn't add this for years... (DOH!)
457
458 //Now the case if the thing to delete is not the first
459 while (node!=NULL)
460 {
461 #ifdef KEY_MEM_OPS
462 if (0==memcmp(&(node->key),&key,sizeof(K)))
463 #else
464 if (node->key==key)
465 #endif
466 {
467 #ifdef VALUE_MEM_OPS
468 memcpy(&value,&(node->value),sizeof(V));
469 #else
470 value=node->value;
471 #endif
472 last->hashNext=node->hashNext;
473 entries--;
474 delete(node);
475 retval=TRUE; // yes, we deleted something
476 break;
477 }
478 last=node;
479 node=node->hashNext;
480 }
481
482 if (percent <= SHRINK_THRESHOLD)
483 shrink();
484 return(retval);
485}
486
487
488template <class K,class V>
490{
491 V temp;
492 return(remove(key,temp));
493}
494
495
496// Remove some random K/V pair that's in the Dictionary
497template <class K,class V>
499{
500 int offset;
501 DNode<K,V> *node,*last,*temp;
502 float percent;
503
504 if (entries==0)
505 return(FALSE);
506
507 percent=(entries-1);
508 percent/=(float)getSize();
509
510 int i;
511 offset=-1;
512 for (i=0; i<(int)getSize(); i++)
513 if (table[i]!=NULL)
514 {
515 offset=i;
516 break;
517 }
518
519 if (offset==-1) // Nothing there
520 return(FALSE);
521
522 node=table[offset];
523 last=node;
524
525 #ifdef KEY_MEM_OPS
526 memcpy(&key,&(node->key),sizeof(K));
527 #else
528 key=node->key;
529 #endif
530 #ifdef VALUE_MEM_OPS
531 memcpy(&value,&(node->value),sizeof(V));
532 #else
533 value=node->value;
534 #endif
535
536 temp=table[offset]->hashNext;
537 delete(table[offset]);
538 table[offset]=temp;
539 entries--;
540 if (percent <= SHRINK_THRESHOLD)
541 shrink();
542 return(TRUE);
543}
544
545
546template <class K,class V>
547bool Dictionary<K,V>::getValue(IN K &key,OUT V &value) RO
548{
549 V *valptr=NULL;
550 bool retval=getPointer(key,&valptr);
551 if (retval && valptr)
552 {
553 #ifdef VALUE_MEM_OPS
554 assert(0);
555 #else
556 value=*valptr;
557 #endif
558 }
559 return(retval);
560}
561
562// Try and avoid this since you're getting a pointer to the internally
563// managed data!
564template <class K,class V>
565bool Dictionary<K,V>::getPointer(IN K &key,OUT V **valptr) RO
566{
567 int offset;
568 DNode<K,V> *node;
569
570 if (entries==0)
571 return(FALSE);
572
573 offset=keyHash(key);
574
575 node=table[offset];
576
577 if (node==NULL)
578 return(FALSE);
579
580 #ifdef KEY_MEM_OPS
581 while ((node!=NULL)&&(memcmp(&(node->key),&key,sizeof(K))))
582 #else
583 while ((node!=NULL)&&( ! ((node->key)==key)) ) // odd syntax so you don't
584 #endif // have to do oper !=
585 { node=node->hashNext; }
586
587 if (node==NULL)
588 { return(FALSE); }
589
590 *valptr=&(node->value);
591
592 return(TRUE);
593}
594
595
596//A note about Shrink and Expand: They are never necessary, they are
597//only here to improve performance of the hash table by reducing
598//the length of the linked list at each table entry.
599
600// Shrink the hash table by a factor of 2 (and relocate entries)
601template <class K,class V>
602void Dictionary<K,V>::shrink(void)
603{
604 int i;
605 int oldsize;
606 uint32 offset;
607 DNode<K,V> **oldtable,*temp,*first,*next;
608
609 if ((size<=(uint32)MIN_TABLE_SIZE)||(keepSize==TRUE))
610 return;
611
612 //fprintf(stderr,"Shrinking....\n");
613
614 oldtable=table;
615 oldsize=size;
616 size/=2;
617 tableBits--;
618
619 table=(DNode<K,V> **)new DNode<K,V>*[size];
620 assert(table!=NULL);
621 memset((void *)table,0,size*sizeof(void *));
622
623 for (i=0; i<oldsize; i++)
624 {
625 temp=oldtable[i];
626 while (temp!=NULL)
627 {
628 offset=keyHash(temp->key);
629 first=table[offset];
630 table[offset]=temp;
631 next=temp->hashNext;
632 temp->hashNext=first;
633 temp=next;
634 }
635 }
636 delete[](oldtable);
637}
638
639
640template <class K,class V>
641void Dictionary<K,V>::expand(void)
642{
643 int i;
644 int oldsize;
645 uint32 offset;
646 DNode<K,V> **oldtable,*temp,*first,*next;
647
648 if (keepSize==TRUE)
649 return;
650
651 //fprintf(stderr,"Expanding...\n");
652
653 oldtable=table;
654 oldsize=size;
655 size*=2;
656 tableBits++;
657
658 table=(DNode<K,V> **)new DNode<K,V>* [size];
659 assert(table!=NULL);
660 memset((void *)table,0,size*sizeof(void *));
661
662 for (i=0; i<oldsize; i++)
663 {
664 temp=oldtable[i];
665 while (temp!=NULL)
666 {
667 offset=keyHash(temp->key);
668 first=table[offset];
669 table[offset]=temp;
670 next=temp->hashNext;
671 temp->hashNext=first;
672 temp=next;
673 }
674 }
675 delete[](oldtable);
676}
677
678
679#endif
680
#define NULL
Definition BaseType.h:92
#define TRUE
Definition BaseType.h:109
#define FALSE
Definition BaseType.h:113
void const char * value
char bit8
Definition wstypes.h:61
#define INOUT
Definition wstypes.h:59
#define IN
Definition wstypes.h:57
#define OUT
Definition wstypes.h:58
unsigned long uint32
Definition bittype.h:46
signed long sint32
Definition bittype.h:51
void add(float *sum, float *addend)
V value
Definition dictionary.h:56
DNode< K, V > * hashNext
Definition dictionary.h:57
bit8 contains(IN K &key) RO
void print(FILE *out) RO
Definition dictionary.h:181
bit8 iterate(INOUT int &index, INOUT int &offset, OUT V &value) const
Definition dictionary.h:201
void print(IN FILE *out) const
Definition dictionary.h:172
bit8 add(IN K &key, IN V &value)
void clear(void)
bit8 removeAny(OUT K &key, OUT V &value)
bit8 iterate(INOUT int &index, INOUT int &offset, OUT K &key, OUT V &value) RO
Definition dictionary.h:267
bit8 getValue(IN K &key, OUT V &value)
Definition dictionary.h:474
bit8 remove(IN K &key)
Dictionary(uint32(*hashFn)(Wstring &key))
Definition dictionary.h:106
bit8 iterate(INOUT int &index, INOUT int &offset, OUT V &value) RO
Definition dictionary.h:218
uint32 getEntries(void) const
Definition dictionary.h:252
uint32 getSize(void) RO
Definition dictionary.h:314
bit8 contains(IN K &key)
Definition dictionary.h:258
bool getPointer(IN K &key, OUT V **value) RO
Definition dictionary.h:565
bool getValue(IN K &key, OUT V &value) RO
Dictionary(uint32(*hashFn)(const K &key))
Definition dictionary.h:71
bit8 remove(IN K &key, OUT V &value)
uint32 getEntries(void) RO
Definition dictionary.h:320
uint32 getSize(void) const
Definition dictionary.h:246
Dictionary< K, V > & operator=(Dictionary< K, V > &other)
Definition dictionary.h:206
bit8 updateValue(IN K &key, IN V &value)
#define RO
Definition wstypes.h:92
int percent
Definition patch.cpp:426