Simplify scm_array_get_handle for tc7-arrays
[bpt/guile.git] / libguile / array-map.c
CommitLineData
72e2b592 1/* Copyright (C) 1996, 1998, 2000, 2001, 2004, 2005, 2006, 2008, 2009,
5e8c9d4a 2 * 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
0f2d19dd 3 *
73be1d9e 4 * This library is free software; you can redistribute it and/or
53befeb7
NJ
5 * modify it under the terms of the GNU Lesser General Public License
6 * as published by the Free Software Foundation; either version 3 of
7 * the License, or (at your option) any later version.
0f2d19dd 8 *
53befeb7
NJ
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
0f2d19dd 13 *
73be1d9e
MV
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
53befeb7
NJ
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301 USA
73be1d9e 18 */
1bbd0b84 19
1bbd0b84 20
0f2d19dd
JB
21\f
22
23
24\f
dbb605f5
LC
25#ifdef HAVE_CONFIG_H
26# include <config.h>
27#endif
0f2d19dd 28
a0599745 29#include "libguile/_scm.h"
405aaef9 30#include "libguile/strings.h"
2fa901a5 31#include "libguile/arrays.h"
a0599745
MD
32#include "libguile/smob.h"
33#include "libguile/chars.h"
34#include "libguile/eq.h"
35#include "libguile/eval.h"
36#include "libguile/feature.h"
37#include "libguile/root.h"
38#include "libguile/vectors.h"
cf396142 39#include "libguile/bitvectors.h"
b4bdadde 40#include "libguile/srfi-4.h"
1030b450 41#include "libguile/generalized-arrays.h"
a0599745
MD
42
43#include "libguile/validate.h"
5d1b3b2d 44#include "libguile/array-map.h"
0f2d19dd
JB
45\f
46
d66b74dc
LC
47/* The WHAT argument for `scm_gc_malloc ()' et al. */
48static const char indices_gc_hint[] = "array-indices";
49
5e8c9d4a
DL
50static SCM
51AREF (SCM v, size_t pos)
52{
53 return scm_c_array_ref_1 (v, pos);
54}
0f2d19dd 55
5e8c9d4a
DL
56static void
57ASET (SCM v, size_t pos, SCM val)
58{
59 scm_c_array_set_1_x (v, val, pos);
60}
c209c88e 61
c014a02e 62static unsigned long
b4b33636 63cind (SCM ra, long *ve)
0f2d19dd 64{
c014a02e 65 unsigned long i;
0f2d19dd 66 int k;
04b87de5 67 if (!SCM_I_ARRAYP (ra))
0f2d19dd 68 return *ve;
04b87de5
MV
69 i = SCM_I_ARRAY_BASE (ra);
70 for (k = 0; k < SCM_I_ARRAY_NDIM (ra); k++)
71 i += (ve[k] - SCM_I_ARRAY_DIMS (ra)[k].lbnd) * SCM_I_ARRAY_DIMS (ra)[k].inc;
0f2d19dd
JB
72 return i;
73}
74
75
76/* Checker for scm_array mapping functions:
8269f0be
DL
77 return values:
78 5 --> empty axes;
79 4 --> shapes, increments, and bases are the same;
0f2d19dd
JB
80 3 --> shapes and increments are the same;
81 2 --> shapes are the same;
82 1 --> ras are at least as big as ra0;
83 0 --> no match.
84 */
1cc91f1b 85
8269f0be 86int
6e8d25a6 87scm_ra_matchp (SCM ra0, SCM ras)
0f2d19dd 88{
8269f0be
DL
89 int i, exact = 4, empty = 0;
90 scm_t_array_handle h0;
399aba0a 91
8269f0be
DL
92 scm_array_get_handle (ra0, &h0);
93 for (i = 0; i < h0.ndims; ++i)
f0521cda 94 {
8269f0be 95 empty = empty || (h0.dims[i].lbnd > h0.dims[i].ubnd);
f0521cda 96 }
399aba0a 97
62fdadb0 98 while (scm_is_pair (ras))
c209c88e 99 {
8269f0be 100 scm_t_array_handle h1;
16259ae3 101
8269f0be 102 scm_array_get_handle (SCM_CAR (ras), &h1);
16259ae3 103
8269f0be
DL
104 if (h0.ndims != h1.ndims)
105 {
106 scm_array_handle_release (&h0);
107 scm_array_handle_release (&h1);
108 return 0;
109 }
110 if (h0.base != h1.base)
111 exact = min(3, exact);
399aba0a 112
8269f0be
DL
113 for (i = 0; i < h0.ndims; ++i)
114 {
115 empty = empty || (h1.dims[i].lbnd > h1.dims[i].ubnd);
116 switch (exact)
117 {
118 case 4:
119 case 3:
120 if (h0.dims[i].inc != h1.dims[i].inc)
121 exact = 2;
122 case 2:
123 if (h0.dims[i].lbnd == h1.dims[i].lbnd && h0.dims[i].ubnd == h1.dims[i].ubnd)
124 break;
125 exact = 1;
126 default:
127 if (h0.dims[i].lbnd < h1.dims[i].lbnd || h0.dims[i].ubnd > h1.dims[i].ubnd)
128 {
129 scm_array_handle_release (&h0);
130 scm_array_handle_release (&h1);
131 return 0;
132 }
133 }
134 }
135 scm_array_handle_release (&h1);
c209c88e
GB
136 ras = SCM_CDR (ras);
137 }
8269f0be
DL
138 scm_array_handle_release (&h0);
139 return empty ? 5 : exact;
0f2d19dd
JB
140}
141
8269f0be 142/* array mapper: apply cproc to each dimension of the given arrays?.
1bbd0b84 143 int (*cproc) (); procedure to call on unrolled arrays?
5c11cc9d 144 cproc (dest, source list) or
8269f0be
DL
145 cproc (dest, data, source list).
146 SCM data; data to give to cproc or unbound.
1bbd0b84
GB
147 SCM ra0; destination array.
148 SCM lra; list of source arrays.
149 const char *what; caller, for error reporting. */
8269f0be 150int
10b9343f 151scm_ramapc (void *cproc_ptr, SCM data, SCM ra0, SCM lra, const char *what)
0f2d19dd 152{
b4b33636 153 SCM z;
0f2d19dd
JB
154 SCM vra0, ra1, vra1;
155 SCM lvra, *plvra;
c014a02e 156 long *vinds;
0f2d19dd 157 int k, kmax;
13af75bf 158 int (*cproc) () = cproc_ptr;
10b9343f 159
0f2d19dd
JB
160 switch (scm_ra_matchp (ra0, lra))
161 {
162 default:
163 case 0:
9cf5d9b7 164 scm_misc_error (what, "array shape mismatch: ~S", scm_list_1 (ra0));
0f2d19dd
JB
165 case 2:
166 case 3:
167 case 4: /* Try unrolling arrays */
04b87de5 168 kmax = (SCM_I_ARRAYP (ra0) ? SCM_I_ARRAY_NDIM (ra0) - 1 : 0);
0f2d19dd
JB
169 if (kmax < 0)
170 goto gencase;
171 vra0 = scm_array_contents (ra0, SCM_UNDEFINED);
19239bbf
DL
172 if (scm_is_false (vra0))
173 goto gencase;
04b87de5 174 if (!SCM_I_ARRAYP (vra0))
0f2d19dd 175 {
16259ae3 176 size_t length = scm_c_array_length (vra0);
66b9d7d3 177 vra1 = scm_i_make_array (1);
04b87de5
MV
178 SCM_I_ARRAY_BASE (vra1) = 0;
179 SCM_I_ARRAY_DIMS (vra1)->lbnd = 0;
180 SCM_I_ARRAY_DIMS (vra1)->ubnd = length - 1;
181 SCM_I_ARRAY_DIMS (vra1)->inc = 1;
182 SCM_I_ARRAY_V (vra1) = vra0;
0f2d19dd
JB
183 vra0 = vra1;
184 }
185 lvra = SCM_EOL;
186 plvra = &lvra;
62fdadb0 187 for (z = lra; scm_is_pair (z); z = SCM_CDR (z))
0f2d19dd
JB
188 {
189 ra1 = SCM_CAR (z);
66b9d7d3 190 vra1 = scm_i_make_array (1);
04b87de5
MV
191 SCM_I_ARRAY_DIMS (vra1)->lbnd = SCM_I_ARRAY_DIMS (vra0)->lbnd;
192 SCM_I_ARRAY_DIMS (vra1)->ubnd = SCM_I_ARRAY_DIMS (vra0)->ubnd;
193 if (!SCM_I_ARRAYP (ra1))
0f2d19dd 194 {
04b87de5
MV
195 SCM_I_ARRAY_BASE (vra1) = 0;
196 SCM_I_ARRAY_DIMS (vra1)->inc = 1;
197 SCM_I_ARRAY_V (vra1) = ra1;
0f2d19dd 198 }
04b87de5 199 else if (!SCM_I_ARRAY_CONTP (ra1))
0f2d19dd
JB
200 goto gencase;
201 else
202 {
04b87de5
MV
203 SCM_I_ARRAY_BASE (vra1) = SCM_I_ARRAY_BASE (ra1);
204 SCM_I_ARRAY_DIMS (vra1)->inc = SCM_I_ARRAY_DIMS (ra1)[kmax].inc;
205 SCM_I_ARRAY_V (vra1) = SCM_I_ARRAY_V (ra1);
0f2d19dd
JB
206 }
207 *plvra = scm_cons (vra1, SCM_EOL);
25d8012c 208 plvra = SCM_CDRLOC (*plvra);
0f2d19dd
JB
209 }
210 return (SCM_UNBNDP (data) ? cproc(vra0, lvra) : cproc(vra0, data, lvra));
211 case 1:
212 gencase: /* Have to loop over all dimensions. */
66b9d7d3 213 vra0 = scm_i_make_array (1);
04b87de5 214 if (SCM_I_ARRAYP (ra0))
c209c88e 215 {
04b87de5 216 kmax = SCM_I_ARRAY_NDIM (ra0) - 1;
c209c88e 217 if (kmax < 0)
0f2d19dd 218 {
04b87de5
MV
219 SCM_I_ARRAY_DIMS (vra0)->lbnd = 0;
220 SCM_I_ARRAY_DIMS (vra0)->ubnd = 0;
221 SCM_I_ARRAY_DIMS (vra0)->inc = 1;
0f2d19dd 222 }
c209c88e
GB
223 else
224 {
04b87de5
MV
225 SCM_I_ARRAY_DIMS (vra0)->lbnd = SCM_I_ARRAY_DIMS (ra0)[kmax].lbnd;
226 SCM_I_ARRAY_DIMS (vra0)->ubnd = SCM_I_ARRAY_DIMS (ra0)[kmax].ubnd;
227 SCM_I_ARRAY_DIMS (vra0)->inc = SCM_I_ARRAY_DIMS (ra0)[kmax].inc;
c209c88e 228 }
04b87de5
MV
229 SCM_I_ARRAY_BASE (vra0) = SCM_I_ARRAY_BASE (ra0);
230 SCM_I_ARRAY_V (vra0) = SCM_I_ARRAY_V (ra0);
c209c88e
GB
231 }
232 else
233 {
16259ae3 234 size_t length = scm_c_array_length (ra0);
c209c88e 235 kmax = 0;
04b87de5
MV
236 SCM_I_ARRAY_DIMS (vra0)->lbnd = 0;
237 SCM_I_ARRAY_DIMS (vra0)->ubnd = length - 1;
238 SCM_I_ARRAY_DIMS (vra0)->inc = 1;
239 SCM_I_ARRAY_BASE (vra0) = 0;
240 SCM_I_ARRAY_V (vra0) = ra0;
c209c88e
GB
241 ra0 = vra0;
242 }
243 lvra = SCM_EOL;
244 plvra = &lvra;
62fdadb0 245 for (z = lra; scm_is_pair (z); z = SCM_CDR (z))
c209c88e
GB
246 {
247 ra1 = SCM_CAR (z);
66b9d7d3 248 vra1 = scm_i_make_array (1);
04b87de5
MV
249 SCM_I_ARRAY_DIMS (vra1)->lbnd = SCM_I_ARRAY_DIMS (vra0)->lbnd;
250 SCM_I_ARRAY_DIMS (vra1)->ubnd = SCM_I_ARRAY_DIMS (vra0)->ubnd;
251 if (SCM_I_ARRAYP (ra1))
c209c88e
GB
252 {
253 if (kmax >= 0)
04b87de5
MV
254 SCM_I_ARRAY_DIMS (vra1)->inc = SCM_I_ARRAY_DIMS (ra1)[kmax].inc;
255 SCM_I_ARRAY_V (vra1) = SCM_I_ARRAY_V (ra1);
c209c88e
GB
256 }
257 else
258 {
04b87de5
MV
259 SCM_I_ARRAY_DIMS (vra1)->inc = 1;
260 SCM_I_ARRAY_V (vra1) = ra1;
c209c88e
GB
261 }
262 *plvra = scm_cons (vra1, SCM_EOL);
263 plvra = SCM_CDRLOC (*plvra);
264 }
b4b33636 265
d66b74dc
LC
266 vinds = scm_gc_malloc_pointerless (sizeof(long) * SCM_I_ARRAY_NDIM (ra0),
267 indices_gc_hint);
b4b33636 268
c209c88e 269 for (k = 0; k <= kmax; k++)
04b87de5 270 vinds[k] = SCM_I_ARRAY_DIMS (ra0)[k].lbnd;
c209c88e
GB
271 k = kmax;
272 do
273 {
274 if (k == kmax)
275 {
276 SCM y = lra;
04b87de5 277 SCM_I_ARRAY_BASE (vra0) = cind (ra0, vinds);
62fdadb0 278 for (z = lvra; scm_is_pair (z); z = SCM_CDR (z), y = SCM_CDR (y))
04b87de5 279 SCM_I_ARRAY_BASE (SCM_CAR (z)) = cind (SCM_CAR (y), vinds);
c209c88e
GB
280 if (0 == (SCM_UNBNDP (data) ? cproc(vra0, lvra) : cproc(vra0, data, lvra)))
281 return 0;
282 k--;
283 continue;
284 }
04b87de5 285 if (vinds[k] < SCM_I_ARRAY_DIMS (ra0)[k].ubnd)
c209c88e
GB
286 {
287 vinds[k]++;
288 k++;
289 continue;
290 }
04b87de5 291 vinds[k] = SCM_I_ARRAY_DIMS (ra0)[k].lbnd - 1;
c209c88e
GB
292 k--;
293 }
294 while (k >= 0);
b4b33636 295
8269f0be 296 case 5:
c209c88e 297 return 1;
0f2d19dd
JB
298 }
299}
300
ab1ca179
DL
301static int
302rafill (SCM dst, SCM fill)
303{
304 long n = (SCM_I_ARRAY_DIMS (dst)->ubnd - SCM_I_ARRAY_DIMS (dst)->lbnd + 1);
305 scm_t_array_handle h;
306 size_t i;
307 ssize_t inc;
48ffc52c 308 scm_array_get_handle (SCM_I_ARRAY_V (dst), &h);
13af75bf
DL
309 i = SCM_I_ARRAY_BASE (dst);
310 inc = SCM_I_ARRAY_DIMS (dst)->inc;
ab1ca179
DL
311
312 for (; n-- > 0; i += inc)
cf64dca6 313 h.vset (h.vector, i, fill);
ab1ca179
DL
314
315 scm_array_handle_release (&h);
316 return 1;
317}
0f2d19dd 318
3b3b36dd 319SCM_DEFINE (scm_array_fill_x, "array-fill!", 2, 0, 0,
c209c88e 320 (SCM ra, SCM fill),
b7e64f8b
BT
321 "Store @var{fill} in every element of array @var{ra}. The value\n"
322 "returned is unspecified.")
1bbd0b84 323#define FUNC_NAME s_scm_array_fill_x
ad310508 324{
ab1ca179 325 scm_ramapc (rafill, fill, ra, SCM_EOL, FUNC_NAME);
ad310508
MD
326 return SCM_UNSPECIFIED;
327}
1bbd0b84 328#undef FUNC_NAME
ad310508 329
0f2d19dd 330
72e2b592 331static int
1bbd0b84 332racp (SCM src, SCM dst)
0f2d19dd 333{
04b87de5 334 long n = (SCM_I_ARRAY_DIMS (src)->ubnd - SCM_I_ARRAY_DIMS (src)->lbnd + 1);
72e2b592
DL
335 scm_t_array_handle h_s, h_d;
336 size_t i_s, i_d;
337 ssize_t inc_s, inc_d;
338
0f2d19dd 339 dst = SCM_CAR (dst);
48ffc52c
DL
340 scm_array_get_handle (SCM_I_ARRAY_V (src), &h_s);
341 scm_array_get_handle (SCM_I_ARRAY_V (dst), &h_d);
72e2b592 342
13af75bf
DL
343 i_s = SCM_I_ARRAY_BASE (src);
344 i_d = SCM_I_ARRAY_BASE (dst);
345 inc_s = SCM_I_ARRAY_DIMS (src)->inc;
346 inc_d = SCM_I_ARRAY_DIMS (dst)->inc;
c209c88e 347
399aba0a 348 for (; n-- > 0; i_s += inc_s, i_d += inc_d)
cf64dca6 349 h_d.vset (h_d.vector, i_d, h_s.vref (h_s.vector, i_s));
72e2b592
DL
350
351 scm_array_handle_release (&h_d);
352 scm_array_handle_release (&h_s);
353
0f2d19dd
JB
354 return 1;
355}
356
1bbd0b84 357SCM_REGISTER_PROC(s_array_copy_in_order_x, "array-copy-in-order!", 2, 0, 0, scm_array_copy_x);
1cc91f1b 358
1bbd0b84 359
3b3b36dd 360SCM_DEFINE (scm_array_copy_x, "array-copy!", 2, 0, 0,
c209c88e 361 (SCM src, SCM dst),
8f85c0c6 362 "@deffnx {Scheme Procedure} array-copy-in-order! src dst\n"
b7e64f8b
BT
363 "Copy every element from vector or array @var{src} to the\n"
364 "corresponding element of @var{dst}. @var{dst} must have the\n"
365 "same rank as @var{src}, and be at least as large in each\n"
b380b885 366 "dimension. The order is unspecified.")
1bbd0b84 367#define FUNC_NAME s_scm_array_copy_x
0f2d19dd 368{
c209c88e 369 scm_ramapc (racp, SCM_UNDEFINED, src, scm_cons (dst, SCM_EOL), FUNC_NAME);
0f2d19dd
JB
370 return SCM_UNSPECIFIED;
371}
1bbd0b84 372#undef FUNC_NAME
0f2d19dd 373
0f2d19dd 374
75a1b26c 375#if SCM_ENABLE_DEPRECATED == 1
1cc91f1b 376
d09b201d
DL
377/* to be used as cproc in scm_ramapc to fill an array dimension with
378 "fill". */
379int
380scm_array_fill_int (SCM ra, SCM fill, SCM ignore SCM_UNUSED)
381{
382 unsigned long i;
383 unsigned long n = SCM_I_ARRAY_DIMS (ra)->ubnd - SCM_I_ARRAY_DIMS (ra)->lbnd + 1;
384 long inc = SCM_I_ARRAY_DIMS (ra)->inc;
385 unsigned long base = SCM_I_ARRAY_BASE (ra);
386
387 ra = SCM_I_ARRAY_V (ra);
388
389 for (i = base; n--; i += inc)
5e8c9d4a 390 ASET (ra, i, fill);
d09b201d
DL
391
392 return 1;
393}
394
395/* Functions callable by ARRAY-MAP! */
1cc91f1b 396
0f2d19dd 397int
1bbd0b84 398scm_ra_eqp (SCM ra0, SCM ras)
0f2d19dd
JB
399{
400 SCM ra1 = SCM_CAR (ras), ra2 = SCM_CAR (SCM_CDR (ras));
fab07c30
MV
401 scm_t_array_handle ra0_handle;
402 scm_t_array_dim *ra0_dims;
403 size_t n;
404 ssize_t inc0;
405 size_t i0 = 0;
406 unsigned long i1 = SCM_I_ARRAY_BASE (ra1), i2 = SCM_I_ARRAY_BASE (ra2);
04b87de5
MV
407 long inc1 = SCM_I_ARRAY_DIMS (ra1)->inc;
408 long inc2 = SCM_I_ARRAY_DIMS (ra1)->inc;
04b87de5
MV
409 ra1 = SCM_I_ARRAY_V (ra1);
410 ra2 = SCM_I_ARRAY_V (ra2);
fab07c30
MV
411
412 scm_array_get_handle (ra0, &ra0_handle);
413 ra0_dims = scm_array_handle_dims (&ra0_handle);
414 n = ra0_dims[0].ubnd - ra0_dims[0].lbnd + 1;
415 inc0 = ra0_dims[0].inc;
416
399aba0a 417 {
399aba0a 418 for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2)
fab07c30 419 if (scm_is_true (scm_array_handle_ref (&ra0_handle, i0)))
5e8c9d4a 420 if (!scm_is_eq (AREF (ra1, i1), AREF (ra2, i2)))
fab07c30 421 scm_array_handle_set (&ra0_handle, i0, SCM_BOOL_F);
399aba0a
MV
422 }
423
fab07c30 424 scm_array_handle_release (&ra0_handle);
0f2d19dd
JB
425 return 1;
426}
427
428/* opt 0 means <, nonzero means >= */
1cc91f1b 429
0f2d19dd 430static int
34d19ef6 431ra_compare (SCM ra0, SCM ra1, SCM ra2, int opt)
0f2d19dd 432{
fab07c30
MV
433 scm_t_array_handle ra0_handle;
434 scm_t_array_dim *ra0_dims;
435 size_t n;
436 ssize_t inc0;
437 size_t i0 = 0;
438 unsigned long i1 = SCM_I_ARRAY_BASE (ra1), i2 = SCM_I_ARRAY_BASE (ra2);
04b87de5
MV
439 long inc1 = SCM_I_ARRAY_DIMS (ra1)->inc;
440 long inc2 = SCM_I_ARRAY_DIMS (ra1)->inc;
04b87de5
MV
441 ra1 = SCM_I_ARRAY_V (ra1);
442 ra2 = SCM_I_ARRAY_V (ra2);
399aba0a 443
fab07c30
MV
444 scm_array_get_handle (ra0, &ra0_handle);
445 ra0_dims = scm_array_handle_dims (&ra0_handle);
446 n = ra0_dims[0].ubnd - ra0_dims[0].lbnd + 1;
447 inc0 = ra0_dims[0].inc;
448
399aba0a 449 {
399aba0a 450 for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2)
fab07c30 451 if (scm_is_true (scm_array_handle_ref (&ra0_handle, i0)))
399aba0a 452 if (opt ?
5e8c9d4a
DL
453 scm_is_true (scm_less_p (AREF (ra1, i1), AREF (ra2, i2))) :
454 scm_is_false (scm_less_p (AREF (ra1, i1), AREF (ra2, i2))))
fab07c30 455 scm_array_handle_set (&ra0_handle, i0, SCM_BOOL_F);
399aba0a
MV
456 }
457
fab07c30 458 scm_array_handle_release (&ra0_handle);
0f2d19dd
JB
459 return 1;
460}
461
462
1cc91f1b 463
0f2d19dd 464int
1bbd0b84 465scm_ra_lessp (SCM ra0, SCM ras)
0f2d19dd
JB
466{
467 return ra_compare (ra0, SCM_CAR (ras), SCM_CAR (SCM_CDR (ras)), 0);
468}
469
1cc91f1b 470
0f2d19dd 471int
1bbd0b84 472scm_ra_leqp (SCM ra0, SCM ras)
0f2d19dd
JB
473{
474 return ra_compare (ra0, SCM_CAR (SCM_CDR (ras)), SCM_CAR (ras), 1);
475}
476
1cc91f1b 477
0f2d19dd 478int
1bbd0b84 479scm_ra_grp (SCM ra0, SCM ras)
0f2d19dd
JB
480{
481 return ra_compare (ra0, SCM_CAR (SCM_CDR (ras)), SCM_CAR (ras), 0);
482}
483
1cc91f1b 484
0f2d19dd 485int
1bbd0b84 486scm_ra_greqp (SCM ra0, SCM ras)
0f2d19dd
JB
487{
488 return ra_compare (ra0, SCM_CAR (ras), SCM_CAR (SCM_CDR (ras)), 1);
489}
490
491
0f2d19dd 492int
1bbd0b84 493scm_ra_sum (SCM ra0, SCM ras)
0f2d19dd 494{
04b87de5
MV
495 long n = SCM_I_ARRAY_DIMS (ra0)->ubnd - SCM_I_ARRAY_DIMS (ra0)->lbnd + 1;
496 unsigned long i0 = SCM_I_ARRAY_BASE (ra0);
497 long inc0 = SCM_I_ARRAY_DIMS (ra0)->inc;
498 ra0 = SCM_I_ARRAY_V (ra0);
d2e53ed6 499 if (!scm_is_null(ras))
c209c88e
GB
500 {
501 SCM ra1 = SCM_CAR (ras);
04b87de5
MV
502 unsigned long i1 = SCM_I_ARRAY_BASE (ra1);
503 long inc1 = SCM_I_ARRAY_DIMS (ra1)->inc;
504 ra1 = SCM_I_ARRAY_V (ra1);
c209c88e
GB
505 switch (SCM_TYP7 (ra0) == SCM_TYP7 (ra1) ? SCM_TYP7 (ra0) : 0)
506 {
507 default:
0f2d19dd 508 {
c209c88e 509 for (; n-- > 0; i0 += inc0, i1 += inc1)
5e8c9d4a 510 ASET (ra0, i0, scm_sum (AREF(ra0, i0), AREF(ra1, i1)));
c209c88e
GB
511 break;
512 }
c209c88e
GB
513 }
514 }
0f2d19dd
JB
515 return 1;
516}
517
518
1cc91f1b 519
0f2d19dd 520int
1bbd0b84 521scm_ra_difference (SCM ra0, SCM ras)
0f2d19dd 522{
04b87de5
MV
523 long n = SCM_I_ARRAY_DIMS (ra0)->ubnd - SCM_I_ARRAY_DIMS (ra0)->lbnd + 1;
524 unsigned long i0 = SCM_I_ARRAY_BASE (ra0);
525 long inc0 = SCM_I_ARRAY_DIMS (ra0)->inc;
526 ra0 = SCM_I_ARRAY_V (ra0);
d2e53ed6 527 if (scm_is_null (ras))
c209c88e
GB
528 {
529 switch (SCM_TYP7 (ra0))
530 {
531 default:
532 {
c209c88e 533 for (; n-- > 0; i0 += inc0)
5e8c9d4a 534 ASET (ra0, i0, scm_difference (AREF(ra0, i0), SCM_UNDEFINED));
c209c88e
GB
535 break;
536 }
c209c88e
GB
537 }
538 }
0f2d19dd
JB
539 else
540 {
541 SCM ra1 = SCM_CAR (ras);
04b87de5
MV
542 unsigned long i1 = SCM_I_ARRAY_BASE (ra1);
543 long inc1 = SCM_I_ARRAY_DIMS (ra1)->inc;
544 ra1 = SCM_I_ARRAY_V (ra1);
0f2d19dd
JB
545 switch (SCM_TYP7 (ra0) == SCM_TYP7 (ra1) ? SCM_TYP7 (ra0) : 0)
546 {
547 default:
548 {
0f2d19dd 549 for (; n-- > 0; i0 += inc0, i1 += inc1)
5e8c9d4a 550 ASET (ra0, i0, scm_difference (AREF (ra0, i0), AREF (ra1, i1)));
0f2d19dd
JB
551 break;
552 }
0f2d19dd
JB
553 }
554 }
555 return 1;
556}
557
558
1cc91f1b 559
0f2d19dd 560int
1bbd0b84 561scm_ra_product (SCM ra0, SCM ras)
0f2d19dd 562{
04b87de5
MV
563 long n = SCM_I_ARRAY_DIMS (ra0)->ubnd - SCM_I_ARRAY_DIMS (ra0)->lbnd + 1;
564 unsigned long i0 = SCM_I_ARRAY_BASE (ra0);
565 long inc0 = SCM_I_ARRAY_DIMS (ra0)->inc;
566 ra0 = SCM_I_ARRAY_V (ra0);
d2e53ed6 567 if (!scm_is_null (ras))
c209c88e
GB
568 {
569 SCM ra1 = SCM_CAR (ras);
04b87de5
MV
570 unsigned long i1 = SCM_I_ARRAY_BASE (ra1);
571 long inc1 = SCM_I_ARRAY_DIMS (ra1)->inc;
572 ra1 = SCM_I_ARRAY_V (ra1);
c209c88e
GB
573 switch (SCM_TYP7 (ra0) == SCM_TYP7 (ra1) ? SCM_TYP7 (ra0) : 0)
574 {
575 default:
0f2d19dd 576 {
c209c88e 577 for (; n-- > 0; i0 += inc0, i1 += inc1)
5e8c9d4a 578 ASET (ra0, i0, scm_product (AREF (ra0, i0), AREF (ra1, i1)));
c209c88e 579 }
c209c88e
GB
580 }
581 }
0f2d19dd
JB
582 return 1;
583}
584
1cc91f1b 585
0f2d19dd 586int
1bbd0b84 587scm_ra_divide (SCM ra0, SCM ras)
0f2d19dd 588{
04b87de5
MV
589 long n = SCM_I_ARRAY_DIMS (ra0)->ubnd - SCM_I_ARRAY_DIMS (ra0)->lbnd + 1;
590 unsigned long i0 = SCM_I_ARRAY_BASE (ra0);
591 long inc0 = SCM_I_ARRAY_DIMS (ra0)->inc;
592 ra0 = SCM_I_ARRAY_V (ra0);
d2e53ed6 593 if (scm_is_null (ras))
c209c88e
GB
594 {
595 switch (SCM_TYP7 (ra0))
596 {
597 default:
598 {
c209c88e 599 for (; n-- > 0; i0 += inc0)
5e8c9d4a 600 ASET (ra0, i0, scm_divide (AREF (ra0, i0), SCM_UNDEFINED));
c209c88e
GB
601 break;
602 }
c209c88e
GB
603 }
604 }
0f2d19dd
JB
605 else
606 {
607 SCM ra1 = SCM_CAR (ras);
04b87de5
MV
608 unsigned long i1 = SCM_I_ARRAY_BASE (ra1);
609 long inc1 = SCM_I_ARRAY_DIMS (ra1)->inc;
610 ra1 = SCM_I_ARRAY_V (ra1);
0f2d19dd
JB
611 switch (SCM_TYP7 (ra0) == SCM_TYP7 (ra1) ? SCM_TYP7 (ra0) : 0)
612 {
613 default:
614 {
0f2d19dd 615 for (; n-- > 0; i0 += inc0, i1 += inc1)
afaf9d0b 616 {
5e8c9d4a
DL
617 SCM res = scm_divide (AREF (ra0, i0), AREF (ra1, i1));
618 ASET (ra0, i0, res);
afaf9d0b 619 }
0f2d19dd
JB
620 break;
621 }
0f2d19dd
JB
622 }
623 }
624 return 1;
625}
626
1cc91f1b 627
0f2d19dd 628int
1bbd0b84 629scm_array_identity (SCM dst, SCM src)
0f2d19dd
JB
630{
631 return racp (SCM_CAR (src), scm_cons (dst, SCM_EOL));
632}
633
75a1b26c 634#endif /* SCM_ENABLE_DEPRECATED */
0f2d19dd 635
75a1b26c 636static int
34d19ef6 637ramap (SCM ra0, SCM proc, SCM ras)
0f2d19dd 638{
9a68d7b3 639 ssize_t i = SCM_I_ARRAY_DIMS (ra0)->lbnd;
51a1763f 640 size_t n = SCM_I_ARRAY_DIMS (ra0)->ubnd - i + 1;
9a68d7b3 641
51a1763f
DL
642 scm_t_array_handle h0;
643 size_t i0, i0end;
644 ssize_t inc0;
48ffc52c 645 scm_array_get_handle (SCM_I_ARRAY_V (ra0), &h0);
13af75bf
DL
646 i0 = SCM_I_ARRAY_BASE (ra0);
647 inc0 = SCM_I_ARRAY_DIMS (ra0)->inc;
51a1763f 648 i0end = i0 + n*inc0;
d2e53ed6 649 if (scm_is_null (ras))
9a68d7b3 650 for (; i0 < i0end; i0 += inc0)
cf64dca6 651 h0.vset (h0.vector, i0, scm_call_0 (proc));
0f2d19dd
JB
652 else
653 {
654 SCM ra1 = SCM_CAR (ras);
51a1763f
DL
655 scm_t_array_handle h1;
656 size_t i1;
657 ssize_t inc1;
48ffc52c 658 scm_array_get_handle (SCM_I_ARRAY_V (ra1), &h1);
13af75bf
DL
659 i1 = SCM_I_ARRAY_BASE (ra1);
660 inc1 = SCM_I_ARRAY_DIMS (ra1)->inc;
9a68d7b3 661 ras = SCM_CDR (ras);
51a1763f 662 if (scm_is_null (ras))
9a68d7b3 663 for (; i0 < i0end; i0 += inc0, i1 += inc1)
cf64dca6 664 h0.vset (h0.vector, i0, scm_call_1 (proc, h1.vref (h1.vector, i1)));
9a68d7b3
DL
665 else
666 {
667 ras = scm_vector (ras);
668 for (; i0 < i0end; i0 += inc0, i1 += inc1, ++i)
669 {
670 SCM args = SCM_EOL;
671 unsigned long k;
672 for (k = scm_c_vector_length (ras); k--;)
5e8c9d4a 673 args = scm_cons (AREF (scm_c_vector_ref (ras, k), i), args);
cf64dca6
AW
674 h0.vset (h0.vector, i0,
675 scm_apply_1 (proc, h1.vref (h1.vector, i1), args));
9a68d7b3
DL
676 }
677 }
51a1763f 678 scm_array_handle_release (&h1);
0f2d19dd 679 }
51a1763f 680 scm_array_handle_release (&h0);
0f2d19dd
JB
681 return 1;
682}
683
1cc91f1b 684
1bbd0b84 685SCM_REGISTER_PROC(s_array_map_in_order_x, "array-map-in-order!", 2, 0, 1, scm_array_map_x);
1cc91f1b 686
718866aa 687SCM_SYMBOL (sym_b, "b");
1bbd0b84 688
3b3b36dd 689SCM_DEFINE (scm_array_map_x, "array-map!", 2, 0, 1,
c209c88e 690 (SCM ra0, SCM proc, SCM lra),
8f85c0c6 691 "@deffnx {Scheme Procedure} array-map-in-order! ra0 proc . lra\n"
b7e64f8b
BT
692 "@var{array1}, @dots{} must have the same number of dimensions\n"
693 "as @var{ra0} and have a range for each index which includes the\n"
694 "range for the corresponding index in @var{ra0}. @var{proc} is\n"
695 "applied to each tuple of elements of @var{array1}, @dots{} and\n"
696 "the result is stored as the corresponding element in @var{ra0}.\n"
697 "The value returned is unspecified. The order of application is\n"
698 "unspecified.")
1bbd0b84 699#define FUNC_NAME s_scm_array_map_x
0f2d19dd 700{
34d19ef6 701 SCM_VALIDATE_PROC (2, proc);
af45e3b0 702 SCM_VALIDATE_REST_ARGUMENT (lra);
f530e94f 703
31d845b4
AW
704 scm_ramapc (ramap, proc, ra0, lra, FUNC_NAME);
705 return SCM_UNSPECIFIED;
0f2d19dd 706}
1bbd0b84 707#undef FUNC_NAME
0f2d19dd 708
1cc91f1b 709
0f2d19dd 710static int
34d19ef6 711rafe (SCM ra0, SCM proc, SCM ras)
0f2d19dd 712{
c3e3ef6e
DL
713 ssize_t i = SCM_I_ARRAY_DIMS (ra0)->lbnd;
714 size_t n = SCM_I_ARRAY_DIMS (ra0)->ubnd - i + 1;
715
716 scm_t_array_handle h0;
717 size_t i0, i0end;
718 ssize_t inc0;
48ffc52c 719 scm_array_get_handle (SCM_I_ARRAY_V (ra0), &h0);
13af75bf
DL
720 i0 = SCM_I_ARRAY_BASE (ra0);
721 inc0 = SCM_I_ARRAY_DIMS (ra0)->inc;
c3e3ef6e 722 i0end = i0 + n*inc0;
d2e53ed6 723 if (scm_is_null (ras))
c3e3ef6e 724 for (; i0 < i0end; i0 += inc0)
cf64dca6 725 scm_call_1 (proc, h0.vref (h0.vector, i0));
0f2d19dd
JB
726 else
727 {
c3e3ef6e
DL
728 ras = scm_vector (ras);
729 for (; i0 < i0end; i0 += inc0, ++i)
730 {
731 SCM args = SCM_EOL;
732 unsigned long k;
733 for (k = scm_c_vector_length (ras); k--;)
5e8c9d4a 734 args = scm_cons (AREF (scm_c_vector_ref (ras, k), i), args);
cf64dca6 735 scm_apply_1 (proc, h0.vref (h0.vector, i0), args);
c3e3ef6e 736 }
0f2d19dd 737 }
c3e3ef6e 738 scm_array_handle_release (&h0);
0f2d19dd
JB
739 return 1;
740}
741
3b3b36dd 742SCM_DEFINE (scm_array_for_each, "array-for-each", 2, 0, 1,
c209c88e 743 (SCM proc, SCM ra0, SCM lra),
b7e64f8b 744 "Apply @var{proc} to each tuple of elements of @var{ra0} @dots{}\n"
b380b885 745 "in row-major order. The value returned is unspecified.")
1bbd0b84 746#define FUNC_NAME s_scm_array_for_each
0f2d19dd 747{
34d19ef6 748 SCM_VALIDATE_PROC (1, proc);
af45e3b0 749 SCM_VALIDATE_REST_ARGUMENT (lra);
c209c88e 750 scm_ramapc (rafe, proc, ra0, lra, FUNC_NAME);
0f2d19dd
JB
751 return SCM_UNSPECIFIED;
752}
1bbd0b84 753#undef FUNC_NAME
0f2d19dd 754
828ada13 755static void
f0521cda
AW
756array_index_map_1 (SCM ra, SCM proc)
757{
828ada13
AW
758 scm_t_array_handle h;
759 ssize_t i, inc;
760 size_t p;
828ada13 761 scm_array_get_handle (ra, &h);
828ada13
AW
762 inc = h.dims[0].inc;
763 for (i = h.dims[0].lbnd, p = h.base; i <= h.dims[0].ubnd; ++i, p += inc)
cf64dca6 764 h.vset (h.vector, p, scm_call_1 (proc, scm_from_ulong (i)));
828ada13 765 scm_array_handle_release (&h);
f0521cda
AW
766}
767
768/* Here we assume that the array is a scm_tc7_array, as that is the only
769 kind of array in Guile that supports rank > 1. */
828ada13 770static void
f0521cda
AW
771array_index_map_n (SCM ra, SCM proc)
772{
828ada13 773 size_t i;
f0521cda
AW
774 SCM args = SCM_EOL;
775 int j, k, kmax = SCM_I_ARRAY_NDIM (ra) - 1;
f0521cda
AW
776 long *vinds;
777
778 vinds = scm_gc_malloc_pointerless (sizeof(long) * SCM_I_ARRAY_NDIM (ra),
779 indices_gc_hint);
780
781 for (k = 0; k <= kmax; k++)
b0d9b074
DL
782 {
783 vinds[k] = SCM_I_ARRAY_DIMS (ra)[k].lbnd;
784 if (vinds[k] > SCM_I_ARRAY_DIMS (ra)[k].ubnd)
785 return;
786 }
f0521cda
AW
787 k = kmax;
788 do
789 {
790 if (k == kmax)
791 {
792 vinds[k] = SCM_I_ARRAY_DIMS (ra)[k].lbnd;
793 i = cind (ra, vinds);
794 for (; vinds[k] <= SCM_I_ARRAY_DIMS (ra)[k].ubnd; vinds[k]++)
795 {
796 for (j = kmax + 1, args = SCM_EOL; j--;)
797 args = scm_cons (scm_from_long (vinds[j]), args);
798 ASET (SCM_I_ARRAY_V (ra), i, scm_apply_0 (proc, args));
799 i += SCM_I_ARRAY_DIMS (ra)[k].inc;
800 }
801 k--;
f0521cda 802 }
b0d9b074 803 else if (vinds[k] < SCM_I_ARRAY_DIMS (ra)[k].ubnd)
f0521cda
AW
804 {
805 vinds[k]++;
806 k++;
f0521cda 807 }
b0d9b074
DL
808 else
809 {
810 vinds[k] = SCM_I_ARRAY_DIMS (ra)[k].lbnd - 1;
811 k--;
812 }
f0521cda
AW
813 }
814 while (k >= 0);
f0521cda
AW
815}
816
3b3b36dd 817SCM_DEFINE (scm_array_index_map_x, "array-index-map!", 2, 0, 0,
c209c88e 818 (SCM ra, SCM proc),
b7e64f8b 819 "Apply @var{proc} to the indices of each element of @var{ra} in\n"
b380b885
MD
820 "turn, storing the result in the corresponding element. The value\n"
821 "returned and the order of application are unspecified.\n\n"
822 "One can implement @var{array-indexes} as\n"
1e6808ea 823 "@lisp\n"
b380b885
MD
824 "(define (array-indexes array)\n"
825 " (let ((ra (apply make-array #f (array-shape array))))\n"
826 " (array-index-map! ra (lambda x x))\n"
827 " ra))\n"
1e6808ea 828 "@end lisp\n"
b380b885 829 "Another example:\n"
1e6808ea 830 "@lisp\n"
b380b885
MD
831 "(define (apl:index-generator n)\n"
832 " (let ((v (make-uniform-vector n 1)))\n"
833 " (array-index-map! v (lambda (i) i))\n"
834 " v))\n"
1e6808ea 835 "@end lisp")
1bbd0b84 836#define FUNC_NAME s_scm_array_index_map_x
0f2d19dd 837{
34d19ef6 838 SCM_VALIDATE_PROC (2, proc);
399aba0a 839
f0521cda 840 switch (scm_c_array_rank (ra))
16259ae3 841 {
f0521cda
AW
842 case 0:
843 scm_array_set_x (ra, scm_call_0 (proc), SCM_EOL);
844 break;
845 case 1:
846 array_index_map_1 (ra, proc);
847 break;
848 default:
849 array_index_map_n (ra, proc);
850 break;
16259ae3 851 }
b4b33636 852
f0521cda 853 return SCM_UNSPECIFIED;
0f2d19dd 854}
1bbd0b84 855#undef FUNC_NAME
0f2d19dd 856
1cc91f1b 857
0f2d19dd 858static int
a587d6a9
AW
859array_compare (scm_t_array_handle *hx, scm_t_array_handle *hy,
860 size_t dim, unsigned long posx, unsigned long posy)
0f2d19dd 861{
a587d6a9
AW
862 if (dim == scm_array_handle_rank (hx))
863 return scm_is_true (scm_equal_p (scm_array_handle_ref (hx, posx),
864 scm_array_handle_ref (hy, posy)));
e466c6a2 865 else
c209c88e 866 {
a587d6a9
AW
867 long incx, incy;
868 size_t i;
399aba0a 869
a587d6a9
AW
870 if (hx->dims[dim].lbnd != hy->dims[dim].lbnd
871 || hx->dims[dim].ubnd != hy->dims[dim].ubnd)
872 return 0;
873
874 i = hx->dims[dim].ubnd - hx->dims[dim].lbnd + 1;
875
876 incx = hx->dims[dim].inc;
877 incy = hy->dims[dim].inc;
878 posx += (i - 1) * incx;
879 posy += (i - 1) * incy;
880
881 for (; i > 0; i--, posx -= incx, posy -= incy)
882 if (!array_compare (hx, hy, dim + 1, posx, posy))
883 return 0;
c209c88e 884 return 1;
c209c88e 885 }
0f2d19dd
JB
886}
887
a587d6a9
AW
888SCM
889scm_array_equal_p (SCM x, SCM y)
0f2d19dd 890{
a587d6a9
AW
891 scm_t_array_handle hx, hy;
892 SCM res;
893
894 scm_array_get_handle (x, &hx);
895 scm_array_get_handle (y, &hy);
896
897 res = scm_from_bool (hx.ndims == hy.ndims
898 && hx.element_type == hy.element_type);
3ffd1ba9 899
a587d6a9
AW
900 if (scm_is_true (res))
901 res = scm_from_bool (array_compare (&hx, &hy, 0, 0, 0));
0f2d19dd 902
a587d6a9
AW
903 scm_array_handle_release (&hy);
904 scm_array_handle_release (&hx);
1cc91f1b 905
a587d6a9 906 return res;
0f2d19dd
JB
907}
908
f1d19308 909static SCM scm_i_array_equal_p (SCM, SCM, SCM);
31d845b4
AW
910SCM_DEFINE (scm_i_array_equal_p, "array-equal?", 0, 2, 1,
911 (SCM ra0, SCM ra1, SCM rest),
1e6808ea
MG
912 "Return @code{#t} iff all arguments are arrays with the same\n"
913 "shape, the same type, and have corresponding elements which are\n"
914 "either @code{equal?} or @code{array-equal?}. This function\n"
a587d6a9 915 "differs from @code{equal?} in that all arguments must be arrays.")
31d845b4
AW
916#define FUNC_NAME s_scm_i_array_equal_p
917{
918 if (SCM_UNBNDP (ra0) || SCM_UNBNDP (ra1))
919 return SCM_BOOL_T;
920
921 while (!scm_is_null (rest))
8a1f4f98 922 { if (scm_is_false (scm_array_equal_p (ra0, ra1)))
31d845b4 923 return SCM_BOOL_F;
8a1f4f98
AW
924 ra0 = ra1;
925 ra1 = scm_car (rest);
31d845b4
AW
926 rest = scm_cdr (rest);
927 }
928 return scm_array_equal_p (ra0, ra1);
0f981281 929}
4079f87e 930#undef FUNC_NAME
0f2d19dd 931
1cc91f1b 932
0f2d19dd 933void
5d1b3b2d 934scm_init_array_map (void)
0f2d19dd 935{
5d1b3b2d 936#include "libguile/array-map.x"
1bbd0b84 937 scm_add_feature (s_scm_array_for_each);
0f2d19dd 938}
89e00824
ML
939
940/*
941 Local Variables:
942 c-file-style: "gnu"
943 End:
944*/