boot_closure_print cleanup
[bpt/guile.git] / libguile / arrays.c
CommitLineData
03976fee 1/* Copyright (C) 1995,1996,1997,1998,2000,2001,2002,2003,2004, 2005, 2006, 2009, 2010, 2011 Free Software Foundation, Inc.
0f2d19dd 2 *
73be1d9e 3 * This library is free software; you can redistribute it and/or
53befeb7
NJ
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
0f2d19dd 7 *
53befeb7
NJ
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
0f2d19dd 12 *
73be1d9e
MV
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
53befeb7
NJ
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
73be1d9e 17 */
1bbd0b84 18
1bbd0b84 19
0f2d19dd
JB
20\f
21
dbb605f5 22#ifdef HAVE_CONFIG_H
2a5cd898
RB
23# include <config.h>
24#endif
25
0f2d19dd 26#include <stdio.h>
e6e2e95a 27#include <errno.h>
783e7774 28#include <string.h>
e6e2e95a 29
a0599745 30#include "libguile/_scm.h"
e0e49670
MV
31#include "libguile/__scm.h"
32#include "libguile/eq.h"
a0599745
MD
33#include "libguile/chars.h"
34#include "libguile/eval.h"
35#include "libguile/fports.h"
36#include "libguile/smob.h"
a0599745
MD
37#include "libguile/feature.h"
38#include "libguile/root.h"
39#include "libguile/strings.h"
c44ca4fe 40#include "libguile/srfi-13.h"
e0e49670 41#include "libguile/srfi-4.h"
a0599745 42#include "libguile/vectors.h"
cf396142 43#include "libguile/bitvectors.h"
438974d0 44#include "libguile/bytevectors.h"
bfad4005 45#include "libguile/list.h"
d44ff083 46#include "libguile/dynwind.h"
943a0a87 47#include "libguile/read.h"
a0599745
MD
48
49#include "libguile/validate.h"
2fa901a5 50#include "libguile/arrays.h"
943a0a87 51#include "libguile/array-map.h"
f332e957 52#include "libguile/generalized-vectors.h"
943a0a87 53#include "libguile/generalized-arrays.h"
476b894c 54#include "libguile/uniform.h"
0f2d19dd 55
0f2d19dd 56
04b87de5 57scm_t_bits scm_i_tc16_array;
04b87de5 58#define SCM_SET_ARRAY_CONTIGUOUS_FLAG(x) \
c395cb78 59 (SCM_SET_SMOB_FLAGS ((x), SCM_SMOB_FLAGS (x) | SCM_I_ARRAY_FLAG_CONTIGUOUS))
04b87de5 60#define SCM_CLR_ARRAY_CONTIGUOUS_FLAG(x) \
c395cb78 61 (SCM_SET_SMOB_FLAGS ((x), SCM_SMOB_FLAGS (x) & ~SCM_I_ARRAY_FLAG_CONTIGUOUS))
1cc91f1b 62
0f2d19dd 63
e2d37336
MD
64SCM_DEFINE (scm_shared_array_root, "shared-array-root", 1, 0, 0,
65 (SCM ra),
66 "Return the root vector of a shared array.")
67#define FUNC_NAME s_scm_shared_array_root
68{
66b9d7d3 69 if (SCM_I_ARRAYP (ra))
04b87de5 70 return SCM_I_ARRAY_V (ra);
52372719
MV
71 else if (scm_is_generalized_vector (ra))
72 return ra;
943a0a87 73 scm_wrong_type_arg_msg (FUNC_NAME, SCM_ARG1, ra, "array");
e2d37336
MD
74}
75#undef FUNC_NAME
76
77
78SCM_DEFINE (scm_shared_array_offset, "shared-array-offset", 1, 0, 0,
79 (SCM ra),
80 "Return the root vector index of the first element in the array.")
81#define FUNC_NAME s_scm_shared_array_offset
82{
52372719
MV
83 scm_t_array_handle handle;
84 SCM res;
85
86 scm_array_get_handle (ra, &handle);
87 res = scm_from_size_t (handle.base);
88 scm_array_handle_release (&handle);
89 return res;
e2d37336
MD
90}
91#undef FUNC_NAME
92
93
94SCM_DEFINE (scm_shared_array_increments, "shared-array-increments", 1, 0, 0,
95 (SCM ra),
96 "For each dimension, return the distance between elements in the root vector.")
97#define FUNC_NAME s_scm_shared_array_increments
98{
52372719 99 scm_t_array_handle handle;
e2d37336 100 SCM res = SCM_EOL;
1be6b49c 101 size_t k;
92c2555f 102 scm_t_array_dim *s;
02339e5b 103
52372719
MV
104 scm_array_get_handle (ra, &handle);
105 k = scm_array_handle_rank (&handle);
106 s = scm_array_handle_dims (&handle);
e2d37336 107 while (k--)
52372719
MV
108 res = scm_cons (scm_from_ssize_t (s[k].inc), res);
109 scm_array_handle_release (&handle);
e2d37336
MD
110 return res;
111}
112#undef FUNC_NAME
113
0cd6cb2f 114SCM
66b9d7d3 115scm_i_make_array (int ndim)
0f2d19dd
JB
116{
117 SCM ra;
66b9d7d3 118 SCM_NEWSMOB(ra, ((scm_t_bits) ndim << 17) + scm_i_tc16_array,
04b87de5 119 scm_gc_malloc ((sizeof (scm_i_t_array) +
4c9419ac
MV
120 ndim * sizeof (scm_t_array_dim)),
121 "array"));
04b87de5 122 SCM_I_ARRAY_V (ra) = SCM_BOOL_F;
0f2d19dd
JB
123 return ra;
124}
125
126static char s_bad_spec[] = "Bad scm_array dimension";
0f2d19dd 127
1cc91f1b 128
02339e5b
MV
129/* Increments will still need to be set. */
130
0cd6cb2f
MV
131static SCM
132scm_i_shap2ra (SCM args)
0f2d19dd 133{
92c2555f 134 scm_t_array_dim *s;
0f2d19dd
JB
135 SCM ra, spec, sp;
136 int ndim = scm_ilength (args);
b3fcac34 137 if (ndim < 0)
0cd6cb2f 138 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
b3fcac34 139
66b9d7d3 140 ra = scm_i_make_array (ndim);
04b87de5
MV
141 SCM_I_ARRAY_BASE (ra) = 0;
142 s = SCM_I_ARRAY_DIMS (ra);
d2e53ed6 143 for (; !scm_is_null (args); s++, args = SCM_CDR (args))
0f2d19dd
JB
144 {
145 spec = SCM_CAR (args);
e11e83f3 146 if (scm_is_integer (spec))
0f2d19dd 147 {
e11e83f3 148 if (scm_to_long (spec) < 0)
0cd6cb2f 149 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
0f2d19dd 150 s->lbnd = 0;
e11e83f3 151 s->ubnd = scm_to_long (spec) - 1;
0f2d19dd
JB
152 s->inc = 1;
153 }
154 else
155 {
d2e53ed6 156 if (!scm_is_pair (spec) || !scm_is_integer (SCM_CAR (spec)))
0cd6cb2f 157 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
e11e83f3 158 s->lbnd = scm_to_long (SCM_CAR (spec));
0f2d19dd 159 sp = SCM_CDR (spec);
d2e53ed6 160 if (!scm_is_pair (sp)
e11e83f3 161 || !scm_is_integer (SCM_CAR (sp))
d2e53ed6 162 || !scm_is_null (SCM_CDR (sp)))
0cd6cb2f 163 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
e11e83f3 164 s->ubnd = scm_to_long (SCM_CAR (sp));
0f2d19dd
JB
165 s->inc = 1;
166 }
167 }
168 return ra;
169}
170
f301dbf3
MV
171SCM_DEFINE (scm_make_typed_array, "make-typed-array", 2, 0, 1,
172 (SCM type, SCM fill, SCM bounds),
173 "Create and return an array of type @var{type}.")
174#define FUNC_NAME s_scm_make_typed_array
0f2d19dd 175{
f301dbf3 176 size_t k, rlen = 1;
92c2555f 177 scm_t_array_dim *s;
0f2d19dd 178 SCM ra;
1be6b49c 179
0cd6cb2f 180 ra = scm_i_shap2ra (bounds);
e038c042 181 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
04b87de5
MV
182 s = SCM_I_ARRAY_DIMS (ra);
183 k = SCM_I_ARRAY_NDIM (ra);
1be6b49c 184
0f2d19dd
JB
185 while (k--)
186 {
a3a32939 187 s[k].inc = rlen;
2caaadd1 188 SCM_ASSERT_RANGE (1, bounds, s[k].lbnd <= s[k].ubnd + 1);
0f2d19dd 189 rlen = (s[k].ubnd - s[k].lbnd + 1) * s[k].inc;
0f2d19dd 190 }
a3a32939 191
f0b91039 192 if (scm_is_eq (fill, SCM_UNSPECIFIED))
f301dbf3 193 fill = SCM_UNDEFINED;
a3a32939 194
943a0a87
AW
195 SCM_I_ARRAY_V (ra) =
196 scm_make_generalized_vector (type, scm_from_size_t (rlen), fill);
a3a32939 197
04b87de5 198 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
c014a02e 199 if (s->ubnd < s->lbnd || (0 == s->lbnd && 1 == s->inc))
04b87de5 200 return SCM_I_ARRAY_V (ra);
0f2d19dd
JB
201 return ra;
202}
1bbd0b84 203#undef FUNC_NAME
0f2d19dd 204
782a82ee
AW
205SCM
206scm_from_contiguous_typed_array (SCM type, SCM bounds, const void *bytes,
207 size_t byte_len)
208#define FUNC_NAME "scm_from_contiguous_typed_array"
209{
210 size_t k, rlen = 1;
211 scm_t_array_dim *s;
782a82ee
AW
212 SCM ra;
213 scm_t_array_handle h;
f5a51cae 214 void *elts;
782a82ee
AW
215 size_t sz;
216
782a82ee
AW
217 ra = scm_i_shap2ra (bounds);
218 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
219 s = SCM_I_ARRAY_DIMS (ra);
220 k = SCM_I_ARRAY_NDIM (ra);
221
222 while (k--)
223 {
224 s[k].inc = rlen;
225 SCM_ASSERT_RANGE (1, bounds, s[k].lbnd <= s[k].ubnd + 1);
226 rlen = (s[k].ubnd - s[k].lbnd + 1) * s[k].inc;
227 }
943a0a87
AW
228 SCM_I_ARRAY_V (ra) =
229 scm_make_generalized_vector (type, scm_from_size_t (rlen), SCM_UNDEFINED);
782a82ee
AW
230
231
232 scm_array_get_handle (ra, &h);
f5a51cae
AW
233 elts = h.writable_elements;
234 sz = scm_array_handle_uniform_element_bit_size (&h);
782a82ee
AW
235 scm_array_handle_release (&h);
236
f5a51cae
AW
237 if (sz >= 8 && ((sz % 8) == 0))
238 {
239 if (byte_len % (sz / 8))
240 SCM_MISC_ERROR ("byte length not a multiple of the unit size", SCM_EOL);
241 if (byte_len / (sz / 8) != rlen)
242 SCM_MISC_ERROR ("byte length and dimensions do not match", SCM_EOL);
243 }
b0fae4ec 244 else if (sz < 8)
f5a51cae 245 {
cd48c32c
LC
246 /* byte_len ?= ceil (rlen * sz / 8) */
247 if (byte_len != (rlen * sz + 7) / 8)
f5a51cae
AW
248 SCM_MISC_ERROR ("byte length and dimensions do not match", SCM_EOL);
249 }
b0fae4ec
AW
250 else
251 /* an internal guile error, really */
252 SCM_MISC_ERROR ("uniform elements larger than 8 bits must fill whole bytes", SCM_EOL);
782a82ee 253
f5a51cae 254 memcpy (elts, bytes, byte_len);
782a82ee
AW
255
256 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
257 if (s->ubnd < s->lbnd || (0 == s->lbnd && 1 == s->inc))
258 return SCM_I_ARRAY_V (ra);
259 return ra;
260}
261#undef FUNC_NAME
262
73788ca8
AW
263SCM
264scm_from_contiguous_array (SCM bounds, const SCM *elts, size_t len)
265#define FUNC_NAME "scm_from_contiguous_array"
266{
267 size_t k, rlen = 1;
268 scm_t_array_dim *s;
269 SCM ra;
270 scm_t_array_handle h;
271
272 ra = scm_i_shap2ra (bounds);
273 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
274 s = SCM_I_ARRAY_DIMS (ra);
275 k = SCM_I_ARRAY_NDIM (ra);
276
277 while (k--)
278 {
279 s[k].inc = rlen;
280 SCM_ASSERT_RANGE (1, bounds, s[k].lbnd <= s[k].ubnd + 1);
281 rlen = (s[k].ubnd - s[k].lbnd + 1) * s[k].inc;
282 }
283 if (rlen != len)
284 SCM_MISC_ERROR ("element length and dimensions do not match", SCM_EOL);
285
286 SCM_I_ARRAY_V (ra) = scm_c_make_vector (rlen, SCM_UNDEFINED);
287 scm_array_get_handle (ra, &h);
288 memcpy (h.writable_elements, elts, rlen * sizeof(SCM));
289 scm_array_handle_release (&h);
290
291 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
292 if (s->ubnd < s->lbnd || (0 == s->lbnd && 1 == s->inc))
293 return SCM_I_ARRAY_V (ra);
294 return ra;
295}
296#undef FUNC_NAME
297
f301dbf3
MV
298SCM_DEFINE (scm_make_array, "make-array", 1, 0, 1,
299 (SCM fill, SCM bounds),
300 "Create and return an array.")
301#define FUNC_NAME s_scm_make_array
302{
303 return scm_make_typed_array (SCM_BOOL_T, fill, bounds);
304}
305#undef FUNC_NAME
306
0cd6cb2f
MV
307static void
308scm_i_ra_set_contp (SCM ra)
0f2d19dd 309{
04b87de5 310 size_t k = SCM_I_ARRAY_NDIM (ra);
0f2d19dd 311 if (k)
0f2d19dd 312 {
04b87de5 313 long inc = SCM_I_ARRAY_DIMS (ra)[k - 1].inc;
fe0c6dae 314 while (k--)
0f2d19dd 315 {
04b87de5 316 if (inc != SCM_I_ARRAY_DIMS (ra)[k].inc)
fe0c6dae 317 {
e038c042 318 SCM_CLR_ARRAY_CONTIGUOUS_FLAG (ra);
fe0c6dae
JB
319 return;
320 }
04b87de5
MV
321 inc *= (SCM_I_ARRAY_DIMS (ra)[k].ubnd
322 - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1);
0f2d19dd 323 }
0f2d19dd 324 }
e038c042 325 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
0f2d19dd
JB
326}
327
328
3b3b36dd 329SCM_DEFINE (scm_make_shared_array, "make-shared-array", 2, 0, 1,
1bbd0b84 330 (SCM oldra, SCM mapfunc, SCM dims),
b380b885
MD
331 "@code{make-shared-array} can be used to create shared subarrays of other\n"
332 "arrays. The @var{mapper} is a function that translates coordinates in\n"
333 "the new array into coordinates in the old array. A @var{mapper} must be\n"
334 "linear, and its range must stay within the bounds of the old array, but\n"
335 "it can be otherwise arbitrary. A simple example:\n"
1e6808ea 336 "@lisp\n"
b380b885
MD
337 "(define fred (make-array #f 8 8))\n"
338 "(define freds-diagonal\n"
339 " (make-shared-array fred (lambda (i) (list i i)) 8))\n"
340 "(array-set! freds-diagonal 'foo 3)\n"
341 "(array-ref fred 3 3) @result{} foo\n"
342 "(define freds-center\n"
343 " (make-shared-array fred (lambda (i j) (list (+ 3 i) (+ 3 j))) 2 2))\n"
344 "(array-ref freds-center 0 0) @result{} foo\n"
1e6808ea 345 "@end lisp")
1bbd0b84 346#define FUNC_NAME s_scm_make_shared_array
0f2d19dd 347{
112ba0ac 348 scm_t_array_handle old_handle;
0f2d19dd
JB
349 SCM ra;
350 SCM inds, indptr;
351 SCM imap;
112ba0ac
MV
352 size_t k;
353 ssize_t i;
2b829bbb 354 long old_base, old_min, new_min, old_max, new_max;
92c2555f 355 scm_t_array_dim *s;
b3fcac34
DH
356
357 SCM_VALIDATE_REST_ARGUMENT (dims);
34d19ef6 358 SCM_VALIDATE_PROC (2, mapfunc);
0cd6cb2f 359 ra = scm_i_shap2ra (dims);
112ba0ac
MV
360
361 scm_array_get_handle (oldra, &old_handle);
362
04b87de5 363 if (SCM_I_ARRAYP (oldra))
0f2d19dd 364 {
04b87de5 365 SCM_I_ARRAY_V (ra) = SCM_I_ARRAY_V (oldra);
2b829bbb 366 old_base = old_min = old_max = SCM_I_ARRAY_BASE (oldra);
112ba0ac
MV
367 s = scm_array_handle_dims (&old_handle);
368 k = scm_array_handle_rank (&old_handle);
0f2d19dd
JB
369 while (k--)
370 {
371 if (s[k].inc > 0)
372 old_max += (s[k].ubnd - s[k].lbnd) * s[k].inc;
373 else
374 old_min += (s[k].ubnd - s[k].lbnd) * s[k].inc;
375 }
376 }
377 else
378 {
04b87de5 379 SCM_I_ARRAY_V (ra) = oldra;
2b829bbb 380 old_base = old_min = 0;
02339e5b 381 old_max = scm_c_generalized_vector_length (oldra) - 1;
0f2d19dd 382 }
112ba0ac 383
0f2d19dd 384 inds = SCM_EOL;
04b87de5
MV
385 s = SCM_I_ARRAY_DIMS (ra);
386 for (k = 0; k < SCM_I_ARRAY_NDIM (ra); k++)
0f2d19dd 387 {
e11e83f3 388 inds = scm_cons (scm_from_long (s[k].lbnd), inds);
0f2d19dd
JB
389 if (s[k].ubnd < s[k].lbnd)
390 {
04b87de5 391 if (1 == SCM_I_ARRAY_NDIM (ra))
943a0a87
AW
392 ra = scm_make_generalized_vector (scm_array_type (ra),
393 SCM_INUM0, SCM_UNDEFINED);
0f2d19dd 394 else
943a0a87
AW
395 SCM_I_ARRAY_V (ra) =
396 scm_make_generalized_vector (scm_array_type (ra),
397 SCM_INUM0, SCM_UNDEFINED);
112ba0ac 398 scm_array_handle_release (&old_handle);
0f2d19dd
JB
399 return ra;
400 }
401 }
112ba0ac 402
fdc28395 403 imap = scm_apply_0 (mapfunc, scm_reverse (inds));
0cd6cb2f 404 i = scm_array_handle_pos (&old_handle, imap);
2b829bbb 405 SCM_I_ARRAY_BASE (ra) = new_min = new_max = i + old_base;
0f2d19dd 406 indptr = inds;
04b87de5 407 k = SCM_I_ARRAY_NDIM (ra);
0f2d19dd
JB
408 while (k--)
409 {
410 if (s[k].ubnd > s[k].lbnd)
411 {
e11e83f3 412 SCM_SETCAR (indptr, scm_sum (SCM_CAR (indptr), scm_from_int (1)));
fdc28395 413 imap = scm_apply_0 (mapfunc, scm_reverse (inds));
0cd6cb2f 414 s[k].inc = scm_array_handle_pos (&old_handle, imap) - i;
0f2d19dd
JB
415 i += s[k].inc;
416 if (s[k].inc > 0)
417 new_max += (s[k].ubnd - s[k].lbnd) * s[k].inc;
418 else
419 new_min += (s[k].ubnd - s[k].lbnd) * s[k].inc;
420 }
421 else
422 s[k].inc = new_max - new_min + 1; /* contiguous by default */
423 indptr = SCM_CDR (indptr);
424 }
112ba0ac
MV
425
426 scm_array_handle_release (&old_handle);
427
b3fcac34
DH
428 if (old_min > new_min || old_max < new_max)
429 SCM_MISC_ERROR ("mapping out of range", SCM_EOL);
04b87de5 430 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
0f2d19dd 431 {
04b87de5 432 SCM v = SCM_I_ARRAY_V (ra);
6e708ef2 433 size_t length = scm_c_generalized_vector_length (v);
74014c46
DH
434 if (1 == s->inc && 0 == s->lbnd && length == 1 + s->ubnd)
435 return v;
0f2d19dd 436 if (s->ubnd < s->lbnd)
943a0a87
AW
437 return scm_make_generalized_vector (scm_array_type (ra), SCM_INUM0,
438 SCM_UNDEFINED);
0f2d19dd 439 }
0cd6cb2f 440 scm_i_ra_set_contp (ra);
0f2d19dd
JB
441 return ra;
442}
1bbd0b84 443#undef FUNC_NAME
0f2d19dd
JB
444
445
446/* args are RA . DIMS */
af45e3b0
DH
447SCM_DEFINE (scm_transpose_array, "transpose-array", 1, 0, 1,
448 (SCM ra, SCM args),
1e6808ea
MG
449 "Return an array sharing contents with @var{array}, but with\n"
450 "dimensions arranged in a different order. There must be one\n"
451 "@var{dim} argument for each dimension of @var{array}.\n"
452 "@var{dim0}, @var{dim1}, @dots{} should be integers between 0\n"
453 "and the rank of the array to be returned. Each integer in that\n"
454 "range must appear at least once in the argument list.\n"
455 "\n"
456 "The values of @var{dim0}, @var{dim1}, @dots{} correspond to\n"
457 "dimensions in the array to be returned, their positions in the\n"
458 "argument list to dimensions of @var{array}. Several @var{dim}s\n"
459 "may have the same value, in which case the returned array will\n"
460 "have smaller rank than @var{array}.\n"
461 "\n"
462 "@lisp\n"
b380b885
MD
463 "(transpose-array '#2((a b) (c d)) 1 0) @result{} #2((a c) (b d))\n"
464 "(transpose-array '#2((a b) (c d)) 0 0) @result{} #1(a d)\n"
465 "(transpose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1 1 0) @result{}\n"
466 " #2((a 4) (b 5) (c 6))\n"
1e6808ea 467 "@end lisp")
1bbd0b84 468#define FUNC_NAME s_scm_transpose_array
0f2d19dd 469{
34d19ef6 470 SCM res, vargs;
92c2555f 471 scm_t_array_dim *s, *r;
0f2d19dd 472 int ndim, i, k;
af45e3b0 473
b3fcac34 474 SCM_VALIDATE_REST_ARGUMENT (args);
1bbd0b84 475 SCM_ASSERT (SCM_NIMP (ra), ra, SCM_ARG1, FUNC_NAME);
e0e49670 476
20930f28 477 if (scm_is_generalized_vector (ra))
e0e49670
MV
478 {
479 /* Make sure that we are called with a single zero as
480 arguments.
481 */
482 if (scm_is_null (args) || !scm_is_null (SCM_CDR (args)))
483 SCM_WRONG_NUM_ARGS ();
484 SCM_VALIDATE_INT_COPY (SCM_ARG2, SCM_CAR (args), i);
485 SCM_ASSERT_RANGE (SCM_ARG2, SCM_CAR (args), i == 0);
486 return ra;
487 }
488
66b9d7d3 489 if (SCM_I_ARRAYP (ra))
0f2d19dd 490 {
0f2d19dd 491 vargs = scm_vector (args);
04b87de5 492 if (SCM_SIMPLE_VECTOR_LENGTH (vargs) != SCM_I_ARRAY_NDIM (ra))
b3fcac34 493 SCM_WRONG_NUM_ARGS ();
0f2d19dd 494 ndim = 0;
04b87de5 495 for (k = 0; k < SCM_I_ARRAY_NDIM (ra); k++)
0f2d19dd 496 {
6e708ef2 497 i = scm_to_signed_integer (SCM_SIMPLE_VECTOR_REF (vargs, k),
04b87de5 498 0, SCM_I_ARRAY_NDIM(ra));
0f2d19dd
JB
499 if (ndim < i)
500 ndim = i;
501 }
502 ndim++;
66b9d7d3 503 res = scm_i_make_array (ndim);
04b87de5
MV
504 SCM_I_ARRAY_V (res) = SCM_I_ARRAY_V (ra);
505 SCM_I_ARRAY_BASE (res) = SCM_I_ARRAY_BASE (ra);
0f2d19dd
JB
506 for (k = ndim; k--;)
507 {
04b87de5
MV
508 SCM_I_ARRAY_DIMS (res)[k].lbnd = 0;
509 SCM_I_ARRAY_DIMS (res)[k].ubnd = -1;
0f2d19dd 510 }
04b87de5 511 for (k = SCM_I_ARRAY_NDIM (ra); k--;)
0f2d19dd 512 {
6e708ef2 513 i = scm_to_int (SCM_SIMPLE_VECTOR_REF (vargs, k));
04b87de5
MV
514 s = &(SCM_I_ARRAY_DIMS (ra)[k]);
515 r = &(SCM_I_ARRAY_DIMS (res)[i]);
0f2d19dd
JB
516 if (r->ubnd < r->lbnd)
517 {
518 r->lbnd = s->lbnd;
519 r->ubnd = s->ubnd;
520 r->inc = s->inc;
521 ndim--;
522 }
523 else
524 {
525 if (r->ubnd > s->ubnd)
526 r->ubnd = s->ubnd;
527 if (r->lbnd < s->lbnd)
528 {
04b87de5 529 SCM_I_ARRAY_BASE (res) += (s->lbnd - r->lbnd) * r->inc;
0f2d19dd
JB
530 r->lbnd = s->lbnd;
531 }
532 r->inc += s->inc;
533 }
534 }
b3fcac34
DH
535 if (ndim > 0)
536 SCM_MISC_ERROR ("bad argument list", SCM_EOL);
0cd6cb2f 537 scm_i_ra_set_contp (res);
0f2d19dd
JB
538 return res;
539 }
20930f28
MV
540
541 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
0f2d19dd 542}
1bbd0b84 543#undef FUNC_NAME
0f2d19dd 544
1d7bdb25
GH
545/* attempts to unroll an array into a one-dimensional array.
546 returns the unrolled array or #f if it can't be done. */
1bbd0b84 547 /* if strict is not SCM_UNDEFINED, return #f if returned array
1d7bdb25 548 wouldn't have contiguous elements. */
3b3b36dd 549SCM_DEFINE (scm_array_contents, "array-contents", 1, 1, 0,
1bbd0b84 550 (SCM ra, SCM strict),
b380b885
MD
551 "If @var{array} may be @dfn{unrolled} into a one dimensional shared array\n"
552 "without changing their order (last subscript changing fastest), then\n"
553 "@code{array-contents} returns that shared array, otherwise it returns\n"
554 "@code{#f}. All arrays made by @var{make-array} and\n"
555 "@var{make-uniform-array} may be unrolled, some arrays made by\n"
556 "@var{make-shared-array} may not be.\n\n"
557 "If the optional argument @var{strict} is provided, a shared array will\n"
558 "be returned only if its elements are stored internally contiguous in\n"
559 "memory.")
1bbd0b84 560#define FUNC_NAME s_scm_array_contents
0f2d19dd
JB
561{
562 SCM sra;
e0e49670 563
20930f28 564 if (scm_is_generalized_vector (ra))
e0e49670
MV
565 return ra;
566
04b87de5 567 if (SCM_I_ARRAYP (ra))
0f2d19dd 568 {
04b87de5
MV
569 size_t k, ndim = SCM_I_ARRAY_NDIM (ra), len = 1;
570 if (!SCM_I_ARRAYP (ra) || !SCM_I_ARRAY_CONTP (ra))
20930f28
MV
571 return SCM_BOOL_F;
572 for (k = 0; k < ndim; k++)
04b87de5 573 len *= SCM_I_ARRAY_DIMS (ra)[k].ubnd - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1;
943a0a87 574 if (!SCM_UNBNDP (strict) && scm_is_true (strict))
74014c46 575 {
04b87de5 576 if (ndim && (1 != SCM_I_ARRAY_DIMS (ra)[ndim - 1].inc))
20930f28 577 return SCM_BOOL_F;
04b87de5 578 if (scm_is_bitvector (SCM_I_ARRAY_V (ra)))
20930f28 579 {
04b87de5
MV
580 if (len != scm_c_bitvector_length (SCM_I_ARRAY_V (ra)) ||
581 SCM_I_ARRAY_BASE (ra) % SCM_LONG_BIT ||
20930f28
MV
582 len % SCM_LONG_BIT)
583 return SCM_BOOL_F;
584 }
74014c46 585 }
20930f28
MV
586
587 {
04b87de5 588 SCM v = SCM_I_ARRAY_V (ra);
20930f28 589 size_t length = scm_c_generalized_vector_length (v);
04b87de5 590 if ((len == length) && 0 == SCM_I_ARRAY_BASE (ra) && SCM_I_ARRAY_DIMS (ra)->inc)
20930f28 591 return v;
0f2d19dd 592 }
20930f28 593
66b9d7d3 594 sra = scm_i_make_array (1);
04b87de5
MV
595 SCM_I_ARRAY_DIMS (sra)->lbnd = 0;
596 SCM_I_ARRAY_DIMS (sra)->ubnd = len - 1;
597 SCM_I_ARRAY_V (sra) = SCM_I_ARRAY_V (ra);
598 SCM_I_ARRAY_BASE (sra) = SCM_I_ARRAY_BASE (ra);
599 SCM_I_ARRAY_DIMS (sra)->inc = (ndim ? SCM_I_ARRAY_DIMS (ra)[ndim - 1].inc : 1);
20930f28 600 return sra;
0f2d19dd 601 }
02339e5b
MV
602 else
603 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
0f2d19dd 604}
1bbd0b84 605#undef FUNC_NAME
0f2d19dd 606
1cc91f1b 607
943a0a87
AW
608static void
609list_to_array (SCM lst, scm_t_array_handle *handle, ssize_t pos, size_t k)
610{
611 if (k == scm_array_handle_rank (handle))
612 scm_array_handle_set (handle, pos, lst);
613 else
614 {
615 scm_t_array_dim *dim = scm_array_handle_dims (handle) + k;
616 ssize_t inc = dim->inc;
617 size_t len = 1 + dim->ubnd - dim->lbnd, n;
618 char *errmsg = NULL;
619
620 n = len;
621 while (n > 0 && scm_is_pair (lst))
622 {
623 list_to_array (SCM_CAR (lst), handle, pos, k + 1);
624 pos += inc;
625 lst = SCM_CDR (lst);
626 n -= 1;
627 }
628 if (n != 0)
629 errmsg = "too few elements for array dimension ~a, need ~a";
630 if (!scm_is_null (lst))
631 errmsg = "too many elements for array dimension ~a, want ~a";
632 if (errmsg)
633 scm_misc_error (NULL, errmsg, scm_list_2 (scm_from_ulong (k),
634 scm_from_size_t (len)));
635 }
636}
637
1cc91f1b 638
f301dbf3 639SCM_DEFINE (scm_list_to_typed_array, "list->typed-array", 3, 0, 0,
2caaadd1 640 (SCM type, SCM shape, SCM lst),
f301dbf3
MV
641 "Return an array of the type @var{type}\n"
642 "with elements the same as those of @var{lst}.\n"
bfad4005 643 "\n"
2caaadd1
MV
644 "The argument @var{shape} determines the number of dimensions\n"
645 "of the array and their shape. It is either an exact integer,\n"
646 "giving the\n"
647 "number of dimensions directly, or a list whose length\n"
648 "specifies the number of dimensions and each element specified\n"
649 "the lower and optionally the upper bound of the corresponding\n"
650 "dimension.\n"
651 "When the element is list of two elements, these elements\n"
652 "give the lower and upper bounds. When it is an exact\n"
653 "integer, it gives only the lower bound.")
f301dbf3 654#define FUNC_NAME s_scm_list_to_typed_array
0f2d19dd 655{
2caaadd1 656 SCM row;
0f2d19dd 657 SCM ra;
bcbbea0e 658 scm_t_array_handle handle;
bfad4005 659
bfad4005 660 row = lst;
2caaadd1 661 if (scm_is_integer (shape))
0f2d19dd 662 {
2caaadd1
MV
663 size_t k = scm_to_size_t (shape);
664 shape = SCM_EOL;
bfad4005
MV
665 while (k-- > 0)
666 {
667 shape = scm_cons (scm_length (row), shape);
2caaadd1 668 if (k > 0 && !scm_is_null (row))
bfad4005
MV
669 row = scm_car (row);
670 }
671 }
672 else
673 {
2caaadd1
MV
674 SCM shape_spec = shape;
675 shape = SCM_EOL;
bfad4005
MV
676 while (1)
677 {
2caaadd1
MV
678 SCM spec = scm_car (shape_spec);
679 if (scm_is_pair (spec))
680 shape = scm_cons (spec, shape);
681 else
682 shape = scm_cons (scm_list_2 (spec,
683 scm_sum (scm_sum (spec,
684 scm_length (row)),
685 scm_from_int (-1))),
686 shape);
687 shape_spec = scm_cdr (shape_spec);
688 if (scm_is_pair (shape_spec))
689 {
690 if (!scm_is_null (row))
691 row = scm_car (row);
692 }
bfad4005
MV
693 else
694 break;
695 }
0f2d19dd 696 }
bfad4005 697
f0b91039
MV
698 ra = scm_make_typed_array (type, SCM_UNSPECIFIED,
699 scm_reverse_x (shape, SCM_EOL));
20930f28 700
bcbbea0e 701 scm_array_get_handle (ra, &handle);
943a0a87 702 list_to_array (lst, &handle, 0, 0);
bcbbea0e
MV
703 scm_array_handle_release (&handle);
704
705 return ra;
0f2d19dd 706}
1bbd0b84 707#undef FUNC_NAME
0f2d19dd 708
f301dbf3
MV
709SCM_DEFINE (scm_list_to_array, "list->array", 2, 0, 0,
710 (SCM ndim, SCM lst),
711 "Return an array with elements the same as those of @var{lst}.")
712#define FUNC_NAME s_scm_list_to_array
713{
714 return scm_list_to_typed_array (SCM_BOOL_T, ndim, lst);
715}
716#undef FUNC_NAME
717
e0e49670
MV
718/* Print dimension DIM of ARRAY.
719 */
0f2d19dd 720
e0e49670 721static int
943a0a87 722scm_i_print_array_dimension (scm_t_array_handle *h, int dim, int pos,
e0e49670
MV
723 SCM port, scm_print_state *pstate)
724{
943a0a87
AW
725 if (dim == h->ndims)
726 scm_iprin1 (scm_array_handle_ref (h, pos), port, pstate);
727 else
e0e49670 728 {
943a0a87
AW
729 ssize_t i;
730 scm_putc ('(', port);
731 for (i = h->dims[dim].lbnd; i <= h->dims[dim].ubnd;
732 i++, pos += h->dims[dim].inc)
733 {
734 scm_i_print_array_dimension (h, dim+1, pos, port, pstate);
735 if (i < h->dims[dim].ubnd)
736 scm_putc (' ', port);
737 }
738 scm_putc (')', port);
e0e49670 739 }
e0e49670
MV
740 return 1;
741}
742
943a0a87 743/* Print an array.
e0e49670
MV
744*/
745
e0e49670
MV
746static int
747scm_i_print_array (SCM array, SCM port, scm_print_state *pstate)
748{
943a0a87 749 scm_t_array_handle h;
e0e49670 750 long i;
2caaadd1 751 int print_lbnds = 0, zero_size = 0, print_lens = 0;
e0e49670 752
943a0a87
AW
753 scm_array_get_handle (array, &h);
754
e0e49670 755 scm_putc ('#', port);
943a0a87
AW
756 if (h.ndims != 1 || h.dims[0].lbnd != 0)
757 scm_intprint (h.ndims, 10, port);
758 if (h.element_type != SCM_ARRAY_ELEMENT_TYPE_SCM)
759 scm_write (scm_array_handle_element_type (&h), port);
20930f28 760
943a0a87 761 for (i = 0; i < h.ndims; i++)
2caaadd1 762 {
943a0a87 763 if (h.dims[i].lbnd != 0)
2caaadd1 764 print_lbnds = 1;
943a0a87 765 if (h.dims[i].ubnd - h.dims[i].lbnd + 1 == 0)
2caaadd1
MV
766 zero_size = 1;
767 else if (zero_size)
768 print_lens = 1;
769 }
770
771 if (print_lbnds || print_lens)
943a0a87 772 for (i = 0; i < h.ndims; i++)
e0e49670 773 {
2caaadd1 774 if (print_lbnds)
e0e49670
MV
775 {
776 scm_putc ('@', port);
943a0a87 777 scm_intprint (h.dims[i].lbnd, 10, port);
2caaadd1
MV
778 }
779 if (print_lens)
780 {
781 scm_putc (':', port);
943a0a87 782 scm_intprint (h.dims[i].ubnd - h.dims[i].lbnd + 1,
2caaadd1 783 10, port);
e0e49670 784 }
e0e49670
MV
785 }
786
943a0a87 787 if (h.ndims == 0)
5f37cb63
MV
788 {
789 /* Rank zero arrays, which are really just scalars, are printed
790 specially. The consequent way would be to print them as
791
792 #0 OBJ
793
794 where OBJ is the printed representation of the scalar, but we
795 print them instead as
796
797 #0(OBJ)
798
799 to make them look less strange.
800
801 Just printing them as
802
803 OBJ
804
805 would be correct in a way as well, but zero rank arrays are
806 not really the same as Scheme values since they are boxed and
807 can be modified with array-set!, say.
808 */
809 scm_putc ('(', port);
943a0a87 810 scm_i_print_array_dimension (&h, 0, 0, port, pstate);
5f37cb63
MV
811 scm_putc (')', port);
812 return 1;
813 }
814 else
943a0a87 815 return scm_i_print_array_dimension (&h, 0, 0, port, pstate);
e0e49670 816}
1cc91f1b 817
bfad4005
MV
818/* Read an array. This function can also read vectors and uniform
819 vectors. Also, the conflict between '#f' and '#f32' and '#f64' is
820 handled here.
821
822 C is the first character read after the '#'.
823*/
824
2caaadd1
MV
825static int
826read_decimal_integer (SCM port, int c, ssize_t *resp)
827{
828 ssize_t sign = 1;
829 ssize_t res = 0;
830 int got_it = 0;
831
832 if (c == '-')
833 {
834 sign = -1;
835 c = scm_getc (port);
836 }
837
838 while ('0' <= c && c <= '9')
839 {
840 res = 10*res + c-'0';
841 got_it = 1;
842 c = scm_getc (port);
843 }
844
845 if (got_it)
f30e1bdf 846 *resp = sign * res;
2caaadd1
MV
847 return c;
848}
849
bfad4005
MV
850SCM
851scm_i_read_array (SCM port, int c)
852{
5a6d139b 853 ssize_t rank;
eff3dd99 854 scm_t_wchar tag_buf[8];
bfad4005
MV
855 int tag_len;
856
eff3dd99 857 SCM tag, shape = SCM_BOOL_F, elements;
bfad4005
MV
858
859 /* XXX - shortcut for ordinary vectors. Shouldn't be necessary but
860 the array code can not deal with zero-length dimensions yet, and
861 we want to allow zero-length vectors, of course.
862 */
863 if (c == '(')
864 {
865 scm_ungetc (c, port);
866 return scm_vector (scm_read (port));
867 }
868
869 /* Disambiguate between '#f' and uniform floating point vectors.
870 */
871 if (c == 'f')
872 {
873 c = scm_getc (port);
874 if (c != '3' && c != '6')
875 {
876 if (c != EOF)
877 scm_ungetc (c, port);
878 return SCM_BOOL_F;
879 }
880 rank = 1;
eff3dd99 881 tag_buf[0] = 'f';
bfad4005
MV
882 tag_len = 1;
883 goto continue_reading_tag;
884 }
885
2caaadd1
MV
886 /* Read rank.
887 */
888 rank = 1;
889 c = read_decimal_integer (port, c, &rank);
890 if (rank < 0)
891 scm_i_input_error (NULL, port, "array rank must be non-negative",
892 SCM_EOL);
bfad4005 893
2caaadd1
MV
894 /* Read tag.
895 */
bfad4005
MV
896 tag_len = 0;
897 continue_reading_tag:
eff3dd99
AW
898 while (c != EOF && c != '(' && c != '@' && c != ':'
899 && tag_len < sizeof tag_buf / sizeof tag_buf[0])
bfad4005 900 {
eff3dd99 901 tag_buf[tag_len++] = c;
bfad4005
MV
902 c = scm_getc (port);
903 }
eff3dd99
AW
904 if (tag_len == 0)
905 tag = SCM_BOOL_T;
906 else
907 {
908 tag = scm_string_to_symbol (scm_from_utf32_stringn (tag_buf, tag_len));
909 if (tag_len == sizeof tag_buf / sizeof tag_buf[0])
910 scm_i_input_error (NULL, port, "invalid array tag, starting with: ~a",
911 scm_list_1 (tag));
912 }
913
2caaadd1
MV
914 /* Read shape.
915 */
916 if (c == '@' || c == ':')
bfad4005 917 {
2caaadd1 918 shape = SCM_EOL;
5f37cb63
MV
919
920 do
bfad4005 921 {
2caaadd1
MV
922 ssize_t lbnd = 0, len = 0;
923 SCM s;
5f37cb63 924
2caaadd1 925 if (c == '@')
5f37cb63 926 {
5f37cb63 927 c = scm_getc (port);
2caaadd1 928 c = read_decimal_integer (port, c, &lbnd);
5f37cb63 929 }
2caaadd1
MV
930
931 s = scm_from_ssize_t (lbnd);
932
933 if (c == ':')
5f37cb63 934 {
5f37cb63 935 c = scm_getc (port);
2caaadd1 936 c = read_decimal_integer (port, c, &len);
f30e1bdf
LC
937 if (len < 0)
938 scm_i_input_error (NULL, port,
939 "array length must be non-negative",
940 SCM_EOL);
941
2caaadd1 942 s = scm_list_2 (s, scm_from_ssize_t (lbnd+len-1));
5f37cb63 943 }
2caaadd1
MV
944
945 shape = scm_cons (s, shape);
946 } while (c == '@' || c == ':');
947
948 shape = scm_reverse_x (shape, SCM_EOL);
bfad4005
MV
949 }
950
951 /* Read nested lists of elements.
952 */
953 if (c != '(')
954 scm_i_input_error (NULL, port,
955 "missing '(' in vector or array literal",
956 SCM_EOL);
957 scm_ungetc (c, port);
958 elements = scm_read (port);
959
2caaadd1 960 if (scm_is_false (shape))
5a6d139b 961 shape = scm_from_ssize_t (rank);
2caaadd1
MV
962 else if (scm_ilength (shape) != rank)
963 scm_i_input_error
964 (NULL, port,
965 "the number of shape specifications must match the array rank",
966 SCM_EOL);
bfad4005 967
5f37cb63
MV
968 /* Handle special print syntax of rank zero arrays; see
969 scm_i_print_array for a rationale.
970 */
971 if (rank == 0)
2caaadd1
MV
972 {
973 if (!scm_is_pair (elements))
974 scm_i_input_error (NULL, port,
975 "too few elements in array literal, need 1",
976 SCM_EOL);
977 if (!scm_is_null (SCM_CDR (elements)))
978 scm_i_input_error (NULL, port,
979 "too many elements in array literal, want 1",
980 SCM_EOL);
981 elements = SCM_CAR (elements);
982 }
5f37cb63
MV
983
984 /* Construct array.
985 */
eff3dd99 986 return scm_list_to_typed_array (tag, shape, elements);
bfad4005
MV
987}
988
ab1be174 989
2a610be5
AW
990static SCM
991array_handle_ref (scm_t_array_handle *h, size_t pos)
992{
993 return scm_c_generalized_vector_ref (SCM_I_ARRAY_V (h->array), pos);
994}
995
996static void
997array_handle_set (scm_t_array_handle *h, size_t pos, SCM val)
998{
999 scm_c_generalized_vector_set_x (SCM_I_ARRAY_V (h->array), pos, val);
1000}
1001
1002/* FIXME: should be handle for vect? maybe not, because of dims */
1003static void
1004array_get_handle (SCM array, scm_t_array_handle *h)
1005{
1006 scm_t_array_handle vh;
1007 scm_array_get_handle (SCM_I_ARRAY_V (array), &vh);
1008 h->element_type = vh.element_type;
1009 h->elements = vh.elements;
1010 h->writable_elements = vh.writable_elements;
1011 scm_array_handle_release (&vh);
1012
1013 h->dims = SCM_I_ARRAY_DIMS (array);
1014 h->ndims = SCM_I_ARRAY_NDIM (array);
1015 h->base = SCM_I_ARRAY_BASE (array);
1016}
1017
735bcfe5
AW
1018SCM_ARRAY_IMPLEMENTATION (SCM_SMOB_TYPE_BITS (scm_i_tc16_array),
1019 SCM_SMOB_TYPE_MASK,
2a610be5 1020 array_handle_ref, array_handle_set,
f65e0168 1021 array_get_handle)
2a610be5 1022
0f2d19dd 1023void
2fa901a5 1024scm_init_arrays ()
0f2d19dd 1025{
04b87de5 1026 scm_i_tc16_array = scm_make_smob_type ("array", 0);
04b87de5
MV
1027 scm_set_smob_print (scm_i_tc16_array, scm_i_print_array);
1028 scm_set_smob_equalp (scm_i_tc16_array, scm_array_equal_p);
1029
0f2d19dd 1030 scm_add_feature ("array");
20930f28 1031
2fa901a5 1032#include "libguile/arrays.x"
bfad4005 1033
0f2d19dd 1034}
89e00824
ML
1035
1036/*
1037 Local Variables:
1038 c-file-style: "gnu"
1039 End:
1040*/