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