master
c 219 lines 6.15 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "../libnetdata.h"
4 #include "c_rhash_internal.h"
5
6 c_rhash c_rhash_new(size_t bin_count) {
7 if (!bin_count)
8 bin_count = 1000;
9
10 c_rhash hash = callocz(1, sizeof(struct c_rhash_s) + (bin_count * sizeof(struct bin_ll*)) );
11 hash->bin_count = bin_count;
12 hash->bins = (c_rhash_bin *)((char*)hash + sizeof(struct c_rhash_s));
13
14 return hash;
15 }
16
17 static size_t get_itemtype_len(uint8_t item_type, const void* item_data) {
18 switch (item_type) {
19 case ITEMTYPE_STRING:
20 return strlen(item_data) + 1;
21 case ITEMTYPE_UINT64:
22 return sizeof(uint64_t);
23 case ITEMTYPE_UINT8:
24 return 1;
25 case ITEMTYPE_OPAQUE_PTR:
26 return sizeof(void*);
27 default:
28 return 0;
29 }
30 }
31
32 static int compare_bin_item(struct bin_item *item, uint8_t key_type, const void *key) {
33 if (item->key_type != key_type)
34 return 1;
35
36 size_t key_value_len = get_itemtype_len(key_type, key);
37
38 if(key_type == ITEMTYPE_STRING) {
39 size_t new_key_value_len = get_itemtype_len(item->key_type, item->key);
40 if (new_key_value_len != key_value_len)
41 return 1;
42 }
43
44 if(memcmp(item->key, key, key_value_len) == 0) {
45 return 0;
46 }
47
48 return 1;
49 }
50
51 static int insert_into_bin(c_rhash_bin *bin, uint8_t key_type, const void *key, uint8_t value_type, const void *value) {
52 struct bin_item *prev = NULL;
53 while (*bin != NULL) {
54 if (!compare_bin_item(*bin, key_type, key)) {
55 freez((*bin)->value);
56 (*bin)->value_type = value_type;
57 (*bin)->value = mallocz(get_itemtype_len(value_type, value));
58 memcpy((*bin)->value, value, get_itemtype_len(value_type, value));
59 return 0;
60 }
61 prev = *bin;
62 bin = &(*bin)->next;
63 }
64
65 if (*bin == NULL)
66 *bin = callocz(1, sizeof(struct bin_item));
67 if (prev != NULL)
68 prev->next = *bin;
69
70 (*bin)->key_type = key_type;
71 size_t len = get_itemtype_len(key_type, key);
72 (*bin)->key = mallocz(len);
73 memcpy((*bin)->key, key, len);
74
75 (*bin)->value_type = value_type;
76 len = get_itemtype_len(value_type, value);
77 (*bin)->value = mallocz(len);
78 memcpy((*bin)->value, value, len);
79 return 0;
80 }
81
82 static inline uint32_t get_bin_idx_str(c_rhash hash, const char *key) {
83 uint32_t nhash = simple_hash(key);
84 return nhash % hash->bin_count;
85 }
86
87 static inline c_rhash_bin *get_binptr_by_str(c_rhash hash, const char *key) {
88 return &hash->bins[get_bin_idx_str(hash, key)];
89 }
90
91 int c_rhash_insert_str_ptr(c_rhash hash, const char *key, void *value) {
92 c_rhash_bin *bin = get_binptr_by_str(hash, key);
93
94 return insert_into_bin(bin, ITEMTYPE_STRING, key, ITEMTYPE_OPAQUE_PTR, &value);
95 }
96
97 int c_rhash_insert_str_uint8(c_rhash hash, const char *key, uint8_t value) {
98 c_rhash_bin *bin = get_binptr_by_str(hash, key);
99
100 return insert_into_bin(bin, ITEMTYPE_STRING, key, ITEMTYPE_UINT8, &value);
101 }
102
103 int c_rhash_insert_uint64_ptr(c_rhash hash, uint64_t key, void *value) {
104 c_rhash_bin *bin = &hash->bins[key % hash->bin_count];
105
106 return insert_into_bin(bin, ITEMTYPE_UINT64, &key, ITEMTYPE_OPAQUE_PTR, &value);
107 }
108
109 int c_rhash_get_uint8_by_str(c_rhash hash, const char *key, uint8_t *ret_val) {
110 uint32_t nhash = get_bin_idx_str(hash, key);
111
112 struct bin_item *bin = hash->bins[nhash];
113
114 while (bin) {
115 if (bin->key_type == ITEMTYPE_STRING) {
116 if (!strcmp(bin->key, key)) {
117 *ret_val = *(uint8_t*)bin->value;
118 return 0;
119 }
120 }
121 bin = bin->next;
122 }
123 return 1;
124 }
125
126 int c_rhash_get_ptr_by_str(c_rhash hash, const char *key, void **ret_val) {
127 uint32_t nhash = get_bin_idx_str(hash, key);
128
129 struct bin_item *bin = hash->bins[nhash];
130
131 while (bin) {
132 if (bin->key_type == ITEMTYPE_STRING) {
133 if (!strcmp(bin->key, key)) {
134 *ret_val = *((void**)bin->value);
135 return 0;
136 }
137 }
138 bin = bin->next;
139 }
140 *ret_val = NULL;
141 return 1;
142 }
143
144 int c_rhash_get_ptr_by_uint64(c_rhash hash, uint64_t key, void **ret_val) {
145 uint32_t nhash = key % hash->bin_count;
146
147 struct bin_item *bin = hash->bins[nhash];
148
149 while (bin) {
150 if (bin->key_type == ITEMTYPE_UINT64) {
151 if (*((uint64_t *)bin->key) == key) {
152 *ret_val = *((void**)bin->value);
153 return 0;
154 }
155 }
156 bin = bin->next;
157 }
158 *ret_val = NULL;
159 return 1;
160 }
161
162 static void c_rhash_destroy_bin(c_rhash_bin bin) {
163 struct bin_item *next;
164 do {
165 next = bin->next;
166 freez(bin->key);
167 freez(bin->value);
168 freez(bin);
169 bin = next;
170 } while (bin != NULL);
171 }
172
173 int c_rhash_iter_uint64_keys(c_rhash hash, c_rhash_iter_t *iter, uint64_t *key) {
174 while (iter->bin < hash->bin_count) {
175 if (iter->item != NULL)
176 iter->item = iter->item->next;
177 if (iter->item == NULL) {
178 if (iter->initialized)
179 iter->bin++;
180 else
181 iter->initialized = 1;
182 if (iter->bin < hash->bin_count)
183 iter->item = hash->bins[iter->bin];
184 }
185 if (iter->item != NULL && iter->item->key_type == ITEMTYPE_UINT64) {
186 *key = *(uint64_t*)iter->item->key;
187 return 0;
188 }
189 }
190 return 1;
191 }
192
193 int c_rhash_iter_str_keys(c_rhash hash, c_rhash_iter_t *iter, const char **key) {
194 while (iter->bin < hash->bin_count) {
195 if (iter->item != NULL)
196 iter->item = iter->item->next;
197 if (iter->item == NULL) {
198 if (iter->initialized)
199 iter->bin++;
200 else
201 iter->initialized = 1;
202 if (iter->bin < hash->bin_count)
203 iter->item = hash->bins[iter->bin];
204 }
205 if (iter->item != NULL && iter->item->key_type == ITEMTYPE_STRING) {
206 *key = (const char*)iter->item->key;
207 return 0;
208 }
209 }
210 return 1;
211 }
212
213 void c_rhash_destroy(c_rhash hash) {
214 for (size_t i = 0; i < hash->bin_count; i++) {
215 if (hash->bins[i] != NULL)
216 c_rhash_destroy_bin(hash->bins[i]);
217 }
218 freez(hash);
219 }