1 /*
2 * Copyright (c) 2022 Meta
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #ifndef ZEPHYR_INCLUDE_SYS_HASH_FUNCTION_H_
8 #define ZEPHYR_INCLUDE_SYS_HASH_FUNCTION_H_
9
10 #include <stddef.h>
11 #include <stdint.h>
12
13 #include <zephyr/sys/__assert.h>
14 #include <zephyr/sys/util_macro.h>
15
16 #ifdef __cplusplus
17 extern "C" {
18 #endif
19
20 /**
21 * @ingroup hashmap_apis
22 * @defgroup hash_functions Hash Functions
23 * @{
24 */
25
26 /**
27 * @brief 32-bit Hash function interface
28 *
29 * Hash functions are used to map data from an arbitrarily large space to a
30 * (typically smaller) fixed-size space. For a given input, a hash function will
31 * consistently generate the same, semi-unique numerical value. Even for
32 * marginally different data, a good hash function will distribute the entropy
33 * almost evenly over all bits in the hashed value when combined with modulo
34 * arithmetic over a finite-sized numeric field.
35 *
36 * @param str a string of input data
37 * @param n the number of bytes in @p str
38 *
39 * @return the numeric hash associated with @p str
40 */
41 typedef uint32_t (*sys_hash_func32_t)(const void *str, size_t n);
42
43 /**
44 * @brief The naive identity hash function
45 *
46 * This hash function requires that @p n is equal to the size of a primitive
47 * type, such as `[u]int8_t`, `[u]int16_t`, `[u]int32_t`, `[u]int64_t`,
48 * `float`, `double`, or `void *`, and that the alignment of @p str agrees
49 * with that of the respective native type.
50 *
51 * @note The identity hash function is used for testing @ref sys_hashmap.
52 *
53 * @param str a string of input data
54 * @param n the number of bytes in @p str
55 *
56 * @return the numeric hash associated with @p str
57 */
sys_hash32_identity(const void * str,size_t n)58 static inline uint32_t sys_hash32_identity(const void *str, size_t n)
59 {
60 switch (n) {
61 case sizeof(uint8_t):
62 return *(uint8_t *)str;
63 case sizeof(uint16_t):
64 return *(uint16_t *)str;
65 case sizeof(uint32_t):
66 return *(uint32_t *)str;
67 case sizeof(uint64_t):
68 return (uint32_t)(*(uint64_t *)str);
69 default:
70 break;
71 }
72
73 __ASSERT(false, "invalid str length %zu", n);
74
75 return 0;
76 }
77
78 /**
79 * @brief Daniel J.\ Bernstein's hash function
80 *
81 * Some notes:
82 * - normally, this hash function is used on NUL-terminated strings
83 * - it has been modified to support arbitrary sequences of bytes
84 * - it has been modified to use XOR rather than addition
85 *
86 * @param str a string of input data
87 * @param n the number of bytes in @p str
88 *
89 * @return the numeric hash associated with @p str
90 *
91 * @note enable with @kconfig{CONFIG_SYS_HASH_FUNC32_DJB2}
92 *
93 * @see https://theartincode.stanis.me/008-djb2/
94 */
95 uint32_t sys_hash32_djb2(const void *str, size_t n);
96
97 /**
98 * @brief Murmur3 hash function
99 *
100 * @param str a string of input data
101 * @param n the number of bytes in @p str
102 *
103 * @return the numeric hash associated with @p str
104 *
105 * @note enable with @kconfig{CONFIG_SYS_HASH_FUNC32_MURMUR3}
106 *
107 * @see https://en.wikipedia.org/wiki/MurmurHash
108 */
109 uint32_t sys_hash32_murmur3(const void *str, size_t n);
110
111 /**
112 * @brief System default 32-bit hash function
113 *
114 * @param str a string of input data
115 * @param n the number of bytes in @p str
116 *
117 * @return the numeric hash associated with @p str
118 */
sys_hash32(const void * str,size_t n)119 static inline uint32_t sys_hash32(const void *str, size_t n)
120 {
121 if (IS_ENABLED(CONFIG_SYS_HASH_FUNC32_CHOICE_IDENTITY)) {
122 return sys_hash32_identity(str, n);
123 }
124
125 if (IS_ENABLED(CONFIG_SYS_HASH_FUNC32_CHOICE_DJB2)) {
126 return sys_hash32_djb2(str, n);
127 }
128
129 if (IS_ENABLED(CONFIG_SYS_HASH_FUNC32_CHOICE_MURMUR3)) {
130 return sys_hash32_murmur3(str, n);
131 }
132
133 __ASSERT(0, "No default 32-bit hash. See CONFIG_SYS_HASH_FUNC32_CHOICE");
134
135 return 0;
136 }
137
138 /**
139 * @}
140 */
141
142 #ifdef __cplusplus
143 }
144 #endif
145
146 #endif /* ZEPHYR_INCLUDE_SYS_HASH_FUNCTION_H_ */
147