diff tests/farray-alist.t @ 756:33df05108ba1

farray.sh: New implementation alists: searching is done using a binary search now while preserving insertion order. The implementation uses two key lists: The first one is sorted and is used for searching using binary search. The second is a double-linked list and is used for remembering the insertion order.
author Franz Glasner <fzglas.hg@dom66.de>
date Sat, 19 Oct 2024 22:40:11 +0200
parents 4101e755b3e7
children 7ead30e3b2f9
line wrap: on
line diff
--- a/tests/farray-alist.t	Fri Oct 18 14:02:18 2024 +0200
+++ b/tests/farray-alist.t	Sat Oct 19 22:40:11 2024 +0200
@@ -18,6 +18,14 @@
 Create an empty alist
 
   $ falist_create LIST
+Has some initial global variables set
+  $ check_no_alist_artifacts
+  _farr_KV_[a-f0-9]+_B=0 (re)
+  _farr_KV_[a-f0-9]+_C=1 (re)
+  _farr_KV_[a-f0-9]+_P='0;0' (re)
+  _farr_KV_[a-f0-9]+__=0 (re)
+  [1]
+
   $ falist_length _i LIST
   $ echo "$_i"
   0
@@ -37,6 +45,161 @@
 
   $ check_no_alist_artifacts
 
+  $ falist_create LIST
+  $ falist_clear LIST
+  $ falist_istrue LIST
+  [1]
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 0
+  $ falist_release LIST
+  $ ( falist_release LIST )
+  ERROR: object `LIST' not created properly: token empty
+  [1]
+  $ check_no_alist_artifacts
+
+
+Creation and Destruction with one Item
+======================================
+
+Create an alist with one item
+
+  $ falist_create LIST K1 V1
+  $ falist_length _i LIST
+  $ echo "$_i"
+  1
+  $ test "${_i}" -eq 1
+  $ falist_print_length LIST
+  1 (no-eol)
+
+  $ falist_istrue LIST
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 1
+  DEBUG:   the items:
+  DEBUG:     `K1' -> `V1'
+  $ falist_release LIST
+  $ ( falist_release LIST )
+  ERROR: object `LIST' not created properly: token empty
+  [1]
+
+  $ check_no_alist_artifacts
+
+One Item that replaces the first item
+
+  $ falist_create LIST K1 V1 K1 "V1 1"
+  $ falist_length _i LIST
+  $ echo "$_i"
+  1
+  $ test "${_i}" -eq 1
+  $ falist_print_length LIST
+  1 (no-eol)
+
+  $ falist_istrue LIST
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 1
+  DEBUG:   the items:
+  DEBUG:     `K1' -> `V1 1'
+  $ falist_release LIST
+  $ ( falist_release LIST )
+  ERROR: object `LIST' not created properly: token empty
+  [1]
+
+  $ check_no_alist_artifacts
+
+
+Creation and Destruction with more Items
+========================================
+
+Create an alist with two items
+
+  $ falist_create LIST K1 V1 K2 V2
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 2
+  DEBUG:   the items:
+  DEBUG:     `K1' -> `V1'
+  DEBUG:     `K2' -> `V2'
+
+  $ falist_release LIST
+
+  $ check_no_alist_artifacts
+
+Create with inverse insertion order
+
+  $ falist_create LIST K2 V2 K1 V1
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 2
+  DEBUG:   the items:
+  DEBUG:     `K2' -> `V2'
+  DEBUG:     `K1' -> `V1'
+
+  $ falist_release LIST
+
+Insert at the beginning
+
+
+  $ falist_create LIST K2 V2 K1 V1 K0 V0
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 3
+  DEBUG:   the items:
+  DEBUG:     `K2' -> `V2'
+  DEBUG:     `K1' -> `V1'
+  DEBUG:     `K0' -> `V0'
+
+Replace: beginning
+
+  $ falist_set $LIST K2 $'V2 \' \\ "$abc'
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 3
+  DEBUG:   the items:
+  DEBUG:     `K2' -> `V2 ' \ "$abc'
+  DEBUG:     `K1' -> `V1'
+  DEBUG:     `K0' -> `V0'
+
+Replace: mid
+
+  $ falist_set $LIST K1 'V1 1'
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 3
+  DEBUG:   the items:
+  DEBUG:     `K2' -> `V2 ' \ "$abc'
+  DEBUG:     `K1' -> `V1 1'
+  DEBUG:     `K0' -> `V0'
+
+Replace: end
+
+  $ falist_set $LIST K0 'V0 1'
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 3
+  DEBUG:   the items:
+  DEBUG:     `K2' -> `V2 ' \ "$abc'
+  DEBUG:     `K1' -> `V1 1'
+  DEBUG:     `K0' -> `V0 1'
+
+Insert in the midele again
+
+  $ falist_set LIST K1-1 'V1-1'
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 4
+  DEBUG:   the items:
+  DEBUG:     `K2' -> `V2 ' \ "$abc'
+  DEBUG:     `K1' -> `V1 1'
+  DEBUG:     `K0' -> `V0 1'
+  DEBUG:     `K1-1' -> `V1-1'
+
+Clear resets to initial values
+
+  $ falist_clear LIST
+  $ check_no_alist_artifacts
+  _farr_KV_[a-f0-9]+_B=0 (re)
+  _farr_KV_[a-f0-9]+_C=1 (re)
+  _farr_KV_[a-f0-9]+_P='0;0' (re)
+  _farr_KV_[a-f0-9]+__=0 (re)
+  [1]
+
+  $ falist_print_length LIST
+  0 (no-eol)
+  $ falist_release LIST
+  $ check_no_alist_artifacts
+
 
 Clear
 =====
