• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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