11cb0ef41Sopenharmony_ci/* MIT License
21cb0ef41Sopenharmony_ci *
31cb0ef41Sopenharmony_ci * Copyright (c) 2023 Brad House
41cb0ef41Sopenharmony_ci *
51cb0ef41Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
61cb0ef41Sopenharmony_ci * of this software and associated documentation files (the "Software"), to deal
71cb0ef41Sopenharmony_ci * in the Software without restriction, including without limitation the rights
81cb0ef41Sopenharmony_ci * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
91cb0ef41Sopenharmony_ci * copies of the Software, and to permit persons to whom the Software is
101cb0ef41Sopenharmony_ci * furnished to do so, subject to the following conditions:
111cb0ef41Sopenharmony_ci *
121cb0ef41Sopenharmony_ci * The above copyright notice and this permission notice (including the next
131cb0ef41Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
141cb0ef41Sopenharmony_ci * Software.
151cb0ef41Sopenharmony_ci *
161cb0ef41Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
171cb0ef41Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
181cb0ef41Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
191cb0ef41Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
201cb0ef41Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
211cb0ef41Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
221cb0ef41Sopenharmony_ci * SOFTWARE.
231cb0ef41Sopenharmony_ci *
241cb0ef41Sopenharmony_ci * SPDX-License-Identifier: MIT
251cb0ef41Sopenharmony_ci */
261cb0ef41Sopenharmony_ci#include "ares_setup.h"
271cb0ef41Sopenharmony_ci#include "ares.h"
281cb0ef41Sopenharmony_ci#include "ares_private.h"
291cb0ef41Sopenharmony_ci#include "ares__htable.h"
301cb0ef41Sopenharmony_ci#include "ares__htable_asvp.h"
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_cistruct ares__htable_asvp {
331cb0ef41Sopenharmony_ci  ares__htable_asvp_val_free_t free_val;
341cb0ef41Sopenharmony_ci  ares__htable_t              *hash;
351cb0ef41Sopenharmony_ci};
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_citypedef struct {
381cb0ef41Sopenharmony_ci  ares_socket_t        key;
391cb0ef41Sopenharmony_ci  void                *val;
401cb0ef41Sopenharmony_ci  ares__htable_asvp_t *parent;
411cb0ef41Sopenharmony_ci} ares__htable_asvp_bucket_t;
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_civoid ares__htable_asvp_destroy(ares__htable_asvp_t *htable)
441cb0ef41Sopenharmony_ci{
451cb0ef41Sopenharmony_ci  if (htable == NULL) {
461cb0ef41Sopenharmony_ci    return;
471cb0ef41Sopenharmony_ci  }
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ci  ares__htable_destroy(htable->hash);
501cb0ef41Sopenharmony_ci  ares_free(htable);
511cb0ef41Sopenharmony_ci}
521cb0ef41Sopenharmony_ci
531cb0ef41Sopenharmony_cistatic unsigned int hash_func(const void *key, unsigned int seed)
541cb0ef41Sopenharmony_ci{
551cb0ef41Sopenharmony_ci  const ares_socket_t *arg = key;
561cb0ef41Sopenharmony_ci  return ares__htable_hash_FNV1a((const unsigned char *)arg, sizeof(*arg),
571cb0ef41Sopenharmony_ci                                 seed);
581cb0ef41Sopenharmony_ci}
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_cistatic const void *bucket_key(const void *bucket)
611cb0ef41Sopenharmony_ci{
621cb0ef41Sopenharmony_ci  const ares__htable_asvp_bucket_t *arg = bucket;
631cb0ef41Sopenharmony_ci  return &arg->key;
641cb0ef41Sopenharmony_ci}
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_cistatic void bucket_free(void *bucket)
671cb0ef41Sopenharmony_ci{
681cb0ef41Sopenharmony_ci  ares__htable_asvp_bucket_t *arg = bucket;
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ci  if (arg->parent->free_val) {
711cb0ef41Sopenharmony_ci    arg->parent->free_val(arg->val);
721cb0ef41Sopenharmony_ci  }
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ci  ares_free(arg);
751cb0ef41Sopenharmony_ci}
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_cistatic ares_bool_t key_eq(const void *key1, const void *key2)
781cb0ef41Sopenharmony_ci{
791cb0ef41Sopenharmony_ci  const ares_socket_t *k1 = key1;
801cb0ef41Sopenharmony_ci  const ares_socket_t *k2 = key2;
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_ci  if (*k1 == *k2) {
831cb0ef41Sopenharmony_ci    return ARES_TRUE;
841cb0ef41Sopenharmony_ci  }
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_ci  return ARES_FALSE;
871cb0ef41Sopenharmony_ci}
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_ciares__htable_asvp_t *
901cb0ef41Sopenharmony_ci  ares__htable_asvp_create(ares__htable_asvp_val_free_t val_free)
911cb0ef41Sopenharmony_ci{
921cb0ef41Sopenharmony_ci  ares__htable_asvp_t *htable = ares_malloc(sizeof(*htable));
931cb0ef41Sopenharmony_ci  if (htable == NULL) {
941cb0ef41Sopenharmony_ci    goto fail;
951cb0ef41Sopenharmony_ci  }
961cb0ef41Sopenharmony_ci
971cb0ef41Sopenharmony_ci  htable->hash =
981cb0ef41Sopenharmony_ci    ares__htable_create(hash_func, bucket_key, bucket_free, key_eq);
991cb0ef41Sopenharmony_ci  if (htable->hash == NULL) {
1001cb0ef41Sopenharmony_ci    goto fail;
1011cb0ef41Sopenharmony_ci  }
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ci  htable->free_val = val_free;
1041cb0ef41Sopenharmony_ci
1051cb0ef41Sopenharmony_ci  return htable;
1061cb0ef41Sopenharmony_ci
1071cb0ef41Sopenharmony_cifail:
1081cb0ef41Sopenharmony_ci  if (htable) {
1091cb0ef41Sopenharmony_ci    ares__htable_destroy(htable->hash);
1101cb0ef41Sopenharmony_ci    ares_free(htable);
1111cb0ef41Sopenharmony_ci  }
1121cb0ef41Sopenharmony_ci  return NULL;
1131cb0ef41Sopenharmony_ci}
1141cb0ef41Sopenharmony_ci
1151cb0ef41Sopenharmony_ciares_socket_t *ares__htable_asvp_keys(const ares__htable_asvp_t *htable,
1161cb0ef41Sopenharmony_ci                                      size_t                    *num)
1171cb0ef41Sopenharmony_ci{
1181cb0ef41Sopenharmony_ci  const void   **buckets = NULL;
1191cb0ef41Sopenharmony_ci  size_t         cnt     = 0;
1201cb0ef41Sopenharmony_ci  ares_socket_t *out     = NULL;
1211cb0ef41Sopenharmony_ci  size_t         i;
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci  if (htable == NULL || num == NULL) {
1241cb0ef41Sopenharmony_ci    return NULL;
1251cb0ef41Sopenharmony_ci  }
1261cb0ef41Sopenharmony_ci
1271cb0ef41Sopenharmony_ci  *num = 0;
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ci  buckets = ares__htable_all_buckets(htable->hash, &cnt);
1301cb0ef41Sopenharmony_ci  if (buckets == NULL || cnt == 0) {
1311cb0ef41Sopenharmony_ci    return NULL;
1321cb0ef41Sopenharmony_ci  }
1331cb0ef41Sopenharmony_ci
1341cb0ef41Sopenharmony_ci  out = ares_malloc_zero(sizeof(*out) * cnt);
1351cb0ef41Sopenharmony_ci  if (out == NULL) {
1361cb0ef41Sopenharmony_ci    ares_free(buckets);
1371cb0ef41Sopenharmony_ci    return NULL;
1381cb0ef41Sopenharmony_ci  }
1391cb0ef41Sopenharmony_ci
1401cb0ef41Sopenharmony_ci  for (i = 0; i < cnt; i++) {
1411cb0ef41Sopenharmony_ci    out[i] = ((const ares__htable_asvp_bucket_t *)buckets[i])->key;
1421cb0ef41Sopenharmony_ci  }
1431cb0ef41Sopenharmony_ci
1441cb0ef41Sopenharmony_ci  ares_free(buckets);
1451cb0ef41Sopenharmony_ci  *num = cnt;
1461cb0ef41Sopenharmony_ci  return out;
1471cb0ef41Sopenharmony_ci}
1481cb0ef41Sopenharmony_ci
1491cb0ef41Sopenharmony_ciares_bool_t ares__htable_asvp_insert(ares__htable_asvp_t *htable,
1501cb0ef41Sopenharmony_ci                                     ares_socket_t key, void *val)
1511cb0ef41Sopenharmony_ci{
1521cb0ef41Sopenharmony_ci  ares__htable_asvp_bucket_t *bucket = NULL;
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_ci  if (htable == NULL) {
1551cb0ef41Sopenharmony_ci    goto fail;
1561cb0ef41Sopenharmony_ci  }
1571cb0ef41Sopenharmony_ci
1581cb0ef41Sopenharmony_ci  bucket = ares_malloc(sizeof(*bucket));
1591cb0ef41Sopenharmony_ci  if (bucket == NULL) {
1601cb0ef41Sopenharmony_ci    goto fail;
1611cb0ef41Sopenharmony_ci  }
1621cb0ef41Sopenharmony_ci
1631cb0ef41Sopenharmony_ci  bucket->parent = htable;
1641cb0ef41Sopenharmony_ci  bucket->key    = key;
1651cb0ef41Sopenharmony_ci  bucket->val    = val;
1661cb0ef41Sopenharmony_ci
1671cb0ef41Sopenharmony_ci  if (!ares__htable_insert(htable->hash, bucket)) {
1681cb0ef41Sopenharmony_ci    goto fail;
1691cb0ef41Sopenharmony_ci  }
1701cb0ef41Sopenharmony_ci
1711cb0ef41Sopenharmony_ci  return ARES_TRUE;
1721cb0ef41Sopenharmony_ci
1731cb0ef41Sopenharmony_cifail:
1741cb0ef41Sopenharmony_ci  if (bucket) {
1751cb0ef41Sopenharmony_ci    ares_free(bucket);
1761cb0ef41Sopenharmony_ci  }
1771cb0ef41Sopenharmony_ci  return ARES_FALSE;
1781cb0ef41Sopenharmony_ci}
1791cb0ef41Sopenharmony_ci
1801cb0ef41Sopenharmony_ciares_bool_t ares__htable_asvp_get(const ares__htable_asvp_t *htable,
1811cb0ef41Sopenharmony_ci                                  ares_socket_t key, void **val)
1821cb0ef41Sopenharmony_ci{
1831cb0ef41Sopenharmony_ci  ares__htable_asvp_bucket_t *bucket = NULL;
1841cb0ef41Sopenharmony_ci
1851cb0ef41Sopenharmony_ci  if (val) {
1861cb0ef41Sopenharmony_ci    *val = NULL;
1871cb0ef41Sopenharmony_ci  }
1881cb0ef41Sopenharmony_ci
1891cb0ef41Sopenharmony_ci  if (htable == NULL) {
1901cb0ef41Sopenharmony_ci    return ARES_FALSE;
1911cb0ef41Sopenharmony_ci  }
1921cb0ef41Sopenharmony_ci
1931cb0ef41Sopenharmony_ci  bucket = ares__htable_get(htable->hash, &key);
1941cb0ef41Sopenharmony_ci  if (bucket == NULL) {
1951cb0ef41Sopenharmony_ci    return ARES_FALSE;
1961cb0ef41Sopenharmony_ci  }
1971cb0ef41Sopenharmony_ci
1981cb0ef41Sopenharmony_ci  if (val) {
1991cb0ef41Sopenharmony_ci    *val = bucket->val;
2001cb0ef41Sopenharmony_ci  }
2011cb0ef41Sopenharmony_ci  return ARES_TRUE;
2021cb0ef41Sopenharmony_ci}
2031cb0ef41Sopenharmony_ci
2041cb0ef41Sopenharmony_civoid *ares__htable_asvp_get_direct(const ares__htable_asvp_t *htable,
2051cb0ef41Sopenharmony_ci                                   ares_socket_t              key)
2061cb0ef41Sopenharmony_ci{
2071cb0ef41Sopenharmony_ci  void *val = NULL;
2081cb0ef41Sopenharmony_ci  ares__htable_asvp_get(htable, key, &val);
2091cb0ef41Sopenharmony_ci  return val;
2101cb0ef41Sopenharmony_ci}
2111cb0ef41Sopenharmony_ci
2121cb0ef41Sopenharmony_ciares_bool_t ares__htable_asvp_remove(ares__htable_asvp_t *htable,
2131cb0ef41Sopenharmony_ci                                     ares_socket_t        key)
2141cb0ef41Sopenharmony_ci{
2151cb0ef41Sopenharmony_ci  if (htable == NULL) {
2161cb0ef41Sopenharmony_ci    return ARES_FALSE;
2171cb0ef41Sopenharmony_ci  }
2181cb0ef41Sopenharmony_ci
2191cb0ef41Sopenharmony_ci  return ares__htable_remove(htable->hash, &key);
2201cb0ef41Sopenharmony_ci}
2211cb0ef41Sopenharmony_ci
2221cb0ef41Sopenharmony_cisize_t ares__htable_asvp_num_keys(const ares__htable_asvp_t *htable)
2231cb0ef41Sopenharmony_ci{
2241cb0ef41Sopenharmony_ci  if (htable == NULL) {
2251cb0ef41Sopenharmony_ci    return 0;
2261cb0ef41Sopenharmony_ci  }
2271cb0ef41Sopenharmony_ci  return ares__htable_num_keys(htable->hash);
2281cb0ef41Sopenharmony_ci}
229