changeset 612:c9ef2339618d

farray.sh: Implemented comparison (ordered and unordered) for alists
author Franz Glasner <fzglas.hg@dom66.de>
date Thu, 19 Sep 2024 18:29:57 +0200
parents dbd793238b94
children 17194ffe3638
files share/local-bsdtools/farray.sh tests/farray-alist.t
diffstat 2 files changed, 168 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/share/local-bsdtools/farray.sh	Thu Sep 19 17:31:59 2024 +0200
+++ b/share/local-bsdtools/farray.sh	Thu Sep 19 18:29:57 2024 +0200
@@ -64,6 +64,8 @@
 #:   Exceptions to this rule are documented.
 #: - An alist preserves insertion order. Note that updating a key does not
 #:   affect the order. Keys added after deletion are inserted at the end.
+#: - Alists compare equal if and only if they have the same (key, value) pairs
+#:   (regardless of ordering).
 #:
 #: Hints and rules for indexes:
 #:
@@ -1896,6 +1898,131 @@
 
 
 #:
+#: Test whether two alists are equal.
+#:
+#: Two alists compare equal if and only if they have the same (key, value)
+#: pairs (regardless of ordering). Comparison is done using the shell's
+#: builtin ``=`` operator for both keys and values.
+#:
+#: Args:
+#:   $1 (str): The name of the first alist
+#:   $2 (str): The name of the second alist
+#:
+#: Returns:
+#:   int: 0 if both input alists are equal, 1 otherwise
+#:
+falist_are_equal() {
+    local __farr_l_name __farr_r_name
+
+    local __farr_l_token __farr_l_objname __farr_l_keyname __farr_l_valname __farr_l_len
+    local __farr_r_token __farr_r_objname __farr_r_keyname __farr_r_valname __farr_r_len
+
+    local __farr_name __farr_token __farr_objname __farr_keyname __farr_valname __farr_len
+    local __farr_l_idx __farr_l_key __farr_l_value
+    local __farr_r_idx __farr_r_key __farr_r_value
+
+    [ $# -ne 2 ] && _farr_fatal "missing alist parameter"
+
+    _farr_alist_get_meta "$1"
+    __farr_l_name="${__farr_name}"
+    __farr_l_token="${__farr_token}"
+    __farr_l_objname="${__farr_objname}"
+    __farr_l_keyname="${__farr_keyname}"
+    __farr_l_valname="${__farr_valname}"
+    __farr_l_len="${__farr_len}"
+    _farr_alist_get_meta "$2"
+    __farr_r_name="${__farr_name}"
+    __farr_r_token="${__farr_token}"
+    __farr_r_objname="${__farr_objname}"
+    __farr_r_keyname="${__farr_keyname}"
+    __farr_r_valname="${__farr_valname}"
+    __farr_r_len="${__farr_len}"
+
+    [ ${__farr_l_len} -ne ${__farr_r_len} ] && return 1
+
+    __farr_l_idx=1
+    while [ ${__farr_l_idx} -le ${__farr_l_len} ]; do
+        __farr_r_idx=1
+        eval __farr_l_key=\"\$\{${__farr_l_keyname}_${__farr_l_idx}\}\"
+        # Find within the right alist
+        __farr_r_idx=1
+        while [ ${__farr_r_idx} -le ${__farr_r_len} ]; do
+            eval __farr_r_key=\"\$\{${__farr_r_keyname}_${__farr_r_idx}\}\"
+            [ "${__farr_l_key}" = "${__farr_r_key}" ] && break
+            __farr_r_idx=$((__farr_r_idx + 1))
+        done
+        # The index is above the right length if not found
+        [ ${__farr_r_idx} -gt ${__farr_r_len} ] && return 1
+        # Also compare the values
+        eval __farr_l_value=\"\$\{${__farr_l_valname}_${__farr_l_idx}\}\"
+        eval __farr_r_value=\"\$\{${__farr_r_valname}_${__farr_r_idx}\}\"
+        [ "${__farr_l_value}" != "${__farr_r_value}" ] && return 1
+        __farr_l_idx=$((__farr_l_idx + 1))
+    done
+    return 0
+}
+
+
+#:
+#: Test whether two alists are equal respecting the (insertion) order.
+#:
+#: Two alists compare equal if and only if they have the same (key, value)
+#: pairs **with** regard of ordering. Comparison is done using the shell's
+#: builtin ``=`` operator for both keys and values.
+#:
+#: Args:
+#:   $1 (str): The name of the first alist
+#:   $2 (str): The name of the second alist
+#:
+#: Returns:
+#:   int: 0 if both input alists are equal, 1 otherwise
+#:
+falist_are_equal_with_order() {
+    local __farr_l_name __farr_r_name
+
+    local __farr_l_token __farr_l_objname __farr_l_keyname __farr_l_valname __farr_l_len
+    local __farr_r_token __farr_r_objname __farr_r_keyname __farr_r_valname __farr_r_len
+
+    local __farr_name __farr_token __farr_objname __farr_keyname __farr_valname __farr_len
+    local __farr_idx
+    local __farr_l_key __farr_l_value
+    local __farr_r_key __farr_r_value
+
+    [ $# -ne 2 ] && _farr_fatal "missing alist parameter"
+
+    _farr_alist_get_meta "$1"
+    __farr_l_name="${__farr_name}"
+    __farr_l_token="${__farr_token}"
+    __farr_l_objname="${__farr_objname}"
+    __farr_l_keyname="${__farr_keyname}"
+    __farr_l_valname="${__farr_valname}"
+    __farr_l_len="${__farr_len}"
+    _farr_alist_get_meta "$2"
+    __farr_r_name="${__farr_name}"
+    __farr_r_token="${__farr_token}"
+    __farr_r_objname="${__farr_objname}"
+    __farr_r_keyname="${__farr_keyname}"
+    __farr_r_valname="${__farr_valname}"
+    __farr_r_len="${__farr_len}"
+
+    [ ${__farr_l_len} -ne ${__farr_r_len} ] && return 1
+
+    __farr_idx=1
+    while [ ${__farr_idx} -le ${__farr_l_len} ]; do
+        eval __farr_l_key=\"\$\{${__farr_l_keyname}_${__farr_idx}\}\"
+        eval __farr_r_key=\"\$\{${__farr_r_keyname}_${__farr_idx}\}\"
+        [ "${__farr_l_key}" != "${__farr_r_key}" ] && return 1
+        # Also compare the values
+        eval __farr_l_value=\"\$\{${__farr_l_valname}_${__farr_idx}\}\"
+        eval __farr_r_value=\"\$\{${__farr_r_valname}_${__farr_idx}\}\"
+        [ "${__farr_l_value}" != "${__farr_r_value}" ] && return 1
+        __farr_idx=$((__farr_idx + 1))
+    done
+    return 0
+}
+
+
+#:
 #: 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:
--- a/tests/farray-alist.t	Thu Sep 19 17:31:59 2024 +0200
+++ b/tests/farray-alist.t	Thu Sep 19 18:29:57 2024 +0200
@@ -225,3 +225,44 @@
   $ falist_destroy LIST
 
   $ check_no_alist_artifacts
+
+
+Compare
+=======
+
+  $ falist_create LIST1
+  $ falist_set LIST1 K1 V1
+  $ falist_set LIST1 K2 V2
+
+  $ falist_create LIST2
+  $ falist_set LIST2 K2 V2
+  $ falist_set LIST2 K1 V1
+
+  $ falist_create LIST3
+  $ falist_set LIST3 K1 V1
+  $ falist_set LIST3 K2 V2
+
+  $ falist_create LIST4
+  $ falist_set LIST4 K1 V1
+  $ falist_set LIST4 K2 V2-4
+
+  $ falist_are_equal LIST1 LIST2
+  $ falist_are_equal LIST1 LIST4
+  [1]
+  $ falist_are_equal_with_order LIST1 LIST2
+  [1]
+  $ falist_are_equal_with_order LIST1 LIST3
+
+  $ falist_clear LIST2
+  $ falist_are_equal LIST1 LIST2
+  [1]
+
+  $ falist_clear LIST3
+  $ falist_are_equal_with_order LIST2 LIST3
+
+  $ falist_destroy LIST1
+  $ falist_destroy LIST2
+  $ falist_destroy LIST3
+  $ falist_destroy LIST4
+
+  $ check_no_alist_artifacts
\ No newline at end of file