Android str_parms

10 篇文章 9 订阅
3 篇文章 0 订阅

str_parms深入分析

在了解android audio,梳理audio hal的流程时,遇到这样一个数据结构,struct str_parms, 查看代码的上下文,它在这里的主要功能是用来对各种参数进行set与get操作的。其底层采用hash map实现,并通过链接法解决哈希碰撞。
在这里插入图片描述

str_parms_create_str

  • str_parms_create
    调用hashmapCreate来创建hash map,其中str_hash_fn为哈希的算法。
    接下来的是将传入的字符串解析为[key, value]的形式, 添加到hashmap中,形如"key=value",如有多个字符串,通过";"来分割。
43Hashmap* hashmapCreate(size_t initialCapacity,
44        int (*hash)(void* key), bool (*equals)(void* keyA, void* keyB)) {
45    assert(hash != NULL);
46    assert(equals != NULL);
47
48    Hashmap* map = static_cast<Hashmap*>(malloc(sizeof(Hashmap)));
49    if (map == NULL) {
50        return NULL;
51    }
52
53    // 0.75 load factor.
54    size_t minimumBucketCount = initialCapacity * 4 / 3;
55    map->bucketCount = 1;
56    while (map->bucketCount <= minimumBucketCount) {
57        // Bucket count must be power of 2.
58        map->bucketCount <<= 1;
59    }
60
61    map->buckets = static_cast<Entry**>(calloc(map->bucketCount, sizeof(Entry*)));
62    if (map->buckets == NULL) {
63        free(map);
64        return NULL;
65    }
66
67    map->size = 0;
68
69    map->hash = hash;
70    map->equals = equals;
71
72    pthread_mutex_init(&map->lock, nullptr);
73
74    return map;
75}

70struct str_parms *str_parms_create(void)
71{
72    str_parms* s = static_cast<str_parms*>(calloc(1, sizeof(str_parms)));
73    if (!s) return NULL;
74
75    s->map = hashmapCreate(5, str_hash_fn, str_eq);
76    if (!s->map) {
77        free(s);
78        return NULL;
79    }
80
81    return s;
82}

139struct str_parms *str_parms_create_str(const char *_string)
140{
141    struct str_parms *str_parms;
142    char *str;
143    char *kvpair;
144    char *tmpstr;
145    int items = 0;
146
147    str_parms = str_parms_create(); /* 创建哈希表 */
148    if (!str_parms)
149        goto err_create_str_parms;
150
151    str = strdup(_string);
152    if (!str)
153        goto err_strdup;
154
155    ALOGV("%s: source string == '%s'\n", __func__, _string);
156
157    kvpair = strtok_r(str, ";", &tmpstr); /* 选取第一个";"前的字符串 */
158    while (kvpair && *kvpair) {
159        char *eq = strchr(kvpair, '='); /* would love strchrnul */
160        char *value;
161        char *key;
162        void *old_val;
163
164        if (eq == kvpair) /* 字符串中没有"=", 不符合key value形式,直接跳过 */
165            goto next_pair;
166
167        if (eq) {
168            key = strndup(kvpair, eq - kvpair);
169            if (*(++eq))
170                value = strdup(eq);
171            else
172                value = strdup("");
173        } else {
174            key = strdup(kvpair);
175            value = strdup("");
176        }
177
178        /* if we replaced a value, free it */
179        old_val = hashmapPut(str_parms->map, key, value);
180        RELEASE_OWNERSHIP(value);
181        if (old_val) {
182            free(old_val);
183            free(key);
184        } else {
185            RELEASE_OWNERSHIP(key);
186        }
187
188        items++;
189next_pair:
190        kvpair = strtok_r(NULL, ";", &tmpstr);
191    }
192
193    if (!items)
194        ALOGV("%s: no items found in string\n", __func__);
195
196    free(str);
197
198    return str_parms;
199
200err_strdup:
201    str_parms_destroy(str_parms);
202err_create_str_parms:
203    return NULL;
204}

str_parms_add_str

向创建好的hashmap中添加键值对

