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 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 64 ESR_ReturnCode HashMapCreate(HashMap** self) 65 { 66 return HashMapCreate_Internal(NULL, self); 67 } 68 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 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 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 129 ESR_ReturnCode HashMap_Remove(HashMap* self, const LCHAR* key) 130 { 131 return HashMap_Remove_Internal((HashMapImpl*) self, key, ESR_FALSE); 132 } 133 134 ESR_ReturnCode HashMap_RemoveAndFree(HashMap* self, const LCHAR* key) 135 { 136 return HashMap_Remove_Internal((HashMapImpl*) self, key, ESR_TRUE); 137 } 138 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 167 ESR_ReturnCode HashMap_RemoveAll(HashMap* self) 168 { 169 return HashMap_RemoveAll_Internal((HashMapImpl *) self, ESR_FALSE); 170 } 171 172 ESR_ReturnCode HashMap_RemoveAndFreeAll(HashMap* self) 173 { 174 return HashMap_RemoveAll_Internal((HashMapImpl *) self, ESR_TRUE); 175 } 176 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 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 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 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 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 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 274 ESR_ReturnCode HashMap_GetSize(HashMap* self, size_t* size) 275 { 276 HashMapImpl* impl = (HashMapImpl*) self; 277 return PHashTableGetSize(impl->table, size); 278 } 279 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