1*00c7fec1SAndroid Build Coastguard Worker /*
2*00c7fec1SAndroid Build Coastguard Worker * Copyright (C) 2007 The Android Open Source Project
3*00c7fec1SAndroid Build Coastguard Worker *
4*00c7fec1SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*00c7fec1SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*00c7fec1SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*00c7fec1SAndroid Build Coastguard Worker *
8*00c7fec1SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*00c7fec1SAndroid Build Coastguard Worker *
10*00c7fec1SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*00c7fec1SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*00c7fec1SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*00c7fec1SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*00c7fec1SAndroid Build Coastguard Worker * limitations under the License.
15*00c7fec1SAndroid Build Coastguard Worker */
16*00c7fec1SAndroid Build Coastguard Worker
17*00c7fec1SAndroid Build Coastguard Worker #include <cutils/hashmap.h>
18*00c7fec1SAndroid Build Coastguard Worker
19*00c7fec1SAndroid Build Coastguard Worker #include <assert.h>
20*00c7fec1SAndroid Build Coastguard Worker #include <errno.h>
21*00c7fec1SAndroid Build Coastguard Worker #include <pthread.h>
22*00c7fec1SAndroid Build Coastguard Worker #include <stdlib.h>
23*00c7fec1SAndroid Build Coastguard Worker #include <string.h>
24*00c7fec1SAndroid Build Coastguard Worker #include <sys/types.h>
25*00c7fec1SAndroid Build Coastguard Worker
26*00c7fec1SAndroid Build Coastguard Worker typedef struct Entry Entry;
27*00c7fec1SAndroid Build Coastguard Worker struct Entry {
28*00c7fec1SAndroid Build Coastguard Worker void* key;
29*00c7fec1SAndroid Build Coastguard Worker int hash;
30*00c7fec1SAndroid Build Coastguard Worker void* value;
31*00c7fec1SAndroid Build Coastguard Worker Entry* next;
32*00c7fec1SAndroid Build Coastguard Worker };
33*00c7fec1SAndroid Build Coastguard Worker
34*00c7fec1SAndroid Build Coastguard Worker struct Hashmap {
35*00c7fec1SAndroid Build Coastguard Worker Entry** buckets;
36*00c7fec1SAndroid Build Coastguard Worker size_t bucketCount;
37*00c7fec1SAndroid Build Coastguard Worker int (*hash)(void* key);
38*00c7fec1SAndroid Build Coastguard Worker bool (*equals)(void* keyA, void* keyB);
39*00c7fec1SAndroid Build Coastguard Worker pthread_mutex_t lock;
40*00c7fec1SAndroid Build Coastguard Worker size_t size;
41*00c7fec1SAndroid Build Coastguard Worker };
42*00c7fec1SAndroid Build Coastguard Worker
hashmapCreate(size_t initialCapacity,int (* hash)(void * key),bool (* equals)(void * keyA,void * keyB))43*00c7fec1SAndroid Build Coastguard Worker Hashmap* hashmapCreate(size_t initialCapacity,
44*00c7fec1SAndroid Build Coastguard Worker int (*hash)(void* key), bool (*equals)(void* keyA, void* keyB)) {
45*00c7fec1SAndroid Build Coastguard Worker assert(hash != NULL);
46*00c7fec1SAndroid Build Coastguard Worker assert(equals != NULL);
47*00c7fec1SAndroid Build Coastguard Worker
48*00c7fec1SAndroid Build Coastguard Worker Hashmap* map = static_cast<Hashmap*>(malloc(sizeof(Hashmap)));
49*00c7fec1SAndroid Build Coastguard Worker if (map == NULL) {
50*00c7fec1SAndroid Build Coastguard Worker return NULL;
51*00c7fec1SAndroid Build Coastguard Worker }
52*00c7fec1SAndroid Build Coastguard Worker
53*00c7fec1SAndroid Build Coastguard Worker // 0.75 load factor.
54*00c7fec1SAndroid Build Coastguard Worker size_t minimumBucketCount = initialCapacity * 4 / 3;
55*00c7fec1SAndroid Build Coastguard Worker map->bucketCount = 1;
56*00c7fec1SAndroid Build Coastguard Worker while (map->bucketCount <= minimumBucketCount) {
57*00c7fec1SAndroid Build Coastguard Worker // Bucket count must be power of 2.
58*00c7fec1SAndroid Build Coastguard Worker map->bucketCount <<= 1;
59*00c7fec1SAndroid Build Coastguard Worker }
60*00c7fec1SAndroid Build Coastguard Worker
61*00c7fec1SAndroid Build Coastguard Worker map->buckets = static_cast<Entry**>(calloc(map->bucketCount, sizeof(Entry*)));
62*00c7fec1SAndroid Build Coastguard Worker if (map->buckets == NULL) {
63*00c7fec1SAndroid Build Coastguard Worker free(map);
64*00c7fec1SAndroid Build Coastguard Worker return NULL;
65*00c7fec1SAndroid Build Coastguard Worker }
66*00c7fec1SAndroid Build Coastguard Worker
67*00c7fec1SAndroid Build Coastguard Worker map->size = 0;
68*00c7fec1SAndroid Build Coastguard Worker
69*00c7fec1SAndroid Build Coastguard Worker map->hash = hash;
70*00c7fec1SAndroid Build Coastguard Worker map->equals = equals;
71*00c7fec1SAndroid Build Coastguard Worker
72*00c7fec1SAndroid Build Coastguard Worker pthread_mutex_init(&map->lock, nullptr);
73*00c7fec1SAndroid Build Coastguard Worker
74*00c7fec1SAndroid Build Coastguard Worker return map;
75*00c7fec1SAndroid Build Coastguard Worker }
76*00c7fec1SAndroid Build Coastguard Worker
77*00c7fec1SAndroid Build Coastguard Worker /**
78*00c7fec1SAndroid Build Coastguard Worker * Hashes the given key.
79*00c7fec1SAndroid Build Coastguard Worker */
80*00c7fec1SAndroid Build Coastguard Worker #ifdef __clang__
81*00c7fec1SAndroid Build Coastguard Worker __attribute__((no_sanitize("integer")))
82*00c7fec1SAndroid Build Coastguard Worker #endif
hashKey(Hashmap * map,void * key)83*00c7fec1SAndroid Build Coastguard Worker static inline int hashKey(Hashmap* map, void* key) {
84*00c7fec1SAndroid Build Coastguard Worker int h = map->hash(key);
85*00c7fec1SAndroid Build Coastguard Worker
86*00c7fec1SAndroid Build Coastguard Worker // We apply this secondary hashing discovered by Doug Lea to defend
87*00c7fec1SAndroid Build Coastguard Worker // against bad hashes.
88*00c7fec1SAndroid Build Coastguard Worker h += ~(h << 9);
89*00c7fec1SAndroid Build Coastguard Worker h ^= (((unsigned int) h) >> 14);
90*00c7fec1SAndroid Build Coastguard Worker h += (h << 4);
91*00c7fec1SAndroid Build Coastguard Worker h ^= (((unsigned int) h) >> 10);
92*00c7fec1SAndroid Build Coastguard Worker
93*00c7fec1SAndroid Build Coastguard Worker return h;
94*00c7fec1SAndroid Build Coastguard Worker }
95*00c7fec1SAndroid Build Coastguard Worker
calculateIndex(size_t bucketCount,int hash)96*00c7fec1SAndroid Build Coastguard Worker static inline size_t calculateIndex(size_t bucketCount, int hash) {
97*00c7fec1SAndroid Build Coastguard Worker return ((size_t) hash) & (bucketCount - 1);
98*00c7fec1SAndroid Build Coastguard Worker }
99*00c7fec1SAndroid Build Coastguard Worker
expandIfNecessary(Hashmap * map)100*00c7fec1SAndroid Build Coastguard Worker static void expandIfNecessary(Hashmap* map) {
101*00c7fec1SAndroid Build Coastguard Worker // If the load factor exceeds 0.75...
102*00c7fec1SAndroid Build Coastguard Worker if (map->size > (map->bucketCount * 3 / 4)) {
103*00c7fec1SAndroid Build Coastguard Worker // Start off with a 0.33 load factor.
104*00c7fec1SAndroid Build Coastguard Worker size_t newBucketCount = map->bucketCount << 1;
105*00c7fec1SAndroid Build Coastguard Worker Entry** newBuckets = static_cast<Entry**>(calloc(newBucketCount, sizeof(Entry*)));
106*00c7fec1SAndroid Build Coastguard Worker if (newBuckets == NULL) {
107*00c7fec1SAndroid Build Coastguard Worker // Abort expansion.
108*00c7fec1SAndroid Build Coastguard Worker return;
109*00c7fec1SAndroid Build Coastguard Worker }
110*00c7fec1SAndroid Build Coastguard Worker
111*00c7fec1SAndroid Build Coastguard Worker // Move over existing entries.
112*00c7fec1SAndroid Build Coastguard Worker size_t i;
113*00c7fec1SAndroid Build Coastguard Worker for (i = 0; i < map->bucketCount; i++) {
114*00c7fec1SAndroid Build Coastguard Worker Entry* entry = map->buckets[i];
115*00c7fec1SAndroid Build Coastguard Worker while (entry != NULL) {
116*00c7fec1SAndroid Build Coastguard Worker Entry* next = entry->next;
117*00c7fec1SAndroid Build Coastguard Worker size_t index = calculateIndex(newBucketCount, entry->hash);
118*00c7fec1SAndroid Build Coastguard Worker entry->next = newBuckets[index];
119*00c7fec1SAndroid Build Coastguard Worker newBuckets[index] = entry;
120*00c7fec1SAndroid Build Coastguard Worker entry = next;
121*00c7fec1SAndroid Build Coastguard Worker }
122*00c7fec1SAndroid Build Coastguard Worker }
123*00c7fec1SAndroid Build Coastguard Worker
124*00c7fec1SAndroid Build Coastguard Worker // Copy over internals.
125*00c7fec1SAndroid Build Coastguard Worker free(map->buckets);
126*00c7fec1SAndroid Build Coastguard Worker map->buckets = newBuckets;
127*00c7fec1SAndroid Build Coastguard Worker map->bucketCount = newBucketCount;
128*00c7fec1SAndroid Build Coastguard Worker }
129*00c7fec1SAndroid Build Coastguard Worker }
130*00c7fec1SAndroid Build Coastguard Worker
hashmapLock(Hashmap * map)131*00c7fec1SAndroid Build Coastguard Worker void hashmapLock(Hashmap* map) {
132*00c7fec1SAndroid Build Coastguard Worker pthread_mutex_lock(&map->lock);
133*00c7fec1SAndroid Build Coastguard Worker }
134*00c7fec1SAndroid Build Coastguard Worker
hashmapUnlock(Hashmap * map)135*00c7fec1SAndroid Build Coastguard Worker void hashmapUnlock(Hashmap* map) {
136*00c7fec1SAndroid Build Coastguard Worker pthread_mutex_unlock(&map->lock);
137*00c7fec1SAndroid Build Coastguard Worker }
138*00c7fec1SAndroid Build Coastguard Worker
hashmapFree(Hashmap * map)139*00c7fec1SAndroid Build Coastguard Worker void hashmapFree(Hashmap* map) {
140*00c7fec1SAndroid Build Coastguard Worker size_t i;
141*00c7fec1SAndroid Build Coastguard Worker for (i = 0; i < map->bucketCount; i++) {
142*00c7fec1SAndroid Build Coastguard Worker Entry* entry = map->buckets[i];
143*00c7fec1SAndroid Build Coastguard Worker while (entry != NULL) {
144*00c7fec1SAndroid Build Coastguard Worker Entry* next = entry->next;
145*00c7fec1SAndroid Build Coastguard Worker free(entry);
146*00c7fec1SAndroid Build Coastguard Worker entry = next;
147*00c7fec1SAndroid Build Coastguard Worker }
148*00c7fec1SAndroid Build Coastguard Worker }
149*00c7fec1SAndroid Build Coastguard Worker free(map->buckets);
150*00c7fec1SAndroid Build Coastguard Worker pthread_mutex_destroy(&map->lock);
151*00c7fec1SAndroid Build Coastguard Worker free(map);
152*00c7fec1SAndroid Build Coastguard Worker }
153*00c7fec1SAndroid Build Coastguard Worker
154*00c7fec1SAndroid Build Coastguard Worker #ifdef __clang__
155*00c7fec1SAndroid Build Coastguard Worker __attribute__((no_sanitize("integer")))
156*00c7fec1SAndroid Build Coastguard Worker #endif
157*00c7fec1SAndroid Build Coastguard Worker /* FIXME: relies on signed integer overflow, which is undefined behavior */
hashmapHash(void * key,size_t keySize)158*00c7fec1SAndroid Build Coastguard Worker int hashmapHash(void* key, size_t keySize) {
159*00c7fec1SAndroid Build Coastguard Worker int h = keySize;
160*00c7fec1SAndroid Build Coastguard Worker char* data = (char*) key;
161*00c7fec1SAndroid Build Coastguard Worker size_t i;
162*00c7fec1SAndroid Build Coastguard Worker for (i = 0; i < keySize; i++) {
163*00c7fec1SAndroid Build Coastguard Worker h = h * 31 + *data;
164*00c7fec1SAndroid Build Coastguard Worker data++;
165*00c7fec1SAndroid Build Coastguard Worker }
166*00c7fec1SAndroid Build Coastguard Worker return h;
167*00c7fec1SAndroid Build Coastguard Worker }
168*00c7fec1SAndroid Build Coastguard Worker
createEntry(void * key,int hash,void * value)169*00c7fec1SAndroid Build Coastguard Worker static Entry* createEntry(void* key, int hash, void* value) {
170*00c7fec1SAndroid Build Coastguard Worker Entry* entry = static_cast<Entry*>(malloc(sizeof(Entry)));
171*00c7fec1SAndroid Build Coastguard Worker if (entry == NULL) {
172*00c7fec1SAndroid Build Coastguard Worker return NULL;
173*00c7fec1SAndroid Build Coastguard Worker }
174*00c7fec1SAndroid Build Coastguard Worker entry->key = key;
175*00c7fec1SAndroid Build Coastguard Worker entry->hash = hash;
176*00c7fec1SAndroid Build Coastguard Worker entry->value = value;
177*00c7fec1SAndroid Build Coastguard Worker entry->next = NULL;
178*00c7fec1SAndroid Build Coastguard Worker return entry;
179*00c7fec1SAndroid Build Coastguard Worker }
180*00c7fec1SAndroid Build Coastguard Worker
equalKeys(void * keyA,int hashA,void * keyB,int hashB,bool (* equals)(void *,void *))181*00c7fec1SAndroid Build Coastguard Worker static inline bool equalKeys(void* keyA, int hashA, void* keyB, int hashB,
182*00c7fec1SAndroid Build Coastguard Worker bool (*equals)(void*, void*)) {
183*00c7fec1SAndroid Build Coastguard Worker if (keyA == keyB) {
184*00c7fec1SAndroid Build Coastguard Worker return true;
185*00c7fec1SAndroid Build Coastguard Worker }
186*00c7fec1SAndroid Build Coastguard Worker if (hashA != hashB) {
187*00c7fec1SAndroid Build Coastguard Worker return false;
188*00c7fec1SAndroid Build Coastguard Worker }
189*00c7fec1SAndroid Build Coastguard Worker return equals(keyA, keyB);
190*00c7fec1SAndroid Build Coastguard Worker }
191*00c7fec1SAndroid Build Coastguard Worker
hashmapPut(Hashmap * map,void * key,void * value)192*00c7fec1SAndroid Build Coastguard Worker void* hashmapPut(Hashmap* map, void* key, void* value) {
193*00c7fec1SAndroid Build Coastguard Worker int hash = hashKey(map, key);
194*00c7fec1SAndroid Build Coastguard Worker size_t index = calculateIndex(map->bucketCount, hash);
195*00c7fec1SAndroid Build Coastguard Worker
196*00c7fec1SAndroid Build Coastguard Worker Entry** p = &(map->buckets[index]);
197*00c7fec1SAndroid Build Coastguard Worker while (true) {
198*00c7fec1SAndroid Build Coastguard Worker Entry* current = *p;
199*00c7fec1SAndroid Build Coastguard Worker
200*00c7fec1SAndroid Build Coastguard Worker // Add a new entry.
201*00c7fec1SAndroid Build Coastguard Worker if (current == NULL) {
202*00c7fec1SAndroid Build Coastguard Worker *p = createEntry(key, hash, value);
203*00c7fec1SAndroid Build Coastguard Worker if (*p == NULL) {
204*00c7fec1SAndroid Build Coastguard Worker errno = ENOMEM;
205*00c7fec1SAndroid Build Coastguard Worker return NULL;
206*00c7fec1SAndroid Build Coastguard Worker }
207*00c7fec1SAndroid Build Coastguard Worker map->size++;
208*00c7fec1SAndroid Build Coastguard Worker expandIfNecessary(map);
209*00c7fec1SAndroid Build Coastguard Worker return NULL;
210*00c7fec1SAndroid Build Coastguard Worker }
211*00c7fec1SAndroid Build Coastguard Worker
212*00c7fec1SAndroid Build Coastguard Worker // Replace existing entry.
213*00c7fec1SAndroid Build Coastguard Worker if (equalKeys(current->key, current->hash, key, hash, map->equals)) {
214*00c7fec1SAndroid Build Coastguard Worker void* oldValue = current->value;
215*00c7fec1SAndroid Build Coastguard Worker current->value = value;
216*00c7fec1SAndroid Build Coastguard Worker return oldValue;
217*00c7fec1SAndroid Build Coastguard Worker }
218*00c7fec1SAndroid Build Coastguard Worker
219*00c7fec1SAndroid Build Coastguard Worker // Move to next entry.
220*00c7fec1SAndroid Build Coastguard Worker p = ¤t->next;
221*00c7fec1SAndroid Build Coastguard Worker }
222*00c7fec1SAndroid Build Coastguard Worker }
223*00c7fec1SAndroid Build Coastguard Worker
hashmapGet(Hashmap * map,void * key)224*00c7fec1SAndroid Build Coastguard Worker void* hashmapGet(Hashmap* map, void* key) {
225*00c7fec1SAndroid Build Coastguard Worker int hash = hashKey(map, key);
226*00c7fec1SAndroid Build Coastguard Worker size_t index = calculateIndex(map->bucketCount, hash);
227*00c7fec1SAndroid Build Coastguard Worker
228*00c7fec1SAndroid Build Coastguard Worker Entry* entry = map->buckets[index];
229*00c7fec1SAndroid Build Coastguard Worker while (entry != NULL) {
230*00c7fec1SAndroid Build Coastguard Worker if (equalKeys(entry->key, entry->hash, key, hash, map->equals)) {
231*00c7fec1SAndroid Build Coastguard Worker return entry->value;
232*00c7fec1SAndroid Build Coastguard Worker }
233*00c7fec1SAndroid Build Coastguard Worker entry = entry->next;
234*00c7fec1SAndroid Build Coastguard Worker }
235*00c7fec1SAndroid Build Coastguard Worker
236*00c7fec1SAndroid Build Coastguard Worker return NULL;
237*00c7fec1SAndroid Build Coastguard Worker }
238*00c7fec1SAndroid Build Coastguard Worker
hashmapRemove(Hashmap * map,void * key)239*00c7fec1SAndroid Build Coastguard Worker void* hashmapRemove(Hashmap* map, void* key) {
240*00c7fec1SAndroid Build Coastguard Worker int hash = hashKey(map, key);
241*00c7fec1SAndroid Build Coastguard Worker size_t index = calculateIndex(map->bucketCount, hash);
242*00c7fec1SAndroid Build Coastguard Worker
243*00c7fec1SAndroid Build Coastguard Worker // Pointer to the current entry.
244*00c7fec1SAndroid Build Coastguard Worker Entry** p = &(map->buckets[index]);
245*00c7fec1SAndroid Build Coastguard Worker Entry* current;
246*00c7fec1SAndroid Build Coastguard Worker while ((current = *p) != NULL) {
247*00c7fec1SAndroid Build Coastguard Worker if (equalKeys(current->key, current->hash, key, hash, map->equals)) {
248*00c7fec1SAndroid Build Coastguard Worker void* value = current->value;
249*00c7fec1SAndroid Build Coastguard Worker *p = current->next;
250*00c7fec1SAndroid Build Coastguard Worker free(current);
251*00c7fec1SAndroid Build Coastguard Worker map->size--;
252*00c7fec1SAndroid Build Coastguard Worker return value;
253*00c7fec1SAndroid Build Coastguard Worker }
254*00c7fec1SAndroid Build Coastguard Worker
255*00c7fec1SAndroid Build Coastguard Worker p = ¤t->next;
256*00c7fec1SAndroid Build Coastguard Worker }
257*00c7fec1SAndroid Build Coastguard Worker
258*00c7fec1SAndroid Build Coastguard Worker return NULL;
259*00c7fec1SAndroid Build Coastguard Worker }
260*00c7fec1SAndroid Build Coastguard Worker
hashmapForEach(Hashmap * map,bool (* callback)(void * key,void * value,void * context),void * context)261*00c7fec1SAndroid Build Coastguard Worker void hashmapForEach(Hashmap* map, bool (*callback)(void* key, void* value, void* context),
262*00c7fec1SAndroid Build Coastguard Worker void* context) {
263*00c7fec1SAndroid Build Coastguard Worker size_t i;
264*00c7fec1SAndroid Build Coastguard Worker for (i = 0; i < map->bucketCount; i++) {
265*00c7fec1SAndroid Build Coastguard Worker Entry* entry = map->buckets[i];
266*00c7fec1SAndroid Build Coastguard Worker while (entry != NULL) {
267*00c7fec1SAndroid Build Coastguard Worker Entry *next = entry->next;
268*00c7fec1SAndroid Build Coastguard Worker if (!callback(entry->key, entry->value, context)) {
269*00c7fec1SAndroid Build Coastguard Worker return;
270*00c7fec1SAndroid Build Coastguard Worker }
271*00c7fec1SAndroid Build Coastguard Worker entry = next;
272*00c7fec1SAndroid Build Coastguard Worker }
273*00c7fec1SAndroid Build Coastguard Worker }
274*00c7fec1SAndroid Build Coastguard Worker }
275