@@ -44,14 +207,14 @@
   $ falist_create LIST
   $ falist_istrue LIST
   [1]
-  $ falist_set LIST K1 V1
+  $ falist_set LIST K2 V2
   $ falist_istrue LIST
-  $ falist_set LIST K2 V2
+  $ falist_set LIST K1 V1
   $ falist_debug LIST
   DEBUG: alist `LIST' has length 2
   DEBUG:   the items:
+  DEBUG:     `K2' -> `V2'
   DEBUG:     `K1' -> `V1'
-  DEBUG:     `K2' -> `V2'
   $ falist_length _i LIST
   $ echo "$_i"
   2
@@ -67,6 +230,17 @@
   $ falist_print_length LIST
   0 (no-eol)
 
+Clear resets to initial values
+
+  $ falist_clear LIST
+  $ check_no_alist_artifacts
+  _farr_KV_[a-f0-9]+_B=0 (re)
+  _farr_KV_[a-f0-9]+_C=1 (re)
+  _farr_KV_[a-f0-9]+_P='0;0' (re)
+  _farr_KV_[a-f0-9]+__=0 (re)
+  [1]
+  $ falist_istrue LIST
+  [1]
   $ falist_release LIST
   $ falist_istrue LIST
   ERROR: object `LIST' not created properly: token empty
@@ -74,6 +248,359 @@
   $ check_no_alist_artifacts
 
 
+Optimized Adding
+================
+
+  $ falist_create LIST
+  $ falist_add LIST k1 v1
+  $ falist_add LIST k2 v2
+Would violate order requirements
+  $ ( falist_add LIST k0 v0 )
+  ERROR: falist_add() would violate key order
+  [70]
+  $ ( falist_add LIST k2 v2-2 )
+  ERROR: falist_add() would violate key order
+  [70]
+  $ falist_add $LIST k3 $'" 111222333" \\\'444555666 '    # '
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 3
+  DEBUG:   the items:
+  DEBUG:     `k1' -> `v1'
+  DEBUG:     `k2' -> `v2'
+  DEBUG:     `k3' -> `" 111222333" \'444555666 '
+  $ falist_add $LIST k4 'v4 1' k5 v5
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 5
+  DEBUG:   the items:
+  DEBUG:     `k1' -> `v1'
+  DEBUG:     `k2' -> `v2'
+  DEBUG:     `k3' -> `" 111222333" \'444555666 '
+  DEBUG:     `k4' -> `v4 1'
+  DEBUG:     `k5' -> `v5'
+  $ falist_release LIST
+  $ check_no_alist_artifacts
+
+
+Iteration
+=========
+
+  $ falist_create LIST
+  $ falist_set LIST K1 V1
+  $ falist_set LIST K2 "V2 2"
+  $ falist_set LIST K3 $'" 111222333" \\\'444555 '    # '
+
+Consistency check of storage cookies
+
+  $ _c="$(falist_cookie_first LIST)"
+  $ echo $_c
+  1/0;2@[a-f0-9]+ (re)
+  $ _cnull="$(falist_cookie_prev "${_c}")"
+  $ echo "${_cnull}"
+  0/0;0@[a-f0-9]+ (re)
+  $ _c2="$(falist_cookie_next "$_c")"
+  $ echo "${_c2}"
+  2/1;3@[a-f0-9]+ (re)
+  $ _c3="$(falist_cookie_prev "${_c2}")"
+  $ test "${_c}" = "${_c3}"
+  $ _c=$(falist_cookie_last LIST)
+  $ echo $_c
+  3/2;0@[a-f0-9]+ (re)
+  $ _cnull="$(falist_cookie_next "${_c}")"
+  $ echo "${_cnull}"
+  0/0;0@[a-f0-9]+ (re)
+
+MANUAL (by cookie, forward in insertion order)
+
+  $ _pos="$(falist_cookie_first LIST)"
+  > while falist_tryget_item_at _k _v "$_pos"; do
+  >   printf $'%s -> `%s\'\\n' "$_k" "$_v"
+  >   _pos="$(falist_cookie_next "$_pos")"
+  > done
+  K1 -> `V1'
+  K2 -> `V2 2'
+  K3 -> `" 111222333" \'444555 '
+
+MANUAL (by cookie, reversed insertion order)
+
+  $ _pos="$(falist_cookie_last LIST)"
+  > while falist_tryget_item_at _k _v "$_pos"; do
+  >   printf $'`%s\' <- %s\\n' "$_v" "$_k"
+  >   _pos="$(falist_cookie_prev "$_pos")"
+  > done
+  `" 111222333" \'444555 ' <- K3
+  `V2 2' <- K2
+  `V1' <- K1
+
+MANUAL values (by cookie, forward in insertion order)
+
+  $ _pos="$(falist_cookie_first LIST)"
+  > while falist_tryget_value_at _v "$_pos"; do
+  >   printf $'`%s\'\\n' "$_v"
+  >   _pos="$(falist_cookie_next "$_pos")"
+  > done
+  `V1'
+  `V2 2'
+  `" 111222333" \'444555 '
+
+
+MANUAL keys (by cookie, reversed insertion order)
+
+  $ _pos="$(falist_cookie_last LIST)"
+  > while falist_tryget_key_at _k "$_pos"; do
+  >   printf '%s\n' "$_k"
+  >   _pos="$(falist_cookie_prev "$_pos")"
+  > done
+  K3
+  K2
+  K1
+
+ITERATE (for each, by name)
+
+  $ falist_for_each LIST $'printf "EACH: %s key \\`%s\\\', value \\`%s\\\' at cookie %s\\n"'   # `
+  EACH: LIST key `K1', value `V1' at cookie 1/[0-9]+;[0-9]+@[a-f0-9]+ (re)
+  EACH: LIST key `K2', value `V2 2' at cookie 2/[0-9]+;[0-9]+@[a-f0-9]+ (re)
+  EACH: LIST key `K3', value `" 111222333" \\'444555 ' at cookie 3/[0-9]+;[0-9]+@[a-f0-9]+ (re)
+
+ITERATE (for each, by value)
+
+  $ falist_for_each "$LIST" $'printf "EACH: %s key \\`%s\\\', value \\`%s\\\' at cookie %s\\n"'   # `
+  EACH: _farr_KV\[\?,\?\]:[a-f0-9]+ key `K1', value `V1' at cookie 1/[0-9]+;[0-9]+@[a-f0-9]+ (re)
+  EACH: _farr_KV\[\?,\?\]:[a-f0-9]+ key `K2', value `V2 2' at cookie 2/[0-9]+;[0-9]+@[a-f0-9]+ (re)
+  EACH: _farr_KV\[\?,\?\]:[a-f0-9]+ key `K3', value `" 111222333" \\'444555 ' at cookie 3/[0-9]+;[0-9]+@[a-f0-9]+ (re)
+
+  $ falist_clear LIST
+
+  $ falist_release LIST
+  $ falist_release LIST
+  ERROR: object `LIST' not created properly: token empty
+  [1]
+  $ check_no_alist_artifacts
+
+
+Deleting
+========
+
+  $ falist_create LIST
+  $ (falist_trydel LIST foo)
+  [1]
+
+  $ falist_release LIST
+  $ check_no_alist_artifacts
+
+  $ falist_create LIST K1 V1
+  $ (falist_trydel LIST foo)
+  [1]
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 1
+  DEBUG:   the items:
+  DEBUG:     `K1' -> `V1'
+  $ falist_istrue LIST
+  $ falist_trydel LIST K1
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 0
+  $ check_no_alist_artifacts
+  _farr_KV_[a-f0-9]+_B=0 (re)
+  _farr_KV_[a-f0-9]+_C=1 (re)
+  _farr_KV_[a-f0-9]+_P='0;0' (re)
+  _farr_KV_[a-f0-9]+__=0 (re)
+  [1]
+  $ (falist_istrue LIST)
+  [1]
+  $ falist_release LIST
+  $ check_no_alist_artifacts
+
+  $ falist_create LIST K1 V1 K2 V2
+  $ (falist_trydel LIST foo)
+  [1]
+  $ falist_trydel LIST K1
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 1
+  DEBUG:   the items:
+  DEBUG:     `K2' -> `V2'
+  $ falist_trydel LIST K2
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 0
+  $ falist_release LIST
+  $ check_no_alist_artifacts
+
+  $ falist_create LIST K1 V1 K2 V2
+  $ (falist_trydel LIST foo)
+  [1]
+  $ falist_trydel LIST K2
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 1
+  DEBUG:   the items:
+  DEBUG:     `K1' -> `V1'
+  $ falist_trydel LIST K1
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 0
+  $ falist_release LIST
+  $ check_no_alist_artifacts
+
+  $ falist_create LIST K1 V1 K2 V2 K3 V3
+  $ (falist_trydel LIST foo)
+  [1]
+  $ falist_trydel LIST K1
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 2
+  DEBUG:   the items:
+  DEBUG:     `K2' -> `V2'
+  DEBUG:     `K3' -> `V3'
+  $ falist_release LIST
+  $ check_no_alist_artifacts
+
+  $ falist_create LIST K1 V1 K2 V2 K3 V3
+  $ (falist_trydel LIST foo)
+  [1]
+  $ falist_trydel LIST K2
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 2
+  DEBUG:   the items:
+  DEBUG:     `K1' -> `V1'
+  DEBUG:     `K3' -> `V3'
+  $ falist_release LIST
+  $ check_no_alist_artifacts
+
+  $ falist_create LIST K1 V1 K2 V2 K3 V3
+  $ (falist_trydel LIST foo)
+  [1]
+  $ falist_trydel LIST K3
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 2
+  DEBUG:   the items:
+  DEBUG:     `K1' -> `V1'
+  DEBUG:     `K2' -> `V2'
+  $ falist_release LIST
+  $ check_no_alist_artifacts
+
+  $ falist_create LIST K1 V1 K2 V2 K3 V3
+  $ (falist_trydel LIST foo)
+  [1]
+  $ falist_trydel LIST K2
+  $ falist_trydel LIST K1
+  $ falist_trydel LIST K3
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 0
+Check that the binary search list is cleaned up
+  $ check_no_alist_artifacts
+  _farr_KV_[a-f0-9]+_B=0 (re)
+  _farr_KV_[a-f0-9]+_C=1 (re)
+  _farr_KV_[a-f0-9]+_P='0;0' (re)
+  _farr_KV_[a-f0-9]+__=0 (re)
+  [1]
+  $ falist_release LIST
+  $ check_no_alist_artifacts
+
+  $ falist_create LIST K1 V1 K2 V2 K3 V3
+  $ (falist_trydel LIST foo)
+  [1]
+  $ falist_trydel LIST K2
+Skipping tombstones
+  $ (falist_trydel LIST K2)
+  [1]
+  $ falist_trydel LIST K3
+  $ (falist_trydel LIST K3)
+  [1]
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 1
+  DEBUG:   the items:
+  DEBUG:     `K1' -> `V1'
+Check that the binary search list is cleaned up properly: just the first
+storage entries are left
+  $ check_no_alist_artifacts
+  _farr_KV_[a-f0-9]+_B=1 (re)
+  _farr_KV_[a-f0-9]+_C=1 (re)
+  _farr_KV_[a-f0-9]+_P='1;1' (re)
+  _farr_KV_[a-f0-9]+__=1 (re)
+  _farr_Kb_[a-f0-9]+_1='1;V@K1' (re)
+  _farr_Ks_[a-f0-9]+_1='0;0@K1' (re)
+  _farr_Vs_[a-f0-9]+_1=V1 (re)
+  [1]
+Can re-add K2 now again
+  $ falist_add LIST K2 'V2 2'
+  $ falist_release LIST
+  $ check_no_alist_artifacts
+
+Try this with reversed insertion order also
+
+  $ falist_create LIST K3 V3 K2 V2 K1 V1
+  $ falist_find _var LIST K3
+Cookie has structure <storage-ptr>/<storage-prev-ptr>;<storage-next-ptr>@<object-token>
+  $ echo "$_var"
+  1/[0-9]+;[0-9]+@[a-f0-9]+ (re)
+  $ falist_contains LIST K3
+  $ falist_find _var LIST K2
+  $ echo "$_var"
+  2/[0-9]+;[0-9]+@[a-f0-9]+ (re)
+  $ falist_contains LIST K2
+  $ falist_find _var LIST K1
+  $ echo "$_var"
+  3/[0-9]+;[0-9]+@[a-f0-9]+ (re)
+  $ falist_contains LIST K1
+  $ (falist_trydel LIST foo)
+  [1]
+  $ falist_trydel LIST K2
+Skipping tombstones
+  $ (falist_trydel LIST K2)
+  [1]
+  $ falist_trydel LIST K3
+  $ (falist_trydel LIST K3)
+  [1]
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 1
+  DEBUG:   the items:
+  DEBUG:     `K1' -> `V1'
+Check that the binary search list is cleaned up properly: just the first
+storage entries are left
+  $ check_no_alist_artifacts
+  _farr_KV_[a-f0-9]+_B=1 (re)
+  _farr_KV_[a-f0-9]+_C=1 (re)
+  _farr_KV_[a-f0-9]+_P='3;3' (re)
+  _farr_KV_[a-f0-9]+__=1 (re)
+  _farr_Kb_[a-f0-9]+_1='3;V@K1' (re)
+  _farr_Ks_[a-f0-9]+_3='0;0@K1' (re)
+  _farr_Vs_[a-f0-9]+_3=V1 (re)
+  [1]
+Can re-add K2 now again
+  $ falist_add LIST K2 'V2 2'
+  $ falist_find _var LIST K2
+  $ falist_contains LIST K2
+But K3 is tombstoned/deleted
+  $ (falist_find _var LIST K3)
+  [1]
+  $ (falist_contains LIST K3)
+  [1]
+  $ farray_create ARRAY
+  $ falist_keys ARRAY LIST
+  $ farray_debug ARRAY
+  DEBUG: array `ARRAY' has length 2
+  DEBUG:   the items:
+  DEBUG:     1: `K1'
+  DEBUG:     2: `K2'
+  $ farray_release ARRAY
+  $ farray_create ARRAY
+  $ falist_values ARRAY LIST
+  $ farray_debug ARRAY
+  DEBUG: array `ARRAY' has length 2
+  DEBUG:   the items:
+  DEBUG:     1: `V1'
+  DEBUG:     2: `V2 2'
+  $ farray_release ARRAY
+  $ farray_create ARRAY
+  $ falist_items ARRAY LIST
+  $ farray_debug ARRAY
+  DEBUG: array `ARRAY' has length 4
+  DEBUG:   the items:
+  DEBUG:     1: `K1'
+  DEBUG:     2: `V1'
+  DEBUG:     3: `K2'
+  DEBUG:     4: `V2 2'
+  $ farray_release ARRAY
+  $ falist_release LIST
+  $ check_no_alist_artifacts
+  $ check_no_array_artifacts
+
+
 Get / Set / Contains / Find Index
 =================================
 
@@ -108,11 +635,12 @@
   3 (no-eol)
 
   $ falist_contains LIST K1
-  $ falist_find idx LIST K1
-  $ test "$idx" -eq 1
+  $ falist_find cookie LIST K1
+  $ echo "$cookie"
+  1/[0-9]+;[0-9]+@[a-f0-9]+ (re)
   $ falist_contains LIST K
   [1]
-  $ falist_find idx LIST K
+  $ falist_find cookie LIST K
   [1]
   $ falist_get _var LIST K2
   $ echo "$_var"
@@ -123,17 +651,17 @@
   $ falist_tryget _i LIST K
   [1]
 
-  $ falist_get _var LIST K2 _idx
+  $ falist_get _var LIST K2 _cookie
   $ echo "$_var"
   V2 2
-  $ echo "$_idx"
-  2
-  $ falist_tryget _var LIST K1 _idx
+  $ echo "$_cookie"
+  2/[0-9]+;[0-9]+@[a-f0-9]+ (re)
+  $ falist_tryget _var LIST K1 _cookie
   $ echo "$_var"
   V1
-  $ echo "$_idx"
-  1
-  $ falist_tryget _i LIST K _idx
+  $ echo "$_cookie"
+  1/[0-9]+;[0-9]+@[a-f0-9]+ (re)
+  $ falist_tryget _i LIST K _cookie
   [1]
   $ _var="$(falist_print_length NON_EXISTING_LIST)"
   ERROR: object `NON_EXISTING_LIST' not created properly: token empty
