move generic array foo out to its own file
[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"
a0599745
MD
47
48#include "libguile/validate.h"
2fa901a5 49#include "libguile/arrays.h"
1030b450 50#include "libguile/generalized-arrays.h"
5d1b3b2d 51#include "libguile/array-map.h"
f27d2057 52#include "libguile/print.h"
bfad4005 53#include "libguile/read.h"
0f2d19dd 54
3d8d56df
GH
55#ifdef HAVE_UNISTD_H
56#include <unistd.h>
57#endif
58
7beabedb
MG
59#ifdef HAVE_IO_H
60#include <io.h>
61#endif
62
0f2d19dd
JB
63\f
64/* The set of uniform scm_vector types is:
e0e49670 65 * Vector of: Called: Replaced by:
bfad4005 66 * unsigned char string
85368844 67 * char byvect s8 or u8, depending on signedness of 'char'
e0e49670
MV
68 * boolean bvect
69 * signed long ivect s32
70 * unsigned long uvect u32
71 * float fvect f32
72 * double dvect d32
85368844 73 * complex double cvect c64
e0e49670
MV
74 * short svect s16
75 * long long llvect s64
0f2d19dd
JB
76 */
77
04b87de5 78scm_t_bits scm_i_tc16_array;
04b87de5
MV
79
80#define SCM_SET_ARRAY_CONTIGUOUS_FLAG(x) \
81 (SCM_SET_CELL_WORD_0 ((x), SCM_CELL_WORD_0 (x) | SCM_I_ARRAY_FLAG_CONTIGUOUS))
82#define SCM_CLR_ARRAY_CONTIGUOUS_FLAG(x) \
83 (SCM_SET_CELL_WORD_0 ((x), SCM_CELL_WORD_0 (x) & ~SCM_I_ARRAY_FLAG_CONTIGUOUS))
1cc91f1b 84
f301dbf3
MV
85typedef SCM creator_proc (SCM len, SCM fill);
86
87struct {
88 char *type_name;
89 SCM type;
90 creator_proc *creator;
91} type_creator_table[] = {
92 { "a", SCM_UNSPECIFIED, scm_make_string },
93 { "b", SCM_UNSPECIFIED, scm_make_bitvector },
94 { "u8", SCM_UNSPECIFIED, scm_make_u8vector },
95 { "s8", SCM_UNSPECIFIED, scm_make_s8vector },
96 { "u16", SCM_UNSPECIFIED, scm_make_u16vector },
97 { "s16", SCM_UNSPECIFIED, scm_make_s16vector },
98 { "u32", SCM_UNSPECIFIED, scm_make_u32vector },
99 { "s32", SCM_UNSPECIFIED, scm_make_s32vector },
100 { "u64", SCM_UNSPECIFIED, scm_make_u64vector },
101 { "s64", SCM_UNSPECIFIED, scm_make_s64vector },
102 { "f32", SCM_UNSPECIFIED, scm_make_f32vector },
103 { "f64", SCM_UNSPECIFIED, scm_make_f64vector },
104 { "c32", SCM_UNSPECIFIED, scm_make_c32vector },
105 { "c64", SCM_UNSPECIFIED, scm_make_c64vector },
438974d0 106 { "vu8", SCM_UNSPECIFIED, scm_make_bytevector },
f301dbf3
MV
107 { NULL }
108};
109
110static void
111init_type_creator_table ()
112{
113 int i;
114 for (i = 0; type_creator_table[i].type_name; i++)
115 {
116 SCM sym = scm_from_locale_symbol (type_creator_table[i].type_name);
117 type_creator_table[i].type = scm_permanent_object (sym);
118 }
119}
120
121static creator_proc *
122type_to_creator (SCM type)
123{
124 int i;
125
126 if (scm_is_eq (type, SCM_BOOL_T))
127 return scm_make_vector;
128 for (i = 0; type_creator_table[i].type_name; i++)
129 if (scm_is_eq (type, type_creator_table[i].type))
130 return type_creator_table[i].creator;
131
132 scm_misc_error (NULL, "unknown array type: ~a", scm_list_1 (type));
133}
134
135static SCM
136make_typed_vector (SCM type, size_t len)
137{
138 creator_proc *creator = type_to_creator (type);
139 return creator (scm_from_size_t (len), SCM_UNDEFINED);
140}
bfad4005 141
0f2d19dd 142
e2d37336
MD
143SCM_DEFINE (scm_shared_array_root, "shared-array-root", 1, 0, 0,
144 (SCM ra),
145 "Return the root vector of a shared array.")
146#define FUNC_NAME s_scm_shared_array_root
147{
66b9d7d3 148 if (SCM_I_ARRAYP (ra))
04b87de5 149 return SCM_I_ARRAY_V (ra);
52372719
MV
150 else if (scm_is_generalized_vector (ra))
151 return ra;
152 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
e2d37336
MD
153}
154#undef FUNC_NAME
155
156
157SCM_DEFINE (scm_shared_array_offset, "shared-array-offset", 1, 0, 0,
158 (SCM ra),
159 "Return the root vector index of the first element in the array.")
160#define FUNC_NAME s_scm_shared_array_offset
161{
52372719
MV
162 scm_t_array_handle handle;
163 SCM res;
164
165 scm_array_get_handle (ra, &handle);
166 res = scm_from_size_t (handle.base);
167 scm_array_handle_release (&handle);
168 return res;
e2d37336
MD
169}
170#undef FUNC_NAME
171
172
173SCM_DEFINE (scm_shared_array_increments, "shared-array-increments", 1, 0, 0,
174 (SCM ra),
175 "For each dimension, return the distance between elements in the root vector.")
176#define FUNC_NAME s_scm_shared_array_increments
177{
52372719 178 scm_t_array_handle handle;
e2d37336 179 SCM res = SCM_EOL;
1be6b49c 180 size_t k;
92c2555f 181 scm_t_array_dim *s;
02339e5b 182
52372719
MV
183 scm_array_get_handle (ra, &handle);
184 k = scm_array_handle_rank (&handle);
185 s = scm_array_handle_dims (&handle);
e2d37336 186 while (k--)
52372719
MV
187 res = scm_cons (scm_from_ssize_t (s[k].inc), res);
188 scm_array_handle_release (&handle);
e2d37336
MD
189 return res;
190}
191#undef FUNC_NAME
192
0cd6cb2f 193SCM
66b9d7d3 194scm_i_make_array (int ndim)
0f2d19dd
JB
195{
196 SCM ra;
66b9d7d3 197 SCM_NEWSMOB(ra, ((scm_t_bits) ndim << 17) + scm_i_tc16_array,
04b87de5 198 scm_gc_malloc ((sizeof (scm_i_t_array) +
4c9419ac
MV
199 ndim * sizeof (scm_t_array_dim)),
200 "array"));
04b87de5 201 SCM_I_ARRAY_V (ra) = SCM_BOOL_F;
0f2d19dd
JB
202 return ra;
203}
204
205static char s_bad_spec[] = "Bad scm_array dimension";
0f2d19dd 206
1cc91f1b 207
02339e5b
MV
208/* Increments will still need to be set. */
209
0cd6cb2f
MV
210static SCM
211scm_i_shap2ra (SCM args)
0f2d19dd 212{
92c2555f 213 scm_t_array_dim *s;
0f2d19dd
JB
214 SCM ra, spec, sp;
215 int ndim = scm_ilength (args);
b3fcac34 216 if (ndim < 0)
0cd6cb2f 217 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
b3fcac34 218
66b9d7d3 219 ra = scm_i_make_array (ndim);
04b87de5
MV
220 SCM_I_ARRAY_BASE (ra) = 0;
221 s = SCM_I_ARRAY_DIMS (ra);
d2e53ed6 222 for (; !scm_is_null (args); s++, args = SCM_CDR (args))
0f2d19dd
JB
223 {
224 spec = SCM_CAR (args);
e11e83f3 225 if (scm_is_integer (spec))
0f2d19dd 226 {
e11e83f3 227 if (scm_to_long (spec) < 0)
0cd6cb2f 228 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
0f2d19dd 229 s->lbnd = 0;
e11e83f3 230 s->ubnd = scm_to_long (spec) - 1;
0f2d19dd
JB
231 s->inc = 1;
232 }
233 else
234 {
d2e53ed6 235 if (!scm_is_pair (spec) || !scm_is_integer (SCM_CAR (spec)))
0cd6cb2f 236 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
e11e83f3 237 s->lbnd = scm_to_long (SCM_CAR (spec));
0f2d19dd 238 sp = SCM_CDR (spec);
d2e53ed6 239 if (!scm_is_pair (sp)
e11e83f3 240 || !scm_is_integer (SCM_CAR (sp))
d2e53ed6 241 || !scm_is_null (SCM_CDR (sp)))
0cd6cb2f 242 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
e11e83f3 243 s->ubnd = scm_to_long (SCM_CAR (sp));
0f2d19dd
JB
244 s->inc = 1;
245 }
246 }
247 return ra;
248}
249
f301dbf3
MV
250SCM_DEFINE (scm_make_typed_array, "make-typed-array", 2, 0, 1,
251 (SCM type, SCM fill, SCM bounds),
252 "Create and return an array of type @var{type}.")
253#define FUNC_NAME s_scm_make_typed_array
0f2d19dd 254{
f301dbf3 255 size_t k, rlen = 1;
92c2555f 256 scm_t_array_dim *s;
f301dbf3 257 creator_proc *creator;
0f2d19dd 258 SCM ra;
1be6b49c 259
f301dbf3 260 creator = type_to_creator (type);
0cd6cb2f 261 ra = scm_i_shap2ra (bounds);
e038c042 262 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
04b87de5
MV
263 s = SCM_I_ARRAY_DIMS (ra);
264 k = SCM_I_ARRAY_NDIM (ra);
1be6b49c 265
0f2d19dd
JB
266 while (k--)
267 {
a3a32939 268 s[k].inc = rlen;
2caaadd1 269 SCM_ASSERT_RANGE (1, bounds, s[k].lbnd <= s[k].ubnd + 1);
0f2d19dd 270 rlen = (s[k].ubnd - s[k].lbnd + 1) * s[k].inc;
0f2d19dd 271 }
a3a32939 272
f0b91039 273 if (scm_is_eq (fill, SCM_UNSPECIFIED))
f301dbf3 274 fill = SCM_UNDEFINED;
a3a32939 275
04b87de5 276 SCM_I_ARRAY_V (ra) = creator (scm_from_size_t (rlen), fill);
a3a32939 277
04b87de5 278 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
c014a02e 279 if (s->ubnd < s->lbnd || (0 == s->lbnd && 1 == s->inc))
04b87de5 280 return SCM_I_ARRAY_V (ra);
0f2d19dd
JB
281 return ra;
282}
1bbd0b84 283#undef FUNC_NAME
0f2d19dd 284
782a82ee
AW
285SCM
286scm_from_contiguous_typed_array (SCM type, SCM bounds, const void *bytes,
287 size_t byte_len)
288#define FUNC_NAME "scm_from_contiguous_typed_array"
289{
290 size_t k, rlen = 1;
291 scm_t_array_dim *s;
292 creator_proc *creator;
293 SCM ra;
294 scm_t_array_handle h;
295 void *base;
296 size_t sz;
297
298 creator = type_to_creator (type);
299 ra = scm_i_shap2ra (bounds);
300 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
301 s = SCM_I_ARRAY_DIMS (ra);
302 k = SCM_I_ARRAY_NDIM (ra);
303
304 while (k--)
305 {
306 s[k].inc = rlen;
307 SCM_ASSERT_RANGE (1, bounds, s[k].lbnd <= s[k].ubnd + 1);
308 rlen = (s[k].ubnd - s[k].lbnd + 1) * s[k].inc;
309 }
310 SCM_I_ARRAY_V (ra) = creator (scm_from_size_t (rlen), SCM_UNDEFINED);
311
312
313 scm_array_get_handle (ra, &h);
314 base = scm_array_handle_uniform_writable_elements (&h);
315 sz = scm_array_handle_uniform_element_size (&h);
316 scm_array_handle_release (&h);
317
318 if (byte_len % sz)
319 SCM_MISC_ERROR ("byte length not a multiple of the unit size", SCM_EOL);
320 if (byte_len / sz != rlen)
321 SCM_MISC_ERROR ("byte length and dimensions do not match", SCM_EOL);
322
323 memcpy (base, bytes, byte_len);
324
325 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
326 if (s->ubnd < s->lbnd || (0 == s->lbnd && 1 == s->inc))
327 return SCM_I_ARRAY_V (ra);
328 return ra;
329}
330#undef FUNC_NAME
331
f301dbf3
MV
332SCM_DEFINE (scm_make_array, "make-array", 1, 0, 1,
333 (SCM fill, SCM bounds),
334 "Create and return an array.")
335#define FUNC_NAME s_scm_make_array
336{
337 return scm_make_typed_array (SCM_BOOL_T, fill, bounds);
338}
339#undef FUNC_NAME
340
0cd6cb2f
MV
341static void
342scm_i_ra_set_contp (SCM ra)
0f2d19dd 343{
04b87de5 344 size_t k = SCM_I_ARRAY_NDIM (ra);
0f2d19dd 345 if (k)
0f2d19dd 346 {
04b87de5 347 long inc = SCM_I_ARRAY_DIMS (ra)[k - 1].inc;
fe0c6dae 348 while (k--)
0f2d19dd 349 {
04b87de5 350 if (inc != SCM_I_ARRAY_DIMS (ra)[k].inc)
fe0c6dae 351 {
e038c042 352 SCM_CLR_ARRAY_CONTIGUOUS_FLAG (ra);
fe0c6dae
JB
353 return;
354 }
04b87de5
MV
355 inc *= (SCM_I_ARRAY_DIMS (ra)[k].ubnd
356 - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1);
0f2d19dd 357 }
0f2d19dd 358 }
e038c042 359 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
0f2d19dd
JB
360}
361
362
3b3b36dd 363SCM_DEFINE (scm_make_shared_array, "make-shared-array", 2, 0, 1,
1bbd0b84 364 (SCM oldra, SCM mapfunc, SCM dims),
b380b885
MD
365 "@code{make-shared-array} can be used to create shared subarrays of other\n"
366 "arrays. The @var{mapper} is a function that translates coordinates in\n"
367 "the new array into coordinates in the old array. A @var{mapper} must be\n"
368 "linear, and its range must stay within the bounds of the old array, but\n"
369 "it can be otherwise arbitrary. A simple example:\n"
1e6808ea 370 "@lisp\n"
b380b885
MD
371 "(define fred (make-array #f 8 8))\n"
372 "(define freds-diagonal\n"
373 " (make-shared-array fred (lambda (i) (list i i)) 8))\n"
374 "(array-set! freds-diagonal 'foo 3)\n"
375 "(array-ref fred 3 3) @result{} foo\n"
376 "(define freds-center\n"
377 " (make-shared-array fred (lambda (i j) (list (+ 3 i) (+ 3 j))) 2 2))\n"
378 "(array-ref freds-center 0 0) @result{} foo\n"
1e6808ea 379 "@end lisp")
1bbd0b84 380#define FUNC_NAME s_scm_make_shared_array
0f2d19dd 381{
112ba0ac 382 scm_t_array_handle old_handle;
0f2d19dd
JB
383 SCM ra;
384 SCM inds, indptr;
385 SCM imap;
112ba0ac
MV
386 size_t k;
387 ssize_t i;
2b829bbb 388 long old_base, old_min, new_min, old_max, new_max;
92c2555f 389 scm_t_array_dim *s;
b3fcac34
DH
390
391 SCM_VALIDATE_REST_ARGUMENT (dims);
34d19ef6 392 SCM_VALIDATE_PROC (2, mapfunc);
0cd6cb2f 393 ra = scm_i_shap2ra (dims);
112ba0ac
MV
394
395 scm_array_get_handle (oldra, &old_handle);
396
04b87de5 397 if (SCM_I_ARRAYP (oldra))
0f2d19dd 398 {
04b87de5 399 SCM_I_ARRAY_V (ra) = SCM_I_ARRAY_V (oldra);
2b829bbb 400 old_base = old_min = old_max = SCM_I_ARRAY_BASE (oldra);
112ba0ac
MV
401 s = scm_array_handle_dims (&old_handle);
402 k = scm_array_handle_rank (&old_handle);
0f2d19dd
JB
403 while (k--)
404 {
405 if (s[k].inc > 0)
406 old_max += (s[k].ubnd - s[k].lbnd) * s[k].inc;
407 else
408 old_min += (s[k].ubnd - s[k].lbnd) * s[k].inc;
409 }
410 }
411 else
412 {
04b87de5 413 SCM_I_ARRAY_V (ra) = oldra;
2b829bbb 414 old_base = old_min = 0;
02339e5b 415 old_max = scm_c_generalized_vector_length (oldra) - 1;
0f2d19dd 416 }
112ba0ac 417
0f2d19dd 418 inds = SCM_EOL;
04b87de5
MV
419 s = SCM_I_ARRAY_DIMS (ra);
420 for (k = 0; k < SCM_I_ARRAY_NDIM (ra); k++)
0f2d19dd 421 {
e11e83f3 422 inds = scm_cons (scm_from_long (s[k].lbnd), inds);
0f2d19dd
JB
423 if (s[k].ubnd < s[k].lbnd)
424 {
04b87de5 425 if (1 == SCM_I_ARRAY_NDIM (ra))
f301dbf3 426 ra = make_typed_vector (scm_array_type (ra), 0);
0f2d19dd 427 else
04b87de5 428 SCM_I_ARRAY_V (ra) = make_typed_vector (scm_array_type (ra), 0);
112ba0ac 429 scm_array_handle_release (&old_handle);
0f2d19dd
JB
430 return ra;
431 }
432 }
112ba0ac 433
fdc28395 434 imap = scm_apply_0 (mapfunc, scm_reverse (inds));
0cd6cb2f 435 i = scm_array_handle_pos (&old_handle, imap);
2b829bbb 436 SCM_I_ARRAY_BASE (ra) = new_min = new_max = i + old_base;
0f2d19dd 437 indptr = inds;
04b87de5 438 k = SCM_I_ARRAY_NDIM (ra);
0f2d19dd
JB
439 while (k--)
440 {
441 if (s[k].ubnd > s[k].lbnd)
442 {
e11e83f3 443 SCM_SETCAR (indptr, scm_sum (SCM_CAR (indptr), scm_from_int (1)));
fdc28395 444 imap = scm_apply_0 (mapfunc, scm_reverse (inds));
0cd6cb2f 445 s[k].inc = scm_array_handle_pos (&old_handle, imap) - i;
0f2d19dd
JB
446 i += s[k].inc;
447 if (s[k].inc > 0)
448 new_max += (s[k].ubnd - s[k].lbnd) * s[k].inc;
449 else
450 new_min += (s[k].ubnd - s[k].lbnd) * s[k].inc;
451 }
452 else
453 s[k].inc = new_max - new_min + 1; /* contiguous by default */
454 indptr = SCM_CDR (indptr);
455 }
112ba0ac
MV
456
457 scm_array_handle_release (&old_handle);
458
b3fcac34
DH
459 if (old_min > new_min || old_max < new_max)
460 SCM_MISC_ERROR ("mapping out of range", SCM_EOL);
04b87de5 461 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
0f2d19dd 462 {
04b87de5 463 SCM v = SCM_I_ARRAY_V (ra);
6e708ef2 464 size_t length = scm_c_generalized_vector_length (v);
74014c46
DH
465 if (1 == s->inc && 0 == s->lbnd && length == 1 + s->ubnd)
466 return v;
0f2d19dd 467 if (s->ubnd < s->lbnd)
f301dbf3 468 return make_typed_vector (scm_array_type (ra), 0);
0f2d19dd 469 }
0cd6cb2f 470 scm_i_ra_set_contp (ra);
0f2d19dd
JB
471 return ra;
472}
1bbd0b84 473#undef FUNC_NAME
0f2d19dd
JB
474
475
476/* args are RA . DIMS */
af45e3b0
DH
477SCM_DEFINE (scm_transpose_array, "transpose-array", 1, 0, 1,
478 (SCM ra, SCM args),
1e6808ea
MG
479 "Return an array sharing contents with @var{array}, but with\n"
480 "dimensions arranged in a different order. There must be one\n"
481 "@var{dim} argument for each dimension of @var{array}.\n"
482 "@var{dim0}, @var{dim1}, @dots{} should be integers between 0\n"
483 "and the rank of the array to be returned. Each integer in that\n"
484 "range must appear at least once in the argument list.\n"
485 "\n"
486 "The values of @var{dim0}, @var{dim1}, @dots{} correspond to\n"
487 "dimensions in the array to be returned, their positions in the\n"
488 "argument list to dimensions of @var{array}. Several @var{dim}s\n"
489 "may have the same value, in which case the returned array will\n"
490 "have smaller rank than @var{array}.\n"
491 "\n"
492 "@lisp\n"
b380b885
MD
493 "(transpose-array '#2((a b) (c d)) 1 0) @result{} #2((a c) (b d))\n"
494 "(transpose-array '#2((a b) (c d)) 0 0) @result{} #1(a d)\n"
495 "(transpose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1 1 0) @result{}\n"
496 " #2((a 4) (b 5) (c 6))\n"
1e6808ea 497 "@end lisp")
1bbd0b84 498#define FUNC_NAME s_scm_transpose_array
0f2d19dd 499{
34d19ef6 500 SCM res, vargs;
92c2555f 501 scm_t_array_dim *s, *r;
0f2d19dd 502 int ndim, i, k;
af45e3b0 503
b3fcac34 504 SCM_VALIDATE_REST_ARGUMENT (args);
1bbd0b84 505 SCM_ASSERT (SCM_NIMP (ra), ra, SCM_ARG1, FUNC_NAME);
e0e49670 506
20930f28 507 if (scm_is_generalized_vector (ra))
e0e49670
MV
508 {
509 /* Make sure that we are called with a single zero as
510 arguments.
511 */
512 if (scm_is_null (args) || !scm_is_null (SCM_CDR (args)))
513 SCM_WRONG_NUM_ARGS ();
514 SCM_VALIDATE_INT_COPY (SCM_ARG2, SCM_CAR (args), i);
515 SCM_ASSERT_RANGE (SCM_ARG2, SCM_CAR (args), i == 0);
516 return ra;
517 }
518
66b9d7d3 519 if (SCM_I_ARRAYP (ra))
0f2d19dd 520 {
0f2d19dd 521 vargs = scm_vector (args);
04b87de5 522 if (SCM_SIMPLE_VECTOR_LENGTH (vargs) != SCM_I_ARRAY_NDIM (ra))
b3fcac34 523 SCM_WRONG_NUM_ARGS ();
0f2d19dd 524 ndim = 0;
04b87de5 525 for (k = 0; k < SCM_I_ARRAY_NDIM (ra); k++)
0f2d19dd 526 {
6e708ef2 527 i = scm_to_signed_integer (SCM_SIMPLE_VECTOR_REF (vargs, k),
04b87de5 528 0, SCM_I_ARRAY_NDIM(ra));
0f2d19dd
JB
529 if (ndim < i)
530 ndim = i;
531 }
532 ndim++;
66b9d7d3 533 res = scm_i_make_array (ndim);
04b87de5
MV
534 SCM_I_ARRAY_V (res) = SCM_I_ARRAY_V (ra);
535 SCM_I_ARRAY_BASE (res) = SCM_I_ARRAY_BASE (ra);
0f2d19dd
JB
536 for (k = ndim; k--;)
537 {
04b87de5
MV
538 SCM_I_ARRAY_DIMS (res)[k].lbnd = 0;
539 SCM_I_ARRAY_DIMS (res)[k].ubnd = -1;
0f2d19dd 540 }
04b87de5 541 for (k = SCM_I_ARRAY_NDIM (ra); k--;)
0f2d19dd 542 {
6e708ef2 543 i = scm_to_int (SCM_SIMPLE_VECTOR_REF (vargs, k));
04b87de5
MV
544 s = &(SCM_I_ARRAY_DIMS (ra)[k]);
545 r = &(SCM_I_ARRAY_DIMS (res)[i]);
0f2d19dd
JB
546 if (r->ubnd < r->lbnd)
547 {
548 r->lbnd = s->lbnd;
549 r->ubnd = s->ubnd;
550 r->inc = s->inc;
551 ndim--;
552 }
553 else
554 {
555 if (r->ubnd > s->ubnd)
556 r->ubnd = s->ubnd;
557 if (r->lbnd < s->lbnd)
558 {
04b87de5 559 SCM_I_ARRAY_BASE (res) += (s->lbnd - r->lbnd) * r->inc;
0f2d19dd
JB
560 r->lbnd = s->lbnd;
561 }
562 r->inc += s->inc;
563 }
564 }
b3fcac34
DH
565 if (ndim > 0)
566 SCM_MISC_ERROR ("bad argument list", SCM_EOL);
0cd6cb2f 567 scm_i_ra_set_contp (res);
0f2d19dd
JB
568 return res;
569 }
20930f28
MV
570
571 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
0f2d19dd 572}
1bbd0b84 573#undef FUNC_NAME
0f2d19dd 574
1d7bdb25
GH
575/* attempts to unroll an array into a one-dimensional array.
576 returns the unrolled array or #f if it can't be done. */
1bbd0b84 577 /* if strict is not SCM_UNDEFINED, return #f if returned array
1d7bdb25 578 wouldn't have contiguous elements. */
3b3b36dd 579SCM_DEFINE (scm_array_contents, "array-contents", 1, 1, 0,
1bbd0b84 580 (SCM ra, SCM strict),
b380b885
MD
581 "If @var{array} may be @dfn{unrolled} into a one dimensional shared array\n"
582 "without changing their order (last subscript changing fastest), then\n"
583 "@code{array-contents} returns that shared array, otherwise it returns\n"
584 "@code{#f}. All arrays made by @var{make-array} and\n"
585 "@var{make-uniform-array} may be unrolled, some arrays made by\n"
586 "@var{make-shared-array} may not be.\n\n"
587 "If the optional argument @var{strict} is provided, a shared array will\n"
588 "be returned only if its elements are stored internally contiguous in\n"
589 "memory.")
1bbd0b84 590#define FUNC_NAME s_scm_array_contents
0f2d19dd
JB
591{
592 SCM sra;
e0e49670 593
20930f28 594 if (scm_is_generalized_vector (ra))
e0e49670
MV
595 return ra;
596
04b87de5 597 if (SCM_I_ARRAYP (ra))
0f2d19dd 598 {
04b87de5
MV
599 size_t k, ndim = SCM_I_ARRAY_NDIM (ra), len = 1;
600 if (!SCM_I_ARRAYP (ra) || !SCM_I_ARRAY_CONTP (ra))
20930f28
MV
601 return SCM_BOOL_F;
602 for (k = 0; k < ndim; k++)
04b87de5 603 len *= SCM_I_ARRAY_DIMS (ra)[k].ubnd - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1;
20930f28 604 if (!SCM_UNBNDP (strict))
74014c46 605 {
04b87de5 606 if (ndim && (1 != SCM_I_ARRAY_DIMS (ra)[ndim - 1].inc))
20930f28 607 return SCM_BOOL_F;
04b87de5 608 if (scm_is_bitvector (SCM_I_ARRAY_V (ra)))
20930f28 609 {
04b87de5
MV
610 if (len != scm_c_bitvector_length (SCM_I_ARRAY_V (ra)) ||
611 SCM_I_ARRAY_BASE (ra) % SCM_LONG_BIT ||
20930f28
MV
612 len % SCM_LONG_BIT)
613 return SCM_BOOL_F;
614 }
74014c46 615 }
20930f28
MV
616
617 {
04b87de5 618 SCM v = SCM_I_ARRAY_V (ra);
20930f28 619 size_t length = scm_c_generalized_vector_length (v);
04b87de5 620 if ((len == length) && 0 == SCM_I_ARRAY_BASE (ra) && SCM_I_ARRAY_DIMS (ra)->inc)
20930f28 621 return v;
0f2d19dd 622 }
20930f28 623
66b9d7d3 624 sra = scm_i_make_array (1);
04b87de5
MV
625 SCM_I_ARRAY_DIMS (sra)->lbnd = 0;
626 SCM_I_ARRAY_DIMS (sra)->ubnd = len - 1;
627 SCM_I_ARRAY_V (sra) = SCM_I_ARRAY_V (ra);
628 SCM_I_ARRAY_BASE (sra) = SCM_I_ARRAY_BASE (ra);
629 SCM_I_ARRAY_DIMS (sra)->inc = (ndim ? SCM_I_ARRAY_DIMS (ra)[ndim - 1].inc : 1);
20930f28 630 return sra;
0f2d19dd 631 }
02339e5b
MV
632 else
633 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
0f2d19dd 634}
1bbd0b84 635#undef FUNC_NAME
0f2d19dd 636
1cc91f1b 637
0f2d19dd 638SCM
6e8d25a6 639scm_ra2contig (SCM ra, int copy)
0f2d19dd
JB
640{
641 SCM ret;
c014a02e
ML
642 long inc = 1;
643 size_t k, len = 1;
04b87de5
MV
644 for (k = SCM_I_ARRAY_NDIM (ra); k--;)
645 len *= SCM_I_ARRAY_DIMS (ra)[k].ubnd - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1;
646 k = SCM_I_ARRAY_NDIM (ra);
647 if (SCM_I_ARRAY_CONTP (ra) && ((0 == k) || (1 == SCM_I_ARRAY_DIMS (ra)[k - 1].inc)))
0f2d19dd 648 {
04b87de5 649 if (!scm_is_bitvector (SCM_I_ARRAY_V (ra)))
0f2d19dd 650 return ra;
04b87de5
MV
651 if ((len == scm_c_bitvector_length (SCM_I_ARRAY_V (ra)) &&
652 0 == SCM_I_ARRAY_BASE (ra) % SCM_LONG_BIT &&
c014a02e 653 0 == len % SCM_LONG_BIT))
0f2d19dd
JB
654 return ra;
655 }
66b9d7d3 656 ret = scm_i_make_array (k);
04b87de5 657 SCM_I_ARRAY_BASE (ret) = 0;
0f2d19dd
JB
658 while (k--)
659 {
04b87de5
MV
660 SCM_I_ARRAY_DIMS (ret)[k].lbnd = SCM_I_ARRAY_DIMS (ra)[k].lbnd;
661 SCM_I_ARRAY_DIMS (ret)[k].ubnd = SCM_I_ARRAY_DIMS (ra)[k].ubnd;
662 SCM_I_ARRAY_DIMS (ret)[k].inc = inc;
663 inc *= SCM_I_ARRAY_DIMS (ra)[k].ubnd - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1;
0f2d19dd 664 }
04b87de5 665 SCM_I_ARRAY_V (ret) = make_typed_vector (scm_array_type (ra), inc);
0f2d19dd
JB
666 if (copy)
667 scm_array_copy_x (ra, ret);
668 return ret;
669}
670
671
672
3b3b36dd 673SCM_DEFINE (scm_uniform_array_read_x, "uniform-array-read!", 1, 3, 0,
03a5397a 674 (SCM ura, SCM port_or_fd, SCM start, SCM end),
8f85c0c6
NJ
675 "@deffnx {Scheme Procedure} uniform-vector-read! uve [port-or-fdes] [start] [end]\n"
676 "Attempt to read all elements of @var{ura}, in lexicographic order, as\n"
b380b885 677 "binary objects from @var{port-or-fdes}.\n"
8f85c0c6
NJ
678 "If an end of file is encountered,\n"
679 "the objects up to that point are put into @var{ura}\n"
b380b885
MD
680 "(starting at the beginning) and the remainder of the array is\n"
681 "unchanged.\n\n"
682 "The optional arguments @var{start} and @var{end} allow\n"
683 "a specified region of a vector (or linearized array) to be read,\n"
684 "leaving the remainder of the vector unchanged.\n\n"
685 "@code{uniform-array-read!} returns the number of objects read.\n"
686 "@var{port-or-fdes} may be omitted, in which case it defaults to the value\n"
687 "returned by @code{(current-input-port)}.")
1bbd0b84 688#define FUNC_NAME s_scm_uniform_array_read_x
0f2d19dd 689{
3d8d56df 690 if (SCM_UNBNDP (port_or_fd))
9de87eea 691 port_or_fd = scm_current_input_port ();
35de7ebe 692
03a5397a 693 if (scm_is_uniform_vector (ura))
20930f28 694 {
03a5397a 695 return scm_uniform_vector_read_x (ura, port_or_fd, start, end);
20930f28 696 }
04b87de5 697 else if (SCM_I_ARRAYP (ura))
20930f28 698 {
03a5397a
MV
699 size_t base, vlen, cstart, cend;
700 SCM cra, ans;
701
702 cra = scm_ra2contig (ura, 0);
04b87de5
MV
703 base = SCM_I_ARRAY_BASE (cra);
704 vlen = SCM_I_ARRAY_DIMS (cra)->inc *
705 (SCM_I_ARRAY_DIMS (cra)->ubnd - SCM_I_ARRAY_DIMS (cra)->lbnd + 1);
35de7ebe 706
03a5397a
MV
707 cstart = 0;
708 cend = vlen;
709 if (!SCM_UNBNDP (start))
1146b6cd 710 {
03a5397a
MV
711 cstart = scm_to_unsigned_integer (start, 0, vlen);
712 if (!SCM_UNBNDP (end))
713 cend = scm_to_unsigned_integer (end, cstart, vlen);
1146b6cd 714 }
35de7ebe 715
04b87de5 716 ans = scm_uniform_vector_read_x (SCM_I_ARRAY_V (cra), port_or_fd,
03a5397a
MV
717 scm_from_size_t (base + cstart),
718 scm_from_size_t (base + cend));
6c951427 719
03a5397a
MV
720 if (!scm_is_eq (cra, ura))
721 scm_array_copy_x (cra, ura);
722 return ans;
3d8d56df 723 }
03a5397a
MV
724 else
725 scm_wrong_type_arg_msg (NULL, 0, ura, "array");
0f2d19dd 726}
1bbd0b84 727#undef FUNC_NAME
0f2d19dd 728
3b3b36dd 729SCM_DEFINE (scm_uniform_array_write, "uniform-array-write", 1, 3, 0,
03a5397a 730 (SCM ura, SCM port_or_fd, SCM start, SCM end),
b380b885
MD
731 "Writes all elements of @var{ura} as binary objects to\n"
732 "@var{port-or-fdes}.\n\n"
733 "The optional arguments @var{start}\n"
734 "and @var{end} allow\n"
735 "a specified region of a vector (or linearized array) to be written.\n\n"
9401323e 736 "The number of objects actually written is returned.\n"
b380b885
MD
737 "@var{port-or-fdes} may be\n"
738 "omitted, in which case it defaults to the value returned by\n"
739 "@code{(current-output-port)}.")
1bbd0b84 740#define FUNC_NAME s_scm_uniform_array_write
0f2d19dd 741{
3d8d56df 742 if (SCM_UNBNDP (port_or_fd))
9de87eea 743 port_or_fd = scm_current_output_port ();
20930f28 744
03a5397a 745 if (scm_is_uniform_vector (ura))
20930f28 746 {
03a5397a 747 return scm_uniform_vector_write (ura, port_or_fd, start, end);
20930f28 748 }
04b87de5 749 else if (SCM_I_ARRAYP (ura))
20930f28 750 {
03a5397a
MV
751 size_t base, vlen, cstart, cend;
752 SCM cra, ans;
753
754 cra = scm_ra2contig (ura, 1);
04b87de5
MV
755 base = SCM_I_ARRAY_BASE (cra);
756 vlen = SCM_I_ARRAY_DIMS (cra)->inc *
757 (SCM_I_ARRAY_DIMS (cra)->ubnd - SCM_I_ARRAY_DIMS (cra)->lbnd + 1);
1146b6cd 758
03a5397a
MV
759 cstart = 0;
760 cend = vlen;
761 if (!SCM_UNBNDP (start))
1146b6cd 762 {
03a5397a
MV
763 cstart = scm_to_unsigned_integer (start, 0, vlen);
764 if (!SCM_UNBNDP (end))
765 cend = scm_to_unsigned_integer (end, cstart, vlen);
1146b6cd 766 }
3d8d56df 767
04b87de5 768 ans = scm_uniform_vector_write (SCM_I_ARRAY_V (cra), port_or_fd,
03a5397a
MV
769 scm_from_size_t (base + cstart),
770 scm_from_size_t (base + cend));
6c951427 771
03a5397a 772 return ans;
3d8d56df 773 }
03a5397a
MV
774 else
775 scm_wrong_type_arg_msg (NULL, 0, ura, "array");
0f2d19dd 776}
1bbd0b84 777#undef FUNC_NAME
0f2d19dd
JB
778
779
bcbbea0e 780static void l2ra (SCM lst, scm_t_array_handle *handle, ssize_t pos, size_t k);
1cc91f1b 781
f301dbf3 782SCM_DEFINE (scm_list_to_typed_array, "list->typed-array", 3, 0, 0,
2caaadd1 783 (SCM type, SCM shape, SCM lst),
f301dbf3
MV
784 "Return an array of the type @var{type}\n"
785 "with elements the same as those of @var{lst}.\n"
bfad4005 786 "\n"
2caaadd1
MV
787 "The argument @var{shape} determines the number of dimensions\n"
788 "of the array and their shape. It is either an exact integer,\n"
789 "giving the\n"
790 "number of dimensions directly, or a list whose length\n"
791 "specifies the number of dimensions and each element specified\n"
792 "the lower and optionally the upper bound of the corresponding\n"
793 "dimension.\n"
794 "When the element is list of two elements, these elements\n"
795 "give the lower and upper bounds. When it is an exact\n"
796 "integer, it gives only the lower bound.")
f301dbf3 797#define FUNC_NAME s_scm_list_to_typed_array
0f2d19dd 798{
2caaadd1 799 SCM row;
0f2d19dd 800 SCM ra;
bcbbea0e 801 scm_t_array_handle handle;
bfad4005 802
bfad4005 803 row = lst;
2caaadd1 804 if (scm_is_integer (shape))
0f2d19dd 805 {
2caaadd1
MV
806 size_t k = scm_to_size_t (shape);
807 shape = SCM_EOL;
bfad4005
MV
808 while (k-- > 0)
809 {
810 shape = scm_cons (scm_length (row), shape);
2caaadd1 811 if (k > 0 && !scm_is_null (row))
bfad4005
MV
812 row = scm_car (row);
813 }
814 }
815 else
816 {
2caaadd1
MV
817 SCM shape_spec = shape;
818 shape = SCM_EOL;
bfad4005
MV
819 while (1)
820 {
2caaadd1
MV
821 SCM spec = scm_car (shape_spec);
822 if (scm_is_pair (spec))
823 shape = scm_cons (spec, shape);
824 else
825 shape = scm_cons (scm_list_2 (spec,
826 scm_sum (scm_sum (spec,
827 scm_length (row)),
828 scm_from_int (-1))),
829 shape);
830 shape_spec = scm_cdr (shape_spec);
831 if (scm_is_pair (shape_spec))
832 {
833 if (!scm_is_null (row))
834 row = scm_car (row);
835 }
bfad4005
MV
836 else
837 break;
838 }
0f2d19dd 839 }
bfad4005 840
f0b91039
MV
841 ra = scm_make_typed_array (type, SCM_UNSPECIFIED,
842 scm_reverse_x (shape, SCM_EOL));
20930f28 843
bcbbea0e
MV
844 scm_array_get_handle (ra, &handle);
845 l2ra (lst, &handle, 0, 0);
846 scm_array_handle_release (&handle);
847
848 return ra;
0f2d19dd 849}
1bbd0b84 850#undef FUNC_NAME
0f2d19dd 851
f301dbf3
MV
852SCM_DEFINE (scm_list_to_array, "list->array", 2, 0, 0,
853 (SCM ndim, SCM lst),
854 "Return an array with elements the same as those of @var{lst}.")
855#define FUNC_NAME s_scm_list_to_array
856{
857 return scm_list_to_typed_array (SCM_BOOL_T, ndim, lst);
858}
859#undef FUNC_NAME
860
bcbbea0e
MV
861static void
862l2ra (SCM lst, scm_t_array_handle *handle, ssize_t pos, size_t k)
0f2d19dd 863{
bcbbea0e
MV
864 if (k == scm_array_handle_rank (handle))
865 scm_array_handle_set (handle, pos, lst);
0f2d19dd
JB
866 else
867 {
bcbbea0e
MV
868 scm_t_array_dim *dim = scm_array_handle_dims (handle) + k;
869 ssize_t inc = dim->inc;
2caaadd1
MV
870 size_t len = 1 + dim->ubnd - dim->lbnd, n;
871 char *errmsg = NULL;
bcbbea0e 872
2caaadd1 873 n = len;
bcbbea0e 874 while (n > 0 && scm_is_pair (lst))
0f2d19dd 875 {
bcbbea0e
MV
876 l2ra (SCM_CAR (lst), handle, pos, k + 1);
877 pos += inc;
0f2d19dd 878 lst = SCM_CDR (lst);
bcbbea0e 879 n -= 1;
0f2d19dd 880 }
bcbbea0e 881 if (n != 0)
2caaadd1 882 errmsg = "too few elements for array dimension ~a, need ~a";
d2e53ed6 883 if (!scm_is_null (lst))
2caaadd1
MV
884 errmsg = "too many elements for array dimension ~a, want ~a";
885 if (errmsg)
886 scm_misc_error (NULL, errmsg, scm_list_2 (scm_from_ulong (k),
887 scm_from_size_t (len)));
0f2d19dd 888 }
0f2d19dd
JB
889}
890
e0e49670
MV
891/* Print dimension DIM of ARRAY.
892 */
0f2d19dd 893
e0e49670 894static int
66b9d7d3 895scm_i_print_array_dimension (SCM array, int dim, int base,
e0e49670
MV
896 SCM port, scm_print_state *pstate)
897{
04b87de5 898 scm_t_array_dim *dim_spec = SCM_I_ARRAY_DIMS (array) + dim;
e0e49670
MV
899 long idx;
900
901 scm_putc ('(', port);
902
e0e49670
MV
903 for (idx = dim_spec->lbnd; idx <= dim_spec->ubnd; idx++)
904 {
04b87de5 905 if (dim < SCM_I_ARRAY_NDIM(array)-1)
66b9d7d3 906 scm_i_print_array_dimension (array, dim+1, base,
02339e5b 907 port, pstate);
e0e49670 908 else
66b9d7d3 909 scm_iprin1 (scm_c_generalized_vector_ref (SCM_I_ARRAY_V (array), base),
e0e49670
MV
910 port, pstate);
911 if (idx < dim_spec->ubnd)
912 scm_putc (' ', port);
913 base += dim_spec->inc;
914 }
915
916 scm_putc (')', port);
917 return 1;
918}
919
f301dbf3 920/* Print an array. (Only for strict arrays, not for generalized vectors.)
e0e49670
MV
921*/
922
e0e49670
MV
923static int
924scm_i_print_array (SCM array, SCM port, scm_print_state *pstate)
925{
04b87de5
MV
926 long ndim = SCM_I_ARRAY_NDIM (array);
927 scm_t_array_dim *dim_specs = SCM_I_ARRAY_DIMS (array);
928 SCM v = SCM_I_ARRAY_V (array);
929 unsigned long base = SCM_I_ARRAY_BASE (array);
e0e49670 930 long i;
2caaadd1 931 int print_lbnds = 0, zero_size = 0, print_lens = 0;
e0e49670
MV
932
933 scm_putc ('#', port);
c0fc64c8 934 if (ndim != 1 || dim_specs[0].lbnd != 0)
e0e49670 935 scm_intprint (ndim, 10, port);
20930f28
MV
936 if (scm_is_uniform_vector (v))
937 scm_puts (scm_i_uniform_vector_tag (v), port);
938 else if (scm_is_bitvector (v))
939 scm_puts ("b", port);
940 else if (scm_is_string (v))
941 scm_puts ("a", port);
942 else if (!scm_is_vector (v))
943 scm_puts ("?", port);
944
e0e49670 945 for (i = 0; i < ndim; i++)
2caaadd1
MV
946 {
947 if (dim_specs[i].lbnd != 0)
948 print_lbnds = 1;
949 if (dim_specs[i].ubnd - dim_specs[i].lbnd + 1 == 0)
950 zero_size = 1;
951 else if (zero_size)
952 print_lens = 1;
953 }
954
955 if (print_lbnds || print_lens)
956 for (i = 0; i < ndim; i++)
e0e49670 957 {
2caaadd1 958 if (print_lbnds)
e0e49670
MV
959 {
960 scm_putc ('@', port);
2caaadd1
MV
961 scm_intprint (dim_specs[i].lbnd, 10, port);
962 }
963 if (print_lens)
964 {
965 scm_putc (':', port);
966 scm_intprint (dim_specs[i].ubnd - dim_specs[i].lbnd + 1,
967 10, port);
e0e49670 968 }
e0e49670
MV
969 }
970
5f37cb63
MV
971 if (ndim == 0)
972 {
973 /* Rank zero arrays, which are really just scalars, are printed
974 specially. The consequent way would be to print them as
975
976 #0 OBJ
977
978 where OBJ is the printed representation of the scalar, but we
979 print them instead as
980
981 #0(OBJ)
982
983 to make them look less strange.
984
985 Just printing them as
986
987 OBJ
988
989 would be correct in a way as well, but zero rank arrays are
990 not really the same as Scheme values since they are boxed and
991 can be modified with array-set!, say.
992 */
993 scm_putc ('(', port);
66b9d7d3 994 scm_iprin1 (scm_c_generalized_vector_ref (v, base), port, pstate);
5f37cb63
MV
995 scm_putc (')', port);
996 return 1;
997 }
998 else
66b9d7d3 999 return scm_i_print_array_dimension (array, 0, base, port, pstate);
e0e49670 1000}
1cc91f1b 1001
bfad4005
MV
1002/* Read an array. This function can also read vectors and uniform
1003 vectors. Also, the conflict between '#f' and '#f32' and '#f64' is
1004 handled here.
1005
1006 C is the first character read after the '#'.
1007*/
1008
bfad4005 1009static SCM
f301dbf3 1010tag_to_type (const char *tag, SCM port)
bfad4005 1011{
5f37cb63
MV
1012 if (*tag == '\0')
1013 return SCM_BOOL_T;
1014 else
1015 return scm_from_locale_symbol (tag);
bfad4005
MV
1016}
1017
2caaadd1
MV
1018static int
1019read_decimal_integer (SCM port, int c, ssize_t *resp)
1020{
1021 ssize_t sign = 1;
1022 ssize_t res = 0;
1023 int got_it = 0;
1024
1025 if (c == '-')
1026 {
1027 sign = -1;
1028 c = scm_getc (port);
1029 }
1030
1031 while ('0' <= c && c <= '9')
1032 {
1033 res = 10*res + c-'0';
1034 got_it = 1;
1035 c = scm_getc (port);
1036 }
1037
1038 if (got_it)
f30e1bdf 1039 *resp = sign * res;
2caaadd1
MV
1040 return c;
1041}
1042
bfad4005
MV
1043SCM
1044scm_i_read_array (SCM port, int c)
1045{
5a6d139b 1046 ssize_t rank;
bfad4005
MV
1047 int got_rank;
1048 char tag[80];
1049 int tag_len;
1050
2caaadd1 1051 SCM shape = SCM_BOOL_F, elements;
bfad4005
MV
1052
1053 /* XXX - shortcut for ordinary vectors. Shouldn't be necessary but
1054 the array code can not deal with zero-length dimensions yet, and
1055 we want to allow zero-length vectors, of course.
1056 */
1057 if (c == '(')
1058 {
1059 scm_ungetc (c, port);
1060 return scm_vector (scm_read (port));
1061 }
1062
1063 /* Disambiguate between '#f' and uniform floating point vectors.
1064 */
1065 if (c == 'f')
1066 {
1067 c = scm_getc (port);
1068 if (c != '3' && c != '6')
1069 {
1070 if (c != EOF)
1071 scm_ungetc (c, port);
1072 return SCM_BOOL_F;
1073 }
1074 rank = 1;
1075 got_rank = 1;
1076 tag[0] = 'f';
1077 tag_len = 1;
1078 goto continue_reading_tag;
1079 }
1080
2caaadd1
MV
1081 /* Read rank.
1082 */
1083 rank = 1;
1084 c = read_decimal_integer (port, c, &rank);
1085 if (rank < 0)
1086 scm_i_input_error (NULL, port, "array rank must be non-negative",
1087 SCM_EOL);
bfad4005 1088
2caaadd1
MV
1089 /* Read tag.
1090 */
bfad4005
MV
1091 tag_len = 0;
1092 continue_reading_tag:
2caaadd1 1093 while (c != EOF && c != '(' && c != '@' && c != ':' && tag_len < 80)
bfad4005
MV
1094 {
1095 tag[tag_len++] = c;
1096 c = scm_getc (port);
1097 }
1098 tag[tag_len] = '\0';
1099
2caaadd1
MV
1100 /* Read shape.
1101 */
1102 if (c == '@' || c == ':')
bfad4005 1103 {
2caaadd1 1104 shape = SCM_EOL;
5f37cb63
MV
1105
1106 do
bfad4005 1107 {
2caaadd1
MV
1108 ssize_t lbnd = 0, len = 0;
1109 SCM s;
5f37cb63 1110
2caaadd1 1111 if (c == '@')
5f37cb63 1112 {
5f37cb63 1113 c = scm_getc (port);
2caaadd1 1114 c = read_decimal_integer (port, c, &lbnd);
5f37cb63 1115 }
2caaadd1
MV
1116
1117 s = scm_from_ssize_t (lbnd);
1118
1119 if (c == ':')
5f37cb63 1120 {
5f37cb63 1121 c = scm_getc (port);
2caaadd1 1122 c = read_decimal_integer (port, c, &len);
f30e1bdf
LC
1123 if (len < 0)
1124 scm_i_input_error (NULL, port,
1125 "array length must be non-negative",
1126 SCM_EOL);
1127
2caaadd1 1128 s = scm_list_2 (s, scm_from_ssize_t (lbnd+len-1));
5f37cb63 1129 }
2caaadd1
MV
1130
1131 shape = scm_cons (s, shape);
1132 } while (c == '@' || c == ':');
1133
1134 shape = scm_reverse_x (shape, SCM_EOL);
bfad4005
MV
1135 }
1136
1137 /* Read nested lists of elements.
1138 */
1139 if (c != '(')
1140 scm_i_input_error (NULL, port,
1141 "missing '(' in vector or array literal",
1142 SCM_EOL);
1143 scm_ungetc (c, port);
1144 elements = scm_read (port);
1145
2caaadd1 1146 if (scm_is_false (shape))
5a6d139b 1147 shape = scm_from_ssize_t (rank);
2caaadd1
MV
1148 else if (scm_ilength (shape) != rank)
1149 scm_i_input_error
1150 (NULL, port,
1151 "the number of shape specifications must match the array rank",
1152 SCM_EOL);
bfad4005 1153
5f37cb63
MV
1154 /* Handle special print syntax of rank zero arrays; see
1155 scm_i_print_array for a rationale.
1156 */
1157 if (rank == 0)
2caaadd1
MV
1158 {
1159 if (!scm_is_pair (elements))
1160 scm_i_input_error (NULL, port,
1161 "too few elements in array literal, need 1",
1162 SCM_EOL);
1163 if (!scm_is_null (SCM_CDR (elements)))
1164 scm_i_input_error (NULL, port,
1165 "too many elements in array literal, want 1",
1166 SCM_EOL);
1167 elements = SCM_CAR (elements);
1168 }
5f37cb63
MV
1169
1170 /* Construct array.
1171 */
2caaadd1 1172 return scm_list_to_typed_array (tag_to_type (tag, port), shape, elements);
bfad4005
MV
1173}
1174
ab1be174 1175
0f2d19dd 1176static SCM
e841c3e0 1177array_mark (SCM ptr)
0f2d19dd 1178{
04b87de5 1179 return SCM_I_ARRAY_V (ptr);
0f2d19dd
JB
1180}
1181
1be6b49c 1182static size_t
e841c3e0 1183array_free (SCM ptr)
0f2d19dd 1184{
04b87de5
MV
1185 scm_gc_free (SCM_I_ARRAY_MEM (ptr),
1186 (sizeof (scm_i_t_array)
1187 + SCM_I_ARRAY_NDIM (ptr) * sizeof (scm_t_array_dim)),
4c9419ac
MV
1188 "array");
1189 return 0;
0f2d19dd
JB
1190}
1191
2a610be5
AW
1192static SCM
1193array_handle_ref (scm_t_array_handle *h, size_t pos)
1194{
1195 return scm_c_generalized_vector_ref (SCM_I_ARRAY_V (h->array), pos);
1196}
1197
1198static void
1199array_handle_set (scm_t_array_handle *h, size_t pos, SCM val)
1200{
1201 scm_c_generalized_vector_set_x (SCM_I_ARRAY_V (h->array), pos, val);
1202}
1203
1204/* FIXME: should be handle for vect? maybe not, because of dims */
1205static void
1206array_get_handle (SCM array, scm_t_array_handle *h)
1207{
1208 scm_t_array_handle vh;
1209 scm_array_get_handle (SCM_I_ARRAY_V (array), &vh);
1210 h->element_type = vh.element_type;
1211 h->elements = vh.elements;
1212 h->writable_elements = vh.writable_elements;
1213 scm_array_handle_release (&vh);
1214
1215 h->dims = SCM_I_ARRAY_DIMS (array);
1216 h->ndims = SCM_I_ARRAY_NDIM (array);
1217 h->base = SCM_I_ARRAY_BASE (array);
1218}
1219
1220SCM_ARRAY_IMPLEMENTATION (scm_i_tc16_array, 0xffff,
1221 array_handle_ref, array_handle_set,
1222 array_get_handle);
1223
0f2d19dd 1224void
2fa901a5 1225scm_init_arrays ()
0f2d19dd 1226{
04b87de5
MV
1227 scm_i_tc16_array = scm_make_smob_type ("array", 0);
1228 scm_set_smob_mark (scm_i_tc16_array, array_mark);
1229 scm_set_smob_free (scm_i_tc16_array, array_free);
1230 scm_set_smob_print (scm_i_tc16_array, scm_i_print_array);
1231 scm_set_smob_equalp (scm_i_tc16_array, scm_array_equal_p);
1232
0f2d19dd 1233 scm_add_feature ("array");
20930f28 1234
f301dbf3
MV
1235 init_type_creator_table ();
1236
2fa901a5 1237#include "libguile/arrays.x"
bfad4005 1238
0f2d19dd 1239}
89e00824
ML
1240
1241/*
1242 Local Variables:
1243 c-file-style: "gnu"
1244 End:
1245*/