1 /*---------------------------------------------------------------------------*
2 * HashMapImpl.c *
3 * *
4 * Copyright 2007, 2008 Nuance Communciations, Inc. *
5 * *
6 * Licensed under the Apache License, Version 2.0 (the 'License'); *
7 * you may not use this file except in compliance with the License. *
8 * *
9 * You may obtain a copy of the License at *
10 * http://www.apache.org/licenses/LICENSE-2.0 *
11 * *
12 * Unless required by applicable law or agreed to in writing, software *
13 * distributed under the License is distributed on an 'AS IS' BASIS, *
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
15 * See the License for the specific language governing permissions and *
16 * limitations under the License. *
17 * *
18 *---------------------------------------------------------------------------*/
19
20
21 #include "HashMap.h"
22 #include "HashMapImpl.h"
23 #include "plog.h"
24 #include "pmemory.h"
25 #include "string.h"
26
27 #define MTAG NULL
28
HashMapCreate_Internal(PHashTableArgs * hashArgs,HashMap ** self)29 static ESR_ReturnCode HashMapCreate_Internal(PHashTableArgs *hashArgs,
30 HashMap **self)
31 {
32 HashMapImpl* impl;
33 ESR_ReturnCode rc = ESR_SUCCESS;
34
35 if (self == NULL)
36 return ESR_INVALID_ARGUMENT;
37 impl = NEW(HashMapImpl, MTAG);
38 if (impl == NULL)
39 return ESR_OUT_OF_MEMORY;
40
41 if ((rc = PHashTableCreate(hashArgs, MTAG, &impl->table)) != ESR_SUCCESS)
42 {
43 FREE(impl);
44 return rc;
45 }
46
47 impl->Interface.put = &HashMap_Put;
48 impl->Interface.remove = &HashMap_Remove;
49 impl->Interface.removeAndFree = &HashMap_RemoveAndFree;
50 impl->Interface.removeAll = &HashMap_RemoveAll;
51 impl->Interface.removeAndFreeAll = &HashMap_RemoveAndFreeAll;
52 impl->Interface.removeAtIndex = &HashMap_RemoveAtIndex;
53 impl->Interface.containsKey = &HashMap_ContainsKey;
54 impl->Interface.getKeyAtIndex = &HashMap_GetKeyAtIndex;
55 impl->Interface.get = &HashMap_Get;
56 impl->Interface.getValueAtIndex = &HashMap_GetValueAtIndex;
57 impl->Interface.getSize = &HashMap_GetSize;
58 impl->Interface.destroy = &HashMap_Destroy;
59
60 *self = (HashMap*) impl;
61 return ESR_SUCCESS;
62 }
63
HashMapCreate(HashMap ** self)64 ESR_ReturnCode HashMapCreate(HashMap** self)
65 {
66 return HashMapCreate_Internal(NULL, self);
67 }
68
HashMapCreateBins(size_t nbBins,HashMap ** self)69 ESR_ReturnCode HashMapCreateBins(size_t nbBins, HashMap** self)
70 {
71 PHashTableArgs hashArgs;
72 hashArgs.capacity = nbBins;
73 hashArgs.maxLoadFactor = PHASH_TABLE_DEFAULT_MAX_LOAD_FACTOR;
74 hashArgs.hashFunction = PHASH_TABLE_DEFAULT_HASH_FUNCTION;
75 hashArgs.compFunction = PHASH_TABLE_DEFAULT_COMP_FUNCTION;
76 return HashMapCreate_Internal(&hashArgs, self);
77 }
78
HashMap_Put(HashMap * self,const LCHAR * key,void * value)79 ESR_ReturnCode HashMap_Put(HashMap* self, const LCHAR* key, void* value)
80 {
81 HashMapImpl* impl = (HashMapImpl*) self;
82 PHashTableEntry *entry = NULL;
83 ESR_ReturnCode rc;
84 ESR_BOOL exists;
85
86 CHKLOG(rc, PHashTableContainsKey(impl->table, key, &exists));
87 if (!exists)
88 {
89 /* Not found, clone the key and insert it. */
90 LCHAR *clone = (LCHAR *) MALLOC(sizeof(LCHAR) * (LSTRLEN(key) + 1), MTAG);
91 if (clone == NULL) return ESR_OUT_OF_MEMORY;
92 LSTRCPY(clone, key);
93 if ((rc = PHashTablePutValue(impl->table, clone, value, NULL)) != ESR_SUCCESS)
94 {
95 FREE(clone);
96 }
97 }
98 else
99 {
100 /* Key already present in table, just change the value. */
101 CHKLOG(rc, PHashTableGetEntry(impl->table, key, &entry));
102 rc = PHashTableEntrySetValue(entry, value, NULL);
103 }
104 return rc;
105 CLEANUP:
106 return rc;
107 }
108
HashMap_Remove_Internal(HashMapImpl * impl,const LCHAR * key,ESR_BOOL freeValue)109 static ESR_ReturnCode HashMap_Remove_Internal(HashMapImpl* impl, const LCHAR* key, ESR_BOOL freeValue)
110 {
111 PHashTableEntry *entry = NULL;
112 ESR_ReturnCode rc = ESR_SUCCESS;
113 LCHAR *clonedKey = NULL;
114 void *value = NULL;
115
116 CHK(rc, PHashTableGetEntry(impl->table, key, &entry));
117 CHK(rc, PHashTableEntryGetKeyValue(entry, (void **)&clonedKey, (void **)&value));
118
119 if (clonedKey)
120 FREE(clonedKey);
121 if (freeValue && value)
122 FREE(value);
123
124 return PHashTableEntryRemove(entry);
125 CLEANUP:
126 return rc;
127 }
128
HashMap_Remove(HashMap * self,const LCHAR * key)129 ESR_ReturnCode HashMap_Remove(HashMap* self, const LCHAR* key)
130 {
131 return HashMap_Remove_Internal((HashMapImpl*) self, key, ESR_FALSE);
132 }
133
HashMap_RemoveAndFree(HashMap * self,const LCHAR * key)134 ESR_ReturnCode HashMap_RemoveAndFree(HashMap* self, const LCHAR* key)
135 {
136 return HashMap_Remove_Internal((HashMapImpl*) self, key, ESR_TRUE);
137 }
138
HashMap_RemoveAll_Internal(HashMapImpl * impl,ESR_BOOL freeValues)139 static ESR_ReturnCode HashMap_RemoveAll_Internal(HashMapImpl *impl, ESR_BOOL freeValues)
140 {
141 PHashTableEntry *entry1 = NULL;
142 PHashTableEntry *entry2 = NULL;
143
144 ESR_ReturnCode rc = ESR_SUCCESS;
145 LCHAR *key = NULL;
146 void *value = NULL;
147
148 if ((rc = PHashTableEntryGetFirst(impl->table, &entry1)) != ESR_SUCCESS)
149 goto end;
150
151 while (entry1 != NULL)
152 {
153 if ((rc = PHashTableEntryGetKeyValue(entry1, (void **)&key, (void **)&value)) != ESR_SUCCESS)
154 goto end;
155 if (key) FREE(key);
156 if (freeValues && value) FREE(value);
157 entry2 = entry1;
158 if ((rc = PHashTableEntryAdvance(&entry1)) != ESR_SUCCESS)
159 goto end;
160 if ((rc = PHashTableEntryRemove(entry2)) != ESR_SUCCESS)
161 goto end;
162 }
163 end:
164 return rc;
165 }
166
HashMap_RemoveAll(HashMap * self)167 ESR_ReturnCode HashMap_RemoveAll(HashMap* self)
168 {
169 return HashMap_RemoveAll_Internal((HashMapImpl *) self, ESR_FALSE);
170 }
171
HashMap_RemoveAndFreeAll(HashMap * self)172 ESR_ReturnCode HashMap_RemoveAndFreeAll(HashMap* self)
173 {
174 return HashMap_RemoveAll_Internal((HashMapImpl *) self, ESR_TRUE);
175 }
176
HashMap_ContainsKey(HashMap * self,const LCHAR * key,ESR_BOOL * exists)177 ESR_ReturnCode HashMap_ContainsKey(HashMap* self, const LCHAR* key, ESR_BOOL* exists)
178 {
179 HashMapImpl* impl = (HashMapImpl*) self;
180 ESR_ReturnCode rc = ESR_SUCCESS;
181
182 CHKLOG(rc, PHashTableContainsKey(impl->table, key, exists));
183 return rc;
184 CLEANUP:
185 return rc;
186 }
187
HashMap_Get(HashMap * self,const LCHAR * key,void ** value)188 ESR_ReturnCode HashMap_Get(HashMap* self, const LCHAR* key, void** value)
189 {
190 HashMapImpl* impl = (HashMapImpl*) self;
191 PHashTableEntry *entry = NULL;
192 ESR_ReturnCode rc = ESR_SUCCESS;
193
194 CHK(rc, PHashTableGetEntry(impl->table, key, &entry));
195 CHK(rc, PHashTableEntryGetKeyValue(entry, (void **)NULL, (void **)value));
196 return ESR_SUCCESS;
197 CLEANUP:
198 return rc;
199 }
200
HashMap_GetEntryAtIndex(HashMapImpl * impl,const size_t index,PHashTableEntry ** entry)201 static ESR_ReturnCode HashMap_GetEntryAtIndex(HashMapImpl *impl, const size_t index,
202 PHashTableEntry **entry)
203 {
204 ESR_ReturnCode rc = ESR_SUCCESS;
205 size_t i = 0;
206
207 if ((rc = PHashTableEntryGetFirst(impl->table, entry)) != ESR_SUCCESS)
208 goto end;
209
210 while (*entry != NULL && i < index)
211 {
212 ++i;
213 if ((rc = PHashTableEntryAdvance(entry)) != ESR_SUCCESS)
214 goto end;
215 }
216 if (*entry == NULL)
217 rc = ESR_ARGUMENT_OUT_OF_BOUNDS;
218 end:
219 return rc;
220 }
221
222
HashMap_GetKeyAtIndex(HashMap * self,const size_t index,LCHAR ** key)223 ESR_ReturnCode HashMap_GetKeyAtIndex(HashMap* self, const size_t index, LCHAR** key)
224 {
225 HashMapImpl* impl = (HashMapImpl*) self;
226 PHashTableEntry *entry = NULL;
227 ESR_ReturnCode rc;
228
229 if ((rc = HashMap_GetEntryAtIndex(impl, index, &entry)) != ESR_SUCCESS)
230 goto end;
231
232 rc = PHashTableEntryGetKeyValue(entry, (void **) key, (void **) NULL);
233
234 end:
235 return rc;
236 }
237
HashMap_GetValueAtIndex(HashMap * self,const size_t index,void ** value)238 ESR_ReturnCode HashMap_GetValueAtIndex(HashMap* self, const size_t index, void** value)
239 {
240 HashMapImpl* impl = (HashMapImpl*) self;
241 PHashTableEntry *entry = NULL;
242 ESR_ReturnCode rc;
243
244 if ((rc = HashMap_GetEntryAtIndex(impl, index, &entry)) != ESR_SUCCESS)
245 goto end;
246
247 rc = PHashTableEntryGetKeyValue(entry, (void **)NULL, (void **)value);
248
249 end:
250 return rc;
251 }
252
HashMap_RemoveAtIndex(HashMap * self,const size_t index)253 ESR_ReturnCode HashMap_RemoveAtIndex(HashMap* self, const size_t index)
254 {
255 HashMapImpl* impl = (HashMapImpl*) self;
256 PHashTableEntry *entry = NULL;
257 ESR_ReturnCode rc;
258 void *key;
259
260 if ((rc = HashMap_GetEntryAtIndex(impl, index, &entry)) != ESR_SUCCESS)
261 goto end;
262
263 if ((rc = PHashTableEntryGetKeyValue(entry, (void **)&key, (void **)NULL)) != ESR_SUCCESS)
264 goto end;
265
266 if (key != NULL) FREE(key);
267
268 rc = PHashTableEntryRemove(entry);
269
270 end:
271 return rc;
272 }
273
HashMap_GetSize(HashMap * self,size_t * size)274 ESR_ReturnCode HashMap_GetSize(HashMap* self, size_t* size)
275 {
276 HashMapImpl* impl = (HashMapImpl*) self;
277 return PHashTableGetSize(impl->table, size);
278 }
279
HashMap_Destroy(HashMap * self)280 ESR_ReturnCode HashMap_Destroy(HashMap* self)
281 {
282 HashMapImpl* impl = (HashMapImpl*) self;
283 ESR_ReturnCode rc = ESR_SUCCESS;
284
285 if ((rc = self->removeAll(self)) != ESR_SUCCESS)
286 goto end;
287
288 if (impl->table != NULL)
289 rc = PHashTableDestroy(impl->table);
290 FREE(impl);
291 end:
292 return rc;
293 }
294