@@ -150,160 +678,39 @@
   $ falist_release LIST
   $ check_no_alist_artifacts
 
-Special case empty list (because of start/stop extra indexes)
 
-  $ falist_create LIST
-  $ falist_find _var LIST foo
-  [1]
-  $ falist_release LIST
-  $ check_no_alist_artifacts
-
-
-Add
-===
-
-  $ falist_create LIST
-  $ falist_add LIST K1 'V 1'
-  $ falist_add LIST K2 'V 2'
-  $ falist_add LIST K3 $'" 111222333" \\\'444555666 '    # '
-  $ falist_debug LIST
-  DEBUG: alist `LIST' has length 3
-  DEBUG:   the items:
-  DEBUG:     `K1' -> `V 1'
-  DEBUG:     `K2' -> `V 2'
-  DEBUG:     `K3' -> `" 111222333" \'444555666 '
-Yes: make a duplicate key
-  $ falist_add LIST K3 $'" 111222333" \\\'444555666 '    #
-  $ falist_debug LIST
-  DEBUG: alist `LIST' has length 4
-  DEBUG:   the items:
-  DEBUG:     `K1' -> `V 1'
-  DEBUG:     `K2' -> `V 2'
-  DEBUG:     `K3' -> `" 111222333" \'444555666 '
-  DEBUG:     `K3' -> `" 111222333" \'444555666 '
-  $ falist_release LIST
-  $ check_no_alist_artifacts
-
-
-Iteration
-=========
-
-ITERATE (manual indexing)
-
-  $ falist_create LIST
-  $ falist_set LIST K1 V1
-  $ falist_set LIST K2 "V2 2"
-  $ falist_set LIST K3 $'" 111222333" \\\'444555 '    # '
-
-Iteration by indexing key and values separately
-
-  $ _i=1
-  > while falist_tryget_key_at_index _k LIST ${_i}; do
-  >     # cannot fail under "normal" circumstances
-  >     falist_tryget_value_at_index _v LIST ${_i}
-  >     printf "  KEY: \`%s', VAL: \`%s'\\n" "${_k}" "${_v}"
-  >     _i=$((_i + 1))
-  > done
-    KEY: `K1', VAL: `V1'
-    KEY: `K2', VAL: `V2 2'
-    KEY: `K3', VAL: `" 111222333" \'444555 '
-
-ITERATE (manual indexing over items)
+Items / Keys / Values
+=====================
 
