OpenMoHAA 0.82.0
Loading...
Searching...
No Matches
con_set.h
1/*
2===========================================================================
3Copyright (C) 2015 the OpenMoHAA team
4
5This file is part of OpenMoHAA source code.
6
7OpenMoHAA source code is free software; you can redistribute it
8and/or modify it under the terms of the GNU General Public License as
9published by the Free Software Foundation; either version 2 of the License,
10or (at your option) any later version.
11
12OpenMoHAA source code is distributed in the hope that it will be
13useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with OpenMoHAA source code; if not, write to the Free Software
19Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20===========================================================================
21*/
22
23// con_set.h: C++ map/set classes. Contains an hash table to improve the speed of finding a key
24
25#pragma once
26
27#include "mem_blockalloc.h"
28
29#if defined(GAME_DLL)
30# include "../fgame/g_local.h"
31
32# define SET_Alloc gi.Malloc
33# define SET_Free gi.Free
34
35#elif defined(CGAME_DLL)
36# include "../cgame/cg_local.h"
37
38# define SET_Alloc cgi.Malloc
39# define SET_Free cgi.Free
40
41#elif defined(REF_DLL)
42# include "../renderercommon/tr_common.h"
43
44# define SET_Alloc ri.Malloc
45# define SET_Free ri.Free
46
47#else
48# include "qcommon.h"
49
50# define SET_Alloc Z_Malloc
51# define SET_Free Z_Free
52#endif
53
54class Class;
55class Archiver;
56
57template<typename k, typename v>
58class con_set;
59
60template<typename key, typename value>
61class con_map;
62
63template<typename key, typename value>
64class con_map_enum;
65
66template<typename key, typename value>
67class con_set_enum;
68
69template<typename T>
71 static const bool con_value = false;
72};
73
74template<typename T>
75struct con_set_is_pointer<T *> {
76 static const bool con_value = true;
77};
78
85template<typename k, typename v>
86class con_set_Entry
87{
88 friend con_set<k, v>;
89 friend con_set_enum<k, v>;
90
91private:
92 con_set_Entry *next;
93 k key;
94
95public:
96 v value;
97
98public:
99 void *operator new(size_t size) { return con_set<k, v>::NewEntry(size); }
100
101 void operator delete(void *ptr) { con_set<k, v>::DeleteEntry(ptr); }
102
103 con_set_Entry()
104 : key(k())
105 , value(v())
106 , next(NULL)
107 {}
108
109#ifdef ARCHIVE_SUPPORTED
110 void Archive(Archiver& arc);
111#endif
112 k& GetKey() { return key; }
113
114 void SetKey(const k& newKey) { key = newKey; }
115};
116
117template<typename k, typename v>
118class con_set
119{
120 friend class con_set_enum<k, v>;
121
122public:
123 using Entry = con_set_Entry<k, v>;
124
125public:
126 static MEM_BlockAlloc<Entry> Entry_allocator;
127
128protected:
129 Entry **table; // hashtable
130 unsigned int tableLength;
131 unsigned int threshold;
132 unsigned int count; // num of entries
133 short unsigned int tableLengthIndex;
134 Entry *defaultEntry;
135
136protected:
137 Entry *findKeyEntry(const k& key) const;
138 Entry *addKeyEntry(const k& key);
139 Entry *addNewKeyEntry(const k& key);
140
141public:
142 static void *NewEntry(size_t size);
143 static void DeleteEntry(void *entry);
144 static void *NewTable(size_t count);
145 static void DeleteTable(void *table);
146
147public:
148 con_set();
149 ~con_set();
150
151#ifdef ARCHIVE_SUPPORTED
152 void Archive(Archiver& arc);
153#endif
154
155 void clear();
156 void resize(int count = 0);
157
158 v *findKeyValue(const k& key) const;
159 k *firstKeyValue();
160
161 v& addKeyValue(const k& key);
162 v& addNewKeyValue(const k& key);
163
164 bool keyExists(const k& key);
165 bool isEmpty();
166 bool remove(const k& key);
167
168 unsigned int size();
169};
170
171template<typename k, typename v>
172MEM_BlockAlloc<typename con_set<k, v>::Entry> con_set<k, v>::Entry_allocator;
173
174template<typename k, typename v>
175void *con_set<k, v>::NewEntry(size_t size)
176{
177 return Entry_allocator.Alloc();
178}
179
180template<typename k, typename v>
181void con_set<k, v>::DeleteEntry(void *entry)
182{
183 Entry_allocator.Free(entry);
184}
185
186template<typename k, typename v>
187void *con_set<k, v>::NewTable(size_t count)
188{
189 return SET_Alloc(sizeof(Entry *) * (int)count);
190}
191
192template<typename k, typename v>
193void con_set<k, v>::DeleteTable(void *table)
194{
195 SET_Free(table);
196}
197
198template<typename k>
199int HashCode(const k& key);
200
201template<typename key, typename value>
202con_set<key, value>::con_set()
203{
204 tableLength = 1;
205 table = &defaultEntry;
206
207 threshold = 1;
208 count = 0;
209 tableLengthIndex = 0;
210
211 defaultEntry = NULL;
212}
213
214template<typename key, typename value>
215con_set<key, value>::~con_set()
216{
217 clear();
218}
219
220template<typename key, typename value>
221void con_set<key, value>::clear()
222{
223 Entry *entry = NULL;
224 Entry *next = NULL;
225 unsigned int i;
226
227 for (i = 0; i < tableLength; i++) {
228 for (entry = table[i]; entry != NULL; entry = next) {
229 next = entry->next;
230 delete entry;
231 }
232 }
233
234 if (tableLength > 1) {
235 DeleteTable(table);
236 }
237
238 tableLength = 1;
239 table = &defaultEntry;
240
241 threshold = 1;
242 count = 0;
243 tableLengthIndex = 0;
244
245 defaultEntry = NULL;
246}
247
248template<typename key, typename value>
249void con_set<key, value>::resize(int count)
250{
251 Entry **oldTable = table;
252 Entry *e, *old;
253 unsigned int oldTableLength = tableLength;
254 unsigned int i;
255 unsigned int index;
256
257 if (count > 0) {
258 tableLength += count;
259 threshold = tableLength;
260 } else {
261 //threshold = ( unsigned int )( ( float )tableLength * 0.75f );
262 threshold = (unsigned int)((float)tableLength * 0.75);
263 if (threshold < 1) {
264 threshold = 1;
265 }
266
267 tableLength += threshold;
268 }
269
270 // allocate a new table
271 table = new (NewTable(tableLength)) Entry *[tableLength]();
272
273 // rehash the table
274 for (i = oldTableLength; i > 0; i--) {
275 // rehash all entries from the old table
276 for (e = oldTable[i - 1]; e != NULL; e = old) {
277 old = e->next;
278
279 // insert the old entry to the table hashindex
280 index = HashCode<key>(e->GetKey()) % tableLength;
281
282 e->next = table[index];
283 table[index] = e;
284 }
285 }
286
287 if (oldTableLength > 1) {
288 // delete the previous table
289 DeleteTable(oldTable);
290 }
291}
292
293template<typename k, typename v>
294typename con_set<k, v>::Entry *con_set<k, v>::findKeyEntry(const k& key) const
295{
296 Entry *entry;
297
298 entry = table[HashCode<k>(key) % tableLength];
299
300 for (; entry != NULL; entry = entry->next) {
301 if (entry->GetKey() == key) {
302 return entry;
303 }
304 }
305
306 return NULL;
307}
308
309template<typename k, typename v>
310typename con_set<k, v>::Entry *con_set<k, v>::addKeyEntry(const k& key)
311{
312 Entry *entry;
313
314 entry = findKeyEntry(key);
315
316 if (entry != NULL) {
317 return entry;
318 } else {
319 return addNewKeyEntry(key);
320 }
321}
322
323template<typename k, typename v>
324typename con_set<k, v>::Entry *con_set<k, v>::addNewKeyEntry(const k& key)
325{
326 Entry *entry;
327 int hash;
328
329 if (count >= threshold) {
330 resize();
331 }
332
333 count++;
334
335 entry = new Entry;
336 entry->SetKey(key);
337 hash = HashCode<k>(entry->GetKey()) % tableLength;
338
339 if (defaultEntry == NULL) {
340 defaultEntry = entry;
341 entry->next = NULL;
342 } else {
343 entry->next = table[hash];
344 }
345 table[hash] = entry;
346
347 return entry;
348}
349
350template<typename key, typename value>
351bool con_set<key, value>::isEmpty(void)
352{
353 return count == 0;
354}
355
356template<typename k, typename v>
357bool con_set<k, v>::remove(const k& key)
358{
359 int hash;
360 int i;
361 Entry *prev = NULL;
362 Entry *entry, *e;
363
364 hash = HashCode<k>(key) % tableLength;
365
366 for (entry = table[hash]; entry != NULL; entry = entry->next) {
367 // just to make sure we're using the correct overloaded operator for the key
368 if (!(entry->GetKey() == key)) {
369 prev = entry;
370 continue;
371 }
372
373 if (defaultEntry == entry) {
374 defaultEntry = prev ? prev : table[hash];
375 // find a default entry
376 for (i = 0; i < tableLength && !defaultEntry; i++) {
377 for (e = table[i]; e; e = e->next) {
378 if (e == entry) {
379 continue;
380 }
381 defaultEntry = e;
382 break;
383 }
384 }
385 }
386
387 if (prev) {
388 prev->next = entry->next;
389 } else {
390 table[hash] = entry->next;
391 }
392
393 count--;
394 delete entry;
395
396 return true;
397 }
398
399 return false;
400}
401
402template<typename k, typename v>
403v *con_set<k, v>::findKeyValue(const k& key) const
404{
405 Entry *entry = findKeyEntry(key);
406
407 if (entry != NULL) {
408 return &entry->value;
409 } else {
410 return NULL;
411 }
412}
413
414template<typename key, typename value>
415key *con_set<key, value>::firstKeyValue(void)
416{
417 if (defaultEntry) {
418 return &defaultEntry->GetKey();
419 } else {
420 return NULL;
421 }
422}
423
424template<typename k, typename v>
425v& con_set<k, v>::addKeyValue(const k& key)
426{
427 Entry *entry = addKeyEntry(key);
428
429 return entry->value;
430}
431
432template<typename k, typename v>
433v& con_set<k, v>::addNewKeyValue(const k& key)
434{
435 Entry *entry = addNewKeyEntry(key);
436
437 return entry->value;
438}
439
440template<typename k, typename v>
441bool con_set<k, v>::keyExists(const k& key)
442{
443 Entry *entry;
444
445 for (entry = table; entry != NULL; entry = entry->next) {
446 if (entry->GetKey() == key) {
447 return true;
448 }
449 }
450
451 return false;
452}
453
454template<typename key, typename value>
455unsigned int con_set<key, value>::size()
456{
457 return count;
458}
459
460template<typename key, typename value>
461class con_set_enum
462{
463 friend class con_map_enum<key, value>;
464
465public:
466 using Entry = typename con_set<key, value>::Entry;
467
468protected:
469 con_set<key, value> *m_Set;
470 unsigned int m_Index;
471 Entry *m_CurrentEntry;
472 Entry *m_NextEntry;
473
474public:
475 con_set_enum();
476 con_set_enum(con_set<key, value>& set);
477
478 bool operator=(con_set<key, value>& set);
479
480 Entry *NextElement(void);
481 Entry *CurrentElement(void);
482};
483
484template<typename key, typename value>
485con_set_enum<key, value>::con_set_enum()
486{
487 m_Set = NULL;
488 m_Index = 0;
489 m_CurrentEntry = NULL;
490 m_NextEntry = NULL;
491}
492
493template<typename key, typename value>
494con_set_enum<key, value>::con_set_enum(con_set<key, value>& set)
495{
496 *this = set;
497}
498
499template<typename key, typename value>
500bool con_set_enum<key, value>::operator=(con_set<key, value>& set)
501{
502 m_Set = &set;
503 m_Index = m_Set->tableLength;
504 m_CurrentEntry = NULL;
505 m_NextEntry = NULL;
506
507 return true;
508}
509
510template<typename key, typename value>
511typename con_set_enum<key, value>::Entry *con_set_enum<key, value>::CurrentElement(void)
512{
513 return m_CurrentEntry;
514}
515
516template<typename key, typename value>
517typename con_set_enum<key, value>::Entry *con_set_enum<key, value>::NextElement(void)
518{
519 if (!m_NextEntry) {
520 while (1) {
521 if (!m_Index) {
522 break;
523 }
524
525 m_Index--;
526 m_NextEntry = m_Set->table[m_Index];
527
528 if (m_NextEntry) {
529 break;
530 }
531 }
532
533 if (!m_NextEntry) {
534 m_CurrentEntry = NULL;
535 return NULL;
536 }
537 }
538
539 m_CurrentEntry = m_NextEntry;
540 m_NextEntry = m_NextEntry->next;
541
542 return m_CurrentEntry;
543}
544
545template<typename key, typename value>
547{
548 friend class con_map_enum<key, value>;
549
550private:
551 con_set<key, value> m_con_set;
552
553public:
554#ifdef ARCHIVE_SUPPORTED
555 void Archive(Archiver& arc);
556#endif
557
558 void clear();
559 virtual void resize(int count = 0);
560
561 value& operator[](const key& index);
562
563 value *find(const key& index);
564 bool remove(const key& index);
565
566 unsigned int size();
567};
568
569template<typename key, typename value>
570void con_map<key, value>::clear()
571{
572 m_con_set.clear();
573}
574
575template<typename key, typename value>
576void con_map<key, value>::resize(int count)
577{
578 m_con_set.resize(count);
579}
580
581template<typename key, typename value>
582value& con_map<key, value>::operator[](const key& index)
583{
584 return m_con_set.addKeyValue(index);
585}
586
587template<typename key, typename value>
588value *con_map<key, value>::find(const key& index)
589{
590 return m_con_set.findKeyValue(index);
591}
592
593template<typename key, typename value>
594bool con_map<key, value>::remove(const key& index)
595{
596 return m_con_set.remove(index);
597}
598
599template<typename key, typename value>
600unsigned int con_map<key, value>::size(void)
601{
602 return m_con_set.size();
603}
604
605template<typename key, typename value>
606class con_map_enum
607{
608public:
609 using Entry = typename con_set_enum<key, value>::Entry;
610
611private:
612 con_set_enum<key, value> m_Set_Enum;
613
614public:
615 con_map_enum();
616 con_map_enum(con_map<key, value>& map);
617
618 bool operator=(con_map<key, value>& map);
619
620 key *NextKey(void);
621 value *NextValue(void);
622 key *CurrentKey(void);
623 value *CurrentValue(void);
624};
625
626template<typename key, typename value>
627con_map_enum<key, value>::con_map_enum()
628{
629 m_Set_Enum.m_Set = NULL;
630 m_Set_Enum.m_Index = 0;
631 m_Set_Enum.m_CurrentEntry = NULL;
632 m_Set_Enum.m_NextEntry = NULL;
633}
634
635template<typename key, typename value>
636con_map_enum<key, value>::con_map_enum(con_map<key, value>& map)
637{
638 *this = map;
639}
640
641template<typename key, typename value>
642bool con_map_enum<key, value>::operator=(con_map<key, value>& map)
643{
644 m_Set_Enum = map.m_con_set;
645
646 return true;
647}
648
649template<typename key, typename value>
650key *con_map_enum<key, value>::CurrentKey(void)
651{
652 Entry *entry = m_Set_Enum.CurrentElement();
653
654 if (entry) {
655 return &entry->GetKey();
656 } else {
657 return NULL;
658 }
659}
660
661template<typename key, typename value>
662value *con_map_enum<key, value>::CurrentValue(void)
663{
664 Entry *entry = m_Set_Enum.CurrentElement();
665
666 if (entry) {
667 return &entry->value;
668 } else {
669 return NULL;
670 }
671}
672
673template<typename key, typename value>
674key *con_map_enum<key, value>::NextKey(void)
675{
676 Entry *entry = m_Set_Enum.NextElement();
677
678 if (entry) {
679 return &entry->GetKey();
680 } else {
681 return NULL;
682 }
683}
684
685template<typename key, typename value>
686value *con_map_enum<key, value>::NextValue(void)
687{
688 Entry *entry = m_Set_Enum.NextElement();
689
690 if (entry) {
691 return &entry->value;
692 } else {
693 return NULL;
694 }
695}
Definition archive.h:86
Definition class.h:276
Definition mem_blockalloc.h:172
Definition con_set.h:607
Definition con_set.h:547
Definition con_set.h:87
Definition con_set.h:462
Definition con_set.h:119
Definition con_set.h:70