/*1Simple DirectMedia Layer2Copyright (C) 1997-2025 Sam Lantinga <[email protected]>34This software is provided 'as-is', without any express or implied5warranty. In no event will the authors be held liable for any damages6arising from the use of this software.78Permission is granted to anyone to use this software for any purpose,9including commercial applications, and to alter it and redistribute it10freely, subject to the following restrictions:11121. The origin of this software must not be misrepresented; you must not13claim that you wrote the original software. If you use this software14in a product, an acknowledgment in the product documentation would be15appreciated but is not required.162. Altered source versions must be plainly marked as such, and must not be17misrepresented as being the original software.183. This notice may not be removed or altered from any source distribution.19*/2021/* this is over-documented because it was almost a public API. Leaving the22full docs here in case it _does_ become public some day. */2324/* WIKI CATEGORY: HashTable */2526/**27* # CategoryHashTable28*29* SDL offers a hash table implementation, as a convenience for C code that30* needs efficient organization and access of arbitrary data.31*32* Hash tables are a popular data structure, designed to make it quick to33* store and look up arbitrary data. Data is stored with an associated "key."34* While one would look up an element of an array with an index, a hash table35* uses a unique key to find an element later.36*37* A key can be anything, as long as its unique and in a format that the table38* understands. For example, it's popular to use strings as keys: the key39* might be a username, and it is used to lookup account information for that40* user, etc.41*42* Hash tables are named because they "hash" their keys down into simple43* integers that can be used to efficiently organize and access the associated44* data.45*46* As this is a C API, there is one generic interface that is intended to work47* with different data types. This can be a little awkward to set up, but is48* easy to use after that.49*50* Hashtables are generated by a call to SDL_CreateHashTable(). This function51* requires several callbacks to be provided (for hashing keys, comparing52* entries, and cleaning up entries when removed). These are necessary to53* allow the hash to manage any arbitrary data type.54*55* Once a hash table is created, the common tasks are inserting data into the56* table, (SDL_InsertIntoHashTable), looking up previously inserted data57* (SDL_FindInHashTable), and removing data (SDL_RemoveFromHashTable and58* SDL_ClearHashTable). Less common but still useful is the ability to59* iterate through all the items in the table (SDL_IterateHashTable).60*61* The underlying hash table implementation is always subject to change, but62* at the time of writing, it uses open addressing and Robin Hood hashing.63* The technical details are explained [here](https://github.com/libsdl-org/SDL/pull/10897).64*65* Hashtables keep an SDL_RWLock internally, so multiple threads can perform66* hash lookups in parallel, while changes to the table will safely serialize67* access between threads.68*69* SDL provides a layer on top of this hash table implementation that might be70* more pleasant to use. SDL_PropertiesID maps a string to arbitrary data of71* various types in the same table, which could be both easier to use and more72* flexible. Refer to [CategoryProperties](CategoryProperties) for details.73*/7475#ifndef SDL_hashtable_h_76#define SDL_hashtable_h_7778#include <SDL3/SDL_stdinc.h>7980#include <SDL3/SDL_begin_code.h>81/* Set up for C function definitions, even when using C++ */82#ifdef __cplusplus83extern "C" {84#endif8586/**87* The opaque type that represents a hash table.88*89* This is hidden behind an opaque pointer because not only does the table90* need to store arbitrary data types, but the hash table implementation may91* change in the future.92*93* \since This struct is available since SDL 3.4.0.94*95* \sa SDL_CreateHashTable96*/97typedef struct SDL_HashTable SDL_HashTable;9899/**100* A function pointer representing a hash table hashing callback.101*102* This is called by SDL_HashTable when it needs to look up a key in103* its dataset. It generates a hash value from that key, and then uses that104* value as a basis for an index into an internal array.105*106* There are no rules on what hashing algorithm is used, so long as it107* can produce a reliable 32-bit value from `key`, and ideally distributes108* those values well across the 32-bit value space. The quality of a109* hashing algorithm is directly related to how well a hash table performs.110*111* Hashing can be a complicated subject, and often times what works best112* for one dataset will be suboptimal for another. There is a good discussion113* of the field [on Wikipedia](https://en.wikipedia.org/wiki/Hash_function).114*115* Also: do you _need_ to write a hashing function? SDL provides generic116* functions for strings (SDL_HashString), generic integer IDs (SDL_HashID),117* and generic pointers (SDL_HashPointer). Often you should use one of these118* before writing your own.119*120* \param userdata what was passed as `userdata` to SDL_CreateHashTable().121* \param key the key to be hashed.122* \returns a 32-bit value that represents a hash of `key`.123*124* \threadsafety This function must be thread safe if the hash table is used125* from multiple threads at the same time.126*127* \since This datatype is available since SDL 3.4.0.128*129* \sa SDL_CreateHashTable130* \sa SDL_HashString131* \sa SDL_HashID132* \sa SDL_HashPointer133*/134typedef Uint32 (SDLCALL *SDL_HashCallback)(void *userdata, const void *key);135136137/**138* A function pointer representing a hash table matching callback.139*140* This is called by SDL_HashTable when it needs to look up a key in its141* dataset. After hashing the key, it looks for items stored in relation to142* that hash value. Since there can be more than one item found through the143* same hash value, this function verifies a specific value is actually144* correct before choosing it.145*146* So this function needs to compare the keys at `a` and `b` and decide if147* they are actually the same.148*149* For example, if the keys are C strings, this function might just be:150*151* ```c152* return (SDL_strcmp((const char *) a, const char *b) == 0);`153* ```154*155* Also: do you _need_ to write a matching function? SDL provides generic156* functions for strings (SDL_KeyMatchString), generic integer IDs157* (SDL_KeyMatchID), and generic pointers (SDL_KeyMatchPointer). Often you158* should use one of these before writing your own.159*160* \param userdata what was passed as `userdata` to SDL_CreateHashTable().161* \param a the first key to be compared.162* \param b the second key to be compared.163* \returns true if two keys are identical, false otherwise.164*165* \threadsafety This function must be thread safe if the hash table is used166* from multiple threads at the same time.167*168* \since This datatype is available since SDL 3.4.0.169*170* \sa SDL_CreateHashTable171*/172typedef bool (SDLCALL *SDL_HashKeyMatchCallback)(void *userdata, const void *a, const void *b);173174175/**176* A function pointer representing a hash table cleanup callback.177*178* This is called by SDL_HashTable when removing items from the hash, or179* destroying the hash table. It is used to optionally deallocate the180* key/value pairs.181*182* This is not required to do anything, if all the data in the table is183* static or POD data, but it can also do more than a simple free: for184* example, if the hash table is storing open files, it can close them here.185* It can also free only the key or only the value; it depends on what the186* hash table contains.187*188* \param userdata what was passed as `userdata` to SDL_CreateHashTable().189* \param key the key to deallocate.190* \param value the value to deallocate.191*192* \threadsafety This function must be thread safe if the hash table is used193* from multiple threads at the same time.194*195* \since This datatype is available since SDL 3.4.0.196*197* \sa SDL_CreateHashTable198*/199typedef void (SDLCALL *SDL_HashDestroyCallback)(void *userdata, const void *key, const void *value);200201202/**203* A function pointer representing a hash table iterator callback.204*205* This function is called once for each key/value pair to be considered206* when iterating a hash table.207*208* Iteration continues as long as there are more items to examine and this209* callback continues to return true.210*211* Do not attempt to modify the hash table during this callback, as it will212* cause incorrect behavior and possibly crashes.213*214* \param userdata what was passed as `userdata` to an iterator function.215* \param table the hash table being iterated.216* \param key the current key being iterated.217* \param value the current value being iterated.218* \returns true to keep iterating, false to stop iteration.219*220* \threadsafety A read lock is held during iteration, so other threads can221* still access the the hash table, but threads attempting to222* make changes will be blocked until iteration completes. If223* this is a concern, do as little in the callback as possible224* and finish iteration quickly.225*226* \since This datatype is available since SDL 3.4.0.227*228* \sa SDL_IterateHashTable229*/230typedef bool (SDLCALL *SDL_HashTableIterateCallback)(void *userdata, const SDL_HashTable *table, const void *key, const void *value);231232233/**234* Create a new hash table.235*236* To deal with different datatypes and needs of the caller, hash tables237* require several callbacks that deal with some specifics: how to hash a key,238* how to compare a key for equality, and how to clean up keys and values.239* SDL provides a few generic functions that can be used for these callbacks:240*241* - SDL_HashString and SDL_KeyMatchString for C strings.242* - SDL_HashPointer and SDL_KeyMatchPointer for generic pointers.243* - SDL_HashID and SDL_KeyMatchID for generic (possibly small) integers.244*245* Oftentimes, these are all you need for any hash table, but depending on246* your dataset, custom implementations might make more sense.247*248* You can specify an estimate of the number of items expected to be stored249* in the table, which can help make the table run more efficiently. The table250* will preallocate resources to accomodate this number of items, which is251* most useful if you intend to fill the table with a lot of data right after252* creating it. Otherwise, it might make more sense to specify the _minimum_253* you expect the table to hold and let it grow as necessary from there. This254* number is only a hint, and the table will be able to handle any amount of255* data--as long as the system doesn't run out of resources--so a perfect256* answer is not required. A value of 0 signifies no guess at all, and the257* table will start small and reallocate as necessary; often this is the258* correct thing to do.259*260* !!! FIXME: add note about `threadsafe` here. And update `threadsafety` tags.261* !!! FIXME: note that `threadsafe` tables can't be recursively locked, so262* !!! FIXME: you can't use `destroy` callbacks that might end up relocking.263*264* Note that SDL provides a higher-level option built on its hash tables:265* SDL_PropertiesID lets you map strings to various datatypes, and this266* might be easier to use. It only allows strings for keys, however. Those are267* created with SDL_CreateProperties().268*269* The returned hash table should be destroyed with SDL_DestroyHashTable()270* when no longer needed.271*272* \param estimated_capacity the approximate maximum number of items to be held273* in the hash table, or 0 for no estimate.274* \param threadsafe true to create an internal rwlock for this table.275* \param hash the function to use to hash keys.276* \param keymatch the function to use to compare keys.277* \param destroy the function to use to clean up keys and values, may be NULL.278* \param userdata a pointer that is passed to the callbacks.279* \returns a newly-created hash table, or NULL if there was an error; call280* SDL_GetError() for more information.281*282* \threadsafety It is safe to call this function from any thread.283*284* \since This function is available since SDL 3.4.0.285*286* \sa SDL_DestroyHashTable287*/288extern SDL_HashTable * SDL_CreateHashTable(int estimated_capacity,289bool threadsafe,290SDL_HashCallback hash,291SDL_HashKeyMatchCallback keymatch,292SDL_HashDestroyCallback destroy,293void *userdata);294295296/**297* Destroy a hash table.298*299* This will call the hash table's SDL_HashDestroyCallback for each item in300* the table, removing all inserted items, before deallocating the table301* itself.302*303* The table becomes invalid once this function is called, and no other thread304* should be accessing this table once this function has started.305*306* \param table the hash table to destroy.307*308* \threadsafety It is safe to call this function from any thread.309*310* \since This function is available since SDL 3.4.0.311*/312extern void SDL_DestroyHashTable(SDL_HashTable *table);313314/**315* Add an item to a hash table.316*317* All keys in the table must be unique. If attempting to insert a key that318* already exists in the hash table, what will be done depends on the319* `replace` value:320*321* - If `replace` is false, this function will return false without modifying322* the table.323* - If `replace` is true, SDL will remove the previous item first, so the new324* value is the only one associated with that key. This will call the hash325* table's SDL_HashDestroyCallback for the previous item.326*327* \param table the hash table to insert into.328* \param key the key of the new item to insert.329* \param value the value of the new item to insert.330* \param replace true if a duplicate key should replace the previous value.331* \returns true if the new item was inserted, false otherwise.332*333* \threadsafety It is safe to call this function from any thread.334*335* \since This function is available since SDL 3.4.0.336*/337extern bool SDL_InsertIntoHashTable(SDL_HashTable *table, const void *key, const void *value, bool replace);338339/**340* Look up an item in a hash table.341*342* On return, the value associated with `key` is stored to `*value`.343* If the key does not exist in the table, `*value` will be set to NULL.344*345* It is legal for `value` to be NULL, to not retrieve the key's value. In346* this case, the return value is still useful for reporting if the key exists347* in the table at all.348*349* \param table the hash table to search.350* \param key the key to search for in the table.351* \param value the found value will be stored here. Can be NULL.352* \returns true if key exists in the table, false otherwise.353*354* \threadsafety It is safe to call this function from any thread.355*356* \since This function is available since SDL 3.4.0.357*358* \sa SDL_InsertIntoHashTable359*/360extern bool SDL_FindInHashTable(const SDL_HashTable *table, const void *key, const void **value);361362/**363* Remove an item from a hash table.364*365* If there is an item that matches `key`, it is removed from the table. This366* will call the hash table's SDL_HashDestroyCallback for the item to be367* removed.368*369* \param table the hash table to remove from.370* \param key the key of the item to remove from the table.371* \returns true if a key was removed, false if the key was not found.372*373* \threadsafety It is safe to call this function from any thread.374*375* \since This function is available since SDL 3.4.0.376*/377extern bool SDL_RemoveFromHashTable(SDL_HashTable *table, const void *key);378379/**380* Remove all items in a hash table.381*382* This will call the hash table's SDL_HashDestroyCallback for each item in383* the table, removing all inserted items.384*385* When this function returns, the hash table will be empty.386*387* \param table the hash table to clear.388*389* \threadsafety It is safe to call this function from any thread.390*391* \since This function is available since SDL 3.4.0.392*/393extern void SDL_ClearHashTable(SDL_HashTable *table);394395/**396* Check if any items are currently stored in a hash table.397*398* If there are no items stored (the table is completely empty), this will399* return true.400*401* \param table the hash table to check.402* \returns true if the table is completely empty, false otherwise.403*404* \threadsafety It is safe to call this function from any thread.405*406* \since This function is available since SDL 3.4.0.407*408* \sa SDL_ClearHashTable409*/410extern bool SDL_HashTableEmpty(SDL_HashTable *table);411412/**413* Iterate all key/value pairs in a hash table.414*415* This function will call `callback` once for each key/value pair in the416* table, until either all pairs have been presented to the callback, or the417* callback has returned false to signal it is done.418*419* There is no guarantee what order results will be returned in.420*421* \param table the hash table to iterate.422* \param callback the function pointer to call for each value.423* \param userdata a pointer that is passed to `callback`.424* \returns true if iteration happened, false if not (bogus parameter, etc).425*426* \since This function is available since SDL 3.4.0.427*/428extern bool SDL_IterateHashTable(const SDL_HashTable *table, SDL_HashTableIterateCallback callback, void *userdata);429430431/* Helper functions for SDL_CreateHashTable callbacks... */432433/**434* Generate a hash from a generic pointer.435*436* The key is intended to be a unique pointer to any datatype.437*438* This is intended to be used as one of the callbacks to SDL_CreateHashTable,439* if this is useful to the type of keys to be used with the hash table.440*441* Note that the implementation may change in the future; do not expect442* the results to be stable vs future SDL releases. Use this in a hash table443* in the current process and don't store them to disk for the future.444*445* \param unused this parameter is ignored.446* \param key the key to hash as a generic pointer.447* \returns a 32-bit hash of the key.448*449* \threadsafety It is safe to call this function from any thread.450*451* \since This function is available since SDL 3.4.0.452*453* \sa SDL_CreateHashTable454*/455extern Uint32 SDL_HashPointer(void *unused, const void *key);456457/**458* Compare two generic pointers as hash table keys.459*460* This is intended to be used as one of the callbacks to SDL_CreateHashTable,461* if this is useful to the type of keys to be used with the hash table.462*463* \param unused this parameter is ignored.464* \param a the first generic pointer to compare.465* \param b the second generic pointer to compare.466* \returns true if the pointers are the same, false otherwise.467*468* \threadsafety It is safe to call this function from any thread.469*470* \since This function is available since SDL 3.4.0.471*472* \sa SDL_CreateHashTable473*/474extern bool SDL_KeyMatchPointer(void *unused, const void *a, const void *b);475476/**477* Generate a hash from a C string.478*479* The key is intended to be a NULL-terminated string, in UTF-8 format.480*481* This is intended to be used as one of the callbacks to SDL_CreateHashTable,482* if this is useful to the type of keys to be used with the hash table.483*484* Note that the implementation may change in the future; do not expect485* the results to be stable vs future SDL releases. Use this in a hash table486* in the current process and don't store them to disk for the future.487*488* \param unused this parameter is ignored.489* \param key the key to hash as a generic pointer.490* \returns a 32-bit hash of the key.491*492* \threadsafety It is safe to call this function from any thread.493*494* \since This function is available since SDL 3.4.0.495*496* \sa SDL_CreateHashTable497*/498extern Uint32 SDL_HashString(void *unused, const void *key);499500/**501* Compare two C strings as hash table keys.502*503* Strings will be compared in a case-sensitive manner. More specifically,504* they'll be compared as NULL-terminated arrays of bytes.505*506* This is intended to be used as one of the callbacks to SDL_CreateHashTable,507* if this is useful to the type of keys to be used with the hash table.508*509* \param unused this parameter is ignored.510* \param a the first string to compare.511* \param b the second string to compare.512* \returns true if the strings are the same, false otherwise.513*514* \threadsafety It is safe to call this function from any thread.515*516* \since This function is available since SDL 3.4.0.517*518* \sa SDL_CreateHashTable519*/520extern bool SDL_KeyMatchString(void *unused, const void *a, const void *b);521522/**523* Generate a hash from an integer ID.524*525* The key is intended to a unique integer, possibly within a small range.526*527* This is intended to be used as one of the callbacks to SDL_CreateHashTable,528* if this is useful to the type of keys to be used with the hash table.529*530* Note that the implementation may change in the future; do not expect531* the results to be stable vs future SDL releases. Use this in a hash table532* in the current process and don't store them to disk for the future.533*534* \param unused this parameter is ignored.535* \param key the key to hash as a generic pointer.536* \returns a 32-bit hash of the key.537*538* \threadsafety It is safe to call this function from any thread.539*540* \since This function is available since SDL 3.4.0.541*542* \sa SDL_CreateHashTable543*/544extern Uint32 SDL_HashID(void *unused, const void *key);545546/**547* Compare two integer IDs as hash table keys.548*549* This is intended to be used as one of the callbacks to SDL_CreateHashTable,550* if this is useful to the type of keys to be used with the hash table.551*552* \param unused this parameter is ignored.553* \param a the first ID to compare.554* \param b the second ID to compare.555* \returns true if the IDs are the same, false otherwise.556*557* \threadsafety It is safe to call this function from any thread.558*559* \since This function is available since SDL 3.4.0.560*561* \sa SDL_CreateHashTable562*/563extern bool SDL_KeyMatchID(void *unused, const void *a, const void *b);564565/**566* Free both the key and value pointers of a hash table item.567*568* This is intended to be used as one of the callbacks to SDL_CreateHashTable,569* if this is useful to the type of data to be used with the hash table.570*571* This literally calls `SDL_free(key);` and `SDL_free(value);`.572*573* \param unused this parameter is ignored.574* \param key the key to be destroyed.575* \param value the value to be destroyed.576*577* \threadsafety It is safe to call this function from any thread.578*579* \since This function is available since SDL 3.4.0.580*581* \sa SDL_CreateHashTable582*/583extern void SDL_DestroyHashKeyAndValue(void *unused, const void *key, const void *value);584585/**586* Free just the value pointer of a hash table item.587*588* This is intended to be used as one of the callbacks to SDL_CreateHashTable,589* if this is useful to the type of data to be used with the hash table.590*591* This literally calls `SDL_free(key);` and leaves `value` alone.592*593* \param unused this parameter is ignored.594* \param key the key to be destroyed.595* \param value the value to be destroyed.596*597* \threadsafety It is safe to call this function from any thread.598*599* \since This function is available since SDL 3.4.0.600*601* \sa SDL_CreateHashTable602*/603extern void SDL_DestroyHashKey(void *unused, const void *key, const void *value);604605/**606* Free just the value pointer of a hash table item.607*608* This is intended to be used as one of the callbacks to SDL_CreateHashTable,609* if this is useful to the type of data to be used with the hash table.610*611* This literally calls `SDL_free(value);` and leaves `key` alone.612*613* \param unused this parameter is ignored.614* \param key the key to be destroyed.615* \param value the value to be destroyed.616*617* \threadsafety It is safe to call this function from any thread.618*619* \since This function is available since SDL 3.4.0.620*621* \sa SDL_CreateHashTable622*/623extern void SDL_DestroyHashValue(void *unused, const void *key, const void *value);624625626/* Ends C function definitions when using C++ */627#ifdef __cplusplus628}629#endif630#include <SDL3/SDL_close_code.h>631632#endif /* SDL_hashtable_h_ */633634635