wingo pushed a commit to branch wip-whippet
in repository guile.

commit 12e8772403eae319070569375908a8312cb373d1
Author: Andy Wingo <wi...@pobox.com>
AuthorDate: Tue Jun 3 13:17:35 2025 +0200

    Move array-map / array-cell functions to Scheme module
    
    * libguile/array-map.c:
    * libguile/array-map.h: Remove.
    
    * module/ice-9/deprecated.scm:
    * libguile/deprecated.h:
    * libguile/deprecated.c: Add deprecation shims.
    
    * module/ice-9/arrays.scm: Move all array-map functionality here.
    
    * libguile/Makefile.am:
    * libguile/init.c:
    * libguile.h: Remove array-map.h use.
    
    * libguile/arrays.c (scm_i_array_equal_p, scm_i_array_copy): New
    helpers.
    (scm_array_cell_ref, scm_array_cell_set_x): Move to Scheme.
    * libguile/arrays.h:
    * libguile/eq.c (scm_equal_p):
    * libguile/sort.c (scm_sort): Use new arrays.c helpers.
    * module/ice-9/pretty-print.scm:
    * module/oop/goops/save.scm: Import (ice-9 arrays).
---
 libguile.h                      |   1 -
 libguile/Makefile.am            |   4 -
 libguile/array-map.c            | 921 ----------------------------------------
 libguile/array-map.h            |  44 --
 libguile/arrays.c               | 137 ++----
 libguile/arrays.h               |   8 +-
 libguile/deprecated.c           | 110 +++++
 libguile/deprecated.h           |  11 +
 libguile/eq.c                   |   6 +-
 libguile/init.c                 |   2 -
 libguile/sort.c                 |   8 +-
 module/ice-9/arrays.scm         | 620 ++++++++++++++++++++++++++-
 module/ice-9/deprecated.scm     |  78 +++-
 module/ice-9/pretty-print.scm   |   3 +-
 module/oop/goops/save.scm       |   1 +
 test-suite/tests/array-map.test |   5 +-
 test-suite/tests/arrays.test    |   5 +-
 17 files changed, 867 insertions(+), 1097 deletions(-)

