rizin/librz/include/rz_util/ht_inc.h
billow 7a77b8f7bd
linter: update clang-format installation to version 20 (#5451)
* fix: format with clang-format-20
* fix: fix clang-format linter with rewrite '^#define.*/\*.*\\$'
* fix: update clang-format to version 20 in workflows and documentation
* fix: add SPDX license information to .git-blame-ignore-revs
2025-10-12 08:02:03 +08:00

222 lines
9.1 KiB
C

// SPDX-FileCopyrightText: 2016-2018 crowell
// SPDX-FileCopyrightText: 2016-2018 pancake <pancake@nopcode.org>
// SPDX-FileCopyrightText: 2016-2018 ret2libc <sirmy15@gmail.com>
// SPDX-FileCopyrightText: 2024 pelijah
// SPDX-License-Identifier: BSD-3-Clause
#include <rz_util/rz_iterator.h>
#ifndef HT_TYPE
#error HT_TYPE should be defined before including this header
#endif
#undef HtName_
#undef Ht_
#undef HT_
#undef KEY_TYPE
#undef VALUE_TYPE
#undef KEY_TO_HASH
#undef HT_NULL_VALUE
#if HT_TYPE == 1
// Hash table HtPP that has void* as key and void* as value
#define HtName_(name) name##PP
#define Ht_(name) ht_pp_##name
#define HT_(name) HtPP##name
#define KEY_TYPE void *
#define VALUE_TYPE void *
#define KEY_TO_HASH(x) ((ut32)(uintptr_t)(x))
#define HT_NULL_VALUE NULL
#elif HT_TYPE == 2
// Hash table HtPU that has void* as key and ut64 as value
#define HtName_(name) name##UP
#define Ht_(name) ht_up_##name
#define HT_(name) HtUP##name
#define KEY_TYPE ut64
#define VALUE_TYPE void *
#define KEY_TO_HASH(x) ((ut32)(x))
#define HT_NULL_VALUE 0
#elif HT_TYPE == 3
// Hash table HtUU that has ut64 as key and ut64 as value
#define HtName_(name) name##UU
#define Ht_(name) ht_uu_##name
#define HT_(name) HtUU##name
#define KEY_TYPE ut64
#define VALUE_TYPE ut64
#define KEY_TO_HASH(x) ((ut32)(x))
#define HT_NULL_VALUE 0
#elif HT_TYPE == 4
// Hash table HtPU that has void* as key and ut64 as value
#define HtName_(name) name##PU
#define Ht_(name) ht_pu_##name
#define HT_(name) HtPU##name
#define KEY_TYPE void *
#define VALUE_TYPE ut64
#define KEY_TO_HASH(x) ((ut32)(uintptr_t)(x))
#define HT_NULL_VALUE 0
#elif HT_TYPE == 5
// Hash table HtSP that has C-string as key and void* as value
#define HtName_(name) name##SP
#define Ht_(name) ht_sp_##name
#define HT_(name) HtSP##name
#define KEY_TYPE char *
#define VALUE_TYPE void *
#define KEY_TO_HASH(x) ((ut32)(uintptr_t)(x))
#define HT_NULL_VALUE NULL
#elif HT_TYPE == 6
// Hash table HtSS that has C-string as key and C-string as value
#define HtName_(name) name##SS
#define Ht_(name) ht_ss_##name
#define HT_(name) HtSS##name
#define KEY_TYPE char *
#define VALUE_TYPE char *
#define KEY_TO_HASH(x) ((ut32)(uintptr_t)(x))
#define HT_NULL_VALUE NULL
#elif HT_TYPE == 7
// Hash table HtSU that has C-string as key and ut64 as value
#define HtName_(name) name##SU
#define Ht_(name) ht_su_##name
#define HT_(name) HtSU##name
#define KEY_TYPE char *
#define VALUE_TYPE ut64
#define KEY_TO_HASH(x) ((ut32)(uintptr_t)(x))
#define HT_NULL_VALUE 0
#endif
#ifndef HT_ENUM_DEFINED
#define HT_ENUM_DEFINED
/**
* Return codes for insert/update methods
* code < 0 <--> code == HT_RC_ERROR
* code >= 0 <--> code != HT_RC_ERROR
* code > 0 <--> code == HT_RC_INSERTED || code == HT_RC_UPDATED
*/
typedef enum {
HT_RC_ERROR = -1, ///< Error (out of memory)
HT_RC_EXISTING = 0, ///< Existing KV prevented an insertion
HT_RC_INSERTED = 1, ///< New KV was inserted during insert/update operation
HT_RC_UPDATED = 2, ///< Existing KV was updated during update operation
} HtRetCode;
typedef enum {
HT_STR_DUP = 0, ///< String is copied when inserting into HT
HT_STR_OWN, ///< String ownership is transferred when inserting into HT
HT_STR_CONST ///< String is treated as constant and not copied when inserting into HT
} HtStrOption;
#endif
#include <rz_types.h>
/* Kv represents a single key/value element in the hashtable */
typedef struct Ht_(kv) {
KEY_TYPE key;
VALUE_TYPE value;
ut32 key_len;
ut32 value_len;
} HT_(Kv);
typedef void (*HT_(FiniKv))(HT_(Kv) *kv, void *user);
typedef KEY_TYPE (*HT_(DupKey))(const KEY_TYPE);
typedef VALUE_TYPE (*HT_(DupValue))(const VALUE_TYPE);
typedef void (*HT_(FreeValue))(VALUE_TYPE val);
typedef ut32 (*HT_(CalcSizeK))(const KEY_TYPE);
typedef ut32 (*HT_(CalcSizeV))(const VALUE_TYPE);
typedef ut32 (*HT_(HashFunction))(const KEY_TYPE);
typedef int (*HT_(Comparator))(const KEY_TYPE, const KEY_TYPE);
typedef bool (*HT_(ForeachCallback))(void *user, const KEY_TYPE, const VALUE_TYPE);
typedef struct Ht_(bucket_t) {
HT_(Kv) *arr;
ut32 count;
} HT_(Bucket);
/**
* Options contain all the settings of the hashtable.
*/
typedef struct Ht_(options_t) {
HT_(Comparator) cmp; ///< RZ_NULLABLE. Function for comparing keys.
///< Returns 0 if keys are equal.
///< Function is invoked only if == operator applied to keys returns false.
HT_(HashFunction) hashfn; ///< RZ_NULLABLE. Function for hashing items in the hash table.
///< If NULL KEY_TO_HASH macro is used.
HT_(DupKey) dupkey; ///< RZ_NULLABLE. Function for making a copy of key.
///< If NULL simple assignment operator is used.
HT_(DupValue) dupvalue; ///< RZ_NULLABLE. Function for making a copy of value.
///< If NULL simple assignment operator is used.
HT_(CalcSizeK) calcsizeK; ///< RZ_NULLABLE. Function to determine the key's size.
///< If NULL zero value is used as a size.
///< Key sizes are checked on equality during keys comparsion as a pre-check.
HT_(CalcSizeV) calcsizeV; ///< RZ_NULLABLE. Function to determine the value's size.
///< If NULL zero value is used as a size.
///< Not required for common scenarios. Could be used in subclasses.
HT_(FiniKv) finiKV; ///< RZ_NULLABLE. Function to clean up the key-value store.
void *finiKV_user; ///< RZ_NULLABLE. User data which is passed into finiKV.
size_t elem_size; ///< Size of each HtKv element (useful for subclassing like SdbKv).
///< Zero value means to use default size of HtKv.
} HT_(Options);
/* Ht is the hashtable structure */
typedef struct Ht_(t) {
ut32 size; ///< Size of the hash table in buckets.
ut32 count; ///< Number of stored elements.
HT_(Bucket) *table; ///< Actual table.
ut32 prime_idx;
HT_(Options) opt;
} HtName_(Ht);
typedef struct Ht_(iter_mut_t) {
HtName_(Ht) *ht; ///< The hash table to iterate over.
ut32 ti; ///< Table index
ut32 bi; ///< Bucket index
HT_(Kv) *kv; ///< Current Key-Value-pair.
} HT_(IterMutState);
typedef struct Ht_(iter_t) {
const HtName_(Ht) *ht; ///< The hash table to iterate over.
ut32 ti; ///< Table index
ut32 bi; ///< Bucket index
const HT_(Kv) *kv; ///< Current Key-Value-pair.
} HT_(IterState);
// Create a new Ht with the provided Options
RZ_API RZ_OWN HtName_(Ht) *Ht_(new_opt)(RZ_NONNULL HT_(Options) *opt);
// Create a new Ht with the provided Options and initial size
RZ_API RZ_OWN HtName_(Ht) *Ht_(new_opt_size)(RZ_NONNULL HT_(Options) *opt, ut32 initial_size);
// Destroy a hashtable and all of its entries.
RZ_API void Ht_(free)(RZ_NULLABLE HtName_(Ht) *ht);
// Insert a new Key-Value pair into the hashtable. If the key already exists, returns false.
RZ_API bool Ht_(insert)(RZ_NONNULL HtName_(Ht) *ht, const KEY_TYPE key, VALUE_TYPE value);
RZ_API HtRetCode Ht_(insert_ex)(RZ_NONNULL HtName_(Ht) *ht, const KEY_TYPE key, VALUE_TYPE value, RZ_OUT RZ_NULLABLE HT_(Kv) **out_kv);
// Insert a new Key-Value pair into the hashtable, or updates the value if the key already exists.
RZ_API bool Ht_(update)(RZ_NONNULL HtName_(Ht) *ht, const KEY_TYPE key, VALUE_TYPE value);
RZ_API HtRetCode Ht_(update_ex)(RZ_NONNULL HtName_(Ht) *ht, const KEY_TYPE key, VALUE_TYPE value, RZ_OUT RZ_NULLABLE HT_(Kv) **out_kv);
// Update the key of an element in the hashtable
RZ_API bool Ht_(update_key)(RZ_NONNULL HtName_(Ht) *ht, const KEY_TYPE old_key, const KEY_TYPE new_key);
// Delete a key from the hashtable.
RZ_API bool Ht_(delete)(RZ_NONNULL HtName_(Ht) *ht, const KEY_TYPE key);
// Find the value corresponding to the matching key.
RZ_API VALUE_TYPE Ht_(find)(RZ_NONNULL HtName_(Ht) *ht, const KEY_TYPE key, RZ_NULLABLE bool *found);
// Iterates over all elements in the hashtable, calling the cb function on each Kv.
// If the cb returns false, the iteration is stopped.
// cb should not modify the hashtable.
// NOTE: cb can delete the current element, but it should be avoided
RZ_API void Ht_(foreach)(RZ_NONNULL HtName_(Ht) *ht, RZ_NONNULL HT_(ForeachCallback) cb, RZ_NULLABLE void *user);
RZ_API ut32 Ht_(size)(const RZ_NONNULL HtName_(Ht) *ht);
RZ_API RZ_BORROW HT_(Kv) *Ht_(find_kv)(RZ_NONNULL HtName_(Ht) *ht, const KEY_TYPE key, RZ_NULLABLE bool *found);
RZ_API bool Ht_(insert_kv)(RZ_NONNULL HtName_(Ht) *ht, RZ_NONNULL HT_(Kv) *kv, bool update);
RZ_API HtRetCode Ht_(insert_kv_ex)(RZ_NONNULL HtName_(Ht) *ht, RZ_NONNULL HT_(Kv) *kv, bool update, RZ_OUT RZ_NULLABLE HT_(Kv) **out_kv);
RZ_API RZ_OWN HT_(IterMutState) *Ht_(new_iter_mut_state)(RZ_NONNULL HtName_(Ht) *ht);
RZ_API RZ_OWN HT_(IterState) *Ht_(new_iter_state)(const RZ_NONNULL HtName_(Ht) *ht);
RZ_API void Ht_(free_iter_mut_state)(RZ_NULLABLE HT_(IterMutState) *state);
RZ_API void Ht_(free_iter_state)(RZ_NULLABLE HT_(IterState) *state);
RZ_API RZ_BORROW VALUE_TYPE *Ht_(iter_next_mut)(RzIterator *it);
RZ_API const VALUE_TYPE *Ht_(iter_next)(RzIterator *it);
RZ_API const KEY_TYPE *Ht_(iter_next_key)(RzIterator *it);
RZ_API RZ_OWN RzIterator /* <HtName_(Ht)> */ *Ht_(as_iter_mut)(RZ_NONNULL HtName_(Ht) *ht);
RZ_API RZ_OWN RzIterator /* <HtName_(Ht)> */ *Ht_(as_iter)(const RZ_NONNULL HtName_(Ht) *ht);
RZ_API RZ_OWN RzIterator /* <HtName_(Ht)> */ *Ht_(as_iter_keys)(const RZ_NONNULL HtName_(Ht) *ht);