struct-set! returns a value, yuck
[bpt/guile.git] / libguile / arrays.c
CommitLineData
493ceb99
MW
1/* Copyright (C) 1995,1996,1997,1998,2000,2001,2002,2003,2004,2005,
2 * 2006, 2009, 2010, 2011, 2012 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
dbb605f5 23#ifdef HAVE_CONFIG_H
2a5cd898
RB
24# include <config.h>
25#endif
26
0f2d19dd 27#include <stdio.h>
e6e2e95a 28#include <errno.h>
783e7774 29#include <string.h>
e6e2e95a 30
a0599745 31#include "libguile/_scm.h"
e0e49670
MV
32#include "libguile/__scm.h"
33#include "libguile/eq.h"
a0599745
MD
34#include "libguile/chars.h"
35#include "libguile/eval.h"
36#include "libguile/fports.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 57#define SCM_SET_ARRAY_CONTIGUOUS_FLAG(x) \
b2637c98 58 (SCM_SET_CELL_WORD_0 ((x), SCM_CELL_WORD_0 (x) | (SCM_I_ARRAY_FLAG_CONTIGUOUS << 16)))
04b87de5 59#define SCM_CLR_ARRAY_CONTIGUOUS_FLAG(x) \
b2637c98 60 (SCM_SET_CELL_WORD_0 ((x), SCM_CELL_WORD_0 (x) & ~(SCM_I_ARRAY_FLAG_CONTIGUOUS << 16)))
1cc91f1b 61
0f2d19dd 62
e2d37336
MD
63SCM_DEFINE (scm_shared_array_root, "shared-array-root", 1, 0, 0,
64 (SCM ra),
65 "Return the root vector of a shared array.")
66#define FUNC_NAME s_scm_shared_array_root
67{
66b9d7d3 68 if (SCM_I_ARRAYP (ra))
04b87de5 69 return SCM_I_ARRAY_V (ra);
52372719
MV
70 else if (scm_is_generalized_vector (ra))
71 return ra;
943a0a87 72 scm_wrong_type_arg_msg (FUNC_NAME, SCM_ARG1, ra, "array");
e2d37336
MD
73}
74#undef FUNC_NAME
75
76
77SCM_DEFINE (scm_shared_array_offset, "shared-array-offset", 1, 0, 0,
78 (SCM ra),
79 "Return the root vector index of the first element in the array.")
80#define FUNC_NAME s_scm_shared_array_offset
81{
52372719
MV
82 scm_t_array_handle handle;
83 SCM res;
84
85 scm_array_get_handle (ra, &handle);
86 res = scm_from_size_t (handle.base);
87 scm_array_handle_release (&handle);
88 return res;
e2d37336
MD
89}
90#undef FUNC_NAME
91
92
93SCM_DEFINE (scm_shared_array_increments, "shared-array-increments", 1, 0, 0,
94 (SCM ra),
95 "For each dimension, return the distance between elements in the root vector.")
96#define FUNC_NAME s_scm_shared_array_increments
97{
52372719 98 scm_t_array_handle handle;
e2d37336 99 SCM res = SCM_EOL;
1be6b49c 100 size_t k;
92c2555f 101 scm_t_array_dim *s;
02339e5b 102
52372719
MV
103 scm_array_get_handle (ra, &handle);
104 k = scm_array_handle_rank (&handle);
105 s = scm_array_handle_dims (&handle);
e2d37336 106 while (k--)
52372719
MV
107 res = scm_cons (scm_from_ssize_t (s[k].inc), res);
108 scm_array_handle_release (&handle);
e2d37336
MD
109 return res;
110}
111#undef FUNC_NAME
112
67543d07 113SCM
66b9d7d3 114scm_i_make_array (int ndim)
0f2d19dd
JB
115{
116 SCM ra;
b2637c98 117 ra = scm_cell (((scm_t_bits) ndim << 17) + scm_tc7_array,
67543d07
LC
118 (scm_t_bits) scm_gc_malloc (sizeof (scm_i_t_array) +
119 ndim * sizeof (scm_t_array_dim),
120 "array"));
04b87de5 121 SCM_I_ARRAY_V (ra) = SCM_BOOL_F;
0f2d19dd
JB
122 return ra;
123}
124
125static char s_bad_spec[] = "Bad scm_array dimension";
0f2d19dd 126
1cc91f1b 127
02339e5b
MV
128/* Increments will still need to be set. */
129
0cd6cb2f
MV
130static SCM
131scm_i_shap2ra (SCM args)
0f2d19dd 132{
92c2555f 133 scm_t_array_dim *s;
0f2d19dd
JB
134 SCM ra, spec, sp;
135 int ndim = scm_ilength (args);
b3fcac34 136 if (ndim < 0)
0cd6cb2f 137 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
b3fcac34 138
66b9d7d3 139 ra = scm_i_make_array (ndim);
04b87de5
MV
140 SCM_I_ARRAY_BASE (ra) = 0;
141 s = SCM_I_ARRAY_DIMS (ra);
d2e53ed6 142 for (; !scm_is_null (args); s++, args = SCM_CDR (args))
0f2d19dd
JB
143 {
144 spec = SCM_CAR (args);
e11e83f3 145 if (scm_is_integer (spec))
0f2d19dd 146 {
e11e83f3 147 if (scm_to_long (spec) < 0)
0cd6cb2f 148 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
0f2d19dd 149 s->lbnd = 0;
e11e83f3 150 s->ubnd = scm_to_long (spec) - 1;
0f2d19dd
JB
151 s->inc = 1;
152 }
153 else
154 {
d2e53ed6 155 if (!scm_is_pair (spec) || !scm_is_integer (SCM_CAR (spec)))
0cd6cb2f 156 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
e11e83f3 157 s->lbnd = scm_to_long (SCM_CAR (spec));
0f2d19dd 158 sp = SCM_CDR (spec);
d2e53ed6 159 if (!scm_is_pair (sp)
e11e83f3 160 || !scm_is_integer (SCM_CAR (sp))
d2e53ed6 161 || !scm_is_null (SCM_CDR (sp)))
0cd6cb2f 162 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
e11e83f3 163 s->ubnd = scm_to_long (SCM_CAR (sp));
0f2d19dd
JB
164 s->inc = 1;
165 }
166 }
167 return ra;
168}
169
f301dbf3
MV
170SCM_DEFINE (scm_make_typed_array, "make-typed-array", 2, 0, 1,
171 (SCM type, SCM fill, SCM bounds),
172 "Create and return an array of type @var{type}.")
173#define FUNC_NAME s_scm_make_typed_array
0f2d19dd 174{
f301dbf3 175 size_t k, rlen = 1;
92c2555f 176 scm_t_array_dim *s;
0f2d19dd 177 SCM ra;
1be6b49c 178
0cd6cb2f 179 ra = scm_i_shap2ra (bounds);
e038c042 180 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
04b87de5
MV
181 s = SCM_I_ARRAY_DIMS (ra);
182 k = SCM_I_ARRAY_NDIM (ra);
1be6b49c 183
0f2d19dd
JB
184 while (k--)
185 {
a3a32939 186 s[k].inc = rlen;
2caaadd1 187 SCM_ASSERT_RANGE (1, bounds, s[k].lbnd <= s[k].ubnd + 1);
0f2d19dd 188 rlen = (s[k].ubnd - s[k].lbnd + 1) * s[k].inc;
0f2d19dd 189 }
a3a32939 190
f0b91039 191 if (scm_is_eq (fill, SCM_UNSPECIFIED))
f301dbf3 192 fill = SCM_UNDEFINED;
a3a32939 193
943a0a87
AW
194 SCM_I_ARRAY_V (ra) =
195 scm_make_generalized_vector (type, scm_from_size_t (rlen), fill);
a3a32939 196
04b87de5 197 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
c014a02e 198 if (s->ubnd < s->lbnd || (0 == s->lbnd && 1 == s->inc))
04b87de5 199 return SCM_I_ARRAY_V (ra);
0f2d19dd
JB
200 return ra;
201}
1bbd0b84 202#undef FUNC_NAME
0f2d19dd 203
782a82ee
AW
204SCM
205scm_from_contiguous_typed_array (SCM type, SCM bounds, const void *bytes,
206 size_t byte_len)
207#define FUNC_NAME "scm_from_contiguous_typed_array"
208{
209 size_t k, rlen = 1;
210 scm_t_array_dim *s;
782a82ee
AW
211 SCM ra;
212 scm_t_array_handle h;
f5a51cae 213 void *elts;
782a82ee
AW
214 size_t sz;
215
782a82ee
AW
216 ra = scm_i_shap2ra (bounds);
217 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
218 s = SCM_I_ARRAY_DIMS (ra);
219 k = SCM_I_ARRAY_NDIM (ra);
220
221 while (k--)
222 {
223 s[k].inc = rlen;
224 SCM_ASSERT_RANGE (1, bounds, s[k].lbnd <= s[k].ubnd + 1);
225 rlen = (s[k].ubnd - s[k].lbnd + 1) * s[k].inc;
226 }
943a0a87
AW
227 SCM_I_ARRAY_V (ra) =
228 scm_make_generalized_vector (type, scm_from_size_t (rlen), SCM_UNDEFINED);
782a82ee
AW
229
230
231 scm_array_get_handle (ra, &h);
f5a51cae
AW
232 elts = h.writable_elements;
233 sz = scm_array_handle_uniform_element_bit_size (&h);
782a82ee
AW
234 scm_array_handle_release (&h);
235
f5a51cae
AW
236 if (sz >= 8 && ((sz % 8) == 0))
237 {
238 if (byte_len % (sz / 8))
239 SCM_MISC_ERROR ("byte length not a multiple of the unit size", SCM_EOL);
240 if (byte_len / (sz / 8) != rlen)
241 SCM_MISC_ERROR ("byte length and dimensions do not match", SCM_EOL);
242 }
b0fae4ec 243 else if (sz < 8)
f5a51cae 244 {
cd48c32c
LC
245 /* byte_len ?= ceil (rlen * sz / 8) */
246 if (byte_len != (rlen * sz + 7) / 8)
f5a51cae
AW
247 SCM_MISC_ERROR ("byte length and dimensions do not match", SCM_EOL);
248 }
b0fae4ec
AW
249 else
250 /* an internal guile error, really */
251 SCM_MISC_ERROR ("uniform elements larger than 8 bits must fill whole bytes", SCM_EOL);
782a82ee 252
f5a51cae 253 memcpy (elts, bytes, byte_len);
782a82ee
AW
254
255 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
256 if (s->ubnd < s->lbnd || (0 == s->lbnd && 1 == s->inc))
257 return SCM_I_ARRAY_V (ra);
258 return ra;
259}
260#undef FUNC_NAME
261
73788ca8
AW
262SCM
263scm_from_contiguous_array (SCM bounds, const SCM *elts, size_t len)
264#define FUNC_NAME "scm_from_contiguous_array"
265{
266 size_t k, rlen = 1;
267 scm_t_array_dim *s;
268 SCM ra;
269 scm_t_array_handle h;
270
271 ra = scm_i_shap2ra (bounds);
272 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
273 s = SCM_I_ARRAY_DIMS (ra);
274 k = SCM_I_ARRAY_NDIM (ra);
275
276 while (k--)
277 {
278 s[k].inc = rlen;
279 SCM_ASSERT_RANGE (1, bounds, s[k].lbnd <= s[k].ubnd + 1);
280 rlen = (s[k].ubnd - s[k].lbnd + 1) * s[k].inc;
281 }
282 if (rlen != len)
283 SCM_MISC_ERROR ("element length and dimensions do not match", SCM_EOL);
284
285 SCM_I_ARRAY_V (ra) = scm_c_make_vector (rlen, SCM_UNDEFINED);
286 scm_array_get_handle (ra, &h);
287 memcpy (h.writable_elements, elts, rlen * sizeof(SCM));
288 scm_array_handle_release (&h);
289
290 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
291 if (s->ubnd < s->lbnd || (0 == s->lbnd && 1 == s->inc))
292 return SCM_I_ARRAY_V (ra);
293 return ra;
294}
295#undef FUNC_NAME
296
f301dbf3
MV
297SCM_DEFINE (scm_make_array, "make-array", 1, 0, 1,
298 (SCM fill, SCM bounds),
299 "Create and return an array.")
300#define FUNC_NAME s_scm_make_array
301{
302 return scm_make_typed_array (SCM_BOOL_T, fill, bounds);
303}
304#undef FUNC_NAME
305
0cd6cb2f
MV
306static void
307scm_i_ra_set_contp (SCM ra)
0f2d19dd 308{
04b87de5 309 size_t k = SCM_I_ARRAY_NDIM (ra);
0f2d19dd 310 if (k)
0f2d19dd 311 {
04b87de5 312 long inc = SCM_I_ARRAY_DIMS (ra)[k - 1].inc;
fe0c6dae 313 while (k--)
0f2d19dd 314 {
04b87de5 315 if (inc != SCM_I_ARRAY_DIMS (ra)[k].inc)
fe0c6dae 316 {
e038c042 317 SCM_CLR_ARRAY_CONTIGUOUS_FLAG (ra);
fe0c6dae
JB
318 return;
319 }
04b87de5
MV
320 inc *= (SCM_I_ARRAY_DIMS (ra)[k].ubnd
321 - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1);
0f2d19dd 322 }
0f2d19dd 323 }
e038c042 324 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
0f2d19dd
JB
325}
326
327
3b3b36dd 328SCM_DEFINE (scm_make_shared_array, "make-shared-array", 2, 0, 1,
1bbd0b84 329 (SCM oldra, SCM mapfunc, SCM dims),
b7e64f8b
BT
330 "@code{make-shared-array} can be used to create shared subarrays\n"
331 "of other arrays. The @var{mapfunc} is a function that\n"
332 "translates coordinates in the new array into coordinates in the\n"
333 "old array. A @var{mapfunc} must be linear, and its range must\n"
334 "stay within the bounds of the old array, but it can be\n"
335 "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),
b7e64f8b 449 "Return an array sharing contents with @var{ra}, but with\n"
1e6808ea 450 "dimensions arranged in a different order. There must be one\n"
b7e64f8b 451 "@var{dim} argument for each dimension of @var{ra}.\n"
1e6808ea
MG
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"
b7e64f8b 458 "argument list to dimensions of @var{ra}. Several @var{dim}s\n"
1e6808ea 459 "may have the same value, in which case the returned array will\n"
b7e64f8b 460 "have smaller rank than @var{ra}.\n"
1e6808ea
MG
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);
8c5bb729 475 SCM_ASSERT (SCM_HEAP_OBJECT_P (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),
b7e64f8b
BT
551 "If @var{ra} may be @dfn{unrolled} into a one dimensional shared\n"
552 "array without changing their order (last subscript changing\n"
553 "fastest), then @code{array-contents} returns that shared array,\n"
554 "otherwise it returns @code{#f}. All arrays made by\n"
555 "@code{make-array} and @code{make-uniform-array} may be unrolled,\n"
556 "some arrays made by @code{make-shared-array} may not be. If\n"
557 "the optional argument @var{strict} is provided, a shared array\n"
558 "will be returned only if its elements are stored internally\n"
559 "contiguous in 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 729 ssize_t i;
0607ebbf 730 scm_putc_unlocked ('(', port);
943a0a87
AW
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)
0607ebbf 736 scm_putc_unlocked (' ', port);
943a0a87 737 }
0607ebbf 738 scm_putc_unlocked (')', port);
e0e49670 739 }
e0e49670
MV
740 return 1;
741}
742
943a0a87 743/* Print an array.
e0e49670
MV
744*/
745
b2637c98 746int
e0e49670
MV
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
0607ebbf 755 scm_putc_unlocked ('#', 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 775 {
0607ebbf 776 scm_putc_unlocked ('@', port);
943a0a87 777 scm_intprint (h.dims[i].lbnd, 10, port);
2caaadd1
MV
778 }
779 if (print_lens)
780 {
0607ebbf 781 scm_putc_unlocked (':', 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 */
0607ebbf 809 scm_putc_unlocked ('(', port);
943a0a87 810 scm_i_print_array_dimension (&h, 0, 0, port, pstate);
0607ebbf 811 scm_putc_unlocked (')', port);
5f37cb63
MV
812 return 1;
813 }
814 else
943a0a87 815 return scm_i_print_array_dimension (&h, 0, 0, port, pstate);
e0e49670 816}
1cc91f1b 817
2a610be5
AW
818static SCM
819array_handle_ref (scm_t_array_handle *h, size_t pos)
820{
821 return scm_c_generalized_vector_ref (SCM_I_ARRAY_V (h->array), pos);
822}
823
824static void
825array_handle_set (scm_t_array_handle *h, size_t pos, SCM val)
826{
827 scm_c_generalized_vector_set_x (SCM_I_ARRAY_V (h->array), pos, val);
828}
829
830/* FIXME: should be handle for vect? maybe not, because of dims */
831static void
832array_get_handle (SCM array, scm_t_array_handle *h)
833{
834 scm_t_array_handle vh;
835 scm_array_get_handle (SCM_I_ARRAY_V (array), &vh);
836 h->element_type = vh.element_type;
837 h->elements = vh.elements;
838 h->writable_elements = vh.writable_elements;
839 scm_array_handle_release (&vh);
840
841 h->dims = SCM_I_ARRAY_DIMS (array);
842 h->ndims = SCM_I_ARRAY_NDIM (array);
843 h->base = SCM_I_ARRAY_BASE (array);
844}
845
b2637c98
AW
846SCM_ARRAY_IMPLEMENTATION (scm_tc7_array,
847 0x7f,
2a610be5 848 array_handle_ref, array_handle_set,
f65e0168 849 array_get_handle)
2a610be5 850
0f2d19dd 851void
2fa901a5 852scm_init_arrays ()
0f2d19dd 853{
0f2d19dd 854 scm_add_feature ("array");
20930f28 855
2fa901a5 856#include "libguile/arrays.x"
bfad4005 857
0f2d19dd 858}
89e00824
ML
859
860/*
861 Local Variables:
862 c-file-style: "gnu"
863 End:
864*/