• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_strvp.h"
29 
30 struct ares_htable_strvp {
31   ares_htable_strvp_val_free_t free_val;
32   ares_htable_t               *hash;
33 };
34 
35 typedef struct {
36   char                *key;
37   void                *val;
38   ares_htable_strvp_t *parent;
39 } ares_htable_strvp_bucket_t;
40 
ares_htable_strvp_destroy(ares_htable_strvp_t * htable)41 void ares_htable_strvp_destroy(ares_htable_strvp_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 char *arg = key;
54   return ares_htable_hash_FNV1a_casecmp((const unsigned char *)arg,
55                                         ares_strlen(arg), seed);
56 }
57 
bucket_key(const void * bucket)58 static const void *bucket_key(const void *bucket)
59 {
60   const ares_htable_strvp_bucket_t *arg = bucket;
61   return arg->key;
62 }
63 
bucket_free(void * bucket)64 static void bucket_free(void *bucket)
65 {
66   ares_htable_strvp_bucket_t *arg = bucket;
67 
68   if (arg->parent->free_val) {
69     arg->parent->free_val(arg->val);
70   }
71   ares_free(arg->key);
72   ares_free(arg);
73 }
74 
key_eq(const void * key1,const void * key2)75 static ares_bool_t key_eq(const void *key1, const void *key2)
76 {
77   return ares_strcaseeq(key1, key2);
78 }
79 
80 ares_htable_strvp_t *
ares_htable_strvp_create(ares_htable_strvp_val_free_t val_free)81   ares_htable_strvp_create(ares_htable_strvp_val_free_t val_free)
82 {
83   ares_htable_strvp_t *htable = ares_malloc(sizeof(*htable));
84   if (htable == NULL) {
85     goto fail;
86   }
87 
88   htable->hash = ares_htable_create(hash_func, bucket_key, bucket_free, key_eq);
89   if (htable->hash == NULL) {
90     goto fail;
91   }
92 
93   htable->free_val = val_free;
94 
95   return htable;
96 
97 fail:
98   if (htable) {
99     ares_htable_destroy(htable->hash);
100     ares_free(htable);
101   }
102   return NULL;
103 }
104 
ares_htable_strvp_insert(ares_htable_strvp_t * htable,const char * key,void * val)105 ares_bool_t ares_htable_strvp_insert(ares_htable_strvp_t *htable,
106                                      const char *key, void *val)
107 {
108   ares_htable_strvp_bucket_t *bucket = NULL;
109 
110   if (htable == NULL || key == NULL) {
111     goto fail;
112   }
113 
114   bucket = ares_malloc(sizeof(*bucket));
115   if (bucket == NULL) {
116     goto fail;
117   }
118 
119   bucket->parent = htable;
120   bucket->key    = ares_strdup(key);
121   if (bucket->key == NULL) {
122     goto fail;
123   }
124   bucket->val = val;
125 
126   if (!ares_htable_insert(htable->hash, bucket)) {
127     goto fail;
128   }
129 
130   return ARES_TRUE;
131 
132 fail:
133   if (bucket) {
134     ares_free(bucket->key);
135     ares_free(bucket);
136   }
137   return ARES_FALSE;
138 }
139 
ares_htable_strvp_get(const ares_htable_strvp_t * htable,const char * key,void ** val)140 ares_bool_t ares_htable_strvp_get(const ares_htable_strvp_t *htable,
141                                   const char *key, void **val)
142 {
143   ares_htable_strvp_bucket_t *bucket = NULL;
144 
145   if (val) {
146     *val = NULL;
147   }
148 
149   if (htable == NULL || key == NULL) {
150     return ARES_FALSE;
151   }
152 
153   bucket = ares_htable_get(htable->hash, key);
154   if (bucket == NULL) {
155     return ARES_FALSE;
156   }
157 
158   if (val) {
159     *val = bucket->val;
160   }
161   return ARES_TRUE;
162 }
163 
ares_htable_strvp_get_direct(const ares_htable_strvp_t * htable,const char * key)164 void *ares_htable_strvp_get_direct(const ares_htable_strvp_t *htable,
165                                    const char                *key)
166 {
167   void *val = NULL;
168   ares_htable_strvp_get(htable, key, &val);
169   return val;
170 }
171 
ares_htable_strvp_remove(ares_htable_strvp_t * htable,const char * key)172 ares_bool_t ares_htable_strvp_remove(ares_htable_strvp_t *htable,
173                                      const char          *key)
174 {
175   if (htable == NULL) {
176     return ARES_FALSE;
177   }
178 
179   return ares_htable_remove(htable->hash, key);
180 }
181 
ares_htable_strvp_claim(ares_htable_strvp_t * htable,const char * key)182 void *ares_htable_strvp_claim(ares_htable_strvp_t *htable, const char *key)
183 {
184   ares_htable_strvp_bucket_t *bucket = NULL;
185   void                       *val;
186 
187   if (htable == NULL || key == NULL) {
188     return NULL;
189   }
190 
191   bucket = ares_htable_get(htable->hash, key);
192   if (bucket == NULL) {
193     return NULL;
194   }
195 
196   /* Unassociate value from bucket */
197   val         = bucket->val;
198   bucket->val = NULL;
199 
200   ares_htable_strvp_remove(htable, key);
201   return val;
202 }
203 
ares_htable_strvp_num_keys(const ares_htable_strvp_t * htable)204 size_t ares_htable_strvp_num_keys(const ares_htable_strvp_t *htable)
205 {
206   if (htable == NULL) {
207     return 0;
208   }
209   return ares_htable_num_keys(htable->hash);
210 }
211