1 /******************************************************************************
2 *
3 * Copyright (C) 2014 Google, Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 #include "bt_common.h"
20 #include "osi/list.h"
21 #include "osi/hash_map.h"
22 #include "osi/allocator.h"
23
24 struct hash_map_t;
25
26 typedef struct hash_map_bucket_t {
27 list_t *list;
28 } hash_map_bucket_t;
29
30 typedef struct hash_map_t {
31 hash_map_bucket_t *bucket;
32 size_t num_bucket;
33 size_t hash_size;
34 hash_index_fn hash_fn;
35 key_free_fn key_fn;
36 data_free_fn data_fn;
37 key_equality_fn keys_are_equal;
38 } hash_map_t;
39
40 // Hidden constructor for list, only to be used by us.
41 list_t *list_new_internal(list_free_cb callback);
42
43 static void bucket_free_(void *data);
44 static bool default_key_equality(const void *x, const void *y);
45 static hash_map_entry_t *find_bucket_entry_(list_t *hash_bucket_list,
46 const void *key);
47
48 // Hidden constructor, only to be used by the allocation tracker. Behaves the same as
49 // |hash_map_new|, except you get to specify the allocator.
hash_map_new_internal(size_t num_bucket,hash_index_fn hash_fn,key_free_fn key_fn,data_free_fn data_fn,key_equality_fn equality_fn)50 hash_map_t *hash_map_new_internal(
51 size_t num_bucket,
52 hash_index_fn hash_fn,
53 key_free_fn key_fn,
54 data_free_fn data_fn,
55 key_equality_fn equality_fn)
56 {
57 assert(hash_fn != NULL);
58 assert(num_bucket > 0);
59 hash_map_t *hash_map = osi_calloc(sizeof(hash_map_t));
60 if (hash_map == NULL) {
61 return NULL;
62 }
63
64 hash_map->hash_fn = hash_fn;
65 hash_map->key_fn = key_fn;
66 hash_map->data_fn = data_fn;
67 hash_map->keys_are_equal = equality_fn ? equality_fn : default_key_equality;
68
69 hash_map->num_bucket = num_bucket;
70 hash_map->bucket = osi_calloc(sizeof(hash_map_bucket_t) * num_bucket);
71 if (hash_map->bucket == NULL) {
72 osi_free(hash_map);
73 return NULL;
74 }
75 return hash_map;
76 }
77
hash_map_new(size_t num_bucket,hash_index_fn hash_fn,key_free_fn key_fn,data_free_fn data_fn,key_equality_fn equality_fn)78 hash_map_t *hash_map_new(
79 size_t num_bucket,
80 hash_index_fn hash_fn,
81 key_free_fn key_fn,
82 data_free_fn data_fn,
83 key_equality_fn equality_fn)
84 {
85 return hash_map_new_internal(num_bucket, hash_fn, key_fn, data_fn, equality_fn);
86 }
87
hash_map_free(hash_map_t * hash_map)88 void hash_map_free(hash_map_t *hash_map)
89 {
90 if (hash_map == NULL) {
91 return;
92 }
93 hash_map_clear(hash_map);
94 osi_free(hash_map->bucket);
95 osi_free(hash_map);
96 }
97
98 /*
99 bool hash_map_is_empty(const hash_map_t *hash_map) {
100 assert(hash_map != NULL);
101 return (hash_map->hash_size == 0);
102 }
103
104 size_t hash_map_size(const hash_map_t *hash_map) {
105 assert(hash_map != NULL);
106 return hash_map->hash_size;
107 }
108
109 size_t hash_map_num_buckets(const hash_map_t *hash_map) {
110 assert(hash_map != NULL);
111 return hash_map->num_bucket;
112 }
113 */
114
hash_map_has_key(const hash_map_t * hash_map,const void * key)115 bool hash_map_has_key(const hash_map_t *hash_map, const void *key)
116 {
117 assert(hash_map != NULL);
118
119 hash_index_t hash_key = hash_map->hash_fn(key) % hash_map->num_bucket;
120 list_t *hash_bucket_list = hash_map->bucket[hash_key].list;
121
122 hash_map_entry_t *hash_map_entry = find_bucket_entry_(hash_bucket_list, key);
123 return (hash_map_entry != NULL);
124 }
125
hash_map_set(hash_map_t * hash_map,const void * key,void * data)126 bool hash_map_set(hash_map_t *hash_map, const void *key, void *data)
127 {
128 assert(hash_map != NULL);
129 assert(data != NULL);
130
131 hash_index_t hash_key = hash_map->hash_fn(key) % hash_map->num_bucket;
132
133 if (hash_map->bucket[hash_key].list == NULL) {
134 hash_map->bucket[hash_key].list = list_new_internal(bucket_free_);
135 if (hash_map->bucket[hash_key].list == NULL) {
136 return false;
137 }
138 }
139 list_t *hash_bucket_list = hash_map->bucket[hash_key].list;
140
141 hash_map_entry_t *hash_map_entry = find_bucket_entry_(hash_bucket_list, key);
142
143 if (hash_map_entry) {
144 // Calls hash_map callback to delete the hash_map_entry.
145 bool rc = list_remove(hash_bucket_list, hash_map_entry);
146 assert(rc == true);
147 } else {
148 hash_map->hash_size++;
149 }
150 hash_map_entry = osi_calloc(sizeof(hash_map_entry_t));
151 if (hash_map_entry == NULL) {
152 return false;
153 }
154
155 hash_map_entry->key = key;
156 hash_map_entry->data = data;
157 hash_map_entry->hash_map = hash_map;
158
159 return list_append(hash_bucket_list, hash_map_entry);
160 }
161
hash_map_erase(hash_map_t * hash_map,const void * key)162 bool hash_map_erase(hash_map_t *hash_map, const void *key)
163 {
164 assert(hash_map != NULL);
165
166 hash_index_t hash_key = hash_map->hash_fn(key) % hash_map->num_bucket;
167 list_t *hash_bucket_list = hash_map->bucket[hash_key].list;
168
169 hash_map_entry_t *hash_map_entry = find_bucket_entry_(hash_bucket_list, key);
170 if (hash_map_entry == NULL) {
171 return false;
172 }
173
174 hash_map->hash_size--;
175 bool remove = list_remove(hash_bucket_list, hash_map_entry);
176 if(list_is_empty(hash_map->bucket[hash_key].list)) {
177 list_free(hash_map->bucket[hash_key].list);
178 hash_map->bucket[hash_key].list = NULL;
179 }
180
181 return remove;
182 }
183
hash_map_get(const hash_map_t * hash_map,const void * key)184 void *hash_map_get(const hash_map_t *hash_map, const void *key)
185 {
186 assert(hash_map != NULL);
187
188 hash_index_t hash_key = hash_map->hash_fn(key) % hash_map->num_bucket;
189 list_t *hash_bucket_list = hash_map->bucket[hash_key].list;
190
191 hash_map_entry_t *hash_map_entry = find_bucket_entry_(hash_bucket_list, key);
192 if (hash_map_entry != NULL) {
193 return hash_map_entry->data;
194 }
195
196 return NULL;
197 }
198
hash_map_clear(hash_map_t * hash_map)199 void hash_map_clear(hash_map_t *hash_map)
200 {
201 assert(hash_map != NULL);
202
203 for (hash_index_t i = 0; i < hash_map->num_bucket; i++) {
204 if (hash_map->bucket[i].list == NULL) {
205 continue;
206 }
207 list_free(hash_map->bucket[i].list);
208 hash_map->bucket[i].list = NULL;
209 }
210 }
211
hash_map_foreach(hash_map_t * hash_map,hash_map_iter_cb callback,void * context)212 void hash_map_foreach(hash_map_t *hash_map, hash_map_iter_cb callback, void *context)
213 {
214 assert(hash_map != NULL);
215 assert(callback != NULL);
216
217 for (hash_index_t i = 0; i < hash_map->num_bucket; ++i) {
218 if (hash_map->bucket[i].list == NULL) {
219 continue;
220 }
221 for (const list_node_t *iter = list_begin(hash_map->bucket[i].list);
222 iter != list_end(hash_map->bucket[i].list);
223 iter = list_next(iter)) {
224 hash_map_entry_t *hash_map_entry = (hash_map_entry_t *)list_node(iter);
225 if (!callback(hash_map_entry, context)) {
226 return;
227 }
228 }
229 }
230 }
231
bucket_free_(void * data)232 static void bucket_free_(void *data)
233 {
234 assert(data != NULL);
235 hash_map_entry_t *hash_map_entry = (hash_map_entry_t *)data;
236 const hash_map_t *hash_map = hash_map_entry->hash_map;
237
238 if (hash_map->key_fn) {
239 hash_map->key_fn((void *)hash_map_entry->key);
240 }
241 if (hash_map->data_fn) {
242 hash_map->data_fn(hash_map_entry->data);
243 }
244 osi_free(hash_map_entry);
245 }
246
find_bucket_entry_(list_t * hash_bucket_list,const void * key)247 static hash_map_entry_t *find_bucket_entry_(list_t *hash_bucket_list,
248 const void *key)
249 {
250
251 if (hash_bucket_list == NULL) {
252 return NULL;
253 }
254
255 for (const list_node_t *iter = list_begin(hash_bucket_list);
256 iter != list_end(hash_bucket_list);
257 iter = list_next(iter)) {
258 hash_map_entry_t *hash_map_entry = (hash_map_entry_t *)list_node(iter);
259 if (hash_map_entry->hash_map->keys_are_equal(hash_map_entry->key, key)) {
260 return hash_map_entry;
261 }
262 }
263 return NULL;
264 }
265
default_key_equality(const void * x,const void * y)266 static bool default_key_equality(const void *x, const void *y)
267 {
268 return x == y;
269 }
270