blob: 13c664515e134daf5f11bf2ba312d5991c27b644 [file] [log] [blame]
Radek Krejci5aeea3a2018-09-05 13:29:36 +02001/**
2 * @file hash_table.h
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @author Michal Vasko <mvasko@cesnet.cz>
5 * @brief libyang hash table
6 *
Michal Vaskoae130f52023-04-20 14:25:16 +02007 * Copyright (c) 2015 - 2023 CESNET, z.s.p.o.
Radek Krejci5aeea3a2018-09-05 13:29:36 +02008 *
9 * This source code is licensed under BSD 3-Clause License (the "License").
10 * You may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * https://opensource.org/licenses/BSD-3-Clause
14 */
15
16#ifndef LY_HASH_TABLE_H_
17#define LY_HASH_TABLE_H_
18
Radek Krejcie7b95092019-05-15 11:03:07 +020019#include <stddef.h>
20#include <stdint.h>
21
Michal Vaskoae130f52023-04-20 14:25:16 +020022#ifdef __cplusplus
23extern "C" {
24#endif
25
Radek Krejcie7b95092019-05-15 11:03:07 +020026#include "log.h"
Radek Krejci5aeea3a2018-09-05 13:29:36 +020027
28/**
Michal Vaskob2c26802023-05-24 14:57:03 +020029 * @struct ly_ht
30 * @brief libyang hash table.
31 */
32struct ly_ht;
33
34/**
Radek Krejci5aeea3a2018-09-05 13:29:36 +020035 * @brief Compute hash from (several) string(s).
36 *
37 * Usage:
38 * - init hash to 0
Michal Vaskoae130f52023-04-20 14:25:16 +020039 * - repeatedly call ::lyht_hash_multi(), provide hash from the last call
40 * - call ::lyht_hash_multi() with key_part = NULL to finish the hash
41 *
42 * @param[in] hash Previous hash.
43 * @param[in] key_part Next key to hash,
44 * @param[in] len Length of @p key_part.
45 * @return Hash with the next key.
Radek Krejci5aeea3a2018-09-05 13:29:36 +020046 */
Michal Vaskoae130f52023-04-20 14:25:16 +020047LIBYANG_API_DECL uint32_t lyht_hash_multi(uint32_t hash, const char *key_part, size_t len);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020048
Michal Vaskoa655fca2022-09-05 15:48:31 +020049/**
Radek Krejcif2dc4c52018-11-08 09:04:13 +010050 * @brief Compute hash from a string.
Michal Vaskoae130f52023-04-20 14:25:16 +020051 *
52 * Bob Jenkin's one-at-a-time hash
53 * http://www.burtleburtle.net/bob/hash/doobs.html
54 *
55 * Spooky hash is faster, but it works only for little endian architectures.
56 *
57 * @param[in] key Key to hash.
58 * @param[in] len Length of @p key.
59 * @return Hash of the key.
Radek Krejcif2dc4c52018-11-08 09:04:13 +010060 */
Michal Vaskoae130f52023-04-20 14:25:16 +020061LIBYANG_API_DECL uint32_t lyht_hash(const char *key, size_t len);
Radek Krejcif2dc4c52018-11-08 09:04:13 +010062
Radek Krejci5aeea3a2018-09-05 13:29:36 +020063/**
64 * @brief Callback for checking hash table values equivalence.
65 *
Michal Vasko90932a92020-02-12 14:33:03 +010066 * @param[in] val1_p Pointer to the first value, the one being searched (inserted/removed).
67 * @param[in] val2_p Pointer to the second value, the one stored in the hash table.
Radek Krejci5aeea3a2018-09-05 13:29:36 +020068 * @param[in] mod Whether the operation modifies the hash table (insert or remove) or not (find).
69 * @param[in] cb_data User callback data.
Radek Krejci857189e2020-09-01 13:26:36 +020070 * @return false (non-equal) or true (equal).
Radek Krejci5aeea3a2018-09-05 13:29:36 +020071 */
Michal Vasko62524a92021-02-26 10:08:50 +010072typedef ly_bool (*lyht_value_equal_cb)(void *val1_p, void *val2_p, ly_bool mod, void *cb_data);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020073
Radek Krejci5aeea3a2018-09-05 13:29:36 +020074/**
75 * @brief Create new hash table.
76 *
77 * @param[in] size Starting size of the hash table (capacity of values), must be power of 2.
78 * @param[in] val_size Size in bytes of value (the stored hashed item).
79 * @param[in] val_equal Callback for checking value equivalence.
Michal Vaskoa655fca2022-09-05 15:48:31 +020080 * @param[in] cb_data User data always passed to @p val_equal.
Radek Krejci5aeea3a2018-09-05 13:29:36 +020081 * @param[in] resize Whether to resize the table on too few/too many records taken.
82 * @return Empty hash table, NULL on error.
83 */
Michal Vaskoae130f52023-04-20 14:25:16 +020084LIBYANG_API_DECL struct ly_ht *lyht_new(uint32_t size, uint16_t val_size, lyht_value_equal_cb val_equal, void *cb_data,
85 uint16_t resize);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020086
87/**
88 * @brief Set hash table value equal callback.
89 *
90 * @param[in] ht Hash table to modify.
91 * @param[in] new_val_equal New callback for checking value equivalence.
92 * @return Previous callback for checking value equivalence.
93 */
Michal Vaskoae130f52023-04-20 14:25:16 +020094LIBYANG_API_DECL lyht_value_equal_cb lyht_set_cb(struct ly_ht *ht, lyht_value_equal_cb new_val_equal);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020095
96/**
97 * @brief Set hash table value equal callback user data.
98 *
99 * @param[in] ht Hash table to modify.
100 * @param[in] new_cb_data New data for values callback.
101 * @return Previous data for values callback.
102 */
Michal Vaskoae130f52023-04-20 14:25:16 +0200103LIBYANG_API_DECL void *lyht_set_cb_data(struct ly_ht *ht, void *new_cb_data);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200104
105/**
106 * @brief Make a duplicate of an existing hash table.
107 *
108 * @param[in] orig Original hash table to duplicate.
Michal Vaskoa655fca2022-09-05 15:48:31 +0200109 * @return Duplicated hash table @p orig, NULL on error.
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200110 */
Michal Vaskoae130f52023-04-20 14:25:16 +0200111LIBYANG_API_DECL struct ly_ht *lyht_dup(const struct ly_ht *orig);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200112
113/**
114 * @brief Free a hash table.
115 *
116 * @param[in] ht Hash table to be freed.
Michal Vasko88ccd582023-03-30 11:50:57 +0200117 * @param[in] val_free Optional callback for freeing all the stored values, @p val_p is a pointer to a stored value.
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200118 */
Michal Vaskoae130f52023-04-20 14:25:16 +0200119LIBYANG_API_DECL void lyht_free(struct ly_ht *ht, void (*val_free)(void *val_p));
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200120
121/**
122 * @brief Find a value in a hash table.
123 *
124 * @param[in] ht Hash table to search in.
125 * @param[in] val_p Pointer to the value to find.
126 * @param[in] hash Hash of the stored value.
127 * @param[out] match_p Pointer to the matching value, optional.
Michal Vaskoda859032020-07-14 12:20:14 +0200128 * @return LY_SUCCESS if value was found,
129 * @return LY_ENOTFOUND if not found.
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200130 */
Michal Vaskoae130f52023-04-20 14:25:16 +0200131LIBYANG_API_DECL LY_ERR lyht_find(struct ly_ht *ht, void *val_p, uint32_t hash, void **match_p);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200132
133/**
134 * @brief Find another equal value in the hash table.
135 *
136 * @param[in] ht Hash table to search in.
Michal Vaskoa655fca2022-09-05 15:48:31 +0200137 * @param[in] val_p Pointer to the previously found value in @p ht.
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200138 * @param[in] hash Hash of the previously found value.
139 * @param[out] match_p Pointer to the matching value, optional.
Michal Vaskoda859032020-07-14 12:20:14 +0200140 * @return LY_SUCCESS if value was found,
141 * @return LY_ENOTFOUND if not found.
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200142 */
Michal Vaskoae130f52023-04-20 14:25:16 +0200143LIBYANG_API_DECL LY_ERR lyht_find_next(struct ly_ht *ht, void *val_p, uint32_t hash, void **match_p);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200144
145/**
Michal Vasko6374de22022-09-05 15:48:48 +0200146 * @brief Find another equal value in the hash table. Same functionality as ::lyht_find_next()
147 * but allows to specify a collision val equal callback to be used for checking for matching colliding values.
148 *
149 * @param[in] ht Hash table to search in.
150 * @param[in] val_p Pointer to the previously found value in @p ht.
151 * @param[in] hash Hash of the previously found value.
152 * @param[in] collision_val_equal Val equal callback to use for checking collisions.
153 * @param[out] match_p Pointer to the matching value, optional.
154 * @return LY_SUCCESS if value was found,
155 * @return LY_ENOTFOUND if not found.
156 */
Michal Vaskoae130f52023-04-20 14:25:16 +0200157LIBYANG_API_DECL LY_ERR lyht_find_next_with_collision_cb(struct ly_ht *ht, void *val_p, uint32_t hash,
Michal Vasko6374de22022-09-05 15:48:48 +0200158 lyht_value_equal_cb collision_val_equal, void **match_p);
159
160/**
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200161 * @brief Insert a value into a hash table.
162 *
163 * @param[in] ht Hash table to insert into.
164 * @param[in] val_p Pointer to the value to insert. Be careful, if the values stored in the hash table
Michal Vaskoa655fca2022-09-05 15:48:31 +0200165 * are pointers, @p val_p must be a pointer to a pointer.
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200166 * @param[in] hash Hash of the stored value.
167 * @param[out] match_p Pointer to the stored value, optional
Michal Vasko4a4c7ed2020-07-17 09:30:12 +0200168 * @return LY_SUCCESS on success,
Radek Krejci011e4aa2020-09-04 15:22:31 +0200169 * @return LY_EEXIST in case the value is already present.
170 * @return LY_EMEM in case of memory allocation failure.
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200171 */
Michal Vaskoae130f52023-04-20 14:25:16 +0200172LIBYANG_API_DECL LY_ERR lyht_insert(struct ly_ht *ht, void *val_p, uint32_t hash, void **match_p);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200173
174/**
Radek Krejci8678fa42020-08-18 16:07:28 +0200175 * @brief Insert a value into hash table. Same functionality as ::lyht_insert()
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200176 * but allows to specify a temporary val equal callback to be used in case the hash table
177 * will be resized after successful insertion.
178 *
179 * @param[in] ht Hash table to insert into.
180 * @param[in] val_p Pointer to the value to insert. Be careful, if the values stored in the hash table
Michal Vaskoa655fca2022-09-05 15:48:31 +0200181 * are pointers, @p val_p must be a pointer to a pointer.
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200182 * @param[in] hash Hash of the stored value.
183 * @param[in] resize_val_equal Val equal callback to use for resizing.
184 * @param[out] match_p Pointer to the stored value, optional
Michal Vasko4a4c7ed2020-07-17 09:30:12 +0200185 * @return LY_SUCCESS on success,
Radek Krejci011e4aa2020-09-04 15:22:31 +0200186 * @return LY_EEXIST in case the value is already present.
187 * @return LY_EMEM in case of memory allocation failure.
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200188 */
Michal Vaskoae130f52023-04-20 14:25:16 +0200189LIBYANG_API_DECL LY_ERR lyht_insert_with_resize_cb(struct ly_ht *ht, void *val_p, uint32_t hash,
190 lyht_value_equal_cb resize_val_equal, void **match_p);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200191
192/**
193 * @brief Remove a value from a hash table.
194 *
195 * @param[in] ht Hash table to remove from.
Michal Vasko5bcc33b2020-10-06 15:33:44 +0200196 * @param[in] val_p Pointer to value to be removed. Be careful, if the values stored in the hash table
Michal Vaskoa655fca2022-09-05 15:48:31 +0200197 * are pointers, @p val_p must be a pointer to a pointer.
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200198 * @param[in] hash Hash of the stored value.
Michal Vasko4a4c7ed2020-07-17 09:30:12 +0200199 * @return LY_SUCCESS on success,
200 * @return LY_ENOTFOUND if value was not found.
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200201 */
Michal Vaskoae130f52023-04-20 14:25:16 +0200202LIBYANG_API_DECL LY_ERR lyht_remove(struct ly_ht *ht, void *val_p, uint32_t hash);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200203
Michal Vasko5bcc33b2020-10-06 15:33:44 +0200204/**
Radek Krejci8678fa42020-08-18 16:07:28 +0200205 * @brief Remove a value from a hash table. Same functionality as ::lyht_remove()
Michal Vasko5bcc33b2020-10-06 15:33:44 +0200206 * but allows to specify a temporary val equal callback to be used in case the hash table
207 * will be resized after successful removal.
208 *
209 * @param[in] ht Hash table to remove from.
210 * @param[in] val_p Pointer to value to be removed. Be careful, if the values stored in the hash table
Michal Vaskoa655fca2022-09-05 15:48:31 +0200211 * are pointers, @p val_p must be a pointer to a pointer.
Michal Vasko5bcc33b2020-10-06 15:33:44 +0200212 * @param[in] hash Hash of the stored value.
213 * @param[in] resize_val_equal Val equal callback to use for resizing.
214 * @return LY_SUCCESS on success,
215 * @return LY_ENOTFOUND if value was not found.
216 */
Michal Vaskoae130f52023-04-20 14:25:16 +0200217LIBYANG_API_DECL LY_ERR lyht_remove_with_resize_cb(struct ly_ht *ht, void *val_p, uint32_t hash,
218 lyht_value_equal_cb resize_val_equal);
Michal Vasko5bcc33b2020-10-06 15:33:44 +0200219
Michal Vasko626196f2022-08-05 12:49:52 +0200220/**
221 * @brief Get suitable size of a hash table for a fixed number of items.
222 *
223 * @param[in] item_count Number of stored items.
224 * @return Hash table size.
225 */
Michal Vaskoae130f52023-04-20 14:25:16 +0200226LIBYANG_API_DECL uint32_t lyht_get_fixed_size(uint32_t item_count);
227
228#ifdef __cplusplus
229}
230#endif
Michal Vasko626196f2022-08-05 12:49:52 +0200231
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200232#endif /* LY_HASH_TABLE_H_ */