-  $ _i=1
-  > while falist_tryget_item_at_index _k _v LIST ${_i}; do
-  >     printf "  KEY: \`%s', VAL: \`%s'\\n" "${_k}" "${_v}"
-  >     _i=$((_i + 1))
-  > done
-    KEY: `K1', VAL: `V1'
-    KEY: `K2', VAL: `V2 2'
-    KEY: `K3', VAL: `" 111222333" \'444555 '
-
-ITERATE (for each, by name)
-
-  $ falist_for_each LIST $'printf "EACH: %s key \\`%s\\\', value \\`%s\\\' at idx %d\\n"'   # `
-  EACH: LIST key `K1', value `V1' at idx 1
-  EACH: LIST key `K2', value `V2 2' at idx 2
-  EACH: LIST key `K3', value `" 111222333" \'444555 ' at idx 3
-
-ITERATE (for each, by value)
-
-  $ falist_for_each "$LIST" $'printf "EACH: %s key \\`%s\\\', value \\`%s\\\' at idx %d\\n"'   # `
-  EACH: _farr_KV\[\?,\?\]:[a-f0-9]+ key `K1', value `V1' at idx 1 (re)
-  EACH: _farr_KV\[\?,\?\]:[a-f0-9]+ key `K2', value `V2 2' at idx 2 (re)
-  EACH: _farr_KV\[\?,\?\]:[a-f0-9]+ key `K3', value `" 111222333" \\'444555 ' at idx 3 (re)
-
-  $ falist_clear LIST
-  $ falist_release LIST
-  $ falist_release LIST
-  ERROR: object `LIST' not created properly: token empty
-  [1]
-
-  $ check_no_alist_artifacts
-
-
-Valid and Invalid Indices
-
-  $ falist_create LIST
-  $ falist_set LIST 'KEY 1' 'VAL 1'
-  $ falist_set LIST 'KEY 2' 'VAL 2'
-  $ falist_set LIST 'KEY 3' 'VAL 3'
-
-  $ (falist_tryget_item_at_index _k _v LIST "")
-  ERROR: missing index
-  [70]
-
-  $ (falist_tryget_item_at_index _k _v LIST)
-  ERROR: missing index
-  [70]
-
-  $ falist_tryget_item_at_index _k _v LIST 4
-  [1]
-
-  $ falist_tryget_item_at_index _k _v LIST 0
-  $ printf '%s:%s' "$_k" "$_v"
-  KEY 3:VAL 3 (no-eol)
-
-  $ falist_tryget_item_at_index _k _v LIST -2
-  $ printf '%s:%s' "$_k" "$_v"
-  KEY 1:VAL 1 (no-eol)
-
-  $ falist_tryget_item_at_index _k _v LIST -3
-  [1]
+  $ farray_create KEYS
+  $ farray_create VALUES
+  $ farray_create ITEMS
+  $ falist_create LIST "Key 1" "Value 1" "Key 2" 'Value 2 '\'''
+  $ falist_items ITEMS LIST
+  $ farray_debug ITEMS
+  DEBUG: array `ITEMS' has length 4
+  DEBUG:   the items:
+  DEBUG:     1: `Key 1'
+  DEBUG:     2: `Value 1'
+  DEBUG:     3: `Key 2'
+  DEBUG:     4: `Value 2 ''
+  $ falist_keys KEYS LIST
+  $ farray_debug KEYS
+  DEBUG: array `KEYS' has length 2
+  DEBUG:   the items:
+  DEBUG:     1: `Key 1'
+  DEBUG:     2: `Key 2'
+  $ falist_values VALUES LIST
+  $ farray_debug VALUES
+  DEBUG: array `VALUES' has length 2
+  DEBUG:   the items:
+  DEBUG:     1: `Value 1'
+  DEBUG:     2: `Value 2 ''
 
   $ falist_release LIST
