BRL-CAD
Loading...
Searching...
No Matches
hash.h
Go to the documentation of this file.
1/* H A S H . H
2 * BRL-CAD
3 *
4 * Copyright (c) 2004-2026 United States Government as represented by
5 * the U.S. Army Research Laboratory.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public License
9 * version 2.1 as published by the Free Software Foundation.
10 *
11 * This library is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this file; see the file named COPYING for more
18 * information.
19 */
20
21#ifndef BU_HASH_H
22#define BU_HASH_H
23
24#include "common.h"
25
26#include "bu/defines.h"
27
29
30/** @addtogroup bu_hash
31 * @brief
32 * An implementation of hash tables. TODO - need much better discussion here. Key points:
33 *
34 * 1. Keys are copied to the table and do not need to be maintained by the user
35 * 2. All keys, regardless of original type, are handled as byte arrays. Need
36 * examples of using strings and pointers as has keys
37 * 3. Void pointers sorted as values are *not* copies - the application must keep
38 * the data pointed to by the pointers intact and not rely on the table.
39 * 4. Performance is not currently a focus of bu_hash - it is not currently suitable
40 * for applications where high performance is critical.
41 */
42/** @{ */
43/** @file bu/hash.h */
44
45/* Use typedefs to hide the details of the hash entry and table structures */
46typedef struct bu_hash_entry bu_hash_entry;
47typedef struct bu_hash_tbl bu_hash_tbl;
49
50/**
51 * Create and initialize a hash table. The input is the number of desired hash
52 * bins. This number will be rounded up to the nearest power of two, or a
53 * minimal size if tbl_size is smaller than the internal minimum bin count.
54 */
55BU_EXPORT extern bu_hash_tbl *bu_hash_create(unsigned long tbl_size);
57
58/**
59 * Free all the memory associated with the specified hash table.
60 *
61 * Note that the keys are freed (they are copies), but the "values"
62 * are not freed. (The values are merely pointers)
63 */
66
67/**
68 * Get the value stored in the hash table entry corresponding to the provided key
69 *
70 * @param[in] t - The hash table to look in
71 * @param[in] key - the key to look for
72 * @param[in] key_len - the length of the key in bytes
73 *
74 * @return
75 * the void pointer stored in the hash table entry corresponding to key, or
76 * NULL if no entry corresponding to key exists.
77 */
78BU_EXPORT extern void *bu_hash_get(const bu_hash_tbl *t, const uint8_t *key, size_t key_len);
80
81/**
82 * Set the value stored in the hash table entry corresponding to the provided
83 * key to val, or if no entry corresponding to the provided key exists create a
84 * new entry associating the key and value. The key value is stored in the
85 * hash entry, but the table does not maintain its own copy of val - ensuring
86 * the value pointer remains valid is the responsibility of the caller.
87 *
88 * Null or zero length keys are not supported. The table will also not store
89 * a key/value combination where the value is NULL, but for random access with
90 * bu_hash_get get this won't matter because the return value for a key not
91 * in the table is NULL - i.e. the return will be the same as if the key/value
92 * pair had actually been added. The only use case where this property is observable
93 * is when a user iterates over the whole contents of a hash table - in that
94 * situation a key, NULL entry might be expected, but will not be present.
95 *
96 * @param[in] t - The hash table to look in
97 * @param[in] key - the key to look for
98 * @param[in] key_len - the length of the key in bytes
99 * @param[in] val - the value to be associated with key
100 *
101 * @return
102 * 1 if a new entry is created, 0 if an existing value was updated, -1 on error.
103 */
104BU_EXPORT extern int bu_hash_set(bu_hash_tbl *t, const uint8_t *key, size_t key_len, void *val);
106
107/**
108 * Remove the hash table entry associated with key from the table.
109 *
110 * @param[in] t - The hash table to look in
111 * @param[in] key - the key to look for
112 * @param[in] key_len - the length of the key in bytes
113 */
114BU_EXPORT extern void bu_hash_rm(bu_hash_tbl *t, const uint8_t *key, size_t key_len);
116
117/**
118 * Supports iteration of all the contents in a hash table.
119 *
120 * @param[in] t - The hash table to look in
121 * @param[in] p - the previous entry in the iteration
122 *
123 * This example prints all values in a hash table:
124 * @code
125 * void print_vals(struct bu_hash_tbl *t) {
126 * struct bu_hash_entry *e = bu_hash_next(t, NULL);
127 * while (e) {
128 * bu_log("Value: %p\n", bu_hash_value(e, NULL));
129 * e = bu_hash_next(t, e);
130 * }
131 * }
132 * @endcode
133 *
134 * @return
135 * Either first entry (if p is NULL) or next entry (if p is NON-null). Returns
136 * NULL when p is last entry in table.
137 */
140
141/**
142 * Supports iteration of all the contents in a hash table.
143 *
144 * @param[in] e - The hash table to look in
145 *
146 * @param[out] key - the entry's key
147 * @param[out] key_len - the length of the entry's key
148 *
149 * @return
150 * Returns 0 on success, 1 on failure.
151 */
152BU_EXPORT extern int bu_hash_key(bu_hash_entry *e, uint8_t **key, size_t *key_len);
154
155/* returns value of bu_hash_entry if nval is NULL.
156 * returns nval if nval was assigned to p's value.
157 * returns NULL on error */
158
159/**
160 * Extracts or updates the void pointer value for a bu_hash_entry. If nval is
161 * not NULL the entry will be updated.
162 *
163 * @param[in] e - The hash table to look in
164 * @param[in] nval - The new void pointer to assign to the entry's value slot, or NULL if no assignment is to be made.
165 *
166 * @return Returns the hash entry's value pointer, or NULL on error.
167 */
168BU_EXPORT extern void *bu_hash_value(bu_hash_entry *e, void *nval);
170/** @} */
171
172
173
174/***************************************************************************
175 * Given data, return an unsigned long long value based on a hashing
176 * calculation. Unlike bu_hash_tbl and its related functions, this
177 * functionality does not implement key/value data storage - it's current
178 * primary use case is generation of content-based UUIDs.
179 *
180 * We are deliberately not documenting the hashing algorithm used
181 * to allow for "under the hood" improvements to its properties over time, and
182 * there should be no assumption of the equality of the hashed value between
183 * different versions of BRL-CAD.
184 *
185 * One of the uses for this function is to provide a "good enough" content-
186 * based universally unique identifier, similarly to how Git uses SHA1 hashes
187 * as UUIDs for commits.
188 **************************************************************************/
189BU_EXPORT unsigned long long
190bu_data_hash(const void *data, size_t len);
192/* bu_data_hash is the simple API, but there are situations where we need to
193 * build up the data to be used for hashing from multiple inputs. For that
194 * case, the below API allows for updating a persistent hash state.
195 */
196struct bu_data_hash_impl;
197struct bu_data_hash_state {
200
204BU_EXPORT void
207BU_EXPORT void
208bu_data_hash_update(struct bu_data_hash_state *s, const void *data, size_t len);
210BU_EXPORT unsigned long long
213
214/***************************************************************************
215 * 128-bit fingerprint API - provides an extremely low probability for birthday
216 * collisions (effectively zero for any realistic number of distinct inputs),
217 * at the expense of API convenience.
218 *
219 * The result type bu_h128_t is a plain C struct (two uint64_t words) that is
220 * ABI-stable and can be stored, compared, and copied with ordinary C code.
221 *
222 * C++ callers that need to use bu_h128_t as a key in std::unordered_map or
223 * std::unordered_set will need to provide operator== (all 128 bits) and
224 * std::hash<bu_h128_t> (folds to size_t for bucket placement only). Those two
225 * roles are intentionally separate: operator== provides strong uniqueness, while
226 * std::hash's fold gives us a value suitable for the initial bucket key. Below
227 * is an example implementation.
228 *
229 * @code
230 * inline bool operator==(const bu_h128_t &a, const bu_h128_t &b)
231 * {
232 * return a.w[0] == b.w[0] && a.w[1] == b.w[1];
233 * }
234 *
235 * // Bucket-placement hasher for bu_h128_t (performance only, not identity).
236 * //
237 * // This function maps a 128-bit fingerprint to a single std::size_t bucket
238 * // index. It is used exclusively for bucket selection; the container
239 * // resolves actual equality with operator== (above), which inspects all
240 * // 128 bits.
241 * //
242 * // Folding to std::size_t increases *bucket* collision probability back to
243 * // roughly N^2 / 2^65 on 64-bit platforms – that is intentional and
244 * // harmless: a bucket collision only lengthens one chain by one node, it
245 * // never causes a false identity match. See the file-level comment for
246 * // a full explanation of the two-level collision model.
247 * //
248 * // Implementation: XOR the two 64-bit halves (both have XXH3's excellent
249 * // avalanche properties), then fold to size_t width for 32-bit platforms.
250 * namespace std {
251 * template<>
252 * struct hash<bu_h128_t> {
253 * std::size_t operator()(const bu_h128_t &h) const noexcept {
254 * // XOR the two 64-bit halves, then fold to size_t width.
255 * // On 64-bit platforms this is a no-op truncation.
256 * // On 32-bit platforms the extra shift folds the upper 32
257 * // bits of the XOR result into the lower 32 before the cast.
258 * uint64_t v = h.w[0] ^ h.w[1];
259 * if (sizeof(std::size_t) < sizeof(uint64_t))
260 * v ^= (v >> 32);
261 * return (std::size_t)v;
262 * }
263 * };
264 * } // namespace std
265 * @endcode
266 *
267 * Note: the implementation hash as of 2026/03/09 is XXH3-128, whose
268 * birthday-bound identity-collision probability is N^2 / 2^129. HOWEVER, while
269 * we are documenting this to illustrate why callers might want to use a 128
270 * bit hash instead of the 64 bit version, the specific underlying hash
271 * algorithm is deliberately and explicitly NOT part of the public contract.
272 * We may change the under-the-hood algorithm and implementation at any time,
273 * so no numerical stability of the hash values between releases can be
274 * assumed.
275 **************************************************************************/
276
277/**
278 * A C-compatible 128-bit fingerprint.
279 * w[0] holds bits 0-63 (the low half); w[1] holds bits 64-127 (the high half).
280 */
281struct bu_h128_t {
284typedef struct bu_h128_t bu_h128_t;
286/** One-shot 128-bit hash of @p len bytes starting at @p data. */
288bu_data_hash128(const void *data, size_t len);
290/** Streaming 128-bit hash: opaque state object. */
299BU_EXPORT void
302BU_EXPORT void
303bu_data_hash128_update(struct bu_data_hash128_state *s, const void *data, size_t len);
305/** Finalise the stream and return the 128-bit digest. */
309
311
312#endif /* BU_HASH_H */
313
314
315/*
316 * Local Variables:
317 * mode: C
318 * tab-width: 8
319 * indent-tabs-mode: t
320 * c-file-style: "stroustrup"
321 * End:
322 * ex: shiftwidth=4 tabstop=8
323 */
Definition dvec.h:74
Header file for the BRL-CAD common definitions.
void * bu_hash_get(const bu_hash_tbl *t, const uint8_t *key, size_t key_len)
bu_hash_tbl * bu_hash_create(unsigned long tbl_size)
struct bu_hash_tbl bu_hash_tbl
Definition hash.h:48
void bu_hash_destroy(bu_hash_tbl *t)
bu_hash_entry * bu_hash_next(bu_hash_tbl *t, bu_hash_entry *p)
struct bu_hash_entry bu_hash_entry
Definition hash.h:47
void * bu_hash_value(bu_hash_entry *e, void *nval)
int bu_hash_key(bu_hash_entry *e, uint8_t **key, size_t *key_len)
int bu_hash_set(bu_hash_tbl *t, const uint8_t *key, size_t key_len, void *val)
void bu_hash_rm(bu_hash_tbl *t, const uint8_t *key, size_t key_len)
bu_h128_t bu_data_hash128_val(struct bu_data_hash128_state *s)
void bu_data_hash128_destroy(struct bu_data_hash128_state *s)
struct bu_data_hash_state * bu_data_hash_create(void)
unsigned long long bu_data_hash_val(struct bu_data_hash_state *s)
void bu_data_hash_update(struct bu_data_hash_state *s, const void *data, size_t len)
void bu_data_hash128_update(struct bu_data_hash128_state *s, const void *data, size_t len)
struct bu_data_hash128_state * bu_data_hash128_create(void)
void bu_data_hash_destroy(struct bu_data_hash_state *s)
unsigned long long bu_data_hash(const void *data, size_t len)
bu_h128_t bu_data_hash128(const void *data, size_t len)
struct bu_data_hash128_impl * i
Definition hash.h:294
struct bu_data_hash_impl * i
Definition hash.h:199
uint64_t w[2]
Definition hash.h:283