From 84e5dba6d5ef301c05d857a91c2ecd47549a29e9 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Mon, 10 Nov 2025 13:44:34 -0500 Subject: [PATCH] api: Added SDL_CreateTemporaryProperties() for more-efficient throwaway props. Fixes #14436. --- include/SDL3/SDL_properties.h | 118 ++++++++ src/SDL_properties.c | 479 +++++++++++++++++++----------- src/dynapi/SDL_dynapi.sym | 1 + src/dynapi/SDL_dynapi_overrides.h | 1 + src/dynapi/SDL_dynapi_procs.h | 1 + 5 files changed, 431 insertions(+), 169 deletions(-) diff --git a/include/SDL3/SDL_properties.h b/include/SDL3/SDL_properties.h index 8e87dfce46970..6ebd95f4ba1ec 100644 --- a/include/SDL3/SDL_properties.h +++ b/include/SDL3/SDL_properties.h @@ -120,6 +120,10 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetGlobalProperties(void); * * All properties are automatically destroyed when SDL_Quit() is called. * + * If you are making a temporary property group with a handful of values, + * meant to be used and disposed of right away, it might be more efficient + * to use SDL_CreateTemporaryProperties() instead. + * * \returns an ID for a new group of properties, or 0 on failure; call * SDL_GetError() for more information. * @@ -561,6 +565,120 @@ extern SDL_DECLSPEC bool SDLCALL SDL_EnumerateProperties(SDL_PropertiesID props, */ extern SDL_DECLSPEC void SDLCALL SDL_DestroyProperties(SDL_PropertiesID props); + +/** + * One key/value pair for a temporary property. + * + * An array of this struct is passed to SDL_CreateTemporaryProperties(). + * Each struct holds a single key/value pair: a single property in the total + * set of properties. + * + * This is intended to be faster than SDL_CreateProperties for simple, one-use, + * disposable data sets. + * + * \since This struct is available since SDL 3.4.0. + * + * \sa SDL_CreateTemporaryProperties + */ +typedef struct SDL_TemporaryPropertyItem +{ + const char *name; /**< property name (the key). */ + SDL_PropertyType type; /**< property type (pointer, string, number, float, bool). */ + union { + Uint64 ui64; /**< a probably-reasonable default field if you initialize without a C99-style designated initializer. */ + void *p; /**< for SDL_PROPERTY_TYPE_POINTER */ + const char *s; /**< for SDL_PROPERTY_TYPE_STRING */ + Sint64 n; /**< for SDL_PROPERTY_TYPE_NUMBER */ + float f; /**< for SDL_PROPERTY_TYPE_FLOAT */ + bool b; /**< for SDL_PROPERTY_TYPE_BOOLEAN */ + } value; /**< property data (the value). */ +} SDL_TemporaryPropertyItem; + + +/** + * Create a throwaway property set with lower overhead. + * + * A common pattern in SDL is to create an SDL_PropertiesID, set some values + * in it, pass it to a function with "WithProperties" in its name, and then + * immediately destroy the property set afterwards. However, since property + * sets are meant to be robust--thread safe, tolerant of incorrect data types, + * etc--they have a lot of overhead for this usage pattern. + * + * A "temporary" property set avoid this overhead by operating mostly like + * a standard set, but with a few limitations: + * + * - They don't have locks, so they can't be accessed from multiple threads + * at the same time. + * - They don't own their data; the data used to create them must continue + * to live until the property set is destroyed. + * - They are read-only (no adding/removing/changing properties). + * - They will not convert data; if a property was created with a certain + * datatype, the set will treat a key as missing if requested as a different + * datatype. + * - They don't have an internal hash table, they only iterate the array + * provided at creation, so they're only suitable for data sets with a + * handful of items. + * + * If these rules are followed, a temporary property set created through this + * function is interchangeable with a standard one created through + * SDL_CreateProperties(), and can be used anywhere an SDL_PropertiesID is + * required. + * + * A common usage pattern is to create a temporary property set on the stack, + * use it to initialize some other object, and then destroy it while the + * stack data is still valid. + * + * For example, if you were to use a normal property set to launch a program + * through SDL_CreateProcessWithProperties(), it might look like this: + * + * ```c + * SDL_PropertiesID props = SDL_CreateProperties(); + * SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, MyArgs); + * SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDIN_NUMBER, SDL_PROCESS_STDIO_NULL); + * SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER, SDL_PROCESS_STDIO_NULL); + * SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDERR_NUMBER, SDL_PROCESS_STDIO_NULL); + * SDL_SetBooleanProperty(props, SDL_PROP_PROCESS_CREATE_BACKGROUND_BOOLEAN, true); + * SDL_Process *handle = SDL_CreateProcessWithProperties(props); + * SDL_DestroyProperties(props); + * ``` + * + * With a temporary property set, however, a large amount of allocations and + * failure cases can be removed: + * + * ```c + * const SDL_TemporaryPropertyItem prop_items[] = { + * { SDL_PROP_PROCESS_CREATE_ARGS_POINTER, SDL_PROPERTY_TYPE_POINTER, { .p = MyArgs } }, + * { SDL_PROP_PROCESS_CREATE_STDIN_NUMBER, SDL_PROPERTY_TYPE_NUMBER, { .n = SDL_PROCESS_STDIO_NULL } }, + * { SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER, SDL_PROPERTY_TYPE_NUMBER, { .n = SDL_PROCESS_STDIO_NULL } }, + * { SDL_PROP_PROCESS_CREATE_STDERR_NUMBER, SDL_PROPERTY_TYPE_NUMBER, { .n = SDL_PROCESS_STDIO_NULL } }, + * { SDL_PROP_PROCESS_CREATE_BACKGROUND_BOOLEAN, SDL_PROPERTY_TYPE_BOOLEAN, { .b = true } } + * }; + * SDL_PropertiesID props = SDL_CreateTemporaryProperties(prop_items, SDL_arraysize(prop_items)); + * SDL_Process *handle = SDL_CreateProcessWithProperties(props); + * SDL_DestroyProperties(props); + * ``` + * + * (This example uses C99 designated initializers--`.n = value`--but the first + * field in the union is a Uint64, which might be a sufficient default on older + * compilers without explicitly specifying a union field.) + * + * This function does allocate a small amount of memory, so it can fail, and + * a successful return value must eventually be disposed of with + * SDL_DestroyProperties(). + * + * All properties are automatically destroyed when SDL_Quit() is called. + * + * \param items an array of items that comprises the entire property set. + * \param num_items the number of items in the `items` array. + * \returns an ID for the new temporary property set, or 0 on failure; call + * SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.4.0. + */ +extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_CreateTemporaryProperties(const SDL_TemporaryPropertyItem *items, int num_items); + /* Ends C function definitions when using C++ */ #ifdef __cplusplus } diff --git a/src/SDL_properties.c b/src/SDL_properties.c index dc3053f820ae3..fcc85553159a9 100644 --- a/src/SDL_properties.c +++ b/src/SDL_properties.c @@ -44,8 +44,17 @@ typedef struct typedef struct { - SDL_HashTable *props; - SDL_Mutex *lock; + union { + struct { + SDL_HashTable *props; + SDL_Mutex *lock; + } std; + struct { + const SDL_TemporaryPropertyItem *items; + int num_items; + } tmp; + } data; + bool is_temp; } SDL_Properties; static SDL_InitState SDL_properties_init; @@ -84,8 +93,12 @@ static void SDLCALL SDL_FreeProperty(void *data, const void *key, const void *va static void SDL_FreeProperties(SDL_Properties *properties) { if (properties) { - SDL_DestroyHashTable(properties->props); - SDL_DestroyMutex(properties->lock); + if (properties->is_temp) { + // we don't own the data under data.tmp, don't free any of it. + } else { + SDL_DestroyHashTable(properties->data.std.props); + SDL_DestroyMutex(properties->data.std.lock); + } SDL_free(properties); } } @@ -153,6 +166,28 @@ SDL_PropertiesID SDL_GetGlobalProperties(void) return props; } +static SDL_PropertiesID AddNewPropertiesID(SDL_Properties *properties) +{ + SDL_PropertiesID props = 0; + while (true) { + props = (SDL_GetAtomicU32(&SDL_last_properties_id) + 1); + if (props == 0) { + continue; + } else if (SDL_CompareAndSwapAtomicU32(&SDL_last_properties_id, props - 1, props)) { + break; + } + } + + SDL_assert(!SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, NULL)); // should NOT be in the hash table already. + + if (!SDL_InsertIntoHashTable(SDL_properties, (const void *)(uintptr_t)props, properties, false)) { + SDL_FreeProperties(properties); + return 0; + } + + return props; // All done! +} + SDL_PropertiesID SDL_CreateProperties(void) { if (!SDL_CheckInitProperties()) { @@ -164,69 +199,73 @@ SDL_PropertiesID SDL_CreateProperties(void) return 0; } - properties->lock = SDL_CreateMutex(); - if (!properties->lock) { + properties->data.std.lock = SDL_CreateMutex(); + if (!properties->data.std.lock) { SDL_free(properties); return 0; } - properties->props = SDL_CreateHashTable(0, false, SDL_HashString, SDL_KeyMatchString, SDL_FreeProperty, NULL); - if (!properties->props) { - SDL_DestroyMutex(properties->lock); + properties->data.std.props = SDL_CreateHashTable(0, false, SDL_HashString, SDL_KeyMatchString, SDL_FreeProperty, NULL); + if (!properties->data.std.props) { + SDL_DestroyMutex(properties->data.std.lock); SDL_free(properties); return 0; } - SDL_PropertiesID props = 0; - while (true) { - props = (SDL_GetAtomicU32(&SDL_last_properties_id) + 1); - if (props == 0) { - continue; - } else if (SDL_CompareAndSwapAtomicU32(&SDL_last_properties_id, props - 1, props)) { - break; - } - } + properties->is_temp = false; - SDL_assert(!SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, NULL)); // should NOT be in the hash table already. + return AddNewPropertiesID(properties); +} - if (!SDL_InsertIntoHashTable(SDL_properties, (const void *)(uintptr_t)props, properties, false)) { - SDL_FreeProperties(properties); +SDL_PropertiesID SDL_CreateTemporaryProperties(const SDL_TemporaryPropertyItem *items, int num_items) +{ + if (!SDL_CheckInitProperties()) { return 0; } - return props; // All done! + SDL_Properties *properties = (SDL_Properties *)SDL_calloc(1, sizeof(*properties)); + if (!properties) { + return 0; + } + + properties->data.tmp.items = items; + properties->data.tmp.num_items = num_items; + properties->is_temp = true; + + return AddNewPropertiesID(properties); } -typedef struct CopyOnePropertyData + +static const SDL_TemporaryPropertyItem *FindTempPropertyItem(SDL_Properties *properties, const char *name) { - SDL_Properties *dst_properties; - bool result; -} CopyOnePropertyData; + const int total = properties->data.tmp.num_items; + for (int i = 0; i < total; i++) { + const SDL_TemporaryPropertyItem *item = &properties->data.tmp.items[i]; + if (SDL_strcmp(name, item->name) == 0) { + return item; + } + } + return NULL; +} -static bool SDLCALL CopyOneProperty(void *userdata, const SDL_HashTable *table, const void *key, const void *value) +static bool CopyOneProperty(SDL_Properties *dst_properties, const char *src_name, const SDL_Property *src_property) { - const SDL_Property *src_property = (const SDL_Property *)value; + SDL_assert(!dst_properties->is_temp); // temp props are read-only. + if (src_property->cleanup) { // Can't copy properties with cleanup functions, we don't know how to duplicate the data return true; // keep iterating. } - CopyOnePropertyData *data = (CopyOnePropertyData *) userdata; - SDL_Properties *dst_properties = data->dst_properties; - const char *src_name = (const char *)key; - SDL_Property *dst_property; - char *dst_name = SDL_strdup(src_name); if (!dst_name) { - data->result = false; - return true; // keep iterating (I guess...?) + return false; } - dst_property = (SDL_Property *)SDL_malloc(sizeof(*dst_property)); + SDL_Property *dst_property = (SDL_Property *)SDL_malloc(sizeof(*dst_property)); if (!dst_property) { SDL_free(dst_name); - data->result = false; - return true; // keep iterating (I guess...?) + return false; } SDL_copyp(dst_property, src_property); @@ -235,16 +274,31 @@ static bool SDLCALL CopyOneProperty(void *userdata, const SDL_HashTable *table, if (!dst_property->value.string_value) { SDL_free(dst_name); SDL_free(dst_property); - data->result = false; - return true; // keep iterating (I guess...?) + return false; } } - if (!SDL_InsertIntoHashTable(dst_properties->props, dst_name, dst_property, true)) { + if (!SDL_InsertIntoHashTable(dst_properties->data.std.props, dst_name, dst_property, true)) { SDL_FreePropertyWithCleanup(dst_name, dst_property, NULL, false); - data->result = false; + return false; } + return true; +} + +typedef struct CopyOnePropertyCallbackData +{ + SDL_Properties *dst_properties; + bool result; +} CopyOnePropertyCallbackData; + + +static bool SDLCALL CopyOnePropertyCallback(void *userdata, const SDL_HashTable *table, const void *key, const void *value) +{ + CopyOnePropertyCallbackData *data = (CopyOnePropertyCallbackData *) userdata; + if (!CopyOneProperty(data->dst_properties, (const char *)key, (const SDL_Property *) value)) { + data->result = false; + } return true; // keep iterating. } @@ -257,28 +311,56 @@ bool SDL_CopyProperties(SDL_PropertiesID src, SDL_PropertiesID dst) return SDL_InvalidParamError("dst"); } - SDL_Properties *src_properties = NULL; SDL_Properties *dst_properties = NULL; + SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)dst, (const void **)&dst_properties); + CHECK_PARAM(!dst_properties) { + return SDL_InvalidParamError("dst"); + } + + if (dst_properties->is_temp) { + return SDL_SetError("Temporary properties are read-only"); + } + SDL_Properties *src_properties = NULL; SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)src, (const void **)&src_properties); CHECK_PARAM(!src_properties) { return SDL_InvalidParamError("src"); } - SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)dst, (const void **)&dst_properties); - CHECK_PARAM(!dst_properties) { - return SDL_InvalidParamError("dst"); - } bool result = true; - SDL_LockMutex(src_properties->lock); - SDL_LockMutex(dst_properties->lock); - { - CopyOnePropertyData data = { dst_properties, true }; - SDL_IterateHashTable(src_properties->props, CopyOneProperty, &data); - result = data.result; + + if (src_properties->is_temp) { + const int total = src_properties->data.tmp.num_items; + SDL_LockMutex(dst_properties->data.std.lock); + for (int i = 0; i < total; i++) { + const SDL_TemporaryPropertyItem *item = &src_properties->data.tmp.items[i]; + SDL_Property src_property; + SDL_zero(src_property); + src_property.type = item->type; + switch (item->type) { + case SDL_PROPERTY_TYPE_POINTER: src_property.value.pointer_value = item->value.p; break; + case SDL_PROPERTY_TYPE_STRING: src_property.value.string_value = (char *) item->value.s; break; + case SDL_PROPERTY_TYPE_NUMBER: src_property.value.number_value = item->value.n; break; + case SDL_PROPERTY_TYPE_FLOAT: src_property.value.float_value = item->value.f; break; + case SDL_PROPERTY_TYPE_BOOLEAN: src_property.value.boolean_value = item->value.b; break; + default: src_property.value.number_value = 0; break; + } + if (!CopyOneProperty(dst_properties, item->name, &src_property)) { + result = false; + } + } + SDL_UnlockMutex(dst_properties->data.std.lock); + } else { + SDL_LockMutex(src_properties->data.std.lock); + SDL_LockMutex(dst_properties->data.std.lock); + { + CopyOnePropertyCallbackData data = { dst_properties, true }; + SDL_IterateHashTable(src_properties->data.std.props, CopyOnePropertyCallback, &data); + result = data.result; + } + SDL_UnlockMutex(dst_properties->data.std.lock); + SDL_UnlockMutex(src_properties->data.std.lock); } - SDL_UnlockMutex(dst_properties->lock); - SDL_UnlockMutex(src_properties->lock); return result; } @@ -296,7 +378,9 @@ bool SDL_LockProperties(SDL_PropertiesID props) return SDL_InvalidParamError("props"); } - SDL_LockMutex(properties->lock); + if (!properties->is_temp) { /* no locks in temporary properties */ + SDL_LockMutex(properties->data.std.lock); + } return true; } @@ -313,7 +397,9 @@ void SDL_UnlockProperties(SDL_PropertiesID props) return; } - SDL_UnlockMutex(properties->lock); + if (!properties->is_temp) { /* no locks in temporary properties */ + SDL_UnlockMutex(properties->data.std.lock); + } } static bool SDL_PrivateSetProperty(SDL_PropertiesID props, const char *name, SDL_Property *property) @@ -336,18 +422,23 @@ static bool SDL_PrivateSetProperty(SDL_PropertiesID props, const char *name, SDL return SDL_InvalidParamError("props"); } - SDL_LockMutex(properties->lock); + if (properties->is_temp) { + SDL_FreePropertyWithCleanup(NULL, property, NULL, true); + return SDL_SetError("Temporary properties are read-only"); + } + + SDL_LockMutex(properties->data.std.lock); { - SDL_RemoveFromHashTable(properties->props, name); + SDL_RemoveFromHashTable(properties->data.std.props, name); if (property) { char *key = SDL_strdup(name); - if (!key || !SDL_InsertIntoHashTable(properties->props, key, property, false)) { + if (!key || !SDL_InsertIntoHashTable(properties->data.std.props, key, property, false)) { SDL_FreePropertyWithCleanup(key, property, NULL, true); result = false; } } } - SDL_UnlockMutex(properties->lock); + SDL_UnlockMutex(properties->data.std.lock); return result; } @@ -493,14 +584,21 @@ SDL_PropertyType SDL_GetPropertyType(SDL_PropertiesID props, const char *name) return SDL_PROPERTY_TYPE_INVALID; } - SDL_LockMutex(properties->lock); - { - SDL_Property *property = NULL; - if (SDL_FindInHashTable(properties->props, name, (const void **)&property)) { - type = property->type; + if (properties->is_temp) { + const SDL_TemporaryPropertyItem *item = FindTempPropertyItem(properties, name); + if (item) { + type = item->type; + } + } else { + SDL_LockMutex(properties->data.std.lock); + { + SDL_Property *property = NULL; + if (SDL_FindInHashTable(properties->data.std.props, name, (const void **)&property)) { + type = property->type; + } } + SDL_UnlockMutex(properties->data.std.lock); } - SDL_UnlockMutex(properties->lock); return type; } @@ -522,19 +620,26 @@ void *SDL_GetPointerProperty(SDL_PropertiesID props, const char *name, void *def return value; } - // Note that taking the lock here only guarantees that we won't read the - // hashtable while it's being modified. The value itself can easily be - // freed from another thread after it is returned here. - SDL_LockMutex(properties->lock); - { - SDL_Property *property = NULL; - if (SDL_FindInHashTable(properties->props, name, (const void **)&property)) { - if (property->type == SDL_PROPERTY_TYPE_POINTER) { - value = property->value.pointer_value; + if (properties->is_temp) { + const SDL_TemporaryPropertyItem *item = FindTempPropertyItem(properties, name); + if (item && (item->type == SDL_PROPERTY_TYPE_POINTER)) { + value = item->value.p; + } + } else { + // Note that taking the lock here only guarantees that we won't read the + // hashtable while it's being modified. The value itself can easily be + // freed from another thread after it is returned here. + SDL_LockMutex(properties->data.std.lock); + { + SDL_Property *property = NULL; + if (SDL_FindInHashTable(properties->data.std.props, name, (const void **)&property)) { + if (property->type == SDL_PROPERTY_TYPE_POINTER) { + value = property->value.pointer_value; + } } } + SDL_UnlockMutex(properties->data.std.lock); } - SDL_UnlockMutex(properties->lock); return value; } @@ -556,43 +661,50 @@ const char *SDL_GetStringProperty(SDL_PropertiesID props, const char *name, cons return value; } - SDL_LockMutex(properties->lock); - { - SDL_Property *property = NULL; - if (SDL_FindInHashTable(properties->props, name, (const void **)&property)) { - switch (property->type) { - case SDL_PROPERTY_TYPE_STRING: - value = property->value.string_value; - break; - case SDL_PROPERTY_TYPE_NUMBER: - if (property->string_storage) { - value = property->string_storage; - } else { - SDL_asprintf(&property->string_storage, "%" SDL_PRIs64, property->value.number_value); + if (properties->is_temp) { + const SDL_TemporaryPropertyItem *item = FindTempPropertyItem(properties, name); + if (item && (item->type == SDL_PROPERTY_TYPE_STRING)) { + value = item->value.s; + } + } else { + SDL_LockMutex(properties->data.std.lock); + { + SDL_Property *property = NULL; + if (SDL_FindInHashTable(properties->data.std.props, name, (const void **)&property)) { + switch (property->type) { + case SDL_PROPERTY_TYPE_STRING: + value = property->value.string_value; + break; + case SDL_PROPERTY_TYPE_NUMBER: if (property->string_storage) { value = property->string_storage; + } else { + SDL_asprintf(&property->string_storage, "%" SDL_PRIs64, property->value.number_value); + if (property->string_storage) { + value = property->string_storage; + } } - } - break; - case SDL_PROPERTY_TYPE_FLOAT: - if (property->string_storage) { - value = property->string_storage; - } else { - SDL_asprintf(&property->string_storage, "%f", property->value.float_value); + break; + case SDL_PROPERTY_TYPE_FLOAT: if (property->string_storage) { value = property->string_storage; + } else { + SDL_asprintf(&property->string_storage, "%f", property->value.float_value); + if (property->string_storage) { + value = property->string_storage; + } } + break; + case SDL_PROPERTY_TYPE_BOOLEAN: + value = property->value.boolean_value ? "true" : "false"; + break; + default: + break; } - break; - case SDL_PROPERTY_TYPE_BOOLEAN: - value = property->value.boolean_value ? "true" : "false"; - break; - default: - break; } } + SDL_UnlockMutex(properties->data.std.lock); } - SDL_UnlockMutex(properties->lock); return value; } @@ -614,29 +726,36 @@ Sint64 SDL_GetNumberProperty(SDL_PropertiesID props, const char *name, Sint64 de return value; } - SDL_LockMutex(properties->lock); - { - SDL_Property *property = NULL; - if (SDL_FindInHashTable(properties->props, name, (const void **)&property)) { - switch (property->type) { - case SDL_PROPERTY_TYPE_STRING: - value = (Sint64)SDL_strtoll(property->value.string_value, NULL, 0); - break; - case SDL_PROPERTY_TYPE_NUMBER: - value = property->value.number_value; - break; - case SDL_PROPERTY_TYPE_FLOAT: - value = (Sint64)SDL_round((double)property->value.float_value); - break; - case SDL_PROPERTY_TYPE_BOOLEAN: - value = property->value.boolean_value; - break; - default: - break; + if (properties->is_temp) { + const SDL_TemporaryPropertyItem *item = FindTempPropertyItem(properties, name); + if (item && (item->type == SDL_PROPERTY_TYPE_NUMBER)) { + value = item->value.n; + } + } else { + SDL_LockMutex(properties->data.std.lock); + { + SDL_Property *property = NULL; + if (SDL_FindInHashTable(properties->data.std.props, name, (const void **)&property)) { + switch (property->type) { + case SDL_PROPERTY_TYPE_STRING: + value = (Sint64)SDL_strtoll(property->value.string_value, NULL, 0); + break; + case SDL_PROPERTY_TYPE_NUMBER: + value = property->value.number_value; + break; + case SDL_PROPERTY_TYPE_FLOAT: + value = (Sint64)SDL_round((double)property->value.float_value); + break; + case SDL_PROPERTY_TYPE_BOOLEAN: + value = property->value.boolean_value; + break; + default: + break; + } } } + SDL_UnlockMutex(properties->data.std.lock); } - SDL_UnlockMutex(properties->lock); return value; } @@ -658,29 +777,36 @@ float SDL_GetFloatProperty(SDL_PropertiesID props, const char *name, float defau return value; } - SDL_LockMutex(properties->lock); - { - SDL_Property *property = NULL; - if (SDL_FindInHashTable(properties->props, name, (const void **)&property)) { - switch (property->type) { - case SDL_PROPERTY_TYPE_STRING: - value = (float)SDL_atof(property->value.string_value); - break; - case SDL_PROPERTY_TYPE_NUMBER: - value = (float)property->value.number_value; - break; - case SDL_PROPERTY_TYPE_FLOAT: - value = property->value.float_value; - break; - case SDL_PROPERTY_TYPE_BOOLEAN: - value = (float)property->value.boolean_value; - break; - default: - break; + if (properties->is_temp) { + const SDL_TemporaryPropertyItem *item = FindTempPropertyItem(properties, name); + if (item && (item->type == SDL_PROPERTY_TYPE_FLOAT)) { + value = item->value.f; + } + } else { + SDL_LockMutex(properties->data.std.lock); + { + SDL_Property *property = NULL; + if (SDL_FindInHashTable(properties->data.std.props, name, (const void **)&property)) { + switch (property->type) { + case SDL_PROPERTY_TYPE_STRING: + value = (float)SDL_atof(property->value.string_value); + break; + case SDL_PROPERTY_TYPE_NUMBER: + value = (float)property->value.number_value; + break; + case SDL_PROPERTY_TYPE_FLOAT: + value = property->value.float_value; + break; + case SDL_PROPERTY_TYPE_BOOLEAN: + value = (float)property->value.boolean_value; + break; + default: + break; + } } } + SDL_UnlockMutex(properties->data.std.lock); } - SDL_UnlockMutex(properties->lock); return value; } @@ -702,29 +828,36 @@ bool SDL_GetBooleanProperty(SDL_PropertiesID props, const char *name, bool defau return value; } - SDL_LockMutex(properties->lock); - { - SDL_Property *property = NULL; - if (SDL_FindInHashTable(properties->props, name, (const void **)&property)) { - switch (property->type) { - case SDL_PROPERTY_TYPE_STRING: - value = SDL_GetStringBoolean(property->value.string_value, default_value); - break; - case SDL_PROPERTY_TYPE_NUMBER: - value = (property->value.number_value != 0); - break; - case SDL_PROPERTY_TYPE_FLOAT: - value = (property->value.float_value != 0.0f); - break; - case SDL_PROPERTY_TYPE_BOOLEAN: - value = property->value.boolean_value; - break; - default: - break; + if (properties->is_temp) { + const SDL_TemporaryPropertyItem *item = FindTempPropertyItem(properties, name); + if (item && (item->type == SDL_PROPERTY_TYPE_BOOLEAN)) { + value = item->value.b; + } + } else { + SDL_LockMutex(properties->data.std.lock); + { + SDL_Property *property = NULL; + if (SDL_FindInHashTable(properties->data.std.props, name, (const void **)&property)) { + switch (property->type) { + case SDL_PROPERTY_TYPE_STRING: + value = SDL_GetStringBoolean(property->value.string_value, default_value); + break; + case SDL_PROPERTY_TYPE_NUMBER: + value = (property->value.number_value != 0); + break; + case SDL_PROPERTY_TYPE_FLOAT: + value = (property->value.float_value != 0.0f); + break; + case SDL_PROPERTY_TYPE_BOOLEAN: + value = property->value.boolean_value; + break; + default: + break; + } } } + SDL_UnlockMutex(properties->data.std.lock); } - SDL_UnlockMutex(properties->lock); return value; } @@ -767,12 +900,19 @@ bool SDL_EnumerateProperties(SDL_PropertiesID props, SDL_EnumeratePropertiesCall return SDL_InvalidParamError("props"); } - SDL_LockMutex(properties->lock); - { - EnumerateOnePropertyData data = { callback, userdata, props }; - SDL_IterateHashTable(properties->props, EnumerateOneProperty, &data); + if (properties->is_temp) { + const int total = properties->data.tmp.num_items; + for (int i = 0; i < total; i++) { + callback(userdata, props, properties->data.tmp.items[i].name); + } + } else { + SDL_LockMutex(properties->data.std.lock); + { + EnumerateOnePropertyData data = { callback, userdata, props }; + SDL_IterateHashTable(properties->data.std.props, EnumerateOneProperty, &data); + } + SDL_UnlockMutex(properties->data.std.lock); } - SDL_UnlockMutex(properties->lock); return true; } @@ -822,3 +962,4 @@ void SDL_DestroyProperties(SDL_PropertiesID props) } } } + diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index 9feb8a0fc6f7d..03f01900ba5d6 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -1268,6 +1268,7 @@ SDL3_0.0.0 { SDL_GetPenDeviceType; SDL_CreateAnimatedCursor; SDL_RotateSurface; + SDL_CreateTemporaryProperties; # extra symbols go here (don't modify this line) local: *; }; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 1d17c7fcf0a2f..1f8dd850f0323 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -1294,3 +1294,4 @@ #define SDL_GetPenDeviceType SDL_GetPenDeviceType_REAL #define SDL_CreateAnimatedCursor SDL_CreateAnimatedCursor_REAL #define SDL_RotateSurface SDL_RotateSurface_REAL +#define SDL_CreateTemporaryProperties SDL_CreateTemporaryProperties_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index a2fc06fd7f14d..22e97432a9f75 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -1302,3 +1302,4 @@ SDL_DYNAPI_PROC(int,SDL_GetSystemPageSize,(void),(),return) SDL_DYNAPI_PROC(SDL_PenDeviceType,SDL_GetPenDeviceType,(SDL_PenID a),(a),return) SDL_DYNAPI_PROC(SDL_Cursor*,SDL_CreateAnimatedCursor,(SDL_CursorFrameInfo *a,int b,int c,int d),(a,b,c,d),return) SDL_DYNAPI_PROC(SDL_Surface*,SDL_RotateSurface,(SDL_Surface *a,float b),(a,b),return) +SDL_DYNAPI_PROC(SDL_PropertiesID,SDL_CreateTemporaryProperties,(const SDL_TemporaryPropertyItem *a,int b),(a,b),return)