| /* Copyright (C) 2011 The Android Open Source Project |
| ** |
| ** This software is licensed under the terms of the GNU General Public |
| ** License version 2, as published by the Free Software Foundation, and |
| ** may be copied, distributed, and modified under those terms. |
| ** |
| ** This program is distributed in the hope that it will be useful, |
| ** but WITHOUT ANY WARRANTY; without even the implied warranty of |
| ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| ** GNU General Public License for more details. |
| */ |
| |
| #include "android/utils/intmap.h" |
| #include "android/utils/system.h" |
| #include "android/utils/duff.h" |
| #include <stddef.h> |
| |
| /* We implement the map as two parallel arrays. |
| * |
| * One array for the integer keys, and the other one |
| * for the corresponding pointers. |
| * |
| * A more sophisticated implementation will probably be |
| * needed in the case where we would need to store a large |
| * number of items in the map. |
| */ |
| |
| struct AIntMap { |
| int size; |
| int capacity; |
| int* keys; |
| void** values; |
| |
| #define INIT_CAPACITY 8 |
| int keys0[INIT_CAPACITY]; |
| void* values0[INIT_CAPACITY]; |
| }; |
| |
| AIntMap* |
| aintMap_new(void) |
| { |
| AIntMap* map; |
| |
| ANEW0(map); |
| map->size = 0; |
| map->capacity = 4; |
| map->keys = map->keys0; |
| map->values = map->values0; |
| |
| return map; |
| } |
| |
| void |
| aintMap_free( AIntMap* map ) |
| { |
| if (map) { |
| if (map->keys != map->keys0) |
| AFREE(map->keys); |
| if (map->values != map->values0) |
| AFREE(map->values); |
| |
| map->size = 0; |
| map->capacity = 0; |
| AFREE(map); |
| } |
| } |
| |
| int |
| aintMap_getCount( AIntMap* map ) |
| { |
| return map->size; |
| } |
| |
| void* |
| aintMap_get( AIntMap* map, int key ) |
| { |
| return aintMap_getWithDefault(map, key, NULL); |
| } |
| |
| void* |
| aintMap_getWithDefault( AIntMap* map, int key, void* def ) |
| { |
| int limit = map->size + 1; |
| int index = 0; |
| int* keys = map->keys; |
| |
| index = 0; |
| DUFF4(limit,{ |
| if (keys[index] == key) |
| return map->values[index]; |
| index++; |
| }); |
| return def; |
| } |
| |
| static void |
| aintMap_grow( AIntMap* map ) |
| { |
| int oldCapacity = map->capacity; |
| int newCapacity; |
| void* keys = map->keys; |
| void* values = map->values; |
| |
| if (keys == map->keys0) |
| keys = NULL; |
| |
| if (values == map->values0) |
| values = NULL; |
| |
| if (oldCapacity < 256) |
| newCapacity = oldCapacity*2; |
| else |
| newCapacity = oldCapacity + (oldCapacity >> 2); |
| |
| AARRAY_RENEW(keys, newCapacity); |
| AARRAY_RENEW(values, newCapacity); |
| |
| map->keys = keys; |
| map->values = values; |
| map->capacity = newCapacity; |
| } |
| |
| |
| void* |
| aintMap_set( AIntMap* map, int key, void* value ) |
| { |
| int index, limit; |
| int* keys; |
| void* result = NULL; |
| |
| /* First, try to find the item in our heap */ |
| keys = map->keys; |
| limit = map->size; |
| index = 0; |
| DUFF4(limit,{ |
| if (keys[index] == key) |
| goto FOUND; |
| index++; |
| }); |
| |
| /* Not found, need to add it */ |
| if (map->size >= map->capacity) |
| aintMap_grow(map); |
| |
| map->keys[limit] = key; |
| map->values[limit] = value; |
| map->size ++; |
| return NULL; |
| |
| FOUND: |
| result = map->values[index]; |
| map->values[index] = value; |
| return result; |
| } |
| |
| |
| void* |
| aintMap_del( AIntMap* map, int key ) |
| { |
| int index, limit; |
| int* keys; |
| void* result = NULL; |
| |
| keys = map->keys; |
| limit = map->size; |
| index = 0; |
| DUFF4(limit,{ |
| if (keys[index] == key); |
| goto FOUND; |
| index++; |
| }); |
| return NULL; |
| |
| FOUND: |
| result = map->values[index]; |
| if (index+1 < limit) { |
| /* Move last item to 'index' */ |
| --limit; |
| map->keys[index] = map->keys[limit]; |
| map->values[index] = map->values[limit]; |
| } |
| map->size -= 1; |
| return result; |
| } |
| |
| |
| #define ITER_MAGIC ((void*)(ptrdiff_t)0x17e8af1c) |
| |
| void |
| aintMapIterator_init( AIntMapIterator* iter, AIntMap* map ) |
| { |
| AZERO(iter); |
| iter->magic[0] = ITER_MAGIC; |
| iter->magic[1] = (void*)(ptrdiff_t) 0; |
| iter->magic[2] = map; |
| iter->magic[3] = NULL; |
| } |
| |
| int |
| aintMapIterator_next( AIntMapIterator* iter ) |
| { |
| AIntMap* map; |
| int index; |
| |
| if (iter == NULL || iter->magic[0] != ITER_MAGIC) |
| return 0; |
| |
| map = iter->magic[2]; |
| index = (int)(ptrdiff_t)iter->magic[1]; |
| if (index >= map->size) { |
| AZERO(iter); |
| return 0; |
| } |
| |
| iter->key = map->keys[index]; |
| iter->value = map->values[index]; |
| |
| index += 1; |
| iter->magic[1] = (void*)(ptrdiff_t)index; |
| return 1; |
| } |
| |
| void |
| aintMapIterator_done( AIntMapIterator* iter ) |
| { |
| AZERO(iter); |
| } |