OpenMoHAA 0.82.1
Loading...
Searching...
No Matches
umap.h
1/*
2===========================================================================
3Copyright (C) 2024 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// umap.h: Hash table based map class template. Maps text based keys to previously
24// stored data.
25//
26
27#pragma once
28
29#include "str.h"
30#include <stdlib.h>
31
32template<class Type>
33class UMap : public Class
34{
35private:
36 struct hashnode_s {
37 str key;
38 Type value;
39 hashnode_s *next;
40
41 hashnode_s(const char *k, Type v, hashnode_s *n)
42 : key(k)
43 , value(v)
44 , next(n) {};
45 hashnode_s(const str& k, Type v, hashnode_s *n)
46 : key(k.c_str())
47 , value(v)
48 , next(n) {};
49 };
50
51 hashnode_s **m_heads;
52 Type m_defaultvalue;
53
54 unsigned m_tablesize;
55 unsigned m_numentries;
56 unsigned m_tablesizemask;
57
58 unsigned getHash(const char *key);
59
60public:
61 void Clear(void);
62 unsigned getNumEntries(void) const;
63 void DeleteDefaultValues(void);
64
65 Type& operator[](const char *key);
66 Type& operator[](const str& key);
67
68 const char *getKeyByIndex(int index) const;
69 Type& getValueByIndex(unsigned index);
70
71 ~UMap<Type>();
72
73 UMap(Type defaultvalue, unsigned tablesize = 64)
74 : m_defaultvalue(defaultvalue)
75 , m_tablesize(tablesize)
76 {
77 int i;
78 int bits;
79
80 assert(m_tablesize > 0);
81
82 m_heads = new hashnode_s *[m_tablesize];
83 memset(m_heads, 0, sizeof(*m_heads) * m_tablesize);
84
85 m_numentries = 0;
86 m_tablesizemask = 0;
87
88 bits = 0;
89 for (i = 0; i < 32; i++) {
90 if (m_tablesize & (1 << i)) {
91 bits++;
92 }
93 }
94
95 if (bits == 1) {
96 m_tablesizemask = m_tablesize - 1;
97 }
98 };
99
100 UMap(UMap<Type>& map)
101 : m_defaultvalue(map.m_defaultvalue)
102 , m_tablesize(map.m_tablesize)
103 {
104 unsigned i;
105 hashnode_s *node;
106 hashnode_s **prev;
107
108 assert(m_tablesize > 0);
109
110 m_heads = new hashnode_s *[m_tablesize];
111 m_numentries = map.m_numentries;
112 m_tablesizemask = map.m_tablesizemask;
113
114 for (i = 0; i < m_tablesize; i++) {
115 if (!map.m_heads[i]) {
116 m_heads[i] = NULL;
117 continue;
118 }
119
120 prev = &m_heads[i];
121 for (node = map.m_heads[i]; node != NULL; node = node->next) {
122 *prev = new hashnode_s(node->key, node->value, NULL);
123 prev = &(*prev)->next;
124 }
125 }
126 };
127};
128
129template<class Type>
130UMap<Type>::~UMap<Type>()
131{
132 Clear();
133 delete m_heads;
134}
135
136template<class Type>
137unsigned UMap<Type>::getHash(const char *key)
138{
139 unsigned h;
140 const char *v;
141
142 if (m_tablesizemask) {
143 h = 0;
144 for (v = key; *v != '\0'; v++) {
145 h = (64 * h + unsigned(*v)) & m_tablesizemask;
146 }
147 } else {
148 h = 0;
149 for (v = key; *v != '\0'; v++) {
150 h = (64 * h + unsigned(*v)) % m_tablesize;
151 }
152 }
153
154 return h;
155}
156
157template<class Type>
158Type& UMap<Type>::operator[](const char *key)
159{
160 hashnode_s **head;
161 hashnode_s *node;
162 unsigned hash;
163
164 // FIXME
165 // if list was always sorted, could just insert new node as soon as we get
166 // node whose key is greater than the search key
167 hash = getHash(key);
168 head = &m_heads[hash];
169 if (*head) {
170 for (node = *head; node != NULL; node = node->next) {
171 if (node->key == key) {
172 return node->value;
173 }
174 }
175 }
176
177 m_numentries++;
178
179 *head = new hashnode_s(key, m_defaultvalue, *head);
180
181 return (*head)->value;
182}
183
184template<class Type>
185const char *UMap<Type>::getKeyByIndex(int index) const
186{
187 unsigned head;
188
189 for (head = 0; head < m_tablesize; head++) {
190 hashnode_s *node;
191
192 for (node = m_heads[head]; node; node = node->next) {
193 if (!index) {
194 return node->key.c_str();
195 }
196
197 index--;
198 }
199 }
200
201 return NULL;
202}
203
204template<class Type>
205Type& UMap<Type>::getValueByIndex(unsigned index)
206{
207 unsigned head;
208
209 ASSERT(index < getNumEntries());
210
211 for (head = 0; head < m_tablesize; head++) {
212 hashnode_s *node;
213
214 for (node = m_heads[head]; node; node = node->next) {
215 if (!index) {
216 return node->value;
217 }
218
219 index--;
220 }
221 }
222
223 // Should never, EVER get here.
224 ASSERT(0);
225 return m_defaultvalue;
226}
227
228template<class Type>
229inline void UMap<Type>::DeleteDefaultValues(void)
230{
231 unsigned head;
232
233 for (head = 0; head < m_tablesize; head++) {
234 hashnode_s *node;
235
236 while (m_heads[head] && m_heads[head]->value == m_defaultvalue) {
237 node = m_heads[head];
238 m_heads[head] = node->next;
239 delete node;
240 m_numentries--;
241 }
242
243 if (!m_heads[head]) {
244 continue;
245 }
246
247 for (node = m_heads[head]; node->next;) {
248 hashnode_s *next = node->next;
249
250 if (next->value == m_defaultvalue) {
251 node->next = next->next;
252 delete next;
253 m_numentries--;
254 } else {
255 node = node->next;
256 }
257 }
258 }
259}
260
261template<class Type>
262inline Type& UMap<Type>::operator[](const str& key)
263{
264 return this->[key.c_str()];
265}
266
267template<class Type>
268void UMap<Type>::Clear(void)
269{
270 unsigned i;
271 hashnode_s *node;
272 hashnode_s *next;
273
274 for (i = 0; i < m_tablesize; i++) {
275 next = m_heads[i];
276 while (next != NULL) {
277 node = next;
278 next = next->next;
279 delete node;
280 }
281
282 m_heads[i] = NULL;
283 }
284
285 m_numentries = 0;
286}
287
288template<class Type>
289inline unsigned UMap<Type>::getNumEntries(void) const
290{
291 return m_numentries;
292}
Definition str.h:77