192void* hashmapPut(Hashmap* map, void* key, void* value) {
193    int hash = hashKey(map, key); /* 计算哈希值 */
194    size_t index = calculateIndex(map->bucketCount, hash); /* 根据hash计算对应的哈希桶index */
195
196    Entry** p = &(map->buckets[index]);
197    while (true) {
198        Entry* current = *p;
199
200        // Add a new entry.
201        if (current == NULL) {
202            *p = createEntry(key, hash, value);
203            if (*p == NULL) {
204                errno = ENOMEM;
205                return NULL;
206            }
207            map->size++;
				  /* 根据哈希桶中元素数量选择是否增大哈希桶,现在的阈值时0.75 */
208            expandIfNecessary(map);
209            return NULL;
210        }
211
212        // Replace existing entry.
213        if (equalKeys(current->key, current->hash, key, hash, map->equals)) {
214            void* oldValue = current->value;
215            current->value = value;
216            return oldValue;
217        }
218
219        // Move to next entry.
220        p = &current->next;
221    }
222}

206int str_parms_add_str(struct str_parms *str_parms, const char *key,
207                      const char *value)
208{
209    void *tmp_key = NULL;
210    void *tmp_val = NULL;
211    void *old_val = NULL;
212
213    // strdup and hashmapPut both set errno on failure.
214    // Set errno to 0 so we can recognize whether anything went wrong.
215    int saved_errno = errno;
216    errno = 0;
217
218    tmp_key = strdup(key);
219    if (tmp_key == NULL) {
220        goto clean_up;
221    }
222
223    tmp_val = strdup(value);
224    if (tmp_val == NULL) {
225        goto clean_up;
226    }
227
228    old_val = hashmapPut(str_parms->map, tmp_key, tmp_val);
229    if (old_val == NULL) {
230        // Did hashmapPut fail?
231        if (errno == ENOMEM) {
232            goto clean_up;
233        }
234        // For new keys, hashmap takes ownership of tmp_key and tmp_val.
235        RELEASE_OWNERSHIP(tmp_key);
236        RELEASE_OWNERSHIP(tmp_val);
237        tmp_key = tmp_val = NULL;
238    } else {
239        // For existing keys, hashmap takes ownership of tmp_val.
240        // (It also gives up ownership of old_val.)
241        RELEASE_OWNERSHIP(tmp_val);
242        tmp_val = NULL;
243    }
244
245clean_up:
246    free(tmp_key);
247    free(tmp_val);
248    free(old_val);
249    int result = -errno;
250    errno = saved_errno;
251    return result;
252}

str_parms_get_str

获取hashmap中key对应的value

224void* hashmapGet(Hashmap* map, void* key) {
225    int hash = hashKey(map, key);
226    size_t index = calculateIndex(map->bucketCount, hash);
227
228    Entry* entry = map->buckets[index];
229    while (entry != NULL) {
230        if (equalKeys(entry->key, entry->hash, key, hash, map->equals)) {
231            return entry->value;
232        }
233        entry = entry->next;
234    }
235
236    return NULL;
237}

285int str_parms_get_str(struct str_parms *str_parms, const char *key, char *val,
286                      int len)
287{
288    // TODO: hashmapGet should take a const* key.
289    char* value = static_cast<char*>(hashmapGet(str_parms->map, (void*)key));
290    if (value)
291        return strlcpy(val, value, len);
292
293    return -ENOENT;
294}

str_parms_to_str

将hashmap中的key,value以形如"key1=value1;key2=value2"的形式保存到context。

331static bool combine_strings(void *key, void *value, void *context)
332{
333    char** old_str = static_cast<char**>(context);
334    char *new_str;
335    int ret;
336
337    ret = asprintf(&new_str, "%s%s%s=%s",
338                   *old_str ? *old_str : "",
339                   *old_str ? ";" : "",
340                   (char *)key,
341                   (char *)value);
342    if (*old_str)
343        free(*old_str);
344
345    if (ret >= 0) {
346        *old_str = new_str;
347        return true;
348    }
349
350    *old_str = NULL;
351    return false;
352}

261void hashmapForEach(Hashmap* map, bool (*callback)(void* key, void* value, void* context),
262                    void* context) {
263    size_t i;
264    for (i = 0; i < map->bucketCount; i++) {
265        Entry* entry = map->buckets[i];
266        while (entry != NULL) {
267            Entry *next = entry->next;
268            if (!callback(entry->key, entry->value, context)) {
269                return;
270            }
271            entry = next;
272        }
273    }
274}

354char *str_parms_to_str(struct str_parms *str_parms)
355{
356    char *str = NULL;
357    hashmapForEach(str_parms->map, combine_strings, &str);
358    return (str != NULL) ? str : strdup("");
359}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值