Skip to content

Commit

Permalink
hashtable: Remove from public API, re-add threadsafe option.
Browse files Browse the repository at this point in the history
  • Loading branch information
icculus committed Feb 15, 2025
1 parent 9def54a commit 64f00a2
Show file tree
Hide file tree
Showing 17 changed files with 78 additions and 116 deletions.
1 change: 0 additions & 1 deletion include/SDL3/SDL.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@
#include <SDL3/SDL_gpu.h>
#include <SDL3/SDL_guid.h>
#include <SDL3/SDL_haptic.h>
#include <SDL3/SDL_hashtable.h>
#include <SDL3/SDL_hidapi.h>
#include <SDL3/SDL_hints.h>
#include <SDL3/SDL_init.h>
Expand Down
18 changes: 11 additions & 7 deletions src/SDL_hashtable.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ SDL_COMPILE_TIME_ASSERT(sizeof_SDL_HashItem, sizeof(SDL_HashItem) <= MAX_HASHITE

struct SDL_HashTable
{
SDL_RWLock *lock;
SDL_RWLock *lock; // NULL if not created threadsafe
SDL_HashItem *table;
SDL_HashCallback hash;
SDL_HashKeyMatchCallback keymatch;
Expand All @@ -66,7 +66,7 @@ static Uint32 CalculateHashBucketsFromEstimate(int estimated_capacity)
return SDL_min(buckets, MAX_HASHTABLE_SIZE);
}

SDL_HashTable *SDL_CreateHashTable(int estimated_capacity, SDL_HashCallback hash,
SDL_HashTable *SDL_CreateHashTable(int estimated_capacity, bool threadsafe, SDL_HashCallback hash,
SDL_HashKeyMatchCallback keymatch,
SDL_HashDestroyCallback destroy, void *userdata)
{
Expand All @@ -76,10 +76,12 @@ SDL_HashTable *SDL_CreateHashTable(int estimated_capacity, SDL_HashCallback hash
return NULL;
}

table->lock = SDL_CreateRWLock();
if (!table->lock) {
SDL_DestroyHashTable(table);
return NULL;
if (threadsafe) {
table->lock = SDL_CreateRWLock();
if (!table->lock) {
SDL_DestroyHashTable(table);
return NULL;
}
}

table->table = (SDL_HashItem *)SDL_calloc(num_buckets, sizeof(SDL_HashItem));
Expand Down Expand Up @@ -451,7 +453,9 @@ void SDL_DestroyHashTable(SDL_HashTable *table)
{
if (table) {
destroy_all(table);
SDL_DestroyRWLock(table->lock);
if (table->lock) {
SDL_DestroyRWLock(table->lock);
}
SDL_free(table->table);
SDL_free(table);
}
Expand Down
49 changes: 27 additions & 22 deletions include/SDL3/SDL_hashtable.h → src/SDL_hashtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
3. This notice may not be removed or altered from any source distribution.
*/

/* this is over-documented because it was almost a public API. Leaving the
full docs here in case it _does_ become public some day. */

/* WIKI CATEGORY: HashTable */

/**
Expand Down Expand Up @@ -255,6 +258,8 @@ typedef bool (SDLCALL *SDL_HashTableIterateCallback)(void *userdata, const SDL_H
* table will start small and reallocate as necessary; often this is the
* correct thing to do.
*
* !!! FIXME: add note about `threadsafe` here. And update `threadsafety` tags.
*
* Note that SDL provides a higher-level option built on its hash tables:
* SDL_PropertiesID lets you map strings to various datatypes, and this
* might be easier to use. It only allows strings for keys, however. Those are
Expand All @@ -278,12 +283,12 @@ typedef bool (SDLCALL *SDL_HashTableIterateCallback)(void *userdata, const SDL_H
*
* \sa SDL_DestroyHashTable
*/
extern SDL_DECLSPEC SDL_HashTable * SDLCALL SDL_CreateHashTable(
int estimated_capacity,
SDL_HashCallback hash,
SDL_HashKeyMatchCallback keymatch,
SDL_HashDestroyCallback destroy,
void *userdata);
extern SDL_HashTable * SDL_CreateHashTable(int estimated_capacity,
bool threadsafe,
SDL_HashCallback hash,
SDL_HashKeyMatchCallback keymatch,
SDL_HashDestroyCallback destroy,
void *userdata);


/**
Expand All @@ -302,7 +307,7 @@ extern SDL_DECLSPEC SDL_HashTable * SDLCALL SDL_CreateHashTable(
*
* \since This function is available since SDL 3.4.0.
*/
extern SDL_DECLSPEC void SDLCALL SDL_DestroyHashTable(SDL_HashTable *table);
extern void SDL_DestroyHashTable(SDL_HashTable *table);

/**
* Add an item to a hash table.
Expand All @@ -327,7 +332,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_DestroyHashTable(SDL_HashTable *table);
*
* \since This function is available since SDL 3.4.0.
*/
extern SDL_DECLSPEC bool SDLCALL SDL_InsertIntoHashTable(SDL_HashTable *table, const void *key, const void *value, bool replace);
extern bool SDL_InsertIntoHashTable(SDL_HashTable *table, const void *key, const void *value, bool replace);

/**
* Look up an item in a hash table.
Expand All @@ -350,7 +355,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_InsertIntoHashTable(SDL_HashTable *table, c
*
* \sa SDL_InsertIntoHashTable
*/
extern SDL_DECLSPEC bool SDLCALL SDL_FindInHashTable(const SDL_HashTable *table, const void *key, const void **value);
extern bool SDL_FindInHashTable(const SDL_HashTable *table, const void *key, const void **value);

/**
* Remove an item from a hash table.
Expand All @@ -367,7 +372,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_FindInHashTable(const SDL_HashTable *table,
*
* \since This function is available since SDL 3.4.0.
*/
extern SDL_DECLSPEC bool SDLCALL SDL_RemoveFromHashTable(SDL_HashTable *table, const void *key);
extern bool SDL_RemoveFromHashTable(SDL_HashTable *table, const void *key);

/**
* Remove all items in a hash table.
Expand All @@ -383,7 +388,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RemoveFromHashTable(SDL_HashTable *table, c
*
* \since This function is available since SDL 3.4.0.
*/
extern SDL_DECLSPEC void SDLCALL SDL_ClearHashTable(SDL_HashTable *table);
extern void SDL_ClearHashTable(SDL_HashTable *table);

/**
* Check if any items are currently stored in a hash table.
Expand All @@ -400,7 +405,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_ClearHashTable(SDL_HashTable *table);
*
* \sa SDL_ClearHashTable
*/
extern SDL_DECLSPEC bool SDLCALL SDL_HashTableEmpty(SDL_HashTable *table);
extern bool SDL_HashTableEmpty(SDL_HashTable *table);

/**
* Iterate all key/value pairs in a hash table.
Expand All @@ -418,7 +423,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_HashTableEmpty(SDL_HashTable *table);
*
* \since This function is available since SDL 3.4.0.
*/
extern SDL_DECLSPEC bool SDLCALL SDL_IterateHashTable(const SDL_HashTable *table, SDL_HashTableIterateCallback callback, void *userdata);
extern bool SDL_IterateHashTable(const SDL_HashTable *table, SDL_HashTableIterateCallback callback, void *userdata);


/* Helper functions for SDL_CreateHashTable callbacks... */
Expand All @@ -445,7 +450,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_IterateHashTable(const SDL_HashTable *table
*
* \sa SDL_CreateHashTable
*/
extern SDL_DECLSPEC Uint32 SDLCALL SDL_HashPointer(void *unused, const void *key);
extern Uint32 SDL_HashPointer(void *unused, const void *key);

/**
* Compare two generic pointers as hash table keys.
Expand All @@ -464,7 +469,7 @@ extern SDL_DECLSPEC Uint32 SDLCALL SDL_HashPointer(void *unused, const void *key
*
* \sa SDL_CreateHashTable
*/
extern SDL_DECLSPEC bool SDLCALL SDL_KeyMatchPointer(void *unused, const void *a, const void *b);
extern bool SDL_KeyMatchPointer(void *unused, const void *a, const void *b);

/**
* Generate a hash from a C string.
Expand All @@ -488,7 +493,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_KeyMatchPointer(void *unused, const void *a
*
* \sa SDL_CreateHashTable
*/
extern SDL_DECLSPEC Uint32 SDLCALL SDL_HashString(void *unused, const void *key);
extern Uint32 SDL_HashString(void *unused, const void *key);

/**
* Compare two C strings as hash table keys.
Expand All @@ -510,7 +515,7 @@ extern SDL_DECLSPEC Uint32 SDLCALL SDL_HashString(void *unused, const void *key)
*
* \sa SDL_CreateHashTable
*/
extern SDL_DECLSPEC bool SDLCALL SDL_KeyMatchString(void *unused, const void *a, const void *b);
extern bool SDL_KeyMatchString(void *unused, const void *a, const void *b);

/**
* Generate a hash from an integer ID.
Expand All @@ -534,7 +539,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_KeyMatchString(void *unused, const void *a,
*
* \sa SDL_CreateHashTable
*/
extern SDL_DECLSPEC Uint32 SDLCALL SDL_HashID(void *unused, const void *key);
extern Uint32 SDL_HashID(void *unused, const void *key);

/**
* Compare two integer IDs as hash table keys.
Expand All @@ -553,7 +558,7 @@ extern SDL_DECLSPEC Uint32 SDLCALL SDL_HashID(void *unused, const void *key);
*
* \sa SDL_CreateHashTable
*/
extern SDL_DECLSPEC bool SDLCALL SDL_KeyMatchID(void *unused, const void *a, const void *b);
extern bool SDL_KeyMatchID(void *unused, const void *a, const void *b);

/**
* Free both the key and value pointers of a hash table item.
Expand All @@ -573,7 +578,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_KeyMatchID(void *unused, const void *a, con
*
* \sa SDL_CreateHashTable
*/
extern SDL_DECLSPEC void SDLCALL SDL_DestroyHashKeyAndValue(void *unused, const void *key, const void *value);
extern void SDL_DestroyHashKeyAndValue(void *unused, const void *key, const void *value);

/**
* Free just the value pointer of a hash table item.
Expand All @@ -593,7 +598,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_DestroyHashKeyAndValue(void *unused, const
*
* \sa SDL_CreateHashTable
*/
extern SDL_DECLSPEC void SDLCALL SDL_DestroyHashKey(void *unused, const void *key, const void *value);
extern void SDL_DestroyHashKey(void *unused, const void *key, const void *value);

/**
* Free just the value pointer of a hash table item.
Expand All @@ -613,7 +618,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_DestroyHashKey(void *unused, const void *ke
*
* \sa SDL_CreateHashTable
*/
extern SDL_DECLSPEC void SDLCALL SDL_DestroyHashValue(void *unused, const void *key, const void *value);
extern void SDL_DestroyHashValue(void *unused, const void *key, const void *value);


/* Ends C function definitions when using C++ */
Expand Down
1 change: 1 addition & 0 deletions src/SDL_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ extern "C" {
#endif

#include "SDL_utils_c.h"
#include "SDL_hashtable.h"

// Do any initialization that needs to happen before threads are started
extern void SDL_InitMainThread(void);
Expand Down
4 changes: 2 additions & 2 deletions src/SDL_properties.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ bool SDL_InitProperties(void)
return true;
}

SDL_properties = SDL_CreateHashTable(0, SDL_HashID, SDL_KeyMatchID, SDL_FreeProperties, NULL);
SDL_properties = SDL_CreateHashTable(0, true, SDL_HashID, SDL_KeyMatchID, SDL_FreeProperties, NULL);
const bool initialized = (SDL_properties != NULL);
SDL_SetInitialized(&SDL_properties_init, initialized);
return initialized;
Expand Down Expand Up @@ -163,7 +163,7 @@ SDL_PropertiesID SDL_CreateProperties(void)
return 0;
}

properties->props = SDL_CreateHashTable(0, SDL_HashString, SDL_KeyMatchString, SDL_FreeProperty, NULL);
properties->props = SDL_CreateHashTable(0, false, SDL_HashString, SDL_KeyMatchString, SDL_FreeProperty, NULL);
if (!properties->props) {
SDL_DestroyMutex(properties->lock);
SDL_free(properties);
Expand Down
4 changes: 2 additions & 2 deletions src/SDL_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ void SDL_SetObjectValid(void *object, SDL_ObjectType type, bool valid)
SDL_assert(object != NULL);

if (SDL_ShouldInit(&SDL_objects_init)) {
SDL_objects = SDL_CreateHashTable(0, SDL_HashObject, SDL_KeyMatchObject, NULL, NULL);
SDL_objects = SDL_CreateHashTable(0, true, SDL_HashObject, SDL_KeyMatchObject, NULL, NULL);
const bool initialized = (SDL_objects != NULL);
SDL_SetInitialized(&SDL_objects_init, initialized);
if (!initialized) {
Expand Down Expand Up @@ -375,7 +375,7 @@ const char *SDL_GetPersistentString(const char *string)

SDL_HashTable *strings = (SDL_HashTable *)SDL_GetTLS(&SDL_string_storage);
if (!strings) {
strings = SDL_CreateHashTable(0, SDL_HashString, SDL_KeyMatchString, SDL_DestroyHashValue, NULL);
strings = SDL_CreateHashTable(0, false, SDL_HashString, SDL_KeyMatchString, SDL_DestroyHashValue, NULL);
if (!strings) {
return NULL;
}
Expand Down
4 changes: 2 additions & 2 deletions src/audio/SDL_audio.c
Original file line number Diff line number Diff line change
Expand Up @@ -898,7 +898,7 @@ static SDL_AudioDevice *GetFirstAddedAudioDevice(const bool recording)
return data.result;
}

static Uint32 HashAudioDeviceID(void *data, const void *key)
static Uint32 SDLCALL HashAudioDeviceID(void *userdata, const void *key)
{
// shift right 2, to dump the first two bits, since these are flags
// (recording vs playback, logical vs physical) and the rest are unique incrementing integers.
Expand All @@ -923,7 +923,7 @@ bool SDL_InitAudio(const char *driver_name)
return false;
}

SDL_HashTable *device_hash = SDL_CreateHashTable(0, HashAudioDeviceID, SDL_KeyMatchID, NULL, NULL);
SDL_HashTable *device_hash = SDL_CreateHashTable(0, false, HashAudioDeviceID, SDL_KeyMatchID, NULL, NULL);
if (!device_hash) {
SDL_DestroyRWLock(device_hash_lock);
return false;
Expand Down
2 changes: 1 addition & 1 deletion src/camera/SDL_camera.c
Original file line number Diff line number Diff line change
Expand Up @@ -1416,7 +1416,7 @@ bool SDL_CameraInit(const char *driver_name)
return false;
}

SDL_HashTable *device_hash = SDL_CreateHashTable(0, SDL_HashID, SDL_KeyMatchID, DestroyCameraHashItem, NULL);
SDL_HashTable *device_hash = SDL_CreateHashTable(0, false, SDL_HashID, SDL_KeyMatchID, DestroyCameraHashItem, NULL);
if (!device_hash) {
SDL_DestroyRWLock(device_hash_lock);
return false;
Expand Down
17 changes: 0 additions & 17 deletions src/dynapi/SDL_dynapi.sym
Original file line number Diff line number Diff line change
Expand Up @@ -1234,23 +1234,6 @@ SDL3_0.0.0 {
SDL_ClickTrayEntry;
SDL_UpdateTrays;
SDL_StretchSurface;
SDL_CreateHashTable;
SDL_DestroyHashTable;
SDL_InsertIntoHashTable;
SDL_FindInHashTable;
SDL_RemoveFromHashTable;
SDL_ClearHashTable;
SDL_HashTableEmpty;
SDL_IterateHashTable;
SDL_HashPointer;
SDL_KeyMatchPointer;
SDL_HashString;
SDL_KeyMatchString;
SDL_HashID;
SDL_KeyMatchID;
SDL_DestroyHashKeyAndValue;
SDL_DestroyHashKey;
SDL_DestroyHashValue;
# extra symbols go here (don't modify this line)
local: *;
};
17 changes: 0 additions & 17 deletions src/dynapi/SDL_dynapi_overrides.h
Original file line number Diff line number Diff line change
Expand Up @@ -1259,20 +1259,3 @@
#define SDL_ClickTrayEntry SDL_ClickTrayEntry_REAL
#define SDL_UpdateTrays SDL_UpdateTrays_REAL
#define SDL_StretchSurface SDL_StretchSurface_REAL
#define SDL_CreateHashTable SDL_CreateHashTable_REAL
#define SDL_DestroyHashTable SDL_DestroyHashTable_REAL
#define SDL_InsertIntoHashTable SDL_InsertIntoHashTable_REAL
#define SDL_FindInHashTable SDL_FindInHashTable_REAL
#define SDL_RemoveFromHashTable SDL_RemoveFromHashTable_REAL
#define SDL_ClearHashTable SDL_ClearHashTable_REAL
#define SDL_HashTableEmpty SDL_HashTableEmpty_REAL
#define SDL_IterateHashTable SDL_IterateHashTable_REAL
#define SDL_HashPointer SDL_HashPointer_REAL
#define SDL_KeyMatchPointer SDL_KeyMatchPointer_REAL
#define SDL_HashString SDL_HashString_REAL
#define SDL_KeyMatchString SDL_KeyMatchString_REAL
#define SDL_HashID SDL_HashID_REAL
#define SDL_KeyMatchID SDL_KeyMatchID_REAL
#define SDL_DestroyHashKeyAndValue SDL_DestroyHashKeyAndValue_REAL
#define SDL_DestroyHashKey SDL_DestroyHashKey_REAL
#define SDL_DestroyHashValue SDL_DestroyHashValue_REAL
17 changes: 0 additions & 17 deletions src/dynapi/SDL_dynapi_procs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1267,20 +1267,3 @@ SDL_DYNAPI_PROC(bool,SDL_AudioStreamDevicePaused,(SDL_AudioStream *a),(a),return
SDL_DYNAPI_PROC(void,SDL_ClickTrayEntry,(SDL_TrayEntry *a),(a),)
SDL_DYNAPI_PROC(void,SDL_UpdateTrays,(void),(),)
SDL_DYNAPI_PROC(bool,SDL_StretchSurface,(SDL_Surface *a,const SDL_Rect *b,SDL_Surface *c,const SDL_Rect *d,SDL_ScaleMode e),(a,b,c,d,e),return)
SDL_DYNAPI_PROC(SDL_HashTable*,SDL_CreateHashTable,(int a,SDL_HashCallback b,SDL_HashKeyMatchCallback c,SDL_HashDestroyCallback d,void *e),(a,b,c,d,e),return)
SDL_DYNAPI_PROC(void,SDL_DestroyHashTable,(SDL_HashTable *a),(a),)
SDL_DYNAPI_PROC(bool,SDL_InsertIntoHashTable,(SDL_HashTable *a,const void *b,const void *c,bool d),(a,b,c,d),return)
SDL_DYNAPI_PROC(bool,SDL_FindInHashTable,(const SDL_HashTable *a,const void *b,const void **c),(a,b,c),return)
SDL_DYNAPI_PROC(bool,SDL_RemoveFromHashTable,(SDL_HashTable *a,const void *b),(a,b),return)
SDL_DYNAPI_PROC(void,SDL_ClearHashTable,(SDL_HashTable *a),(a),)
SDL_DYNAPI_PROC(bool,SDL_HashTableEmpty,(SDL_HashTable *a),(a),return)
SDL_DYNAPI_PROC(bool,SDL_IterateHashTable,(const SDL_HashTable *a,SDL_HashTableIterateCallback b,void *c),(a,b,c),return)
SDL_DYNAPI_PROC(Uint32,SDL_HashPointer,(void *a,const void *b),(a,b),return)
SDL_DYNAPI_PROC(bool,SDL_KeyMatchPointer,(void *a,const void *b,const void *c),(a,b,c),return)
SDL_DYNAPI_PROC(Uint32,SDL_HashString,(void *a,const void *b),(a,b),return)
SDL_DYNAPI_PROC(bool,SDL_KeyMatchString,(void *a,const void *b,const void *c),(a,b,c),return)
SDL_DYNAPI_PROC(Uint32,SDL_HashID,(void *a,const void *b),(a,b),return)
SDL_DYNAPI_PROC(bool,SDL_KeyMatchID,(void *a,const void *b,const void *c),(a,b,c),return)
SDL_DYNAPI_PROC(void,SDL_DestroyHashKeyAndValue,(void *a,const void *b,const void *c),(a,b,c),)
SDL_DYNAPI_PROC(void,SDL_DestroyHashKey,(void *a,const void *b,const void *c),(a,b,c),)
SDL_DYNAPI_PROC(void,SDL_DestroyHashValue,(void *a,const void *b,const void *c),(a,b,c),)
4 changes: 2 additions & 2 deletions src/events/SDL_keymap.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ SDL_Keymap *SDL_CreateKeymap(void)
return NULL;
}

keymap->scancode_to_keycode = SDL_CreateHashTable(256, SDL_HashID, SDL_KeyMatchID, NULL, NULL);
keymap->keycode_to_scancode = SDL_CreateHashTable(256, SDL_HashID, SDL_KeyMatchID, NULL, NULL);
keymap->scancode_to_keycode = SDL_CreateHashTable(256, false, SDL_HashID, SDL_KeyMatchID, NULL, NULL);
keymap->keycode_to_scancode = SDL_CreateHashTable(256, false, SDL_HashID, SDL_KeyMatchID, NULL, NULL);
if (!keymap->scancode_to_keycode || !keymap->keycode_to_scancode) {
SDL_DestroyKeymap(keymap);
return NULL;
Expand Down
Loading

0 comments on commit 64f00a2

Please sign in to comment.