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#ifndef __ARES__HTABLE_H
271cb0ef41Sopenharmony_ci#define __ARES__HTABLE_H
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ci/*! \addtogroup ares__htable Base HashTable Data Structure
311cb0ef41Sopenharmony_ci *
321cb0ef41Sopenharmony_ci * This is a basic hashtable data structure that is meant to be wrapped
331cb0ef41Sopenharmony_ci * by a higher level implementation.  This data structure is designed to
341cb0ef41Sopenharmony_ci * be callback-based in order to facilitate wrapping without needing to
351cb0ef41Sopenharmony_ci * worry about any underlying complexities of the hashtable implementation.
361cb0ef41Sopenharmony_ci *
371cb0ef41Sopenharmony_ci * This implementation supports automatic growing by powers of 2 when reaching
381cb0ef41Sopenharmony_ci * 75% capacity.  A rehash will be performed on the expanded bucket list.
391cb0ef41Sopenharmony_ci *
401cb0ef41Sopenharmony_ci * Average time complexity:
411cb0ef41Sopenharmony_ci *  - Insert: O(1)
421cb0ef41Sopenharmony_ci *  - Search: O(1)
431cb0ef41Sopenharmony_ci *  - Delete: O(1)
441cb0ef41Sopenharmony_ci *
451cb0ef41Sopenharmony_ci * @{
461cb0ef41Sopenharmony_ci */
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_cistruct ares__htable;
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ci/*! Opaque data type for generic hash table implementation */
511cb0ef41Sopenharmony_citypedef struct ares__htable ares__htable_t;
521cb0ef41Sopenharmony_ci
531cb0ef41Sopenharmony_ci/*! Callback for generating a hash of the key.
541cb0ef41Sopenharmony_ci *
551cb0ef41Sopenharmony_ci *  \param[in] key   pointer to key to be hashed
561cb0ef41Sopenharmony_ci *  \param[in] seed  randomly generated seed used by hash function.
571cb0ef41Sopenharmony_ci *                   value is specific to the hashtable instance
581cb0ef41Sopenharmony_ci *                   but otherwise will not change between calls.
591cb0ef41Sopenharmony_ci *  \return hash
601cb0ef41Sopenharmony_ci */
611cb0ef41Sopenharmony_citypedef unsigned int        (*ares__htable_hashfunc_t)(const void  *key,
621cb0ef41Sopenharmony_ci                                                unsigned int seed);
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_ci/*! Callback to free the bucket
651cb0ef41Sopenharmony_ci *
661cb0ef41Sopenharmony_ci *  \param[in] bucket  user provided bucket
671cb0ef41Sopenharmony_ci */
681cb0ef41Sopenharmony_citypedef void                (*ares__htable_bucket_free_t)(void *bucket);
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ci/*! Callback to extract the key from the user-provided bucket
711cb0ef41Sopenharmony_ci *
721cb0ef41Sopenharmony_ci *  \param[in] bucket  user provided bucket
731cb0ef41Sopenharmony_ci *  \return pointer to key held in bucket
741cb0ef41Sopenharmony_ci */
751cb0ef41Sopenharmony_citypedef const void         *(*ares__htable_bucket_key_t)(const void *bucket);
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_ci/*! Callback to compare two keys for equality
781cb0ef41Sopenharmony_ci *
791cb0ef41Sopenharmony_ci *  \param[in] key1  first key
801cb0ef41Sopenharmony_ci *  \param[in] key2  second key
811cb0ef41Sopenharmony_ci *  \return ARES_TRUE if equal, ARES_FALSE if not
821cb0ef41Sopenharmony_ci */
831cb0ef41Sopenharmony_citypedef ares_bool_t         (*ares__htable_key_eq_t)(const void *key1,
841cb0ef41Sopenharmony_ci                                             const void *key2);
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci/*! Destroy the initialized hashtable
881cb0ef41Sopenharmony_ci *
891cb0ef41Sopenharmony_ci *  \param[in] initialized hashtable
901cb0ef41Sopenharmony_ci */
911cb0ef41Sopenharmony_civoid                        ares__htable_destroy(ares__htable_t *htable);
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_ci/*! Create a new hashtable
941cb0ef41Sopenharmony_ci *
951cb0ef41Sopenharmony_ci *  \param[in] hash_func   Required. Callback for Hash function.
961cb0ef41Sopenharmony_ci *  \param[in] bucket_key  Required. Callback to extract key from bucket.
971cb0ef41Sopenharmony_ci *  \param[in] bucket_free Required. Callback to free bucket.
981cb0ef41Sopenharmony_ci *  \param[in] key_eq      Required. Callback to check for key equality.
991cb0ef41Sopenharmony_ci *  \return initialized hashtable.  NULL if out of memory or misuse.
1001cb0ef41Sopenharmony_ci */
1011cb0ef41Sopenharmony_ciares__htable_t *ares__htable_create(ares__htable_hashfunc_t    hash_func,
1021cb0ef41Sopenharmony_ci                                    ares__htable_bucket_key_t  bucket_key,
1031cb0ef41Sopenharmony_ci                                    ares__htable_bucket_free_t bucket_free,
1041cb0ef41Sopenharmony_ci                                    ares__htable_key_eq_t      key_eq);
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_ci/*! Count of keys from initialized hashtable
1071cb0ef41Sopenharmony_ci *
1081cb0ef41Sopenharmony_ci *  \param[in] htable  Initialized hashtable.
1091cb0ef41Sopenharmony_ci *  \return count of keys
1101cb0ef41Sopenharmony_ci */
1111cb0ef41Sopenharmony_cisize_t          ares__htable_num_keys(const ares__htable_t *htable);
1121cb0ef41Sopenharmony_ci
1131cb0ef41Sopenharmony_ci/*! Retrieve an array of buckets from the hashtable.  This is mainly used as
1141cb0ef41Sopenharmony_ci *  a helper for retrieving an array of keys.
1151cb0ef41Sopenharmony_ci *
1161cb0ef41Sopenharmony_ci *  \param[in]  htable   Initialized hashtable
1171cb0ef41Sopenharmony_ci *  \param[out] num      Count of returned buckets
1181cb0ef41Sopenharmony_ci *  \return Array of pointers to the buckets.  These are internal pointers
1191cb0ef41Sopenharmony_ci *          to data within the hashtable, so if the key is removed, there
1201cb0ef41Sopenharmony_ci *          will be a dangling pointer.  It is expected wrappers will make
1211cb0ef41Sopenharmony_ci *          such values safe by duplicating them.
1221cb0ef41Sopenharmony_ci */
1231cb0ef41Sopenharmony_ciconst void    **ares__htable_all_buckets(const ares__htable_t *htable,
1241cb0ef41Sopenharmony_ci                                         size_t               *num);
1251cb0ef41Sopenharmony_ci
1261cb0ef41Sopenharmony_ci/*! Insert bucket into hashtable
1271cb0ef41Sopenharmony_ci *
1281cb0ef41Sopenharmony_ci *  \param[in] htable  Initialized hashtable.
1291cb0ef41Sopenharmony_ci *  \param[in] bucket  User-provided bucket to insert. Takes "ownership". Not
1301cb0ef41Sopenharmony_ci *                     allowed to be NULL.
1311cb0ef41Sopenharmony_ci *  \return ARES_TRUE on success, ARES_FALSE if out of memory
1321cb0ef41Sopenharmony_ci */
1331cb0ef41Sopenharmony_ciares_bool_t     ares__htable_insert(ares__htable_t *htable, void *bucket);
1341cb0ef41Sopenharmony_ci
1351cb0ef41Sopenharmony_ci/*! Retrieve bucket from hashtable based on key.
1361cb0ef41Sopenharmony_ci *
1371cb0ef41Sopenharmony_ci *  \param[in] htable  Initialized hashtable
1381cb0ef41Sopenharmony_ci *  \param[in] key     Pointer to key to use for comparison.
1391cb0ef41Sopenharmony_ci *  \return matching bucket, or NULL if not found.
1401cb0ef41Sopenharmony_ci */
1411cb0ef41Sopenharmony_civoid           *ares__htable_get(const ares__htable_t *htable, const void *key);
1421cb0ef41Sopenharmony_ci
1431cb0ef41Sopenharmony_ci/*! Remove bucket from hashtable by key
1441cb0ef41Sopenharmony_ci *
1451cb0ef41Sopenharmony_ci *  \param[in] htable  Initialized hashtable
1461cb0ef41Sopenharmony_ci *  \param[in] key     Pointer to key to use for comparison
1471cb0ef41Sopenharmony_ci *  \return ARES_TRUE if found, ARES_FALSE if not found
1481cb0ef41Sopenharmony_ci */
1491cb0ef41Sopenharmony_ciares_bool_t     ares__htable_remove(ares__htable_t *htable, const void *key);
1501cb0ef41Sopenharmony_ci
1511cb0ef41Sopenharmony_ci/*! FNV1a hash algorithm.  Can be used as underlying primitive for building
1521cb0ef41Sopenharmony_ci *  a wrapper hashtable.
1531cb0ef41Sopenharmony_ci *
1541cb0ef41Sopenharmony_ci *  \param[in] key      pointer to key
1551cb0ef41Sopenharmony_ci *  \param[in] key_len  Length of key
1561cb0ef41Sopenharmony_ci *  \param[in] seed     Seed for generating hash
1571cb0ef41Sopenharmony_ci *  \return hash value
1581cb0ef41Sopenharmony_ci */
1591cb0ef41Sopenharmony_ciunsigned int ares__htable_hash_FNV1a(const unsigned char *key, size_t key_len,
1601cb0ef41Sopenharmony_ci                                     unsigned int seed);
1611cb0ef41Sopenharmony_ci
1621cb0ef41Sopenharmony_ci/*! FNV1a hash algorithm, but converts all characters to lowercase before
1631cb0ef41Sopenharmony_ci *  hashing to make the hash case-insensitive. Can be used as underlying
1641cb0ef41Sopenharmony_ci *  primitive for building a wrapper hashtable.  Used on string-based keys.
1651cb0ef41Sopenharmony_ci *
1661cb0ef41Sopenharmony_ci *  \param[in] key      pointer to key
1671cb0ef41Sopenharmony_ci *  \param[in] key_len  Length of key
1681cb0ef41Sopenharmony_ci *  \param[in] seed     Seed for generating hash
1691cb0ef41Sopenharmony_ci *  \return hash value
1701cb0ef41Sopenharmony_ci */
1711cb0ef41Sopenharmony_ciunsigned int ares__htable_hash_FNV1a_casecmp(const unsigned char *key,
1721cb0ef41Sopenharmony_ci                                             size_t key_len, unsigned int seed);
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_ci/*! @} */
1751cb0ef41Sopenharmony_ci
1761cb0ef41Sopenharmony_ci#endif /* __ARES__HTABLE_H */
177