1 /* MIT License
2 *
3 * Copyright (c) 2023 Brad House
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 *
24 * SPDX-License-Identifier: MIT
25 */
26 #include "ares_private.h"
27 #include "ares_htable.h"
28 #include "ares_htable_asvp.h"
29
30 struct ares_htable_asvp {
31 ares_htable_asvp_val_free_t free_val;
32 ares_htable_t *hash;
33 };
34
35 typedef struct {
36 ares_socket_t key;
37 void *val;
38 ares_htable_asvp_t *parent;
39 } ares_htable_asvp_bucket_t;
40
ares_htable_asvp_destroy(ares_htable_asvp_t * htable)41 void ares_htable_asvp_destroy(ares_htable_asvp_t *htable)
42 {
43 if (htable == NULL) {
44 return;
45 }
46
47 ares_htable_destroy(htable->hash);
48 ares_free(htable);
49 }
50
hash_func(const void * key,unsigned int seed)51 static unsigned int hash_func(const void *key, unsigned int seed)
52 {
53 const ares_socket_t *arg = key;
54 return ares_htable_hash_FNV1a((const unsigned char *)arg, sizeof(*arg), seed);
55 }
56
bucket_key(const void * bucket)57 static const void *bucket_key(const void *bucket)
58 {
59 const ares_htable_asvp_bucket_t *arg = bucket;
60 return &arg->key;
61 }
62
bucket_free(void * bucket)63 static void bucket_free(void *bucket)
64 {
65 ares_htable_asvp_bucket_t *arg = bucket;
66
67 if (arg->parent->free_val) {
68 arg->parent->free_val(arg->val);
69 }
70
71 ares_free(arg);
72 }
73
key_eq(const void * key1,const void * key2)74 static ares_bool_t key_eq(const void *key1, const void *key2)
75 {
76 const ares_socket_t *k1 = key1;
77 const ares_socket_t *k2 = key2;
78
79 if (*k1 == *k2) {
80 return ARES_TRUE;
81 }
82
83 return ARES_FALSE;
84 }
85
86 ares_htable_asvp_t *
ares_htable_asvp_create(ares_htable_asvp_val_free_t val_free)87 ares_htable_asvp_create(ares_htable_asvp_val_free_t val_free)
88 {
89 ares_htable_asvp_t *htable = ares_malloc(sizeof(*htable));
90 if (htable == NULL) {
91 goto fail;
92 }
93
94 htable->hash = ares_htable_create(hash_func, bucket_key, bucket_free, key_eq);
95 if (htable->hash == NULL) {
96 goto fail;
97 }
98
99 htable->free_val = val_free;
100
101 return htable;
102
103 fail:
104 if (htable) {
105 ares_htable_destroy(htable->hash);
106 ares_free(htable);
107 }
108 return NULL;
109 }
110
ares_htable_asvp_keys(const ares_htable_asvp_t * htable,size_t * num)111 ares_socket_t *ares_htable_asvp_keys(const ares_htable_asvp_t *htable,
112 size_t *num)
113 {
114 const void **buckets = NULL;
115 size_t cnt = 0;
116 ares_socket_t *out = NULL;
117 size_t i;
118
119 if (htable == NULL || num == NULL) {
120 return NULL; /* LCOV_EXCL_LINE: DefensiveCoding */
121 }
122
123 *num = 0;
124
125 buckets = ares_htable_all_buckets(htable->hash, &cnt);
126 if (buckets == NULL || cnt == 0) {
127 return NULL;
128 }
129
130 out = ares_malloc_zero(sizeof(*out) * cnt);
131 if (out == NULL) {
132 ares_free(buckets); /* LCOV_EXCL_LINE: OutOfMemory */
133 return NULL; /* LCOV_EXCL_LINE: OutOfMemory */
134 }
135
136 for (i = 0; i < cnt; i++) {
137 out[i] = ((const ares_htable_asvp_bucket_t *)buckets[i])->key;
138 }
139
140 ares_free(buckets);
141 *num = cnt;
142 return out;
143 }
144
ares_htable_asvp_insert(ares_htable_asvp_t * htable,ares_socket_t key,void * val)145 ares_bool_t ares_htable_asvp_insert(ares_htable_asvp_t *htable,
146 ares_socket_t key, void *val)
147 {
148 ares_htable_asvp_bucket_t *bucket = NULL;
149
150 if (htable == NULL) {
151 goto fail;
152 }
153
154 bucket = ares_malloc(sizeof(*bucket));
155 if (bucket == NULL) {
156 goto fail; /* LCOV_EXCL_LINE: OutOfMemory */
157 }
158
159 bucket->parent = htable;
160 bucket->key = key;
161 bucket->val = val;
162
163 if (!ares_htable_insert(htable->hash, bucket)) {
164 goto fail; /* LCOV_EXCL_LINE: OutOfMemory */
165 }
166
167 return ARES_TRUE;
168
169 fail:
170 if (bucket) {
171 ares_free(bucket); /* LCOV_EXCL_LINE: OutOfMemory */
172 }
173 return ARES_FALSE;
174 }
175
ares_htable_asvp_get(const ares_htable_asvp_t * htable,ares_socket_t key,void ** val)176 ares_bool_t ares_htable_asvp_get(const ares_htable_asvp_t *htable,
177 ares_socket_t key, void **val)
178 {
179 ares_htable_asvp_bucket_t *bucket = NULL;
180
181 if (val) {
182 *val = NULL;
183 }
184
185 if (htable == NULL) {
186 return ARES_FALSE;
187 }
188
189 bucket = ares_htable_get(htable->hash, &key);
190 if (bucket == NULL) {
191 return ARES_FALSE;
192 }
193
194 if (val) {
195 *val = bucket->val;
196 }
197 return ARES_TRUE;
198 }
199
ares_htable_asvp_get_direct(const ares_htable_asvp_t * htable,ares_socket_t key)200 void *ares_htable_asvp_get_direct(const ares_htable_asvp_t *htable,
201 ares_socket_t key)
202 {
203 void *val = NULL;
204 ares_htable_asvp_get(htable, key, &val);
205 return val;
206 }
207
ares_htable_asvp_remove(ares_htable_asvp_t * htable,ares_socket_t key)208 ares_bool_t ares_htable_asvp_remove(ares_htable_asvp_t *htable,
209 ares_socket_t key)
210 {
211 if (htable == NULL) {
212 return ARES_FALSE;
213 }
214
215 return ares_htable_remove(htable->hash, &key);
216 }
217
ares_htable_asvp_num_keys(const ares_htable_asvp_t * htable)218 size_t ares_htable_asvp_num_keys(const ares_htable_asvp_t *htable)
219 {
220 if (htable == NULL) {
221 return 0;
222 }
223 return ares_htable_num_keys(htable->hash);
224 }
225