Merge commit '40a723a92236fe4e58feb89057b4182b1fc76810'
[bpt/guile.git] / libguile / arrays.c
1 /* Copyright (C) 1995,1996,1997,1998,2000,2001,2002,2003,2004,2005,
2 * 2006, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
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.
8 *
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
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
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301 USA
18 */
19
20
21 \f
22
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
26
27 #include <stdio.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <assert.h>
31
32 #include "libguile/_scm.h"
33 #include "libguile/__scm.h"
34 #include "libguile/eq.h"
35 #include "libguile/chars.h"
36 #include "libguile/eval.h"
37 #include "libguile/fports.h"
38 #include "libguile/feature.h"
39 #include "libguile/root.h"
40 #include "libguile/strings.h"
41 #include "libguile/srfi-13.h"
42 #include "libguile/srfi-4.h"
43 #include "libguile/vectors.h"
44 #include "libguile/bitvectors.h"
45 #include "libguile/bytevectors.h"
46 #include "libguile/list.h"
47 #include "libguile/dynwind.h"
48 #include "libguile/read.h"
49
50 #include "libguile/validate.h"
51 #include "libguile/arrays.h"
52 #include "libguile/array-map.h"
53 #include "libguile/generalized-vectors.h"
54 #include "libguile/generalized-arrays.h"
55 #include "libguile/uniform.h"
56
57
58 #define SCM_SET_ARRAY_CONTIGUOUS_FLAG(x) \
59 (SCM_SET_CELL_WORD_0 ((x), SCM_CELL_WORD_0 (x) | (SCM_I_ARRAY_FLAG_CONTIGUOUS << 16)))
60 #define SCM_CLR_ARRAY_CONTIGUOUS_FLAG(x) \
61 (SCM_SET_CELL_WORD_0 ((x), SCM_CELL_WORD_0 (x) & ~(SCM_I_ARRAY_FLAG_CONTIGUOUS << 16)))
62
63
64 SCM_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 {
69 if (!scm_is_array (ra))
70 scm_wrong_type_arg_msg (FUNC_NAME, SCM_ARG1, ra, "array");
71 else if (SCM_I_ARRAYP (ra))
72 return SCM_I_ARRAY_V (ra);
73 else
74 return ra;
75 }
76 #undef FUNC_NAME
77
78
79 SCM_DEFINE (scm_shared_array_offset, "shared-array-offset", 1, 0, 0,
80 (SCM ra),
81 "Return the root vector index of the first element in the array.")
82 #define FUNC_NAME s_scm_shared_array_offset
83 {
84 scm_t_array_handle handle;
85 SCM res;
86
87 scm_array_get_handle (ra, &handle);
88 res = scm_from_size_t (handle.base);
89 scm_array_handle_release (&handle);
90 return res;
91 }
92 #undef FUNC_NAME
93
94
95 SCM_DEFINE (scm_shared_array_increments, "shared-array-increments", 1, 0, 0,
96 (SCM ra),
97 "For each dimension, return the distance between elements in the root vector.")
98 #define FUNC_NAME s_scm_shared_array_increments
99 {
100 scm_t_array_handle handle;
101 SCM res = SCM_EOL;
102 size_t k;
103 scm_t_array_dim *s;
104
105 scm_array_get_handle (ra, &handle);
106 k = scm_array_handle_rank (&handle);
107 s = scm_array_handle_dims (&handle);
108 while (k--)
109 res = scm_cons (scm_from_ssize_t (s[k].inc), res);
110 scm_array_handle_release (&handle);
111 return res;
112 }
113 #undef FUNC_NAME
114
115 SCM
116 scm_i_make_array (int ndim)
117 {
118 SCM ra;
119 ra = scm_cell (((scm_t_bits) ndim << 17) + scm_tc7_array,
120 (scm_t_bits) scm_gc_malloc (sizeof (scm_i_t_array) +
121 ndim * sizeof (scm_t_array_dim),
122 "array"));
123 SCM_I_ARRAY_V (ra) = SCM_BOOL_F;
124 return ra;
125 }
126
127 static char s_bad_spec[] = "Bad scm_array dimension";
128
129
130 /* Increments will still need to be set. */
131
132 static SCM
133 scm_i_shap2ra (SCM args)
134 {
135 scm_t_array_dim *s;
136 SCM ra, spec, sp;
137 int ndim = scm_ilength (args);
138 if (ndim < 0)
139 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
140
141 ra = scm_i_make_array (ndim);
142 SCM_I_ARRAY_BASE (ra) = 0;
143 s = SCM_I_ARRAY_DIMS (ra);
144 for (; !scm_is_null (args); s++, args = SCM_CDR (args))
145 {
146 spec = SCM_CAR (args);
147 if (scm_is_integer (spec))
148 {
149 if (scm_to_long (spec) < 0)
150 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
151 s->lbnd = 0;
152 s->ubnd = scm_to_long (spec) - 1;
153 s->inc = 1;
154 }
155 else
156 {
157 if (!scm_is_pair (spec) || !scm_is_integer (SCM_CAR (spec)))
158 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
159 s->lbnd = scm_to_long (SCM_CAR (spec));
160 sp = SCM_CDR (spec);
161 if (!scm_is_pair (sp)
162 || !scm_is_integer (SCM_CAR (sp))
163 || !scm_is_null (SCM_CDR (sp)))
164 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
165 s->ubnd = scm_to_long (SCM_CAR (sp));
166 s->inc = 1;
167 }
168 }
169 return ra;
170 }
171
172 SCM_DEFINE (scm_make_typed_array, "make-typed-array", 2, 0, 1,
173 (SCM type, SCM fill, SCM bounds),
174 "Create and return an array of type @var{type}.")
175 #define FUNC_NAME s_scm_make_typed_array
176 {
177 size_t k, rlen = 1;
178 scm_t_array_dim *s;
179 SCM ra;
180
181 ra = scm_i_shap2ra (bounds);
182 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
183 s = SCM_I_ARRAY_DIMS (ra);
184 k = SCM_I_ARRAY_NDIM (ra);
185
186 while (k--)
187 {
188 s[k].inc = rlen;
189 SCM_ASSERT_RANGE (1, bounds, s[k].lbnd <= s[k].ubnd + 1);
190 rlen = (s[k].ubnd - s[k].lbnd + 1) * s[k].inc;
191 }
192
193 if (scm_is_eq (fill, SCM_UNSPECIFIED))
194 fill = SCM_UNDEFINED;
195
196 SCM_I_ARRAY_V (ra) =
197 scm_make_generalized_vector (type, scm_from_size_t (rlen), fill);
198
199 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
200 if (0 == s->lbnd)
201 return SCM_I_ARRAY_V (ra);
202
203 return ra;
204 }
205 #undef FUNC_NAME
206
207 SCM
208 scm_from_contiguous_typed_array (SCM type, SCM bounds, const void *bytes,
209 size_t byte_len)
210 #define FUNC_NAME "scm_from_contiguous_typed_array"
211 {
212 size_t k, rlen = 1;
213 scm_t_array_dim *s;
214 SCM ra;
215 scm_t_array_handle h;
216 void *elts;
217 size_t sz;
218
219 ra = scm_i_shap2ra (bounds);
220 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
221 s = SCM_I_ARRAY_DIMS (ra);
222 k = SCM_I_ARRAY_NDIM (ra);
223
224 while (k--)
225 {
226 s[k].inc = rlen;
227 SCM_ASSERT_RANGE (1, bounds, s[k].lbnd <= s[k].ubnd + 1);
228 rlen = (s[k].ubnd - s[k].lbnd + 1) * s[k].inc;
229 }
230 SCM_I_ARRAY_V (ra) =
231 scm_make_generalized_vector (type, scm_from_size_t (rlen), SCM_UNDEFINED);
232
233
234 scm_array_get_handle (ra, &h);
235 elts = h.writable_elements;
236 sz = scm_array_handle_uniform_element_bit_size (&h);
237 scm_array_handle_release (&h);
238
239 if (sz >= 8 && ((sz % 8) == 0))
240 {
241 if (byte_len % (sz / 8))
242 SCM_MISC_ERROR ("byte length not a multiple of the unit size", SCM_EOL);
243 if (byte_len / (sz / 8) != rlen)
244 SCM_MISC_ERROR ("byte length and dimensions do not match", SCM_EOL);
245 }
246 else if (sz < 8)
247 {
248 /* Elements of sub-byte size (bitvectors) are addressed in 32-bit
249 units. */
250 if (byte_len != ((rlen * sz + 31) / 32) * 4)
251 SCM_MISC_ERROR ("byte length and dimensions do not match", SCM_EOL);
252 }
253 else
254 /* an internal guile error, really */
255 SCM_MISC_ERROR ("uniform elements larger than 8 bits must fill whole bytes", SCM_EOL);
256
257 memcpy (elts, bytes, byte_len);
258
259 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
260 if (0 == s->lbnd)
261 return SCM_I_ARRAY_V (ra);
262 return ra;
263 }
264 #undef FUNC_NAME
265
266 SCM
267 scm_from_contiguous_array (SCM bounds, const SCM *elts, size_t len)
268 #define FUNC_NAME "scm_from_contiguous_array"
269 {
270 size_t k, rlen = 1;
271 scm_t_array_dim *s;
272 SCM ra;
273 scm_t_array_handle h;
274
275 ra = scm_i_shap2ra (bounds);
276 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
277 s = SCM_I_ARRAY_DIMS (ra);
278 k = SCM_I_ARRAY_NDIM (ra);
279
280 while (k--)
281 {
282 s[k].inc = rlen;
283 SCM_ASSERT_RANGE (1, bounds, s[k].lbnd <= s[k].ubnd + 1);
284 rlen = (s[k].ubnd - s[k].lbnd + 1) * s[k].inc;
285 }
286 if (rlen != len)
287 SCM_MISC_ERROR ("element length and dimensions do not match", SCM_EOL);
288
289 SCM_I_ARRAY_V (ra) = scm_c_make_vector (rlen, SCM_UNDEFINED);
290 scm_array_get_handle (ra, &h);
291 memcpy (h.writable_elements, elts, rlen * sizeof(SCM));
292 scm_array_handle_release (&h);
293
294 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
295 if (0 == s->lbnd)
296 return SCM_I_ARRAY_V (ra);
297 return ra;
298 }
299 #undef FUNC_NAME
300
301 SCM_DEFINE (scm_make_array, "make-array", 1, 0, 1,
302 (SCM fill, SCM bounds),
303 "Create and return an array.")
304 #define FUNC_NAME s_scm_make_array
305 {
306 return scm_make_typed_array (SCM_BOOL_T, fill, bounds);
307 }
308 #undef FUNC_NAME
309
310 static void
311 scm_i_ra_set_contp (SCM ra)
312 {
313 size_t k = SCM_I_ARRAY_NDIM (ra);
314 if (k)
315 {
316 long inc = SCM_I_ARRAY_DIMS (ra)[k - 1].inc;
317 while (k--)
318 {
319 if (inc != SCM_I_ARRAY_DIMS (ra)[k].inc)
320 {
321 SCM_CLR_ARRAY_CONTIGUOUS_FLAG (ra);
322 return;
323 }
324 inc *= (SCM_I_ARRAY_DIMS (ra)[k].ubnd
325 - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1);
326 }
327 }
328 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
329 }
330
331
332 SCM_DEFINE (scm_make_shared_array, "make-shared-array", 2, 0, 1,
333 (SCM oldra, SCM mapfunc, SCM dims),
334 "@code{make-shared-array} can be used to create shared subarrays\n"
335 "of other arrays. The @var{mapfunc} is a function that\n"
336 "translates coordinates in the new array into coordinates in the\n"
337 "old array. A @var{mapfunc} must be linear, and its range must\n"
338 "stay within the bounds of the old array, but it can be\n"
339 "otherwise arbitrary. A simple example:\n"
340 "@lisp\n"
341 "(define fred (make-array #f 8 8))\n"
342 "(define freds-diagonal\n"
343 " (make-shared-array fred (lambda (i) (list i i)) 8))\n"
344 "(array-set! freds-diagonal 'foo 3)\n"
345 "(array-ref fred 3 3) @result{} foo\n"
346 "(define freds-center\n"
347 " (make-shared-array fred (lambda (i j) (list (+ 3 i) (+ 3 j))) 2 2))\n"
348 "(array-ref freds-center 0 0) @result{} foo\n"
349 "@end lisp")
350 #define FUNC_NAME s_scm_make_shared_array
351 {
352 scm_t_array_handle old_handle;
353 SCM ra;
354 SCM inds, indptr;
355 SCM imap;
356 size_t k;
357 ssize_t i;
358 long old_base, old_min, new_min, old_max, new_max;
359 scm_t_array_dim *s;
360
361 SCM_VALIDATE_REST_ARGUMENT (dims);
362 SCM_VALIDATE_PROC (2, mapfunc);
363 ra = scm_i_shap2ra (dims);
364
365 scm_array_get_handle (oldra, &old_handle);
366
367 if (SCM_I_ARRAYP (oldra))
368 {
369 SCM_I_ARRAY_V (ra) = SCM_I_ARRAY_V (oldra);
370 old_base = old_min = old_max = SCM_I_ARRAY_BASE (oldra);
371 s = scm_array_handle_dims (&old_handle);
372 k = scm_array_handle_rank (&old_handle);
373 while (k--)
374 {
375 if (s[k].inc > 0)
376 old_max += (s[k].ubnd - s[k].lbnd) * s[k].inc;
377 else
378 old_min += (s[k].ubnd - s[k].lbnd) * s[k].inc;
379 }
380 }
381 else
382 {
383 SCM_I_ARRAY_V (ra) = oldra;
384 old_base = old_min = 0;
385 old_max = scm_c_array_length (oldra) - 1;
386 }
387
388 inds = SCM_EOL;
389 s = SCM_I_ARRAY_DIMS (ra);
390 for (k = 0; k < SCM_I_ARRAY_NDIM (ra); k++)
391 {
392 inds = scm_cons (scm_from_long (s[k].lbnd), inds);
393 if (s[k].ubnd < s[k].lbnd)
394 {
395 if (1 == SCM_I_ARRAY_NDIM (ra))
396 ra = scm_make_generalized_vector (scm_array_type (ra),
397 SCM_INUM0, SCM_UNDEFINED);
398 else
399 SCM_I_ARRAY_V (ra) =
400 scm_make_generalized_vector (scm_array_type (ra),
401 SCM_INUM0, SCM_UNDEFINED);
402 scm_array_handle_release (&old_handle);
403 return ra;
404 }
405 }
406
407 imap = scm_apply_0 (mapfunc, scm_reverse (inds));
408 i = scm_array_handle_pos (&old_handle, imap);
409 SCM_I_ARRAY_BASE (ra) = new_min = new_max = i + old_base;
410 indptr = inds;
411 k = SCM_I_ARRAY_NDIM (ra);
412 while (k--)
413 {
414 if (s[k].ubnd > s[k].lbnd)
415 {
416 SCM_SETCAR (indptr, scm_sum (SCM_CAR (indptr), scm_from_int (1)));
417 imap = scm_apply_0 (mapfunc, scm_reverse (inds));
418 s[k].inc = scm_array_handle_pos (&old_handle, imap) - i;
419 i += s[k].inc;
420 if (s[k].inc > 0)
421 new_max += (s[k].ubnd - s[k].lbnd) * s[k].inc;
422 else
423 new_min += (s[k].ubnd - s[k].lbnd) * s[k].inc;
424 }
425 else
426 s[k].inc = new_max - new_min + 1; /* contiguous by default */
427 indptr = SCM_CDR (indptr);
428 }
429
430 scm_array_handle_release (&old_handle);
431
432 if (old_min > new_min || old_max < new_max)
433 SCM_MISC_ERROR ("mapping out of range", SCM_EOL);
434 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
435 {
436 SCM v = SCM_I_ARRAY_V (ra);
437 size_t length = scm_c_array_length (v);
438 if (1 == s->inc && 0 == s->lbnd && length == 1 + s->ubnd)
439 return v;
440 if (s->ubnd < s->lbnd)
441 return scm_make_generalized_vector (scm_array_type (ra), SCM_INUM0,
442 SCM_UNDEFINED);
443 }
444 scm_i_ra_set_contp (ra);
445 return ra;
446 }
447 #undef FUNC_NAME
448
449
450 /* args are RA . DIMS */
451 SCM_DEFINE (scm_transpose_array, "transpose-array", 1, 0, 1,
452 (SCM ra, SCM args),
453 "Return an array sharing contents with @var{ra}, but with\n"
454 "dimensions arranged in a different order. There must be one\n"
455 "@var{dim} argument for each dimension of @var{ra}.\n"
456 "@var{dim0}, @var{dim1}, @dots{} should be integers between 0\n"
457 "and the rank of the array to be returned. Each integer in that\n"
458 "range must appear at least once in the argument list.\n"
459 "\n"
460 "The values of @var{dim0}, @var{dim1}, @dots{} correspond to\n"
461 "dimensions in the array to be returned, their positions in the\n"
462 "argument list to dimensions of @var{ra}. Several @var{dim}s\n"
463 "may have the same value, in which case the returned array will\n"
464 "have smaller rank than @var{ra}.\n"
465 "\n"
466 "@lisp\n"
467 "(transpose-array '#2((a b) (c d)) 1 0) @result{} #2((a c) (b d))\n"
468 "(transpose-array '#2((a b) (c d)) 0 0) @result{} #1(a d)\n"
469 "(transpose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1 1 0) @result{}\n"
470 " #2((a 4) (b 5) (c 6))\n"
471 "@end lisp")
472 #define FUNC_NAME s_scm_transpose_array
473 {
474 SCM res, vargs;
475 scm_t_array_dim *s, *r;
476 int ndim, i, k;
477
478 SCM_VALIDATE_REST_ARGUMENT (args);
479 SCM_ASSERT (SCM_HEAP_OBJECT_P (ra), ra, SCM_ARG1, FUNC_NAME);
480
481 switch (scm_c_array_rank (ra))
482 {
483 case 0:
484 if (!scm_is_null (args))
485 SCM_WRONG_NUM_ARGS ();
486 return ra;
487 case 1:
488 /* Make sure that we are called with a single zero as
489 arguments.
490 */
491 if (scm_is_null (args) || !scm_is_null (SCM_CDR (args)))
492 SCM_WRONG_NUM_ARGS ();
493 SCM_VALIDATE_INT_COPY (SCM_ARG2, SCM_CAR (args), i);
494 SCM_ASSERT_RANGE (SCM_ARG2, SCM_CAR (args), i == 0);
495 return ra;
496 default:
497 vargs = scm_vector (args);
498 if (SCM_SIMPLE_VECTOR_LENGTH (vargs) != SCM_I_ARRAY_NDIM (ra))
499 SCM_WRONG_NUM_ARGS ();
500 ndim = 0;
501 for (k = 0; k < SCM_I_ARRAY_NDIM (ra); k++)
502 {
503 i = scm_to_signed_integer (SCM_SIMPLE_VECTOR_REF (vargs, k),
504 0, SCM_I_ARRAY_NDIM(ra));
505 if (ndim < i)
506 ndim = i;
507 }
508 ndim++;
509 res = scm_i_make_array (ndim);
510 SCM_I_ARRAY_V (res) = SCM_I_ARRAY_V (ra);
511 SCM_I_ARRAY_BASE (res) = SCM_I_ARRAY_BASE (ra);
512 for (k = ndim; k--;)
513 {
514 SCM_I_ARRAY_DIMS (res)[k].lbnd = 0;
515 SCM_I_ARRAY_DIMS (res)[k].ubnd = -1;
516 }
517 for (k = SCM_I_ARRAY_NDIM (ra); k--;)
518 {
519 i = scm_to_int (SCM_SIMPLE_VECTOR_REF (vargs, k));
520 s = &(SCM_I_ARRAY_DIMS (ra)[k]);
521 r = &(SCM_I_ARRAY_DIMS (res)[i]);
522 if (r->ubnd < r->lbnd)
523 {
524 r->lbnd = s->lbnd;
525 r->ubnd = s->ubnd;
526 r->inc = s->inc;
527 ndim--;
528 }
529 else
530 {
531 if (r->ubnd > s->ubnd)
532 r->ubnd = s->ubnd;
533 if (r->lbnd < s->lbnd)
534 {
535 SCM_I_ARRAY_BASE (res) += (s->lbnd - r->lbnd) * r->inc;
536 r->lbnd = s->lbnd;
537 }
538 r->inc += s->inc;
539 }
540 }
541 if (ndim > 0)
542 SCM_MISC_ERROR ("bad argument list", SCM_EOL);
543 scm_i_ra_set_contp (res);
544 return res;
545 }
546 }
547 #undef FUNC_NAME
548
549 /* attempts to unroll an array into a one-dimensional array.
550 returns the unrolled array or #f if it can't be done. */
551 /* if strict is not SCM_UNDEFINED, return #f if returned array
552 wouldn't have contiguous elements. */
553 SCM_DEFINE (scm_array_contents, "array-contents", 1, 1, 0,
554 (SCM ra, SCM strict),
555 "If @var{ra} may be @dfn{unrolled} into a one dimensional shared\n"
556 "array without changing their order (last subscript changing\n"
557 "fastest), then @code{array-contents} returns that shared array,\n"
558 "otherwise it returns @code{#f}. All arrays made by\n"
559 "@code{make-array} and @code{make-uniform-array} may be unrolled,\n"
560 "some arrays made by @code{make-shared-array} may not be. If\n"
561 "the optional argument @var{strict} is provided, a shared array\n"
562 "will be returned only if its elements are stored internally\n"
563 "contiguous in memory.")
564 #define FUNC_NAME s_scm_array_contents
565 {
566 SCM sra;
567
568 if (scm_is_generalized_vector (ra))
569 return ra;
570
571 if (SCM_I_ARRAYP (ra))
572 {
573 size_t k, ndim = SCM_I_ARRAY_NDIM (ra), len = 1;
574 if (!SCM_I_ARRAYP (ra) || !SCM_I_ARRAY_CONTP (ra))
575 return SCM_BOOL_F;
576 for (k = 0; k < ndim; k++)
577 len *= SCM_I_ARRAY_DIMS (ra)[k].ubnd - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1;
578 if (!SCM_UNBNDP (strict) && scm_is_true (strict))
579 {
580 if (ndim && (1 != SCM_I_ARRAY_DIMS (ra)[ndim - 1].inc))
581 return SCM_BOOL_F;
582 if (scm_is_bitvector (SCM_I_ARRAY_V (ra)))
583 {
584 if (len != scm_c_bitvector_length (SCM_I_ARRAY_V (ra)) ||
585 SCM_I_ARRAY_BASE (ra) % SCM_LONG_BIT ||
586 len % SCM_LONG_BIT)
587 return SCM_BOOL_F;
588 }
589 }
590
591 {
592 SCM v = SCM_I_ARRAY_V (ra);
593 size_t length = scm_c_array_length (v);
594 if ((len == length) && 0 == SCM_I_ARRAY_BASE (ra) && SCM_I_ARRAY_DIMS (ra)->inc)
595 return v;
596 }
597
598 sra = scm_i_make_array (1);
599 SCM_I_ARRAY_DIMS (sra)->lbnd = 0;
600 SCM_I_ARRAY_DIMS (sra)->ubnd = len - 1;
601 SCM_I_ARRAY_V (sra) = SCM_I_ARRAY_V (ra);
602 SCM_I_ARRAY_BASE (sra) = SCM_I_ARRAY_BASE (ra);
603 SCM_I_ARRAY_DIMS (sra)->inc = (ndim ? SCM_I_ARRAY_DIMS (ra)[ndim - 1].inc : 1);
604 return sra;
605 }
606 else
607 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
608 }
609 #undef FUNC_NAME
610
611
612 static void
613 list_to_array (SCM lst, scm_t_array_handle *handle, ssize_t pos, size_t k)
614 {
615 if (k == scm_array_handle_rank (handle))
616 scm_array_handle_set (handle, pos, lst);
617 else
618 {
619 scm_t_array_dim *dim = scm_array_handle_dims (handle) + k;
620 ssize_t inc = dim->inc;
621 size_t len = 1 + dim->ubnd - dim->lbnd, n;
622 char *errmsg = NULL;
623
624 n = len;
625 while (n > 0 && scm_is_pair (lst))
626 {
627 list_to_array (SCM_CAR (lst), handle, pos, k + 1);
628 pos += inc;
629 lst = SCM_CDR (lst);
630 n -= 1;
631 }
632 if (n != 0)
633 errmsg = "too few elements for array dimension ~a, need ~a";
634 if (!scm_is_null (lst))
635 errmsg = "too many elements for array dimension ~a, want ~a";
636 if (errmsg)
637 scm_misc_error (NULL, errmsg, scm_list_2 (scm_from_ulong (k),
638 scm_from_size_t (len)));
639 }
640 }
641
642
643 SCM_DEFINE (scm_list_to_typed_array, "list->typed-array", 3, 0, 0,
644 (SCM type, SCM shape, SCM lst),
645 "Return an array of the type @var{type}\n"
646 "with elements the same as those of @var{lst}.\n"
647 "\n"
648 "The argument @var{shape} determines the number of dimensions\n"
649 "of the array and their shape. It is either an exact integer,\n"
650 "giving the\n"
651 "number of dimensions directly, or a list whose length\n"
652 "specifies the number of dimensions and each element specified\n"
653 "the lower and optionally the upper bound of the corresponding\n"
654 "dimension.\n"
655 "When the element is list of two elements, these elements\n"
656 "give the lower and upper bounds. When it is an exact\n"
657 "integer, it gives only the lower bound.")
658 #define FUNC_NAME s_scm_list_to_typed_array
659 {
660 SCM row;
661 SCM ra;
662 scm_t_array_handle handle;
663
664 row = lst;
665 if (scm_is_integer (shape))
666 {
667 size_t k = scm_to_size_t (shape);
668 shape = SCM_EOL;
669 while (k-- > 0)
670 {
671 shape = scm_cons (scm_length (row), shape);
672 if (k > 0 && !scm_is_null (row))
673 row = scm_car (row);
674 }
675 }
676 else
677 {
678 SCM shape_spec = shape;
679 shape = SCM_EOL;
680 while (1)
681 {
682 SCM spec = scm_car (shape_spec);
683 if (scm_is_pair (spec))
684 shape = scm_cons (spec, shape);
685 else
686 shape = scm_cons (scm_list_2 (spec,
687 scm_sum (scm_sum (spec,
688 scm_length (row)),
689 scm_from_int (-1))),
690 shape);
691 shape_spec = scm_cdr (shape_spec);
692 if (scm_is_pair (shape_spec))
693 {
694 if (!scm_is_null (row))
695 row = scm_car (row);
696 }
697 else
698 break;
699 }
700 }
701
702 ra = scm_make_typed_array (type, SCM_UNSPECIFIED,
703 scm_reverse_x (shape, SCM_EOL));
704
705 scm_array_get_handle (ra, &handle);
706 list_to_array (lst, &handle, 0, 0);
707 scm_array_handle_release (&handle);
708
709 return ra;
710 }
711 #undef FUNC_NAME
712
713 SCM_DEFINE (scm_list_to_array, "list->array", 2, 0, 0,
714 (SCM ndim, SCM lst),
715 "Return an array with elements the same as those of @var{lst}.")
716 #define FUNC_NAME s_scm_list_to_array
717 {
718 return scm_list_to_typed_array (SCM_BOOL_T, ndim, lst);
719 }
720 #undef FUNC_NAME
721
722 /* Print dimension DIM of ARRAY.
723 */
724
725 static int
726 scm_i_print_array_dimension (scm_t_array_handle *h, int dim, int pos,
727 SCM port, scm_print_state *pstate)
728 {
729 if (dim == h->ndims)
730 scm_iprin1 (scm_array_handle_ref (h, pos), port, pstate);
731 else
732 {
733 ssize_t i;
734 scm_putc_unlocked ('(', port);
735 for (i = h->dims[dim].lbnd; i <= h->dims[dim].ubnd;
736 i++, pos += h->dims[dim].inc)
737 {
738 scm_i_print_array_dimension (h, dim+1, pos, port, pstate);
739 if (i < h->dims[dim].ubnd)
740 scm_putc_unlocked (' ', port);
741 }
742 scm_putc_unlocked (')', port);
743 }
744 return 1;
745 }
746
747 /* Print an array.
748 */
749
750 int
751 scm_i_print_array (SCM array, SCM port, scm_print_state *pstate)
752 {
753 scm_t_array_handle h;
754 long i;
755 int print_lbnds = 0, zero_size = 0, print_lens = 0;
756
757 scm_array_get_handle (array, &h);
758
759 scm_putc_unlocked ('#', port);
760 if (h.ndims != 1 || h.dims[0].lbnd != 0)
761 scm_intprint (h.ndims, 10, port);
762 if (h.element_type != SCM_ARRAY_ELEMENT_TYPE_SCM)
763 scm_write (scm_array_handle_element_type (&h), port);
764
765 for (i = 0; i < h.ndims; i++)
766 {
767 if (h.dims[i].lbnd != 0)
768 print_lbnds = 1;
769 if (h.dims[i].ubnd - h.dims[i].lbnd + 1 == 0)
770 zero_size = 1;
771 else if (zero_size)
772 print_lens = 1;
773 }
774
775 if (print_lbnds || print_lens)
776 for (i = 0; i < h.ndims; i++)
777 {
778 if (print_lbnds)
779 {
780 scm_putc_unlocked ('@', port);
781 scm_intprint (h.dims[i].lbnd, 10, port);
782 }
783 if (print_lens)
784 {
785 scm_putc_unlocked (':', port);
786 scm_intprint (h.dims[i].ubnd - h.dims[i].lbnd + 1,
787 10, port);
788 }
789 }
790
791 if (h.ndims == 0)
792 {
793 /* Rank zero arrays, which are really just scalars, are printed
794 specially. The consequent way would be to print them as
795
796 #0 OBJ
797
798 where OBJ is the printed representation of the scalar, but we
799 print them instead as
800
801 #0(OBJ)
802
803 to make them look less strange.
804
805 Just printing them as
806
807 OBJ
808
809 would be correct in a way as well, but zero rank arrays are
810 not really the same as Scheme values since they are boxed and
811 can be modified with array-set!, say.
812 */
813 scm_putc_unlocked ('(', port);
814 scm_i_print_array_dimension (&h, 0, 0, port, pstate);
815 scm_putc_unlocked (')', port);
816 return 1;
817 }
818 else
819 return scm_i_print_array_dimension (&h, 0, 0, port, pstate);
820 }
821
822 static SCM
823 array_handle_ref (scm_t_array_handle *hh, size_t pos)
824 {
825 return scm_c_array_ref_1 (SCM_I_ARRAY_V (hh->array), pos);
826 }
827
828 static void
829 array_handle_set (scm_t_array_handle *hh, size_t pos, SCM val)
830 {
831 scm_c_array_set_1_x (SCM_I_ARRAY_V (hh->array), val, pos);
832 }
833
834 /* FIXME: should be handle for vect? maybe not, because of dims */
835 static void
836 array_get_handle (SCM array, scm_t_array_handle *h)
837 {
838 scm_t_array_handle vh;
839 scm_array_get_handle (SCM_I_ARRAY_V (array), &vh);
840 assert (vh.dims[0].inc == 1 && vh.dims[0].lbnd == 0 && vh.base == 0);
841 h->element_type = vh.element_type;
842 h->elements = vh.elements;
843 h->writable_elements = vh.writable_elements;
844 scm_array_handle_release (&vh);
845
846 h->dims = SCM_I_ARRAY_DIMS (array);
847 h->ndims = SCM_I_ARRAY_NDIM (array);
848 h->base = SCM_I_ARRAY_BASE (array);
849 }
850
851 SCM_ARRAY_IMPLEMENTATION (scm_tc7_array,
852 0x7f,
853 array_handle_ref, array_handle_set,
854 array_get_handle)
855
856 void
857 scm_init_arrays ()
858 {
859 scm_add_feature ("array");
860
861 #include "libguile/arrays.x"
862
863 }
864
865 /*
866 Local Variables:
867 c-file-style: "gnu"
868 End:
869 */