1d9f0492fSopenharmony_ci/*
2d9f0492fSopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd.
3d9f0492fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4d9f0492fSopenharmony_ci * you may not use this file except in compliance with the License.
5d9f0492fSopenharmony_ci * You may obtain a copy of the License at
6d9f0492fSopenharmony_ci *
7d9f0492fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8d9f0492fSopenharmony_ci *
9d9f0492fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10d9f0492fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11d9f0492fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12d9f0492fSopenharmony_ci * See the License for the specific language governing permissions and
13d9f0492fSopenharmony_ci * limitations under the License.
14d9f0492fSopenharmony_ci */
15d9f0492fSopenharmony_ci#include "init_hashmap.h"
16d9f0492fSopenharmony_ci#include "init_log.h"
17d9f0492fSopenharmony_ci
18d9f0492fSopenharmony_citypedef struct {
19d9f0492fSopenharmony_ci    HashNodeCompare nodeCompare;
20d9f0492fSopenharmony_ci    HashKeyCompare keyCompare;
21d9f0492fSopenharmony_ci    HashNodeFunction nodeHash;
22d9f0492fSopenharmony_ci    HashKeyFunction keyHash;
23d9f0492fSopenharmony_ci    HashNodeOnFree nodeFree;
24d9f0492fSopenharmony_ci    int maxBucket;
25d9f0492fSopenharmony_ci    uint32_t tableId;
26d9f0492fSopenharmony_ci    HashNode *buckets[0];
27d9f0492fSopenharmony_ci} HashTab;
28d9f0492fSopenharmony_ci
29d9f0492fSopenharmony_cistatic uint32_t g_tableId = 0;
30d9f0492fSopenharmony_ciint32_t OH_HashMapCreate(HashMapHandle *handle, const HashInfo *info)
31d9f0492fSopenharmony_ci{
32d9f0492fSopenharmony_ci    INIT_ERROR_CHECK(handle != NULL, return -1, "Invalid hash handle");
33d9f0492fSopenharmony_ci    INIT_ERROR_CHECK(info != NULL && info->maxBucket > 0, return -1, "Invalid hash info");
34d9f0492fSopenharmony_ci    INIT_ERROR_CHECK(info->keyHash != NULL && info->nodeHash != NULL, return -1, "Invalid hash key");
35d9f0492fSopenharmony_ci    INIT_ERROR_CHECK(info->nodeCompare != NULL && info->keyCompare != NULL, return -1, "Invalid hash compare");
36d9f0492fSopenharmony_ci    HashTab *tab = (HashTab *)calloc(1, sizeof(HashTab) + sizeof(HashNode*) * info->maxBucket);
37d9f0492fSopenharmony_ci    INIT_ERROR_CHECK(tab != NULL, return -1, "Failed to create hash tab");
38d9f0492fSopenharmony_ci    tab->maxBucket = info->maxBucket;
39d9f0492fSopenharmony_ci    tab->keyHash = info->keyHash;
40d9f0492fSopenharmony_ci    tab->nodeCompare = info->nodeCompare;
41d9f0492fSopenharmony_ci    tab->keyCompare = info->keyCompare;
42d9f0492fSopenharmony_ci    tab->nodeHash = info->nodeHash;
43d9f0492fSopenharmony_ci    tab->nodeFree = info->nodeFree;
44d9f0492fSopenharmony_ci    tab->tableId = g_tableId++;
45d9f0492fSopenharmony_ci    *handle = (HashMapHandle)tab;
46d9f0492fSopenharmony_ci    return 0;
47d9f0492fSopenharmony_ci}
48d9f0492fSopenharmony_ci
49d9f0492fSopenharmony_cistatic HashNode *GetHashNodeByNode(const HashTab *tab, const HashNode *root, const HashNode *new)
50d9f0492fSopenharmony_ci{
51d9f0492fSopenharmony_ci    HashNode *node = (HashNode *)root;
52d9f0492fSopenharmony_ci    while (node != NULL) {
53d9f0492fSopenharmony_ci        int ret = tab->nodeCompare(node, new);
54d9f0492fSopenharmony_ci        if (ret == 0) {
55d9f0492fSopenharmony_ci            return node;
56d9f0492fSopenharmony_ci        }
57d9f0492fSopenharmony_ci        node = node->next;
58d9f0492fSopenharmony_ci    }
59d9f0492fSopenharmony_ci    return NULL;
60d9f0492fSopenharmony_ci}
61d9f0492fSopenharmony_ci
62d9f0492fSopenharmony_cistatic HashNode *GetHashNodeByKey(const HashTab *tab, const HashNode *root, const void *key, HashKeyCompare keyCompare)
63d9f0492fSopenharmony_ci{
64d9f0492fSopenharmony_ci    (void)tab;
65d9f0492fSopenharmony_ci    HashNode *node = (HashNode *)root;
66d9f0492fSopenharmony_ci    while (node != NULL) {
67d9f0492fSopenharmony_ci        int ret = keyCompare(node, key);
68d9f0492fSopenharmony_ci        if (ret == 0) {
69d9f0492fSopenharmony_ci            return node;
70d9f0492fSopenharmony_ci        }
71d9f0492fSopenharmony_ci        node = node->next;
72d9f0492fSopenharmony_ci    }
73d9f0492fSopenharmony_ci    return NULL;
74d9f0492fSopenharmony_ci}
75d9f0492fSopenharmony_ci
76d9f0492fSopenharmony_ciint32_t OH_HashMapAdd(HashMapHandle handle, HashNode *node)
77d9f0492fSopenharmony_ci{
78d9f0492fSopenharmony_ci    INIT_ERROR_CHECK(handle != NULL, return -1, "Invalid hash handle");
79d9f0492fSopenharmony_ci    INIT_ERROR_CHECK(node != NULL && node->next == NULL, return -1, "Invalid param");
80d9f0492fSopenharmony_ci    HashTab *tab = (HashTab *)handle;
81d9f0492fSopenharmony_ci    int hashCode = tab->nodeHash(node);
82d9f0492fSopenharmony_ci    hashCode = (hashCode < 0) ? -hashCode : hashCode;
83d9f0492fSopenharmony_ci    hashCode = hashCode % tab->maxBucket;
84d9f0492fSopenharmony_ci    INIT_ERROR_CHECK(hashCode < tab->maxBucket, return -1, "Invalid hashcode %d %d", tab->maxBucket, hashCode);
85d9f0492fSopenharmony_ci
86d9f0492fSopenharmony_ci    // check key exist
87d9f0492fSopenharmony_ci    HashNode *tmp = GetHashNodeByNode(tab, tab->buckets[hashCode], node);
88d9f0492fSopenharmony_ci    if (tmp != NULL) {
89d9f0492fSopenharmony_ci        INIT_LOGE("node hash been exist");
90d9f0492fSopenharmony_ci        return -1;
91d9f0492fSopenharmony_ci    }
92d9f0492fSopenharmony_ci    node->next = tab->buckets[hashCode];
93d9f0492fSopenharmony_ci    tab->buckets[hashCode] = node;
94d9f0492fSopenharmony_ci    return 0;
95d9f0492fSopenharmony_ci}
96d9f0492fSopenharmony_ci
97d9f0492fSopenharmony_civoid OH_HashMapRemove(HashMapHandle handle, const void *key)
98d9f0492fSopenharmony_ci{
99d9f0492fSopenharmony_ci    INIT_ERROR_CHECK(handle != NULL && key != NULL, return, "Invalid hash handle key:%s", key);
100d9f0492fSopenharmony_ci    HashTab *tab = (HashTab *)handle;
101d9f0492fSopenharmony_ci    int hashCode = tab->keyHash(key);
102d9f0492fSopenharmony_ci    hashCode = (hashCode < 0) ? -hashCode : hashCode;
103d9f0492fSopenharmony_ci    hashCode = hashCode % tab->maxBucket;
104d9f0492fSopenharmony_ci    INIT_ERROR_CHECK(hashCode < tab->maxBucket, return, "Invalid hashcode %d %d", tab->maxBucket, hashCode);
105d9f0492fSopenharmony_ci
106d9f0492fSopenharmony_ci    HashNode *node = tab->buckets[hashCode];
107d9f0492fSopenharmony_ci    HashNode *preNode = node;
108d9f0492fSopenharmony_ci    while (node != NULL) {
109d9f0492fSopenharmony_ci        int ret = tab->keyCompare(node, key);
110d9f0492fSopenharmony_ci        if (ret == 0) {
111d9f0492fSopenharmony_ci            if (node == tab->buckets[hashCode]) {
112d9f0492fSopenharmony_ci                tab->buckets[hashCode] = node->next;
113d9f0492fSopenharmony_ci            } else {
114d9f0492fSopenharmony_ci                preNode->next = node->next;
115d9f0492fSopenharmony_ci            }
116d9f0492fSopenharmony_ci            return;
117d9f0492fSopenharmony_ci        }
118d9f0492fSopenharmony_ci        preNode = node;
119d9f0492fSopenharmony_ci        node = node->next;
120d9f0492fSopenharmony_ci    }
121d9f0492fSopenharmony_ci}
122d9f0492fSopenharmony_ci
123d9f0492fSopenharmony_ciHashNode *OH_HashMapGet(HashMapHandle handle, const void *key)
124d9f0492fSopenharmony_ci{
125d9f0492fSopenharmony_ci    INIT_ERROR_CHECK(handle != NULL && key != NULL, return NULL, "Invalid hash handle key:%s", key);
126d9f0492fSopenharmony_ci    HashTab *tab = (HashTab *)handle;
127d9f0492fSopenharmony_ci    int hashCode = tab->keyHash(key);
128d9f0492fSopenharmony_ci    hashCode = (hashCode < 0) ? -hashCode : hashCode;
129d9f0492fSopenharmony_ci    hashCode = hashCode % tab->maxBucket;
130d9f0492fSopenharmony_ci    INIT_ERROR_CHECK(hashCode < tab->maxBucket, return NULL,
131d9f0492fSopenharmony_ci        "Invalid hashcode %d %d", tab->maxBucket, hashCode);
132d9f0492fSopenharmony_ci    return GetHashNodeByKey(tab, tab->buckets[hashCode], key, tab->keyCompare);
133d9f0492fSopenharmony_ci}
134d9f0492fSopenharmony_ci
135d9f0492fSopenharmony_cistatic void HashListFree(HashTab *tab, HashNode *root, void *context)
136d9f0492fSopenharmony_ci{
137d9f0492fSopenharmony_ci    if (root == NULL) {
138d9f0492fSopenharmony_ci        return;
139d9f0492fSopenharmony_ci    }
140d9f0492fSopenharmony_ci    HashNode *node = root;
141d9f0492fSopenharmony_ci    while (node != NULL) {
142d9f0492fSopenharmony_ci        HashNode *next = node->next;
143d9f0492fSopenharmony_ci        if (tab->nodeFree != NULL) {
144d9f0492fSopenharmony_ci            tab->nodeFree(node, context);
145d9f0492fSopenharmony_ci        }
146d9f0492fSopenharmony_ci        node = next;
147d9f0492fSopenharmony_ci    }
148d9f0492fSopenharmony_ci}
149d9f0492fSopenharmony_ci
150d9f0492fSopenharmony_civoid OH_HashMapDestory(HashMapHandle handle, void *context)
151d9f0492fSopenharmony_ci{
152d9f0492fSopenharmony_ci    INIT_ERROR_CHECK(handle != NULL, return, "Invalid hash handle");
153d9f0492fSopenharmony_ci    HashTab *tab = (HashTab *)handle;
154d9f0492fSopenharmony_ci    for (int i = 0; i < tab->maxBucket; i++) {
155d9f0492fSopenharmony_ci        HashListFree(tab, tab->buckets[i], context);
156d9f0492fSopenharmony_ci    }
157d9f0492fSopenharmony_ci    free(tab);
158d9f0492fSopenharmony_ci}
159d9f0492fSopenharmony_ci
160d9f0492fSopenharmony_ciHashNode *OH_HashMapFind(HashMapHandle handle,
161d9f0492fSopenharmony_ci    int hashCode, const void *key, HashKeyCompare keyCompare)
162d9f0492fSopenharmony_ci{
163d9f0492fSopenharmony_ci    INIT_ERROR_CHECK(handle != NULL, return NULL, "Invalid hash handle");
164d9f0492fSopenharmony_ci    INIT_ERROR_CHECK(key != NULL && keyCompare != NULL, return NULL, "Invalid hash key");
165d9f0492fSopenharmony_ci    HashTab *tab = (HashTab *)handle;
166d9f0492fSopenharmony_ci    INIT_ERROR_CHECK((hashCode < tab->maxBucket) && (hashCode >= 0), return NULL,
167d9f0492fSopenharmony_ci        "Invalid hash code %d %d", tab->maxBucket, hashCode);
168d9f0492fSopenharmony_ci    return GetHashNodeByKey(tab, tab->buckets[hashCode], key, keyCompare);
169d9f0492fSopenharmony_ci}
170d9f0492fSopenharmony_ci
171d9f0492fSopenharmony_civoid OH_HashMapTraverse(HashMapHandle handle, void (*hashNodeTraverse)(const HashNode *node, const void *context),
172d9f0492fSopenharmony_ci    const void *context)
173d9f0492fSopenharmony_ci{
174d9f0492fSopenharmony_ci    INIT_ERROR_CHECK(handle != NULL && hashNodeTraverse != NULL, return, "Invalid hash handle");
175d9f0492fSopenharmony_ci    HashTab *tab = (HashTab *)handle;
176d9f0492fSopenharmony_ci    for (int i = 0; i < tab->maxBucket; i++) {
177d9f0492fSopenharmony_ci        HashNode *node = tab->buckets[i];
178d9f0492fSopenharmony_ci        while (node != NULL) {
179d9f0492fSopenharmony_ci            HashNode *next = node->next;
180d9f0492fSopenharmony_ci            hashNodeTraverse(node, context);
181d9f0492fSopenharmony_ci            node = next;
182d9f0492fSopenharmony_ci        }
183d9f0492fSopenharmony_ci    }
184d9f0492fSopenharmony_ci}
185d9f0492fSopenharmony_ci
186d9f0492fSopenharmony_ciint OH_HashMapIsEmpty(HashMapHandle handle)
187d9f0492fSopenharmony_ci{
188d9f0492fSopenharmony_ci    INIT_ERROR_CHECK(handle != NULL, return 1, "Invalid hash handle");
189d9f0492fSopenharmony_ci    HashTab *tab = (HashTab *)handle;
190d9f0492fSopenharmony_ci    for (int i = 0; i < tab->maxBucket; i++) {
191d9f0492fSopenharmony_ci        HashNode *node = tab->buckets[i];
192d9f0492fSopenharmony_ci        if (node != NULL) {
193d9f0492fSopenharmony_ci            return 0;
194d9f0492fSopenharmony_ci        }
195d9f0492fSopenharmony_ci    }
196d9f0492fSopenharmony_ci    return 1;
197d9f0492fSopenharmony_ci}
198