quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

ares_htable_dict.c (5327B)


      1 /* MIT License
      2  *
      3  * Copyright (c) 2024 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_dict.h"
     29 
     30 struct ares_htable_dict {
     31   ares_htable_t *hash;
     32 };
     33 
     34 typedef struct {
     35   char               *key;
     36   char               *val;
     37   ares_htable_dict_t *parent;
     38 } ares_htable_dict_bucket_t;
     39 
     40 void ares_htable_dict_destroy(ares_htable_dict_t *htable)
     41 {
     42   if (htable == NULL) {
     43     return; /* LCOV_EXCL_LINE: DefensiveCoding */
     44   }
     45 
     46   ares_htable_destroy(htable->hash);
     47   ares_free(htable);
     48 }
     49 
     50 static unsigned int hash_func(const void *key, unsigned int seed)
     51 {
     52   return ares_htable_hash_FNV1a_casecmp(key, ares_strlen(key), seed);
     53 }
     54 
     55 static const void *bucket_key(const void *bucket)
     56 {
     57   const ares_htable_dict_bucket_t *arg = bucket;
     58   return arg->key;
     59 }
     60 
     61 static void bucket_free(void *bucket)
     62 {
     63   ares_htable_dict_bucket_t *arg = bucket;
     64 
     65   ares_free(arg->key);
     66   ares_free(arg->val);
     67 
     68   ares_free(arg);
     69 }
     70 
     71 static ares_bool_t key_eq(const void *key1, const void *key2)
     72 {
     73   return ares_strcaseeq(key1, key2);
     74 }
     75 
     76 ares_htable_dict_t *ares_htable_dict_create(void)
     77 {
     78   ares_htable_dict_t *htable = ares_malloc(sizeof(*htable));
     79   if (htable == NULL) {
     80     goto fail; /* LCOV_EXCL_LINE: OutOfMemory */
     81   }
     82 
     83   htable->hash = ares_htable_create(hash_func, bucket_key, bucket_free, key_eq);
     84   if (htable->hash == NULL) {
     85     goto fail; /* LCOV_EXCL_LINE: OutOfMemory */
     86   }
     87 
     88   return htable;
     89 
     90 /* LCOV_EXCL_START: OutOfMemory */
     91 fail:
     92   if (htable) {
     93     ares_htable_destroy(htable->hash);
     94     ares_free(htable);
     95   }
     96   return NULL;
     97   /* LCOV_EXCL_STOP */
     98 }
     99 
    100 ares_bool_t ares_htable_dict_insert(ares_htable_dict_t *htable, const char *key,
    101                                     const char *val)
    102 {
    103   ares_htable_dict_bucket_t *bucket = NULL;
    104 
    105   if (htable == NULL || ares_strlen(key) == 0) {
    106     goto fail;
    107   }
    108 
    109   bucket = ares_malloc_zero(sizeof(*bucket));
    110   if (bucket == NULL) {
    111     goto fail;
    112   }
    113 
    114   bucket->parent = htable;
    115   bucket->key    = ares_strdup(key);
    116   if (bucket->key == NULL) {
    117     goto fail;
    118   }
    119 
    120   if (val != NULL) {
    121     bucket->val = ares_strdup(val);
    122     if (bucket->val == NULL) {
    123       goto fail;
    124     }
    125   }
    126 
    127   if (!ares_htable_insert(htable->hash, bucket)) {
    128     goto fail;
    129   }
    130 
    131   return ARES_TRUE;
    132 
    133 fail:
    134   if (bucket) {
    135     ares_free(bucket->val);
    136     ares_free(bucket);
    137   }
    138   return ARES_FALSE;
    139 }
    140 
    141 ares_bool_t ares_htable_dict_get(const ares_htable_dict_t *htable,
    142                                  const char *key, const char **val)
    143 {
    144   const ares_htable_dict_bucket_t *bucket = NULL;
    145 
    146   if (val) {
    147     *val = NULL;
    148   }
    149 
    150   if (htable == NULL) {
    151     return ARES_FALSE;
    152   }
    153 
    154   bucket = ares_htable_get(htable->hash, key);
    155   if (bucket == NULL) {
    156     return ARES_FALSE;
    157   }
    158 
    159   if (val) {
    160     *val = bucket->val;
    161   }
    162   return ARES_TRUE;
    163 }
    164 
    165 const char *ares_htable_dict_get_direct(const ares_htable_dict_t *htable,
    166                                         const char               *key)
    167 {
    168   const char *val = NULL;
    169   ares_htable_dict_get(htable, key, &val);
    170   return val;
    171 }
    172 
    173 ares_bool_t ares_htable_dict_remove(ares_htable_dict_t *htable, const char *key)
    174 {
    175   if (htable == NULL) {
    176     return ARES_FALSE;
    177   }
    178 
    179   return ares_htable_remove(htable->hash, key);
    180 }
    181 
    182 size_t ares_htable_dict_num_keys(const ares_htable_dict_t *htable)
    183 {
    184   if (htable == NULL) {
    185     return 0;
    186   }
    187   return ares_htable_num_keys(htable->hash);
    188 }
    189 
    190 char **ares_htable_dict_keys(const ares_htable_dict_t *htable, size_t *num)
    191 {
    192   const void **buckets = NULL;
    193   size_t       cnt     = 0;
    194   char       **out     = NULL;
    195   size_t       i;
    196 
    197   if (htable == NULL || num == NULL) {
    198     return NULL; /* LCOV_EXCL_LINE: DefensiveCoding */
    199   }
    200 
    201   *num = 0;
    202 
    203   buckets = ares_htable_all_buckets(htable->hash, &cnt);
    204   if (buckets == NULL || cnt == 0) {
    205     return NULL;
    206   }
    207 
    208   out = ares_malloc_zero(sizeof(*out) * cnt);
    209   if (out == NULL) {
    210     goto fail; /* LCOV_EXCL_LINE: OutOfMemory */
    211   }
    212 
    213   for (i = 0; i < cnt; i++) {
    214     out[i] = ares_strdup(((const ares_htable_dict_bucket_t *)buckets[i])->key);
    215     if (out[i] == NULL) {
    216       goto fail;
    217     }
    218   }
    219 
    220   ares_free(buckets);
    221   *num = cnt;
    222   return out;
    223 
    224 fail:
    225   *num = 0;
    226   ares_free_array(out, cnt, ares_free);
    227   return NULL;
    228 }