-  $ check_no_alist_artifacts
-
-
-Deletion of keys
-================
-
-  $ falist_create LIST
-  $ falist_set LIST 'key 1' 'value 1'
-  $ falist_set LIST 'key 2' 'value 2'
-  $ falist_set LIST 'key 3' 'value 3'
-  $ falist_set LIST 'key 4' 'value 4'
-  $ falist_set LIST 'key 5' 'value 5'
-  $ falist_trydel LIST 'key 1'
-  $ falist_trydel LIST 'key 5'
-  $ falist_trydel LIST 'key 3'
-  $ falist_debug LIST
-  DEBUG: alist `LIST' has length 2
-  DEBUG:   the items:
-  DEBUG:     `key 2' -> `value 2'
-  DEBUG:     `key 4' -> `value 4'
-  $ falist_trydel LIST "non-existing key"
-  [1]
-  $ falist_print_length LIST
-  2 (no-eol)
-  $ falist_get _var LIST 'key 2'
-  $ printf '%s' "$_var"
-  value 2 (no-eol)
-  $ falist_get _var LIST 'key 4'
-  $ printf '%s' "$_var"
-  value 4 (no-eol)
-
-  $ falist_release LIST
+  $ farray_release KEYS
+  $ farray_release VALUES
+  $ farray_release ITEMS
 
   $ check_no_alist_artifacts
 
