From 654b208641779b67e39acef47d5a4d0b223125a2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 15 Mar 2023 19:47:30 +0900 Subject: [PATCH] [plist] Add functions to extend dictionaries and arrays The idea is to make it easy (and efficient) to merge property list items. --- include/QF/plist.h | 26 +++++++++++++ libs/util/plist.c | 93 +++++++++++++++++++++++++++++++++++++++------- 2 files changed, 105 insertions(+), 14 deletions(-) diff --git a/include/QF/plist.h b/include/QF/plist.h index 884f6b9f3..942bdf8a3 100644 --- a/include/QF/plist.h +++ b/include/QF/plist.h @@ -294,6 +294,20 @@ int PL_D_NumKeys (const plitem_t *dict) __attribute__((pure)); */ qboolean PL_D_AddObject (plitem_t *dict, const char *key, plitem_t *value); +/** Copy contents of one dictionary into another. + + The contents of \a srcDict are added to \a dstDict without affecting + \a srcDict. Any collisions in \a dstDict result in those values in + \a dstDict being replaced by the the values from \a srcDict: the new + key-value pairs override the old. + + \param dstDict The dictionary to extend + \param srcDict The dictionary from which key-value pairs will be copied + \return true if values were copied, false if nothing was copied (either + dictionary is null, or not a dictionary, or if \a srcDict was empty) +*/ +qboolean PL_D_Extend (plitem_t *dstDict, plitem_t *srcDict); + /** Add an item to an array. \param array The array to which the item will be added @@ -306,6 +320,18 @@ qboolean PL_D_AddObject (plitem_t *dict, const char *key, plitem_t *value); */ qboolean PL_A_AddObject (plitem_t *array, plitem_t *item); +/** Append contents of one array to another. + + The contents of \a srcArray are added to \a dstArray without affecting + \a srcArray. Those values are appended to the destination array values. + + \param dstArray The array to extend + \param srcArray The array from which values will be copied + \return true if values were copied, false if nothing was copied (either + array is null, or not an array, or if \a srcArray was empty) +*/ +qboolean PL_A_Extend (plitem_t *dstArray, plitem_t *srcArray); + /** Retrieve the number of items in an array. \param array The array from which to get the number of objects diff --git a/libs/util/plist.c b/libs/util/plist.c index 9beda5a15..07a1faf6e 100644 --- a/libs/util/plist.c +++ b/libs/util/plist.c @@ -414,7 +414,7 @@ PL_D_AddObject (plitem_t *item, const char *key, plitem_t *value) dictkey_t *k; if ((k = Hash_Find (dict->tab, key))) { - value->users++; + PL_Retain (value); PL_Release (k->value); k->value = value; } else { @@ -423,7 +423,7 @@ PL_D_AddObject (plitem_t *item, const char *key, plitem_t *value) if (!k) return false; - value->users++; + PL_Retain (value); k->key = strdup (key); k->value = value; @@ -433,6 +433,60 @@ PL_D_AddObject (plitem_t *item, const char *key, plitem_t *value) return true; } +VISIBLE qboolean +PL_D_Extend (plitem_t *dstDict, plitem_t *srcDict) +{ + if (!dstDict || dstDict->type != QFDictionary + || !srcDict || srcDict->type != QFDictionary + || ((pldict_t *) srcDict->data)->keys.size < 1) { + return false; + } + pldict_t *dst = dstDict->data; + pldict_t *src = srcDict->data; + size_t count = dst->keys.size; + DARRAY_RESIZE (&dst->keys, dst->keys.size + src->keys.size);// open space + DARRAY_RESIZE (&dst->keys, count); // put size back so it's correct + for (size_t i = 0; i < src->keys.size; i++) { + dictkey_t *key = src->keys.a[i]; + dictkey_t *k; + if ((k = Hash_Find (dst->tab, key->key))) { + PL_Retain (key->value); + PL_Release (k->value); + k->value = key->value; + } else { + k = malloc (sizeof (dictkey_t)); + + if (!k) + return false; + + PL_Retain (key->value); + k->key = strdup (key->key); + k->value = key->value; + + Hash_Add (dst->tab, k); + DARRAY_APPEND (&dst->keys, k); + } + } + return true; +} + +static qboolean +check_array_size (plarray_t *arr, int count) +{ + if (count > arr->maxvals) { + int newmax = (count + 127) & ~127; + int size = newmax * sizeof (plitem_t *); + plitem_t **tmp = realloc (arr->values, size); + + if (!tmp) + return false; + + arr->maxvals = newmax; + arr->values = tmp; + } + return true; +} + VISIBLE qboolean PL_A_InsertObjectAtIndex (plitem_t *array, plitem_t *item, int index) { @@ -444,17 +498,8 @@ PL_A_InsertObjectAtIndex (plitem_t *array, plitem_t *item, int index) arr = (plarray_t *)array->data; - if (arr->numvals == arr->maxvals) { - int size = (arr->maxvals + 128) * sizeof (plitem_t *); - plitem_t **tmp = realloc (arr->values, size); - - if (!tmp) - return false; - - arr->maxvals += 128; - arr->values = tmp; - memset (arr->values + arr->numvals, 0, - (arr->maxvals - arr->numvals) * sizeof (plitem_t *)); + if (!check_array_size (arr, arr->numvals + 1)) { + return false; } if (index == -1) @@ -466,7 +511,7 @@ PL_A_InsertObjectAtIndex (plitem_t *array, plitem_t *item, int index) memmove (arr->values + index + 1, arr->values + index, (arr->numvals - index) * sizeof (plitem_t *)); - item->users++; + PL_Retain (item); arr->values[index] = item; arr->numvals++; return true; @@ -478,6 +523,26 @@ PL_A_AddObject (plitem_t *array, plitem_t *item) return PL_A_InsertObjectAtIndex (array, item, -1); } +VISIBLE qboolean +PL_A_Extend (plitem_t *dstArray, plitem_t *srcArray) +{ + if (!dstArray || dstArray->type != QFArray + || !srcArray || srcArray->type != QFArray + || ((plarray_t *) srcArray->data)->numvals < 1) { + return false; + } + plarray_t *dst = dstArray->data; + plarray_t *src = srcArray->data; + if (!check_array_size (dst, dst->numvals + src->numvals)) { + return false; + } + for (int i = 0; i < src->numvals; i++) { + PL_Retain (src->values[i]); + dst->values[dst->numvals++] = src->values[i]; + } + return true; +} + VISIBLE int PL_A_NumObjects (const plitem_t *array) {