fix erroneous compilation of #@2(1 2 3) as #(1 2 3)
[bpt/guile.git] / libguile / arrays.c
CommitLineData
438974d0 1/* Copyright (C) 1995,1996,1997,1998,2000,2001,2002,2003,2004, 2005, 2006, 2009 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
f301dbf3
MV
263SCM_DEFINE (scm_make_array, "make-array", 1, 0, 1,
264 (SCM fill, SCM bounds),
265 "Create and return an array.")
266#define FUNC_NAME s_scm_make_array
267{
268 return scm_make_typed_array (SCM_BOOL_T, fill, bounds);
269}
270#undef FUNC_NAME
271
0cd6cb2f
MV
272static void
273scm_i_ra_set_contp (SCM ra)
0f2d19dd 274{
04b87de5 275 size_t k = SCM_I_ARRAY_NDIM (ra);
0f2d19dd 276 if (k)
0f2d19dd 277 {
04b87de5 278 long inc = SCM_I_ARRAY_DIMS (ra)[k - 1].inc;
fe0c6dae 279 while (k--)
0f2d19dd 280 {
04b87de5 281 if (inc != SCM_I_ARRAY_DIMS (ra)[k].inc)
fe0c6dae 282 {
e038c042 283 SCM_CLR_ARRAY_CONTIGUOUS_FLAG (ra);
fe0c6dae
JB
284 return;
285 }
04b87de5
MV
286 inc *= (SCM_I_ARRAY_DIMS (ra)[k].ubnd
287 - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1);
0f2d19dd 288 }
0f2d19dd 289 }
e038c042 290 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
0f2d19dd
JB
291}
292
293
3b3b36dd 294SCM_DEFINE (scm_make_shared_array, "make-shared-array", 2, 0, 1,
1bbd0b84 295 (SCM oldra, SCM mapfunc, SCM dims),
b380b885
MD
296 "@code{make-shared-array} can be used to create shared subarrays of other\n"
297 "arrays. The @var{mapper} is a function that translates coordinates in\n"
298 "the new array into coordinates in the old array. A @var{mapper} must be\n"
299 "linear, and its range must stay within the bounds of the old array, but\n"
300 "it can be otherwise arbitrary. A simple example:\n"
1e6808ea 301 "@lisp\n"
b380b885
MD
302 "(define fred (make-array #f 8 8))\n"
303 "(define freds-diagonal\n"
304 " (make-shared-array fred (lambda (i) (list i i)) 8))\n"
305 "(array-set! freds-diagonal 'foo 3)\n"
306 "(array-ref fred 3 3) @result{} foo\n"
307 "(define freds-center\n"
308 " (make-shared-array fred (lambda (i j) (list (+ 3 i) (+ 3 j))) 2 2))\n"
309 "(array-ref freds-center 0 0) @result{} foo\n"
1e6808ea 310 "@end lisp")
1bbd0b84 311#define FUNC_NAME s_scm_make_shared_array
0f2d19dd 312{
112ba0ac 313 scm_t_array_handle old_handle;
0f2d19dd
JB
314 SCM ra;
315 SCM inds, indptr;
316 SCM imap;
112ba0ac
MV
317 size_t k;
318 ssize_t i;
2b829bbb 319 long old_base, old_min, new_min, old_max, new_max;
92c2555f 320 scm_t_array_dim *s;
b3fcac34
DH
321
322 SCM_VALIDATE_REST_ARGUMENT (dims);
34d19ef6 323 SCM_VALIDATE_PROC (2, mapfunc);
0cd6cb2f 324 ra = scm_i_shap2ra (dims);
112ba0ac
MV
325
326 scm_array_get_handle (oldra, &old_handle);
327
04b87de5 328 if (SCM_I_ARRAYP (oldra))
0f2d19dd 329 {
04b87de5 330 SCM_I_ARRAY_V (ra) = SCM_I_ARRAY_V (oldra);
2b829bbb 331 old_base = old_min = old_max = SCM_I_ARRAY_BASE (oldra);
112ba0ac
MV
332 s = scm_array_handle_dims (&old_handle);
333 k = scm_array_handle_rank (&old_handle);
0f2d19dd
JB
334 while (k--)
335 {
336 if (s[k].inc > 0)
337 old_max += (s[k].ubnd - s[k].lbnd) * s[k].inc;
338 else
339 old_min += (s[k].ubnd - s[k].lbnd) * s[k].inc;
340 }
341 }
342 else
343 {
04b87de5 344 SCM_I_ARRAY_V (ra) = oldra;
2b829bbb 345 old_base = old_min = 0;
02339e5b 346 old_max = scm_c_generalized_vector_length (oldra) - 1;
0f2d19dd 347 }
112ba0ac 348
0f2d19dd 349 inds = SCM_EOL;
04b87de5
MV
350 s = SCM_I_ARRAY_DIMS (ra);
351 for (k = 0; k < SCM_I_ARRAY_NDIM (ra); k++)
0f2d19dd 352 {
e11e83f3 353 inds = scm_cons (scm_from_long (s[k].lbnd), inds);
0f2d19dd
JB
354 if (s[k].ubnd < s[k].lbnd)
355 {
04b87de5 356 if (1 == SCM_I_ARRAY_NDIM (ra))
943a0a87
AW
357 ra = scm_make_generalized_vector (scm_array_type (ra),
358 SCM_INUM0, SCM_UNDEFINED);
0f2d19dd 359 else
943a0a87
AW
360 SCM_I_ARRAY_V (ra) =
361 scm_make_generalized_vector (scm_array_type (ra),
362 SCM_INUM0, SCM_UNDEFINED);
112ba0ac 363 scm_array_handle_release (&old_handle);
0f2d19dd
JB
364 return ra;
365 }
366 }
112ba0ac 367
fdc28395 368 imap = scm_apply_0 (mapfunc, scm_reverse (inds));
0cd6cb2f 369 i = scm_array_handle_pos (&old_handle, imap);
2b829bbb 370 SCM_I_ARRAY_BASE (ra) = new_min = new_max = i + old_base;
0f2d19dd 371 indptr = inds;
04b87de5 372 k = SCM_I_ARRAY_NDIM (ra);
0f2d19dd
JB
373 while (k--)
374 {
375 if (s[k].ubnd > s[k].lbnd)
376 {
e11e83f3 377 SCM_SETCAR (indptr, scm_sum (SCM_CAR (indptr), scm_from_int (1)));
fdc28395 378 imap = scm_apply_0 (mapfunc, scm_reverse (inds));
0cd6cb2f 379 s[k].inc = scm_array_handle_pos (&old_handle, imap) - i;
0f2d19dd
JB
380 i += s[k].inc;
381 if (s[k].inc > 0)
382 new_max += (s[k].ubnd - s[k].lbnd) * s[k].inc;
383 else
384 new_min += (s[k].ubnd - s[k].lbnd) * s[k].inc;
385 }
386 else
387 s[k].inc = new_max - new_min + 1; /* contiguous by default */
388 indptr = SCM_CDR (indptr);
389 }
112ba0ac
MV
390
391 scm_array_handle_release (&old_handle);
392
b3fcac34
DH
393 if (old_min > new_min || old_max < new_max)
394 SCM_MISC_ERROR ("mapping out of range", SCM_EOL);
04b87de5 395 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
0f2d19dd 396 {
04b87de5 397 SCM v = SCM_I_ARRAY_V (ra);
6e708ef2 398 size_t length = scm_c_generalized_vector_length (v);
74014c46
DH
399 if (1 == s->inc && 0 == s->lbnd && length == 1 + s->ubnd)
400 return v;
0f2d19dd 401 if (s->ubnd < s->lbnd)
943a0a87
AW
402 return scm_make_generalized_vector (scm_array_type (ra), SCM_INUM0,
403 SCM_UNDEFINED);
0f2d19dd 404 }
0cd6cb2f 405 scm_i_ra_set_contp (ra);
0f2d19dd
JB
406 return ra;
407}
1bbd0b84 408#undef FUNC_NAME
0f2d19dd
JB
409
410
411/* args are RA . DIMS */
af45e3b0
DH
412SCM_DEFINE (scm_transpose_array, "transpose-array", 1, 0, 1,
413 (SCM ra, SCM args),
1e6808ea
MG
414 "Return an array sharing contents with @var{array}, but with\n"
415 "dimensions arranged in a different order. There must be one\n"
416 "@var{dim} argument for each dimension of @var{array}.\n"
417 "@var{dim0}, @var{dim1}, @dots{} should be integers between 0\n"
418 "and the rank of the array to be returned. Each integer in that\n"
419 "range must appear at least once in the argument list.\n"
420 "\n"
421 "The values of @var{dim0}, @var{dim1}, @dots{} correspond to\n"
422 "dimensions in the array to be returned, their positions in the\n"
423 "argument list to dimensions of @var{array}. Several @var{dim}s\n"
424 "may have the same value, in which case the returned array will\n"
425 "have smaller rank than @var{array}.\n"
426 "\n"
427 "@lisp\n"
b380b885
MD
428 "(transpose-array '#2((a b) (c d)) 1 0) @result{} #2((a c) (b d))\n"
429 "(transpose-array '#2((a b) (c d)) 0 0) @result{} #1(a d)\n"
430 "(transpose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1 1 0) @result{}\n"
431 " #2((a 4) (b 5) (c 6))\n"
1e6808ea 432 "@end lisp")
1bbd0b84 433#define FUNC_NAME s_scm_transpose_array
0f2d19dd 434{
34d19ef6 435 SCM res, vargs;
92c2555f 436 scm_t_array_dim *s, *r;
0f2d19dd 437 int ndim, i, k;
af45e3b0 438
b3fcac34 439 SCM_VALIDATE_REST_ARGUMENT (args);
1bbd0b84 440 SCM_ASSERT (SCM_NIMP (ra), ra, SCM_ARG1, FUNC_NAME);
e0e49670 441
20930f28 442 if (scm_is_generalized_vector (ra))
e0e49670
MV
443 {
444 /* Make sure that we are called with a single zero as
445 arguments.
446 */
447 if (scm_is_null (args) || !scm_is_null (SCM_CDR (args)))
448 SCM_WRONG_NUM_ARGS ();
449 SCM_VALIDATE_INT_COPY (SCM_ARG2, SCM_CAR (args), i);
450 SCM_ASSERT_RANGE (SCM_ARG2, SCM_CAR (args), i == 0);
451 return ra;
452 }
453
66b9d7d3 454 if (SCM_I_ARRAYP (ra))
0f2d19dd 455 {
0f2d19dd 456 vargs = scm_vector (args);
04b87de5 457 if (SCM_SIMPLE_VECTOR_LENGTH (vargs) != SCM_I_ARRAY_NDIM (ra))
b3fcac34 458 SCM_WRONG_NUM_ARGS ();
0f2d19dd 459 ndim = 0;
04b87de5 460 for (k = 0; k < SCM_I_ARRAY_NDIM (ra); k++)
0f2d19dd 461 {
6e708ef2 462 i = scm_to_signed_integer (SCM_SIMPLE_VECTOR_REF (vargs, k),
04b87de5 463 0, SCM_I_ARRAY_NDIM(ra));
0f2d19dd
JB
464 if (ndim < i)
465 ndim = i;
466 }
467 ndim++;
66b9d7d3 468 res = scm_i_make_array (ndim);
04b87de5
MV
469 SCM_I_ARRAY_V (res) = SCM_I_ARRAY_V (ra);
470 SCM_I_ARRAY_BASE (res) = SCM_I_ARRAY_BASE (ra);
0f2d19dd
JB
471 for (k = ndim; k--;)
472 {
04b87de5
MV
473 SCM_I_ARRAY_DIMS (res)[k].lbnd = 0;
474 SCM_I_ARRAY_DIMS (res)[k].ubnd = -1;
0f2d19dd 475 }
04b87de5 476 for (k = SCM_I_ARRAY_NDIM (ra); k--;)
0f2d19dd 477 {
6e708ef2 478 i = scm_to_int (SCM_SIMPLE_VECTOR_REF (vargs, k));
04b87de5
MV
479 s = &(SCM_I_ARRAY_DIMS (ra)[k]);
480 r = &(SCM_I_ARRAY_DIMS (res)[i]);
0f2d19dd
JB
481 if (r->ubnd < r->lbnd)
482 {
483 r->lbnd = s->lbnd;
484 r->ubnd = s->ubnd;
485 r->inc = s->inc;
486 ndim--;
487 }
488 else
489 {
490 if (r->ubnd > s->ubnd)
491 r->ubnd = s->ubnd;
492 if (r->lbnd < s->lbnd)
493 {
04b87de5 494 SCM_I_ARRAY_BASE (res) += (s->lbnd - r->lbnd) * r->inc;
0f2d19dd
JB
495 r->lbnd = s->lbnd;
496 }
497 r->inc += s->inc;
498 }
499 }
b3fcac34
DH
500 if (ndim > 0)
501 SCM_MISC_ERROR ("bad argument list", SCM_EOL);
0cd6cb2f 502 scm_i_ra_set_contp (res);
0f2d19dd
JB
503 return res;
504 }
20930f28
MV
505
506 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
0f2d19dd 507}
1bbd0b84 508#undef FUNC_NAME
0f2d19dd 509
1d7bdb25
GH
510/* attempts to unroll an array into a one-dimensional array.
511 returns the unrolled array or #f if it can't be done. */
1bbd0b84 512 /* if strict is not SCM_UNDEFINED, return #f if returned array
1d7bdb25 513 wouldn't have contiguous elements. */
3b3b36dd 514SCM_DEFINE (scm_array_contents, "array-contents", 1, 1, 0,
1bbd0b84 515 (SCM ra, SCM strict),
b380b885
MD
516 "If @var{array} may be @dfn{unrolled} into a one dimensional shared array\n"
517 "without changing their order (last subscript changing fastest), then\n"
518 "@code{array-contents} returns that shared array, otherwise it returns\n"
519 "@code{#f}. All arrays made by @var{make-array} and\n"
520 "@var{make-uniform-array} may be unrolled, some arrays made by\n"
521 "@var{make-shared-array} may not be.\n\n"
522 "If the optional argument @var{strict} is provided, a shared array will\n"
523 "be returned only if its elements are stored internally contiguous in\n"
524 "memory.")
1bbd0b84 525#define FUNC_NAME s_scm_array_contents
0f2d19dd
JB
526{
527 SCM sra;
e0e49670 528
20930f28 529 if (scm_is_generalized_vector (ra))
e0e49670
MV
530 return ra;
531
04b87de5 532 if (SCM_I_ARRAYP (ra))
0f2d19dd 533 {
04b87de5
MV
534 size_t k, ndim = SCM_I_ARRAY_NDIM (ra), len = 1;
535 if (!SCM_I_ARRAYP (ra) || !SCM_I_ARRAY_CONTP (ra))
20930f28
MV
536 return SCM_BOOL_F;
537 for (k = 0; k < ndim; k++)
04b87de5 538 len *= SCM_I_ARRAY_DIMS (ra)[k].ubnd - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1;
943a0a87 539 if (!SCM_UNBNDP (strict) && scm_is_true (strict))
74014c46 540 {
04b87de5 541 if (ndim && (1 != SCM_I_ARRAY_DIMS (ra)[ndim - 1].inc))
20930f28 542 return SCM_BOOL_F;
04b87de5 543 if (scm_is_bitvector (SCM_I_ARRAY_V (ra)))
20930f28 544 {
04b87de5
MV
545 if (len != scm_c_bitvector_length (SCM_I_ARRAY_V (ra)) ||
546 SCM_I_ARRAY_BASE (ra) % SCM_LONG_BIT ||
20930f28
MV
547 len % SCM_LONG_BIT)
548 return SCM_BOOL_F;
549 }
74014c46 550 }
20930f28
MV
551
552 {
04b87de5 553 SCM v = SCM_I_ARRAY_V (ra);
20930f28 554 size_t length = scm_c_generalized_vector_length (v);
04b87de5 555 if ((len == length) && 0 == SCM_I_ARRAY_BASE (ra) && SCM_I_ARRAY_DIMS (ra)->inc)
20930f28 556 return v;
0f2d19dd 557 }
20930f28 558
66b9d7d3 559 sra = scm_i_make_array (1);
04b87de5
MV
560 SCM_I_ARRAY_DIMS (sra)->lbnd = 0;
561 SCM_I_ARRAY_DIMS (sra)->ubnd = len - 1;
562 SCM_I_ARRAY_V (sra) = SCM_I_ARRAY_V (ra);
563 SCM_I_ARRAY_BASE (sra) = SCM_I_ARRAY_BASE (ra);
564 SCM_I_ARRAY_DIMS (sra)->inc = (ndim ? SCM_I_ARRAY_DIMS (ra)[ndim - 1].inc : 1);
20930f28 565 return sra;
0f2d19dd 566 }
02339e5b
MV
567 else
568 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
0f2d19dd 569}
1bbd0b84 570#undef FUNC_NAME
0f2d19dd 571
1cc91f1b 572
943a0a87
AW
573static void
574list_to_array (SCM lst, scm_t_array_handle *handle, ssize_t pos, size_t k)
575{
576 if (k == scm_array_handle_rank (handle))
577 scm_array_handle_set (handle, pos, lst);
578 else
579 {
580 scm_t_array_dim *dim = scm_array_handle_dims (handle) + k;
581 ssize_t inc = dim->inc;
582 size_t len = 1 + dim->ubnd - dim->lbnd, n;
583 char *errmsg = NULL;
584
585 n = len;
586 while (n > 0 && scm_is_pair (lst))
587 {
588 list_to_array (SCM_CAR (lst), handle, pos, k + 1);
589 pos += inc;
590 lst = SCM_CDR (lst);
591 n -= 1;
592 }
593 if (n != 0)
594 errmsg = "too few elements for array dimension ~a, need ~a";
595 if (!scm_is_null (lst))
596 errmsg = "too many elements for array dimension ~a, want ~a";
597 if (errmsg)
598 scm_misc_error (NULL, errmsg, scm_list_2 (scm_from_ulong (k),
599 scm_from_size_t (len)));
600 }
601}
602
1cc91f1b 603
f301dbf3 604SCM_DEFINE (scm_list_to_typed_array, "list->typed-array", 3, 0, 0,
2caaadd1 605 (SCM type, SCM shape, SCM lst),
f301dbf3
MV
606 "Return an array of the type @var{type}\n"
607 "with elements the same as those of @var{lst}.\n"
bfad4005 608 "\n"
2caaadd1
MV
609 "The argument @var{shape} determines the number of dimensions\n"
610 "of the array and their shape. It is either an exact integer,\n"
611 "giving the\n"
612 "number of dimensions directly, or a list whose length\n"
613 "specifies the number of dimensions and each element specified\n"
614 "the lower and optionally the upper bound of the corresponding\n"
615 "dimension.\n"
616 "When the element is list of two elements, these elements\n"
617 "give the lower and upper bounds. When it is an exact\n"
618 "integer, it gives only the lower bound.")
f301dbf3 619#define FUNC_NAME s_scm_list_to_typed_array
0f2d19dd 620{
2caaadd1 621 SCM row;
0f2d19dd 622 SCM ra;
bcbbea0e 623 scm_t_array_handle handle;
bfad4005 624
bfad4005 625 row = lst;
2caaadd1 626 if (scm_is_integer (shape))
0f2d19dd 627 {
2caaadd1
MV
628 size_t k = scm_to_size_t (shape);
629 shape = SCM_EOL;
bfad4005
MV
630 while (k-- > 0)
631 {
632 shape = scm_cons (scm_length (row), shape);
2caaadd1 633 if (k > 0 && !scm_is_null (row))
bfad4005
MV
634 row = scm_car (row);
635 }
636 }
637 else
638 {
2caaadd1
MV
639 SCM shape_spec = shape;
640 shape = SCM_EOL;
bfad4005
MV
641 while (1)
642 {
2caaadd1
MV
643 SCM spec = scm_car (shape_spec);
644 if (scm_is_pair (spec))
645 shape = scm_cons (spec, shape);
646 else
647 shape = scm_cons (scm_list_2 (spec,
648 scm_sum (scm_sum (spec,
649 scm_length (row)),
650 scm_from_int (-1))),
651 shape);
652 shape_spec = scm_cdr (shape_spec);
653 if (scm_is_pair (shape_spec))
654 {
655 if (!scm_is_null (row))
656 row = scm_car (row);
657 }
bfad4005
MV
658 else
659 break;
660 }
0f2d19dd 661 }
bfad4005 662
f0b91039
MV
663 ra = scm_make_typed_array (type, SCM_UNSPECIFIED,
664 scm_reverse_x (shape, SCM_EOL));
20930f28 665
bcbbea0e 666 scm_array_get_handle (ra, &handle);
943a0a87 667 list_to_array (lst, &handle, 0, 0);
bcbbea0e
MV
668 scm_array_handle_release (&handle);
669
670 return ra;
0f2d19dd 671}
1bbd0b84 672#undef FUNC_NAME
0f2d19dd 673
f301dbf3
MV
674SCM_DEFINE (scm_list_to_array, "list->array", 2, 0, 0,
675 (SCM ndim, SCM lst),
676 "Return an array with elements the same as those of @var{lst}.")
677#define FUNC_NAME s_scm_list_to_array
678{
679 return scm_list_to_typed_array (SCM_BOOL_T, ndim, lst);
680}
681#undef FUNC_NAME
682
e0e49670
MV
683/* Print dimension DIM of ARRAY.
684 */
0f2d19dd 685
e0e49670 686static int
943a0a87 687scm_i_print_array_dimension (scm_t_array_handle *h, int dim, int pos,
e0e49670
MV
688 SCM port, scm_print_state *pstate)
689{
943a0a87
AW
690 if (dim == h->ndims)
691 scm_iprin1 (scm_array_handle_ref (h, pos), port, pstate);
692 else
e0e49670 693 {
943a0a87
AW
694 ssize_t i;
695 scm_putc ('(', port);
696 for (i = h->dims[dim].lbnd; i <= h->dims[dim].ubnd;
697 i++, pos += h->dims[dim].inc)
698 {
699 scm_i_print_array_dimension (h, dim+1, pos, port, pstate);
700 if (i < h->dims[dim].ubnd)
701 scm_putc (' ', port);
702 }
703 scm_putc (')', port);
e0e49670 704 }
e0e49670
MV
705 return 1;
706}
707
943a0a87 708/* Print an array.
e0e49670
MV
709*/
710
e0e49670
MV
711static int
712scm_i_print_array (SCM array, SCM port, scm_print_state *pstate)
713{
943a0a87 714 scm_t_array_handle h;
e0e49670 715 long i;
2caaadd1 716 int print_lbnds = 0, zero_size = 0, print_lens = 0;
e0e49670 717
943a0a87
AW
718 scm_array_get_handle (array, &h);
719
e0e49670 720 scm_putc ('#', port);
943a0a87
AW
721 if (h.ndims != 1 || h.dims[0].lbnd != 0)
722 scm_intprint (h.ndims, 10, port);
723 if (h.element_type != SCM_ARRAY_ELEMENT_TYPE_SCM)
724 scm_write (scm_array_handle_element_type (&h), port);
20930f28 725
943a0a87 726 for (i = 0; i < h.ndims; i++)
2caaadd1 727 {
943a0a87 728 if (h.dims[i].lbnd != 0)
2caaadd1 729 print_lbnds = 1;
943a0a87 730 if (h.dims[i].ubnd - h.dims[i].lbnd + 1 == 0)
2caaadd1
MV
731 zero_size = 1;
732 else if (zero_size)
733 print_lens = 1;
734 }
735
736 if (print_lbnds || print_lens)
943a0a87 737 for (i = 0; i < h.ndims; i++)
e0e49670 738 {
2caaadd1 739 if (print_lbnds)
e0e49670
MV
740 {
741 scm_putc ('@', port);
943a0a87 742 scm_intprint (h.dims[i].lbnd, 10, port);
2caaadd1
MV
743 }
744 if (print_lens)
745 {
746 scm_putc (':', port);
943a0a87 747 scm_intprint (h.dims[i].ubnd - h.dims[i].lbnd + 1,
2caaadd1 748 10, port);
e0e49670 749 }
e0e49670
MV
750 }
751
943a0a87 752 if (h.ndims == 0)
5f37cb63
MV
753 {
754 /* Rank zero arrays, which are really just scalars, are printed
755 specially. The consequent way would be to print them as
756
757 #0 OBJ
758
759 where OBJ is the printed representation of the scalar, but we
760 print them instead as
761
762 #0(OBJ)
763
764 to make them look less strange.
765
766 Just printing them as
767
768 OBJ
769
770 would be correct in a way as well, but zero rank arrays are
771 not really the same as Scheme values since they are boxed and
772 can be modified with array-set!, say.
773 */
774 scm_putc ('(', port);
943a0a87 775 scm_i_print_array_dimension (&h, 0, 0, port, pstate);
5f37cb63
MV
776 scm_putc (')', port);
777 return 1;
778 }
779 else
943a0a87 780 return scm_i_print_array_dimension (&h, 0, 0, port, pstate);
e0e49670 781}
1cc91f1b 782
bfad4005
MV
783/* Read an array. This function can also read vectors and uniform
784 vectors. Also, the conflict between '#f' and '#f32' and '#f64' is
785 handled here.
786
787 C is the first character read after the '#'.
788*/
789
bfad4005 790static SCM
f301dbf3 791tag_to_type (const char *tag, SCM port)
bfad4005 792{
5f37cb63
MV
793 if (*tag == '\0')
794 return SCM_BOOL_T;
795 else
796 return scm_from_locale_symbol (tag);
bfad4005
MV
797}
798
2caaadd1
MV
799static int
800read_decimal_integer (SCM port, int c, ssize_t *resp)
801{
802 ssize_t sign = 1;
803 ssize_t res = 0;
804 int got_it = 0;
805
806 if (c == '-')
807 {
808 sign = -1;
809 c = scm_getc (port);
810 }
811
812 while ('0' <= c && c <= '9')
813 {
814 res = 10*res + c-'0';
815 got_it = 1;
816 c = scm_getc (port);
817 }
818
819 if (got_it)
f30e1bdf 820 *resp = sign * res;
2caaadd1
MV
821 return c;
822}
823
bfad4005
MV
824SCM
825scm_i_read_array (SCM port, int c)
826{
5a6d139b 827 ssize_t rank;
bfad4005
MV
828 int got_rank;
829 char tag[80];
830 int tag_len;
831
2caaadd1 832 SCM shape = SCM_BOOL_F, elements;
bfad4005
MV
833
834 /* XXX - shortcut for ordinary vectors. Shouldn't be necessary but
835 the array code can not deal with zero-length dimensions yet, and
836 we want to allow zero-length vectors, of course.
837 */
838 if (c == '(')
839 {
840 scm_ungetc (c, port);
841 return scm_vector (scm_read (port));
842 }
843
844 /* Disambiguate between '#f' and uniform floating point vectors.
845 */
846 if (c == 'f')
847 {
848 c = scm_getc (port);
849 if (c != '3' && c != '6')
850 {
851 if (c != EOF)
852 scm_ungetc (c, port);
853 return SCM_BOOL_F;
854 }
855 rank = 1;
856 got_rank = 1;
857 tag[0] = 'f';
858 tag_len = 1;
859 goto continue_reading_tag;
860 }
861
2caaadd1
MV
862 /* Read rank.
863 */
864 rank = 1;
865 c = read_decimal_integer (port, c, &rank);
866 if (rank < 0)
867 scm_i_input_error (NULL, port, "array rank must be non-negative",
868 SCM_EOL);
bfad4005 869
2caaadd1
MV
870 /* Read tag.
871 */
bfad4005
MV
872 tag_len = 0;
873 continue_reading_tag:
2caaadd1 874 while (c != EOF && c != '(' && c != '@' && c != ':' && tag_len < 80)
bfad4005
MV
875 {
876 tag[tag_len++] = c;
877 c = scm_getc (port);
878 }
879 tag[tag_len] = '\0';
880
2caaadd1
MV
881 /* Read shape.
882 */
883 if (c == '@' || c == ':')
bfad4005 884 {
2caaadd1 885 shape = SCM_EOL;
5f37cb63
MV
886
887 do
bfad4005 888 {
2caaadd1
MV
889 ssize_t lbnd = 0, len = 0;
890 SCM s;
5f37cb63 891
2caaadd1 892 if (c == '@')
5f37cb63 893 {
5f37cb63 894 c = scm_getc (port);
2caaadd1 895 c = read_decimal_integer (port, c, &lbnd);
5f37cb63 896 }
2caaadd1
MV
897
898 s = scm_from_ssize_t (lbnd);
899
900 if (c == ':')
5f37cb63 901 {
5f37cb63 902 c = scm_getc (port);
2caaadd1 903 c = read_decimal_integer (port, c, &len);
f30e1bdf
LC
904 if (len < 0)
905 scm_i_input_error (NULL, port,
906 "array length must be non-negative",
907 SCM_EOL);
908
2caaadd1 909 s = scm_list_2 (s, scm_from_ssize_t (lbnd+len-1));
5f37cb63 910 }
2caaadd1
MV
911
912 shape = scm_cons (s, shape);
913 } while (c == '@' || c == ':');
914
915 shape = scm_reverse_x (shape, SCM_EOL);
bfad4005
MV
916 }
917
918 /* Read nested lists of elements.
919 */
920 if (c != '(')
921 scm_i_input_error (NULL, port,
922 "missing '(' in vector or array literal",
923 SCM_EOL);
924 scm_ungetc (c, port);
925 elements = scm_read (port);
926
2caaadd1 927 if (scm_is_false (shape))
5a6d139b 928 shape = scm_from_ssize_t (rank);
2caaadd1
MV
929 else if (scm_ilength (shape) != rank)
930 scm_i_input_error
931 (NULL, port,
932 "the number of shape specifications must match the array rank",
933 SCM_EOL);
bfad4005 934
5f37cb63
MV
935 /* Handle special print syntax of rank zero arrays; see
936 scm_i_print_array for a rationale.
937 */
938 if (rank == 0)
2caaadd1
MV
939 {
940 if (!scm_is_pair (elements))
941 scm_i_input_error (NULL, port,
942 "too few elements in array literal, need 1",
943 SCM_EOL);
944 if (!scm_is_null (SCM_CDR (elements)))
945 scm_i_input_error (NULL, port,
946 "too many elements in array literal, want 1",
947 SCM_EOL);
948 elements = SCM_CAR (elements);
949 }
5f37cb63
MV
950
951 /* Construct array.
952 */
2caaadd1 953 return scm_list_to_typed_array (tag_to_type (tag, port), shape, elements);
bfad4005
MV
954}
955
ab1be174 956
2a610be5
AW
957static SCM
958array_handle_ref (scm_t_array_handle *h, size_t pos)
959{
960 return scm_c_generalized_vector_ref (SCM_I_ARRAY_V (h->array), pos);
961}
962
963static void
964array_handle_set (scm_t_array_handle *h, size_t pos, SCM val)
965{
966 scm_c_generalized_vector_set_x (SCM_I_ARRAY_V (h->array), pos, val);
967}
968
969/* FIXME: should be handle for vect? maybe not, because of dims */
970static void
971array_get_handle (SCM array, scm_t_array_handle *h)
972{
973 scm_t_array_handle vh;
974 scm_array_get_handle (SCM_I_ARRAY_V (array), &vh);
975 h->element_type = vh.element_type;
976 h->elements = vh.elements;
977 h->writable_elements = vh.writable_elements;
978 scm_array_handle_release (&vh);
979
980 h->dims = SCM_I_ARRAY_DIMS (array);
981 h->ndims = SCM_I_ARRAY_NDIM (array);
982 h->base = SCM_I_ARRAY_BASE (array);
983}
984
735bcfe5
AW
985SCM_ARRAY_IMPLEMENTATION (SCM_SMOB_TYPE_BITS (scm_i_tc16_array),
986 SCM_SMOB_TYPE_MASK,
2a610be5 987 array_handle_ref, array_handle_set,
f65e0168 988 array_get_handle)
2a610be5 989
0f2d19dd 990void
2fa901a5 991scm_init_arrays ()
0f2d19dd 992{
04b87de5 993 scm_i_tc16_array = scm_make_smob_type ("array", 0);
04b87de5
MV
994 scm_set_smob_print (scm_i_tc16_array, scm_i_print_array);
995 scm_set_smob_equalp (scm_i_tc16_array, scm_array_equal_p);
996
0f2d19dd 997 scm_add_feature ("array");
20930f28 998
2fa901a5 999#include "libguile/arrays.x"
bfad4005 1000
0f2d19dd 1001}
89e00824
ML
1002
1003/*
1004 Local Variables:
1005 c-file-style: "gnu"
1006 End:
1007*/