@@ -364,191 +771,123 @@
 Updating
 ========
 
-  $ falist_create ARR "Key 1" "Value 1" "Key 2" 'Value 2 '\'''
-  $ falist_create UPDATE1 "Key 1" "Value 1" "Key 2" 'Value 2 '\'''
-  $ falist_create UPDATE2 "Key 2" 'Value 2 (Updated) '\''' "Key 3" "Value 3"
-  $ falist_create EMPTY
-
-  $ falist_are_equal_with_order ARR UPDATE1
-  $ falist_are_equal_with_order ARR UPDATE2
-  [1]
+Just replace existing items
 
-  $ falist_update ARR UPDATE1
-  $ falist_are_equal_with_order ARR UPDATE1
-
-  $ falist_update ARR UPDATE2
-  $ falist_debug ARR
-  DEBUG: alist `ARR' has length 3
+  $ falist_create LIST k2 v2 k4 v4 k6 v6 k8 v8
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 4
   DEBUG:   the items:
-  DEBUG:     `Key 1' -> `Value 1'
-  DEBUG:     `Key 2' -> `Value 2 (Updated) ''
-  DEBUG:     `Key 3' -> `Value 3'
+  DEBUG:     `k2' -> `v2'
+  DEBUG:     `k4' -> `v4'
+  DEBUG:     `k6' -> `v6'
+  DEBUG:     `k8' -> `v8'
 
-Updating an into an empty alist is just a copy
-
-  $ falist_update EMPTY UPDATE1
-  $ falist_debug EMPTY
-  DEBUG: alist `EMPTY' has length 2
+  $ falist_create UPDATE1 k2 v2-2 k4 v4-2 k8 v8-2
+  $ falist_update LIST UPDATE1
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 4
   DEBUG:   the items:
-  DEBUG:     `Key 1' -> `Value 1'
-  DEBUG:     `Key 2' -> `Value 2 ''
-  $ falist_debug UPDATE1
-  DEBUG: alist `UPDATE1' has length 2
-  DEBUG:   the items:
-  DEBUG:     `Key 1' -> `Value 1'
-  DEBUG:     `Key 2' -> `Value 2 ''
+  DEBUG:     `k2' -> `v2-2'
+  DEBUG:     `k4' -> `v4-2'
+  DEBUG:     `k6' -> `v6'
+  DEBUG:     `k8' -> `v8-2'
 
-  $ falist_release ARR
+  $ falist_release LIST
   $ falist_release UPDATE1
-  $ falist_release UPDATE2
-  $ falist_release EMPTY
-
   $ check_no_alist_artifacts
 
 
-Merging
-=======
-
-  $ falist_create RES
-  $ falist_create INPUT1 "K1" "V1" "K2" "V2" "K3" "V3"
-  $ falist_create INPUT2
-  $ falist_merge "$RES" "$INPUT1" "$INPUT2"
-  $ falist_release INPUT1
-  $ falist_release INPUT2
-  $ falist_debug RES
-  DEBUG: alist `RES' has length 3
-  DEBUG:   the items:
-  DEBUG:     `K1' -> `V1'
-  DEBUG:     `K2' -> `V2'
-  DEBUG:     `K3' -> `V3'
-  $ falist_release RES
-  $ check_no_alist_artifacts
+Handle previously deleted items also
 
-  $ falist_create RES
-  $ falist_create INPUT1
-  $ falist_create INPUT2 "k1" "v1" "k2" "v2" "k3" "v3"
-  $ falist_merge "$RES" "$INPUT1" "$INPUT2"
-  $ falist_release INPUT1
-  $ falist_release INPUT2
-  $ falist_debug RES
-  DEBUG: alist `RES' has length 3
+  $ falist_create LIST k2 v2 k4 v4 k6 v6 k8 v8
+  $ falist_trydel LIST k2
+  $ falist_create UPDATE1 k2 v2-2 k4 v4-2 k8 v8-2
+  $ falist_update LIST UPDATE1
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 4
   DEBUG:   the items:
-  DEBUG:     `k1' -> `v1'
-  DEBUG:     `k2' -> `v2'
-  DEBUG:     `k3' -> `v3'
-  $ falist_release RES
-  $ check_no_alist_artifacts
+  DEBUG:     `k4' -> `v4-2'
+  DEBUG:     `k6' -> `v6'
+  DEBUG:     `k8' -> `v8-2'
+  DEBUG:     `k2' -> `v2-2'
 
-  $ falist_create RES
-  $ falist_create INPUT1 "K1" "V1" "K2" "V2" "K3" "V3"
-  $ falist_create INPUT2 "k1" "v1" "k2" "v2" "k3" "v3" "k4" "v4"
-  $ falist_merge "$RES" "$INPUT1" "$INPUT2"
-  $ falist_release INPUT1
-  $ falist_release INPUT2
-  $ falist_debug RES
-  DEBUG: alist `RES' has length 7
-  DEBUG:   the items:
-  DEBUG:     `K1' -> `V1'
-  DEBUG:     `K2' -> `V2'
-  DEBUG:     `K3' -> `V3'
-  DEBUG:     `k1' -> `v1'
-  DEBUG:     `k2' -> `v2'
-  DEBUG:     `k3' -> `v3'
-  DEBUG:     `k4' -> `v4'
-  $ falist_release RES
+  $ falist_release LIST
+  $ falist_release UPDATE1
   $ check_no_alist_artifacts
 
-  $ falist_create RES
-  $ falist_create INPUT1 "k1" "v1" "k2" "v2" "k3" "v3" "k4" "v4"
-  $ falist_create INPUT2 "K1" "V1" "K2" "V2" "K3" "V3"
-  $ falist_merge "$RES" "$INPUT1" "$INPUT2"
-  $ falist_release INPUT1
-  $ falist_release INPUT2
-  $ falist_debug RES
-  DEBUG: alist `RES' has length 7
-  DEBUG:   the items:
-  DEBUG:     `K1' -> `V1'
-  DEBUG:     `K2' -> `V2'
-  DEBUG:     `K3' -> `V3'
-  DEBUG:     `k1' -> `v1'
-  DEBUG:     `k2' -> `v2'
-  DEBUG:     `k3' -> `v3'
-  DEBUG:     `k4' -> `v4'
-  $ falist_release RES
-  $ check_no_alist_artifacts
-
-  $ falist_create RES
-  $ falist_create INPUT1 "K1" "V1" "K3" "V3" "k1" "v1" "k4" "v4"
-  $ falist_create INPUT2 "K2" "V2" "k2" "v2" "k3" "v3"
-  $ falist_merge "$RES" "$INPUT1" "$INPUT2"
-  $ falist_release INPUT1
-  $ falist_release INPUT2
-  $ falist_debug RES
-  DEBUG: alist `RES' has length 7
+  $ falist_create LIST k2 v2 k4 v4 k6 v6 k8 v8
+  $ falist_trydel LIST k4
+  $ falist_create UPDATE1 k2 v2-2 k4 v4-2 k8 v8-2
+  $ falist_update LIST UPDATE1
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 4
   DEBUG:   the items:
-  DEBUG:     `K1' -> `V1'
-  DEBUG:     `K2' -> `V2'
-  DEBUG:     `K3' -> `V3'
-  DEBUG:     `k1' -> `v1'
-  DEBUG:     `k2' -> `v2'
-  DEBUG:     `k3' -> `v3'
-  DEBUG:     `k4' -> `v4'
-  $ falist_release RES
-  $ check_no_alist_artifacts
+  DEBUG:     `k2' -> `v2-2'
+  DEBUG:     `k6' -> `v6'
+  DEBUG:     `k8' -> `v8-2'
+  DEBUG:     `k4' -> `v4-2'
 
-  $ falist_create RES
-  $ falist_create INPUT1 "K1" "V1" "K3" "V3" "k1" "v1" "k4" "v4"
-  $ falist_create INPUT2 "K2" "V2" "k2" "v2" "k3" "v3"
-  $ falist_merge "$RES" INPUT2 INPUT1
-  $ falist_release INPUT1
-  $ falist_release INPUT2
-  $ falist_debug RES
-  DEBUG: alist `RES' has length 7
-  DEBUG:   the items:
-  DEBUG:     `K1' -> `V1'
-  DEBUG:     `K2' -> `V2'
-  DEBUG:     `K3' -> `V3'
-  DEBUG:     `k1' -> `v1'
-  DEBUG:     `k2' -> `v2'
-  DEBUG:     `k3' -> `v3'
-  DEBUG:     `k4' -> `v4'
-  $ falist_release RES
+  $ falist_release LIST
+  $ falist_release UPDATE1
   $ check_no_alist_artifacts
 
 
-Items / Keys / Values
-=====================
+Just appending
 
-  $ farray_create KEYS
-  $ farray_create VALUES
-  $ farray_create ITEMS
-  $ falist_create LIST "Key 1" "Value 1" "Key 2" 'Value 2 '\'''
-  $ falist_items ITEMS LIST
-  $ farray_debug ITEMS
-  DEBUG: array `ITEMS' has length 4
+  $ falist_create LIST k2 v2 k4 v4 k6 v6 k8 v8
+  $ falist_create UPDATE1 k9 v9 k91 v91
+  $ falist_update LIST UPDATE1
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 6
   DEBUG:   the items:
-  DEBUG:     1: `Key 1'
-  DEBUG:     2: `Value 1'
-  DEBUG:     3: `Key 2'
-  DEBUG:     4: `Value 2 ''
-  $ falist_keys KEYS LIST
-  $ farray_debug KEYS
-  DEBUG: array `KEYS' has length 2
-  DEBUG:   the items:
-  DEBUG:     1: `Key 1'
-  DEBUG:     2: `Key 2'
-  $ falist_values VALUES LIST
-  $ farray_debug VALUES
-  DEBUG: array `VALUES' has length 2
-  DEBUG:   the items:
-  DEBUG:     1: `Value 1'
-  DEBUG:     2: `Value 2 ''
+  DEBUG:     `k2' -> `v2'
+  DEBUG:     `k4' -> `v4'
+  DEBUG:     `k6' -> `v6'
+  DEBUG:     `k8' -> `v8'
+  DEBUG:     `k9' -> `v9'
+  DEBUG:     `k91' -> `v91'
 
   $ falist_release LIST
-  $ farray_release KEYS
-  $ farray_release VALUES
-  $ farray_release ITEMS
+  $ falist_release UPDATE1
+  $ check_no_alist_artifacts
+
+
+Append after deletion
+
+  $ falist_create LIST k2 v2 k4 v4 k6 v6 k8 v8
+  $ falist_trydel LIST k8
+  $ falist_create UPDATE1 k2 v2-2 k4 v4-2 k8 v8-2
+  $ falist_update LIST UPDATE1
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 4
+  DEBUG:   the items:
+  DEBUG:     `k2' -> `v2-2'
+  DEBUG:     `k4' -> `v4-2'
+  DEBUG:     `k6' -> `v6'
+  DEBUG:     `k8' -> `v8-2'
 
+  $ falist_release LIST
+  $ falist_release UPDATE1
+  $ check_no_alist_artifacts
+
+Insertions
+
+  $ falist_create LIST k2 v2 k4 v4 k6 v6 k8 v8
+  $ falist_create UPDATE1 k1 v1 k3 v3 k7 v7
+  $ falist_update LIST UPDATE1
+  $ falist_debug LIST
+  DEBUG: alist `LIST' has length 7
+  DEBUG:   the items:
+  DEBUG:     `k2' -> `v2'
+  DEBUG:     `k4' -> `v4'
+  DEBUG:     `k6' -> `v6'
+  DEBUG:     `k8' -> `v8'
+  DEBUG:     `k1' -> `v1'
+  DEBUG:     `k3' -> `v3'
+  DEBUG:     `k7' -> `v7'
+
+  $ falist_release LIST
+  $ falist_release UPDATE1
   $ check_no_alist_artifacts