diff options
| author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:29:04 -0800 |
|---|---|---|
| committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:29:04 -0800 |
| commit | e54eebbf1a908d65ee8cf80bab62821c05666d70 (patch) | |
| tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /libcutils/hashmap.c | |
| parent | a1e1c1b106423de09bc918502e7a51d4ffe5a4ae (diff) | |
| download | system_core-e54eebbf1a908d65ee8cf80bab62821c05666d70.tar.gz system_core-e54eebbf1a908d65ee8cf80bab62821c05666d70.tar.bz2 system_core-e54eebbf1a908d65ee8cf80bab62821c05666d70.zip | |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'libcutils/hashmap.c')
| -rw-r--r-- | libcutils/hashmap.c | 350 |
1 files changed, 0 insertions, 350 deletions
diff --git a/libcutils/hashmap.c b/libcutils/hashmap.c deleted file mode 100644 index e29bc246..00000000 --- a/libcutils/hashmap.c +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <cutils/hashmap.h> -#include <assert.h> -#include <errno.h> -#include <cutils/threads.h> -#include <stdlib.h> -#include <string.h> -#include <stdbool.h> -#include <sys/types.h> - -typedef struct Entry Entry; -struct Entry { - void* key; - int hash; - void* value; - Entry* next; -}; - -struct Hashmap { - Entry** buckets; - size_t bucketCount; - int (*hash)(void* key); - bool (*equals)(void* keyA, void* keyB); - mutex_t lock; - size_t size; -}; - -Hashmap* hashmapCreate(size_t initialCapacity, - int (*hash)(void* key), bool (*equals)(void* keyA, void* keyB)) { - assert(hash != NULL); - assert(equals != NULL); - - Hashmap* map = malloc(sizeof(Hashmap)); - if (map == NULL) { - return NULL; - } - - // 0.75 load factor. - size_t minimumBucketCount = initialCapacity * 4 / 3; - map->bucketCount = 1; - while (map->bucketCount <= minimumBucketCount) { - // Bucket count must be power of 2. - map->bucketCount <<= 1; - } - - map->buckets = calloc(map->bucketCount, sizeof(Entry*)); - if (map->buckets == NULL) { - free(map); - return NULL; - } - - map->size = 0; - - map->hash = hash; - map->equals = equals; - - mutex_init(&map->lock); - - return map; -} - -/** - * Hashes the given key. - */ -static inline int hashKey(Hashmap* map, void* key) { - int h = map->hash(key); - - // We apply this secondary hashing discovered by Doug Lea to defend - // against bad hashes. - h += ~(h << 9); - h ^= (((unsigned int) h) >> 14); - h += (h << 4); - h ^= (((unsigned int) h) >> 10); - - return h; -} - -size_t hashmapSize(Hashmap* map) { - return map->size; -} - -static inline size_t calculateIndex(size_t bucketCount, int hash) { - return ((size_t) hash) & (bucketCount - 1); -} - -static void expandIfNecessary(Hashmap* map) { - // If the load factor exceeds 0.75... - if (map->size > (map->bucketCount * 3 / 4)) { - // Start off with a 0.33 load factor. - size_t newBucketCount = map->bucketCount << 1; - Entry** newBuckets = calloc(newBucketCount, sizeof(Entry*)); - if (newBuckets == NULL) { - // Abort expansion. - return; - } - - // Move over existing entries. - size_t i; - for (i = 0; i < map->bucketCount; i++) { - Entry* entry = map->buckets[i]; - while (entry != NULL) { - Entry* next = entry->next; - size_t index = calculateIndex(newBucketCount, entry->hash); - entry->next = newBuckets[index]; - newBuckets[index] = entry; - entry = next; - } - } - - // Copy over internals. - free(map->buckets); - map->buckets = newBuckets; - map->bucketCount = newBucketCount; - } -} - -void hashmapLock(Hashmap* map) { - mutex_lock(&map->lock); -} - -void hashmapUnlock(Hashmap* map) { - mutex_unlock(&map->lock); -} - -void hashmapFree(Hashmap* map) { - size_t i; - for (i = 0; i < map->bucketCount; i++) { - Entry* entry = map->buckets[i]; - while (entry != NULL) { - Entry* next = entry->next; - free(entry); - entry = next; - } - } - free(map->buckets); - mutex_destroy(&map->lock); - free(map); -} - -int hashmapHash(void* key, size_t keySize) { - int h = keySize; - char* data = (char*) key; - size_t i; - for (i = 0; i < keySize; i++) { - h = h * 31 + *data; - data++; - } - return h; -} - -static Entry* createEntry(void* key, int hash, void* value) { - Entry* entry = malloc(sizeof(Entry)); - if (entry == NULL) { - return NULL; - } - entry->key = key; - entry->hash = hash; - entry->value = value; - entry->next = NULL; - return entry; -} - -static inline bool equalKeys(void* keyA, int hashA, void* keyB, int hashB, - bool (*equals)(void*, void*)) { - if (keyA == keyB) { - return true; - } - if (hashA != hashB) { - return false; - } - return equals(keyA, keyB); -} - -void* hashmapPut(Hashmap* map, void* key, void* value) { - int hash = hashKey(map, key); - size_t index = calculateIndex(map->bucketCount, hash); - - Entry** p = &(map->buckets[index]); - while (true) { - Entry* current = *p; - - // Add a new entry. - if (current == NULL) { - *p = createEntry(key, hash, value); - if (*p == NULL) { - errno = ENOMEM; - return NULL; - } - map->size++; - expandIfNecessary(map); - return NULL; - } - - // Replace existing entry. - if (equalKeys(current->key, current->hash, key, hash, map->equals)) { - void* oldValue = current->value; - current->value = value; - return oldValue; - } - - // Move to next entry. - p = ¤t->next; - } -} - -void* hashmapGet(Hashmap* map, void* key) { - int hash = hashKey(map, key); - size_t index = calculateIndex(map->bucketCount, hash); - - Entry* entry = map->buckets[index]; - while (entry != NULL) { - if (equalKeys(entry->key, entry->hash, key, hash, map->equals)) { - return entry->value; - } - entry = entry->next; - } - - return NULL; -} - -bool hashmapContainsKey(Hashmap* map, void* key) { - int hash = hashKey(map, key); - size_t index = calculateIndex(map->bucketCount, hash); - - Entry* entry = map->buckets[index]; - while (entry != NULL) { - if (equalKeys(entry->key, entry->hash, key, hash, map->equals)) { - return true; - } - entry = entry->next; - } - - return false; -} - -void* hashmapMemoize(Hashmap* map, void* key, - void* (*initialValue)(void* key, void* context), void* context) { - int hash = hashKey(map, key); - size_t index = calculateIndex(map->bucketCount, hash); - - Entry** p = &(map->buckets[index]); - while (true) { - Entry* current = *p; - - // Add a new entry. - if (current == NULL) { - *p = createEntry(key, hash, NULL); - if (*p == NULL) { - errno = ENOMEM; - return NULL; - } - void* value = initialValue(key, context); - (*p)->value = value; - map->size++; - expandIfNecessary(map); - return value; - } - - // Return existing value. - if (equalKeys(current->key, current->hash, key, hash, map->equals)) { - return current->value; - } - - // Move to next entry. - p = ¤t->next; - } -} - -void* hashmapRemove(Hashmap* map, void* key) { - int hash = hashKey(map, key); - size_t index = calculateIndex(map->bucketCount, hash); - - // Pointer to the current entry. - Entry** p = &(map->buckets[index]); - Entry* current; - while ((current = *p) != NULL) { - if (equalKeys(current->key, current->hash, key, hash, map->equals)) { - void* value = current->value; - *p = current->next; - free(current); - map->size--; - return value; - } - - p = ¤t->next; - } - - return NULL; -} - -void hashmapForEach(Hashmap* map, - bool (*callback)(void* key, void* value, void* context), - void* context) { - size_t i; - for (i = 0; i < map->bucketCount; i++) { - Entry* entry = map->buckets[i]; - while (entry != NULL) { - if (!callback(entry->key, entry->value, context)) { - return; - } - entry = entry->next; - } - } -} - -size_t hashmapCurrentCapacity(Hashmap* map) { - size_t bucketCount = map->bucketCount; - return bucketCount * 3 / 4; -} - -size_t hashmapCountCollisions(Hashmap* map) { - size_t collisions = 0; - size_t i; - for (i = 0; i < map->bucketCount; i++) { - Entry* entry = map->buckets[i]; - while (entry != NULL) { - if (entry->next != NULL) { - collisions++; - } - entry = entry->next; - } - } - return collisions; -} - -int hashmapIntHash(void* key) { - // Return the key value itself. - return *((int*) key); -} - -bool hashmapIntEquals(void* keyA, void* keyB) { - int a = *((int*) keyA); - int b = *((int*) keyB); - return a == b; -} |
