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