Home | History | Annotate | Download | only in src
      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