changeset 522:210695c732dd

array.sh: Implement alist_for_each(). This is analogous to array_for_each().
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 02 Sep 2024 02:12:07 +0200
parents c05ef1c86c9c
children ea199195b214
files share/local-bsdtools/array.sh
diffstat 1 files changed, 62 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/share/local-bsdtools/array.sh	Sun Sep 01 21:52:01 2024 +0200
+++ b/share/local-bsdtools/array.sh	Mon Sep 02 02:12:07 2024 +0200
@@ -1048,7 +1048,7 @@
     __farr_varname=$1
     [ $# -lt 2 ] && _farr_fatal "missing array name"
     __farr_name=$2
-    __farr_val_array=${_farr_alist_value_infix}${__farr_name}    
+    __farr_val_array=${_farr_alist_value_infix}${__farr_name}
     [ $# -lt 3 ] && _farr_fatal "missing index"
     __farr_index=$3
 
@@ -1087,6 +1087,61 @@
 
 
 #:
+#: Call a function for every key-value pair in an alist starting in index order.
+#:
+#: The function to be called must accept three or four arguments:
+#: - the alist name
+#: - the element key at the current index
+#: - the element value at the current index
+#: - the current index
+#:
+#: The iteration stops if the called function returns a falsy value.
+#:
+#: Args:
+#:   $1 (str): The name of an existing array.
+#:   $2 (str): The name of a function to be called with four arguments.
+#:
+#: Warning:
+#:   If the number of elements changes while being in `alist_for_each` then
+#:   the behaviour is undefined.
+#:   The current implementation determines the length of the alist once
+#:   at the start of execution.
+#:
+alist_for_each() {
+    local __farr_name __farr_callback
+
+    local __farr_key_array __farr_val_array __farr_idx __farr_length
+    local __farr_feidx __farr_fekey __farr_feval __farr_rv
+
+    [ $# -lt 1 ] && _farr_fatal "missing alist name"
+    __farr_name=$1
+    __farr_key_array=${_farr_alist_key_infix}${__farr_name}
+    __farr_val_array=${_farr_alist_value_infix}${__farr_name}
+    [ $# -lt 2 ] && _farr_fatal "missing callback function name"
+    __farr_callback="$2"
+
+    if ! alist_length __farr_length ${__farr_name}; then
+        _farr_fatal "alist \`${__farr_name}' does not exist"
+    fi
+    __farr_feidx=1
+    while [ ${__farr_feidx} -le ${__farr_length} ]; do
+        if alist_tryget_key_at_index __farr_fekey ${__farr_name} ${__farr_feidx}; then
+            if alist_tryget_value_at_index __farr_feval ${__farr_name} ${__farr_feidx}; then
+                eval "${__farr_callback} ${__farr_name} \"\${__farr_fekey}\" \"\${__farr_feval}\" ${__farr_feidx}"
+                __farr_rv=$?
+                [ ${__farr_rv} -ne 0 ] && return ${__farr_rv}
+            else
+                _farr_fatal "alist \`${__farr_name}': missing value index"
+            fi
+        else
+            _farr_fatal "alist \`${__farr_name}': missing key index"
+        fi
+        __farr_feidx=$((${__farr_feidx} + 1))
+    done
+}
+
+
+#:
 #: Print the contents of an alist to stderr.
 #:
 #: Args:
@@ -1233,7 +1288,7 @@
         echo "VALID LENGTH (ERROR)"
     fi
 
-    # Iteration
+    # Iteration by indexing
     echo "ITERATE:"
     _i=1
     while alist_tryget_key_at_index _k LIST ${_i}; do
@@ -1242,7 +1297,11 @@
         printf "  KEY: \`%s', VAL: \`%s'\\n" "${_k}" "${_v}"
         _i=$((${_i} + 1))
     done
-    
+
+    # Iteration with for each
+    echo "ITERATE (for each):"
+    alist_for_each LIST $'printf "EACH: %s key \\`%s\\\', value \\`%s\\\' at idx %d\\n"'   # `
+
     alist_clear LIST
     if ! alist_destroy LIST ; then
         echo "DESTROY FAILED (ERROR)"