diff --git a/libguile.h b/libguile.h
index b5594a4d8..2b17052c2 100644
--- a/libguile.h
+++ b/libguile.h
@@ -30,7 +30,6 @@ extern "C" {
 
 #include "libguile/alist.h"
 #include "libguile/array-handle.h"
-#include "libguile/array-map.h"
 #include "libguile/arrays.h"
 #include "libguile/async.h"
 #include "libguile/atomic.h"
diff --git a/libguile/Makefile.am b/libguile/Makefile.am
index ef1dc6970..5b3cb0740 100644
--- a/libguile/Makefile.am
+++ b/libguile/Makefile.am
@@ -134,7 +134,6 @@ libguile_@GUILE_EFFECTIVE_VERSION@_la_CFLAGS = 
$(GUILE_CFLAGS) $(AM_CFLAGS)
 libguile_@GUILE_EFFECTIVE_VERSION@_la_SOURCES =                                
\
        alist.c                                 \
        array-handle.c                          \
-       array-map.c                             \
        arrays.c                                \
        async.c                                 \
        atomic.c                                \
@@ -250,7 +249,6 @@ endif
 DOT_X_FILES =                                  \
        alist.x                                 \
        array-handle.x                          \
-       array-map.x                             \
        arrays.x                                \
        async.x                                 \
        atomic.x                                \
@@ -352,7 +350,6 @@ EXTRA_DOT_X_FILES = @EXTRA_DOT_X_FILES@
 DOT_DOC_FILES =                                \
        alist.doc                               \
        array-handle.doc                        \
-       array-map.doc                           \
        arrays.doc                              \
        async.doc                               \
        atomic.doc                              \
@@ -592,7 +589,6 @@ modinclude_HEADERS =                                \
        __scm.h                                 \
        alist.h                                 \
        array-handle.h                          \
-       array-map.h                             \
        arrays.h                                \
        async.h                                 \
        atomic.h                                \
diff --git a/libguile/array-map.c b/libguile/array-map.c
deleted file mode 100644
index ce0f7ba09..000000000
--- a/libguile/array-map.c
+++ /dev/null
@@ -1,921 +0,0 @@
-/* Copyright 1996,1998,2000-2001,2004-2006,2008-2015,2018-2019
-     Free Software Foundation, Inc.
-
-   This file is part of Guile.
-
-   Guile is free software: you can redistribute it and/or modify it
-   under the terms of the GNU Lesser General Public License as published
-   by the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   Guile is distributed in the hope that it will be useful, but WITHOUT
-   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-   License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with Guile.  If not, see
-   <https://www.gnu.org/licenses/>.  */
-
-
-
-
-
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <assert.h>
-#include <string.h>
-
-#include "arrays.h"
-#include "bitvectors.h"
-#include "boolean.h"
-#include "chars.h"
-#include "eq.h"
-#include "eval.h"
-#include "feature.h"
-#include "gsubr.h"
-#include "list.h"
-#include "numbers.h"
-#include "pairs.h"
-#include "procs.h"
-#include "smob.h"
-#include "srfi-4.h"
-#include "strings.h"
-#include "symbols.h"
-#include "vectors.h"
-
-#include "array-map.h"
-
-
-/* The WHAT argument for `scm_gc_malloc ()' et al.  */
-static const char vi_gc_hint[] = "array-indices";
-
-static SCM
-make1array (SCM v, ssize_t inc)
-{
-  SCM a = scm_i_make_array (1);
-  SCM_I_ARRAY_SET_BASE (a, 0);
-  SCM_I_ARRAY_DIMS (a)->lbnd = 0;
-  SCM_I_ARRAY_DIMS (a)->ubnd = scm_c_array_length (v) - 1;
-  SCM_I_ARRAY_DIMS (a)->inc = inc;
-  SCM_I_ARRAY_SET_V (a, v);
-  return a;
-}
-
-/* Linear index of not-unrolled index set. */
-static size_t
-cindk (SCM ra, ssize_t *ve, int kend)
-{
-  if (SCM_I_ARRAYP (ra))
-    {
-      int k;
-      size_t i = SCM_I_ARRAY_BASE (ra);
-      for (k = 0; k < kend; ++k)
-        i += (ve[k] - SCM_I_ARRAY_DIMS (ra)[k].lbnd) * SCM_I_ARRAY_DIMS 
(ra)[k].inc;
-      return i;
-    }
-  else
-    return 0; /* this is BASE */
-}
-
-/* array mapper: apply cproc to each dimension of the given arrays?.
-     int (*cproc) ();   procedure to call on unrolled arrays?
-                          cproc (dest, source list) or
-                          cproc (dest, data, source list).
-     SCM data;          data to give to cproc or unbound.
-     SCM ra0;           destination array.
-     SCM lra;           list of source arrays.
-     const char *what;  caller, for error reporting. */
-
-#define LBND(ra, k) SCM_I_ARRAY_DIMS (ra)[k].lbnd
-#define UBND(ra, k) SCM_I_ARRAY_DIMS (ra)[k].ubnd
-#define MAX(A, B) ((A) >= (B) ? (A) : (B))
-
-
-/* scm_ramapc() always calls cproc with rank-1 arrays created by
-   make1array. cproc (rafe, ramap, rafill, racp) can assume that the
-   dims[0].lbnd of these arrays is always 0. */
-int
-scm_ramapc (void *cproc_ptr, SCM data, SCM ra0, SCM lra, const char *what)
-{
-  int (*cproc) () = cproc_ptr;
-  SCM z, va0, lva, *plva;
-  int k, kmax, kroll;
-  ssize_t *vi, inc;
-  size_t len;
-
-  /* Prepare reference argument. */
-  if (SCM_I_ARRAYP (ra0))
-    {
-      kmax = SCM_I_ARRAY_NDIM (ra0)-1;
-      inc = kmax < 0 ?  0 : SCM_I_ARRAY_DIMS (ra0)[kmax].inc;
-      va0 = make1array (SCM_I_ARRAY_V (ra0), inc);
-
-      /* Find unroll depth */
-      for (kroll = MAX (0, kmax); kroll > 0; --kroll)
-        {
-          inc *= (UBND (ra0, kroll) - LBND (ra0, kroll) + 1);
-          if (inc != SCM_I_ARRAY_DIMS (ra0)[kroll-1].inc)
-            break;
-        }
-    }
-  else
-    {
-      kroll = kmax = 0;
-      va0 = ra0 = make1array (ra0, 1);
-    }
-
-  /* Prepare rest arguments. */
-  lva = SCM_EOL;
-  plva = &lva;
-  for (z = lra; !scm_is_null (z); z = SCM_CDR (z))
-    {
-      SCM va1, ra1 = SCM_CAR (z);
-      if (SCM_I_ARRAYP (ra1))
-        {
-          if (kmax != SCM_I_ARRAY_NDIM (ra1) - 1)
-            scm_misc_error (what, "array shape mismatch: ~S", scm_list_1 
(ra0));
-          inc = kmax < 0 ? 0 : SCM_I_ARRAY_DIMS (ra1)[kmax].inc;
-          va1 = make1array (SCM_I_ARRAY_V (ra1), inc);
-
-          /* Check unroll depth. */
-          for (k = kmax; k > kroll; --k)
-            {
-              ssize_t l0 = LBND (ra0, k), u0 = UBND (ra0, k);
-              if (l0 < LBND (ra1, k) || u0 > UBND (ra1, k))
-                scm_misc_error (what, "array shape mismatch: ~S", scm_list_1 
(ra0));
-              inc *= (u0 - l0 + 1);
-              if (inc != SCM_I_ARRAY_DIMS (ra1)[k-1].inc)
-                {
-                  kroll = k;
-                  break;
-                }
-            }
-
-          /* Check matching of not-unrolled axes. */
-          for (; k>=0; --k)
-            if (LBND (ra0, k) < LBND (ra1, k) || UBND (ra0, k) > UBND (ra1, k))
-              scm_misc_error (what, "array shape mismatch: ~S", scm_list_1 
(ra0));
-        }
-      else
-        {
-          if (kmax != 0)
-            scm_misc_error (what, "array shape mismatch: ~S", scm_list_1 
(ra0));
-          va1 = make1array (ra1, 1);
-
-          if (LBND (ra0, 0) < 0 /* LBND (va1, 0) */ || UBND (ra0, 0) > UBND 
(va1, 0))
-            scm_misc_error (what, "array shape mismatch: ~S", scm_list_1 
(ra0));
-        }
-      *plva = scm_cons (va1, SCM_EOL);
-      plva = SCM_CDRLOC (*plva);
-    }
-
-  /* Check emptiness of not-unrolled axes. */
-  for (k = 0; k < kroll; ++k)
-    if (0 == (UBND (ra0, k) - LBND (ra0, k) + 1))
-      return 1;
-
-  /* Set unrolled size. */
-  for (len = 1; k <= kmax; ++k)
-    len *= (UBND (ra0, k) - LBND (ra0, k) + 1);
-  UBND (va0, 0) = len - 1;
-  for (z = lva; !scm_is_null (z); z = SCM_CDR (z))
-    UBND (SCM_CAR (z), 0) = len - 1;
-
-  /* Set starting indices and go. */
-  vi = scm_gc_malloc_pointerless (sizeof(ssize_t) * kroll, vi_gc_hint);
-  for (k = 0; k < kroll; ++k)
-    vi[k] = LBND (ra0, k);
-  do
-    {
-      if (k == kroll)
-        {
-          SCM y = lra;
-          SCM_I_ARRAY_SET_BASE (va0, cindk (ra0, vi, kroll));
-          for (z = lva; !scm_is_null (z); z = SCM_CDR (z), y = SCM_CDR (y))
-            SCM_I_ARRAY_SET_BASE (SCM_CAR (z), cindk (SCM_CAR (y), vi, kroll));
-          if (! (SCM_UNBNDP (data) ? cproc (va0, lva) : cproc (va0, data, 
lva)))
-            return 0;
-          --k;
-        }
-      else if (vi[k] < UBND (ra0, k))
-        {
-          ++vi[k];
-          ++k;
-        }
-      else
-        {
-          vi[k] = LBND (ra0, k) - 1;
-          --k;
-        }
-    }
-  while (k >= 0);
-
-  return 1;
-}
-
-#undef UBND
-#undef LBND
-
-static int
-rafill (SCM dst, SCM fill)
-{
-  size_t n = SCM_I_ARRAY_DIMS (dst)->ubnd + 1;
-  size_t i = SCM_I_ARRAY_BASE (dst);
-  ssize_t inc = SCM_I_ARRAY_DIMS (dst)->inc;
-  scm_t_array_handle h;
-  dst = SCM_I_ARRAY_V (dst);
-  scm_array_get_handle (dst, &h);
-
-  for (; n-- > 0; i += inc)
-    h.vset (h.vector, i, fill);
-
-  scm_array_handle_release (&h);
-  return 1;
-}
-
-SCM_DEFINE (scm_array_fill_x, "array-fill!", 2, 0, 0,
-           (SCM ra, SCM fill),
-           "Store @var{fill} in every element of array @var{ra}.  The value\n"
-           "returned is unspecified.")
-#define FUNC_NAME s_scm_array_fill_x
-{
-  scm_ramapc (rafill, fill, ra, SCM_EOL, FUNC_NAME);
-  return SCM_UNSPECIFIED;
-}
-#undef FUNC_NAME
-
-
-static int
-racp (SCM src, SCM dst)
-{
-  size_t i_s, i_d, n;
-  ssize_t inc_s, inc_d;
-  scm_t_array_handle h_s, h_d;
-  dst = SCM_CAR (dst);
-  i_s = SCM_I_ARRAY_BASE (src);
-  i_d = SCM_I_ARRAY_BASE (dst);
-  n = (SCM_I_ARRAY_DIMS (src)->ubnd + 1);
-  inc_s = SCM_I_ARRAY_DIMS (src)->inc;
-  inc_d = SCM_I_ARRAY_DIMS (dst)->inc;
-  src = SCM_I_ARRAY_V (src);
-  dst = SCM_I_ARRAY_V (dst);
-  scm_array_get_handle (src, &h_s);
-  scm_array_get_handle (dst, &h_d);
-
-  if (h_s.element_type == SCM_ARRAY_ELEMENT_TYPE_SCM
-      && h_d.element_type == SCM_ARRAY_ELEMENT_TYPE_SCM)
-    {
-      SCM const * el_s = h_s.elements;
-      SCM * el_d = h_d.writable_elements;
-      if (!el_d && n>0)
-        scm_wrong_type_arg_msg ("array-copy!", SCM_ARG2, dst, "mutable array");
-      for (; n-- > 0; i_s += inc_s, i_d += inc_d)
-        el_d[i_d] = el_s[i_s];
-    }
-  else
-    for (; n-- > 0; i_s += inc_s, i_d += inc_d)
-      h_d.vset (h_d.vector, i_d, h_s.vref (h_s.vector, i_s));
-
-  scm_array_handle_release (&h_d);
-  scm_array_handle_release (&h_s);
-
-  return 1;
-}
-
-SCM_REGISTER_PROC(s_array_copy_in_order_x, "array-copy-in-order!", 2, 0, 0, 
scm_array_copy_x);
-
-
-SCM_DEFINE (scm_array_copy_x, "array-copy!", 2, 0, 0,
-           (SCM src, SCM dst),
-           "@deffnx {Scheme Procedure} array-copy-in-order! src dst\n"
-           "Copy every element from vector or array @var{src} to the\n"
-           "corresponding element of @var{dst}.  @var{dst} must have the\n"
-           "same rank as @var{src}, and be at least as large in each\n"
-           "dimension.  The order is unspecified.")
-#define FUNC_NAME s_scm_array_copy_x
-{
-  scm_ramapc (racp, SCM_UNDEFINED, src, scm_cons (dst, SCM_EOL), FUNC_NAME);
-  return SCM_UNSPECIFIED;
-}
-#undef FUNC_NAME
-
-
-static int
-ramap (SCM ra0, SCM proc, SCM ras)
-{
-  size_t i0 = SCM_I_ARRAY_BASE (ra0);
-  ssize_t inc0 = SCM_I_ARRAY_DIMS (ra0)->inc;
-  size_t n = SCM_I_ARRAY_DIMS (ra0)->ubnd + 1;
-  scm_t_array_handle h0;
-  ra0 = SCM_I_ARRAY_V (ra0);
-  scm_array_get_handle (ra0, &h0);
-
-  if (scm_is_null (ras))
-    for (; n--; i0 += inc0)
-      h0.vset (h0.vector, i0, scm_call_0 (proc));
-  else
-    {
-      SCM ra1 = SCM_CAR (ras);
-      size_t i1 = SCM_I_ARRAY_BASE (ra1);
-      ssize_t inc1 = SCM_I_ARRAY_DIMS (ra1)->inc;
-      scm_t_array_handle h1;
-      ra1 = SCM_I_ARRAY_V (ra1);
-      scm_array_get_handle (ra1, &h1);
-      ras = SCM_CDR (ras);
-      if (scm_is_null (ras))
-        for (; n--; i0 += inc0, i1 += inc1)
-          h0.vset (h0.vector, i0, scm_call_1 (proc, h1.vref (h1.vector, i1)));
-      else
-        {
-          SCM ra2 = SCM_CAR (ras);
-          size_t i2 = SCM_I_ARRAY_BASE (ra2);
-          ssize_t inc2 = SCM_I_ARRAY_DIMS (ra2)->inc;
-          scm_t_array_handle h2;
-          ra2 = SCM_I_ARRAY_V (ra2);
-          scm_array_get_handle (ra2, &h2);
-          ras = SCM_CDR (ras);
-          if (scm_is_null (ras))
-            for (; n--; i0 += inc0, i1 += inc1, i2 += inc2)
-              h0.vset (h0.vector, i0, scm_call_2 (proc, h1.vref (h1.vector, 
i1), h2.vref (h2.vector, i2)));
-          else
-            {
-              scm_t_array_handle *hs;
-              size_t restn = scm_ilength (ras);
-              SCM args = SCM_EOL;
-              SCM *p = &args;
-              SCM **sa = scm_gc_malloc (sizeof(SCM *) * restn, vi_gc_hint);
-              size_t k;
-              ssize_t i;
-              
-              for (k = 0; k < restn; ++k)
-                {
-                  *p = scm_cons (SCM_UNSPECIFIED, SCM_EOL);
-                  sa[k] = SCM_CARLOC (*p);
-                  p = SCM_CDRLOC (*p);
-                }
-
-              hs = scm_gc_malloc (sizeof(scm_t_array_handle) * restn, 
vi_gc_hint);
-              for (k = 0; k < restn; ++k, ras = scm_cdr (ras))
-                scm_array_get_handle (scm_car (ras), hs+k);
-
-              for (i = 0; n--; i0 += inc0, i1 += inc1, i2 += inc2, ++i)
-                {
-                  for (k = 0; k < restn; ++k)
-                    *(sa[k]) = scm_array_handle_ref (hs+k, 
i*hs[k].dims[0].inc);
-                  h0.vset (h0.vector, i0, scm_apply_2 (proc, h1.vref 
(h1.vector, i1), h2.vref (h2.vector, i2), args));
-                }
-
-              for (k = 0; k < restn; ++k)
-                scm_array_handle_release (hs+k);
-            }
-          scm_array_handle_release (&h2);
-        }
-      scm_array_handle_release (&h1);
-    }
-  scm_array_handle_release (&h0);
-  return 1;
-}
-
-
-SCM_REGISTER_PROC(s_array_map_in_order_x, "array-map-in-order!", 2, 0, 1, 
scm_array_map_x);
-
-SCM_SYMBOL (sym_b, "b");
-
-SCM_DEFINE (scm_array_map_x, "array-map!", 2, 0, 1,
-           (SCM ra0, SCM proc, SCM lra),
-           "@deffnx {Scheme Procedure} array-map-in-order! ra0 proc . lra\n"
-           "@var{array1}, @dots{} must have the same number of dimensions\n"
-           "as @var{ra0} and have a range for each index which includes the\n"
-           "range for the corresponding index in @var{ra0}.  @var{proc} is\n"
-           "applied to each tuple of elements of @var{array1}, @dots{} and\n"
-           "the result is stored as the corresponding element in @var{ra0}.\n"
-           "The value returned is unspecified.  The order of application is\n"
-           "unspecified.")
-#define FUNC_NAME s_scm_array_map_x
-{
-  SCM_VALIDATE_PROC (2, proc);
-  SCM_VALIDATE_REST_ARGUMENT (lra);
-
-  scm_ramapc (ramap, proc, ra0, lra, FUNC_NAME);
-  return SCM_UNSPECIFIED;
-}
-#undef FUNC_NAME
-
-
-static int
-rafe (SCM ra0, SCM proc, SCM ras)
-{
-  size_t i0 = SCM_I_ARRAY_BASE (ra0);
-  ssize_t inc0 = SCM_I_ARRAY_DIMS (ra0)->inc;
-  size_t n = SCM_I_ARRAY_DIMS (ra0)->ubnd + 1;
-  scm_t_array_handle h0;
-  ra0 = SCM_I_ARRAY_V (ra0);
-  scm_array_get_handle (ra0, &h0);
-
-  if (scm_is_null (ras))
-    for (; n--; i0 += inc0)
-      scm_call_1 (proc, h0.vref (h0.vector, i0));
-  else
-    {
-      scm_t_array_handle *hs;      
-      size_t restn = scm_ilength (ras);
-
-      SCM args = SCM_EOL;
-      SCM *p = &args;
-      SCM **sa = scm_gc_malloc (sizeof(SCM *) * restn, vi_gc_hint);
-      for (size_t k = 0; k < restn; ++k)
-        {
-          *p = scm_cons (SCM_UNSPECIFIED, SCM_EOL);
-          sa[k] = SCM_CARLOC (*p);
-          p = SCM_CDRLOC (*p);
-        }
-
-      hs = scm_gc_malloc (sizeof(scm_t_array_handle) * restn, vi_gc_hint);
-      for (size_t k = 0; k < restn; ++k, ras = scm_cdr (ras))
-        scm_array_get_handle (scm_car (ras), hs+k);
-
-      for (ssize_t i = 0; n--; i0 += inc0, ++i)
-        {
-          for (size_t k = 0; k < restn; ++k)
-            *(sa[k]) = scm_array_handle_ref (hs+k, i*hs[k].dims[0].inc);
-          scm_apply_1 (proc, h0.vref (h0.vector, i0), args);
-        }
-
-      for (size_t k = 0; k < restn; ++k)
-        scm_array_handle_release (hs+k);
-    }
-  scm_array_handle_release (&h0);
-  return 1;
-}
-
-SCM_DEFINE (scm_array_for_each, "array-for-each", 2, 0, 1,
-           (SCM proc, SCM ra0, SCM lra),
-           "Apply @var{proc} to each tuple of elements of @var{ra0} @dots{}\n"
-           "in row-major order.  The value returned is unspecified.")
-#define FUNC_NAME s_scm_array_for_each
-{
-  SCM_VALIDATE_PROC (1, proc);
-  SCM_VALIDATE_REST_ARGUMENT (lra);
-  scm_ramapc (rafe, proc, ra0, lra, FUNC_NAME);
-  return SCM_UNSPECIFIED;
-}
-#undef FUNC_NAME
-
-static void
-array_index_map_1 (SCM ra, SCM proc)
-{
-  scm_t_array_handle h;
-  ssize_t i, inc;
-  size_t p;
-  scm_array_get_handle (ra, &h);
-  inc = h.dims[0].inc;
-  for (i = h.dims[0].lbnd, p = h.base; i <= h.dims[0].ubnd; ++i, p += inc)
-    h.vset (h.vector, p, scm_call_1 (proc, scm_from_ssize_t (i)));
-  scm_array_handle_release (&h);
-}
-
-/* Here we assume that the array is a scm_tc7_array, as that is the only
-   kind of array in Guile that supports rank > 1.  */
-static void
-array_index_map_n (SCM ra, SCM proc)
-{
-  scm_t_array_handle h;
-  int k, kmax = SCM_I_ARRAY_NDIM (ra) - 1;
-  SCM args = SCM_EOL;
-  SCM *p = &args;
-
-  ssize_t *vi = scm_gc_malloc_pointerless (sizeof(ssize_t) * (kmax + 1), 
vi_gc_hint);
-  SCM **si = scm_gc_malloc_pointerless (sizeof(SCM *) * (kmax + 1), 
vi_gc_hint);
-
-  for (k = 0; k <= kmax; k++)
-    {
-      vi[k] = SCM_I_ARRAY_DIMS (ra)[k].lbnd;
-      if (vi[k] > SCM_I_ARRAY_DIMS (ra)[k].ubnd)
-        return;
-      *p = scm_cons (scm_from_ssize_t (vi[k]), SCM_EOL);
-      si[k] = SCM_CARLOC (*p);
-      p = SCM_CDRLOC (*p);
-    }
-
-  scm_array_get_handle (ra, &h);
-  k = kmax;
-  do
-    {
-      if (k == kmax)
-        {
-          size_t i;
-          vi[kmax] = SCM_I_ARRAY_DIMS (ra)[kmax].lbnd;
-          i = cindk (ra, vi, kmax+1);
-          for (; vi[kmax] <= SCM_I_ARRAY_DIMS (ra)[kmax].ubnd; ++vi[kmax])
-            {
-              *(si[kmax]) = scm_from_ssize_t (vi[kmax]);
-              h.vset (h.vector, i, scm_apply_0 (proc, args));
-              i += SCM_I_ARRAY_DIMS (ra)[kmax].inc;
-            }
-          k--;
-        }
-      else if (vi[k] < SCM_I_ARRAY_DIMS (ra)[k].ubnd)
-        {
-          *(si[k]) = scm_from_ssize_t (++vi[k]);
-          k++;
-        }
-      else
-        {
-          vi[k] = SCM_I_ARRAY_DIMS (ra)[k].lbnd - 1;
-          k--;
-        }
-    }
-  while (k >= 0);
-  scm_array_handle_release (&h);
-}
-
-SCM_DEFINE (scm_array_index_map_x, "array-index-map!", 2, 0, 0,
-           (SCM ra, SCM proc),
-           "Apply @var{proc} to the indices of each element of @var{ra} in\n"
-           "turn, storing the result in the corresponding element.  The 
value\n"
-           "returned and the order of application are unspecified.\n\n"
-           "One can implement @var{array-indexes} as\n"
-           "@lisp\n"
-           "(define (array-indexes array)\n"
-           "    (let ((ra (apply make-array #f (array-shape array))))\n"
-           "      (array-index-map! ra (lambda x x))\n"
-           "      ra))\n"
-           "@end lisp\n"
-           "Another example:\n"
-           "@lisp\n"
-           "(define (apl:index-generator n)\n"
-           "    (let ((v (make-uniform-vector n 1)))\n"
-           "      (array-index-map! v (lambda (i) i))\n"
-           "      v))\n"
-           "@end lisp")
-#define FUNC_NAME s_scm_array_index_map_x
-{
-  SCM_VALIDATE_PROC (2, proc);
-
-  switch (scm_c_array_rank (ra))
-    {
-    case 0:
-      scm_array_set_x (ra, scm_call_0 (proc), SCM_EOL);
-      break;
-    case 1:
-      array_index_map_1 (ra, proc);
-      break;
-    default:
-      array_index_map_n (ra, proc);
-      break;
-    }
-
-  return SCM_UNSPECIFIED;
-}
-#undef FUNC_NAME
-
-
-static int
-array_compare (scm_t_array_handle *hx, scm_t_array_handle *hy,
-               size_t dim, unsigned long posx, unsigned long posy)
-{
-  if (dim == scm_array_handle_rank (hx))
-    return scm_is_true (scm_equal_p (scm_array_handle_ref (hx, posx),
-                                     scm_array_handle_ref (hy, posy)));
-  else
-    {
-      long incx, incy;
-      size_t i;
-
-      if (hx->dims[dim].lbnd != hy->dims[dim].lbnd
-          || hx->dims[dim].ubnd != hy->dims[dim].ubnd)
-        return 0;
-
-      i = hx->dims[dim].ubnd - hx->dims[dim].lbnd + 1;
-
-      incx = hx->dims[dim].inc;
-      incy = hy->dims[dim].inc;
-      posx += (i - 1) * incx;
-      posy += (i - 1) * incy;
-
-      for (; i > 0; i--, posx -= incx, posy -= incy)
-        if (!array_compare (hx, hy, dim + 1, posx, posy))
-          return 0;
-      return 1;
-    }
-}
-
-SCM
-scm_array_equal_p (SCM x, SCM y)
-{
-  scm_t_array_handle hx, hy;
-  SCM res;
-
-  scm_array_get_handle (x, &hx);
-  scm_array_get_handle (y, &hy);
-
-  scm_t_array_element_type t1 = hx.element_type;
-  scm_t_array_element_type t2 = hy.element_type;
-
-  /* R6RS and Guile mostly use #vu8(...) as the literal syntax for
-     bytevectors, but R7RS uses #u8.  To allow R7RS users to re-use the
-     various routines implemented on bytevectors which return vu8-tagged
-     values and to also be able to do (equal? #u8(1 2 3) (bytevector 1 2
-     3)), we allow equality comparisons between vu8 and u8.  */
-  if (t1 == SCM_ARRAY_ELEMENT_TYPE_VU8)
-    t1 = SCM_ARRAY_ELEMENT_TYPE_U8;
-  if (t2 == SCM_ARRAY_ELEMENT_TYPE_VU8)
-    t2 = SCM_ARRAY_ELEMENT_TYPE_U8;
-
-  res = scm_from_bool (hx.ndims == hy.ndims && t1 == t2);
-
-  if (scm_is_true (res))
-    res = scm_from_bool (array_compare (&hx, &hy, 0, 0, 0));
-
-  scm_array_handle_release (&hy);
-  scm_array_handle_release (&hx);
-
-  return res;
-}
-
-static SCM scm_i_array_equal_p (SCM, SCM, SCM);
-SCM_DEFINE (scm_i_array_equal_p, "array-equal?", 0, 2, 1,
-            (SCM ra0, SCM ra1, SCM rest),
-           "Return @code{#t} iff all arguments are arrays with the same\n"
-           "shape, the same type, and have corresponding elements which are\n"
-           "either @code{equal?}  or @code{array-equal?}.  This function\n"
-           "differs from @code{equal?} in that all arguments must be arrays.")
-#define FUNC_NAME s_scm_i_array_equal_p
-{
-  if (SCM_UNBNDP (ra0) || SCM_UNBNDP (ra1))
-    return SCM_BOOL_T;
-
-  while (!scm_is_null (rest))
-    {
-      if (scm_is_false (scm_array_equal_p (ra0, ra1)))
-        return SCM_BOOL_F;
-      ra0 = ra1;
-      ra1 = scm_car (rest);
-      rest = scm_cdr (rest);
-    }
-  return scm_array_equal_p (ra0, ra1);
-}
-#undef FUNC_NAME
-
-
-/* Copy array descriptor with different base. */
-SCM
-scm_i_array_rebase (SCM a, size_t base)
-{
-    size_t ndim = SCM_I_ARRAY_NDIM (a);
-    SCM b = scm_i_raw_array (ndim);
-    SCM_I_ARRAY_SET_V (b, SCM_I_ARRAY_V (a));
-/* FIXME do check base */
-    SCM_I_ARRAY_SET_BASE (b, base);
-    memcpy (SCM_I_ARRAY_DIMS (b), SCM_I_ARRAY_DIMS (a), sizeof 
(scm_t_array_dim)*ndim);
-    return b;
-}
-
-static inline size_t padtoptr(size_t d) { return (d + (sizeof (void *) - 1)) & 
~(sizeof (void *) - 1); }
-
-SCM_DEFINE (scm_array_slice_for_each, "array-slice-for-each", 2, 0, 1,
-            (SCM frame_rank, SCM op, SCM args),
-            "Apply @var{op} to each of the cells of rank 
rank(@var{arg})-@var{frame_rank}\n"
-            "of the arrays @var{args}, in unspecified order. The first\n"
-            "@var{frame_rank} dimensions of each @var{arg} must match.\n"
-            "Rank-0 cells are passed as rank-0 arrays.\n\n"
-            "The value returned is unspecified.\n\n"
-            "For example:\n"
-            "@lisp\n"
-            ";; Sort the rows of rank-2 array A.\n\n"
-            "(array-slice-for-each 1 (lambda (x) (sort! x <)) a)\n"
-            "\n"
-            ";; Compute the arguments of the (x y) vectors in the rows of 
rank-2\n"
-            ";; array XYS and store them in rank-1 array ANGLES. Inside OP,\n"
-            ";; XY is a rank-1 (2-1) array, and ANGLE is a rank-0 (1-1) 
array.\n\n"
-            "(array-slice-for-each 1 \n"
-            "  (lambda (xy angle)\n"
-            "    (array-set! angle (atan (array-ref xy 1) (array-ref xy 
0))))\n"
-            "  xys angles)\n"
-            "@end lisp")
-#define FUNC_NAME s_scm_array_slice_for_each
-{
-  SCM xargs = args;
-  int const N = scm_ilength (args);
-  int const frank = scm_to_int (frame_rank);
-  int ocd;
-  ssize_t step;
-  SCM dargs_ = SCM_EOL;
-  char const * msg;
-  scm_t_array_dim * ais;
-  int n, k;
-  ssize_t z;
-
-  /* to be allocated inside the pool */
-  scm_t_array_handle * ah;
-  SCM * args_;
-  scm_t_array_dim ** as;
-  int * rank;
-
-  ssize_t * s;
-  SCM * ai;
-  SCM ** dargs;
-  ssize_t * i;
-
-  int * order;
-  size_t * base;
-
-  /* size the pool */
-  char * pool;
-  char * pool0;
-  size_t pool_size = 0;
-  pool_size += padtoptr(N*sizeof (scm_t_array_handle));
-  pool_size += padtoptr(N*sizeof (SCM));
-  pool_size += padtoptr(N*sizeof (scm_t_array_dim *));
-  pool_size += padtoptr(N*sizeof (int));
-
-  pool_size += padtoptr(frank*sizeof (ssize_t));
-  pool_size += padtoptr(N*sizeof (SCM));
-  pool_size += padtoptr(N*sizeof (SCM *));
-  pool_size += padtoptr(frank*sizeof (ssize_t));
-
-  pool_size += padtoptr(frank*sizeof (int));
-  pool_size += padtoptr(N*sizeof (size_t));
-  pool = scm_gc_malloc (pool_size, "pool");
-
-  /* place the items in the pool */
-#define AFIC_ALLOC_ADVANCE(pool, count, type, name)    \
-  name = (void *)pool;                                 \
-  pool += padtoptr(count*sizeof (type));
-
-  pool0 = pool;
-  AFIC_ALLOC_ADVANCE (pool, N, scm_t_array_handle, ah);
-  AFIC_ALLOC_ADVANCE (pool, N, SCM, args_);
-  AFIC_ALLOC_ADVANCE (pool, N, scm_t_array_dim *, as);
-  AFIC_ALLOC_ADVANCE (pool, N, int, rank);
-
-  AFIC_ALLOC_ADVANCE (pool, frank, ssize_t, s);
-  AFIC_ALLOC_ADVANCE (pool, N, SCM, ai);
-  AFIC_ALLOC_ADVANCE (pool, N, SCM *, dargs);
-  AFIC_ALLOC_ADVANCE (pool, frank, ssize_t, i);
-
-  AFIC_ALLOC_ADVANCE (pool, frank, int, order);
-  AFIC_ALLOC_ADVANCE (pool, N, size_t, base);
-  assert((pool0+pool_size==pool) && "internal error");
-#undef AFIC_ALLOC_ADVANCE
-
-  for (n=0, xargs=args; scm_is_pair(xargs); xargs=scm_cdr(xargs), ++n)
-    {
-      args_[n] = scm_car(xargs);
-      scm_array_get_handle(args_[n], ah+n);
-      as[n] = scm_array_handle_dims(ah+n);
-      rank[n] = scm_array_handle_rank(ah+n);
-    }
-  /* checks */
-  msg = NULL;
-  if (frank<0)
-    msg = "bad frame rank ~S, ~S";
-  else
-    {
-      for (n=0; n!=N; ++n)
-        {
-          if (rank[n]<frank)
-            {
-              msg = "frame too large for arguments: ~S, ~S";
-              goto check_msg;
-            }
-          for (k=0; k!=frank; ++k)
-            {
-              if (as[0][k].lbnd!=as[n][k].lbnd || as[0][k].ubnd!=as[n][k].ubnd)
-                {
-                  msg = "mismatched frames: ~S, ~S";
-                  goto check_msg;
-                }
-              s[k] = as[n][k].ubnd - as[n][k].lbnd + 1;
-
-              /* this check is needed if the array cannot be entirely */
-              /* unrolled, because the unrolled subloop will be run before */
-              /* checking the dimensions of the frame. */
-              if (s[k]==0)
-                goto end;
-            }
-        }
-    }
- check_msg: ;
-  if (msg!=NULL)
-    {
-      for (n=0; n!=N; ++n)
-        scm_array_handle_release(ah+n);
-      scm_misc_error("array-slice-for-each", msg, scm_cons(frame_rank, args));
-    }
-  /* prepare moving cells. */
-  for (n=0; n!=N; ++n)
-    {
-      ai[n] = scm_i_make_array(rank[n]-frank);
-      SCM_I_ARRAY_SET_V (ai[n], scm_shared_array_root(args_[n]));
-      /* FIXME scm_array_handle_base (ah+n) should be in Guile */
-      SCM_I_ARRAY_SET_BASE (ai[n], ah[n].base);
-      ais = SCM_I_ARRAY_DIMS(ai[n]);
-      for (k=frank; k!=rank[n]; ++k)
-        {
-          ais[k-frank] = as[n][k];
-        }
-    }
-  /* prepare rest list for callee. */
-  {
-    SCM *p = &dargs_;
-    for (n=0; n<N; ++n)
-      {
-        *p = scm_cons (SCM_UNSPECIFIED, SCM_EOL);
-        dargs[n] = SCM_CARLOC (*p);
-        p = SCM_CDRLOC (*p);
-      }
-  }
-  /* special case for rank 0. */
-  if (frank==0)
-    {
-      for (n=0; n<N; ++n)
-        *dargs[n] = ai[n];
-      scm_apply_0(op, dargs_);
-      for (n=0; n<N; ++n)
-        scm_array_handle_release(ah+n);
-      return SCM_UNSPECIFIED;
-    }
-  /* FIXME determine best looping order. */
-  for (k=0; k!=frank; ++k)
-    {
-      i[k] = 0;
-      order[k] = frank-1-k;
-    }
-  /* find outermost compact dim. */
-  step = s[order[0]];
-  ocd = 1;
-  for (; ocd<frank; step *= s[order[ocd]], ++ocd)
-    for (n=0; n!=N; ++n)
-      if (step*as[n][order[0]].inc!=as[n][order[ocd]].inc)
-        goto ocd_reached;
- ocd_reached: ;
-  /* rank loop. */
-  for (n=0; n!=N; ++n)
-    base[n] = SCM_I_ARRAY_BASE(ai[n]);
-  for (;;)
-    {
-      /* unrolled loop. */
-      for (z=0; z!=step; ++z)
-        {
-          /* we are forced to create fresh array descriptors for each */
-          /* call since we don't know whether the callee will keep them, */
-          /* and Guile offers no way to copy the descriptor (since */
-          /* descriptors are immutable). Yet another reason why this */
-          /* should be in Scheme. */
-          for (n=0; n<N; ++n)
-            {
-              *dargs[n] = scm_i_array_rebase(ai[n], base[n]);
-              base[n] += as[n][order[0]].inc;
-            }
-          scm_apply_0(op, dargs_);
-        }
-      for (n=0; n<N; ++n)
-        base[n] -= step*as[n][order[0]].inc;
-      for (k=ocd; ; ++k)
-        {
-          if (k==frank)
-            goto end;
-          else if (i[order[k]]<s[order[k]]-1)
-            {
-              ++i[order[k]];
-              for (n=0; n<N; ++n)
-                base[n] += as[n][order[k]].inc;
-              break;
-            }
-          else
-            {
-              i[order[k]] = 0;
-              for (n=0; n<N; ++n)
-                base[n] += as[n][order[k]].inc*(1-s[order[k]]);
-            }
-        }
-    }
- end:;
-  for (n=0; n<N; ++n)
-    scm_array_handle_release(ah+n);
-  return SCM_UNSPECIFIED;
-}
-#undef FUNC_NAME
-
-SCM_DEFINE (scm_array_slice_for_each_in_order, 
"array-slice-for-each-in-order", 2, 0, 1,
-            (SCM frank, SCM op, SCM a),
-            "Same as array-slice-for-each, but visit the cells sequentially\n"
-            "and in row-major order.\n")
-#define FUNC_NAME s_scm_array_slice_for_each_in_order
-{
-  return scm_array_slice_for_each (frank, op, a);
-}
-#undef FUNC_NAME
-
-
-void
-scm_init_array_map (void)
-{
-#include "array-map.x"
-  scm_add_feature (s_scm_array_for_each);
-}
diff --git a/libguile/array-map.h b/libguile/array-map.h
deleted file mode 100644
index 3e96bec1f..000000000
--- a/libguile/array-map.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef SCM_ARRAY_MAP_H
-#define SCM_ARRAY_MAP_H
-
-/* Copyright 1995-1997,2000,2006,2008-2011,2013,2015,2018
-     Free Software Foundation, Inc.
-
-   This file is part of Guile.
-
-   Guile is free software: you can redistribute it and/or modify it
-   under the terms of the GNU Lesser General Public License as published
-   by the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   Guile is distributed in the hope that it will be useful, but WITHOUT
-   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-   License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with Guile.  If not, see
-   <https://www.gnu.org/licenses/>.  */
-
-
-
-#include "libguile/scm.h"
-
-
-
-SCM_API int scm_ra_matchp (SCM ra0, SCM ras);
-SCM_API int scm_ramapc (void *cproc, SCM data, SCM ra0, SCM lra,
-                       const char *what);
-SCM_API SCM scm_array_fill_x (SCM ra, SCM fill);
-SCM_API SCM scm_array_copy_x (SCM src, SCM dst);
-SCM_API SCM scm_array_map_x (SCM ra0, SCM proc, SCM lra);
-SCM_API SCM scm_array_for_each (SCM proc, SCM ra0, SCM lra);
-SCM_API SCM scm_array_index_map_x (SCM ra, SCM proc);
-SCM_API SCM scm_array_equal_p (SCM ra0, SCM ra1);
-SCM_API SCM scm_array_slice_for_each (SCM frank, SCM op, SCM args);
-SCM_API SCM scm_array_slice_for_each_in_order (SCM frank, SCM op, SCM args);
-
-SCM_INTERNAL SCM scm_i_array_rebase (SCM a, size_t base);
-SCM_INTERNAL void scm_init_array_map (void);
-
-#endif  /* SCM_ARRAY_MAP_H */
diff --git a/libguile/arrays.c b/libguile/arrays.c
index cf9ec8c62..46ac7bfc8 100644
--- a/libguile/arrays.c
+++ b/libguile/arrays.c
@@ -28,7 +28,6 @@
 #include <errno.h>
 #include <string.h>
 
