# HG changeset patch # User Franz Glasner # Date 1728297378 -7200 # Node ID 858f4208d9cb5d08b6acbc3b61d43b733d2b28c4 # Parent 35c29e9919bac0049b45f660ccf127e26cbea3bc farray.sh: Resource management by reference counting done diff -r 35c29e9919ba -r 858f4208d9cb share/local-bsdtools/farray.sh --- a/share/local-bsdtools/farray.sh Sun Oct 06 17:23:09 2024 +0200 +++ b/share/local-bsdtools/farray.sh Mon Oct 07 12:36:18 2024 +0200 @@ -462,8 +462,10 @@ eval __farr_len=\$\{${__farr_gvrname}__+SET\} [ -n "${__farr_len}" ] && _farr_fatal "farray \`${__farr_name}' already exists: existing token \`${__farr_token}'" - # Really create the storage by initializing its length + # Really create the storage by initializing its length ... eval ${__farr_gvrname}__=0 + # ... and its reference count + eval ${__farr_gvrname}_C=1 # And associate the token with the array name eval "${__farr_name}=\"\${_farr_array_token_prefix}\${__farr_token}\"" @@ -498,6 +500,8 @@ _farr_array_get_meta() { local __farr_gm_name_or_value + local __farr_tmp_refcount + __farr_gm_name_or_value="${1-}" case "${__farr_gm_name_or_value}" in '') @@ -531,7 +535,8 @@ eval __farr_len=\$\{${__farr_gvrname}__:+SET\} [ -z "${__farr_len}" ] && _farr_fatal "farray \`${__farr_name:-"${__farr_gm_name_or_value}"}' not created properly: no storage for token \`${__farr_token}'" -# eval __farr_len="\$((\${${__farr_gvrname}__} + 0))" + eval __farr_tmp_refcount=\$\{${__farr_gvrname}_C:+SET\} + [ -z "${__farr_tmp_refcount}" ] && _farr_fatal "farray \`${__farr_name:-"${__farr_gm_name_or_value}"}' not created properly: no refcnt for token \`${__farr_token}'" eval __farr_len=\"\$\{${__farr_gvrname}__\}\" return 0 } @@ -557,6 +562,8 @@ _farr_array_tryget_meta() { local __farr_gm_name_or_value + local __farr_tmp_refcount + __farr_token='' __farr_gvrname='' __farr_len='' @@ -601,6 +608,11 @@ _farr_err "farray \`${__farr_name:-"${__farr_gm_name_or_value}"}' not created properly: no storage for token \`${__farr_token}'" return 1 fi + eval __farr_tmp_refcount=\$\{${__farr_gvrname}_C:+SET\} + if [ -z "${__farr_tmp_refcount}" ] ; then + _farr_err "farray \`${__farr_name:-"${__farr_gm_name_or_value}"}' not created properly: no refcnt for token \`${__farr_token}'" + return 1 + fi eval __farr_len=\"\$\{${__farr_gvrname}__\}\" return 0 } @@ -634,6 +646,8 @@ _farr_array_tryget_meta_nonfatal() { local __farr_gm_name_or_value + local __farr_tmp_refcount + __farr_token='' __farr_gvrname='' __farr_len='' @@ -672,6 +686,8 @@ eval __farr_len=\$\{${__farr_gvrname}__:+SET\} [ -z "${__farr_len}" ] && return 1 + eval __farr_tmp_refcount=\$\{${__farr_gvrname}_C:+SET\} + [ -z "${__farr_tmp_refcount}" ] && return 1 eval __farr_len=\"\$\{${__farr_gvrname}__\}\" return 0 } @@ -741,6 +757,7 @@ # Set value Escape properly: use $' ' and escape any # backslashes and single quotes. # + _farr_acquire_object "${__farr_newval}" eval ${__farr_gvrname}_${__farr_len_1}="$(_farr_quote_for_eval "${__farr_newval}")" # the implementation below line does not escape properly # eval ${__farr_gvrname}_${__farr_len_1}="\"${__farr_value}\"" @@ -771,6 +788,7 @@ local __farr_name __farr_index __farr_value local __farr_token __farr_gvrname __farr_len __farr_len_1 + local __farr_old_value _farr_array_get_meta "$@" _farr_make_index __farr_index "${2-}" "${__farr_len}" @@ -780,11 +798,15 @@ # For proper quoting: see farray_append if [ \( ${__farr_index} -ge 1 \) -a \( ${__farr_index} -le ${__farr_len} \) ]; then + _farr_acquire_object "${__farr_value}" # replace a value at an existing index + eval __farr_old_value=\"\$\{${__farr_gvrname}_${__farr_index}\}\" + _farr_release_object "${__farr_old_value}" eval ${__farr_gvrname}_${__farr_index}="$(_farr_quote_for_eval "${__farr_value}")" else __farr_len_1=$((__farr_len + 1)) if [ ${__farr_index} -eq ${__farr_len_1} ]; then + _farr_acquire_object "${__farr_value}" # append value eval ${__farr_gvrname}_${__farr_len_1}="$(_farr_quote_for_eval "${__farr_value}")" # and set new length @@ -808,6 +830,7 @@ local __farr_varname __farr_name __farr_index local __farr_token __farr_gvrname __farr_len + local __farr_get_value __farr_varname="${1-}" [ -z "${__farr_varname}" ] && _farr_fatal "missing variable name" @@ -819,7 +842,9 @@ _farr_fatal "array index out of bounds" fi - eval "${__farr_varname}"=\"\$\{${__farr_gvrname}_${__farr_index}\}\" + eval __farr_get_value=\"\$\{${__farr_gvrname}_${__farr_index}\}\" + _farr_acquire_object "${__farr_get_value}" + eval "${__farr_varname}"=\"\$\{__farr_get_value\}\" } @@ -843,6 +868,7 @@ local __farr_varname __farr_name __farr_index local __farr_token __farr_gvrname __farr_len + local __farr_get_value __farr_varname="${1-}" [ -z "${__farr_varname}" ] && _farr_fatal "missing variable name" @@ -855,7 +881,9 @@ return 1 fi - eval "${__farr_varname}"=\"\$\{${__farr_gvrname}_${__farr_index}\}\" + eval __farr_get_value=\"\$\{${__farr_gvrname}_${__farr_index}\}\" + _farr_acquire_object "${__farr_get_value}" + eval "${__farr_varname}"=\"\$\{__farr_get_value\}\" return 0 } @@ -871,6 +899,7 @@ local __farr_name __farr_index local __farr_token __farr_gvrname __farr_len __farr_idx + local __farr_del_value _farr_array_get_meta "$@" _farr_make_index __farr_index "${2-}" "${__farr_len}" @@ -879,6 +908,11 @@ _farr_fatal "array index out of bounds" fi + # Release the item at index + eval __farr_del_value=\"\$\{${__farr_gvrname}_${__farr_index}\}\" + _farr_release_object "${__farr_del_value}" + + # Move all other items down by one __farr_idx=${__farr_index} while [ ${__farr_idx} -lt ${__farr_len} ]; do # copy the following value to the current index @@ -1003,11 +1037,13 @@ # Just replace __farr_off=0 while [ ${__farr_off} -lt ${__farr_length} ]; do + eval __farr_v=\"\$\{${__farr_l_gvrname}_$((__farr_index + __farr_off))\}\" if [ -n "${__farr_del_name}" ]; then - eval __farr_v=\"\$\{${__farr_l_gvrname}_$((__farr_index + __farr_off))\}\" farray_append "${__farr_del_name}" "${__farr_v}" fi + _farr_release_object "${__farr_v}" eval __farr_v=\"\$\{${__farr_r_gvrname}_$((__farr_off + 1))\}\" + _farr_acquire_object "${__farr_v}" eval ${__farr_l_gvrname}_$((__farr_index + __farr_off))=\"\$\{__farr_v\}\" __farr_off=$((__farr_off + 1)) done @@ -1016,24 +1052,27 @@ __farr_delta=$((__farr_length - __farr_r_len)) __farr_off=0 while [ ${__farr_off} -lt ${__farr_r_len} ]; do + eval __farr_v=\"\$\{${__farr_l_gvrname}_$((__farr_index + __farr_off))\}\" if [ -n "${__farr_del_name}" ]; then - eval __farr_v=\"\$\{${__farr_l_gvrname}_$((__farr_index + __farr_off))\}\" farray_append "${__farr_del_name}" "${__farr_v}" fi + _farr_release_object "${__farr_v}" eval __farr_v=\"\$\{${__farr_r_gvrname}_$((__farr_off + 1))\}\" + _farr_acquire_object "${__farr_v}" eval ${__farr_l_gvrname}_$((__farr_index + __farr_off))=\"\$\{__farr_v\}\" __farr_off=$((__farr_off + 1)) done # Copy / unset the rest that is to delete while [ ${__farr_off} -lt ${__farr_length} ]; do + eval __farr_v=\"\$\{${__farr_l_gvrname}_$((__farr_index + __farr_off))\}\" if [ -n "${__farr_del_name}" ]; then - eval __farr_v=\"\$\{${__farr_l_gvrname}_$((__farr_index + __farr_off))\}\" farray_append "${__farr_del_name}" "${__farr_v}" fi + _farr_release_object "${__farr_v}" eval unset ${__farr_l_gvrname}_$((__farr_index + __farr_off)) __farr_off=$((__farr_off + 1)) done - # Move the rest + # Move the rest -- here no refcount changes __farr_src_idx=$((__farr_index + __farr_length)) __farr_dst_idx=$((__farr_index + __farr_r_len)) while [ ${__farr_src_idx} -le ${__farr_l_len} ]; do @@ -1050,15 +1089,21 @@ __farr_delta=$((__farr_r_len - __farr_length)) __farr_off=0 while [ ${__farr_off} -lt ${__farr_length} ]; do + eval __farr_v=\"\$\{${__farr_l_gvrname}_$((__farr_index + __farr_off))\}\" + if [ -n "${__farr_del_name}" ]; then - eval __farr_v=\"\$\{${__farr_l_gvrname}_$((__farr_index + __farr_off))\}\" farray_append "${__farr_del_name}" "${__farr_v}" fi + _farr_release_object "${__farr_v}" eval __farr_v=\"\$\{${__farr_r_gvrname}_$((__farr_off + 1))\}\" + _farr_acquire_object "${__farr_v}" eval ${__farr_l_gvrname}_$((__farr_index + __farr_off))=\"\$\{__farr_v\}\" __farr_off=$((__farr_off + 1)) done + # # Make room from last item to the first non-deleted + # -- no refcount changes + # __farr_src_idx=${__farr_l_len} __farr_dst_idx=$((__farr_src_idx + __farr_delta)) while [ ${__farr_src_idx} -ge $((__farr_index + __farr_length)) ]; do @@ -1075,6 +1120,7 @@ # while [ ${__farr_off} -lt ${__farr_r_len} ]; do eval __farr_v=\"\$\{${__farr_r_gvrname}_$((__farr_off + 1))\}\" + _farr_acquire_object "${__farr_v}" eval ${__farr_l_gvrname}_$((__farr_index + __farr_off))=\"\$\{__farr_v\}\" __farr_off=$((__farr_off + 1)) done @@ -1091,30 +1137,17 @@ #: Args: #: $1 (str): The name of the existing array. #: -#: Other Parameters: -#: --unset-only: If given then no recursive deletion of other complex -#: objects are done. -#: farray_clear() { - local __farr_name __farr_opt_unset_only + local __farr_name local __farr_token __farr_gvrname __farr_len __farr_idx __farr_del_value - __farr_opt_unset_only="${1-}" - if [ "${__farr_opt_unset_only}" = '--unset-only' ] ; then - shift - else - __farr_opt_unset_only='' - fi - _farr_array_get_meta "$@" __farr_idx=1 while [ ${__farr_idx} -le ${__farr_len} ]; do - if [ -n "${__farr_opt_unset_only}" ] ; then - eval __farr_del_value=\"\$\{${__farr_gvrname}_${__farr_idx}\}\" - _farr_destroy_object "${__farr_del_value}" - fi + eval __farr_del_value=\"\$\{${__farr_gvrname}_${__farr_idx}\}\" + _farr_release_object "${__farr_del_value}" eval unset ${__farr_gvrname}_${__farr_idx} __farr_idx=$((__farr_idx + 1)) done @@ -1139,20 +1172,37 @@ local __farr_token __farr_gvrname __farr_len local __farr_idx __farr_del_value + local __farr_refcnt _farr_array_tryget_meta "$@" || return 1 - # Remove "storage" + # + # Decrement the reference count. + # Note that the existence of the reference count proper is already + # checked by `_farr_array_tryget_meta`. + # + eval __farr_refcnt=\$\{${__farr_gvrname}_C\} + __farr_refcnt=$((__farr_refcnt - 1)) + eval ${__farr_gvrname}_C=\$\{__farr_refcnt\} + if [ "${__farr_refcnt}" -ne 0 ] ; then + # Clean out the array name from the token always + [ -n "${__farr_name}" ] && eval "${__farr_name}=''" + return 0 + fi + + # Remove "storage" because the reference count is 0 __farr_idx=1 while [ ${__farr_idx} -le ${__farr_len} ]; do eval __farr_del_value=\"\$\{${__farr_gvrname}_${__farr_idx}\}\" - _farr_destroy_object "${__farr_del_value}" + _farr_release_object "${__farr_del_value}" eval unset ${__farr_gvrname}_${__farr_idx} __farr_idx=$((__farr_idx + 1)) done - # Remove length itself + # Remove length itself ... eval unset ${__farr_gvrname}__ + # ... and the reference count + eval unset ${__farr_gvrname}_C # Clean out the array name from the token [ -n "${__farr_name}" ] && eval "${__farr_name}=''" return 0 @@ -1467,6 +1517,7 @@ local __farr_token __farr_gvrname __farr_len __farr_idx __farr_rv local __farr_gm_name_or_value + local __farr_feval __farr_gm_name_or_value="${1-}" _farr_array_get_meta "$@" @@ -1478,8 +1529,11 @@ __farr_idx=1 while [ ${__farr_idx} -le ${__farr_len} ]; do - eval "${__farr_callback} \"\${__farr_name:-\"\${__farr_gm_name_or_value}\"}\" \"\${__farr_idx}\" \"\${${__farr_gvrname}_${__farr_idx}}\" \"\$@\"" + eval __farr_feval=\"\$\{${__farr_gvrname}_${__farr_idx}\}\" + _farr_acquire_object "${__farr_feval}" + eval "${__farr_callback} \"\${__farr_name:-\"\${__farr_gm_name_or_value}\"}\" \"\${__farr_idx}\" \"\${__farr_feval}\" \"\$@\"" __farr_rv=$? + _farr_release_object "${__farr_feval}" [ ${__farr_rv} -ne 0 ] && return ${__farr_rv} __farr_idx=$((__farr_idx + 1)) done @@ -1496,6 +1550,7 @@ local __farr_token __farr_gvrname __farr_len __farr_idx __farr_rv local __farr_gm_name_or_value + local __farr_feval __farr_gm_name_or_value="${1-}" _farr_array_get_meta "$@" @@ -1506,8 +1561,11 @@ __farr_idx=${__farr_len} while [ ${__farr_idx} -gt 0 ]; do - eval "${__farr_callback} \"\${__farr_name:-\"\${__farr_gm_name_or_value}\"}\" \"\${__farr_idx}\" \"\${${__farr_gvrname}_${__farr_idx}}\" \"\$@\"" + eval __farr_feval=\"\$\{${__farr_gvrname}_${__farr_idx}\}\" + _farr_acquire_object "${__farr_feval}" + eval "${__farr_callback} \"\${__farr_name:-\"\${__farr_gm_name_or_value}\"}\" \"\${__farr_idx}\" \"\${__farr_feval}\" \"\$@\"" __farr_rv=$? + _farr_release_object "${__farr_feval}" [ ${__farr_rv} -ne 0 ] && return ${__farr_rv} __farr_idx=$((__farr_idx - 1)) done @@ -1644,8 +1702,10 @@ eval __farr_len=\$\{${__farr_objname}__+SET\} [ -n "${__farr_len}" ] && _farr_fatal "falist \`${__farr_name}' already exists: existing token \`${__farr_token}'" - # Really create the storage by initializing its length + # Really create the storage by initializing its length ... eval ${__farr_objname}__=0 + # ... and its reference count + eval ${__farr_objname}_C=1 # And associate the token with the array name eval "${__farr_name}=\"\${_farr_alist_token_prefix}\${__farr_token}\"" @@ -1682,6 +1742,8 @@ _farr_alist_get_meta() { local __farr_gm_name_or_value + local __farr_tmp_refcount + __farr_gm_name_or_value="${1-}" case "${__farr_gm_name_or_value}" in '') @@ -1717,7 +1779,8 @@ eval __farr_len=\$\{${__farr_objname}__:+SET\} [ -z "${__farr_len}" ] && _farr_fatal "falist \`${__farr_name:-"${__farr_gm_name_or_value}"}' not created properly: no object for token \`${__farr_token}'" - # eval __farr_len="\$((\${${__farr_objname}__} + 0))" + eval __farr_tmp_refcount=\$\{${__farr_objname}_C:+SET\} + [ -z "${__farr_tmp_refcount}" ] && _farr_fatal "falist \`${__farr_name:-"${__farr_gm_name_or_value}"}' not created properly: no refcnt for token \`${__farr_token}'" eval __farr_len="\${${__farr_objname}__}" return 0 } @@ -1745,6 +1808,8 @@ _farr_alist_tryget_meta() { local __farr_gm_name_or_value + local __farr_tmp_refcount + __farr_gm_name_or_value="${1-}" case "${__farr_gm_name_or_value}" in '') @@ -1782,8 +1847,15 @@ __farr_valname=${_farr_alist_value_prefix}${__farr_token} eval __farr_len=\$\{${__farr_objname}__:+SET\} - [ -z "${__farr_len}" ] && _farr_fatal "falist \`${__farr_name:-"${__farr_gm_name_or_value}"}' not created properly: no object for token \`${__farr_token}'" - # eval __farr_len="\$((\${${__farr_objname}__} + 0))" + if [ -z "${__farr_len}" ] ; then + _farr_err "falist \`${__farr_name:-"${__farr_gm_name_or_value}"}' not created properly: no object for token \`${__farr_token}'" + return 1 + fi + eval __farr_tmp_refcount=\$\{${__farr_objname}_C:+SET\} + if [ -z "${__farr_tmp_refcount}" ] ; then + _farr_err "falist \`${__farr_name:-"${__farr_gm_name_or_value}"}' not created properly: no refcnt for token \`${__farr_token}'" + return 1 + fi eval __farr_len="\${${__farr_objname}__}" return 0 } @@ -1836,34 +1908,22 @@ #: Args: #: $1 (str): The name of the existing alist. #: -#: Other Parameters: -#: --unset-only: If given then no recursive deletion of other complex -#: objects are done. -#: falist_clear() { - local __farr_name __farr_opt_unset_only + local __farr_name local __farr_token __farr_objname __farr_keyname __farr_valname __farr_len local __farr_idx __farr_del_value - __farr_opt_unset_only="${1-}" - if [ "${__farr_opt_unset_only}" = '--unset-only' ] ; then - shift - else - __farr_opt_unset_only='' - fi - _farr_alist_get_meta "$@" # Remove "storage" __farr_idx=1 while [ ${__farr_idx} -le ${__farr_len} ]; do - if [ -n "${__farr_opt_unset_only}" ] ; then - eval __farr_del_value=\"\$\{${__farr_valname}_${__farr_idx}\}\" - _farr_destroy_object "${__farr_del_value}" - eval __farr_del_value=\"\$\{${__farr_keyname}_${__farr_idx}\}\" - _farr_destroy_object "${__farr_del_value}" - fi + # XXX FIXME: no arrays/alists as keys: should we check this + #eval __farr_del_value=\"\$\{${__farr_valname}_${__farr_idx}\}\" + #_farr_release_object "${__farr_del_value}" + eval __farr_del_value=\"\$\{${__farr_keyname}_${__farr_idx}\}\" + _farr_release_object "${__farr_del_value}" eval unset ${__farr_valname}_${__farr_idx} eval unset ${__farr_keyname}_${__farr_idx} __farr_idx=$((__farr_idx + 1)) @@ -1890,23 +1950,41 @@ local __farr_token __farr_objname __farr_keyname __farr_valname __farr_len local __farr_idx __farr_del_value + local __farr_refcnt _farr_alist_tryget_meta "$@" || return 1 - # Remove "storage" + # + # Decrement the reference count. + # Note that the existence of the reference count proper is already + # checked by `_farr_alist_tryget_meta`. + # + eval __farr_refcnt=\$\{${__farr_objname}_C\} + __farr_refcnt=$((__farr_refcnt - 1)) + eval ${__farr_objname}_C=\$\{__farr_refcnt\} + if [ "${__farr_refcnt}" -ne 0 ] ; then + # Clean out the alist name from the token always + [ -n "${__farr_name}" ] && eval "${__farr_name}=''" + return 0 + fi + + # Remove "storage" because the reference count is 0 __farr_idx=1 while [ ${__farr_idx} -le ${__farr_len} ]; do eval __farr_del_value=\"\$\{${__farr_valname}_${__farr_idx}\}\" - _farr_destroy_object "${__farr_del_value}" - eval __farr_del_value=\"\$\{${__farr_keyname}_${__farr_idx}\}\" - _farr_destroy_object "${__farr_del_value}" + _farr_release_object "${__farr_del_value}" + # XXX FIXME: no arrays/alists as keys: should we check this + #eval __farr_del_value=\"\$\{${__farr_keyname}_${__farr_idx}\}\" + #_farr_release_object "${__farr_del_value}" eval unset ${__farr_valname}_${__farr_idx} eval unset ${__farr_keyname}_${__farr_idx} __farr_idx=$((__farr_idx + 1)) done - # Remove object (length) itself + # Remove object (length) itself ... eval unset ${__farr_objname}__ + # ... and its reference count + eval unset ${__farr_objname}_C # Clean out the alist name from the token [ -n "${__farr_name}" ] && eval "${__farr_name}=''" return 0 @@ -1930,6 +2008,7 @@ local __farr_token __farr_objname __farr_keyname __farr_valname __farr_len local __farr_idx __farr_elkey + local __farr_old_value _farr_alist_get_meta "$@" shift @@ -1946,6 +2025,9 @@ if [ -n "${__farr_elkey}" ]; then eval __farr_elkey=\"\$\{${__farr_keyname}_${__farr_idx}\}\" if [ "${__farr_elkey}" = "${__farr_key}" ]; then + eval __farr_old_value=\"\$\{${__farr_valname}_${__farr_idx}\}\" + _farr_release_object "${__farr_old_value}" + _farr_acquire_object "${__farr_value}" eval ${__farr_valname}_${__farr_idx}="$(_farr_quote_for_eval "${__farr_value}")" return 0 fi @@ -1962,6 +2044,7 @@ __farr_len=${__farr_idx} # ... the key/value pairs to storage eval ${__farr_keyname}_${__farr_len}="$(_farr_quote_for_eval "${__farr_key}")" + _farr_acquire_object "${__farr_value}" eval ${__farr_valname}_${__farr_len}="$(_farr_quote_for_eval "${__farr_value}")" # ... the new length eval ${__farr_objname}__=${__farr_len} @@ -2009,6 +2092,7 @@ if [ -n "${__farr_elkey}" ]; then eval __farr_elkey=\"\$\{${__farr_keyname}_${__farr_idx}\}\" if [ "${__farr_elkey}" = "${__farr_key}" ]; then + # key is already set: would be non-unique return 1 fi else @@ -2024,6 +2108,7 @@ __farr_len=${__farr_idx} # ... the key/value pairs to storage eval ${__farr_keyname}_${__farr_len}="$(_farr_quote_for_eval "${__farr_key}")" + _farr_acquire_object "${__farr_value}" eval ${__farr_valname}_${__farr_len}="$(_farr_quote_for_eval "${__farr_value}")" # ... the new length eval ${__farr_objname}__=${__farr_len} @@ -2077,6 +2162,7 @@ eval __farr_l_key=\"\$\{${__farr_l_keyname}_${__farr_l_idx}\}\" if [ "${__farr_l_key}" = "${__farr_r_key}" ]; then eval __farr_value=\"\$\{${__farr_r_valname}_${__farr_r_idx}\}\" + _farr_acquire_object "${__farr_value}" eval ${__farr_l_valname}_${__farr_l_idx}=\"\$\{__farr_value\}\" break fi @@ -2091,6 +2177,7 @@ # ... the key/value pairs to storage eval ${__farr_l_keyname}_${__farr_l_idx}=\"\$\{__farr_r_key\}\" eval __farr_value=\"\$\{${__farr_r_valname}_${__farr_r_idx}\}\" + _farr_acquire_object "${__farr_value}" eval ${__farr_l_valname}_${__farr_l_idx}=\"\$\{__farr_value\}\" # ... the new length in storage eval ${__farr_l_objname}__=${__farr_l_idx} @@ -2121,6 +2208,7 @@ local __farr_token __farr_objname __farr_keyname __farr_valname __farr_len local __farr_idx __farr_getkey + local __farr_get_value __farr_varname="${1-}" [ -z "${__farr_varname}" ] && _farr_fatal "missing variable name" @@ -2135,7 +2223,9 @@ if [ -n "${__farr_getkey}" ]; then eval __farr_getkey=\"\$\{${__farr_keyname}_${__farr_idx}\}\" if [ "${__farr_getkey}" = "${__farr_key}" ]; then - eval "${__farr_varname}"=\"\$\{${__farr_valname}_${__farr_idx}\}\" + eval __farr_get_value=\"\$\{${__farr_valname}_${__farr_idx}\}\" + _farr_acquire_object "${__farr_get_value}" + eval "${__farr_varname}"=\"\$\{__farr_get_value\}\" return 0 fi else @@ -2165,6 +2255,7 @@ local __farr_token __farr_objname __farr_keyname __farr_valname __farr_len local __farr_idx __farr_getkey + local __farr_get_value __farr_varname="${1-}" [ -z "${__farr_varname}" ] && _farr_fatal "missing variable name" @@ -2179,7 +2270,9 @@ if [ -n "${__farr_getkey}" ]; then eval __farr_getkey=\"\$\{${__farr_keyname}_${__farr_idx}\}\" if [ "${__farr_getkey}" = "${__farr_key}" ]; then - eval "${__farr_varname}"=\"\$\{${__farr_valname}_${__farr_idx}\}\" + eval __farr_get_value=\"\$\{${__farr_valname}_${__farr_idx}\}\" + _farr_acquire_object "${__farr_get_value}" + eval "${__farr_varname}"=\"\$\{__farr_get_value\}\" return 0 fi else @@ -2226,6 +2319,7 @@ if [ \( ${__farr_index} -ge 1 \) -a \( ${__farr_index} -le ${__farr_len} \) ]; then eval __farr_getikey=\"\$\{${__farr_keyname}_${__farr_index}+SET\}\" if [ -n "${__farr_getikey}" ]; then + # no refcount change because no complex values allowed yet eval "${__farr_varname}"=\"\$\{${__farr_keyname}_${__farr_index}\}\" return 0 else @@ -2272,7 +2366,9 @@ if [ \( ${__farr_index} -ge 1 \) -a \( ${__farr_index} -le ${__farr_len} \) ]; then eval __farr_getival=\"\$\{${__farr_valname}_${__farr_index}+SET\}\" if [ -n "${__farr_getival}" ]; then - eval "${__farr_varname}"=\"\$\{${__farr_valname}_${__farr_index}\}\" + eval __farr_getival=\"\$\{${__farr_valname}_${__farr_index}\}\" + _farr_acquire_object "${__farr_getival}" + eval "${__farr_varname}"=\"\$\{__farr_getival\}\" return 0 else _farr_fatal "value unexpectedly unset (index ${__farr_index})" @@ -2325,7 +2421,9 @@ eval __farr_getival=\"\$\{${__farr_valname}_${__farr_index}+SET\}\" if [ -n "${__farr_getival}" ]; then eval "${__farr_key_varname}"=\"\$\{${__farr_keyname}_${__farr_index}\}\" - eval "${__farr_value_varname}"=\"\$\{${__farr_valname}_${__farr_index}\}\" + eval __farr_getival=\"\$\{${__farr_valname}_${__farr_index}\}\" + _farr_acquire_object "${__farr_getival}" + eval "${__farr_value_varname}"=\"\$\{__farr_getival\}\" return 0 else _farr_fatal "value unexpectedly unset (index ${__farr_index})" @@ -2385,6 +2483,7 @@ #: $2 (int): The current length of the storage object (i.e. the current #: length of the alist) #: $3 (int): The storage index that will be deleted +#: $4: if no-null use release semantics (used for values) #: #: Returns: #: int: Always 0 @@ -2399,13 +2498,22 @@ #: _farr_alist_del_storage_at_index() { local __farr_storage_name __farr_storage_length __farr_storage_index - - local __farr_idx + local __farr_use_release + + local __farr_idx __farr_del_item __farr_storage_name="$1" __farr_storage_length="$2" __farr_storage_index="$3" - + __farr_use_release="$4" + + # Release the item at index -- if requested + if [ -n "${__farr_use_release}" ] ; then + eval __farr_del_item=\"\$\{${__farr_storage_name}_${__farr_idx}\}\" + _farr_release_object "${__farr_del_item}" + fi + + # Move all other items down by one __farr_idx=${__farr_storage_index} while [ ${__farr_idx} -lt ${__farr_storage_length} ] ; do # copy the following value to the current index @@ -2445,8 +2553,8 @@ if [ -n "${__farr_curkey}" ]; then eval __farr_curkey=\"\$\{${__farr_keyname}_${__farr_idx}\}\" if [ "${__farr_curkey}" = "${__farr_delkey}" ]; then - _farr_alist_del_storage_at_index "${__farr_valname}" ${__farr_len} ${__farr_idx} - _farr_alist_del_storage_at_index "${__farr_keyname}" ${__farr_len} ${__farr_idx} + _farr_alist_del_storage_at_index "${__farr_valname}" "${__farr_len}" "${__farr_idx}" '1' + _farr_alist_del_storage_at_index "${__farr_keyname}" "${__farr_len}" "${__farr_idx}" "" # Reduce the length by 1 eval ${__farr_objname}__=$((__farr_len - 1)) return 0 @@ -2807,8 +2915,10 @@ eval __farr_feval=\"\$\{${__farr_valname}_${__farr_feidx}+SET\}\" if [ -n "${__farr_feval}" ]; then eval __farr_feval=\"\$\{${__farr_valname}_${__farr_feidx}\}\" + _farr_acquire_object "${__farr_feval}" eval "${__farr_callback} \"\${__farr_name:-\"\${__farr_gm_name_or_value}\"}\" \"\${__farr_fekey}\" \"\${__farr_feval}\" \"\${__farr_feidx}\" \"\$@\"" __farr_rv=$? + _farr_release_object "${__farr_feval}" [ ${__farr_rv} -ne 0 ] && return ${__farr_rv} else _farr_fatal "alist \`${__farr_name:-"${__farr_gm_name_or_value}"}': missing value index" @@ -2898,10 +3008,55 @@ #: -#: Destroy any object. -#: -#: If an object represents an array or alist its contents will be destroyed -#: properly. +#: Acquire any object. +#: +#: If an object represents an array or alist its reference count will be +#: increased. +#: +#: Args: +#: $1: The object's value +#: +#: Returns: +#: int: 0 if the incrementation went properly, 1 otherwise +#: +_farr_acquire_object() { + + local __farr_tmp_refcount __farr_tmp_token + + case "$1" in + '') + return 0 + ;; + "${_farr_array_token_prefix}"*) + __farr_tmp_token="${1#"${_farr_array_token_prefix}"}" + eval __farr_tmp_refcount=\$\{${_farr_array_prefix}${__farr_tmp_token}_C:+SET\} + [ -z "${__farr_tmp_refcount}" ] && return 1 + eval __farr_tmp_refcount=\$\{${_farr_array_prefix}${__farr_tmp_token}_C\} + __farr_tmp_refcount=$((__farr_tmp_refcount + 1)) + eval ${_farr_array_prefix}${__farr_tmp_token}_C=\$\{__farr_tmp_refcount\} + return 0 + ;; + "${_farr_alist_token_prefix}"*) + __farr_tmp_token="${1#"${_farr_alist_token_prefix}"}" + eval __farr_tmp_refcount=\$\{${_farr_alist_prefix}${__farr_tmp_token}_C:+SET\} + [ -z "${__farr_tmp_refcount}" ] && return 1 + eval __farr_tmp_refcount=\$\{${_farr_alist_prefix}${__farr_tmp_token}_C\} + __farr_tmp_refcount=$((__farr_tmp_refcount + 1)) + eval ${_farr_alist_prefix}${__farr_tmp_token}_C=\$\{__farr_tmp_refcount\} + return 0 + ;; + *) + return 0 + ;; + esac +} + + +#: +#: Release any object. +#: +#: If an object represents an array or alist its reference count will be +#: decreased properly. #: #: Args: #: $1: The object's value @@ -2909,7 +3064,7 @@ #: Returns: #: int: 0 if the destruction went properly without errors, 1 otherwise #: -_farr_destroy_object() { +_farr_release_object() { case "$1" in '') diff -r 35c29e9919ba -r 858f4208d9cb tests/farray-alist.t --- a/tests/farray-alist.t Sun Oct 06 17:23:09 2024 +0200 +++ b/tests/farray-alist.t Mon Oct 07 12:36:18 2024 +0200 @@ -420,13 +420,13 @@ $ falist_debug LIST DEBUG: alist `LIST' has length 1 DEBUG: `k1' -> `v2' - $ _farr_destroy_object "$LIST" + $ _farr_release_object "$LIST" $ check_no_alist_artifacts - $ (_farr_destroy_object "$LIST") + $ (_farr_release_object "$LIST") ERROR: falist `_farr_KV\?\?:([a-f0-9]+)' not created properly: no object for token `\1' (re) - [70] + [1] $ LIST='' - $ _farr_destroy_object "$LIST" + $ _farr_release_object "$LIST" $ check_no_alist_artifacts @@ -436,8 +436,8 @@ $ falist_create LIST $ falist_set LIST K1 V1 $ falist_create ITEM1 K11 V11 K22 V22 -# This also transfers ownership $ falist_set LIST K2 "$ITEM1" + $ falist_destroy ITEM1 $ falist_debug LIST DEBUG: alist `LIST' has length 2 DEBUG: `K1' -> `V1' diff -r 35c29e9919ba -r 858f4208d9cb tests/farray-array.t --- a/tests/farray-array.t Sun Oct 06 17:23:09 2024 +0200 +++ b/tests/farray-array.t Mon Oct 07 12:36:18 2024 +0200 @@ -1093,7 +1093,8 @@ [70] $ check_no_array_artifacts - _farr_A_[0-9a-f]+__=0 (re) + _farr_A_[0-9a-f]+_C\=1 (re) + _farr_A_[0-9a-f]+__\=0 (re) [1] $ farray_destroy DUP @@ -1143,13 +1144,13 @@ DEBUG: its contents: DEBUG: 1: `i1' DEBUG: 2: `i2' - $ _farr_destroy_object "$TEST" + $ _farr_release_object "$TEST" $ check_no_array_artifacts - $ (_farr_destroy_object "$TEST") + $ (_farr_release_object "$TEST") ERROR: farray `_farr_A\?:([a-f0-9]+)' not created properly: no storage for token `\1' (re) [1] $ TEST='' - $ _farr_destroy_object "$TEST" + $ _farr_release_object "$TEST" $ check_no_array_artifacts @@ -1158,8 +1159,8 @@ $ farray_create TEST i1 i2 $ farray_create ITEM1 i11 i22 -This also transfers ownership $ farray_append TEST "$ITEM1" + $ farray_destroy ITEM1 $ farray_debug TEST DEBUG: array `TEST' has length 3 DEBUG: its contents: diff -r 35c29e9919ba -r 858f4208d9cb tests/farray-object.t --- a/tests/farray-object.t Sun Oct 06 17:23:09 2024 +0200 +++ b/tests/farray-object.t Mon Oct 07 12:36:18 2024 +0200 @@ -17,13 +17,12 @@ $ farray_create ARRAY1 i1 i2 $ farray_create ITEM1 i11 i22 -This also transfers ownership $ farray_append ARRAY1 "$ITEM1" - $ ITEM1='' + $ farray_destroy ITEM1 $ falist_create LIST2 k1 v1 k2 v2 k3 v3 This also transfers ownership $ farray_append ARRAY1 "$LIST2" - $ LIST2='' + $ falist_destroy LIST2 $ farray_debug ARRAY1 DEBUG: array `ARRAY1' has length 4 DEBUG: its contents: @@ -49,13 +48,11 @@ $ falist_create LIST1 k1 v1 $ falist_create ITEM1 k11 v11 k22 v22 k33 v33 k44 v44 -This also transfers ownership $ falist_set LIST1 k2 "$ITEM1" - $ ITEM1='' + $ falist_destroy ITEM1 $ farray_create ARRAY2 a1 a2 a3 -This also transfers ownership $ falist_set LIST1 k3 "$ARRAY2" - $ ARRAY2='' + $ farray_destroy ARRAY2 $ falist_debug LIST1 DEBUG: alist `LIST1' has length 3 DEBUG: `k1' -> `v1'