From cadde0b61e1343610b4b028e9b5035b460ce5879 Mon Sep 17 00:00:00 2001 From: CismonX Date: Thu, 6 Mar 2025 10:33:15 +0800 Subject: [PATCH] doc: update docs for the utility library Move documentation for the hash table from source code comments to the user manual. --- doc/bookmarkfs.texi | 236 ++++++++++++++++++++++++++++++++++++++++++++ src/hashmap.h | 42 -------- 2 files changed, 236 insertions(+), 42 deletions(-) diff --git a/doc/bookmarkfs.texi b/doc/bookmarkfs.texi index 9a3358c..68a5724 100644 --- a/doc/bookmarkfs.texi +++ b/doc/bookmarkfs.texi @@ -3731,6 +3731,242 @@ An opaque pointer to be passed to the @code{callback} function. @node Hash Tables @section Hash Tables +A simple hash table implementation, based on a variant of +@uref{https://en.wikipedia.org/wiki/Hopscotch_hashing, Hopscotch Hashing}. + +Time complexity: + +@multitable @columnfractions .33 .33 .33 +@headitem Operation @tab Average @tab Worst case +@item Insert @tab @t{Θ(1)} @tab @t{O(n log n)} +@item Search @tab @t{Θ(1)} @tab @t{O(log n)} +@item Delete @tab @t{Θ(1)} @tab @t{O(log n)} +@end multitable + +Functions: + +@table @code +@item hashmap_create +Creates a new hash table. + +@example c +#include + +struct hashmap * +hashmap_create ( + hashmap_comp_func *entry_comp, + hashmap_hash_func *entry_hash +); +@end example + +Function arguments: + +@table @code +@item entry_comp +The callback function for checking whether a key matches an entry. + +Type of @code{entry_comp} is defined as: + +@example c +typedef int (hashmap_comp_func) ( + union hashmap_key key, + void const *entry +); +@end example + +The function should return @t{0} if the objects match, non-zero if not. + +@item entry_hash +The callback function for obtaining the hashcode for an entry. + +Type of @code{entry_hash} is defined as: + +@example c +typedef unsigned long (hashmap_hash_func) ( + void const *entry +); +@end example + +This function is only called during rehashing and @code{hashmap_entry_delete}. +@end table + +Returns an opaque pointer referring to the new hash table. + +@item hashmap_insert +Inserts a new entry into a hash table. + +@example c +void +hashmap_insert ( + struct hashmap *map, + unsigned long hashcode, + void *entry +); +@end example + +Function arguments: + +@table @code +@item map +The hash table to insert entry into. + +@item hashcode +The hash code for the new entry. + +@item entry +An arbitrary pointer to be associated with the new entry. +It must not be @code{NULL}. +@end table + +@item hashmap_search +Searches for an entry in a hash table. + +@example c +void * +hashmap_search ( + struct hashmap const *map, + union hashmap_key key, + unsigned long hashcode, + unsigned long *entry_id_ptr +); +@end example + +Function arguments: + +@table @code +@item map +The hash table to search from. + +@item key +An object to identify the entry being searched. + +Type of the @code{hashmap_key} union is defined as: + +@example c +union hashmap_key @{ + void const *ptr; + uint64_t u64; +@}; +@end example + +For each entry in the hash table with the given @code{hashcode}, +the @code{entry_comp} callback function is called with @code{key} +as the first argument, until a matching entry is found. + +@item hashcode +The hash code for the entry to search. + +@item entry_id_ptr +If not @code{NULL}, and a matching entry is found, +the function sets @code{*entry_id_ptr} to an opaque integer value, +which can be used to identify the entry when calling @code{hashmap_delete()}. + +A subsequent call to @code{hashmap_insert()} and @code{hashmap_delete()} +on this hash table invalidates that value. +@end table + +Returns the pointer associated with the entry, +or @code{NULL} if no matching entry is found. + +@item hashmap_delete +Removes an entry from a hash table. + +@example c +void +hashmap_delete ( + struct hashmap *map, + void const *entry, + long entry_id +); +@end example + +Function arguments: + +@table @code +@item map +The hash table to delete entry from. + +@item entry +The entry to be deleted from the hash table. + +If the hash table does not contain this entry, function behavior is undefined. + +@item entry_id +An opaque integer obtained from @code{hashmap_search()} which identifies +the entry to be deleted. +If not readily available, @t{-1} should be used. + +If provided, the delete operation is always of @t{O(1)} time complexity. +@end table + +@item hashmap_foreach +Iterates through all entries of a hash table. + +@example c +void +hashmap_foreach ( + struct hashmap const *map, + hashmap_walk_func *walk_func, + void *user_data +); +@end example + +Function arguments: + +@table @code +@item map +The hash table to traverse. + +@item walk_func +The callback function to be called for each entry. + +Type of @code{walk_func} is defined as: + +@example c +typedef void (hashmap_walk_func) ( + void *entry, + void *user_data +); +@end example + +The callback function must not insert to or delete from the current hash table. + +@item user_data +An opaque pointer to be passed to @code{walk_func}. +@end table + +@item hashmap_destroy +Destroys a hash table. + +@example c +void +hashmap_destroy ( + struct hashmap *map +); +@end example + +Function arguments: + +@table @code +@item map +The hash table to destroy. +If @code{NULL}, this function has no effect. +@end table +@end table + +Limitations: + +@itemize @bullet{} +@item Insertion performance is sacrificed in favor of search performance. + +@item Suffers more from collisions than traditional open addressing. + +@item Performance is suboptimal without hardware support for +@uref{https://en.wikipedia.org/wiki/Find_first_set, Find First Set}. + +@item Concurrent writes on the same hash table is MT-Unsafe. +@end itemize + @node Pseudo-Random Number Generator @section Pseudo-Random Number Generator diff --git a/src/hashmap.h b/src/hashmap.h index 5272289..6d9be50 100644 --- a/src/hashmap.h +++ b/src/hashmap.h @@ -37,28 +37,15 @@ typedef void (hashmap_walk_func) ( void *entry ); -/** - * Obtain the hashcode for an entry. - * - * This function is only called during rehash and entry delete. - */ typedef unsigned long (hashmap_hash_func) ( void const *entry ); -/** - * Check if the given key matches an entry in the hashmap. - * - * Returns 0 if matches, non-zero if not. - */ typedef int (hashmap_comp_func) ( union hashmap_key key, void const *entry ); -/** - * Creates a new hashmap with given callback functions. - */ struct hashmap * hashmap_create ( hashmap_comp_func *entry_comp, @@ -70,10 +57,6 @@ hashmap_destroy ( struct hashmap *map ); -/** - * Apply the walk_func callback to each entry in hashmap, - * passing user_data as its second argument. - */ void hashmap_foreach ( struct hashmap const *map, @@ -81,18 +64,6 @@ hashmap_foreach ( void *user_data ); -/** - * Search for an entry in the hashmap that matches the given key. - * - * If the key matches multiple entries, - * it is unspecified which one will return. - * - * If entry_id_ptr is not NULL, on a successful lookup, - * it will be set to a value that can be later be passed to - * hashmap_entry_delete(). - * - * Returns an entry if found, or NULL if not. - */ void * hashmap_search ( struct hashmap const *map, @@ -101,11 +72,6 @@ hashmap_search ( unsigned long *entry_id_ptr ); -/** - * Insert an entry into the hashmap. - * - * Invalidates all entry IDs given by previous hashmap_search() calls. - */ void hashmap_insert ( struct hashmap *map, @@ -113,14 +79,6 @@ hashmap_insert ( void *entry ); -/** - * Remove an entry from the hashmap. - * Undefined behavior if the entry does not exist in hashmap. - * - * The entry_id argument should either be the value given by the - * hashmap_search() or hashmap_insert() function call where the - * entry is returned from, or -1 (less efficient). - */ void hashmap_delete ( struct hashmap *map,