File Coverage

third_party/modest/source/mycore/utils/mhash.c
Criterion Covered Total %
statement 0 134 0.0
branch 0 66 0.0
condition n/a
subroutine n/a
pod n/a
total 0 200 0.0


line stmt bran cond sub pod time code
1             /*
2             Copyright (C) 2017 Alexander Borisov
3            
4             This library is free software; you can redistribute it and/or
5             modify it under the terms of the GNU Lesser General Public
6             License as published by the Free Software Foundation; either
7             version 2.1 of the License, or (at your option) any later version.
8            
9             This library is distributed in the hope that it will be useful,
10             but WITHOUT ANY WARRANTY; without even the implied warranty of
11             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12             Lesser General Public License for more details.
13            
14             You should have received a copy of the GNU Lesser General Public
15             License along with this library; if not, write to the Free Software
16             Foundation, Inc., 51 Franklin avl_treet, Fifth Floor, Boston, MA 02110-1301 USA
17            
18             Author: lex.borisov@gmail.com (Alexander Borisov)
19             */
20              
21             #include "mycore/utils/mhash.h"
22              
23 0           size_t mycore_utils_mhash_hash(const char* key, size_t key_size, size_t table_size)
24             {
25             size_t hash, i;
26            
27 0 0         for(hash = i = 0; i < key_size; i++)
28             {
29 0           hash += key[i];
30 0           hash += (hash << 10);
31 0           hash ^= (hash >> 6);
32             }
33            
34 0           hash += (hash << 3);
35 0           hash ^= (hash >> 11);
36 0           hash += (hash << 15);
37            
38 0           return hash % table_size;
39             }
40              
41 0           mycore_utils_mhash_t * mycore_utils_mhash_create(void)
42             {
43 0           return mycore_calloc(1, sizeof(mycore_utils_mhash_t));
44             }
45              
46 0           mystatus_t mycore_utils_mhash_init(mycore_utils_mhash_t* mhash, size_t table_size, size_t max_depth)
47             {
48             mystatus_t status;
49            
50 0           mhash->mchar_obj = mchar_async_create();
51 0 0         if(mhash->mchar_obj == NULL)
52 0           return MyCORE_STATUS_ERROR_MEMORY_ALLOCATION;
53            
54 0 0         if((status = mchar_async_init(mhash->mchar_obj, 128, 4096)))
55 0           return status;
56            
57             /* nodest data for input char* */
58 0           mhash->mchar_node = mchar_async_node_add(mhash->mchar_obj, &status);
59 0 0         if(status)
60 0           return status;
61            
62 0 0         if(table_size < 128)
63 0           table_size = 128;
64            
65 0           mhash->table = mycore_calloc(table_size, sizeof(mycore_utils_mhash_entry_t*));
66 0 0         if(mhash->table == NULL)
67 0           return MyCORE_STATUS_ERROR_MEMORY_ALLOCATION;
68            
69 0 0         if(max_depth < 1)
70 0           max_depth = 1;
71            
72 0           mhash->table_max_depth = max_depth;
73 0           mhash->table_size = table_size;
74            
75 0           return MyCORE_STATUS_OK;
76             }
77              
78 0           void mycore_utils_mhash_clean(mycore_utils_mhash_t* mhash)
79             {
80 0           mchar_async_clean(mhash->mchar_obj);
81 0           memset(mhash->table, 0, (sizeof(mycore_utils_mhash_entry_t*) * mhash->table_size));
82 0           }
83              
84 0           mycore_utils_mhash_t * mycore_utils_mhash_destroy(mycore_utils_mhash_t* mhash, bool self_destroy)
85             {
86 0 0         if(mhash == NULL)
87 0           return NULL;
88            
89 0 0         if(mhash->table) {
90 0           mycore_free(mhash->table);
91 0           mhash->table = NULL;
92             }
93            
94 0 0         if(self_destroy) {
95 0           mycore_free(mhash->table);
96 0           return NULL;
97             }
98            
99 0           return mhash;
100             }
101              
102 0           mycore_utils_mhash_entry_t * mycore_utils_mhash_create_entry(mycore_utils_mhash_t* mhash, const char* key, size_t key_size, void* value)
103             {
104 0           mycore_utils_mhash_entry_t *entry = (mycore_utils_mhash_entry_t*)
105 0           mchar_async_malloc(mhash->mchar_obj, mhash->mchar_node, sizeof(mycore_utils_mhash_entry_t));
106            
107 0           entry->key = mchar_async_malloc(mhash->mchar_obj, mhash->mchar_node, (sizeof(char) * key_size) + 1);
108            
109 0 0         if(entry->key == NULL) {
110 0           mchar_async_free(mhash->mchar_obj, mhash->mchar_node, (char*)entry);
111 0           return NULL;
112             }
113            
114 0           memcpy(entry->key, key, (sizeof(char) * key_size));
115 0           entry->key[key_size] = '\0';
116            
117 0           entry->key_length = key_size;
118 0           entry->value = value;
119 0           entry->next = NULL;
120            
121 0           return entry;
122             }
123              
124 0           mycore_utils_mhash_entry_t * mycore_utils_mhash_add_with_choice(mycore_utils_mhash_t* mhash, const char* key, size_t key_size)
125             {
126 0 0         if(key == NULL || key_size == 0)
    0          
127 0           return NULL;
128            
129 0           size_t hash_id = mycore_utils_mhash_hash(key, key_size, mhash->table_size);
130            
131            
132             mycore_utils_mhash_entry_t *entry;
133            
134 0 0         if(mhash->table[hash_id] == NULL) {
135             /* rebuild table if need */
136 0 0         if(mhash->table_length >= (mhash->table_size - (mhash->table_size / 4))) {
137 0           mycore_utils_mhash_rebuld(mhash);
138             }
139            
140 0           mhash->table[hash_id] = mycore_utils_mhash_create_entry(mhash, key, key_size, NULL);
141 0           return mhash->table[hash_id];
142             }
143            
144 0           size_t depth = 0;
145 0           entry = mhash->table[hash_id];
146            
147             do {
148 0 0         if(entry->key_length == key_size) {
149 0 0         if(strncmp(entry->key, key, key_size) == 0)
150 0           return entry;
151             }
152            
153 0 0         if(entry->next == NULL) {
154 0           entry->next = mycore_utils_mhash_create_entry(mhash, key, key_size, NULL);
155            
156 0 0         if(depth > mhash->table_max_depth) {
157 0           mycore_utils_mhash_entry_t *entry_new = entry->next;
158 0           mycore_utils_mhash_rebuld(mhash);
159            
160 0           return entry_new;
161             }
162            
163 0           return entry->next;
164             }
165            
166 0           depth++;
167 0           entry = entry->next;
168             }
169 0           while(1);
170             }
171              
172 0           mycore_utils_mhash_entry_t * mycore_utils_mhash_add(mycore_utils_mhash_t* mhash, const char* key, size_t key_size, void* value)
173             {
174 0           mycore_utils_mhash_entry_t *entry = mycore_utils_mhash_add_with_choice(mhash, key, key_size);
175            
176 0 0         if(entry)
177 0           entry->value = value;
178            
179 0           return entry;
180             }
181              
182 0           mycore_utils_mhash_entry_t * mycore_utils_mhash_search(mycore_utils_mhash_t* mhash, const char* key, size_t key_size, void* value)
183             {
184 0 0         if(key == NULL || key_size == 0)
    0          
185 0           return NULL;
186            
187 0           size_t hash_id = mycore_utils_mhash_hash(key, key_size, mhash->table_size);
188            
189 0           mycore_utils_mhash_entry_t *entry = mhash->table[hash_id];
190            
191 0 0         while(entry) {
192 0 0         if(entry->key_length == key_size) {
193 0 0         if(strncmp(entry->key, key, key_size) == 0)
194 0           return entry;
195             }
196            
197 0           entry = entry->next;
198             }
199            
200 0           return NULL;
201             }
202              
203 0           mycore_utils_mhash_entry_t * mycore_utils_mhash_entry_by_id(mycore_utils_mhash_t* mhash, size_t id)
204             {
205 0 0         if(mhash->table_size > id)
206 0           return mhash->table[id];
207            
208 0           return NULL;
209             }
210              
211 0           size_t mycore_utils_mhash_get_table_size(mycore_utils_mhash_t* mhash)
212             {
213 0           return mhash->table_size;
214             }
215              
216 0           mycore_utils_mhash_entry_t * mycore_utils_mhash_rebuild_add_entry(mycore_utils_mhash_t* mhash, const char* key, size_t key_size, mycore_utils_mhash_entry_t *ext_entry)
217             {
218 0 0         if(key == NULL || key_size == 0)
    0          
219 0           return NULL;
220            
221 0           ext_entry->next = NULL;
222            
223 0           size_t hash_id = mycore_utils_mhash_hash(key, key_size, mhash->table_size);
224            
225 0 0         if(mhash->table[hash_id] == NULL) {
226 0           mhash->table[hash_id] = ext_entry;
227 0           return ext_entry;
228             }
229            
230 0           mycore_utils_mhash_entry_t *entry = mhash->table[hash_id];
231            
232             do {
233 0 0         if(entry->next == NULL) {
234 0           entry->next = ext_entry;
235 0           break;
236             }
237            
238 0           entry = entry->next;
239             }
240 0           while(1);
241            
242 0           return ext_entry;
243             }
244              
245 0           mycore_utils_mhash_entry_t ** mycore_utils_mhash_rebuld(mycore_utils_mhash_t* mhash)
246             {
247 0           mycore_utils_mhash_entry_t **table = mhash->table;
248 0           size_t size = mhash->table_size;
249            
250 0           mhash->table_size = mhash->table_size << 1;
251 0           mhash->table = mycore_calloc(mhash->table_size, sizeof(mycore_utils_mhash_entry_t*));
252            
253 0 0         if(mhash->table == NULL) {
254 0           mhash->table = table;
255 0           mhash->table_size = size;
256            
257 0           return NULL;
258             }
259            
260 0 0         for(size_t i = 0; i < mhash->table_size; i++) {
261 0           mycore_utils_mhash_entry_t *entry = table[i];
262            
263 0 0         while(entry) {
264 0           mycore_utils_mhash_rebuild_add_entry(mhash, entry->key, entry->key_length, entry);
265            
266 0           entry = entry->next;
267             }
268             }
269            
270 0           mycore_free(table);
271            
272 0           return mhash->table;
273             }
274              
275