-#include "array-map.h"
 #include "bitvectors.h"
 #include "boolean.h"
 #include "chars.h"
@@ -49,7 +48,9 @@
 #include "srfi-13.h"
 #include "srfi-4.h"
 #include "strings.h"
+#include "threads.h"
 #include "uniform.h"
+#include "variable.h"
 #include "vectors.h"
 
 #include "arrays.h"
@@ -785,109 +786,6 @@ SCM_DEFINE (scm_array_slice, "array-slice", 1, 0, 1,
 #undef FUNC_NAME
 
 
-SCM_DEFINE (scm_array_cell_ref, "array-cell-ref", 1, 0, 1,
-            (SCM ra, SCM indices),
-            "Return the element at the @code{(@var{indices} ...)} position\n"
-            "in array @var{ra}, or the array slice @var{ra}[@var{indices} ..., 
...]\n"
-            "if the rank of @var{ra} is larger than the number of indices.\n\n"
-            "See also @code{array-ref}, @code{array-slice}, 
@code{array-cell-set!}.\n\n"
-            "@code{array-cell-ref} never returns a rank 0 array. For 
example:\n"
-            "@lisp\n"
-            "(array-cell-ref #2((1 2 3) (4 5 6)) 1 1) @result{} 5\n"
-            "(array-cell-ref #2((1 2 3) (4 5 6)) 1) @result{} #(4 5 6)\n"
-            "(array-cell-ref #2((1 2 3) (4 5 6))) @result{} #2((1 2 3) (4 5 
6))\n"
-            "(array-cell-ref #0(5) @result{} 5.\n"
-            "@end lisp")
-#define FUNC_NAME s_scm_array_cell_ref
-{
-  scm_t_array_handle handle;
-  scm_array_get_handle (ra, &handle);
-  SCM i = indices;
-  size_t k;
-  ssize_t pos = 0;
-  scm_t_array_dim *s;
-  array_from_pos (&handle, &k, &i, &pos, &s);
-  if (!s)
-    {
-      scm_array_handle_release (&handle);
-      scm_misc_error (FUNC_NAME, "indices ~a out of range for array bounds 
~a", scm_list_2 (indices, scm_array_dimensions (ra)));
-    }
-  SCM o;
-  if (k>0)
-    array_from_get_o (&handle, k, s, pos, &o);
-  else if (scm_is_null(i))
-    o = scm_array_handle_ref (&handle, pos);
-  else
-    {
-      scm_array_handle_release (&handle);
-      scm_misc_error (FUNC_NAME, "too many indices ~a for rank ~a", scm_list_2 
(indices, scm_array_rank (ra)));
-    }
-  scm_array_handle_release (&handle);
-  return o;
-}
-#undef FUNC_NAME
-
-
-SCM_DEFINE (scm_array_cell_set_x, "array-cell-set!", 2, 0, 1,
-            (SCM ra, SCM b, SCM indices),
-            "Set the array slice @var{ra}[@var{indices} ..., ...] to 
@var{b}\n."
-            "Equivalent to @code{(array-copy! @var{b} (apply array-cell-ref 
@var{ra} @var{indices}))}\n"
-            "if the number of indices is smaller than the rank of @var{ra}; 
otherwise\n"
-            "equivalent to @code{(apply array-set! @var{ra} @var{b} 
@var{indices})}.\n"
-            "This function returns the modified array @var{ra}.\n\n"
-            "See also @code{array-ref}, @code{array-cell-ref}, 
@code{array-slice}.\n\n"
-            "For example:\n"
-            "@lisp\n"
-            "(define A (list->array 2 '((1 2 3) (4 5 6))))\n"
-            "(array-cell-set! A #0(99) 1 1) @result{} #2((1 2 3) (4 #0(99) 
6))\n"
-            "(array-cell-set! A 99 1 1) @result{} #2((1 2 3) (4 99 6))\n"
-            "(array-cell-set! A #(a b c) 0) @result{} #2((a b c) (4 99 6))\n"
-            "(array-cell-set! A #2((x y z) (9 8 7))) @result{} #2((x y z) (9 8 
7))\n\n"
-            "(define B (make-array 0))\n"
-            "(array-cell-set! B 15) @result{} #0(15)\n"
-            "@end lisp")
-#define FUNC_NAME s_scm_array_cell_set_x
-{
-  scm_t_array_handle handle;
-  scm_array_get_handle (ra, &handle);
-  SCM i = indices;
-  size_t k;
-  ssize_t pos = 0;
-  scm_t_array_dim *s;
-  array_from_pos (&handle, &k, &i, &pos, &s);
-  if (!s)
-    {
-      scm_array_handle_release (&handle);
-      scm_misc_error (FUNC_NAME, "indices ~a out of range for array bounds 
~a", scm_list_2 (indices, scm_array_dimensions (ra)));
-    }
-  if (k>0)
-    {
-      SCM o;
-      array_from_get_o(&handle, k, s, pos, &o);
-      scm_array_handle_release(&handle);
-      /* an error is still possible here if o and b don't match. */
-      /* FIXME copying like this wastes the handle, and the bounds matching
-         behavior of array-copy! is not strict. */
-      scm_array_copy_x(b, o);
-    }
-  else if (scm_is_null(i))
-    {
-      scm_array_handle_set (&handle, pos, b);  /* ra may be non-ARRAYP */
-      scm_array_handle_release (&handle);
-    }
-  else
-    {
-      scm_array_handle_release (&handle);
-      scm_misc_error (FUNC_NAME, "too many indices ~a for rank ~a", scm_list_2 
(indices, scm_array_rank (ra)));
-    }
-  return ra;
-}
-#undef FUNC_NAME
-
-
-#undef ARRAY_FROM_GET_O
-
-
 /* args are RA . DIMS */
 SCM_DEFINE (scm_transpose_array, "transpose-array", 1, 0, 1,
             (SCM ra, SCM args),
@@ -1235,6 +1133,37 @@ scm_i_print_array (SCM array, SCM port, scm_print_state 
*pstate)
   return d;
 }
 
+static SCM array_equal_p_var;
+static SCM array_copy_var;
+
+static void
+init_array_map_vars (void)
+{
+  array_equal_p_var = scm_c_public_lookup ("ice-9 arrays", "array-equal?");
+  array_copy_var = scm_c_public_lookup ("ice-9 arrays", "array-copy");
+}
+
+static void
+init_array_map_functions (void)
+{
+  static scm_i_pthread_once_t once = SCM_I_PTHREAD_ONCE_INIT;
+  scm_i_pthread_once (&once, init_array_map_vars);
+}
+
+SCM
+scm_i_array_equal_p (SCM ra0, SCM ra1)
+{
+  init_array_map_functions ();
+  return scm_call_2 (scm_variable_ref (array_equal_p_var), ra0, ra1);
+}
+
+SCM
+scm_i_array_copy (SCM ra)
+{
+  init_array_map_functions ();
+  return scm_call_1 (scm_variable_ref (array_copy_var), ra);
+}
+
 void
 scm_init_arrays ()
 {
diff --git a/libguile/arrays.h b/libguile/arrays.h
index 5457ddb95..40e3ad7bd 100644
--- a/libguile/arrays.h
+++ b/libguile/arrays.h
@@ -1,7 +1,7 @@
 #ifndef SCM_ARRAY_H
 #define SCM_ARRAY_H
 
-/* Copyright 1995-1997,1999-2001,2004,2006,2008-2010,2012,2018
+/* Copyright 1995-1997,1999-2001,2004,2006,2008-2010,2012,2018,2025
      Free Software Foundation, Inc.
 
    This file is part of Guile.
@@ -50,8 +50,6 @@ SCM_API SCM scm_make_shared_array (SCM oldra, SCM mapfunc, 
SCM dims);
 SCM_API SCM scm_transpose_array (SCM ra, SCM args);
 SCM_API SCM scm_array_contents (SCM ra, SCM strict);
 SCM_API SCM scm_array_slice (SCM ra, SCM indices);
-SCM_API SCM scm_array_cell_ref (SCM ra, SCM indices);
-SCM_API SCM scm_array_cell_set_x (SCM ra, SCM b, SCM indices);
 
 SCM_API SCM scm_list_to_array (SCM ndim, SCM lst);
 SCM_API SCM scm_list_to_typed_array (SCM type, SCM ndim, SCM lst);
@@ -84,6 +82,10 @@ SCM_API SCM scm_array_ref (SCM v, SCM args);
 SCM_API SCM scm_array_set_x (SCM v, SCM obj, SCM args);
 SCM_API SCM scm_array_to_list (SCM v);
 
+SCM_INTERNAL SCM scm_i_array_equal_p (SCM ra0, SCM ra1);
+SCM_INTERNAL SCM scm_i_array_copy (SCM ra);
+
+
 typedef struct scm_t_array_dim
 {
   ssize_t lbnd;
diff --git a/libguile/deprecated.c b/libguile/deprecated.c
index 8078b680d..7da74fb8a 100644
--- a/libguile/deprecated.c
+++ b/libguile/deprecated.c
@@ -304,6 +304,116 @@ scm_cons_source (SCM orig, SCM x, SCM y)
   return scm_call_3 (scm_variable_ref (cons_source_var), orig, x, y);
 }
 
+/* In versions 3.0 and prior, the hash table interface could also access
+   weak tables.  This is now deprecated.  */
+
+
+
+static SCM array_fill_x_var;
+static SCM array_copy_x_var;
+static SCM array_map_x_var;
+static SCM array_for_each_var;
+static SCM array_index_map_x_var;
+static SCM array_equal_p_var;
+static SCM array_slice_for_each_var;
+static SCM array_cell_ref_var;
+static SCM array_cell_set_x_var;
+
+static void
+init_array_map_vars (void)
+{
+  array_fill_x_var = scm_c_public_lookup ("ice-9 arrays", "array-fill!");
+  array_copy_x_var = scm_c_public_lookup ("ice-9 arrays", "array-copy!");
+  array_map_x_var = scm_c_public_lookup ("ice-9 arrays", "array-map!");
+  array_for_each_var = scm_c_public_lookup ("ice-9 arrays", "array-for-each");
+  array_index_map_x_var = scm_c_public_lookup ("ice-9 arrays", 
"array-index-map!");
+  array_equal_p_var = scm_c_public_lookup ("ice-9 arrays", "array-equal?");
+  array_fill_x_var = scm_c_public_lookup ("ice-9 arrays", "array-fill!");
+  array_cell_ref_var = scm_c_public_lookup ("ice-9 arrays", "array-cell-ref");
+  array_cell_set_x_var = scm_c_public_lookup ("ice-9 arrays", 
"array-cell-set!");
+}
+
+static void
+init_array_map_functions (void)
+{
+  static scm_i_pthread_once_t once = SCM_I_PTHREAD_ONCE_INIT;
+  scm_c_issue_deprecation_warning
+    ("Using the array map functions from C is deprecated.  Invoke "
+     "array-map!, etc. from (ice-9 arrays) instead.");
+  scm_i_pthread_once (&once, init_array_map_vars);
+}
+
+SCM
+scm_array_fill_x (SCM ra, SCM fill)
+{
+  init_array_map_functions ();
+  return scm_call_2 (scm_variable_ref (array_fill_x_var), ra, fill);
+}
+
+SCM
+scm_array_copy_x (SCM src, SCM dst)
+{
+  init_array_map_functions ();
+  return scm_call_2 (scm_variable_ref (array_copy_x_var), src, dst);
+}
+
+SCM
+scm_array_map_x (SCM ra0, SCM proc, SCM lra)
+{
+  init_array_map_functions ();
+  return scm_apply_2 (scm_variable_ref (array_map_x_var), ra0, proc, lra);
+}
+
+SCM
+scm_array_for_each (SCM proc, SCM ra0, SCM lra)
+{
+  init_array_map_functions ();
+  return scm_apply_2 (scm_variable_ref (array_for_each_var), proc, ra0, lra);
+}
+
+SCM
+scm_array_index_map_x (SCM ra, SCM proc)
+{
+  init_array_map_functions ();
+  return scm_call_2 (scm_variable_ref (array_index_map_x_var), ra, proc);
+}
+
+SCM
+scm_array_equal_p (SCM ra0, SCM ra1)
+{
+  init_array_map_functions ();
+  return scm_call_2 (scm_variable_ref (array_equal_p_var), ra0, ra1);
+}
+
+SCM
+scm_array_slice_for_each (SCM frank, SCM op, SCM args)
+{
+  init_array_map_functions ();
+  return scm_apply_2 (scm_variable_ref (array_slice_for_each_var), frank, op,
+                      args);
+}
+
+SCM
+scm_array_slice_for_each_in_order (SCM frank, SCM op, SCM args)
+{
+  return scm_array_slice_for_each (frank, op, args);
+}
+
+SCM
+scm_array_cell_ref (SCM array, SCM indices)
+{
+  init_array_map_functions ();
+  return scm_apply_1 (scm_variable_ref (array_cell_ref_var), array, indices);
+}
+
+SCM
+scm_array_cell_set_x (SCM array, SCM val, SCM indices)
+{
+  init_array_map_functions ();
+  return scm_apply_2 (scm_variable_ref (array_cell_set_x_var), array, val,
+                      indices);
+}
+
 
 
 
diff --git a/libguile/deprecated.h b/libguile/deprecated.h
index f0189a676..bade32244 100644
--- a/libguile/deprecated.h
+++ b/libguile/deprecated.h
@@ -64,6 +64,17 @@ SCM_DEPRECATED SCM scm_source_properties (SCM obj);
 SCM_DEPRECATED SCM scm_set_source_properties_x (SCM obj, SCM props);
 SCM_DEPRECATED SCM scm_cons_source (SCM xorig, SCM x, SCM y);
 
+SCM_DEPRECATED SCM scm_array_fill_x (SCM ra, SCM fill);
+SCM_DEPRECATED SCM scm_array_copy_x (SCM src, SCM dst);
+SCM_DEPRECATED SCM scm_array_map_x (SCM ra0, SCM proc, SCM lra);
+SCM_DEPRECATED SCM scm_array_for_each (SCM proc, SCM ra0, SCM lra);
+SCM_DEPRECATED SCM scm_array_index_map_x (SCM ra, SCM proc);
+SCM_DEPRECATED SCM scm_array_equal_p (SCM ra0, SCM ra1);
+SCM_DEPRECATED SCM scm_array_slice_for_each (SCM frank, SCM op, SCM args);
+SCM_DEPRECATED SCM scm_array_slice_for_each_in_order (SCM frank, SCM op, SCM 
args);
+SCM_DEPRECATED SCM scm_array_cell_ref (SCM array, SCM indices);
+SCM_DEPRECATED SCM scm_array_cell_set_x (SCM array, SCM val, SCM indices);
+
 /* Deprecated declarations go here.  */
 
 void scm_i_init_deprecated (void);
diff --git a/libguile/eq.c b/libguile/eq.c
index d4d51a05e..57e4b931a 100644
--- a/libguile/eq.c
+++ b/libguile/eq.c
@@ -25,7 +25,7 @@
 #include <math.h>
 #include <string.h>
 
-#include "array-map.h"
+#include "arrays.h"
 #include "async.h"
 #include "bitvectors.h"
 #include "boolean.h"
@@ -329,7 +329,7 @@ scm_equal_p (SCM x, SCM y)
       /* Vectors can be equal to one-dimensional arrays.
        */
       if (scm_is_array (x) && scm_is_array (y))
-       return scm_array_equal_p (x, y);
+       return scm_i_array_equal_p (x, y);
 
       return SCM_BOOL_F;
     }
@@ -367,7 +367,7 @@ scm_equal_p (SCM x, SCM y)
     case scm_tc7_bytevector:
       return scm_bytevector_eq_p (x, y);
     case scm_tc7_array:
-      return scm_array_equal_p (x, y);
+      return scm_i_array_equal_p (x, y);
     case scm_tc7_bitvector:
       return scm_i_bitvector_equal_p (x, y);
     case scm_tc7_vector:
diff --git a/libguile/init.c b/libguile/init.c
index a5935a437..c52de0c53 100644
--- a/libguile/init.c
+++ b/libguile/init.c
@@ -41,7 +41,6 @@
 
 /* Everybody has an init function.  */
 #include "alist.h"
-#include "array-map.h"
 #include "arrays.h"
 #include "async.h"
 #include "atomic.h"
@@ -435,7 +434,6 @@ scm_i_init_guile (struct gc_stack_addr base)
   scm_init_bitvectors ();  /* Requires smob_prehistory, array-handle */
   scm_bootstrap_srfi_4 ();  /* Requires smob_prehistory, array-handle */
   scm_init_arrays ();    /* Requires smob_prehistory, array-handle */
-  scm_init_array_map ();
 
   scm_init_frames ();   /* Requires smob_prehistory */
   scm_init_stacks ();   /* Requires strings, struct, frames */
diff --git a/libguile/sort.c b/libguile/sort.c
index 38f64c37c..63e3dff41 100644
--- a/libguile/sort.c
+++ b/libguile/sort.c
@@ -1,4 +1,4 @@
-/* Copyright 1999-2002,2004,2006-2012,2014,2018
+/* Copyright 1999-2002,2004,2006-2012,2014,2018,2025
      Free Software Foundation, Inc.
 
    This file is part of Guile.
@@ -39,7 +39,6 @@
 # include <config.h>
 #endif
 
-#include "array-map.h"
 #include "arrays.h"
 #include "async.h"
 #include "boolean.h"
@@ -467,12 +466,9 @@ SCM_DEFINE (scm_sort, "sort", 2, 0, 0,
     return scm_sort_x (scm_list_copy (items), less);
   else if (scm_is_array (items) && scm_c_array_rank (items) == 1)
     {
-      SCM copy;
       if (scm_c_array_rank (items) != 1)
         scm_error (scm_misc_error_key, FUNC_NAME, "rank must be 1", items, 
SCM_EOL);
-      copy = scm_make_typed_array (scm_array_type (items), SCM_UNSPECIFIED, 
scm_array_dimensions (items));
-      scm_array_copy_x (items, copy);
-      return scm_sort_x (copy, less);
+      return scm_sort_x (scm_i_array_copy (items), less);
     }
   else
     SCM_WRONG_TYPE_ARG (1, items);
diff --git a/module/ice-9/arrays.scm b/module/ice-9/arrays.scm
index f03eb351b..ac1f656d3 100644
--- a/module/ice-9/arrays.scm
+++ b/module/ice-9/arrays.scm
@@ -1,6 +1,6 @@
 ;;; -*- mode: scheme; coding: utf-8; -*-
 ;;;
-;;; Copyright (C) 1999, 2001, 2004, 2006, 2017 Free Software Foundation, Inc.
+;;; Copyright (C) 1999, 2001, 2004, 2006, 2017, 2025 Free Software Foundation, 
Inc.
 ;;;
 ;;; This library is free software; you can redistribute it and/or
 ;;; modify it under the terms of the GNU Lesser General Public
@@ -18,22 +18,636 @@
 
 (define-module (ice-9 arrays)
   #:use-module (rnrs io ports)
+  #:use-module (rnrs bytevectors)
+  #:use-module (ice-9 match)
   #:use-module (srfi srfi-1)
-  #:export (array-copy))
+  #:export (array-copy)
+  ;; FIXME: Use #:export when deprecated code removed.
+  #:replace (array-fill!
+             array-copy!
+             array-copy-in-order!
+             array-map!
+             array-for-each
+             array-index-map!
+             array-equal?
+             array-slice-for-each
+             array-slice-for-each-in-order
+             array-cell-ref
+             array-cell-set!))
+
+(define (string-accessors buffer)
+  (values (string-length buffer)
+          (lambda (x i) (string-ref x i))
+          (lambda (x i v) (string-set! x i v))))
+
+(define (vector-accessors buffer)
+  (values (vector-length buffer)
+          (lambda (x i) (vector-ref x i))
+          (lambda (x i v) (vector-set! x i v))))
+
+(define (bitvector-accessors buffer)
+  (values (bitvector-length buffer)
+          (lambda (x i) (bitvector-bit-set? x i))
+          (lambda (x i v)
+            (if v
+                (bitvector-set-bit! x i)
+                (bitvector-clear-bit! x i)))))
+
+(define (bytevector-accessors buffer)
+  (case (array-type buffer)
+    ((u8 vu8)
+     (values (bytevector-length buffer)
+             (lambda (x i) (bytevector-u8-ref x i))
+             (lambda (x i v) (bytevector-u8-set! x i v))))
+    ((s8)
+     (values (bytevector-length buffer)
+             (lambda (x i) (bytevector-s8-ref x i))
+             (lambda (x i v) (bytevector-s8-set! x i v))))
+    ((u16)
+     (values (ash (bytevector-length buffer) -1)
+             (lambda (x i) (bytevector-u16-native-ref x (ash i 1)))
+             (lambda (x i v) (bytevector-u16-native-set! x (ash i 1) v))))
+    ((s16)
+     (values (ash (bytevector-length buffer) -1)
+             (lambda (x i) (bytevector-s16-native-ref x (ash i 2)))
+             (lambda (x i v) (bytevector-s16-native-set! x (ash i 2) v))))
+    ((u32)
+     (values (ash (bytevector-length buffer) -2)
+             (lambda (x i) (bytevector-u32-native-ref x (ash i 2)))
+             (lambda (x i v) (bytevector-u32-native-set! x (ash i 2) v))))
+    ((s32)
+     (values (ash (bytevector-length buffer) -2)
+             (lambda (x i) (bytevector-s32-native-ref x (ash i 2)))
+             (lambda (x i v) (bytevector-s32-native-set! x (ash i 2) v))))
+    ((u64)
+     (values (ash (bytevector-length buffer) -3)
+             (lambda (x i) (bytevector-u64-native-ref x (ash i 3)))
+             (lambda (x i v) (bytevector-u64-native-set! x (ash i 3) v))))
+    ((s64)
+     (values (ash (bytevector-length buffer) -3)
+             (lambda (x i) (bytevector-s64-native-ref x (ash i 3)))
+             (lambda (x i v) (bytevector-s64-native-set! x (ash i 3) v))))
+    ((f32)
+     (values (ash (bytevector-length buffer) -2)
+             (lambda (x i) (bytevector-ieee-single-native-ref x (ash i 2)))
+             (lambda (x i v) (bytevector-ieee-single-native-set! x (ash i 2) 
v))))
+    ((f64)
+     (values (ash (bytevector-length buffer) -3)
+             (lambda (x i) (bytevector-ieee-double-native-ref x (ash i 3)))
+             (lambda (x i v) (bytevector-ieee-double-native-set! x (ash i 3) 
v))))
+    ((c32)
+     (values (ash (bytevector-length buffer) -3)
+             (lambda (x i)
+               (make-rectangular
+                (bytevector-ieee-single-native-ref x (ash i 3))
+                (bytevector-ieee-single-native-ref x (+ (ash i 3) 4))))
+             (lambda (x i v)
+               (bytevector-ieee-single-native-set! x (ash i 3) (real-part v))
+               (bytevector-ieee-single-native-set! x (+ (ash i 3) 4) 
(imag-part v)))))
+    ((c64)
+     (values (ash (bytevector-length buffer) -4)
+             (lambda (x i)
+               (make-rectangular
+                (bytevector-ieee-single-native-ref x (ash i 4))
+                (bytevector-ieee-single-native-ref x (+ (ash i 4) 8))))
+             (lambda (x i v)
+               (bytevector-ieee-single-native-set! x (ash i 4) (real-part v))
+               (bytevector-ieee-single-native-set! x (+ (ash i 3) 8) 
(imag-part v)))))
+    (else (error "unreachable"))))
+
+(define (compute-accessors buffer)
+  (cond
+   ((string? buffer) (string-accessors buffer))
+   ((vector? buffer) (vector-accessors buffer))
+   ((bitvector? buffer) (bitvector-accessors buffer))
+   ((bytevector? buffer) (bytevector-accessors buffer))
+   (else
+    (error "bad array buffer"))))
+
+(define (array-shapev a)
+  (let ((v (make-vector (array-rank a))))
+    (let lp ((i 0)
+             (dims (array-dimensions a))
+             (incs (shared-array-increments a)))
+      (match dims
+        (() v)
+        (((start end) . dims)
+         (match incs
+           ((inc . incs)
+            (vector-set! v i (vector start (1+ (- end start)) inc))
+            (lp (1+ i) dims incs))))
+        ((end . dims)
+         (match incs
+           ((inc . incs)
+            (vector-set! v i (vector 0 end inc))
+            (lp (1+ i) dims incs))))))))
+
+(define (shapev<=? a b)
+  (and (eqv? (vector-length a) (vector-length b))
+       (let lp ((i 0))
+         (or (eqv? i (vector-length a))
+             (match (vector-ref a i)
+               (#(abase acount ainc)
+                (match (vector-ref b i)
+                  (#(bbase bcount binc)
+                   (and (<= bbase abase)
+                        (<= (+ abase acount) (+ bbase bcount))
+                        (lp (1+ i)))))))))))
+
+(define (prepare-reads dst-shape src)
+  (define src-shape (array-shapev src))
+
+  (unless (shapev<=? dst-shape src-shape)
+    (error "array shape mismatch" dst-shape src))
+
+  (define initial-offset
+    (let lp ((dim 0) (offset (shared-array-offset src)))
+      (cond
+       ((= dim (vector-length dst-shape))
+        offset)
+       (else
+        (match (vector-ref dst-shape dim)
+          (#(dst-start _ _)
+           (match (vector-ref src-shape dim)
+             (#(src-start _ src-inc)
+              (lp (+ dim 1)
+                  (+ offset (* (- src-start dst-start) src-inc)))))))))))
+
+  (define incs
+    (let ((incs (make-vector (vector-length src-shape))))
+      (let lp ((dim 0))
+        (when (< dim (vector-length dst-shape))
+          (match (vector-ref src-shape dim)
+            (#(start _ inc)
+             (vector-set! incs dim inc)
+             (lp (+ dim 1))))))
+      incs))
+
+  (define offset initial-offset)  ; Mutable.
+
+  (define read
+    (let ((buf (shared-array-root src)))
+      (call-with-values (lambda () (compute-accessors buf))
+        (lambda (length ref set)
+          (lambda () (ref buf offset))))))
+
+  (define (advance! dim)
+    (set! offset (+ offset (vector-ref incs dim))))
+
+  (define (restore! dim count)
+    (set! offset (- offset (* count (vector-ref incs dim)))))
+
+  (values read advance! restore!))
+
+(define (array-map! dst proc . src*)
+  (define dst-buf (shared-array-root dst))
+  (define dst-set (call-with-values (lambda () (compute-accessors dst-buf))
+                    (lambda (length ref set) set)))
+  (define dst-dims (array-shapev dst))
+
+  (define src-count (length src*))
+  (define src-advancev (make-vector src-count))
+  (define src-restorev (make-vector src-count))
+  (define src-readv (make-vector src-count))
+
+  (let lp ((i 0) (src* src*))
+    (match src*
+      (() #t)
+      ((src . src*)
+       (call-with-values (lambda () (prepare-reads dst-dims src))
+         (lambda (read advance restore)
+           (vector-set! src-readv i read)
+           (vector-set! src-advancev i advance)
+           (vector-set! src-restorev i restore)))
+       (lp (1+ i) src*))))
+
+  (define proc*
+    (match (vector-length src-readv)
+      (0 proc)
+      (1 (let ((read0 (vector-ref src-readv 0)))
+           (lambda () (proc (read0)))))
+      (2 (let ((read0 (vector-ref src-readv 0))
+               (read1 (vector-ref src-readv 1)))
+           (lambda () (proc (read0) (read1)))))
+      (n (let ((read0 (vector-ref src-readv 0))
+               (read1 (vector-ref src-readv 1))
+               (args (make-list (- n 2))))
+           (lambda ()
+             (let* ((v0 (read0))
+                    (v1 (read1)))
+               (let lp ((i 2) (args args))
+                 (let ((read (vector-ref src-readv i)))
+                   (set-car! args (read))
+                   (let ((i (1+ i)))
+                     (when (< i n)
+                       (lp i (cdr args))))))
+               (apply proc v0 v1 args)))))))
+
+  (define (advance-src-offsets! dim)
+    (let lp ((i 0))
+      (when (< i (vector-length src-advancev))
+        (let ((advance! (vector-ref src-advancev i)))
+          (advance! dim)
+          (lp (1+ i))))))
+
+  (define (restore-src-offsets! dim count)
+    (let lp ((i 0))
+      (when (< i (vector-length src-restorev))
+        (let ((restore! (vector-ref src-restorev i)))
+          (restore! dim count)
+          (lp (1+ i))))))
+
+  (cond
+   ((zero? (vector-length dst-dims))
+    (dst-set dst-buf (shared-array-offset dst) (proc*)))
+   (else
+    (let recur ((dim 0)
+                (dst-offset (shared-array-offset dst)))
+      (match (vector-ref dst-dims dim)
+        (#(start count dst-inc)
+         (if (eq? (1+ dim) (vector-length dst-dims))
+             (let lp ((n 0) (dst-offset dst-offset))
+               (cond
+                ((= n count)
+                 (restore-src-offsets! dim count))
+                (else
+                 (dst-set dst-buf dst-offset (proc*))
+                 (advance-src-offsets! dim)
+                 (lp (1+ n) (+ dst-offset dst-inc)))))
+             (let lp ((n 0) (dst-offset dst-offset))
+               (cond
+                ((= n count)
+                 (restore-src-offsets! dim count))
+                (else
+                 (recur (1+ dim) dst-offset)
+                 (advance-src-offsets! dim)
+                 (lp (1+ n) (+ dst-offset dst-inc))))))))))))
+
+(define (array-fill! array fill)
+  "Store @var{fill} in every element of array @var{array}.  The value
+returned is unspecified."
+  (array-map! array (lambda () fill)))
 
 ;; This is actually defined in boot-9.scm, apparently for backwards
 ;; compatibility.
-
+;;
 ;; (define (array-shape a)
 ;;   (map (lambda (ind) (if (number? ind) (list 0 (+ -1 ind)) ind))
 ;;        (array-dimensions a)))
 
+(define (array-copy! src dst)
+  "Copy every element from vector or array @var{src} to the
+corresponding element of @var{dst}.  @var{dst} must have the same rank
+as @var{src}, and be at least as large in each dimension.  The order is
+unspecified."
+  ;; Unlike array-map! which can read from larger arrays into a smaller,
+  ;; here we can read from a smaller array into a larger.  If src is
+  ;; smaller than dst, we need to slice dst.
+  (let ((src-shape (array-shapev src))
+        (dst-shape (array-shapev dst)))
+    (unless (= (vector-length src-shape) (vector-length dst-shape))
+      (error "array shape mismatch" dst-shape src))
+    (array-map! (if (equal? src-shape dst-shape)
+                    dst
+                    (if (shapev<=? src-shape dst-shape)
+                        (apply make-shared-array dst list (array-shape src))
+                        (error "array shape mismatch" dst-shape src)))
+                (lambda (v) v)
+                src)))
+
+(define (array-copy-in-order! src dst)
+  "Like @code{array-copy!}, but guaranteed to proceed in row-major order."
+  (array-copy! src dst))
+
 ; FIXME writes over the array twice if (array-type) is #t
 (define (array-copy a)
   (let ((b (apply make-typed-array (array-type a) *unspecified* (array-shape 
a))))
     (array-copy! a b)
     b))
 
+(define (dim-start dim)
+  (match dim ((start end) start) (end 0)))
+(define (dim-end dim)
+  (match dim ((start end) (1+ end)) (end end)))
+       
+(define (array-for-each1 proc array)
+  (cond
+   ((string? array)
+    (let lp ((n 0))
+      (when (< n (string-length array))
+        (proc (string-ref array n))
+        (lp (1+ n)))))
+   ((vector? array)
+    (let lp ((n 0))
+      (when (< n (vector-length array))
+        (proc (vector-ref array n))
+        (lp (1+ n)))))
+   ((bitvector? array)
+    (let lp ((n 0))
+      (when (< n (bitvector-length array))
+        (proc (bitvector-bit-set? array n))
+        (lp (1+ n)))))
+   ((bytevector? array)
+    (call-with-values (bytevector-accessors array)
+      (lambda (len ref set)
+        (let lp ((n 0))
+          (when (< n len)
+            (proc (ref n))
+            (lp (1+ n)))))))
+   (else
+    (let ((v (shared-array-root array)))
+      (define-values (length ref set) (compute-accessors v))
+      (match (array-shapev array)
+        (#() (proc (ref v (shared-array-offset array))))
+        (dims
+         (let ((ndims (vector-length dims)))
+           (let recur ((dim 0)
+                       (offset (shared-array-offset array)))
+             (match (vector-ref dims dim)
+               (#(first count inc)
+                (if (eqv? dim (1- ndims))
+                    (let lp ((i 0) (offset offset))
+                      (when (< i count)
+                        (proc (ref v offset))
+                        (lp (1+ i) (+ offset inc))))
+                    (let lp ((i 0) (offset offset))
+                      (when (< i count)
+                        (recur (1+ dim) offset)
+                        (lp (1+ i) (+ offset inc)))))))))))))))
+
+(define (array-for-each* proc arrays)
+  (define shape (array-shapev (car arrays)))
+
+  (define src-count (length arrays))
+  (define src-advancev (make-vector src-count))
+  (define src-restorev (make-vector src-count))
+  (define src-readv (make-vector src-count))
+
+  (let lp ((i 0) (arrays arrays))
+    (match arrays
+      (() #t)
+      ((src . arrays)
+       (call-with-values (lambda () (prepare-reads shape src))
+         (lambda (read advance restore)
+           (vector-set! src-readv i read)
+           (vector-set! src-advancev i advance)
+           (vector-set! src-restorev i restore)))
+       (lp (1+ i) arrays))))
+
+  (define proc*
+    (match (vector-length src-readv)
+      (0 proc)
+      (1 (let ((read0 (vector-ref src-readv 0)))
+           (lambda () (proc (read0)))))
+      (2 (let ((read0 (vector-ref src-readv 0))
+               (read1 (vector-ref src-readv 1)))
+           (lambda () (proc (read0) (read1)))))
+      (n (let ((read0 (vector-ref src-readv 0))
+               (read1 (vector-ref src-readv 1))
+               (args (make-list (- n 2))))
+           (lambda ()
+             (let* ((v0 (read0))
+                    (v1 (read1)))
+               (let lp ((i 2) (args args))
+                 (let ((read (vector-ref src-readv i)))
+                   (set-car! args (read))
+                   (let ((i (1+ i)))
+                     (when (< i n)
+                       (lp i (cdr args))))))
+               (apply proc v0 v1 args)))))))
+
+  (define (advance-src-offsets! dim)
+    (let lp ((i 0))
+      (when (< i (vector-length src-advancev))
+        (let ((advance! (vector-ref src-advancev i)))
+          (advance! dim)
+          (lp (1+ i))))))
+
+  (define (restore-src-offsets! dim count)
+    (let lp ((i 0))
+      (when (< i (vector-length src-restorev))
+        (let ((restore! (vector-ref src-restorev i)))
+          (restore! dim count)
+          (lp (1+ i))))))
+
+  (cond
+   ((zero? (vector-length shape))
+    (proc*))
+   (else
+    (let recur ((dim 0))
+      (match (vector-ref shape dim)
+        (#(start count dst-inc)
+         (if (eq? (1+ dim) (vector-length shape))
+             (let lp ((n 0))
+               (cond
+                ((= n count)
+                 (restore-src-offsets! dim count))
+                (else
+                 (proc*)
+                 (advance-src-offsets! dim)
+                 (lp (1+ n)))))
+             (let lp ((n 0))
+               (cond
+                ((= n count)
+                 (restore-src-offsets! dim count))
+                (else
+                 (recur (1+ dim))
+                 (advance-src-offsets! dim)
+                 (lp (1+ n)))))))))))
+  *unspecified*)
+
+(define array-for-each
+  (case-lambda
+   ((proc array)
+    (array-for-each1 proc array))
+   ((proc array . arrays)
+    (array-for-each* proc (cons array arrays)))))
+
+(define (array-index-map! array proc)
+  "Apply @var{proc} to the indices of each element of @var{ra} in
+turn, storing the result in the corresponding element.  The value
+returned and the order of application are unspecified.
+
+One can implement @var{array-indexes} as
+@lisp
+(define (array-indexes array)
+    (let ((ra (apply make-array #f (array-shape array))))
+      (array-index-map! ra (lambda x x))
+      ra))
+@end lisp
+Another example:
+@lisp
+(define (apl:index-generator n)
+    (let ((v (make-uniform-vector n 1)))
+      (array-index-map! v (lambda (i) i))
+      v))
+@end lisp"
+  (match (array-dimensions array)
+    (() (array-set! array (proc)))
+    ((dim)
+     (let lp ((n (dim-start dim)))
+       (unless (eqv? n (dim-end dim))
+         (array-set! array (proc n) n)
+         (lp (1+ n)))))
+    (dims
+     (let recur ((head '()) (dims dims))
+       (match dims
+         ((dim)
+          (let lp ((n (dim-start dim)))
+            (unless (eqv? n (dim-end dim))
+              (let ((idx (append head (list n))))
+                (apply array-set! array (apply proc idx) idx))
+              (lp (1+ n)))))
+         ((dim . dims)
+          (let lp ((n (dim-start dim)))
+            (unless (eqv? n (dim-end dim))
+              (recur (append head (list n)) dims)
+              (lp (1+ n))))))))))
+
+(define array-equal?
+  (case-lambda
+   "Return @code{#t} iff all arguments are arrays with the same
+shape, the same type, and have corresponding elements which are either
+@code{equal?}  or @code{array-equal?}.  This function differs from
+@code{equal?} in that all arguments must be arrays."
+   (() #t)
+   ((a) #t)
+   ((a b)
+    (define (slices-equal? a b dims)
+      (match dims
+        ((dim . dims)
+         (define (recur a b)
+           (if (null? dims)
+               (equal? a b)
+               (slices-equal? a b dims)))
+         (define (dim-start dim)
+           (match dim ((start end) start) (end 0)))
+         (define (dim-end dim)
+           (match dim ((start end) end) (end end)))
+         (let lp ((n (dim-start dim)))
+           (or (eqv? n (dim-end dim))
+               (and (recur (array-cell-ref a n)
+                           (array-cell-ref b n))
+                    (lp (1+ n))))))))
+    
+    (and (equal? (array-dimensions a) (array-dimensions b))
+         (match (array-type a)
+           ((or 'vu8 'u8)
+            ;; R6RS and Guile mostly use #vu8(...) as the literal syntax
+            ;; for bytevectors, but R7RS uses #u8.  To allow R7RS users
+            ;; to re-use the various routines implemented on bytevectors
+            ;; which return vu8-tagged values and to also be able to do
+            ;; (equal? #u8(1 2 3) (bytevector 1 2 3)), we allow equality
+            ;; comparisons between vu8 and u8.
+            (match (array-type b)
+              ((or 'vu8 'u8) #t)
+              (_ #f)))
+           (ta (eq? ta (array-type b))))
+         (if (zero? (array-rank a))
+             (equal? (array-ref a) (array-ref b))
+             (slices-equal? a b (array-dimensions a)))))
+
+   ((a b . rest)
+    (and (array-equal? a b)
+         (apply array-equal? b rest)))))
+
+(define (array-slice-for-each frame-rank proc . arrays)
+  "Apply @var{op} to each of the cells of rank rank(@var{arg})-@var{frame_rank}
+of the arrays @var{args}, in unspecified order. The first
+@var{frame-rank} dimensions of each @var{arg} must match.  Rank-0 cells
+are passed as rank-0 arrays.  The value returned is unspecified.
+
+For example:
+@lisp
+;; Sort the rows of rank-2 array A.
+(array-slice-for-each 1 (lambda (x) (sort! x <)) a)
+
+;; Compute the arguments of the (x y) vectors in the rows of rank-2
+;; array XYS and store them in rank-1 array ANGLES. Inside OP,
+;; XY is a rank-1 (2-1) array, and ANGLE is a rank-0 (1-1) array.
+
+(array-slice-for-each 1 
+  (lambda (xy angle)
+    (array-set! angle (atan (array-ref xy 1) (array-ref xy 0))))
+  xys angles)
+@end lisp"
+  (match arrays
+    (() (values))
+    ((head tail ...)
+     (let ((dims (array-dimensions head)))
+       (unless (<= frame-rank (length dims))
+         (error "frame too large for argument" frame-rank head))
+       (define frame-dims (list-head dims frame-rank))
+       (for-each (lambda (array)
+                   (define dims (array-dimensions array))
+                   (unless (<= frame-rank (length dims))
+                     (error "frame too large for argument" frame-rank array))
+                   (unless (equal? (list-head dims frame-rank) frame-dims)
+                     (error "mismatched frames" frame-dims array)))
+                 tail)
+       (let recur ((arrays arrays)
+                   (frame-dims frame-dims))
+         (match frame-dims
+           (()
+            (apply proc arrays))
+           ((dim . frame-dims)
+            (let slice ((n (dim-start dim)))
+              (when (< n (dim-end dim))
+                (recur (map (lambda (array) (array-slice array n)) arrays)
+                       frame-dims)
+                (slice (1+ n))))))))))
+  *unspecified*)
+
+(define (array-slice-for-each-in-order frame-rank proc . arrays)
+  "Same as array-slice-for-each, but visit the cells sequentially
+and in row-major order."
+  (apply array-slice-for-each frame-rank proc arrays))
+
+(define (array-cell-ref array . indices)
+  "Return the element at the @code{(@var{indices} ...)} position
+in array @var{ra}, or the array slice @var{ra}[@var{indices} ..., ...]
+if the rank of @var{ra} is larger than the number of indices.
+
+See also @code{array-ref}, @code{array-slice}, @code{array-cell-set!}.
+
+@code{array-cell-ref} never returns a rank 0 array. For example:
+@lisp
+(array-cell-ref #2((1 2 3) (4 5 6)) 1 1) @result{} 5
+(array-cell-ref #2((1 2 3) (4 5 6)) 1) @result{} #(4 5 6)
+(array-cell-ref #2((1 2 3) (4 5 6))) @result{} #2((1 2 3) (4 5 6))
+(array-cell-ref #0(5) @result{} 5.
+@end lisp"
+  (if (= (length indices) (array-rank array))
+      (apply array-ref array indices)
+      (apply array-slice array indices)))
+
+(define (array-cell-set! array val . indices)
+  "Set the array slice @var{ra}[@var{indices} ..., ...] to @var{b}.
+
+Equivalent to @code{(array-copy! @var{b} (apply array-cell-ref @var{ra}
+@var{indices}))} if the number of indices is smaller than the rank of
+@var{ra}; otherwise equivalent to @code{(apply array-set! @var{ra}
+@var{b} @var{indices})}.  This function returns the modified array
+@var{ra}.
+
+See also @code{array-ref}, @code{array-cell-ref}, @code{array-slice}.
+
+For example:
+@lisp
+(define A (list->array 2 '((1 2 3) (4 5 6))))
+(array-cell-set! A #0(99) 1 1) @result{} #2((1 2 3) (4 #0(99) 6))
+(array-cell-set! A 99 1 1) @result{} #2((1 2 3) (4 99 6))
+(array-cell-set! A #(a b c) 0) @result{} #2((a b c) (4 99 6))
+(array-cell-set! A #2((x y z) (9 8 7))) @result{} #2((x y z) (9 8 7))
+
+(define B (make-array 0))
+(array-cell-set! B 15) @result{} #0(15)
+@end lisp"
+  (if (= (length indices) (array-rank array))
+      (apply array-set! array val indices)
+      (array-copy! val (apply array-slice array indices)))
+  array)
+
 
 ;; Printing arrays
 
diff --git a/module/ice-9/deprecated.scm b/module/ice-9/deprecated.scm
index 6ff24c4c6..75f0e48a0 100644
--- a/module/ice-9/deprecated.scm
+++ b/module/ice-9/deprecated.scm
@@ -20,6 +20,7 @@
   #:use-module (ice-9 object-properties)
   #:use-module (ice-9 source-properties)
   #:use-module (ice-9 weak-tables)
+  #:use-module (ice-9 arrays)
   #:export ((make-guardian* . make-guardian)
             module-observe-weak
             (make-object-property* . make-object-property)
@@ -34,7 +35,16 @@
             (set-source-properties!* . set-source-properties!)
             (source-property* . source-property)
             (set-source-properties* . set-source-property!)
-            (cons-source* . cons-source)))
+            (cons-source* . cons-source)
+            (array-fill!* . array-fill!)
+            (array-copy!* . array-copy!)
+            (array-copy-in-order!* . array-copy-in-order!)
+            (array-map!* . array-map!)
+            (array-for-each* . array-for-each)
+            (array-index-map!* . array-index-map!)
+            (array-equal?* . array-equal?)
+            (array-slice-for-each* . array-slice-for-each)
+            (array-slice-for-each-in-order* . array-slice-for-each-in-order)))
 
 #;
 (define-syntax-rule (define-deprecated name message exp)
@@ -158,3 +168,69 @@ Import it from (ice-9 source-properties) instead.")
    "cons-source in the default environment is deprecated.
 Import it from (ice-9 source-properties) instead.")
   (cons-source orig x y))
+
+(define (array-fill!* array fill)
+  (issue-deprecation-warning
+   "array-fill! in the default environment is deprecated.
+Import it from (ice-9 arrays) instead.")
+  (array-fill! array fill))
+
+(define (array-copy!* src dst)
+  (issue-deprecation-warning
+   "array-copy! in the default environment is deprecated.
+Import it from (ice-9 arrays) instead.")
+  (array-copy! src dst))
+
+(define (array-copy-in-order!* src dst)
+  (issue-deprecation-warning
+   "array-copy-in-order! in the default environment is deprecated.
+Import it from (ice-9 arrays) instead.")
+  (array-copy-in-order! src dst))
+
+(define (array-map!* dst proc . src*)
+  (issue-deprecation-warning
+   "array-map! in the default environment is deprecated.
+Import it from (ice-9 arrays) instead.")
+  (apply array-map! dst proc src*))
+
+(define (array-for-each* proc array . arrays)
+  (issue-deprecation-warning
+   "array-for-each in the default environment is deprecated.
+Import it from (ice-9 arrays) instead.")
+  (apply array-for-each proc array arrays))
+
+(define (array-index-map!* array proc)
+  (issue-deprecation-warning
+   "array-index-map! in the default environment is deprecated.
+Import it from (ice-9 arrays) instead.")
+  (array-index-map! array proc))
+
+(define (array-equal?* . arrays)
+  (issue-deprecation-warning
+   "array-equal? in the default environment is deprecated.
+Import it from (ice-9 arrays) instead.")
+  (apply array-equal? arrays))
+
+(define (array-slice-for-each* frame-rank proc . arrays)
+  (issue-deprecation-warning
+   "array-slice-for-each in the default environment is deprecated.
+Import it from (ice-9 arrays) instead.")
+  (apply array-slice-for-each frame-rank proc arrays))
+
+(define (array-slice-for-each-in-order* frame-rank proc . arrays)
+  (issue-deprecation-warning
+   "array-slice-for-each-in-order in the default environment is deprecated.
+Import it from (ice-9 arrays) instead.")
+  (apply array-slice-for-each-in-order frame-rank proc arrays))
+
+(define (array-cell-ref* array . indices)
+  (issue-deprecation-warning
+   "array-cell-ref in the default environment is deprecated.
+Import it from (ice-9 arrays) instead.")
+  (apply array-cell-ref array indices))
+
+(define (array-cell-set!* array val . indices)
+  (issue-deprecation-warning
+   "array-cell-set! in the default environment is deprecated.
+Import it from (ice-9 arrays) instead.")
+  (apply array-cell-set! array val indices))
diff --git a/module/ice-9/pretty-print.scm b/module/ice-9/pretty-print.scm
index 4bc951ebf..3007afda1 100644
--- a/module/ice-9/pretty-print.scm
+++ b/module/ice-9/pretty-print.scm
@@ -1,7 +1,7 @@
 ;;;; -*- coding: utf-8; mode: scheme -*-
 ;;;;
 ;;;;   Copyright (C) 2001, 2004, 2006, 2009, 2010,
-;;;;      2012, 2013, 2014, 2023 Free Software Foundation, Inc.
+;;;;      2012, 2013, 2014, 2023, 2025 Free Software Foundation, Inc.
 ;;;; 
 ;;;; This library is free software; you can redistribute it and/or
 ;;;; modify it under the terms of the GNU Lesser General Public
@@ -23,6 +23,7 @@
   #:use-module (rnrs bytevectors)
   #:use-module (ice-9 soft-ports)
   #:use-module (ice-9 textual-ports)
+  #:use-module (ice-9 arrays)
   #:export (pretty-print
             truncated-print))
 
diff --git a/module/oop/goops/save.scm b/module/oop/goops/save.scm
index 6dda93eac..24df57864 100644
--- a/module/oop/goops/save.scm
+++ b/module/oop/goops/save.scm
@@ -21,6 +21,7 @@
 (define-module (oop goops save)
   #:use-module (ice-9 copy-tree)
   #:use-module (ice-9 weak-tables)
+  #:use-module (ice-9 arrays)
   #:use-module (oop goops internal)
   #:export (make-unbound save-objects load-objects restore
            enumerate! enumerate-component!
diff --git a/test-suite/tests/array-map.test b/test-suite/tests/array-map.test
index 25b4aaa9d..a55f1fd73 100644
--- a/test-suite/tests/array-map.test
+++ b/test-suite/tests/array-map.test
@@ -1,6 +1,6 @@
 ;;;; array-map.test --- test array mapping functions -*- scheme -*-
 ;;;;
-;;;; Copyright (C) 2004, 2005, 2006, 2009, 2013 Free Software Foundation, Inc.
+;;;; Copyright (C) 2004, 2005, 2006, 2009, 2013, 2025 Free Software 
Foundation, Inc.
 ;;;;
 ;;;; This library is free software; you can redistribute it and/or
 ;;;; modify it under the terms of the GNU Lesser General Public
@@ -17,7 +17,8 @@
 ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 
USA
 
 (define-module (test-suite test-array-map)
-  #:use-module (test-suite lib))
+  #:use-module (test-suite lib)
+  #:use-module (ice-9 arrays))
 
 (define exception:shape-mismatch
   (cons 'misc-error ".*shape mismatch.*"))
diff --git a/test-suite/tests/arrays.test b/test-suite/tests/arrays.test
index 3bf433582..edc5e28a8 100644
--- a/test-suite/tests/arrays.test
+++ b/test-suite/tests/arrays.test
@@ -1,6 +1,6 @@
 ;;;; arrays.test --- tests guile's uniform arrays     -*- scheme -*-
 ;;;;
-;;;; Copyright 2004, 2006, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Free
+;;;; Copyright 2004, 2006, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2025 Free
 ;;;; Software Foundation, Inc.
 ;;;;
 ;;;; This library is free software; you can redistribute it and/or
@@ -20,6 +20,7 @@
 (define-module (test-suite test-arrays)
   #:use-module ((system base compile) #:select (compile))
   #:use-module (test-suite lib)
+  #:use-module (ice-9 arrays)
   #:use-module (srfi srfi-4)
   #:use-module (srfi srfi-4 gnu))
 
@@ -656,7 +657,7 @@
        (array-fill! a 128))
       (pass-if-exception "-129" exception:out-of-range
        (array-fill! a -129))
-      (pass-if-exception "symbol" exception:wrong-type-arg
+      (pass-if-exception "symbol" exception:out-of-range
        (array-fill! a 'symbol))))
 
   (with-test-prefix "short"

Reply via email to