Swadge 2024 2.0.0
APIs to develop games for the Magfest Swadge
|
A generic map for storing arbitrary key-value pairs.
This is a generic hash map data structure, which supports the basic put, get, and remove operations, as well as iteration. By default, keys are assumed to be nul-terminated strings, but any type can be used if alternate hash and equality functions are supplied. The hash map will automatically resize itself once it becomes about 75% full, but setting a sufficiently large initial capacity will improve efficiency overall.
Keys inserted into the map must remain valid for the duration they are in the map, as the map maintains a reference rather than copying them. This also means that modifying the key itself after it has been inserted into the map will cause it to become inaccessible, so using immutable data as pointers is also recommended. To change the key of an entry in the map, remove it and add it with the new key instead.
Basic operations against the hash map have O(1) time in the average case, with O(n) time in the worst case. Hash collisions are handled by storing multiple items within the same bucket in a linked list. Resizing is O(k), where k is the number of buckets in the hash map, and should occur once in every k put operations.
Iteration over the map is O(k) best case, O(k+n) worst case, and O(k) average case, as we do not know ahead of time which buckets or keys are in use. This could theoretically be improved to O(n) worst case if keys were also kept in a separate array, but this would be a marginal improvement with a lot of added complexity.
It's important to note that, even though the hash map is a reasonably efficient data structure, its main use case is really for convenience. Due to the added overhead of the hashing operation and traversal of the relatively complex hash map structure, in most cases its real-world performance will be worse than a simple linear search through an array, up to a surprisingly large number of items. With that said, this is unlikely to be a real concern in almost all situations. So unless a massive number of hash map operations is actually causing performance issues, it's best to avoid premature optimization and instead just use whatever is the most convenient and results in the simplest code.
hashInit() allocates a new hash map for use with string keys.
hashPut() adds a new entry to the map or updates the value of an existing one.
hashGet() retrieves a value from the map.
hashRemove() removes an entry from the map by its key.
hashDeinit() deallocates a hash map and all its entries.
hashIterate() can be used to loop over a hash map's entries.
hashIterReset() is used to reset an iterator if iteration stopped before hashIterate() returned false.
hashIterRemove() can be used to safely remove entries during iteration.
hashPutBin(), hashGetBin(), and hashRemoveBin() are variants of the normal hash map functions which accept a void pointer in the key
argument, rather than a char pointer. You must provide hash and equality functions to hashInitBin() in order to safely use keys which are not nul-terminated strings.
hashString() and strEq() are the default hash and comparison functions respectively, and will be used when the hash map is initialized with hashInit().
hashInt() and intsEq() are alternative hash and comparison functions that operate directly on a pointer address without dereferencing it. They can also be used when the key is any int or enum type that is not wider than a void*
.
hashBytes(), and bytesEq() are helper functions useful when implementing custom hash and comparison functions, particularly when the key is a struct pointer, with fields or data that must be included in the hash. Default implementations can't be supplied for a struct, since their length is not known to the hash map and the user implementer may wish to exclude some fields from the comparison or traverse nested values.
Create a hash map, add and retrieve some values:
Iterate over items in the map:
Remove items while iterating:
Breaking iteration early:
The hash map also supports using structs or even primitives as key types, instead of strings. This can be done using hashInitBin() to supply custom hashing and comparison functions appropriate for the type of key being used.
This example shows how to use a hash map where the keys are enum values. This method will work with any numeric type, as long as sizeof(type)
is less than or equal to sizeof(void*)
– that is, as long as its value fits inside a pointer. In practice this means an int32_t
can be used as a key in a hash map in this way, but an int64_t
cannot.
This example shows how to use an entire structure as a key for the hash map, using the hashBytes() and bytesEq() helper functions.
Go to the source code of this file.
Data Structures | |
struct | hashIterator_t |
Struct used for iterating through a hash map efficiently. More... | |
struct | hashMap_t |
A hash map for storing key-value pairs. More... | |
Typedefs | |
typedef uint32_t(* | hashFunction_t) (const void *data) |
A function that takes a pointer to key data and returns its hash value. | |
typedef bool(* | eqFunction_t) (const void *a, const void *b) |
A function that takes two pointers to keys and returns true if the values they point to are equal. | |
typedef struct hashBucket | hashBucket_t |
typedef struct hashIterState | hashIterState_t |
Functions | |
uint32_t | hashString (const void *str) |
Convert a NULL-terminated string to a hash value. | |
bool | strEq (const void *a, const void *b) |
Compare two NUL-terminated strings. | |
uint32_t | hashBytes (const uint8_t *bytes, size_t length) |
Convert an arbitrary byte sequence to a hash value. | |
bool | bytesEq (const uint8_t *a, size_t aLength, const uint8_t *b, size_t bLength) |
Compare two byte arrays. | |
uint32_t | hashInt (const void *intKey) |
Convert a pointer address or integral value to a hash value. | |
bool | intsEq (const void *keyA, const void *keyB) |
Compare two void pointers based on their address, or two integer types cast to a void pointer. | |
void | hashPut (hashMap_t *map, const char *key, void *value) |
Create or update a key-value pair in the hash map with a string key. | |
void * | hashGet (hashMap_t *map, const char *key) |
Return the value in the hash map associated with the given string key. | |
void * | hashRemove (hashMap_t *map, const char *key) |
Remove the value with a given string key from the hash map. | |
void | hashPutBin (hashMap_t *map, const void *key, void *value) |
Create or update a key-value pair in the hash map with a non-string key. | |
void * | hashGetBin (hashMap_t *map, const void *key) |
Return the value in the hash map associated with the given key. | |
void * | hashRemoveBin (hashMap_t *map, const void *key) |
Remove the value with a given non-string key from the hash map. | |
void | hashInit (hashMap_t *map, int initialSize) |
Initialize a hash map for string keys. | |
void | hashInitBin (hashMap_t *map, int initialSize, hashFunction_t hashFunc, eqFunction_t eqFunc) |
Initialize a hash map for non-string keys, using the given functions for hashing and comparison. | |
void | hashDeinit (hashMap_t *map) |
Deinitialize and free all memory associated with the given hash map. | |
bool | hashIterate (const hashMap_t *map, hashIterator_t *iterator) |
Advance the given iterator to the next item, or return false if there is no next item. | |
bool | hashIterRemove (hashMap_t *map, hashIterator_t *iter) |
Remove the last item returned by the iterator from the hash map. | |
void | hashIterReset (hashIterator_t *iterator) |
Reset the given iterator struct, freeing any memory associated with it. | |
void | hashReport (const hashMap_t *map) |
Prints out a detailed report on the hash map state. | |
struct hashIterator_t |
Data Fields | ||
---|---|---|
const void * | key | The key of the current key-value pair. |
void * | value | The value of the current key-value pair. |
hashIterState_t * | _state |
struct hashMap_t |
Data Fields | ||
---|---|---|
int | size | The total number of allocated buckets in the hash map. |
int | count | The actual number of items stored in the hash map. |
hashBucket_t * | values | The array of bucket values. |
hashFunction_t | hashFunc | The key hash function to use, or NULL to use hashString() |
eqFunction_t | eqFunc | The key equality function to use, or NULL to use strEq() |
typedef uint32_t(* hashFunction_t) (const void *data) |
A function that takes a pointer to key data and returns its hash value.
data | The data to hash |
typedef bool(* eqFunction_t) (const void *a, const void *b) |
A function that takes two pointers to keys and returns true if the values they point to are equal.
typedef struct hashBucket hashBucket_t |
typedef struct hashIterState hashIterState_t |
uint32_t hashString | ( | const void * | str | ) |
Convert a NULL-terminated string to a hash value.
Uses the 'djb2' algorithm, described at http://www.cse.yorku.ca/~oz/hash.html
str | The string to hash |
bool strEq | ( | const void * | a, |
const void * | b ) |
Compare two NUL-terminated strings.
a | The first string to compare |
b | The second string to compare |
uint32_t hashBytes | ( | const uint8_t * | bytes, |
size_t | length ) |
Convert an arbitrary byte sequence to a hash value.
Uses the 'djb2' algorithm, described at http://www.cse.yorku.ca/~oz/hash.html
bytes | A pointer to a byte array to hash |
length | The length of the byte array |
bool bytesEq | ( | const uint8_t * | a, |
size_t | aLength, | ||
const uint8_t * | b, | ||
size_t | bLength ) |
Compare two byte arrays.
a | A pointer to the first byte array |
aLength | The length of the first byte array |
b | A pointer to the second byte array |
bLength | The length of the second byte array |
uint32_t hashInt | ( | const void * | intKey | ) |
Convert a pointer address or integral value to a hash value.
The pointer is not dereferenced.
intKey | A void pointer whose address will be hashed, or any integral type cast to a void pointer |
bool intsEq | ( | const void * | keyA, |
const void * | keyB ) |
Compare two void pointers based on their address, or two integer types cast to a void pointer.
The pointers are not dereferenced.
keyA | The first pointer value |
keyB | The second pointer value |
void hashPut | ( | hashMap_t * | map, |
const char * | key, | ||
void * | value ) |
Create or update a key-value pair in the hash map with a string key.
map | The hash map to update |
key | The string key to associate the value with |
value | The value to add to the map |
void * hashGet | ( | hashMap_t * | map, |
const char * | key ) |
Return the value in the hash map associated with the given string key.
map | The hash map to search |
key | The string key to retrieve the value for |
void * hashRemove | ( | hashMap_t * | map, |
const char * | key ) |
Remove the value with a given string key from the hash map.
map | The hash map to remove from |
key | The string key to remove the value for |
void hashPutBin | ( | hashMap_t * | map, |
const void * | key, | ||
void * | value ) |
Create or update a key-value pair in the hash map with a non-string key.
map | The hash map to update |
key | The key to associate the value with |
value | The value to add to the map |
void * hashGetBin | ( | hashMap_t * | map, |
const void * | key ) |
Return the value in the hash map associated with the given key.
map | The hash map to search |
key | The key to retrieve the value for |
void * hashRemoveBin | ( | hashMap_t * | map, |
const void * | key ) |
Remove the value with a given non-string key from the hash map.
map | The hash map to remove from |
key | The non-string key to remove the value for |
void hashInit | ( | hashMap_t * | map, |
int | initialSize ) |
Initialize a hash map for string keys.
map | A pointer to a hashMap_t struct to be initialized |
initialSize | The initial size of the hash map |
void hashInitBin | ( | hashMap_t * | map, |
int | initialSize, | ||
hashFunction_t | hashFunc, | ||
eqFunction_t | eqFunc ) |
Initialize a hash map for non-string keys, using the given functions for hashing and comparison.
map | A pointer to a hashMap_t struct to be initialized |
initialSize | The initial size of the hash map |
hashFunc | The hash function to use for the key datatype |
eqFunc | The comparison function to use for the key datatype |
void hashDeinit | ( | hashMap_t * | map | ) |
Deinitialize and free all memory associated with the given hash map.
map | The map to deinitialize |
bool hashIterate | ( | const hashMap_t * | map, |
hashIterator_t * | iterator ) |
Advance the given iterator to the next item, or return false if there is no next item.
The iterator
should point to a zero-initialized struct at the start of iteration. Once iteration completes and this function returns false
, iterator
will be reset. If iteration is stopped before this function returns false
, the iterator must be reset with hashIterReset() to prevent memory leaks.
Items in the hash map are not returned in any particular order.
It is possible to remove items during iteration, but this must be done with hashIterRemove(). Using hashRemove() or hashRemoveBin() during iteration is not allowed and will cause undefined behavior.
Adding or udpating items during iteration is permitted, with the caveat that a new item inserted during iteration may or may not later be returned by the iterator.
[in] | map | The map to iterate over |
[in,out] | iterator | A pointer to a hashIterator_t struct |
bool hashIterRemove | ( | hashMap_t * | map, |
hashIterator_t * | iter ) |
Remove the last item returned by the iterator from the hash map.
This function does not need to search and so it always runs in constant time.
If you want to remove an item from the hash map while iterating over it, this function is the only safe way to do it.
map | The hash map to remove the item from |
iter | The iterator whose current item to remove from the hash map |
void hashIterReset | ( | hashIterator_t * | iterator | ) |
Reset the given iterator struct, freeing any memory associated with it.
iterator | A pointer to the iterator struct to be reset |
void hashReport | ( | const hashMap_t * | map | ) |
Prints out a detailed report on the hash map state.
This can be useful when testing to determine the effectiveness of a hash function.
map | The hash map to print the state of |