4 * This file is part of BeRTOS.
6 * Bertos is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * As a special exception, you may use this file as part of a free software
21 * library without restriction. Specifically, if other files instantiate
22 * templates or use macros or inline functions from this file, or you compile
23 * this file and link it with other files to produce an executable, this
24 * file does not by itself cause the resulting executable to be covered by
25 * the GNU General Public License. This exception does not however
26 * invalidate any other reasons why the executable file might be covered by
27 * the GNU General Public License.
29 * Copyright 2004, 2006, 2008 Develer S.r.l. (http://www.develer.com/)
30 * Copyright 2004 Giovanni Bajo
33 * \author Giovanni Bajo <rasky@develer.com>
35 * \brief Portable hash table
37 * This file implements a portable hash table, with the following features:
39 * \li Open double-hashing. The maximum number of elements is fixed. The double hashing
40 * function improves recovery in case of collisions.
41 * \li Configurable size (which is clamped to a power of two)
42 * \li Visiting interface through iterator (returns the element in random order).
43 * \li The key is stored within the data and a hook is used to extract it. Optionally, it
44 * is possible to store a copy of the key within the hash table.
46 * Since the hashing is open, there is no way to remove elements from the table. Instead, a
47 * function is provided to clear the table completely.
49 * The data stored within the table must be a pointer. The NULL pointer is used as
50 * a marker for a free node, so it is invalid to store a NULL pointer in the table
51 * with \c ht_insert().
53 * $WIZ$ module_name = "hashtable"
54 * $WIZ$ module_configuration = "bertos/cfg/cfg_hashtable.h"
57 #ifndef STRUCT_HASHTABLE_H
58 #define STRUCT_HASHTABLE_H
60 #include "cfg/cfg_hashtable.h"
62 #include <cfg/compiler.h>
63 #include <cfg/macros.h>
64 #include <cfg/debug.h>
66 /// Maximum length of the internal key (use (2^n)-1 for slight speedup)
67 #define INTERNAL_KEY_MAX_LENGTH 15
70 * Hook to get the key from \a data, which is an element of the hash table. The
71 * key must be returned together with \a key_length (in words).
73 typedef const void *(*hook_get_key)(const void *data, uint8_t *key_length);
77 * Hash table description
79 * \note This structures MUST NOT be accessed directly. Its definition is
80 * provided in the header file only for optimization purposes (see the rationale
83 * \note If new elements must be added to this list, please double check
84 * \c DECLARE_HASHTABLE, which requires the existing elements to be at the top.
88 const void **mem; ///< Buckets of data
89 uint16_t max_elts_log2; ///< Log2 of the size of the table
91 bool key_internal : 1; ///< true if the key is copied internally
94 hook_get_key hook; ///< Hook to get the key
95 uint8_t *mem; ///< Pointer to the key memory
100 /// Iterator to walk the hash table
109 * Declare a hash table in the current scope
111 * \param name Variable name
112 * \param size Number of elements
113 * \param hook_gk Hook to be used to extract the key from the node
115 * \note The number of elements will be rounded down to the nearest
119 #define DECLARE_HASHTABLE(name, size, hook_gk) \
120 static const void* name##_nodes[1 << UINT32_LOG2(size)]; \
121 struct HashTable name = \
123 .mem = name##_nodes, \
124 .max_elts_log2 = UINT32_LOG2(size), \
125 .flags = { .key_internal = false }, \
126 .key_data.hook = hook_gk \
130 /** Exactly like \c DECLARE_HASHTABLE, but the variable will be declared as static. */
131 #define DECLARE_HASHTABLE_STATIC(name, size, hook_gk) \
132 static const void* name##_nodes[1 << UINT32_LOG2(size)]; \
133 static struct HashTable name = \
135 .mem = name##_nodes, \
136 .max_elts_log2 = UINT32_LOG2(size), \
137 .flags = { .key_internal = false }, \
138 .key_data.hook = hook_gk \
141 #if CONFIG_HT_OPTIONAL_INTERNAL_KEY
142 /** Declare a hash table with internal copies of the keys. This version does not
143 * require a hook, nor it requires the user to allocate static memory for the keys.
144 * It is mostly suggested for tables whose keys are computed on the fly and need
145 * to be stored somewhere.
147 #define DECLARE_HASHTABLE_INTERNALKEY(name, size) \
148 static uint8_t name##_keys[(1 << UINT32_LOG2(size)) * (INTERNAL_KEY_MAX_LENGTH + 1)]; \
149 static const void* name##_nodes[1 << UINT32_LOG2(size)]; \
150 struct HashTable name = { name##_nodes, UINT32_LOG2(size), { true }, name##_keys }
152 /** Exactly like \c DECLARE_HASHTABLE_INTERNALKEY, but the variable will be declared as static. */
153 #define DECLARE_HASHTABLE_INTERNALKEY_STATIC(name, size) \
154 static uint8_t name##_keys[(1 << UINT32_LOG2(size)) * (INTERNAL_KEY_MAX_LENGTH + 1)]; \
155 static const void* name##_nodes[1 << UINT32_LOG2(size)]; \
156 static struct HashTable name = \
158 .mem = name##_nodes, \
159 .max_elts_log2 = UINT32_LOG2(size), \
160 .flags = { .key_internal = true }, \
161 .key_data.mem = name##_keys \
166 * Initialize (and clear) a hash table in a memory buffer.
168 * \param ht Hash table declared with \c DECLARE_HASHTABLE
170 * \note This function must be called before using the hash table. Optionally,
171 * it can be called later in the program to clear the hash table,
172 * removing all its elements.
174 void ht_init(struct HashTable* ht);
177 * Insert an element into the hash table
179 * \param ht Handle of the hash table
180 * \param data Data to be inserted into the table
181 * \return true if insertion was successful, false otherwise (table is full)
183 * \note The key for the element to insert is extract from the data with
184 * the hook. This means that this function cannot be called for hashtables
185 * with internal keys.
187 * \note If an element with the same key already exists in the table,
188 * it will be overwritten.
190 * \note It is not allowed to store NULL in the table. If you pass NULL as data,
191 * the function call will fail.
193 bool ht_insert(struct HashTable* ht, const void* data);
196 * Insert an element into the hash table
198 * \param ht Handle of the hash table
199 * \param key Key of the element
200 * \param key_length Length of the key in characters
201 * \param data Data to be inserted into the table
202 * \return true if insertion was successful, false otherwise (table is full)
204 * \note If this function is called for hash table with external keys,
205 * the key provided must be match the key that would be extracted with the
206 * hook, otherwise the function will fail.
208 * \note If an element with the same key already exists in the table,
209 * it will be overwritten.
211 * \note It is not allowed to store NULL in the table. If you pass NULL as data,
212 * the function call will fail.
214 bool ht_insert_with_key(struct HashTable* ht, const void* key, uint8_t key_length, const void* data);
217 * Find an element in the hash table
219 * \param ht Handle of the hash table
220 * \param key Key of the element
221 * \param key_length Length of the key in characters
222 * \return Data of the element, or NULL if no element was found for the given key.
224 const void* ht_find(struct HashTable* ht, const void* key, uint8_t key_length);
226 /** Similar to \c ht_insert_with_key() but \a key is an ASCIIZ string */
227 #define ht_insert_str(ht, key, data) ht_insert_with_key(ht, key, strlen(key), data)
229 /** Similar to \c ht_find() but \a key is an ASCIIZ string */
230 #define ht_find_str(ht, key) ht_find(ht, key, strlen(key))
232 /// Get an iterator to the begin of the hash table \a ht
233 INLINE HashIterator ht_iter_begin(struct HashTable* ht)
238 h.end = &ht->mem[1 << ht->max_elts_log2];
240 while (h.pos != h.end && !*h.pos)
247 * Get an iterator to the (exclusive) end of the hash table \a ht
249 * \note Like in STL, the end iterator is not a valid iterator (you
250 * cannot call \c ht_iter_get() on it), and it must be used only to
251 * detect if we reached the end of the iteration (through \c ht_iter_cmp()).
253 INLINE HashIterator ht_iter_end(struct HashTable* ht)
257 h.pos = h.end = &ht->mem[1 << ht->max_elts_log2];
262 /// Compare \a it1 and \a it2 for equality
263 INLINE bool ht_iter_cmp(HashIterator it1, HashIterator it2)
265 ASSERT(it1.end == it2.end);
266 return it1.pos == it2.pos;
269 /// Get the element within the hash table \a ht pointed by the iterator \a iter
270 INLINE const void* ht_iter_get(HashIterator iter)
271 { return *iter.pos; }
273 /** Return an iterator pointing to the element following \a h
275 * \note The order of the elements visited during the iteration is casual,
276 * and depends on the implementation.
279 INLINE HashIterator ht_iter_next(HashIterator h)
282 while (h.pos != h.end && !(*h.pos))
288 int hashtable_testSetup(void);
289 int hashtable_testRun(void);
290 int hashtable_testTearDown(void);
292 #endif /* STRUCT_HASHTABLE_H */