| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 |
- /******************************************************************************
- *
- * Copyright (C) 2014 Google, Inc.
- *
- * 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 "bt_common.h"
- #include "osi/list.h"
- #include "osi/hash_map.h"
- #include "osi/allocator.h"
- struct hash_map_t;
- typedef struct hash_map_bucket_t {
- list_t *list;
- } hash_map_bucket_t;
- typedef struct hash_map_t {
- hash_map_bucket_t *bucket;
- size_t num_bucket;
- size_t hash_size;
- hash_index_fn hash_fn;
- key_free_fn key_fn;
- data_free_fn data_fn;
- key_equality_fn keys_are_equal;
- } hash_map_t;
- // Hidden constructor for list, only to be used by us.
- list_t *list_new_internal(list_free_cb callback);
- static void bucket_free_(void *data);
- static bool default_key_equality(const void *x, const void *y);
- static hash_map_entry_t *find_bucket_entry_(list_t *hash_bucket_list,
- const void *key);
- // Hidden constructor, only to be used by the allocation tracker. Behaves the same as
- // |hash_map_new|, except you get to specify the allocator.
- hash_map_t *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)
- {
- assert(hash_fn != NULL);
- assert(num_bucket > 0);
- hash_map_t *hash_map = osi_calloc(sizeof(hash_map_t));
- if (hash_map == NULL) {
- return NULL;
- }
- hash_map->hash_fn = hash_fn;
- hash_map->key_fn = key_fn;
- hash_map->data_fn = data_fn;
- hash_map->keys_are_equal = equality_fn ? equality_fn : default_key_equality;
- hash_map->num_bucket = num_bucket;
- hash_map->bucket = osi_calloc(sizeof(hash_map_bucket_t) * num_bucket);
- if (hash_map->bucket == NULL) {
- osi_free(hash_map);
- return NULL;
- }
- return hash_map;
- }
- hash_map_t *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)
- {
- return hash_map_new_internal(num_bucket, hash_fn, key_fn, data_fn, equality_fn);
- }
- void hash_map_free(hash_map_t *hash_map)
- {
- if (hash_map == NULL) {
- return;
- }
- hash_map_clear(hash_map);
- osi_free(hash_map->bucket);
- osi_free(hash_map);
- }
- /*
- bool hash_map_is_empty(const hash_map_t *hash_map) {
- assert(hash_map != NULL);
- return (hash_map->hash_size == 0);
- }
- size_t hash_map_size(const hash_map_t *hash_map) {
- assert(hash_map != NULL);
- return hash_map->hash_size;
- }
- size_t hash_map_num_buckets(const hash_map_t *hash_map) {
- assert(hash_map != NULL);
- return hash_map->num_bucket;
- }
- */
- bool hash_map_has_key(const hash_map_t *hash_map, const void *key)
- {
- assert(hash_map != NULL);
- hash_index_t hash_key = hash_map->hash_fn(key) % hash_map->num_bucket;
- list_t *hash_bucket_list = hash_map->bucket[hash_key].list;
- hash_map_entry_t *hash_map_entry = find_bucket_entry_(hash_bucket_list, key);
- return (hash_map_entry != NULL);
- }
- bool hash_map_set(hash_map_t *hash_map, const void *key, void *data)
- {
- assert(hash_map != NULL);
- assert(data != NULL);
- hash_index_t hash_key = hash_map->hash_fn(key) % hash_map->num_bucket;
- if (hash_map->bucket[hash_key].list == NULL) {
- hash_map->bucket[hash_key].list = list_new_internal(bucket_free_);
- if (hash_map->bucket[hash_key].list == NULL) {
- return false;
- }
- }
- list_t *hash_bucket_list = hash_map->bucket[hash_key].list;
- hash_map_entry_t *hash_map_entry = find_bucket_entry_(hash_bucket_list, key);
- if (hash_map_entry) {
- // Calls hash_map callback to delete the hash_map_entry.
- bool rc = list_remove(hash_bucket_list, hash_map_entry);
- assert(rc == true);
- } else {
- hash_map->hash_size++;
- }
- hash_map_entry = osi_calloc(sizeof(hash_map_entry_t));
- if (hash_map_entry == NULL) {
- return false;
- }
- hash_map_entry->key = key;
- hash_map_entry->data = data;
- hash_map_entry->hash_map = hash_map;
- return list_append(hash_bucket_list, hash_map_entry);
- }
- bool hash_map_erase(hash_map_t *hash_map, const void *key)
- {
- assert(hash_map != NULL);
- hash_index_t hash_key = hash_map->hash_fn(key) % hash_map->num_bucket;
- list_t *hash_bucket_list = hash_map->bucket[hash_key].list;
- hash_map_entry_t *hash_map_entry = find_bucket_entry_(hash_bucket_list, key);
- if (hash_map_entry == NULL) {
- return false;
- }
- hash_map->hash_size--;
- bool remove = list_remove(hash_bucket_list, hash_map_entry);
- if(list_is_empty(hash_map->bucket[hash_key].list)) {
- list_free(hash_map->bucket[hash_key].list);
- hash_map->bucket[hash_key].list = NULL;
- }
-
- return remove;
- }
- void *hash_map_get(const hash_map_t *hash_map, const void *key)
- {
- assert(hash_map != NULL);
- hash_index_t hash_key = hash_map->hash_fn(key) % hash_map->num_bucket;
- list_t *hash_bucket_list = hash_map->bucket[hash_key].list;
- hash_map_entry_t *hash_map_entry = find_bucket_entry_(hash_bucket_list, key);
- if (hash_map_entry != NULL) {
- return hash_map_entry->data;
- }
- return NULL;
- }
- void hash_map_clear(hash_map_t *hash_map)
- {
- assert(hash_map != NULL);
- for (hash_index_t i = 0; i < hash_map->num_bucket; i++) {
- if (hash_map->bucket[i].list == NULL) {
- continue;
- }
- list_free(hash_map->bucket[i].list);
- hash_map->bucket[i].list = NULL;
- }
- }
- void hash_map_foreach(hash_map_t *hash_map, hash_map_iter_cb callback, void *context)
- {
- assert(hash_map != NULL);
- assert(callback != NULL);
- for (hash_index_t i = 0; i < hash_map->num_bucket; ++i) {
- if (hash_map->bucket[i].list == NULL) {
- continue;
- }
- for (const list_node_t *iter = list_begin(hash_map->bucket[i].list);
- iter != list_end(hash_map->bucket[i].list);
- iter = list_next(iter)) {
- hash_map_entry_t *hash_map_entry = (hash_map_entry_t *)list_node(iter);
- if (!callback(hash_map_entry, context)) {
- return;
- }
- }
- }
- }
- static void bucket_free_(void *data)
- {
- assert(data != NULL);
- hash_map_entry_t *hash_map_entry = (hash_map_entry_t *)data;
- const hash_map_t *hash_map = hash_map_entry->hash_map;
- if (hash_map->key_fn) {
- hash_map->key_fn((void *)hash_map_entry->key);
- }
- if (hash_map->data_fn) {
- hash_map->data_fn(hash_map_entry->data);
- }
- osi_free(hash_map_entry);
- }
- static hash_map_entry_t *find_bucket_entry_(list_t *hash_bucket_list,
- const void *key)
- {
- if (hash_bucket_list == NULL) {
- return NULL;
- }
- for (const list_node_t *iter = list_begin(hash_bucket_list);
- iter != list_end(hash_bucket_list);
- iter = list_next(iter)) {
- hash_map_entry_t *hash_map_entry = (hash_map_entry_t *)list_node(iter);
- if (hash_map_entry->hash_map->keys_are_equal(hash_map_entry->key, key)) {
- return hash_map_entry;
- }
- }
- return NULL;
- }
- static bool default_key_equality(const void *x, const void *y)
- {
- return x == y;
- }
|