blob: c45a6da631f99a6c07c4950ac82a7a2965c3f657 [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 <pthread.h>
20#include <stddef.h>
21#include <stdint.h>
22
Michal Vaskoae130f52023-04-20 14:25:16 +020023#ifdef __cplusplus
24extern "C" {
25#endif
26
Michal Vaskoc5a22832020-08-20 13:21:33 +020027#include "compat.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020028#include "log.h"
Radek Krejci5aeea3a2018-09-05 13:29:36 +020029
30/**
31 * @brief Compute hash from (several) string(s).
32 *
33 * Usage:
34 * - init hash to 0
Michal Vaskoae130f52023-04-20 14:25:16 +020035 * - repeatedly call ::lyht_hash_multi(), provide hash from the last call
36 * - call ::lyht_hash_multi() with key_part = NULL to finish the hash
37 *
38 * @param[in] hash Previous hash.
39 * @param[in] key_part Next key to hash,
40 * @param[in] len Length of @p key_part.
41 * @return Hash with the next key.
Radek Krejci5aeea3a2018-09-05 13:29:36 +020042 */
Michal Vaskoae130f52023-04-20 14:25:16 +020043LIBYANG_API_DECL uint32_t lyht_hash_multi(uint32_t hash, const char *key_part, size_t len);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020044
Michal Vaskoa655fca2022-09-05 15:48:31 +020045/**
Radek Krejcif2dc4c52018-11-08 09:04:13 +010046 * @brief Compute hash from a string.
Michal Vaskoae130f52023-04-20 14:25:16 +020047 *
48 * Bob Jenkin's one-at-a-time hash
49 * http://www.burtleburtle.net/bob/hash/doobs.html
50 *
51 * Spooky hash is faster, but it works only for little endian architectures.
52 *
53 * @param[in] key Key to hash.
54 * @param[in] len Length of @p key.
55 * @return Hash of the key.
Radek Krejcif2dc4c52018-11-08 09:04:13 +010056 */
Michal Vaskoae130f52023-04-20 14:25:16 +020057LIBYANG_API_DECL uint32_t lyht_hash(const char *key, size_t len);
Radek Krejcif2dc4c52018-11-08 09:04:13 +010058
Radek Krejci5aeea3a2018-09-05 13:29:36 +020059/**
60 * @brief Callback for checking hash table values equivalence.
61 *
Michal Vasko90932a92020-02-12 14:33:03 +010062 * @param[in] val1_p Pointer to the first value, the one being searched (inserted/removed).
63 * @param[in] val2_p Pointer to the second value, the one stored in the hash table.
Radek Krejci5aeea3a2018-09-05 13:29:36 +020064 * @param[in] mod Whether the operation modifies the hash table (insert or remove) or not (find).
65 * @param[in] cb_data User callback data.
Radek Krejci857189e2020-09-01 13:26:36 +020066 * @return false (non-equal) or true (equal).
Radek Krejci5aeea3a2018-09-05 13:29:36 +020067 */
Michal Vasko62524a92021-02-26 10:08:50 +010068typedef 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 +020069
Radek Krejci5aeea3a2018-09-05 13:29:36 +020070/**
71 * @brief Create new hash table.
72 *
73 * @param[in] size Starting size of the hash table (capacity of values), must be power of 2.
74 * @param[in] val_size Size in bytes of value (the stored hashed item).
75 * @param[in] val_equal Callback for checking value equivalence.
Michal Vaskoa655fca2022-09-05 15:48:31 +020076 * @param[in] cb_data User data always passed to @p val_equal.
Radek Krejci5aeea3a2018-09-05 13:29:36 +020077 * @param[in] resize Whether to resize the table on too few/too many records taken.
78 * @return Empty hash table, NULL on error.
79 */
Michal Vaskoae130f52023-04-20 14:25:16 +020080LIBYANG_API_DECL struct ly_ht *lyht_new(uint32_t size, uint16_t val_size, lyht_value_equal_cb val_equal, void *cb_data,
81 uint16_t resize);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020082
83/**
84 * @brief Set hash table value equal callback.
85 *
86 * @param[in] ht Hash table to modify.
87 * @param[in] new_val_equal New callback for checking value equivalence.
88 * @return Previous callback for checking value equivalence.
89 */
Michal Vaskoae130f52023-04-20 14:25:16 +020090LIBYANG_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 +020091
92/**
93 * @brief Set hash table value equal callback user data.
94 *
95 * @param[in] ht Hash table to modify.
96 * @param[in] new_cb_data New data for values callback.
97 * @return Previous data for values callback.
98 */
Michal Vaskoae130f52023-04-20 14:25:16 +020099LIBYANG_API_DECL void *lyht_set_cb_data(struct ly_ht *ht, void *new_cb_data);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200100
101/**
102 * @brief Make a duplicate of an existing hash table.
103 *
104 * @param[in] orig Original hash table to duplicate.
Michal Vaskoa655fca2022-09-05 15:48:31 +0200105 * @return Duplicated hash table @p orig, NULL on error.
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200106 */
Michal Vaskoae130f52023-04-20 14:25:16 +0200107LIBYANG_API_DECL struct ly_ht *lyht_dup(const struct ly_ht *orig);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200108
109/**
110 * @brief Free a hash table.
111 *
112 * @param[in] ht Hash table to be freed.
Michal Vasko88ccd582023-03-30 11:50:57 +0200113 * @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 +0200114 */
Michal Vaskoae130f52023-04-20 14:25:16 +0200115LIBYANG_API_DECL void lyht_free(struct ly_ht *ht, void (*val_free)(void *val_p));
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200116
117/**
118 * @brief Find a value in a hash table.
119 *
120 * @param[in] ht Hash table to search in.
121 * @param[in] val_p Pointer to the value to find.
122 * @param[in] hash Hash of the stored value.
123 * @param[out] match_p Pointer to the matching value, optional.
Michal Vaskoda859032020-07-14 12:20:14 +0200124 * @return LY_SUCCESS if value was found,
125 * @return LY_ENOTFOUND if not found.
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200126 */
Michal Vaskoae130f52023-04-20 14:25:16 +0200127LIBYANG_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 +0200128
129/**
130 * @brief Find another equal value in the hash table.
131 *
132 * @param[in] ht Hash table to search in.
Michal Vaskoa655fca2022-09-05 15:48:31 +0200133 * @param[in] val_p Pointer to the previously found value in @p ht.
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200134 * @param[in] hash Hash of the previously found value.
135 * @param[out] match_p Pointer to the matching value, optional.
Michal Vaskoda859032020-07-14 12:20:14 +0200136 * @return LY_SUCCESS if value was found,
137 * @return LY_ENOTFOUND if not found.
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200138 */
Michal Vaskoae130f52023-04-20 14:25:16 +0200139LIBYANG_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 +0200140
141/**
Michal Vasko6374de22022-09-05 15:48:48 +0200142 * @brief Find another equal value in the hash table. Same functionality as ::lyht_find_next()
143 * but allows to specify a collision val equal callback to be used for checking for matching colliding values.
144 *
145 * @param[in] ht Hash table to search in.
146 * @param[in] val_p Pointer to the previously found value in @p ht.
147 * @param[in] hash Hash of the previously found value.
148 * @param[in] collision_val_equal Val equal callback to use for checking collisions.
149 * @param[out] match_p Pointer to the matching value, optional.
150 * @return LY_SUCCESS if value was found,
151 * @return LY_ENOTFOUND if not found.
152 */
Michal Vaskoae130f52023-04-20 14:25:16 +0200153LIBYANG_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 +0200154 lyht_value_equal_cb collision_val_equal, void **match_p);
155
156/**
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200157 * @brief Insert a value into a hash table.
158 *
159 * @param[in] ht Hash table to insert into.
160 * @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 +0200161 * are pointers, @p val_p must be a pointer to a pointer.
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200162 * @param[in] hash Hash of the stored value.
163 * @param[out] match_p Pointer to the stored value, optional
Michal Vasko4a4c7ed2020-07-17 09:30:12 +0200164 * @return LY_SUCCESS on success,
Radek Krejci011e4aa2020-09-04 15:22:31 +0200165 * @return LY_EEXIST in case the value is already present.
166 * @return LY_EMEM in case of memory allocation failure.
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200167 */
Michal Vaskoae130f52023-04-20 14:25:16 +0200168LIBYANG_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 +0200169
170/**
Radek Krejci8678fa42020-08-18 16:07:28 +0200171 * @brief Insert a value into hash table. Same functionality as ::lyht_insert()
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200172 * but allows to specify a temporary val equal callback to be used in case the hash table
173 * will be resized after successful insertion.
174 *
175 * @param[in] ht Hash table to insert into.
176 * @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 +0200177 * are pointers, @p val_p must be a pointer to a pointer.
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200178 * @param[in] hash Hash of the stored value.
179 * @param[in] resize_val_equal Val equal callback to use for resizing.
180 * @param[out] match_p Pointer to the stored value, optional
Michal Vasko4a4c7ed2020-07-17 09:30:12 +0200181 * @return LY_SUCCESS on success,
Radek Krejci011e4aa2020-09-04 15:22:31 +0200182 * @return LY_EEXIST in case the value is already present.
183 * @return LY_EMEM in case of memory allocation failure.
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200184 */
Michal Vaskoae130f52023-04-20 14:25:16 +0200185LIBYANG_API_DECL LY_ERR lyht_insert_with_resize_cb(struct ly_ht *ht, void *val_p, uint32_t hash,
186 lyht_value_equal_cb resize_val_equal, void **match_p);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200187
188/**
189 * @brief Remove a value from a hash table.
190 *
191 * @param[in] ht Hash table to remove from.
Michal Vasko5bcc33b2020-10-06 15:33:44 +0200192 * @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 +0200193 * are pointers, @p val_p must be a pointer to a pointer.
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200194 * @param[in] hash Hash of the stored value.
Michal Vasko4a4c7ed2020-07-17 09:30:12 +0200195 * @return LY_SUCCESS on success,
196 * @return LY_ENOTFOUND if value was not found.
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200197 */
Michal Vaskoae130f52023-04-20 14:25:16 +0200198LIBYANG_API_DECL LY_ERR lyht_remove(struct ly_ht *ht, void *val_p, uint32_t hash);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200199
Michal Vasko5bcc33b2020-10-06 15:33:44 +0200200/**
Radek Krejci8678fa42020-08-18 16:07:28 +0200201 * @brief Remove a value from a hash table. Same functionality as ::lyht_remove()
Michal Vasko5bcc33b2020-10-06 15:33:44 +0200202 * but allows to specify a temporary val equal callback to be used in case the hash table
203 * will be resized after successful removal.
204 *
205 * @param[in] ht Hash table to remove from.
206 * @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 +0200207 * are pointers, @p val_p must be a pointer to a pointer.
Michal Vasko5bcc33b2020-10-06 15:33:44 +0200208 * @param[in] hash Hash of the stored value.
209 * @param[in] resize_val_equal Val equal callback to use for resizing.
210 * @return LY_SUCCESS on success,
211 * @return LY_ENOTFOUND if value was not found.
212 */
Michal Vaskoae130f52023-04-20 14:25:16 +0200213LIBYANG_API_DECL LY_ERR lyht_remove_with_resize_cb(struct ly_ht *ht, void *val_p, uint32_t hash,
214 lyht_value_equal_cb resize_val_equal);
Michal Vasko5bcc33b2020-10-06 15:33:44 +0200215
Michal Vasko626196f2022-08-05 12:49:52 +0200216/**
217 * @brief Get suitable size of a hash table for a fixed number of items.
218 *
219 * @param[in] item_count Number of stored items.
220 * @return Hash table size.
221 */
Michal Vaskoae130f52023-04-20 14:25:16 +0200222LIBYANG_API_DECL uint32_t lyht_get_fixed_size(uint32_t item_count);
223
224#ifdef __cplusplus
225}
226#endif
Michal Vasko626196f2022-08-05 12:49:52 +0200227
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200228#endif /* LY_HASH_TABLE_H_ */