bitvector exodus from unif.[ch]
[bpt/guile.git] / libguile / unif.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
c209c88e
GB
20/*
21 This file has code for arrays in lots of variants (double, integer,
22 unsigned etc. ). It suffers from hugely repetitive code because
23 there is similar (but different) code for every variant included. (urg.)
24
25 --hwn
26*/
0f2d19dd
JB
27\f
28
dbb605f5 29#ifdef HAVE_CONFIG_H
2a5cd898
RB
30# include <config.h>
31#endif
32
0f2d19dd 33#include <stdio.h>
e6e2e95a 34#include <errno.h>
783e7774 35#include <string.h>
e6e2e95a 36
a0599745 37#include "libguile/_scm.h"
e0e49670
MV
38#include "libguile/__scm.h"
39#include "libguile/eq.h"
a0599745
MD
40#include "libguile/chars.h"
41#include "libguile/eval.h"
42#include "libguile/fports.h"
43#include "libguile/smob.h"
a0599745
MD
44#include "libguile/feature.h"
45#include "libguile/root.h"
46#include "libguile/strings.h"
c44ca4fe 47#include "libguile/srfi-13.h"
e0e49670 48#include "libguile/srfi-4.h"
a0599745 49#include "libguile/vectors.h"
cf396142 50#include "libguile/bitvectors.h"
438974d0 51#include "libguile/bytevectors.h"
bfad4005 52#include "libguile/list.h"
d44ff083 53#include "libguile/dynwind.h"
a0599745
MD
54
55#include "libguile/validate.h"
56#include "libguile/unif.h"
5d1b3b2d 57#include "libguile/array-map.h"
f27d2057 58#include "libguile/print.h"
bfad4005 59#include "libguile/read.h"
0f2d19dd 60
3d8d56df
GH
61#ifdef HAVE_UNISTD_H
62#include <unistd.h>
63#endif
64
7beabedb
MG
65#ifdef HAVE_IO_H
66#include <io.h>
67#endif
68
0f2d19dd
JB
69\f
70/* The set of uniform scm_vector types is:
e0e49670 71 * Vector of: Called: Replaced by:
bfad4005 72 * unsigned char string
85368844 73 * char byvect s8 or u8, depending on signedness of 'char'
e0e49670
MV
74 * boolean bvect
75 * signed long ivect s32
76 * unsigned long uvect u32
77 * float fvect f32
78 * double dvect d32
85368844 79 * complex double cvect c64
e0e49670
MV
80 * short svect s16
81 * long long llvect s64
0f2d19dd
JB
82 */
83
04b87de5
MV
84scm_t_bits scm_i_tc16_array;
85scm_t_bits scm_i_tc16_enclosed_array;
86
87#define SCM_SET_ARRAY_CONTIGUOUS_FLAG(x) \
88 (SCM_SET_CELL_WORD_0 ((x), SCM_CELL_WORD_0 (x) | SCM_I_ARRAY_FLAG_CONTIGUOUS))
89#define SCM_CLR_ARRAY_CONTIGUOUS_FLAG(x) \
90 (SCM_SET_CELL_WORD_0 ((x), SCM_CELL_WORD_0 (x) & ~SCM_I_ARRAY_FLAG_CONTIGUOUS))
1cc91f1b 91
f301dbf3
MV
92typedef SCM creator_proc (SCM len, SCM fill);
93
94struct {
95 char *type_name;
96 SCM type;
97 creator_proc *creator;
98} type_creator_table[] = {
99 { "a", SCM_UNSPECIFIED, scm_make_string },
100 { "b", SCM_UNSPECIFIED, scm_make_bitvector },
101 { "u8", SCM_UNSPECIFIED, scm_make_u8vector },
102 { "s8", SCM_UNSPECIFIED, scm_make_s8vector },
103 { "u16", SCM_UNSPECIFIED, scm_make_u16vector },
104 { "s16", SCM_UNSPECIFIED, scm_make_s16vector },
105 { "u32", SCM_UNSPECIFIED, scm_make_u32vector },
106 { "s32", SCM_UNSPECIFIED, scm_make_s32vector },
107 { "u64", SCM_UNSPECIFIED, scm_make_u64vector },
108 { "s64", SCM_UNSPECIFIED, scm_make_s64vector },
109 { "f32", SCM_UNSPECIFIED, scm_make_f32vector },
110 { "f64", SCM_UNSPECIFIED, scm_make_f64vector },
111 { "c32", SCM_UNSPECIFIED, scm_make_c32vector },
112 { "c64", SCM_UNSPECIFIED, scm_make_c64vector },
438974d0 113 { "vu8", SCM_UNSPECIFIED, scm_make_bytevector },
f301dbf3
MV
114 { NULL }
115};
116
117static void
118init_type_creator_table ()
119{
120 int i;
121 for (i = 0; type_creator_table[i].type_name; i++)
122 {
123 SCM sym = scm_from_locale_symbol (type_creator_table[i].type_name);
124 type_creator_table[i].type = scm_permanent_object (sym);
125 }
126}
127
128static creator_proc *
129type_to_creator (SCM type)
130{
131 int i;
132
133 if (scm_is_eq (type, SCM_BOOL_T))
134 return scm_make_vector;
135 for (i = 0; type_creator_table[i].type_name; i++)
136 if (scm_is_eq (type, type_creator_table[i].type))
137 return type_creator_table[i].creator;
138
139 scm_misc_error (NULL, "unknown array type: ~a", scm_list_1 (type));
140}
141
142static SCM
143make_typed_vector (SCM type, size_t len)
144{
145 creator_proc *creator = type_to_creator (type);
146 return creator (scm_from_size_t (len), SCM_UNDEFINED);
147}
bfad4005 148
f301dbf3
MV
149int
150scm_is_array (SCM obj)
0f2d19dd 151{
04b87de5
MV
152 return (SCM_I_ENCLOSED_ARRAYP (obj)
153 || SCM_I_ARRAYP (obj)
f301dbf3
MV
154 || scm_is_generalized_vector (obj));
155}
156
157int
158scm_is_typed_array (SCM obj, SCM type)
159{
04b87de5 160 if (SCM_I_ENCLOSED_ARRAYP (obj))
0f2d19dd 161 {
f301dbf3 162 /* Enclosed arrays are arrays but are not of any type.
02339e5b 163 */
f301dbf3 164 return 0;
e0e49670
MV
165 }
166
02339e5b
MV
167 /* Get storage vector.
168 */
04b87de5
MV
169 if (SCM_I_ARRAYP (obj))
170 obj = SCM_I_ARRAY_V (obj);
02339e5b 171
20930f28 172 /* It must be a generalized vector (which includes vectors, strings, etc).
bfad4005 173 */
f301dbf3
MV
174 if (!scm_is_generalized_vector (obj))
175 return 0;
9b0018a1 176
f301dbf3
MV
177 return scm_is_eq (type, scm_i_generalized_vector_type (obj));
178}
20930f28 179
f301dbf3
MV
180/* We keep the old 2-argument C prototype for a while although the old
181 PROT argument is always ignored now. C code should probably use
182 scm_is_array or scm_is_typed_array anyway.
183*/
184
86d88a22 185SCM_DEFINE (scm_array_p, "array?", 1, 0, 0,
6e708ef2 186 (SCM obj),
f301dbf3
MV
187 "Return @code{#t} if the @var{obj} is an array, and @code{#f} if\n"
188 "not.")
86d88a22 189#define FUNC_NAME s_scm_array_p
f301dbf3
MV
190{
191 return scm_from_bool (scm_is_array (obj));
192}
193#undef FUNC_NAME
194
f301dbf3
MV
195SCM_DEFINE (scm_typed_array_p, "typed-array?", 2, 0, 0,
196 (SCM obj, SCM type),
197 "Return @code{#t} if the @var{obj} is an array of type\n"
198 "@var{type}, and @code{#f} if not.")
199#define FUNC_NAME s_scm_typed_array_p
200{
201 return scm_from_bool (scm_is_typed_array (obj, type));
0f2d19dd 202}
1bbd0b84 203#undef FUNC_NAME
0f2d19dd 204
04b87de5
MV
205size_t
206scm_c_array_rank (SCM array)
0f2d19dd 207{
52372719 208 scm_t_array_handle handle;
04b87de5 209 size_t res;
e0e49670 210
52372719 211 scm_array_get_handle (array, &handle);
04b87de5 212 res = scm_array_handle_rank (&handle);
52372719
MV
213 scm_array_handle_release (&handle);
214 return res;
0f2d19dd 215}
04b87de5
MV
216
217SCM_DEFINE (scm_array_rank, "array-rank", 1, 0, 0,
218 (SCM array),
219 "Return the number of dimensions of the array @var{array.}\n")
220#define FUNC_NAME s_scm_array_rank
221{
222 return scm_from_size_t (scm_c_array_rank (array));
223}
1bbd0b84 224#undef FUNC_NAME
0f2d19dd
JB
225
226
3b3b36dd 227SCM_DEFINE (scm_array_dimensions, "array-dimensions", 1, 0, 0,
1bbd0b84 228 (SCM ra),
02339e5b 229 "@code{array-dimensions} is similar to @code{array-shape} but replaces\n"
b380b885 230 "elements with a @code{0} minimum with one greater than the maximum. So:\n"
1e6808ea 231 "@lisp\n"
b380b885 232 "(array-dimensions (make-array 'foo '(-1 3) 5)) @result{} ((-1 3) 5)\n"
1e6808ea 233 "@end lisp")
1bbd0b84 234#define FUNC_NAME s_scm_array_dimensions
0f2d19dd 235{
52372719
MV
236 scm_t_array_handle handle;
237 scm_t_array_dim *s;
238 SCM res = SCM_EOL;
239 size_t k;
20930f28 240
52372719
MV
241 scm_array_get_handle (ra, &handle);
242 s = scm_array_handle_dims (&handle);
243 k = scm_array_handle_rank (&handle);
20930f28 244
52372719
MV
245 while (k--)
246 res = scm_cons (s[k].lbnd
247 ? scm_cons2 (scm_from_ssize_t (s[k].lbnd),
248 scm_from_ssize_t (s[k].ubnd),
249 SCM_EOL)
250 : scm_from_ssize_t (1 + s[k].ubnd),
251 res);
252
253 scm_array_handle_release (&handle);
254 return res;
0f2d19dd 255}
1bbd0b84 256#undef FUNC_NAME
0f2d19dd
JB
257
258
e2d37336
MD
259SCM_DEFINE (scm_shared_array_root, "shared-array-root", 1, 0, 0,
260 (SCM ra),
261 "Return the root vector of a shared array.")
262#define FUNC_NAME s_scm_shared_array_root
263{
04b87de5
MV
264 if (SCM_I_ARRAYP (ra) || SCM_I_ENCLOSED_ARRAYP (ra))
265 return SCM_I_ARRAY_V (ra);
52372719
MV
266 else if (scm_is_generalized_vector (ra))
267 return ra;
268 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
e2d37336
MD
269}
270#undef FUNC_NAME
271
272
273SCM_DEFINE (scm_shared_array_offset, "shared-array-offset", 1, 0, 0,
274 (SCM ra),
275 "Return the root vector index of the first element in the array.")
276#define FUNC_NAME s_scm_shared_array_offset
277{
52372719
MV
278 scm_t_array_handle handle;
279 SCM res;
280
281 scm_array_get_handle (ra, &handle);
282 res = scm_from_size_t (handle.base);
283 scm_array_handle_release (&handle);
284 return res;
e2d37336
MD
285}
286#undef FUNC_NAME
287
288
289SCM_DEFINE (scm_shared_array_increments, "shared-array-increments", 1, 0, 0,
290 (SCM ra),
291 "For each dimension, return the distance between elements in the root vector.")
292#define FUNC_NAME s_scm_shared_array_increments
293{
52372719 294 scm_t_array_handle handle;
e2d37336 295 SCM res = SCM_EOL;
1be6b49c 296 size_t k;
92c2555f 297 scm_t_array_dim *s;
02339e5b 298
52372719
MV
299 scm_array_get_handle (ra, &handle);
300 k = scm_array_handle_rank (&handle);
301 s = scm_array_handle_dims (&handle);
e2d37336 302 while (k--)
52372719
MV
303 res = scm_cons (scm_from_ssize_t (s[k].inc), res);
304 scm_array_handle_release (&handle);
e2d37336
MD
305 return res;
306}
307#undef FUNC_NAME
308
0cd6cb2f
MV
309ssize_t
310scm_array_handle_pos (scm_t_array_handle *h, SCM indices)
52372719
MV
311{
312 scm_t_array_dim *s = scm_array_handle_dims (h);
313 ssize_t pos = 0, i;
314 size_t k = scm_array_handle_rank (h);
315
316 while (k > 0 && scm_is_pair (indices))
317 {
318 i = scm_to_signed_integer (SCM_CAR (indices), s->lbnd, s->ubnd);
319 pos += (i - s->lbnd) * s->inc;
320 k--;
321 s++;
322 indices = SCM_CDR (indices);
323 }
324 if (k > 0 || !scm_is_null (indices))
325 scm_misc_error (NULL, "wrong number of indices, expecting ~a",
326 scm_list_1 (scm_from_size_t (scm_array_handle_rank (h))));
327 return pos;
328}
1cc91f1b 329
0cd6cb2f 330SCM
b6149d8d 331scm_i_make_array (int ndim, int enclosed)
0f2d19dd 332{
04b87de5 333 scm_t_bits tag = enclosed? scm_i_tc16_enclosed_array : scm_i_tc16_array;
0f2d19dd 334 SCM ra;
02339e5b 335 SCM_NEWSMOB(ra, ((scm_t_bits) ndim << 17) + tag,
04b87de5 336 scm_gc_malloc ((sizeof (scm_i_t_array) +
4c9419ac
MV
337 ndim * sizeof (scm_t_array_dim)),
338 "array"));
04b87de5 339 SCM_I_ARRAY_V (ra) = SCM_BOOL_F;
0f2d19dd
JB
340 return ra;
341}
342
343static char s_bad_spec[] = "Bad scm_array dimension";
0f2d19dd 344
1cc91f1b 345
02339e5b
MV
346/* Increments will still need to be set. */
347
0cd6cb2f
MV
348static SCM
349scm_i_shap2ra (SCM args)
0f2d19dd 350{
92c2555f 351 scm_t_array_dim *s;
0f2d19dd
JB
352 SCM ra, spec, sp;
353 int ndim = scm_ilength (args);
b3fcac34 354 if (ndim < 0)
0cd6cb2f 355 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
b3fcac34 356
b6149d8d 357 ra = scm_i_make_array (ndim, 0);
04b87de5
MV
358 SCM_I_ARRAY_BASE (ra) = 0;
359 s = SCM_I_ARRAY_DIMS (ra);
d2e53ed6 360 for (; !scm_is_null (args); s++, args = SCM_CDR (args))
0f2d19dd
JB
361 {
362 spec = SCM_CAR (args);
e11e83f3 363 if (scm_is_integer (spec))
0f2d19dd 364 {
e11e83f3 365 if (scm_to_long (spec) < 0)
0cd6cb2f 366 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
0f2d19dd 367 s->lbnd = 0;
e11e83f3 368 s->ubnd = scm_to_long (spec) - 1;
0f2d19dd
JB
369 s->inc = 1;
370 }
371 else
372 {
d2e53ed6 373 if (!scm_is_pair (spec) || !scm_is_integer (SCM_CAR (spec)))
0cd6cb2f 374 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
e11e83f3 375 s->lbnd = scm_to_long (SCM_CAR (spec));
0f2d19dd 376 sp = SCM_CDR (spec);
d2e53ed6 377 if (!scm_is_pair (sp)
e11e83f3 378 || !scm_is_integer (SCM_CAR (sp))
d2e53ed6 379 || !scm_is_null (SCM_CDR (sp)))
0cd6cb2f 380 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
e11e83f3 381 s->ubnd = scm_to_long (SCM_CAR (sp));
0f2d19dd
JB
382 s->inc = 1;
383 }
384 }
385 return ra;
386}
387
f301dbf3
MV
388SCM_DEFINE (scm_make_typed_array, "make-typed-array", 2, 0, 1,
389 (SCM type, SCM fill, SCM bounds),
390 "Create and return an array of type @var{type}.")
391#define FUNC_NAME s_scm_make_typed_array
0f2d19dd 392{
f301dbf3 393 size_t k, rlen = 1;
92c2555f 394 scm_t_array_dim *s;
f301dbf3 395 creator_proc *creator;
0f2d19dd 396 SCM ra;
1be6b49c 397
f301dbf3 398 creator = type_to_creator (type);
0cd6cb2f 399 ra = scm_i_shap2ra (bounds);
e038c042 400 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
04b87de5
MV
401 s = SCM_I_ARRAY_DIMS (ra);
402 k = SCM_I_ARRAY_NDIM (ra);
1be6b49c 403
0f2d19dd
JB
404 while (k--)
405 {
a3a32939 406 s[k].inc = rlen;
2caaadd1 407 SCM_ASSERT_RANGE (1, bounds, s[k].lbnd <= s[k].ubnd + 1);
0f2d19dd 408 rlen = (s[k].ubnd - s[k].lbnd + 1) * s[k].inc;
0f2d19dd 409 }
a3a32939 410
f0b91039 411 if (scm_is_eq (fill, SCM_UNSPECIFIED))
f301dbf3 412 fill = SCM_UNDEFINED;
a3a32939 413
04b87de5 414 SCM_I_ARRAY_V (ra) = creator (scm_from_size_t (rlen), fill);
a3a32939 415
04b87de5 416 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
c014a02e 417 if (s->ubnd < s->lbnd || (0 == s->lbnd && 1 == s->inc))
04b87de5 418 return SCM_I_ARRAY_V (ra);
0f2d19dd
JB
419 return ra;
420}
1bbd0b84 421#undef FUNC_NAME
0f2d19dd 422
782a82ee
AW
423SCM
424scm_from_contiguous_typed_array (SCM type, SCM bounds, const void *bytes,
425 size_t byte_len)
426#define FUNC_NAME "scm_from_contiguous_typed_array"
427{
428 size_t k, rlen = 1;
429 scm_t_array_dim *s;
430 creator_proc *creator;
431 SCM ra;
432 scm_t_array_handle h;
433 void *base;
434 size_t sz;
435
436 creator = type_to_creator (type);
437 ra = scm_i_shap2ra (bounds);
438 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
439 s = SCM_I_ARRAY_DIMS (ra);
440 k = SCM_I_ARRAY_NDIM (ra);
441
442 while (k--)
443 {
444 s[k].inc = rlen;
445 SCM_ASSERT_RANGE (1, bounds, s[k].lbnd <= s[k].ubnd + 1);
446 rlen = (s[k].ubnd - s[k].lbnd + 1) * s[k].inc;
447 }
448 SCM_I_ARRAY_V (ra) = creator (scm_from_size_t (rlen), SCM_UNDEFINED);
449
450
451 scm_array_get_handle (ra, &h);
452 base = scm_array_handle_uniform_writable_elements (&h);
453 sz = scm_array_handle_uniform_element_size (&h);
454 scm_array_handle_release (&h);
455
456 if (byte_len % sz)
457 SCM_MISC_ERROR ("byte length not a multiple of the unit size", SCM_EOL);
458 if (byte_len / sz != rlen)
459 SCM_MISC_ERROR ("byte length and dimensions do not match", SCM_EOL);
460
461 memcpy (base, bytes, byte_len);
462
463 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
464 if (s->ubnd < s->lbnd || (0 == s->lbnd && 1 == s->inc))
465 return SCM_I_ARRAY_V (ra);
466 return ra;
467}
468#undef FUNC_NAME
469
f301dbf3
MV
470SCM_DEFINE (scm_make_array, "make-array", 1, 0, 1,
471 (SCM fill, SCM bounds),
472 "Create and return an array.")
473#define FUNC_NAME s_scm_make_array
474{
475 return scm_make_typed_array (SCM_BOOL_T, fill, bounds);
476}
477#undef FUNC_NAME
478
0cd6cb2f
MV
479static void
480scm_i_ra_set_contp (SCM ra)
0f2d19dd 481{
04b87de5 482 size_t k = SCM_I_ARRAY_NDIM (ra);
0f2d19dd 483 if (k)
0f2d19dd 484 {
04b87de5 485 long inc = SCM_I_ARRAY_DIMS (ra)[k - 1].inc;
fe0c6dae 486 while (k--)
0f2d19dd 487 {
04b87de5 488 if (inc != SCM_I_ARRAY_DIMS (ra)[k].inc)
fe0c6dae 489 {
e038c042 490 SCM_CLR_ARRAY_CONTIGUOUS_FLAG (ra);
fe0c6dae
JB
491 return;
492 }
04b87de5
MV
493 inc *= (SCM_I_ARRAY_DIMS (ra)[k].ubnd
494 - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1);
0f2d19dd 495 }
0f2d19dd 496 }
e038c042 497 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
0f2d19dd
JB
498}
499
500
3b3b36dd 501SCM_DEFINE (scm_make_shared_array, "make-shared-array", 2, 0, 1,
1bbd0b84 502 (SCM oldra, SCM mapfunc, SCM dims),
b380b885
MD
503 "@code{make-shared-array} can be used to create shared subarrays of other\n"
504 "arrays. The @var{mapper} is a function that translates coordinates in\n"
505 "the new array into coordinates in the old array. A @var{mapper} must be\n"
506 "linear, and its range must stay within the bounds of the old array, but\n"
507 "it can be otherwise arbitrary. A simple example:\n"
1e6808ea 508 "@lisp\n"
b380b885
MD
509 "(define fred (make-array #f 8 8))\n"
510 "(define freds-diagonal\n"
511 " (make-shared-array fred (lambda (i) (list i i)) 8))\n"
512 "(array-set! freds-diagonal 'foo 3)\n"
513 "(array-ref fred 3 3) @result{} foo\n"
514 "(define freds-center\n"
515 " (make-shared-array fred (lambda (i j) (list (+ 3 i) (+ 3 j))) 2 2))\n"
516 "(array-ref freds-center 0 0) @result{} foo\n"
1e6808ea 517 "@end lisp")
1bbd0b84 518#define FUNC_NAME s_scm_make_shared_array
0f2d19dd 519{
112ba0ac 520 scm_t_array_handle old_handle;
0f2d19dd
JB
521 SCM ra;
522 SCM inds, indptr;
523 SCM imap;
112ba0ac
MV
524 size_t k;
525 ssize_t i;
2b829bbb 526 long old_base, old_min, new_min, old_max, new_max;
92c2555f 527 scm_t_array_dim *s;
b3fcac34
DH
528
529 SCM_VALIDATE_REST_ARGUMENT (dims);
34d19ef6 530 SCM_VALIDATE_PROC (2, mapfunc);
0cd6cb2f 531 ra = scm_i_shap2ra (dims);
112ba0ac
MV
532
533 scm_array_get_handle (oldra, &old_handle);
534
04b87de5 535 if (SCM_I_ARRAYP (oldra))
0f2d19dd 536 {
04b87de5 537 SCM_I_ARRAY_V (ra) = SCM_I_ARRAY_V (oldra);
2b829bbb 538 old_base = old_min = old_max = SCM_I_ARRAY_BASE (oldra);
112ba0ac
MV
539 s = scm_array_handle_dims (&old_handle);
540 k = scm_array_handle_rank (&old_handle);
0f2d19dd
JB
541 while (k--)
542 {
543 if (s[k].inc > 0)
544 old_max += (s[k].ubnd - s[k].lbnd) * s[k].inc;
545 else
546 old_min += (s[k].ubnd - s[k].lbnd) * s[k].inc;
547 }
548 }
549 else
550 {
04b87de5 551 SCM_I_ARRAY_V (ra) = oldra;
2b829bbb 552 old_base = old_min = 0;
02339e5b 553 old_max = scm_c_generalized_vector_length (oldra) - 1;
0f2d19dd 554 }
112ba0ac 555
0f2d19dd 556 inds = SCM_EOL;
04b87de5
MV
557 s = SCM_I_ARRAY_DIMS (ra);
558 for (k = 0; k < SCM_I_ARRAY_NDIM (ra); k++)
0f2d19dd 559 {
e11e83f3 560 inds = scm_cons (scm_from_long (s[k].lbnd), inds);
0f2d19dd
JB
561 if (s[k].ubnd < s[k].lbnd)
562 {
04b87de5 563 if (1 == SCM_I_ARRAY_NDIM (ra))
f301dbf3 564 ra = make_typed_vector (scm_array_type (ra), 0);
0f2d19dd 565 else
04b87de5 566 SCM_I_ARRAY_V (ra) = make_typed_vector (scm_array_type (ra), 0);
112ba0ac 567 scm_array_handle_release (&old_handle);
0f2d19dd
JB
568 return ra;
569 }
570 }
112ba0ac 571
fdc28395 572 imap = scm_apply_0 (mapfunc, scm_reverse (inds));
0cd6cb2f 573 i = scm_array_handle_pos (&old_handle, imap);
2b829bbb 574 SCM_I_ARRAY_BASE (ra) = new_min = new_max = i + old_base;
0f2d19dd 575 indptr = inds;
04b87de5 576 k = SCM_I_ARRAY_NDIM (ra);
0f2d19dd
JB
577 while (k--)
578 {
579 if (s[k].ubnd > s[k].lbnd)
580 {
e11e83f3 581 SCM_SETCAR (indptr, scm_sum (SCM_CAR (indptr), scm_from_int (1)));
fdc28395 582 imap = scm_apply_0 (mapfunc, scm_reverse (inds));
0cd6cb2f 583 s[k].inc = scm_array_handle_pos (&old_handle, imap) - i;
0f2d19dd
JB
584 i += s[k].inc;
585 if (s[k].inc > 0)
586 new_max += (s[k].ubnd - s[k].lbnd) * s[k].inc;
587 else
588 new_min += (s[k].ubnd - s[k].lbnd) * s[k].inc;
589 }
590 else
591 s[k].inc = new_max - new_min + 1; /* contiguous by default */
592 indptr = SCM_CDR (indptr);
593 }
112ba0ac
MV
594
595 scm_array_handle_release (&old_handle);
596
b3fcac34
DH
597 if (old_min > new_min || old_max < new_max)
598 SCM_MISC_ERROR ("mapping out of range", SCM_EOL);
04b87de5 599 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
0f2d19dd 600 {
04b87de5 601 SCM v = SCM_I_ARRAY_V (ra);
6e708ef2 602 size_t length = scm_c_generalized_vector_length (v);
74014c46
DH
603 if (1 == s->inc && 0 == s->lbnd && length == 1 + s->ubnd)
604 return v;
0f2d19dd 605 if (s->ubnd < s->lbnd)
f301dbf3 606 return make_typed_vector (scm_array_type (ra), 0);
0f2d19dd 607 }
0cd6cb2f 608 scm_i_ra_set_contp (ra);
0f2d19dd
JB
609 return ra;
610}
1bbd0b84 611#undef FUNC_NAME
0f2d19dd
JB
612
613
614/* args are RA . DIMS */
af45e3b0
DH
615SCM_DEFINE (scm_transpose_array, "transpose-array", 1, 0, 1,
616 (SCM ra, SCM args),
1e6808ea
MG
617 "Return an array sharing contents with @var{array}, but with\n"
618 "dimensions arranged in a different order. There must be one\n"
619 "@var{dim} argument for each dimension of @var{array}.\n"
620 "@var{dim0}, @var{dim1}, @dots{} should be integers between 0\n"
621 "and the rank of the array to be returned. Each integer in that\n"
622 "range must appear at least once in the argument list.\n"
623 "\n"
624 "The values of @var{dim0}, @var{dim1}, @dots{} correspond to\n"
625 "dimensions in the array to be returned, their positions in the\n"
626 "argument list to dimensions of @var{array}. Several @var{dim}s\n"
627 "may have the same value, in which case the returned array will\n"
628 "have smaller rank than @var{array}.\n"
629 "\n"
630 "@lisp\n"
b380b885
MD
631 "(transpose-array '#2((a b) (c d)) 1 0) @result{} #2((a c) (b d))\n"
632 "(transpose-array '#2((a b) (c d)) 0 0) @result{} #1(a d)\n"
633 "(transpose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1 1 0) @result{}\n"
634 " #2((a 4) (b 5) (c 6))\n"
1e6808ea 635 "@end lisp")
1bbd0b84 636#define FUNC_NAME s_scm_transpose_array
0f2d19dd 637{
34d19ef6 638 SCM res, vargs;
92c2555f 639 scm_t_array_dim *s, *r;
0f2d19dd 640 int ndim, i, k;
af45e3b0 641
b3fcac34 642 SCM_VALIDATE_REST_ARGUMENT (args);
1bbd0b84 643 SCM_ASSERT (SCM_NIMP (ra), ra, SCM_ARG1, FUNC_NAME);
e0e49670 644
20930f28 645 if (scm_is_generalized_vector (ra))
e0e49670
MV
646 {
647 /* Make sure that we are called with a single zero as
648 arguments.
649 */
650 if (scm_is_null (args) || !scm_is_null (SCM_CDR (args)))
651 SCM_WRONG_NUM_ARGS ();
652 SCM_VALIDATE_INT_COPY (SCM_ARG2, SCM_CAR (args), i);
653 SCM_ASSERT_RANGE (SCM_ARG2, SCM_CAR (args), i == 0);
654 return ra;
655 }
656
04b87de5 657 if (SCM_I_ARRAYP (ra) || SCM_I_ENCLOSED_ARRAYP (ra))
0f2d19dd 658 {
0f2d19dd 659 vargs = scm_vector (args);
04b87de5 660 if (SCM_SIMPLE_VECTOR_LENGTH (vargs) != SCM_I_ARRAY_NDIM (ra))
b3fcac34 661 SCM_WRONG_NUM_ARGS ();
0f2d19dd 662 ndim = 0;
04b87de5 663 for (k = 0; k < SCM_I_ARRAY_NDIM (ra); k++)
0f2d19dd 664 {
6e708ef2 665 i = scm_to_signed_integer (SCM_SIMPLE_VECTOR_REF (vargs, k),
04b87de5 666 0, SCM_I_ARRAY_NDIM(ra));
0f2d19dd
JB
667 if (ndim < i)
668 ndim = i;
669 }
670 ndim++;
b6149d8d 671 res = scm_i_make_array (ndim, 0);
04b87de5
MV
672 SCM_I_ARRAY_V (res) = SCM_I_ARRAY_V (ra);
673 SCM_I_ARRAY_BASE (res) = SCM_I_ARRAY_BASE (ra);
0f2d19dd
JB
674 for (k = ndim; k--;)
675 {
04b87de5
MV
676 SCM_I_ARRAY_DIMS (res)[k].lbnd = 0;
677 SCM_I_ARRAY_DIMS (res)[k].ubnd = -1;
0f2d19dd 678 }
04b87de5 679 for (k = SCM_I_ARRAY_NDIM (ra); k--;)
0f2d19dd 680 {
6e708ef2 681 i = scm_to_int (SCM_SIMPLE_VECTOR_REF (vargs, k));
04b87de5
MV
682 s = &(SCM_I_ARRAY_DIMS (ra)[k]);
683 r = &(SCM_I_ARRAY_DIMS (res)[i]);
0f2d19dd
JB
684 if (r->ubnd < r->lbnd)
685 {
686 r->lbnd = s->lbnd;
687 r->ubnd = s->ubnd;
688 r->inc = s->inc;
689 ndim--;
690 }
691 else
692 {
693 if (r->ubnd > s->ubnd)
694 r->ubnd = s->ubnd;
695 if (r->lbnd < s->lbnd)
696 {
04b87de5 697 SCM_I_ARRAY_BASE (res) += (s->lbnd - r->lbnd) * r->inc;
0f2d19dd
JB
698 r->lbnd = s->lbnd;
699 }
700 r->inc += s->inc;
701 }
702 }
b3fcac34
DH
703 if (ndim > 0)
704 SCM_MISC_ERROR ("bad argument list", SCM_EOL);
0cd6cb2f 705 scm_i_ra_set_contp (res);
0f2d19dd
JB
706 return res;
707 }
20930f28
MV
708
709 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
0f2d19dd 710}
1bbd0b84 711#undef FUNC_NAME
0f2d19dd
JB
712
713/* args are RA . AXES */
af45e3b0
DH
714SCM_DEFINE (scm_enclose_array, "enclose-array", 1, 0, 1,
715 (SCM ra, SCM axes),
b380b885
MD
716 "@var{dim0}, @var{dim1} @dots{} should be nonnegative integers less than\n"
717 "the rank of @var{array}. @var{enclose-array} returns an array\n"
718 "resembling an array of shared arrays. The dimensions of each shared\n"
719 "array are the same as the @var{dim}th dimensions of the original array,\n"
720 "the dimensions of the outer array are the same as those of the original\n"
721 "array that did not match a @var{dim}.\n\n"
722 "An enclosed array is not a general Scheme array. Its elements may not\n"
723 "be set using @code{array-set!}. Two references to the same element of\n"
724 "an enclosed array will be @code{equal?} but will not in general be\n"
725 "@code{eq?}. The value returned by @var{array-prototype} when given an\n"
726 "enclosed array is unspecified.\n\n"
727 "examples:\n"
1e6808ea 728 "@lisp\n"
b380b885
MD
729 "(enclose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1) @result{}\n"
730 " #<enclosed-array (#1(a d) #1(b e) #1(c f)) (#1(1 4) #1(2 5) #1(3 6))>\n\n"
731 "(enclose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1 0) @result{}\n"
732 " #<enclosed-array #2((a 1) (d 4)) #2((b 2) (e 5)) #2((c 3) (f 6))>\n"
1e6808ea 733 "@end lisp")
1bbd0b84 734#define FUNC_NAME s_scm_enclose_array
0f2d19dd 735{
af45e3b0 736 SCM axv, res, ra_inr;
cc95e00a 737 const char *c_axv;
92c2555f 738 scm_t_array_dim vdim, *s = &vdim;
0f2d19dd 739 int ndim, j, k, ninr, noutr;
af45e3b0 740
b3fcac34 741 SCM_VALIDATE_REST_ARGUMENT (axes);
d2e53ed6 742 if (scm_is_null (axes))
04b87de5 743 axes = scm_cons ((SCM_I_ARRAYP (ra) ? scm_from_size_t (SCM_I_ARRAY_NDIM (ra) - 1) : SCM_INUM0), SCM_EOL);
0f2d19dd 744 ninr = scm_ilength (axes);
b3fcac34
DH
745 if (ninr < 0)
746 SCM_WRONG_NUM_ARGS ();
b6149d8d 747 ra_inr = scm_i_make_array (ninr, 0);
e0e49670 748
20930f28 749 if (scm_is_generalized_vector (ra))
0f2d19dd 750 {
0f2d19dd 751 s->lbnd = 0;
6e708ef2 752 s->ubnd = scm_c_generalized_vector_length (ra) - 1;
0f2d19dd 753 s->inc = 1;
04b87de5
MV
754 SCM_I_ARRAY_V (ra_inr) = ra;
755 SCM_I_ARRAY_BASE (ra_inr) = 0;
0f2d19dd 756 ndim = 1;
20930f28 757 }
04b87de5 758 else if (SCM_I_ARRAYP (ra))
20930f28 759 {
04b87de5
MV
760 s = SCM_I_ARRAY_DIMS (ra);
761 SCM_I_ARRAY_V (ra_inr) = SCM_I_ARRAY_V (ra);
762 SCM_I_ARRAY_BASE (ra_inr) = SCM_I_ARRAY_BASE (ra);
763 ndim = SCM_I_ARRAY_NDIM (ra);
0f2d19dd 764 }
20930f28
MV
765 else
766 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
767
0f2d19dd 768 noutr = ndim - ninr;
b3fcac34
DH
769 if (noutr < 0)
770 SCM_WRONG_NUM_ARGS ();
e11e83f3 771 axv = scm_make_string (scm_from_int (ndim), SCM_MAKE_CHAR (0));
b6149d8d 772 res = scm_i_make_array (noutr, 1);
04b87de5
MV
773 SCM_I_ARRAY_BASE (res) = SCM_I_ARRAY_BASE (ra_inr);
774 SCM_I_ARRAY_V (res) = ra_inr;
0f2d19dd
JB
775 for (k = 0; k < ninr; k++, axes = SCM_CDR (axes))
776 {
e11e83f3 777 if (!scm_is_integer (SCM_CAR (axes)))
b3fcac34 778 SCM_MISC_ERROR ("bad axis", SCM_EOL);
e11e83f3 779 j = scm_to_int (SCM_CAR (axes));
04b87de5
MV
780 SCM_I_ARRAY_DIMS (ra_inr)[k].lbnd = s[j].lbnd;
781 SCM_I_ARRAY_DIMS (ra_inr)[k].ubnd = s[j].ubnd;
782 SCM_I_ARRAY_DIMS (ra_inr)[k].inc = s[j].inc;
cc95e00a 783 scm_c_string_set_x (axv, j, SCM_MAKE_CHAR (1));
0f2d19dd 784 }
cc95e00a 785 c_axv = scm_i_string_chars (axv);
0f2d19dd
JB
786 for (j = 0, k = 0; k < noutr; k++, j++)
787 {
cc95e00a 788 while (c_axv[j])
0f2d19dd 789 j++;
04b87de5
MV
790 SCM_I_ARRAY_DIMS (res)[k].lbnd = s[j].lbnd;
791 SCM_I_ARRAY_DIMS (res)[k].ubnd = s[j].ubnd;
792 SCM_I_ARRAY_DIMS (res)[k].inc = s[j].inc;
0f2d19dd 793 }
cc95e00a 794 scm_remember_upto_here_1 (axv);
0cd6cb2f
MV
795 scm_i_ra_set_contp (ra_inr);
796 scm_i_ra_set_contp (res);
0f2d19dd
JB
797 return res;
798}
1bbd0b84 799#undef FUNC_NAME
0f2d19dd
JB
800
801
802
af45e3b0
DH
803SCM_DEFINE (scm_array_in_bounds_p, "array-in-bounds?", 1, 0, 1,
804 (SCM v, SCM args),
1e6808ea
MG
805 "Return @code{#t} if its arguments would be acceptable to\n"
806 "@code{array-ref}.")
1bbd0b84 807#define FUNC_NAME s_scm_array_in_bounds_p
0f2d19dd 808{
02339e5b 809 SCM res = SCM_BOOL_T;
af45e3b0 810
b3fcac34 811 SCM_VALIDATE_REST_ARGUMENT (args);
0f2d19dd 812
cb5773fe 813 if (SCM_I_ARRAYP (v) || SCM_I_ENCLOSED_ARRAYP (v))
0f2d19dd 814 {
f30e1bdf 815 size_t k, ndim = SCM_I_ARRAY_NDIM (v);
04b87de5 816 scm_t_array_dim *s = SCM_I_ARRAY_DIMS (v);
02339e5b 817
f30e1bdf 818 for (k = 0; k < ndim; k++)
0f2d19dd 819 {
02339e5b 820 long ind;
20930f28 821
02339e5b
MV
822 if (!scm_is_pair (args))
823 SCM_WRONG_NUM_ARGS ();
824 ind = scm_to_long (SCM_CAR (args));
825 args = SCM_CDR (args);
02339e5b 826
f30e1bdf 827 if (ind < s[k].lbnd || ind > s[k].ubnd)
02339e5b
MV
828 {
829 res = SCM_BOOL_F;
830 /* We do not stop the checking after finding a violation
831 since we want to validate the type-correctness and
832 number of arguments in any case.
833 */
834 }
835 }
0f2d19dd 836 }
cb5773fe
MV
837 else if (scm_is_generalized_vector (v))
838 {
839 /* Since real arrays have been covered above, all generalized
840 vectors are guaranteed to be zero-origin here.
841 */
842
843 long ind;
844
845 if (!scm_is_pair (args))
846 SCM_WRONG_NUM_ARGS ();
847 ind = scm_to_long (SCM_CAR (args));
848 args = SCM_CDR (args);
849 res = scm_from_bool (ind >= 0
850 && ind < scm_c_generalized_vector_length (v));
851 }
02339e5b
MV
852 else
853 scm_wrong_type_arg_msg (NULL, 0, v, "array");
20930f28 854
02339e5b
MV
855 if (!scm_is_null (args))
856 SCM_WRONG_NUM_ARGS ();
857
858 return res;
0f2d19dd 859}
1bbd0b84 860#undef FUNC_NAME
0f2d19dd 861
2d4d7f27 862SCM
02339e5b
MV
863scm_i_cvref (SCM v, size_t pos, int enclosed)
864{
865 if (enclosed)
866 {
04b87de5 867 int k = SCM_I_ARRAY_NDIM (v);
b6149d8d 868 SCM res = scm_i_make_array (k, 0);
04b87de5
MV
869 SCM_I_ARRAY_V (res) = SCM_I_ARRAY_V (v);
870 SCM_I_ARRAY_BASE (res) = pos;
02339e5b
MV
871 while (k--)
872 {
04b87de5
MV
873 SCM_I_ARRAY_DIMS (res)[k].ubnd = SCM_I_ARRAY_DIMS (v)[k].ubnd;
874 SCM_I_ARRAY_DIMS (res)[k].lbnd = SCM_I_ARRAY_DIMS (v)[k].lbnd;
875 SCM_I_ARRAY_DIMS (res)[k].inc = SCM_I_ARRAY_DIMS (v)[k].inc;
02339e5b
MV
876 }
877 return res;
878 }
879 else
880 return scm_c_generalized_vector_ref (v, pos);
881}
882
e0e49670 883SCM_DEFINE (scm_array_ref, "array-ref", 1, 0, 1,
1bbd0b84 884 (SCM v, SCM args),
1e6808ea
MG
885 "Return the element at the @code{(index1, index2)} element in\n"
886 "@var{array}.")
e0e49670 887#define FUNC_NAME s_scm_array_ref
0f2d19dd 888{
52372719
MV
889 scm_t_array_handle handle;
890 SCM res;
e0e49670 891
52372719 892 scm_array_get_handle (v, &handle);
0cd6cb2f 893 res = scm_array_handle_ref (&handle, scm_array_handle_pos (&handle, args));
52372719
MV
894 scm_array_handle_release (&handle);
895 return res;
0f2d19dd 896}
1bbd0b84 897#undef FUNC_NAME
0f2d19dd 898
0f2d19dd 899
3b3b36dd 900SCM_DEFINE (scm_array_set_x, "array-set!", 2, 0, 1,
1bbd0b84 901 (SCM v, SCM obj, SCM args),
8f85c0c6 902 "Set the element at the @code{(index1, index2)} element in @var{array} to\n"
b380b885 903 "@var{new-value}. The value returned by array-set! is unspecified.")
1bbd0b84 904#define FUNC_NAME s_scm_array_set_x
0f2d19dd 905{
52372719 906 scm_t_array_handle handle;
b3fcac34 907
52372719 908 scm_array_get_handle (v, &handle);
0cd6cb2f 909 scm_array_handle_set (&handle, scm_array_handle_pos (&handle, args), obj);
52372719 910 scm_array_handle_release (&handle);
02339e5b 911 return SCM_UNSPECIFIED;
0f2d19dd 912}
1bbd0b84 913#undef FUNC_NAME
0f2d19dd 914
1d7bdb25
GH
915/* attempts to unroll an array into a one-dimensional array.
916 returns the unrolled array or #f if it can't be done. */
1bbd0b84 917 /* if strict is not SCM_UNDEFINED, return #f if returned array
1d7bdb25 918 wouldn't have contiguous elements. */
3b3b36dd 919SCM_DEFINE (scm_array_contents, "array-contents", 1, 1, 0,
1bbd0b84 920 (SCM ra, SCM strict),
b380b885
MD
921 "If @var{array} may be @dfn{unrolled} into a one dimensional shared array\n"
922 "without changing their order (last subscript changing fastest), then\n"
923 "@code{array-contents} returns that shared array, otherwise it returns\n"
924 "@code{#f}. All arrays made by @var{make-array} and\n"
925 "@var{make-uniform-array} may be unrolled, some arrays made by\n"
926 "@var{make-shared-array} may not be.\n\n"
927 "If the optional argument @var{strict} is provided, a shared array will\n"
928 "be returned only if its elements are stored internally contiguous in\n"
929 "memory.")
1bbd0b84 930#define FUNC_NAME s_scm_array_contents
0f2d19dd
JB
931{
932 SCM sra;
e0e49670 933
20930f28 934 if (scm_is_generalized_vector (ra))
e0e49670
MV
935 return ra;
936
04b87de5 937 if (SCM_I_ARRAYP (ra))
0f2d19dd 938 {
04b87de5
MV
939 size_t k, ndim = SCM_I_ARRAY_NDIM (ra), len = 1;
940 if (!SCM_I_ARRAYP (ra) || !SCM_I_ARRAY_CONTP (ra))
20930f28
MV
941 return SCM_BOOL_F;
942 for (k = 0; k < ndim; k++)
04b87de5 943 len *= SCM_I_ARRAY_DIMS (ra)[k].ubnd - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1;
20930f28 944 if (!SCM_UNBNDP (strict))
74014c46 945 {
04b87de5 946 if (ndim && (1 != SCM_I_ARRAY_DIMS (ra)[ndim - 1].inc))
20930f28 947 return SCM_BOOL_F;
04b87de5 948 if (scm_is_bitvector (SCM_I_ARRAY_V (ra)))
20930f28 949 {
04b87de5
MV
950 if (len != scm_c_bitvector_length (SCM_I_ARRAY_V (ra)) ||
951 SCM_I_ARRAY_BASE (ra) % SCM_LONG_BIT ||
20930f28
MV
952 len % SCM_LONG_BIT)
953 return SCM_BOOL_F;
954 }
74014c46 955 }
20930f28
MV
956
957 {
04b87de5 958 SCM v = SCM_I_ARRAY_V (ra);
20930f28 959 size_t length = scm_c_generalized_vector_length (v);
04b87de5 960 if ((len == length) && 0 == SCM_I_ARRAY_BASE (ra) && SCM_I_ARRAY_DIMS (ra)->inc)
20930f28 961 return v;
0f2d19dd 962 }
20930f28 963
b6149d8d 964 sra = scm_i_make_array (1, 0);
04b87de5
MV
965 SCM_I_ARRAY_DIMS (sra)->lbnd = 0;
966 SCM_I_ARRAY_DIMS (sra)->ubnd = len - 1;
967 SCM_I_ARRAY_V (sra) = SCM_I_ARRAY_V (ra);
968 SCM_I_ARRAY_BASE (sra) = SCM_I_ARRAY_BASE (ra);
969 SCM_I_ARRAY_DIMS (sra)->inc = (ndim ? SCM_I_ARRAY_DIMS (ra)[ndim - 1].inc : 1);
20930f28 970 return sra;
0f2d19dd 971 }
04b87de5 972 else if (SCM_I_ENCLOSED_ARRAYP (ra))
02339e5b
MV
973 scm_wrong_type_arg_msg (NULL, 0, ra, "non-enclosed array");
974 else
975 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
0f2d19dd 976}
1bbd0b84 977#undef FUNC_NAME
0f2d19dd 978
1cc91f1b 979
0f2d19dd 980SCM
6e8d25a6 981scm_ra2contig (SCM ra, int copy)
0f2d19dd
JB
982{
983 SCM ret;
c014a02e
ML
984 long inc = 1;
985 size_t k, len = 1;
04b87de5
MV
986 for (k = SCM_I_ARRAY_NDIM (ra); k--;)
987 len *= SCM_I_ARRAY_DIMS (ra)[k].ubnd - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1;
988 k = SCM_I_ARRAY_NDIM (ra);
989 if (SCM_I_ARRAY_CONTP (ra) && ((0 == k) || (1 == SCM_I_ARRAY_DIMS (ra)[k - 1].inc)))
0f2d19dd 990 {
04b87de5 991 if (!scm_is_bitvector (SCM_I_ARRAY_V (ra)))
0f2d19dd 992 return ra;
04b87de5
MV
993 if ((len == scm_c_bitvector_length (SCM_I_ARRAY_V (ra)) &&
994 0 == SCM_I_ARRAY_BASE (ra) % SCM_LONG_BIT &&
c014a02e 995 0 == len % SCM_LONG_BIT))
0f2d19dd
JB
996 return ra;
997 }
b6149d8d 998 ret = scm_i_make_array (k, 0);
04b87de5 999 SCM_I_ARRAY_BASE (ret) = 0;
0f2d19dd
JB
1000 while (k--)
1001 {
04b87de5
MV
1002 SCM_I_ARRAY_DIMS (ret)[k].lbnd = SCM_I_ARRAY_DIMS (ra)[k].lbnd;
1003 SCM_I_ARRAY_DIMS (ret)[k].ubnd = SCM_I_ARRAY_DIMS (ra)[k].ubnd;
1004 SCM_I_ARRAY_DIMS (ret)[k].inc = inc;
1005 inc *= SCM_I_ARRAY_DIMS (ra)[k].ubnd - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1;
0f2d19dd 1006 }
04b87de5 1007 SCM_I_ARRAY_V (ret) = make_typed_vector (scm_array_type (ra), inc);
0f2d19dd
JB
1008 if (copy)
1009 scm_array_copy_x (ra, ret);
1010 return ret;
1011}
1012
1013
1014
3b3b36dd 1015SCM_DEFINE (scm_uniform_array_read_x, "uniform-array-read!", 1, 3, 0,
03a5397a 1016 (SCM ura, SCM port_or_fd, SCM start, SCM end),
8f85c0c6
NJ
1017 "@deffnx {Scheme Procedure} uniform-vector-read! uve [port-or-fdes] [start] [end]\n"
1018 "Attempt to read all elements of @var{ura}, in lexicographic order, as\n"
b380b885 1019 "binary objects from @var{port-or-fdes}.\n"
8f85c0c6
NJ
1020 "If an end of file is encountered,\n"
1021 "the objects up to that point are put into @var{ura}\n"
b380b885
MD
1022 "(starting at the beginning) and the remainder of the array is\n"
1023 "unchanged.\n\n"
1024 "The optional arguments @var{start} and @var{end} allow\n"
1025 "a specified region of a vector (or linearized array) to be read,\n"
1026 "leaving the remainder of the vector unchanged.\n\n"
1027 "@code{uniform-array-read!} returns the number of objects read.\n"
1028 "@var{port-or-fdes} may be omitted, in which case it defaults to the value\n"
1029 "returned by @code{(current-input-port)}.")
1bbd0b84 1030#define FUNC_NAME s_scm_uniform_array_read_x
0f2d19dd 1031{
3d8d56df 1032 if (SCM_UNBNDP (port_or_fd))
9de87eea 1033 port_or_fd = scm_current_input_port ();
35de7ebe 1034
03a5397a 1035 if (scm_is_uniform_vector (ura))
20930f28 1036 {
03a5397a 1037 return scm_uniform_vector_read_x (ura, port_or_fd, start, end);
20930f28 1038 }
04b87de5 1039 else if (SCM_I_ARRAYP (ura))
20930f28 1040 {
03a5397a
MV
1041 size_t base, vlen, cstart, cend;
1042 SCM cra, ans;
1043
1044 cra = scm_ra2contig (ura, 0);
04b87de5
MV
1045 base = SCM_I_ARRAY_BASE (cra);
1046 vlen = SCM_I_ARRAY_DIMS (cra)->inc *
1047 (SCM_I_ARRAY_DIMS (cra)->ubnd - SCM_I_ARRAY_DIMS (cra)->lbnd + 1);
35de7ebe 1048
03a5397a
MV
1049 cstart = 0;
1050 cend = vlen;
1051 if (!SCM_UNBNDP (start))
1146b6cd 1052 {
03a5397a
MV
1053 cstart = scm_to_unsigned_integer (start, 0, vlen);
1054 if (!SCM_UNBNDP (end))
1055 cend = scm_to_unsigned_integer (end, cstart, vlen);
1146b6cd 1056 }
35de7ebe 1057
04b87de5 1058 ans = scm_uniform_vector_read_x (SCM_I_ARRAY_V (cra), port_or_fd,
03a5397a
MV
1059 scm_from_size_t (base + cstart),
1060 scm_from_size_t (base + cend));
6c951427 1061
03a5397a
MV
1062 if (!scm_is_eq (cra, ura))
1063 scm_array_copy_x (cra, ura);
1064 return ans;
3d8d56df 1065 }
04b87de5 1066 else if (SCM_I_ENCLOSED_ARRAYP (ura))
02339e5b 1067 scm_wrong_type_arg_msg (NULL, 0, ura, "non-enclosed array");
03a5397a
MV
1068 else
1069 scm_wrong_type_arg_msg (NULL, 0, ura, "array");
0f2d19dd 1070}
1bbd0b84 1071#undef FUNC_NAME
0f2d19dd 1072
3b3b36dd 1073SCM_DEFINE (scm_uniform_array_write, "uniform-array-write", 1, 3, 0,
03a5397a 1074 (SCM ura, SCM port_or_fd, SCM start, SCM end),
b380b885
MD
1075 "Writes all elements of @var{ura} as binary objects to\n"
1076 "@var{port-or-fdes}.\n\n"
1077 "The optional arguments @var{start}\n"
1078 "and @var{end} allow\n"
1079 "a specified region of a vector (or linearized array) to be written.\n\n"
9401323e 1080 "The number of objects actually written is returned.\n"
b380b885
MD
1081 "@var{port-or-fdes} may be\n"
1082 "omitted, in which case it defaults to the value returned by\n"
1083 "@code{(current-output-port)}.")
1bbd0b84 1084#define FUNC_NAME s_scm_uniform_array_write
0f2d19dd 1085{
3d8d56df 1086 if (SCM_UNBNDP (port_or_fd))
9de87eea 1087 port_or_fd = scm_current_output_port ();
20930f28 1088
03a5397a 1089 if (scm_is_uniform_vector (ura))
20930f28 1090 {
03a5397a 1091 return scm_uniform_vector_write (ura, port_or_fd, start, end);
20930f28 1092 }
04b87de5 1093 else if (SCM_I_ARRAYP (ura))
20930f28 1094 {
03a5397a
MV
1095 size_t base, vlen, cstart, cend;
1096 SCM cra, ans;
1097
1098 cra = scm_ra2contig (ura, 1);
04b87de5
MV
1099 base = SCM_I_ARRAY_BASE (cra);
1100 vlen = SCM_I_ARRAY_DIMS (cra)->inc *
1101 (SCM_I_ARRAY_DIMS (cra)->ubnd - SCM_I_ARRAY_DIMS (cra)->lbnd + 1);
1146b6cd 1102
03a5397a
MV
1103 cstart = 0;
1104 cend = vlen;
1105 if (!SCM_UNBNDP (start))
1146b6cd 1106 {
03a5397a
MV
1107 cstart = scm_to_unsigned_integer (start, 0, vlen);
1108 if (!SCM_UNBNDP (end))
1109 cend = scm_to_unsigned_integer (end, cstart, vlen);
1146b6cd 1110 }
3d8d56df 1111
04b87de5 1112 ans = scm_uniform_vector_write (SCM_I_ARRAY_V (cra), port_or_fd,
03a5397a
MV
1113 scm_from_size_t (base + cstart),
1114 scm_from_size_t (base + cend));
6c951427 1115
03a5397a 1116 return ans;
3d8d56df 1117 }
04b87de5 1118 else if (SCM_I_ENCLOSED_ARRAYP (ura))
02339e5b 1119 scm_wrong_type_arg_msg (NULL, 0, ura, "non-enclosed array");
03a5397a
MV
1120 else
1121 scm_wrong_type_arg_msg (NULL, 0, ura, "array");
0f2d19dd 1122}
1bbd0b84 1123#undef FUNC_NAME
0f2d19dd
JB
1124
1125
0f2d19dd 1126static SCM
34d19ef6 1127ra2l (SCM ra, unsigned long base, unsigned long k)
0f2d19dd 1128{
02339e5b 1129 SCM res = SCM_EOL;
5f37cb63 1130 long inc;
02339e5b 1131 size_t i;
04b87de5 1132 int enclosed = SCM_I_ENCLOSED_ARRAYP (ra);
02339e5b 1133
04b87de5
MV
1134 if (k == SCM_I_ARRAY_NDIM (ra))
1135 return scm_i_cvref (SCM_I_ARRAY_V (ra), base, enclosed);
5f37cb63 1136
04b87de5
MV
1137 inc = SCM_I_ARRAY_DIMS (ra)[k].inc;
1138 if (SCM_I_ARRAY_DIMS (ra)[k].ubnd < SCM_I_ARRAY_DIMS (ra)[k].lbnd)
0f2d19dd 1139 return SCM_EOL;
04b87de5 1140 i = base + (1 + SCM_I_ARRAY_DIMS (ra)[k].ubnd - SCM_I_ARRAY_DIMS (ra)[k].lbnd) * inc;
5f37cb63 1141 do
0f2d19dd 1142 {
5f37cb63
MV
1143 i -= inc;
1144 res = scm_cons (ra2l (ra, i, k + 1), res);
0f2d19dd 1145 }
5f37cb63 1146 while (i != base);
0f2d19dd
JB
1147 return res;
1148}
1149
1150
cd328b4f 1151SCM_DEFINE (scm_array_to_list, "array->list", 1, 0, 0,
1bbd0b84 1152 (SCM v),
1e6808ea
MG
1153 "Return a list consisting of all the elements, in order, of\n"
1154 "@var{array}.")
cd328b4f 1155#define FUNC_NAME s_scm_array_to_list
0f2d19dd 1156{
20930f28
MV
1157 if (scm_is_generalized_vector (v))
1158 return scm_generalized_vector_to_list (v);
04b87de5
MV
1159 else if (SCM_I_ARRAYP (v) || SCM_I_ENCLOSED_ARRAYP (v))
1160 return ra2l (v, SCM_I_ARRAY_BASE (v), 0);
e0e49670 1161
20930f28 1162 scm_wrong_type_arg_msg (NULL, 0, v, "array");
0f2d19dd 1163}
1bbd0b84 1164#undef FUNC_NAME
0f2d19dd
JB
1165
1166
bcbbea0e 1167static void l2ra (SCM lst, scm_t_array_handle *handle, ssize_t pos, size_t k);
1cc91f1b 1168
f301dbf3 1169SCM_DEFINE (scm_list_to_typed_array, "list->typed-array", 3, 0, 0,
2caaadd1 1170 (SCM type, SCM shape, SCM lst),
f301dbf3
MV
1171 "Return an array of the type @var{type}\n"
1172 "with elements the same as those of @var{lst}.\n"
bfad4005 1173 "\n"
2caaadd1
MV
1174 "The argument @var{shape} determines the number of dimensions\n"
1175 "of the array and their shape. It is either an exact integer,\n"
1176 "giving the\n"
1177 "number of dimensions directly, or a list whose length\n"
1178 "specifies the number of dimensions and each element specified\n"
1179 "the lower and optionally the upper bound of the corresponding\n"
1180 "dimension.\n"
1181 "When the element is list of two elements, these elements\n"
1182 "give the lower and upper bounds. When it is an exact\n"
1183 "integer, it gives only the lower bound.")
f301dbf3 1184#define FUNC_NAME s_scm_list_to_typed_array
0f2d19dd 1185{
2caaadd1 1186 SCM row;
0f2d19dd 1187 SCM ra;
bcbbea0e 1188 scm_t_array_handle handle;
bfad4005 1189
bfad4005 1190 row = lst;
2caaadd1 1191 if (scm_is_integer (shape))
0f2d19dd 1192 {
2caaadd1
MV
1193 size_t k = scm_to_size_t (shape);
1194 shape = SCM_EOL;
bfad4005
MV
1195 while (k-- > 0)
1196 {
1197 shape = scm_cons (scm_length (row), shape);
2caaadd1 1198 if (k > 0 && !scm_is_null (row))
bfad4005
MV
1199 row = scm_car (row);
1200 }
1201 }
1202 else
1203 {
2caaadd1
MV
1204 SCM shape_spec = shape;
1205 shape = SCM_EOL;
bfad4005
MV
1206 while (1)
1207 {
2caaadd1
MV
1208 SCM spec = scm_car (shape_spec);
1209 if (scm_is_pair (spec))
1210 shape = scm_cons (spec, shape);
1211 else
1212 shape = scm_cons (scm_list_2 (spec,
1213 scm_sum (scm_sum (spec,
1214 scm_length (row)),
1215 scm_from_int (-1))),
1216 shape);
1217 shape_spec = scm_cdr (shape_spec);
1218 if (scm_is_pair (shape_spec))
1219 {
1220 if (!scm_is_null (row))
1221 row = scm_car (row);
1222 }
bfad4005
MV
1223 else
1224 break;
1225 }
0f2d19dd 1226 }
bfad4005 1227
f0b91039
MV
1228 ra = scm_make_typed_array (type, SCM_UNSPECIFIED,
1229 scm_reverse_x (shape, SCM_EOL));
20930f28 1230
bcbbea0e
MV
1231 scm_array_get_handle (ra, &handle);
1232 l2ra (lst, &handle, 0, 0);
1233 scm_array_handle_release (&handle);
1234
1235 return ra;
0f2d19dd 1236}
1bbd0b84 1237#undef FUNC_NAME
0f2d19dd 1238
f301dbf3
MV
1239SCM_DEFINE (scm_list_to_array, "list->array", 2, 0, 0,
1240 (SCM ndim, SCM lst),
1241 "Return an array with elements the same as those of @var{lst}.")
1242#define FUNC_NAME s_scm_list_to_array
1243{
1244 return scm_list_to_typed_array (SCM_BOOL_T, ndim, lst);
1245}
1246#undef FUNC_NAME
1247
bcbbea0e
MV
1248static void
1249l2ra (SCM lst, scm_t_array_handle *handle, ssize_t pos, size_t k)
0f2d19dd 1250{
bcbbea0e
MV
1251 if (k == scm_array_handle_rank (handle))
1252 scm_array_handle_set (handle, pos, lst);
0f2d19dd
JB
1253 else
1254 {
bcbbea0e
MV
1255 scm_t_array_dim *dim = scm_array_handle_dims (handle) + k;
1256 ssize_t inc = dim->inc;
2caaadd1
MV
1257 size_t len = 1 + dim->ubnd - dim->lbnd, n;
1258 char *errmsg = NULL;
bcbbea0e 1259
2caaadd1 1260 n = len;
bcbbea0e 1261 while (n > 0 && scm_is_pair (lst))
0f2d19dd 1262 {
bcbbea0e
MV
1263 l2ra (SCM_CAR (lst), handle, pos, k + 1);
1264 pos += inc;
0f2d19dd 1265 lst = SCM_CDR (lst);
bcbbea0e 1266 n -= 1;
0f2d19dd 1267 }
bcbbea0e 1268 if (n != 0)
2caaadd1 1269 errmsg = "too few elements for array dimension ~a, need ~a";
d2e53ed6 1270 if (!scm_is_null (lst))
2caaadd1
MV
1271 errmsg = "too many elements for array dimension ~a, want ~a";
1272 if (errmsg)
1273 scm_misc_error (NULL, errmsg, scm_list_2 (scm_from_ulong (k),
1274 scm_from_size_t (len)));
0f2d19dd 1275 }
0f2d19dd
JB
1276}
1277
e0e49670
MV
1278/* Print dimension DIM of ARRAY.
1279 */
0f2d19dd 1280
e0e49670 1281static int
02339e5b 1282scm_i_print_array_dimension (SCM array, int dim, int base, int enclosed,
e0e49670
MV
1283 SCM port, scm_print_state *pstate)
1284{
04b87de5 1285 scm_t_array_dim *dim_spec = SCM_I_ARRAY_DIMS (array) + dim;
e0e49670
MV
1286 long idx;
1287
1288 scm_putc ('(', port);
1289
e0e49670
MV
1290 for (idx = dim_spec->lbnd; idx <= dim_spec->ubnd; idx++)
1291 {
04b87de5 1292 if (dim < SCM_I_ARRAY_NDIM(array)-1)
02339e5b
MV
1293 scm_i_print_array_dimension (array, dim+1, base, enclosed,
1294 port, pstate);
e0e49670 1295 else
04b87de5 1296 scm_iprin1 (scm_i_cvref (SCM_I_ARRAY_V (array), base, enclosed),
e0e49670
MV
1297 port, pstate);
1298 if (idx < dim_spec->ubnd)
1299 scm_putc (' ', port);
1300 base += dim_spec->inc;
1301 }
1302
1303 scm_putc (')', port);
1304 return 1;
1305}
1306
f301dbf3 1307/* Print an array. (Only for strict arrays, not for generalized vectors.)
e0e49670
MV
1308*/
1309
e0e49670
MV
1310static int
1311scm_i_print_array (SCM array, SCM port, scm_print_state *pstate)
1312{
04b87de5
MV
1313 long ndim = SCM_I_ARRAY_NDIM (array);
1314 scm_t_array_dim *dim_specs = SCM_I_ARRAY_DIMS (array);
1315 SCM v = SCM_I_ARRAY_V (array);
1316 unsigned long base = SCM_I_ARRAY_BASE (array);
e0e49670 1317 long i;
2caaadd1 1318 int print_lbnds = 0, zero_size = 0, print_lens = 0;
e0e49670
MV
1319
1320 scm_putc ('#', port);
c0fc64c8 1321 if (ndim != 1 || dim_specs[0].lbnd != 0)
e0e49670 1322 scm_intprint (ndim, 10, port);
20930f28
MV
1323 if (scm_is_uniform_vector (v))
1324 scm_puts (scm_i_uniform_vector_tag (v), port);
1325 else if (scm_is_bitvector (v))
1326 scm_puts ("b", port);
1327 else if (scm_is_string (v))
1328 scm_puts ("a", port);
1329 else if (!scm_is_vector (v))
1330 scm_puts ("?", port);
1331
e0e49670 1332 for (i = 0; i < ndim; i++)
2caaadd1
MV
1333 {
1334 if (dim_specs[i].lbnd != 0)
1335 print_lbnds = 1;
1336 if (dim_specs[i].ubnd - dim_specs[i].lbnd + 1 == 0)
1337 zero_size = 1;
1338 else if (zero_size)
1339 print_lens = 1;
1340 }
1341
1342 if (print_lbnds || print_lens)
1343 for (i = 0; i < ndim; i++)
e0e49670 1344 {
2caaadd1 1345 if (print_lbnds)
e0e49670
MV
1346 {
1347 scm_putc ('@', port);
2caaadd1
MV
1348 scm_intprint (dim_specs[i].lbnd, 10, port);
1349 }
1350 if (print_lens)
1351 {
1352 scm_putc (':', port);
1353 scm_intprint (dim_specs[i].ubnd - dim_specs[i].lbnd + 1,
1354 10, port);
e0e49670 1355 }
e0e49670
MV
1356 }
1357
5f37cb63
MV
1358 if (ndim == 0)
1359 {
1360 /* Rank zero arrays, which are really just scalars, are printed
1361 specially. The consequent way would be to print them as
1362
1363 #0 OBJ
1364
1365 where OBJ is the printed representation of the scalar, but we
1366 print them instead as
1367
1368 #0(OBJ)
1369
1370 to make them look less strange.
1371
1372 Just printing them as
1373
1374 OBJ
1375
1376 would be correct in a way as well, but zero rank arrays are
1377 not really the same as Scheme values since they are boxed and
1378 can be modified with array-set!, say.
1379 */
1380 scm_putc ('(', port);
1381 scm_iprin1 (scm_i_cvref (v, base, 0), port, pstate);
1382 scm_putc (')', port);
1383 return 1;
1384 }
1385 else
1386 return scm_i_print_array_dimension (array, 0, base, 0, port, pstate);
02339e5b
MV
1387}
1388
1389static int
1390scm_i_print_enclosed_array (SCM array, SCM port, scm_print_state *pstate)
1391{
1392 size_t base;
1393
1394 scm_putc ('#', port);
04b87de5 1395 base = SCM_I_ARRAY_BASE (array);
02339e5b
MV
1396 scm_puts ("<enclosed-array ", port);
1397 scm_i_print_array_dimension (array, 0, base, 1, port, pstate);
1398 scm_putc ('>', port);
1399 return 1;
e0e49670 1400}
1cc91f1b 1401
bfad4005
MV
1402/* Read an array. This function can also read vectors and uniform
1403 vectors. Also, the conflict between '#f' and '#f32' and '#f64' is
1404 handled here.
1405
1406 C is the first character read after the '#'.
1407*/
1408
bfad4005 1409static SCM
f301dbf3 1410tag_to_type (const char *tag, SCM port)
bfad4005 1411{
5f37cb63
MV
1412 if (*tag == '\0')
1413 return SCM_BOOL_T;
1414 else
1415 return scm_from_locale_symbol (tag);
bfad4005
MV
1416}
1417
2caaadd1
MV
1418static int
1419read_decimal_integer (SCM port, int c, ssize_t *resp)
1420{
1421 ssize_t sign = 1;
1422 ssize_t res = 0;
1423 int got_it = 0;
1424
1425 if (c == '-')
1426 {
1427 sign = -1;
1428 c = scm_getc (port);
1429 }
1430
1431 while ('0' <= c && c <= '9')
1432 {
1433 res = 10*res + c-'0';
1434 got_it = 1;
1435 c = scm_getc (port);
1436 }
1437
1438 if (got_it)
f30e1bdf 1439 *resp = sign * res;
2caaadd1
MV
1440 return c;
1441}
1442
bfad4005
MV
1443SCM
1444scm_i_read_array (SCM port, int c)
1445{
5a6d139b 1446 ssize_t rank;
bfad4005
MV
1447 int got_rank;
1448 char tag[80];
1449 int tag_len;
1450
2caaadd1 1451 SCM shape = SCM_BOOL_F, elements;
bfad4005
MV
1452
1453 /* XXX - shortcut for ordinary vectors. Shouldn't be necessary but
1454 the array code can not deal with zero-length dimensions yet, and
1455 we want to allow zero-length vectors, of course.
1456 */
1457 if (c == '(')
1458 {
1459 scm_ungetc (c, port);
1460 return scm_vector (scm_read (port));
1461 }
1462
1463 /* Disambiguate between '#f' and uniform floating point vectors.
1464 */
1465 if (c == 'f')
1466 {
1467 c = scm_getc (port);
1468 if (c != '3' && c != '6')
1469 {
1470 if (c != EOF)
1471 scm_ungetc (c, port);
1472 return SCM_BOOL_F;
1473 }
1474 rank = 1;
1475 got_rank = 1;
1476 tag[0] = 'f';
1477 tag_len = 1;
1478 goto continue_reading_tag;
1479 }
1480
2caaadd1
MV
1481 /* Read rank.
1482 */
1483 rank = 1;
1484 c = read_decimal_integer (port, c, &rank);
1485 if (rank < 0)
1486 scm_i_input_error (NULL, port, "array rank must be non-negative",
1487 SCM_EOL);
bfad4005 1488
2caaadd1
MV
1489 /* Read tag.
1490 */
bfad4005
MV
1491 tag_len = 0;
1492 continue_reading_tag:
2caaadd1 1493 while (c != EOF && c != '(' && c != '@' && c != ':' && tag_len < 80)
bfad4005
MV
1494 {
1495 tag[tag_len++] = c;
1496 c = scm_getc (port);
1497 }
1498 tag[tag_len] = '\0';
1499
2caaadd1
MV
1500 /* Read shape.
1501 */
1502 if (c == '@' || c == ':')
bfad4005 1503 {
2caaadd1 1504 shape = SCM_EOL;
5f37cb63
MV
1505
1506 do
bfad4005 1507 {
2caaadd1
MV
1508 ssize_t lbnd = 0, len = 0;
1509 SCM s;
5f37cb63 1510
2caaadd1 1511 if (c == '@')
5f37cb63 1512 {
5f37cb63 1513 c = scm_getc (port);
2caaadd1 1514 c = read_decimal_integer (port, c, &lbnd);
5f37cb63 1515 }
2caaadd1
MV
1516
1517 s = scm_from_ssize_t (lbnd);
1518
1519 if (c == ':')
5f37cb63 1520 {
5f37cb63 1521 c = scm_getc (port);
2caaadd1 1522 c = read_decimal_integer (port, c, &len);
f30e1bdf
LC
1523 if (len < 0)
1524 scm_i_input_error (NULL, port,
1525 "array length must be non-negative",
1526 SCM_EOL);
1527
2caaadd1 1528 s = scm_list_2 (s, scm_from_ssize_t (lbnd+len-1));
5f37cb63 1529 }
2caaadd1
MV
1530
1531 shape = scm_cons (s, shape);
1532 } while (c == '@' || c == ':');
1533
1534 shape = scm_reverse_x (shape, SCM_EOL);
bfad4005
MV
1535 }
1536
1537 /* Read nested lists of elements.
1538 */
1539 if (c != '(')
1540 scm_i_input_error (NULL, port,
1541 "missing '(' in vector or array literal",
1542 SCM_EOL);
1543 scm_ungetc (c, port);
1544 elements = scm_read (port);
1545
2caaadd1 1546 if (scm_is_false (shape))
5a6d139b 1547 shape = scm_from_ssize_t (rank);
2caaadd1
MV
1548 else if (scm_ilength (shape) != rank)
1549 scm_i_input_error
1550 (NULL, port,
1551 "the number of shape specifications must match the array rank",
1552 SCM_EOL);
bfad4005 1553
5f37cb63
MV
1554 /* Handle special print syntax of rank zero arrays; see
1555 scm_i_print_array for a rationale.
1556 */
1557 if (rank == 0)
2caaadd1
MV
1558 {
1559 if (!scm_is_pair (elements))
1560 scm_i_input_error (NULL, port,
1561 "too few elements in array literal, need 1",
1562 SCM_EOL);
1563 if (!scm_is_null (SCM_CDR (elements)))
1564 scm_i_input_error (NULL, port,
1565 "too many elements in array literal, want 1",
1566 SCM_EOL);
1567 elements = SCM_CAR (elements);
1568 }
5f37cb63
MV
1569
1570 /* Construct array.
1571 */
2caaadd1 1572 return scm_list_to_typed_array (tag_to_type (tag, port), shape, elements);
bfad4005
MV
1573}
1574
f301dbf3 1575SCM_DEFINE (scm_array_type, "array-type", 1, 0, 0,
ab1be174 1576 (SCM ra),
f301dbf3
MV
1577 "")
1578#define FUNC_NAME s_scm_array_type
ab1be174 1579{
04b87de5
MV
1580 if (SCM_I_ARRAYP (ra))
1581 return scm_i_generalized_vector_type (SCM_I_ARRAY_V (ra));
02339e5b 1582 else if (scm_is_generalized_vector (ra))
f301dbf3 1583 return scm_i_generalized_vector_type (ra);
04b87de5 1584 else if (SCM_I_ENCLOSED_ARRAYP (ra))
02339e5b 1585 scm_wrong_type_arg_msg (NULL, 0, ra, "non-enclosed array");
ab1be174 1586 else
02339e5b 1587 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
ab1be174
MV
1588}
1589#undef FUNC_NAME
1590
0f2d19dd 1591static SCM
e841c3e0 1592array_mark (SCM ptr)
0f2d19dd 1593{
04b87de5 1594 return SCM_I_ARRAY_V (ptr);
0f2d19dd
JB
1595}
1596
1be6b49c 1597static size_t
e841c3e0 1598array_free (SCM ptr)
0f2d19dd 1599{
04b87de5
MV
1600 scm_gc_free (SCM_I_ARRAY_MEM (ptr),
1601 (sizeof (scm_i_t_array)
1602 + SCM_I_ARRAY_NDIM (ptr) * sizeof (scm_t_array_dim)),
4c9419ac
MV
1603 "array");
1604 return 0;
0f2d19dd
JB
1605}
1606
0f2d19dd
JB
1607void
1608scm_init_unif ()
0f2d19dd 1609{
04b87de5
MV
1610 scm_i_tc16_array = scm_make_smob_type ("array", 0);
1611 scm_set_smob_mark (scm_i_tc16_array, array_mark);
1612 scm_set_smob_free (scm_i_tc16_array, array_free);
1613 scm_set_smob_print (scm_i_tc16_array, scm_i_print_array);
1614 scm_set_smob_equalp (scm_i_tc16_array, scm_array_equal_p);
1615
1616 scm_i_tc16_enclosed_array = scm_make_smob_type ("enclosed-array", 0);
1617 scm_set_smob_mark (scm_i_tc16_enclosed_array, array_mark);
1618 scm_set_smob_free (scm_i_tc16_enclosed_array, array_free);
1619 scm_set_smob_print (scm_i_tc16_enclosed_array, scm_i_print_enclosed_array);
1620 scm_set_smob_equalp (scm_i_tc16_enclosed_array, scm_array_equal_p);
02339e5b 1621
0f2d19dd 1622 scm_add_feature ("array");
20930f28 1623
f301dbf3
MV
1624 init_type_creator_table ();
1625
a0599745 1626#include "libguile/unif.x"
bfad4005 1627
0f2d19dd 1628}
89e00824
ML
1629
1630/*
1631 Local Variables:
1632 c-file-style: "gnu"
1633 End:
1634*/